firebase-tools 12.2.1 → 12.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.command = void 0;
3
+ exports.hostingChannelDeployAction = exports.command = void 0;
4
4
  const colorette_1 = require("colorette");
5
5
  const command_1 = require("../command");
6
6
  const error_1 = require("../error");
@@ -25,7 +25,8 @@ exports.command = new command_1.Command("hosting:channel:deploy [channelId]")
25
25
  .before(requireConfig_1.requireConfig)
26
26
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
27
27
  .before(requireHostingSite_1.requireHostingSite)
28
- .action(async (channelId, options) => {
28
+ .action(hostingChannelDeployAction);
29
+ async function hostingChannelDeployAction(channelId, options) {
29
30
  const projectId = (0, projectUtils_1.needProjectId)(options);
30
31
  if (options.open) {
31
32
  throw new error_1.FirebaseError("open is not yet implemented");
@@ -122,7 +123,8 @@ exports.command = new command_1.Command("hosting:channel:deploy [channelId]")
122
123
  (0, utils_1.logLabeledSuccess)(LOG_TAG, `Channel URL (${(0, colorette_1.bold)(d.site || d.target || "")}): ${d.url} ${expires}${version}`);
123
124
  });
124
125
  return deploys;
125
- });
126
+ }
127
+ exports.hostingChannelDeployAction = hostingChannelDeployAction;
126
128
  async function syncAuthState(projectId, sites) {
127
129
  const siteNames = sites.map((d) => d.site);
128
130
  const urlNames = sites.map((d) => d.url);
@@ -52,7 +52,7 @@ const deploy = async function (targetNames, options, customContext = {}) {
52
52
  const config = options.config.get("hosting");
53
53
  if (Array.isArray(config) ? config.some((it) => it.source) : config.source) {
54
54
  experiments.assertEnabled("webframeworks", "deploy a web framework from source");
55
- await (0, frameworks_1.prepareFrameworks)(targetNames, context, options);
55
+ await (0, frameworks_1.prepareFrameworks)("deploy", targetNames, context, options);
56
56
  }
57
57
  }
58
58
  if (targetNames.includes("hosting") && (0, prepare_1.hasPinnedFunctions)(options)) {
@@ -146,13 +146,13 @@ async function signUp(state, reqBody, ctx) {
146
146
  (0, errors_1.assert)(state.enableAnonymousUser, "ADMIN_ONLY_OPERATION");
147
147
  }
148
148
  }
149
- if (reqBody.email) {
149
+ if (typeof reqBody.email === "string") {
150
150
  (0, errors_1.assert)((0, utils_1.isValidEmailAddress)(reqBody.email), "INVALID_EMAIL");
151
151
  const email = (0, utils_1.canonicalizeEmailAddress)(reqBody.email);
152
152
  (0, errors_1.assert)(!state.getUserByEmail(email), "EMAIL_EXISTS");
153
153
  updates.email = email;
154
154
  }
155
- if (reqBody.password) {
155
+ if (typeof reqBody.password === "string") {
156
156
  (0, errors_1.assert)(reqBody.password.length >= PASSWORD_MIN_LENGTH, `WEAK_PASSWORD : Password should be at least ${PASSWORD_MIN_LENGTH} characters`);
157
157
  updates.salt = "fakeSalt" + (0, utils_1.randomId)(20);
158
158
  updates.passwordHash = hashPassword(reqBody.password, updates.salt);
@@ -288,7 +288,7 @@ async function emulatorExec(script, options) {
288
288
  let deprecationNotices;
289
289
  try {
290
290
  const showUI = !!options.ui;
291
- ({ deprecationNotices } = await controller.startAll(options, showUI));
291
+ ({ deprecationNotices } = await controller.startAll(options, showUI, true));
292
292
  exitCode = await runScript(script, extraEnv);
293
293
  await controller.onExit(options);
294
294
  }
@@ -116,6 +116,10 @@ function shouldStart(options, name) {
116
116
  }
117
117
  exports.shouldStart = shouldStart;
118
118
  function findExportMetadata(importPath) {
119
+ const pathExists = fs.existsSync(importPath);
120
+ if (!pathExists) {
121
+ throw new error_1.FirebaseError(`Directory "${importPath}" does not exist.`);
122
+ }
119
123
  const pathIsDirectory = fs.lstatSync(importPath).isDirectory();
120
124
  if (!pathIsDirectory) {
121
125
  return;
@@ -151,7 +155,7 @@ function findExportMetadata(importPath) {
151
155
  return metadata;
152
156
  }
153
157
  }
154
- async function startAll(options, showUI = true) {
158
+ async function startAll(options, showUI = true, runningTestScript = false) {
155
159
  var _a, _b, _c, _d, _e, _f, _g;
156
160
  const targets = filterEmulatorTargets(options);
157
161
  options.targets = targets;
@@ -291,7 +295,7 @@ async function startAll(options, showUI = true) {
291
295
  });
292
296
  }
293
297
  }
294
- await (0, frameworks_1.prepareFrameworks)(targets, options, options, emulators);
298
+ await (0, frameworks_1.prepareFrameworks)(runningTestScript ? "test" : "emulate", targets, undefined, options, emulators);
295
299
  }
296
300
  const projectDir = (options.extDevDir || options.config.projectDir);
297
301
  if (shouldStart(options, types_1.Emulators.FUNCTIONS)) {
@@ -272,6 +272,9 @@ function getSignatureType(def) {
272
272
  if (def.httpsTrigger || def.blockingTrigger) {
273
273
  return "http";
274
274
  }
275
+ if (def.platform === "gcfv2" && def.schedule) {
276
+ return "http";
277
+ }
275
278
  return def.platform === "gcfv2" ? "cloudevent" : "event";
276
279
  }
277
280
  exports.getSignatureType = getSignatureType;
@@ -44,7 +44,7 @@ async function init(setup, config) {
44
44
  }
45
45
  exports.init = init;
46
46
  async function build(dir, configuration) {
47
- const { targets, serverTarget, serveOptimizedImages, locales, baseHref } = await (0, utils_2.getBuildConfig)(dir, configuration);
47
+ const { targets, serverTarget, serveOptimizedImages, locales, baseHref: baseUrl, } = await (0, utils_2.getBuildConfig)(dir, configuration);
48
48
  await (0, utils_1.warnIfCustomBuildScript)(dir, exports.name, DEFAULT_BUILD_SCRIPT);
49
49
  for (const target of targets) {
50
50
  const cli = (0, utils_1.getNodeModuleBin)("ng", dir);
@@ -60,12 +60,12 @@ async function build(dir, configuration) {
60
60
  ? []
61
61
  : [
62
62
  {
63
- source: path_1.posix.join(baseHref, "**"),
64
- destination: path_1.posix.join(baseHref, "index.html"),
63
+ source: path_1.posix.join(baseUrl, "**"),
64
+ destination: path_1.posix.join(baseUrl, "index.html"),
65
65
  },
66
66
  ];
67
67
  const i18n = !!locales;
68
- return { wantsBackend, i18n, rewrites };
68
+ return { wantsBackend, i18n, rewrites, baseUrl };
69
69
  }
70
70
  exports.build = build;
71
71
  async function getDevModeHandle(dir, configuration) {
@@ -73,7 +73,7 @@ async function getDevModeHandle(dir, configuration) {
73
73
  const { serveTarget } = await (0, utils_2.getContext)(dir, configuration);
74
74
  if (!serveTarget)
75
75
  throw new Error("Could not find the serveTarget");
76
- const host = new Promise((resolve) => {
76
+ const host = new Promise((resolve, reject) => {
77
77
  const cli = (0, utils_1.getNodeModuleBin)("ng", dir);
78
78
  const serve = (0, cross_spawn_1.spawn)(cli, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], {
79
79
  cwd: dir,
@@ -87,6 +87,7 @@ async function getDevModeHandle(dir, configuration) {
87
87
  serve.stderr.on("data", (data) => {
88
88
  process.stderr.write(data);
89
89
  });
90
+ serve.on("exit", reject);
90
91
  });
91
92
  return (0, utils_1.simpleProxy)(await host);
92
93
  }
@@ -114,7 +115,7 @@ async function getValidBuildTargets(purpose, dir) {
114
115
  const validTargetNames = new Set(["development", "production"]);
115
116
  try {
116
117
  const { workspaceProject, browserTarget, serverTarget, serveTarget } = await (0, utils_2.getContext)(dir);
117
- const { target } = ((purpose === "serve" && serveTarget) || serverTarget || browserTarget);
118
+ const { target } = ((purpose === "emulate" && serveTarget) || serverTarget || browserTarget);
118
119
  const workspaceTarget = workspaceProject.targets.get(target);
119
120
  Object.keys(workspaceTarget.configurations || {}).forEach((it) => validTargetNames.add(it));
120
121
  }
@@ -134,7 +135,7 @@ exports.shouldUseDevModeHandle = shouldUseDevModeHandle;
134
135
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir, configuration) {
135
136
  var _a;
136
137
  var _b;
137
- const { packageJson, serverOutputPath, browserOutputPath, defaultLocale, serverLocales, browserLocales, bundleDependencies, externalDependencies, baseHref: baseUrl, serveOptimizedImages, } = await (0, utils_2.getServerConfig)(sourceDir, configuration);
138
+ const { packageJson, serverOutputPath, browserOutputPath, defaultLocale, serverLocales, browserLocales, bundleDependencies, externalDependencies, baseHref, serveOptimizedImages, } = await (0, utils_2.getServerConfig)(sourceDir, configuration);
138
139
  const dotEnv = { __NG_BROWSER_OUTPUT_PATH__: browserOutputPath };
139
140
  let rewriteSource = undefined;
140
141
  await Promise.all([
@@ -187,8 +188,8 @@ exports.handle = function(req,res) {
187
188
  }
188
189
  else {
189
190
  bootstrapScript = `exports.handle = (res, req) => req.sendStatus(404);\n`;
190
- rewriteSource = path_1.posix.join(baseUrl, "__image__");
191
+ rewriteSource = path_1.posix.join(baseHref, "__image__");
191
192
  }
192
- return { bootstrapScript, packageJson, baseUrl, dotEnv, rewriteSource };
193
+ return { bootstrapScript, packageJson, dotEnv, rewriteSource };
193
194
  }
194
195
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
@@ -21,7 +21,7 @@ async function discover(dir) {
21
21
  return;
22
22
  const { output, publicDir: publicDirectory } = await (0, utils_2.getConfig)(dir);
23
23
  return {
24
- mayWantBackend: output === "server",
24
+ mayWantBackend: output !== "static",
25
25
  publicDirectory,
26
26
  };
27
27
  }
@@ -31,18 +31,19 @@ async function build(cwd) {
31
31
  const cli = (0, utils_1.getNodeModuleBin)("astro", cwd);
32
32
  await (0, utils_1.warnIfCustomBuildScript)(cwd, exports.name, DEFAULT_BUILD_SCRIPT);
33
33
  const { output, adapter } = await (0, utils_2.getConfig)(cwd);
34
- if (output === "server" && (adapter === null || adapter === void 0 ? void 0 : adapter.name) !== "@astrojs/node") {
35
- throw new error_1.FirebaseError("Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter.");
34
+ const wantsBackend = output !== "static";
35
+ if (wantsBackend && (adapter === null || adapter === void 0 ? void 0 : adapter.name) !== "@astrojs/node") {
36
+ throw new error_1.FirebaseError("Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter in middleware mode. https://docs.astro.build/en/guides/integrations-guide/node/");
36
37
  }
37
38
  const build = (0, cross_spawn_1.sync)(cli, ["build"], { cwd, stdio: "inherit" });
38
39
  if (build.status !== 0)
39
40
  throw new error_1.FirebaseError("Unable to build your Astro app");
40
- return { wantsBackend: output === "server" };
41
+ return { wantsBackend };
41
42
  }
42
43
  exports.build = build;
43
44
  async function ɵcodegenPublicDirectory(root, dest) {
44
45
  const { outDir, output } = await (0, utils_2.getConfig)(root);
45
- const assetPath = (0, path_1.join)(root, outDir, output === "server" ? "client" : "");
46
+ const assetPath = (0, path_1.join)(root, outDir, output !== "static" ? "client" : "");
46
47
  await (0, fs_extra_1.copy)(assetPath, dest);
47
48
  }
48
49
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
@@ -57,7 +58,7 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
57
58
  }
58
59
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
59
60
  async function getDevModeHandle(cwd) {
60
- const host = new Promise((resolve) => {
61
+ const host = new Promise((resolve, reject) => {
61
62
  const cli = (0, utils_1.getNodeModuleBin)("astro", cwd);
62
63
  const serve = (0, cross_spawn_1.spawn)(cli, ["dev"], { cwd });
63
64
  serve.stdout.on("data", (data) => {
@@ -69,6 +70,7 @@ async function getDevModeHandle(cwd) {
69
70
  serve.stderr.on("data", (data) => {
70
71
  process.stderr.write(data);
71
72
  });
73
+ serve.on("exit", reject);
72
74
  });
73
75
  return (0, utils_1.simpleProxy)(await host);
74
76
  }
@@ -8,7 +8,6 @@ const cross_spawn_1 = require("cross-spawn");
8
8
  const promises_1 = require("fs/promises");
9
9
  const fs_extra_1 = require("fs-extra");
10
10
  const process = require("node:process");
11
- const semver = require("semver");
12
11
  const glob = require("glob");
13
12
  const projectUtils_1 = require("../projectUtils");
14
13
  const config_1 = require("../hosting/config");
@@ -30,6 +29,8 @@ Object.defineProperty(exports, "WebFrameworks", { enumerable: true, get: functio
30
29
  const utils_2 = require("../utils");
31
30
  const ensureTargeted_1 = require("../functions/ensureTargeted");
32
31
  const util_1 = require("util");
32
+ const projectPath_1 = require("../projectPath");
33
+ const logger_1 = require("../logger");
33
34
  async function discover(dir, warn = true) {
34
35
  const allFrameworkTypes = [
35
36
  ...new Set(Object.values(constants_2.WebFrameworks).map(({ type }) => type)),
@@ -71,21 +72,17 @@ function memoizeBuild(dir, build, deps, target) {
71
72
  BUILD_MEMO.set(key, value);
72
73
  return value;
73
74
  }
74
- async function prepareFrameworks(targetNames, context, options, emulators = []) {
75
- var _a, _b, _c, _d, _e;
76
- var _f, _g, _h, _j, _k;
77
- const nodeVersion = process.version;
78
- if (!semver.satisfies(nodeVersion, ">=16.0.0")) {
79
- throw new error_1.FirebaseError(`The frameworks awareness feature requires Node.JS >= 16 and npm >= 8 in order to work correctly, due to some of the downstream dependencies. Please upgrade your version of Node.JS, reinstall firebase-tools, and give it another go.`);
80
- }
81
- const project = (0, projectUtils_1.needProjectId)(context);
82
- const { projectRoot } = options;
75
+ async function prepareFrameworks(purpose, targetNames, context, options, emulators = []) {
76
+ var _a, _b, _c, _d, _e, _f;
77
+ var _g, _h, _j, _k, _l;
78
+ const project = (0, projectUtils_1.needProjectId)(context || options);
79
+ const projectRoot = (0, projectPath_1.resolveProjectPath)(options, ".");
83
80
  const account = (0, auth_1.getProjectDefaultAccount)(projectRoot);
84
81
  if (!options.site) {
85
82
  try {
86
83
  await (0, requireHostingSite_1.requireHostingSite)(options);
87
84
  }
88
- catch (_l) {
85
+ catch (_m) {
89
86
  options.site = project;
90
87
  }
91
88
  }
@@ -189,13 +186,17 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
189
186
  }
190
187
  const { framework, mayWantBackend, publicDirectory } = results;
191
188
  const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = constants_2.WebFrameworks[framework];
192
- console.log(`\n${(0, utils_1.frameworksCallToAction)(constants_2.SupportLevelWarnings[support](name), docsUrl, " ")}\n`);
189
+ logger_1.logger.info(`\n${(0, utils_1.frameworksCallToAction)(constants_2.SupportLevelWarnings[support](name), docsUrl, " ")}\n`);
193
190
  const hostingEmulatorInfo = emulators.find((e) => e.name === types_1.Emulators.HOSTING);
194
- const buildTargetPurpose = context._name === "deploy" ? "deploy" : context._name === "emulators:exec" ? "test" : "serve";
195
- const validBuildTargets = await getValidBuildTargets(buildTargetPurpose, getProjectPath());
196
- const frameworksBuildTarget = (0, utils_1.getFrameworksBuildTarget)(buildTargetPurpose, validBuildTargets);
197
- const useDevModeHandle = await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath());
191
+ const validBuildTargets = await getValidBuildTargets(purpose, getProjectPath());
192
+ const frameworksBuildTarget = (0, utils_1.getFrameworksBuildTarget)(purpose, validBuildTargets);
193
+ const useDevModeHandle = purpose !== "deploy" &&
194
+ (await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath()));
198
195
  let codegenFunctionsDirectory;
196
+ let baseUrl = "";
197
+ const rewrites = [];
198
+ const redirects = [];
199
+ const headers = [];
199
200
  const devModeHandle = useDevModeHandle &&
200
201
  getDevModeHandle &&
201
202
  (await getDevModeHandle(getProjectPath(), frameworksBuildTarget, hostingEmulatorInfo));
@@ -208,13 +209,19 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
208
209
  }
209
210
  else {
210
211
  const buildResult = await memoizeBuild(getProjectPath(), build, [firebaseDefaults, frameworksBuildTarget], frameworksBuildTarget);
211
- const { wantsBackend = false, rewrites = [], redirects = [], headers = [], trailingSlash, i18n = false, } = buildResult || {};
212
- config.rewrites.push(...rewrites);
213
- config.redirects.push(...redirects);
214
- config.headers.push(...headers);
215
- (_d = config.trailingSlash) !== null && _d !== void 0 ? _d : (config.trailingSlash = trailingSlash);
212
+ const { wantsBackend = false, trailingSlash, i18n = false } = buildResult || {};
213
+ if (buildResult) {
214
+ baseUrl = (_d = buildResult.baseUrl) !== null && _d !== void 0 ? _d : baseUrl;
215
+ if (buildResult.headers)
216
+ headers.push(...buildResult.headers);
217
+ if (buildResult.rewrites)
218
+ rewrites.push(...buildResult.rewrites);
219
+ if (buildResult.redirects)
220
+ redirects.push(...buildResult.redirects);
221
+ }
222
+ (_e = config.trailingSlash) !== null && _e !== void 0 ? _e : (config.trailingSlash = trailingSlash);
216
223
  if (i18n)
217
- (_e = config.i18n) !== null && _e !== void 0 ? _e : (config.i18n = { root: constants_2.I18N_ROOT });
224
+ (_f = config.i18n) !== null && _f !== void 0 ? _f : (config.i18n = { root: constants_2.I18N_ROOT });
218
225
  if (await (0, fs_extra_1.pathExists)(hostingDist))
219
226
  await (0, promises_1.rm)(hostingDist, { recursive: true });
220
227
  await (0, fs_extra_1.mkdirp)(hostingDist);
@@ -232,7 +239,7 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
232
239
  firebaseDefaults._authTokenSyncURL = "/__session";
233
240
  process.env.__FIREBASE_DEFAULTS__ = JSON.stringify(firebaseDefaults);
234
241
  }
235
- if (context.hostingChannel) {
242
+ if (context === null || context === void 0 ? void 0 : context.hostingChannel) {
236
243
  experiments.assertEnabled("pintags", "deploy an app that requires a backend to a preview channel");
237
244
  }
238
245
  const codebase = `firebase-frameworks-${site}`;
@@ -246,10 +253,7 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
246
253
  codebase,
247
254
  },
248
255
  ]);
249
- if (!experiments.isEnabled("pintags") ||
250
- context._name === "serve" ||
251
- context._name === "emulators:start" ||
252
- context._name === "emulators:exec") {
256
+ if (!experiments.isEnabled("pintags") || purpose !== "deploy") {
253
257
  if (!targetNames.includes("functions")) {
254
258
  targetNames.unshift("functions");
255
259
  }
@@ -273,38 +277,41 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
273
277
  else {
274
278
  await (0, fs_extra_1.mkdirp)(functionsDist);
275
279
  }
276
- const { packageJson, bootstrapScript, frameworksEntry = framework, baseUrl = "", dotEnv = {}, rewriteSource = path_1.posix.join(baseUrl, "**"), } = await codegenFunctionsDirectory(getProjectPath(), functionsDist, frameworksBuildTarget);
277
- config.rewrites = [
278
- {
279
- source: rewriteSource,
280
- function: {
281
- functionId,
282
- region: ssrRegion,
283
- pinTag: experiments.isEnabled("pintags"),
284
- },
280
+ const { packageJson, bootstrapScript, frameworksEntry = framework, dotEnv = {}, rewriteSource, } = await codegenFunctionsDirectory(getProjectPath(), functionsDist, frameworksBuildTarget);
281
+ const rewrite = {
282
+ source: rewriteSource || path_1.posix.join(baseUrl, "**"),
283
+ function: {
284
+ functionId,
285
+ region: ssrRegion,
286
+ pinTag: experiments.isEnabled("pintags"),
285
287
  },
286
- ...config.rewrites,
287
- ];
288
+ };
289
+ if (rewriteSource) {
290
+ config.rewrites.unshift(rewrite);
291
+ }
292
+ else {
293
+ rewrites.push(rewrite);
294
+ }
288
295
  process.env.__FIREBASE_FRAMEWORKS_ENTRY__ = frameworksEntry;
289
296
  packageJson.main = "server.js";
290
297
  packageJson.dependencies || (packageJson.dependencies = {});
291
- (_f = packageJson.dependencies)["firebase-frameworks"] || (_f["firebase-frameworks"] = constants_2.FIREBASE_FRAMEWORKS_VERSION);
292
- (_g = packageJson.dependencies)["firebase-functions"] || (_g["firebase-functions"] = constants_2.FIREBASE_FUNCTIONS_VERSION);
293
- (_h = packageJson.dependencies)["firebase-admin"] || (_h["firebase-admin"] = constants_2.FIREBASE_ADMIN_VERSION);
298
+ (_g = packageJson.dependencies)["firebase-frameworks"] || (_g["firebase-frameworks"] = constants_2.FIREBASE_FRAMEWORKS_VERSION);
299
+ (_h = packageJson.dependencies)["firebase-functions"] || (_h["firebase-functions"] = constants_2.FIREBASE_FUNCTIONS_VERSION);
300
+ (_j = packageJson.dependencies)["firebase-admin"] || (_j["firebase-admin"] = constants_2.FIREBASE_ADMIN_VERSION);
294
301
  packageJson.engines || (packageJson.engines = {});
295
302
  const validEngines = constants_2.VALID_ENGINES.node.filter((it) => it <= constants_2.NODE_VERSION);
296
303
  const engine = validEngines[validEngines.length - 1] || constants_2.VALID_ENGINES.node[0];
297
304
  if (engine !== constants_2.NODE_VERSION) {
298
305
  (0, utils_2.logWarning)(`This integration expects Node version ${(0, utils_1.conjoinOptions)(constants_2.VALID_ENGINES.node, "or")}. You're running version ${constants_2.NODE_VERSION}, problems may be encountered.`);
299
306
  }
300
- (_j = packageJson.engines).node || (_j.node = engine.toString());
307
+ (_k = packageJson.engines).node || (_k.node = engine.toString());
301
308
  delete packageJson.scripts;
302
309
  delete packageJson.devDependencies;
303
310
  const bundledDependencies = packageJson.bundledDependencies || {};
304
311
  if (Object.keys(bundledDependencies).length) {
305
312
  (0, utils_2.logWarning)("Bundled dependencies aren't supported in Cloud Functions, converting to dependencies.");
306
313
  for (const [dep, version] of Object.entries(bundledDependencies)) {
307
- (_k = packageJson.dependencies)[dep] || (_k[dep] = version);
314
+ (_l = packageJson.dependencies)[dep] || (_l[dep] = version);
308
315
  }
309
316
  delete packageJson.bundledDependencies;
310
317
  }
@@ -376,13 +383,18 @@ ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\
376
383
  await (0, promises_1.rm)(functionsDist, { recursive: true });
377
384
  }
378
385
  }
386
+ const ourConfigShouldComeFirst = !["", "/"].includes(baseUrl);
387
+ const operation = ourConfigShouldComeFirst ? "unshift" : "push";
388
+ config.rewrites[operation](...rewrites);
389
+ config.redirects[operation](...redirects);
390
+ config.headers[operation](...headers);
379
391
  if (firebaseDefaults) {
380
392
  const encodedDefaults = Buffer.from(JSON.stringify(firebaseDefaults)).toString("base64url");
381
393
  const expires = new Date(new Date().getTime() + 60000000000);
382
394
  const sameSite = "Strict";
383
395
  const path = `/`;
384
396
  config.headers.push({
385
- source: "**/*.[jt]s",
397
+ source: path_1.posix.join(baseUrl, "**", "*.[jt]s"),
386
398
  headers: [
387
399
  {
388
400
  key: "Set-Cookie",
@@ -392,10 +404,7 @@ ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\
392
404
  });
393
405
  }
394
406
  }
395
- if (process.env.DEBUG) {
396
- console.log("Effective firebase.json:");
397
- console.log(JSON.stringify(configs, undefined, 2));
398
- }
407
+ logger_1.logger.debug("[web frameworks] effective firebase.json: ", JSON.stringify({ hosting: configs, functions: options.config.get("functions") }, undefined, 2));
399
408
  BUILD_MEMO.clear();
400
409
  delete process.env.__FIREBASE_DEFAULTS__;
401
410
  delete process.env.__FIREBASE_FRAMEWORKS_ENTRY__;
@@ -22,6 +22,7 @@ const utils_2 = require("./utils");
22
22
  const constants_1 = require("../constants");
23
23
  const constants_2 = require("./constants");
24
24
  const api_1 = require("../../hosting/api");
25
+ const logger_1 = require("../../logger");
25
26
  const DEFAULT_BUILD_SCRIPT = ["next build"];
26
27
  const PUBLIC_DIR = "public";
27
28
  exports.name = "Next.js";
@@ -58,7 +59,7 @@ async function build(dir) {
58
59
  throw e;
59
60
  });
60
61
  const reasonsForBackend = new Set();
61
- const { distDir, trailingSlash, basePath } = await getConfig(dir);
62
+ const { distDir, trailingSlash, basePath: baseUrl } = await getConfig(dir);
62
63
  if (await (0, utils_2.isUsingMiddleware)((0, path_1.join)(dir, distDir), false)) {
63
64
  reasonsForBackend.add("middleware");
64
65
  }
@@ -103,7 +104,7 @@ async function build(dir) {
103
104
  (0, utils_1.readJSON)((0, path_1.join)(dir, distDir, constants_2.APP_PATH_ROUTES_MANIFEST)).catch(() => undefined),
104
105
  ]);
105
106
  if (appPathRoutesManifest) {
106
- const headersFromMetaFiles = await (0, utils_2.getHeadersFromMetaFiles)(dir, distDir, basePath, appPathRoutesManifest);
107
+ const headersFromMetaFiles = await (0, utils_2.getHeadersFromMetaFiles)(dir, distDir, baseUrl, appPathRoutesManifest);
107
108
  headers.push(...headersFromMetaFiles);
108
109
  if (appPathsManifest) {
109
110
  const unrenderedServerComponents = (0, utils_2.getNonStaticServerComponents)(appPathsManifest, appPathRoutesManifest, prerenderedRoutes, dynamicRoutes);
@@ -144,15 +145,17 @@ async function build(dir) {
144
145
  }));
145
146
  const wantsBackend = reasonsForBackend.size > 0;
146
147
  if (wantsBackend) {
147
- const numberOfReasonsToList = process.env.DEBUG ? Infinity : DEFAULT_NUMBER_OF_REASONS_TO_LIST;
148
- console.log("Building a Cloud Function to run this application. This is needed due to:");
149
- for (const reason of Array.from(reasonsForBackend).slice(0, numberOfReasonsToList)) {
150
- console.log(` • ${reason}`);
148
+ logger_1.logger.info("Building a Cloud Function to run this application. This is needed due to:");
149
+ for (const reason of Array.from(reasonsForBackend).slice(0, DEFAULT_NUMBER_OF_REASONS_TO_LIST)) {
150
+ logger_1.logger.info(` ${reason}`);
151
151
  }
152
- if (reasonsForBackend.size > numberOfReasonsToList) {
153
- console.log(` • and ${reasonsForBackend.size - numberOfReasonsToList} other reasons, use --debug to see more`);
152
+ for (const reason of Array.from(reasonsForBackend).slice(DEFAULT_NUMBER_OF_REASONS_TO_LIST)) {
153
+ logger_1.logger.debug(` • ${reason}`);
154
154
  }
155
- console.log("");
155
+ if (reasonsForBackend.size > DEFAULT_NUMBER_OF_REASONS_TO_LIST && !process.env.DEBUG) {
156
+ logger_1.logger.info(` • and ${reasonsForBackend.size - DEFAULT_NUMBER_OF_REASONS_TO_LIST} other reasons, use --debug to see more`);
157
+ }
158
+ logger_1.logger.info("");
156
159
  }
157
160
  const i18n = !!nextjsI18n;
158
161
  return {
@@ -162,6 +165,7 @@ async function build(dir) {
162
165
  rewrites,
163
166
  trailingSlash,
164
167
  i18n,
168
+ baseUrl,
165
169
  };
166
170
  }
167
171
  exports.build = build;
@@ -226,13 +230,11 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
226
230
  await Promise.all(Object.entries(routesToCopy).map(async ([path, route]) => {
227
231
  var _a, _b;
228
232
  if (route.initialRevalidateSeconds) {
229
- if (process.env.DEBUG)
230
- console.log(`skipping ${path} due to revalidate`);
233
+ logger_1.logger.debug(`skipping ${path} due to revalidate`);
231
234
  return;
232
235
  }
233
236
  if (pathsUsingsFeaturesNotSupportedByHosting.some((it) => path.match(it))) {
234
- if (process.env.DEBUG)
235
- console.log(`skipping ${path} due to it matching an unsupported rewrite/redirect/header or middlware`);
237
+ logger_1.logger.debug(`skipping ${path} due to it matching an unsupported rewrite/redirect/header or middlware`);
236
238
  return;
237
239
  }
238
240
  const appPathRoute = route.srcRoute && ((_a = appPathRoutesEntries.find(([, it]) => it === route.srcRoute)) === null || _a === void 0 ? void 0 : _a[0]);
@@ -245,8 +247,7 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
245
247
  !matchingI18nDomain.locales ||
246
248
  matchingI18nDomain.locales.includes(locale);
247
249
  if (!includeOnThisDomain) {
248
- if (process.env.DEBUG)
249
- console.log(`skipping ${path} since it is for a locale not deployed on this domain`);
250
+ logger_1.logger.debug(`skipping ${path} since it is for a locale not deployed on this domain`);
250
251
  return;
251
252
  }
252
253
  const sourcePartsOrIndex = sourceParts.length > 0 ? sourceParts : ["index"];
@@ -293,7 +294,7 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
293
294
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
294
295
  const BUNDLE_NEXT_CONFIG_TIMEOUT = 10000;
295
296
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
296
- const { distDir, basePath } = await getConfig(sourceDir);
297
+ const { distDir } = await getConfig(sourceDir);
297
298
  const packageJson = await (0, utils_1.readJSON)((0, path_1.join)(sourceDir, "package.json"));
298
299
  if ((0, fs_1.existsSync)((0, path_1.join)(sourceDir, "next.config.js"))) {
299
300
  try {
@@ -345,7 +346,7 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
345
346
  }
346
347
  await (0, fs_extra_1.mkdirp)((0, path_1.join)(destDir, distDir));
347
348
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir), (0, path_1.join)(destDir, distDir));
348
- return { packageJson, frameworksEntry: "next.js", basePath };
349
+ return { packageJson, frameworksEntry: "next.js" };
349
350
  }
350
351
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
351
352
  async function getDevModeHandle(dir, _, hostingEmulatorInfo) {
@@ -30,7 +30,7 @@ exports.discover = discover;
30
30
  async function build(cwd) {
31
31
  await (0, utils_1.warnIfCustomBuildScript)(cwd, exports.name, DEFAULT_BUILD_SCRIPT);
32
32
  const cli = (0, utils_1.getNodeModuleBin)("nuxt", cwd);
33
- const { ssr: wantsBackend, app: { baseURL }, } = await getConfig(cwd);
33
+ const { ssr: wantsBackend, app: { baseURL: baseUrl }, } = await getConfig(cwd);
34
34
  const command = wantsBackend ? ["build"] : ["generate"];
35
35
  const build = (0, cross_spawn_1.sync)(cli, command, {
36
36
  cwd,
@@ -43,11 +43,11 @@ async function build(cwd) {
43
43
  ? []
44
44
  : [
45
45
  {
46
- source: path_1.posix.join(baseURL, "**"),
47
- destination: path_1.posix.join(baseURL, "200.html"),
46
+ source: path_1.posix.join(baseUrl, "**"),
47
+ destination: path_1.posix.join(baseUrl, "200.html"),
48
48
  },
49
49
  ];
50
- return { wantsBackend, rewrites };
50
+ return { wantsBackend, rewrites, baseUrl };
51
51
  }
52
52
  exports.build = build;
53
53
  async function ɵcodegenPublicDirectory(root, dest) {
@@ -64,12 +64,11 @@ async function ɵcodegenFunctionsDirectory(sourceDir) {
64
64
  const packageJson = JSON.parse(packageJsonBuffer.toString());
65
65
  packageJson.dependencies || (packageJson.dependencies = {});
66
66
  packageJson.dependencies["nitro-output"] = `file:${serverDir}`;
67
- const { app: { baseURL: baseUrl }, } = await getConfig(sourceDir);
68
- return { packageJson, frameworksEntry: "nitro", baseUrl };
67
+ return { packageJson, frameworksEntry: "nitro" };
69
68
  }
70
69
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
71
70
  async function getDevModeHandle(cwd) {
72
- const host = new Promise((resolve) => {
71
+ const host = new Promise((resolve, reject) => {
73
72
  const cli = (0, utils_1.getNodeModuleBin)("nuxt", cwd);
74
73
  const serve = (0, cross_spawn_1.spawn)(cli, ["dev"], { cwd: cwd });
75
74
  serve.stdout.on("data", (data) => {
@@ -81,6 +80,7 @@ async function getDevModeHandle(cwd) {
81
80
  serve.stderr.on("data", (data) => {
82
81
  process.stderr.write(data);
83
82
  });
83
+ serve.on("exit", reject);
84
84
  });
85
85
  return (0, utils_1.simpleProxy)(await host);
86
86
  }
@@ -60,7 +60,7 @@ async function ɵcodegenFunctionsDirectory(rootDir, destDir) {
60
60
  }
61
61
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
62
62
  async function getDevModeHandle(cwd) {
63
- const host = new Promise((resolve) => {
63
+ const host = new Promise((resolve, reject) => {
64
64
  const cli = (0, utils_1.getNodeModuleBin)("nuxt", cwd);
65
65
  const serve = (0, cross_spawn_1.spawn)(cli, ["dev"], { cwd });
66
66
  serve.stdout.on("data", (data) => {
@@ -72,6 +72,7 @@ async function getDevModeHandle(cwd) {
72
72
  serve.stderr.on("data", (data) => {
73
73
  process.stderr.write(data);
74
74
  });
75
+ serve.on("exit", reject);
75
76
  });
76
77
  return (0, utils_3.simpleProxy)(await host);
77
78
  }
@@ -32,16 +32,31 @@ async function warnIfCustomBuildScript(dir, framework, defaultBuildScripts) {
32
32
  }
33
33
  }
34
34
  exports.warnIfCustomBuildScript = warnIfCustomBuildScript;
35
+ function proxyResponse(original, next) {
36
+ return (response) => {
37
+ const { statusCode, statusMessage } = response;
38
+ if (!statusCode) {
39
+ original.end();
40
+ return;
41
+ }
42
+ if (statusCode === 404) {
43
+ return next();
44
+ }
45
+ const headers = "getHeaders" in response ? response.getHeaders() : response.headers;
46
+ original.writeHead(statusCode, statusMessage, headers);
47
+ response.pipe(original);
48
+ };
49
+ }
35
50
  function simpleProxy(hostOrRequestHandler) {
36
51
  const agent = new http_1.Agent({ keepAlive: true });
52
+ const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__;
53
+ const authTokenSyncURL = firebaseDefaultsJSON && JSON.parse(firebaseDefaultsJSON)._authTokenSyncURL;
37
54
  return async (originalReq, originalRes, next) => {
38
55
  const { method, headers, url: path } = originalReq;
39
56
  if (!method || !path) {
40
57
  originalRes.end();
41
58
  return;
42
59
  }
43
- const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__;
44
- const authTokenSyncURL = firebaseDefaultsJSON && JSON.parse(firebaseDefaultsJSON)._authTokenSyncURL;
45
60
  if (path === authTokenSyncURL) {
46
61
  return next();
47
62
  }
@@ -61,8 +76,13 @@ function simpleProxy(hostOrRequestHandler) {
61
76
  };
62
77
  const req = (0, http_1.request)(opts, (response) => {
63
78
  const { statusCode, statusMessage, headers } = response;
64
- originalRes.writeHead(statusCode, statusMessage, headers);
65
- response.pipe(originalRes);
79
+ if (statusCode === 404) {
80
+ next();
81
+ }
82
+ else {
83
+ originalRes.writeHead(statusCode, statusMessage, headers);
84
+ response.pipe(originalRes);
85
+ }
66
86
  });
67
87
  originalReq.pipe(req);
68
88
  req.on("error", (err) => {
@@ -71,7 +91,9 @@ function simpleProxy(hostOrRequestHandler) {
71
91
  });
72
92
  }
73
93
  else {
74
- await hostOrRequestHandler(originalReq, originalRes);
94
+ await Promise.resolve(hostOrRequestHandler(originalReq, originalRes, next));
95
+ const proxiedRes = new http_1.ServerResponse(originalReq);
96
+ proxyResponse(originalRes, next)(proxiedRes);
75
97
  }
76
98
  };
77
99
  }
@@ -183,25 +205,18 @@ function getFrameworksBuildTarget(purpose, validOptions) {
183
205
  }
184
206
  return frameworksBuild;
185
207
  }
186
- else if (purpose === "deploy") {
187
- return "production";
188
- }
189
- else if (process.env.NODE_ENV) {
190
- switch (process.env.NODE_ENV) {
191
- case "development":
192
- return "development";
193
- case "production":
194
- case "test":
195
- return "production";
196
- default:
197
- throw new error_1.FirebaseError(`We cannot infer your build target from a non-standard NODE_ENV. Please set the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable. Valid values are: ${validOptions.join(", ")}`);
198
- }
199
- }
200
- else if (purpose === "test") {
208
+ else if (["test", "deploy"].includes(purpose)) {
201
209
  return "production";
202
210
  }
203
- else {
204
- return "development";
211
+ switch (process.env.NODE_ENV) {
212
+ case undefined:
213
+ case "development":
214
+ return "development";
215
+ case "production":
216
+ case "test":
217
+ return "production";
218
+ default:
219
+ throw new error_1.FirebaseError(`We cannot infer your build target from a non-standard NODE_ENV. Please set the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable. Valid values are: ${validOptions.join(", ")}`);
205
220
  }
206
221
  }
207
222
  exports.getFrameworksBuildTarget = getFrameworksBuildTarget;
@@ -72,7 +72,7 @@ async function ɵcodegenPublicDirectory(root, dest) {
72
72
  }
73
73
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
74
74
  async function getDevModeHandle(dir) {
75
- const host = new Promise((resolve) => {
75
+ const host = new Promise((resolve, reject) => {
76
76
  const cli = (0, utils_1.getNodeModuleBin)("vite", dir);
77
77
  const serve = (0, cross_spawn_1.spawn)(cli, [], { cwd: dir });
78
78
  serve.stdout.on("data", (data) => {
@@ -84,6 +84,7 @@ async function getDevModeHandle(dir) {
84
84
  serve.stderr.on("data", (data) => {
85
85
  process.stderr.write(data);
86
86
  });
87
+ serve.on("exit", reject);
87
88
  });
88
89
  return (0, utils_1.simpleProxy)(await host);
89
90
  }
@@ -19,7 +19,7 @@ async function serve(options) {
19
19
  options.port = parseInt(options.port, 10);
20
20
  if (targetNames.includes("hosting") && config.extract(options).some((it) => it.source)) {
21
21
  experiments.assertEnabled("webframeworks", "emulate a web framework");
22
- await (0, frameworks_1.prepareFrameworks)(targetNames, options, options);
22
+ await (0, frameworks_1.prepareFrameworks)("emulate", targetNames, undefined, options);
23
23
  }
24
24
  const isDemoProject = constants_1.Constants.isDemoProject((0, projectUtils_1.getProjectId)(options) || "");
25
25
  targetNames.forEach((targetName) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "12.2.1",
3
+ "version": "12.3.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -1,7 +1,9 @@
1
1
  # Learn detailed information about the fields of an extension.yaml file in the docs:
2
2
  # https://firebase.google.com/docs/extensions/reference/extension-yaml
3
3
 
4
- name: greet-the-world # Identifier for your extension
4
+ # Identifier for your extension
5
+ # TODO: Replace this with an descriptive name for your extension.
6
+ name: greet-the-world
5
7
  version: 0.0.1 # Follow semver versioning
6
8
  specVersion: v1beta # Version of the Firebase Extensions specification
7
9
 
@@ -14,12 +16,13 @@ description: >-
14
16
 
15
17
  license: Apache-2.0 # https://spdx.org/licenses/
16
18
 
17
- # Public URL for the source code of your extension
18
- sourceUrl: https://github.com/firebase/firebase-tools/tree/master/templates/extensions
19
+ # Public URL for the source code of your extension.
20
+ # TODO: Replace this with your GitHub repo.
21
+ sourceUrl: https://github.com/ORG_OR_USER/REPO_NAME
19
22
 
20
23
  # Specify whether a paid-tier billing plan is required to use your extension.
21
24
  # Learn more in the docs: https://firebase.google.com/docs/extensions/reference/extension-yaml#billing-required-field
22
- billingRequired: false
25
+ billingRequired: true
23
26
 
24
27
  # In an `apis` field, list any Google APIs (like Cloud Translation, BigQuery, etc.)
25
28
  # required for your extension to operate.
@@ -39,8 +42,6 @@ resources:
39
42
  description: >-
40
43
  HTTP request-triggered function that responds with a specified greeting message
41
44
  properties:
42
- # LOCATION is a user-configured parameter value specified by the user during installation.
43
- location: ${LOCATION}
44
45
  # httpsTrigger is used for an HTTP triggered function.
45
46
  httpsTrigger: {}
46
47
  runtime: "nodejs16"
@@ -58,54 +59,3 @@ params:
58
59
  default: Hello
59
60
  required: true
60
61
  immutable: false
61
-
62
- - param: LOCATION
63
- label: Cloud Functions location
64
- description: >-
65
- Where do you want to deploy the functions created for this extension?
66
- For help selecting a location, refer to the [location selection
67
- guide](https://firebase.google.com/docs/functions/locations).
68
- type: select
69
- options:
70
- - label: Iowa (us-central1)
71
- value: us-central1
72
- - label: South Carolina (us-east1)
73
- value: us-east1
74
- - label: Northern Virginia (us-east4)
75
- value: us-east4
76
- - label: Los Angeles (us-west2)
77
- value: us-west2
78
- - label: Salt Lake City (us-west3)
79
- value: us-west3
80
- - label: Las Vegas (us-west4)
81
- value: us-west4
82
- - label: Warsaw (europe-central2)
83
- value: europe-central2
84
- - label: Belgium (europe-west1)
85
- value: europe-west1
86
- - label: London (europe-west2)
87
- value: europe-west2
88
- - label: Frankfurt (europe-west3)
89
- value: europe-west3
90
- - label: Zurich (europe-west6)
91
- value: europe-west6
92
- - label: Hong Kong (asia-east2)
93
- value: asia-east2
94
- - label: Tokyo (asia-northeast1)
95
- value: asia-northeast1
96
- - label: Osaka (asia-northeast2)
97
- value: asia-northeast2
98
- - label: Seoul (asia-northeast3)
99
- value: asia-northeast3
100
- - label: Mumbai (asia-south1)
101
- value: asia-south1
102
- - label: Jakarta (asia-southeast2)
103
- value: asia-southeast2
104
- - label: Montreal (northamerica-northeast1)
105
- value: northamerica-northeast1
106
- - label: Sao Paulo (southamerica-east1)
107
- value: southamerica-east1
108
- - label: Sydney (australia-southeast1)
109
- value: australia-southeast1
110
- required: true
111
- immutable: true
@@ -5,7 +5,7 @@
5
5
  * Reference PARAMETERS in your functions code with:
6
6
  * `process.env.<parameter-name>`
7
7
  * Learn more about building extensions in the docs:
8
- * https://firebase.google.com/docs/extensions/alpha/overview
8
+ * https://firebase.google.com/docs/extensions/publishers
9
9
  */
10
10
 
11
11
  const functions = require("firebase-functions");