diff --git a/.eslintrc.js b/.eslintrc.js index 6fe8e86c542..c3b81a2e0d9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -31,7 +31,6 @@ module.exports = { ], }, ], - "no-useless-escape": "warn", // TODO(bkendall): remove, allow to error. }, overrides: [ { diff --git a/scripts/webframeworks-deploy-tests/tests.ts b/scripts/webframeworks-deploy-tests/tests.ts index 08a846a19d4..259ef0fe725 100644 --- a/scripts/webframeworks-deploy-tests/tests.ts +++ b/scripts/webframeworks-deploy-tests/tests.ts @@ -21,7 +21,7 @@ const I18N_BASE = ""; const DEFAULT_LANG = "en"; const LOG_FILE = "firebase-debug.log"; const NEXT_SOURCE = `${__dirname}/nextjs`; -const PATH_SEPARATOR = IS_WINDOWS ? `\\\\` : `\/`; +const PATH_SEPARATOR = IS_WINDOWS ? `\\\\` : `/`; async function getFilesListFromDir(dir: string): Promise { const files = await glob(`${dir}/**/*`, { nodir: true }); @@ -447,8 +447,8 @@ describe("webframeworks", function (this) { const distDir = ".next"; const UNEXPECTED_PATTERNS = [ - `${distDir}\/cache\/.*-development`, - `${distDir}\/cache\/eslint`, + `${distDir}/cache/.*-development`, + `${distDir}/cache/eslint`, ].map((it) => new RegExp(it)); const files = await getFilesListFromDir(`${NEXT_OUTPUT_PATH}/functions/${distDir}`); @@ -503,9 +503,9 @@ describe("webframeworks", function (this) { const EXPECTED_PATTERNS = ["", "en", "fr", "es"] .flatMap((locale) => [ - [I18N_BASE, locale, ANGULAR_BASE_PATH, `main\.[^\.]+\.js`], - [I18N_BASE, locale, ANGULAR_BASE_PATH, `polyfills\.[^\.]+\.js`], - [I18N_BASE, locale, ANGULAR_BASE_PATH, `styles\.[^\.]+\.css`], + [I18N_BASE, locale, ANGULAR_BASE_PATH, `main.[^.]+.js`], + [I18N_BASE, locale, ANGULAR_BASE_PATH, `polyfills.[^.]+.js`], + [I18N_BASE, locale, ANGULAR_BASE_PATH, `styles.[^.]+.css`], ]) .map((it) => new RegExp(it.filter(Boolean).join(PATH_SEPARATOR))); diff --git a/src/appdistribution/options-parser-util.ts b/src/appdistribution/options-parser-util.ts index b25b94724cc..3d921857a58 100644 --- a/src/appdistribution/options-parser-util.ts +++ b/src/appdistribution/options-parser-util.ts @@ -188,7 +188,7 @@ function isPresenceMismatched(value1?: string, value2?: string) { return (value1 && !value2) || (!value1 && value2); } -const APP_NAME_REGEX = /^projects\/(?[^\/]+)\/apps\/(?[^\/]+)$/; +const APP_NAME_REGEX = /^projects\/(?[^/]+)\/apps\/(?[^/]+)$/; const BUCKET_NAME_FORMAT_REGEX = /^[a-z0-9_.-]+$/; /** diff --git a/src/apphosting/githubConnections.ts b/src/apphosting/githubConnections.ts index 10a885c7895..d849efe3d55 100644 --- a/src/apphosting/githubConnections.ts +++ b/src/apphosting/githubConnections.ts @@ -39,7 +39,7 @@ interface ConnectionNameParts { const APPHOSTING_CONN_PATTERN = /.+\/apphosting-github-conn-.+$/; const CONNECTION_NAME_REGEX = - /^projects\/(?[^\/]+)\/locations\/(?[^\/]+)\/connections\/(?[^\/]+)$/; + /^projects\/(?[^/]+)\/locations\/(?[^/]+)\/connections\/(?[^/]+)$/; /** * Exported for unit testing. diff --git a/src/dataconnect/names.ts b/src/dataconnect/names.ts index 5f2b761adb9..9cb137e81ef 100644 --- a/src/dataconnect/names.ts +++ b/src/dataconnect/names.ts @@ -8,7 +8,7 @@ interface serviceName { } const serviceNameRegex = - /projects\/(?[^\/]+)\/locations\/(?[^\/]+)\/services\/(?[^\/]+)/; + /projects\/(?[^/]+)\/locations\/(?[^/]+)\/services\/(?[^/]+)/; export function parseServiceName(serviceName: string): serviceName { const res = serviceNameRegex.exec(serviceName); @@ -38,7 +38,7 @@ interface connectorName { } const connectorNameRegex = - /projects\/(?[^\/]+)\/locations\/(?[^\/]+)\/services\/(?[^\/]+)\/connectors\/(?[^\/]+)/; + /projects\/(?[^/]+)\/locations\/(?[^/]+)\/services\/(?[^/]+)\/connectors\/(?[^/]+)/; export function parseConnectorName(connectorName: string): connectorName { const res = connectorNameRegex.exec(connectorName); @@ -69,7 +69,7 @@ interface cloudSQLInstanceName { } const cloudSQLInstanceNameRegex = - /projects\/(?[^\/]+)\/locations\/(?[^\/]+)\/instances\/(?[^\/]+)/; + /projects\/(?[^/]+)\/locations\/(?[^/]+)\/instances\/(?[^/]+)/; export function parseCloudSQLInstanceName(cloudSQLInstanceName: string): cloudSQLInstanceName { const res = cloudSQLInstanceNameRegex.exec(cloudSQLInstanceName); diff --git a/src/dataconnect/schemaMigration.ts b/src/dataconnect/schemaMigration.ts index e958682b354..eae8009c565 100644 --- a/src/dataconnect/schemaMigration.ts +++ b/src/dataconnect/schemaMigration.ts @@ -866,5 +866,5 @@ function diffsToString(diffs: Diff[]): string { } function diffToString(diff: Diff) { - return `\/** ${diff.destructive ? clc.red("Destructive: ") : ""}${diff.description}*\/\n${format(diff.sql, { language: "postgresql" })}`; + return `/** ${diff.destructive ? clc.red("Destructive: ") : ""}${diff.description}*/\n${format(diff.sql, { language: "postgresql" })}`; } diff --git a/src/deploy/functions/cel.ts b/src/deploy/functions/cel.ts index b3903a4e76a..ce48fa42350 100644 --- a/src/deploy/functions/cel.ts +++ b/src/deploy/functions/cel.ts @@ -176,7 +176,7 @@ function preprocessLists( params: Record, ): CelExpression { let rv = expr; - const listMatcher = /\[[^\[\]]*\]/g; + const listMatcher = /\[[^[\]]*\]/g; let match: RegExpMatchArray | null; while ((match = listMatcher.exec(expr)) != null) { const list = match[0]; diff --git a/src/deploy/functions/runtimes/discovery/v1alpha1.ts b/src/deploy/functions/runtimes/discovery/v1alpha1.ts index 87bbdb0d9f7..27145bb2474 100644 --- a/src/deploy/functions/runtimes/discovery/v1alpha1.ts +++ b/src/deploy/functions/runtimes/discovery/v1alpha1.ts @@ -194,7 +194,7 @@ export function buildFromV1Alpha1( } const ROLE_REGEX = - /^(roles\/[a-zA-Z0-9_\.\-]+|projects\/[a-zA-Z0-9\-]+\/roles\/[a-zA-Z0-9_\.\-]+|organizations\/[0-9]+\/roles\/[a-zA-Z0-9_\.\-]+)$/; + /^(roles\/[a-zA-Z0-9_.-]+|projects\/[a-zA-Z0-9-]+\/roles\/[a-zA-Z0-9_.-]+|organizations\/[0-9]+\/roles\/[a-zA-Z0-9_.-]+)$/; function parseRequiredRoles(manifest: WireManifest): string[] { const roles: string[] = manifest.requiredRoles || []; diff --git a/src/deploy/lifecycleHooks.ts b/src/deploy/lifecycleHooks.ts index 2d067a46afd..ffd8bf2e7bb 100644 --- a/src/deploy/lifecycleHooks.ts +++ b/src/deploy/lifecycleHooks.ts @@ -9,7 +9,7 @@ import { Options } from "../options"; import { isVSCodeExtension } from "../vsCodeUtils"; function runCommand(command: string, childOptions: childProcess.SpawnOptions) { - const escapedCommand = command.replace(/\"/g, '\\"'); + const escapedCommand = command.replace(/"/g, '\\"'); const nodeExecutable = isVSCodeExtension() ? "node" : process.execPath; const crossEnvShellPath = isVSCodeExtension() ? path.resolve(__dirname, "./cross-env/dist/bin/cross-env-shell.js") diff --git a/src/emulator/auth/server.ts b/src/emulator/auth/server.ts index a118c2d1b87..691fab33200 100644 --- a/src/emulator/auth/server.ts +++ b/src/emulator/auth/server.ts @@ -395,7 +395,7 @@ export async function createApp( `Multiple projectIds are not recommended in single project mode. ` + `Requested project ID ${projectId}, but the emulator is configured for ` + `${defaultProjectId}. To opt-out of single project mode add/set the ` + - `\'"singleProjectMode"\' false' property in the firebase.json emulators config.`; + `'"singleProjectMode"' false' property in the firebase.json emulators config.`; EmulatorLogger.forEmulator(Emulators.AUTH).log("WARN", errorString); if (singleProjectMode === SingleProjectMode.ERROR) { throw new BadRequestError(errorString); diff --git a/src/emulator/auth/widget_ui.spec.ts b/src/emulator/auth/widget_ui.spec.ts new file mode 100644 index 00000000000..62af7a2c232 --- /dev/null +++ b/src/emulator/auth/widget_ui.spec.ts @@ -0,0 +1,10 @@ +import { expect } from "chai"; + +import { WIDGET_UI } from "./widget_ui"; + +describe("WIDGET_UI", () => { + it("should only treat provider IDs with a literal 'saml.' prefix as SAML providers", () => { + // The script is built from a template literal, so the source needs `\\.` for the browser to receive `\.`. + expect(WIDGET_UI).to.include("providerId.match(/^saml\\./)"); + }); +}); diff --git a/src/emulator/auth/widget_ui.ts b/src/emulator/auth/widget_ui.ts index 502fadc5804..ae24c9f1681 100644 --- a/src/emulator/auth/widget_ui.ts +++ b/src/emulator/auth/widget_ui.ts @@ -34,7 +34,7 @@ var firebaseAppId = query.get('appId'); var apn = query.get('apn'); var ibi = query.get('ibi'); var appIdentifier = apn || ibi; -var isSamlProvider = !!providerId.match(/^saml\./); +var isSamlProvider = !!providerId.match(/^saml\\./); assert( appName || clientId || firebaseAppId || appIdentifier, 'Missing one of appName / clientId / appId / apn / ibi query params.' diff --git a/src/emulator/extensions/postinstall.ts b/src/emulator/extensions/postinstall.ts index a4f9fb2a20f..19f9a2b8e4b 100644 --- a/src/emulator/extensions/postinstall.ts +++ b/src/emulator/extensions/postinstall.ts @@ -11,27 +11,27 @@ export function replaceConsoleLinks(postinstall: string): string { let subbedPostinstall = postinstall; const linkReplacements = new Map([ [ - /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/storage[A-Za-z0-9\/-]*(?=[\)\]\s])/, + /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/storage[A-Za-z0-9/-]*(?=[)\]\s])/, `${uiUrl}${Emulators.STORAGE}`, ], // Storage console links [ - /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/firestore[A-Za-z0-9\/-]*(?=[\)\]\s])/, + /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/firestore[A-Za-z0-9/-]*(?=[)\]\s])/, `${uiUrl}${Emulators.FIRESTORE}`, ], // Firestore console links [ - /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/database[A-Za-z0-9\/-]*(?=[\)\]\s])/, + /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/database[A-Za-z0-9/-]*(?=[)\]\s])/, `${uiUrl}${Emulators.DATABASE}`, ], // RTDB console links [ - /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/authentication[A-Za-z0-9\/-]*(?=[\)\]\s])/, + /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/authentication[A-Za-z0-9/-]*(?=[)\]\s])/, `${uiUrl}${Emulators.AUTH}`, ], // Auth console links [ - /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/functions[A-Za-z0-9\/-]*(?=[\)\]\s])/, + /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/functions[A-Za-z0-9/-]*(?=[)\]\s])/, `${uiUrl}logs`, // There is no functions page in the UI, so redirect to logs. ], // Functions console links [ - /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/extensions[A-Za-z0-9\/-]*(?=[\)\]\s])/, + /(http[s]?:\/\/)?console\.firebase\.google\.com\/(u\/[0-9]\/)?project\/[A-Za-z0-9-]+\/extensions[A-Za-z0-9/-]*(?=[)\]\s])/, `${uiUrl}${Emulators.EXTENSIONS}`, ], // Extensions console links ]); diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index 9c26fde1cdc..24d6fb8a930 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -191,10 +191,10 @@ interface EmulatedTriggerRecord { export function createIgnoredFilter(ignore?: string[]): chokidar.Matcher[] { const ignored: chokidar.Matcher[] = [ - /(^|[\/\\])\../, // Ignore hidden files/dirs (covers .dart_tool, .git, etc.) + /(^|[/\\])\../, // Ignore hidden files/dirs (covers .dart_tool, .git, etc.) /.+\.log/, // Ignore log files - /.+?[\\\/]node_modules[\\\/].+?/, // Ignore node_modules - /.+?[\\\/]venv[\\\/].+?/, // Ignore venv + /.+?[\\/]node_modules[\\/].+?/, // Ignore node_modules + /.+?[\\/]venv[\\/].+?/, // Ignore venv ]; if (ignore) { const minimatchInstances = ignore.map((pattern) => { @@ -1948,7 +1948,7 @@ export class FunctionsEmulator implements EmulatorInstance { // req.url = /:projectId/:region/:trigger_name/* const url = new URL(`${req.protocol}://${req.hostname}${req.url}`); let path = `${url.pathname}${url.search}`.replace( - new RegExp(`\/${this.args.projectId}\/[^\/]*\/${req.params.trigger_name}\/?`), + new RegExp(`/${this.args.projectId}/[^/]*/${req.params.trigger_name}/?`), "/", ); diff --git a/src/emulator/storage/files.ts b/src/emulator/storage/files.ts index 04c52cb51ca..eeacfad0e04 100644 --- a/src/emulator/storage/files.ts +++ b/src/emulator/storage/files.ts @@ -658,6 +658,6 @@ export class StorageLayer { /** Returns file separator used in given path, either '\\' or '/'. */ function getPathSep(decodedPath: string): string { // Checks for the first matching file separator - const firstSepIndex = decodedPath.search(/[\/|\\\\]/g); + const firstSepIndex = decodedPath.search(/[/|\\\\]/g); return decodedPath[firstSepIndex]; } diff --git a/src/extensions/extensionsHelper.ts b/src/extensions/extensionsHelper.ts index c457f37064c..214c7a122fc 100644 --- a/src/extensions/extensionsHelper.ts +++ b/src/extensions/extensionsHelper.ts @@ -87,7 +87,7 @@ export const resourceTypeToNiceName: Record = { "firebaseextensions.v1beta.function": "Cloud Function", }; export type ReleaseStage = "alpha" | "beta" | "rc" | "stable"; -const repoRegex = new RegExp(`^https:\/\/github\.com\/[^\/]+\/[^\/]+$`); +const repoRegex = new RegExp(`^https://github.com/[^/]+/[^/]+$`); const stageOptions = ["rc", "alpha", "beta", "stable"]; /** @@ -362,7 +362,7 @@ export function validateSpec(spec: any) { export async function promptForValidInstanceId(instanceId: string): Promise { let instanceIdIsValid = false; let newInstanceId = ""; - const instanceIdRegex = /^[a-z][a-z\d\-]*[a-z\d]$/; + const instanceIdRegex = /^[a-z][a-z\d-]*[a-z\d]$/; while (!instanceIdIsValid) { newInstanceId = await input({ default: instanceId, diff --git a/src/extensions/paramHelper.ts b/src/extensions/paramHelper.ts index da6267c83c2..c1af7370830 100644 --- a/src/extensions/paramHelper.ts +++ b/src/extensions/paramHelper.ts @@ -287,7 +287,7 @@ export function readEnvFile(envPath: string): Record { } export function isSystemParam(paramName: string): boolean { - const regex = /^firebaseextensions\.[a-zA-Z0-9\.]*\//; + const regex = /^firebaseextensions\.[a-zA-Z0-9.]*\//; return regex.test(paramName); } diff --git a/src/extensions/provisioningHelper.ts b/src/extensions/provisioningHelper.ts index 6324df73e0e..9047ad30140 100644 --- a/src/extensions/provisioningHelper.ts +++ b/src/extensions/provisioningHelper.ts @@ -106,7 +106,7 @@ export function getUsedProducts(spec: ExtensionSpec): DeferredProduct[] { * Parses out trigger eventType from the propertiesYaml. */ function getTriggerType(propertiesYaml: string | undefined) { - return propertiesYaml?.match(/eventType:\ ([\S]+)/)?.[1]; + return propertiesYaml?.match(/eventType: ([\S]+)/)?.[1]; } async function isStorageProvisioned(projectId: string): Promise { diff --git a/src/firestore/util.ts b/src/firestore/util.ts index 78cecd0cece..99cb8a728a0 100644 --- a/src/firestore/util.ts +++ b/src/firestore/util.ts @@ -20,15 +20,15 @@ interface FieldName { } // projects/$PROJECT_ID/databases/$DATABASE_ID -const DATABASE_NAME_REGEX = /projects\/([^\/]+?)\/databases\/([^\/]+)/; +const DATABASE_NAME_REGEX = /projects\/([^/]+?)\/databases\/([^/]+)/; // projects/$PROJECT_ID/databases/$DATABASE_ID/collectionGroups/$COLLECTION_GROUP_ID/indexes/$INDEX_ID const INDEX_NAME_REGEX = - /projects\/([^\/]+?)\/databases\/([^\/]+?)\/collectionGroups\/([^\/]+?)\/indexes\/([^\/]*)/; + /projects\/([^/]+?)\/databases\/([^/]+?)\/collectionGroups\/([^/]+?)\/indexes\/([^/]*)/; // projects/$PROJECT_ID/databases/$DATABASE_ID/collectionGroups/$COLLECTION_GROUP_ID/fields/$FIELD_ID const FIELD_NAME_REGEX = - /projects\/([^\/]+?)\/databases\/([^\/]+?)\/collectionGroups\/([^\/]+?)\/fields\/([^\/]*)/; + /projects\/([^/]+?)\/databases\/([^/]+?)\/collectionGroups\/([^/]+?)\/fields\/([^/]*)/; /** * Parse a Database name into useful pieces. diff --git a/src/frameworks/angular/utils.ts b/src/frameworks/angular/utils.ts index 2e8affd746b..b04a2c6f3cd 100644 --- a/src/frameworks/angular/utils.ts +++ b/src/frameworks/angular/utils.ts @@ -52,7 +52,7 @@ async function localesForTarget( for (const [locale, { baseHref }] of Object.entries(i18n.locales)) { if (baseHref !== "") throw new FirebaseError( - `All your i18n locales must have a baseHref of \"\" on Firebase, errored on ${locale}.`, + `All your i18n locales must have a baseHref of "" on Firebase, errored on ${locale}.`, ); locales.push(locale); } diff --git a/src/frameworks/next/testing/app.ts b/src/frameworks/next/testing/app.ts index 049376fc692..86da1bdfdb1 100644 --- a/src/frameworks/next/testing/app.ts +++ b/src/frameworks/next/testing/app.ts @@ -74,9 +74,9 @@ export const pageClientReferenceManifestWithoutImage = `globalThis.__RSC_MANIFES globalThis.__RSC_MANIFEST["/page"] = '{"ssrModuleMapping":{"372":{"*":{"id":"772","name":"*","chunks":[],"async":false}},"1223":{"*":{"id":"4249","name":"*","chunks":[],"async":false}},"3240":{"*":{"id":"7230","name":"*","chunks":[],"async":false}},"3466":{"*":{"id":"885","name":"*","chunks":[],"async":false}},"5721":{"*":{"id":"8262","name":"*","chunks":[],"async":false}},"8095":{"*":{"id":"4564","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"/app-path/node_modules/next/dist/client/components/error-boundary.js":{"id":1223,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/error-boundary.js":{"id":1223,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/client/components/app-router.js":{"id":8095,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/app-router.js":{"id":8095,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/client/components/layout-router.js":{"id":3466,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/layout-router.js":{"id":3466,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/client/components/render-from-template-context.js":{"id":372,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/render-from-template-context.js":{"id":372,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"id":5721,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/static-generation-searchparams-bailout-provider.js":{"id":5721,"name":"*","chunks":["272:static/chunks/webpack-524fad5a962db320.js","253:static/chunks/bce60fc1-3138fc63e84359d9.js","961:static/chunks/961-8f7137d989a0e4e3.js"],"async":false},"/app-path/node_modules/next/font/google/target.css?{\\"path\\":\\"src/app/layout.tsx\\",\\"import\\":\\"Inter\\",\\"arguments\\":[{\\"subsets\\":[\\"latin\\"]}],\\"variableName\\":\\"inter\\"}":{"id":794,"name":"*","chunks":["185:static/chunks/app/layout-1a019a4780e5374b.js"],"async":false},"/app-path/src/app/globals.css":{"id":54,"name":"*","chunks":["185:static/chunks/app/layout-1a019a4780e5374b.js"],"async":false}},"entryCSSFiles":{"/app-path/src/app/page":[],"/app-path/src/app/layout":["static/css/decca5dbb1efb27a.css"]}}';`; -export const clientReferenceManifestWithImage = `{"ssrModuleMapping":{"2306":{"*":{"id":"7833","name":"*","chunks":[],"async":false}},"2353":{"*":{"id":"8709","name":"*","chunks":[],"async":false}},"3029":{"*":{"id":"9556","name":"*","chunks":[],"async":false}},"7330":{"*":{"id":"7734","name":"*","chunks":[],"async":false}},"8531":{"*":{"id":"9150","name":"*","chunks":[],"async":false}},"9180":{"*":{"id":"2698","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"/app-path/node_modules/next/dist/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/image-component.js":{"id":3029,"name":"*","chunks":["931:static/chunks/app/page-8d47763b987bba19.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/image-component.js":{"id":3029,"name":"*","chunks":["931:static/chunks/app/page-8d47763b987bba19.js"],"async":false},"/app-path/node_modules/next/font/google/target.css?{\"path\":\"src/app/layout.tsx\",\"import\":\"Inter\",\"arguments\":[{\"subsets\":[\"latin\"]}],\"variableName\":\"inter\"}":{"id":670,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false},"/app-path/src/app/globals.css":{"id":8410,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false}},"entryCSSFiles":{"/app-path/src/app/page":[],"/app-path/src/app/layout":["static/css/110a35ea7c81b899.css"]}}`; +export const clientReferenceManifestWithImage = `{"ssrModuleMapping":{"2306":{"*":{"id":"7833","name":"*","chunks":[],"async":false}},"2353":{"*":{"id":"8709","name":"*","chunks":[],"async":false}},"3029":{"*":{"id":"9556","name":"*","chunks":[],"async":false}},"7330":{"*":{"id":"7734","name":"*","chunks":[],"async":false}},"8531":{"*":{"id":"9150","name":"*","chunks":[],"async":false}},"9180":{"*":{"id":"2698","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"/app-path/node_modules/next/dist/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/image-component.js":{"id":3029,"name":"*","chunks":["931:static/chunks/app/page-8d47763b987bba19.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/image-component.js":{"id":3029,"name":"*","chunks":["931:static/chunks/app/page-8d47763b987bba19.js"],"async":false},"/app-path/node_modules/next/font/google/target.css?{"path":"src/app/layout.tsx","import":"Inter","arguments":[{"subsets":["latin"]}],"variableName":"inter"}":{"id":670,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false},"/app-path/src/app/globals.css":{"id":8410,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false}},"entryCSSFiles":{"/app-path/src/app/page":[],"/app-path/src/app/layout":["static/css/110a35ea7c81b899.css"]}}`; -export const clientReferenceManifestWithoutImage = `{"ssrModuleMapping":{"2306":{"*":{"id":"7833","name":"*","chunks":[],"async":false}},"2353":{"*":{"id":"8709","name":"*","chunks":[],"async":false}},"3029":{"*":{"id":"9556","name":"*","chunks":[],"async":false}},"7330":{"*":{"id":"7734","name":"*","chunks":[],"async":false}},"8531":{"*":{"id":"9150","name":"*","chunks":[],"async":false}},"9180":{"*":{"id":"2698","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"/app-path/node_modules/next/dist/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/font/google/target.css?{\"path\":\"src/app/layout.tsx\",\"import\":\"Inter\",\"arguments\":[{\"subsets\":[\"latin\"]}],\"variableName\":\"inter\"}":{"id":670,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false},"/app-path/src/app/globals.css":{"id":8410,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false}},"entryCSSFiles":{"/app-path/src/app/page":[],"/app-path/src/app/layout":["static/css/110a35ea7c81b899.css"]}}`; +export const clientReferenceManifestWithoutImage = `{"ssrModuleMapping":{"2306":{"*":{"id":"7833","name":"*","chunks":[],"async":false}},"2353":{"*":{"id":"8709","name":"*","chunks":[],"async":false}},"3029":{"*":{"id":"9556","name":"*","chunks":[],"async":false}},"7330":{"*":{"id":"7734","name":"*","chunks":[],"async":false}},"8531":{"*":{"id":"9150","name":"*","chunks":[],"async":false}},"9180":{"*":{"id":"2698","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"/app-path/node_modules/next/dist/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/app-router.js":{"id":2353,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/layout-router.js":{"id":9180,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/render-from-template-context.js":{"id":2306,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/static-generation-searchparams-bailout-provider.js":{"id":8531,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/dist/esm/client/components/error-boundary.js":{"id":7330,"name":"*","chunks":["272:static/chunks/webpack-76fd8b39fe914c29.js","253:static/chunks/bce60fc1-8c4748991edb1ec4.js","698:static/chunks/698-1321e6d13d35448d.js"],"async":false},"/app-path/node_modules/next/font/google/target.css?{"path":"src/app/layout.tsx","import":"Inter","arguments":[{"subsets":["latin"]}],"variableName":"inter"}":{"id":670,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false},"/app-path/src/app/globals.css":{"id":8410,"name":"*","chunks":["185:static/chunks/app/layout-09ef1f5c8b0e56d1.js"],"async":false}},"entryCSSFiles":{"/app-path/src/app/page":[],"/app-path/src/app/layout":["static/css/110a35ea7c81b899.css"]}}`; export const serverReferenceManifest: ActionManifest = { node: { diff --git a/src/frameworks/next/utils.ts b/src/frameworks/next/utils.ts index 3628a61b31b..a58aea86c7b 100644 --- a/src/frameworks/next/utils.ts +++ b/src/frameworks/next/utils.ts @@ -43,7 +43,7 @@ import { NPM_COMMAND_TIMEOUT_MILLIES } from "../constants"; import { execSync } from "child_process"; import { FirebaseError } from "../../error"; -export const I18N_SOURCE = /\/:nextInternalLocale(\([^\)]+\))?/; +export const I18N_SOURCE = /\/:nextInternalLocale(\([^)]+\))?/; /** * Remove escaping from characters used for Regex patch matching that Next.js diff --git a/src/gcp/devConnect.ts b/src/gcp/devConnect.ts index 2598cc88bfa..7a9a1e2f143 100644 --- a/src/gcp/devConnect.ts +++ b/src/gcp/devConnect.ts @@ -408,8 +408,8 @@ export function extractGitRepositoryLinkComponents(path: string): { connection: string | null; gitRepoLink: string | null; } { - const connectionMatch = /connections\/([^\/]+)/.exec(path); - const repositoryMatch = /gitRepositoryLinks\/([^\/]+)/.exec(path); + const connectionMatch = /connections\/([^/]+)/.exec(path); + const repositoryMatch = /gitRepositoryLinks\/([^/]+)/.exec(path); const connection = connectionMatch ? connectionMatch[1] : null; const gitRepoLink = repositoryMatch ? repositoryMatch[1] : null; diff --git a/src/mcp/prompts/apptesting/run_test.ts b/src/mcp/prompts/apptesting/run_test.ts index 1079d4659f0..9a7e02b0534 100644 --- a/src/mcp/prompts/apptesting/run_test.ts +++ b/src/mcp/prompts/apptesting/run_test.ts @@ -114,14 +114,14 @@ Here are a list of prerequisite steps that must be completed before running a te devices. Once the test has started, provide the developer a link to see the results of the test in the Firebase Console. - You should already know the value of \`appId\' and \`projectId\` from earlier (if you only know \`projectNumber\', + You should already know the value of \`appId\` and \`projectId\` from earlier (if you only know \`projectNumber\`, use the \`firebase_get_project\` tool to get \`projectId\`). \`packageName\` is the package name of the app we tested. The \`apptesting_run_test\` tool returns a response with field \`name\` in the form - projects/{projectNumber}/apps/{appId}/releases/{releaseId}/tests/{releaseTestId}. Extract the values for \'releaseId\' + projects/{projectNumber}/apps/{appId}/releases/{releaseId}/tests/{releaseTestId}. Extract the values for \`releaseId\` and \`releaseTestId\` and use provide a link to the results in the Firebase Console in the format: \`https://console.firebase.google.com/u/0/project/{projectId}/apptesting/app/android:{packageName}/releases/{releaseId}/tests/{releaseTestId}\`. - You can check the status of the test using the \`apptesting_check_status\` tool with \`release_test_name\' set to + You can check the status of the test using the \`apptesting_check_status\` tool with \`release_test_name\` set to the name of the release test returned by the \`run_test\` tool. `.trim(), }, diff --git a/src/mcp/prompts/core/deploy.ts b/src/mcp/prompts/core/deploy.ts index 361f996873c..7d236f15851 100644 --- a/src/mcp/prompts/core/deploy.ts +++ b/src/mcp/prompts/core/deploy.ts @@ -80,12 +80,12 @@ Follow the steps below taking note of any user instructions provided above. Example (No): "No, there are no dependencies or file structures that indicate the use of a server-side rendering framework." 4. If there is no \`firebase.json\` file, manually create one based on whether the app requires SSR: 4a. If the app requires SSR, configure Firebase App Hosting: - Create \`firebase.json\ with an "apphosting" configuration, setting backendId to the app's name in package.json: \`{"apphosting": {"backendId": ""}}\ + Create \`firebase.json\` with an "apphosting" configuration, setting backendId to the app's name in package.json: \`{"apphosting": {"backendId": ""}}\` 4b. If the app does NOT require SSR, configure Firebase Hosting: - Create \`firebase.json\ with a "hosting" configuration. Add a \`{"hosting": {"predeploy": ""}}\` config to build before deploying. + Create \`firebase.json\` with a "hosting" configuration. Add a \`{"hosting": {"predeploy": ""}}\` config to build before deploying. 5. Check if there is an active Firebase project for this environment (the \`firebase_get_environment\` tool may be helpful). If there is, provide the active project ID to the user and ask them if they want to proceed using that project. If there is not an active project, give the user two options: Provide an existing project ID or create a new project. Only use the list_projects tool on user request. Wait for their response before proceeding. 5a. If the user chooses to use an existing Firebase project, the \`firebase_list_projects\` tool may be helpful. Set the selected project as the active project (the \`firebase_update_environment\` tool may be helpful). - 5b. If the user chooses to create a new project, use the \`firebase_create_project \` tool. Then set the new project as the active project (the \`firebase_update_environment\` tool may be helpful). + 5b. If the user chooses to create a new project, use the \`firebase_create_project\` tool. Then set the new project as the active project (the \`firebase_update_environment\` tool may be helpful). 6. If firebase.json contains an "apphosting" configuration, check if a backend exists matching the provided backendId (the \`apphosting_list_backends\` tool may be helpful). If it doesn't exist, create one by running the \`${firebaseCliCommand} apphosting:backends:create --backend --primary-region us-central1 --root-dir .\` shell. 7. Only after making sure Firebase has been initialized, run the \`${firebaseCliCommand} deploy\` shell command to perform the deploy. This may take a few minutes. diff --git a/src/mcp/resources/guides/init_ai.ts b/src/mcp/resources/guides/init_ai.ts index d50fc09910c..c97c05be17f 100644 --- a/src/mcp/resources/guides/init_ai.ts +++ b/src/mcp/resources/guides/init_ai.ts @@ -37,7 +37,7 @@ Before starting, ensure you have **Node.js 16+** and npm installed. Install them ## Firebase Setup Instructions -### 1\. Understand the Application Setup +### 1. Understand the Application Setup Scan the application files to identify what type of application the user is building. Ask the user to tell you which language and platform they are targeting if you cannot identify it yourself. @@ -50,12 +50,12 @@ The following mobile and web applications are supported. Let the user know their Take the following actions depending on the language and platform or framework that is identified: -- Android Platform \-\> Set up Firebase AI Logic -- Web Platform \-\> Set up Firebase AI Logic -- Flutter Platform \-\> Set up Firebase AI Logic. Always do the subsequent firebase_init call using the web app -- Unsupported Platform \-\> Direct the user to Firebase Docs to learn how to set up AI Logic for their application (share this link with the user https://firebase.google.com/docs/ai-logic/get-started?api=dev) +- Android Platform -> Set up Firebase AI Logic +- Web Platform -> Set up Firebase AI Logic +- Flutter Platform -> Set up Firebase AI Logic. Always do the subsequent firebase_init call using the web app +- Unsupported Platform -> Direct the user to Firebase Docs to learn how to set up AI Logic for their application (share this link with the user https://firebase.google.com/docs/ai-logic/get-started?api=dev) -### 2\. Set up Firebase AI Logic +### 2. Set up Firebase AI Logic #### Set up the Firebase AI Logic Backend @@ -65,11 +65,11 @@ Take the following actions depending on the language and platform or framework t - 1. In your project-level \`/build.gradle.kts\` file, add the plugin to the plugins block: id("com.google.gms.google-services") version "4.4.2" apply false - 2. In your **app-level** \`/app/build.gradle.kts\` file, apply the plugin: id("com.google.gms.google-services") -### 3\. Implement AI Features +### 3. Implement AI Features #### Gather Building Blocks for Code Generation - Identify the correct initialization code snippet from the "Initialization Code References" section based on the language, platform, or framework used in the developer's app. - - Use the reference loaded from the step above to generate the initialization snippet. PLEASE USE THE EXACT SNIPPET AS A STARTING POINT\! + - Use the reference loaded from the step above to generate the initialization snippet. PLEASE USE THE EXACT SNIPPET AS A STARTING POINT! - For Android apps, always include the following imports. do not forget or modify them - import com.google.firebase.Firebase - import com.google.firebase.ai.ai @@ -103,7 +103,7 @@ Take the following actions depending on the language and platform or framework t - Now implement the feature according to the plan you put together. Do not stray away from the instructions provided to you. Always re-read them fully and consult them if you run into any issues. - ***DO NOT EXECUTE THE CODE YET. PERFORM THE VALIDATIONS IN STEP 4 BEFORE HANDING THE SESSION BACK OVER TO THE USER*** -### 4\. Validate Implementation +### 4. Validate Implementation #### Perform the following checks before handing the session back to the user. - Walk through the validation steps one-by-one. Analyze your instructions and the code you generated. Confirm you did not make any mistakes. If you made a mistake, FIX IT. @@ -117,7 +117,7 @@ Take the following actions depending on the language and platform or framework t - Confirmation that the backend is correctly configured to use the Google AI backend. - Confirmation that the gemini model is correctly set based on the feature the user is implementing -### 5\. Code Snippet References +### 5. Code Snippet References #### Initialization Code References