firebase-tools 11.21.0 → 11.22.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.FunctionsEmulator = void 0;
3
+ exports.FunctionsEmulator = exports.TCPConn = exports.IPCConn = void 0;
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
6
  const express = require("express");
@@ -8,6 +8,7 @@ const clc = require("colorette");
8
8
  const http = require("http");
9
9
  const jwt = require("jsonwebtoken");
10
10
  const cors = require("cors");
11
+ const semver = require("semver");
11
12
  const url_1 = require("url");
12
13
  const events_1 = require("events");
13
14
  const logger_1 = require("../logger");
@@ -15,6 +16,7 @@ const track_1 = require("../track");
15
16
  const constants_1 = require("./constants");
16
17
  const types_1 = require("./types");
17
18
  const chokidar = require("chokidar");
19
+ const portfinder = require("portfinder");
18
20
  const spawn = require("cross-spawn");
19
21
  const functionsEmulatorShared_1 = require("./functionsEmulatorShared");
20
22
  const registry_1 = require("./registry");
@@ -33,9 +35,34 @@ const functionsEnv = require("../functions/env");
33
35
  const v1_1 = require("../functions/events/v1");
34
36
  const build_1 = require("../deploy/functions/build");
35
37
  const env_1 = require("./env");
38
+ const python_1 = require("../functions/python");
36
39
  const EVENT_INVOKE = "functions:invoke";
37
40
  const EVENT_INVOKE_GA4 = "functions_invoke";
38
41
  const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
42
+ class IPCConn {
43
+ constructor(socketPath) {
44
+ this.socketPath = socketPath;
45
+ }
46
+ httpReqOpts() {
47
+ return {
48
+ socketPath: this.socketPath,
49
+ };
50
+ }
51
+ }
52
+ exports.IPCConn = IPCConn;
53
+ class TCPConn {
54
+ constructor(host, port) {
55
+ this.host = host;
56
+ this.port = port;
57
+ }
58
+ httpReqOpts() {
59
+ return {
60
+ host: this.host,
61
+ port: this.port,
62
+ };
63
+ }
64
+ }
65
+ exports.TCPConn = TCPConn;
39
66
  class FunctionsEmulator {
40
67
  constructor(args) {
41
68
  this.args = args;
@@ -168,7 +195,13 @@ class FunctionsEmulator {
168
195
  const record = this.getTriggerRecordByKey(this.getTriggerKey(trigger));
169
196
  const pool = this.workerPools[record.backend.codebase];
170
197
  if (!pool.readyForWork(trigger.id)) {
171
- await this.startRuntime(record.backend, trigger);
198
+ try {
199
+ await this.startRuntime(record.backend, trigger);
200
+ }
201
+ catch (e) {
202
+ this.logger.logLabeled("ERROR", `Failed to start runtime for ${trigger.id}: ${e}`);
203
+ return;
204
+ }
172
205
  }
173
206
  const worker = pool.getIdleWorker(trigger.id);
174
207
  const reqBody = JSON.stringify(body);
@@ -177,20 +210,13 @@ class FunctionsEmulator {
177
210
  "Content-Length": `${reqBody.length}`,
178
211
  };
179
212
  return new Promise((resolve, reject) => {
180
- const req = http.request({
181
- path: `/`,
182
- socketPath: worker.runtime.socketPath,
183
- headers: headers,
184
- }, resolve);
213
+ const req = http.request(Object.assign(Object.assign({}, worker.runtime.conn.httpReqOpts()), { path: `/`, headers: headers }), resolve);
185
214
  req.on("error", reject);
186
215
  req.write(reqBody);
187
216
  req.end();
188
217
  });
189
218
  }
190
219
  async start() {
191
- for (const backend of this.args.emulatableBackends) {
192
- backend.nodeBinary = this.getNodeBinary(backend);
193
- }
194
220
  const credentialEnv = await this.getCredentialsEnvironment();
195
221
  for (const e of this.args.emulatableBackends) {
196
222
  e.env = Object.assign(Object.assign({}, credentialEnv), e.env);
@@ -219,6 +245,7 @@ class FunctionsEmulator {
219
245
  /.+?[\\\/]node_modules[\\\/].+?/,
220
246
  /(^|[\/\\])\../,
221
247
  /.+\.log/,
248
+ /.+?[\\\/]venv[\\\/].+?/,
222
249
  ],
223
250
  persistent: true,
224
251
  });
@@ -257,21 +284,22 @@ class FunctionsEmulator {
257
284
  projectId: this.args.projectId,
258
285
  projectDir: this.args.projectDir,
259
286
  sourceDir: emulatableBackend.functionsDir,
287
+ runtime: emulatableBackend.runtime,
260
288
  };
261
- if (emulatableBackend.nodeMajorVersion) {
262
- runtimeDelegateContext.runtime = `nodejs${emulatableBackend.nodeMajorVersion}`;
263
- }
264
289
  const runtimeDelegate = await runtimes.getRuntimeDelegate(runtimeDelegateContext);
265
290
  logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
266
291
  await runtimeDelegate.validate();
267
292
  logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
268
293
  await runtimeDelegate.build();
294
+ emulatableBackend.runtime = runtimeDelegate.runtime;
295
+ emulatableBackend.bin = runtimeDelegate.bin;
269
296
  const firebaseConfig = this.getFirebaseConfig();
270
297
  const environment = Object.assign(Object.assign(Object.assign(Object.assign({}, this.getSystemEnvs()), this.getEmulatorEnvs()), { FIREBASE_CONFIG: firebaseConfig }), emulatableBackend.env);
271
298
  const userEnvOpt = {
272
299
  functionsSource: emulatableBackend.functionsDir,
273
300
  projectId: this.args.projectId,
274
301
  projectAlias: this.args.projectAlias,
302
+ isEmulator: true,
275
303
  };
276
304
  const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
277
305
  const discoveredBuild = await runtimeDelegate.discoverBuild(runtimeConfig, environment);
@@ -286,9 +314,7 @@ class FunctionsEmulator {
286
314
  }
287
315
  }
288
316
  async loadTriggers(emulatableBackend, force = false) {
289
- if (!emulatableBackend.nodeBinary) {
290
- throw new error_1.FirebaseError(`No node binary for ${emulatableBackend.functionsDir}. This should never happen.`);
291
- }
317
+ var _a;
292
318
  let triggerDefinitions = [];
293
319
  try {
294
320
  triggerDefinitions = await this.discoverTriggers(emulatableBackend);
@@ -381,13 +407,23 @@ class FunctionsEmulator {
381
407
  }
382
408
  }
383
409
  if (this.args.debugPort) {
384
- emulatableBackend.secretEnv = Object.values(triggerDefinitions.reduce((acc, curr) => {
385
- for (const secret of curr.secretEnvironmentVariables || []) {
386
- acc[secret.key] = secret;
410
+ if (!((_a = emulatableBackend.bin) === null || _a === void 0 ? void 0 : _a.startsWith("node"))) {
411
+ this.logger.log("WARN", "--inspect-functions only supported for Node.js runtimes.");
412
+ }
413
+ else {
414
+ emulatableBackend.secretEnv = Object.values(triggerDefinitions.reduce((acc, curr) => {
415
+ for (const secret of curr.secretEnvironmentVariables || []) {
416
+ acc[secret.key] = secret;
417
+ }
418
+ return acc;
419
+ }, {}));
420
+ try {
421
+ await this.startRuntime(emulatableBackend);
387
422
  }
388
- return acc;
389
- }, {}));
390
- await this.startRuntime(emulatableBackend);
423
+ catch (e) {
424
+ this.logger.logLabeled("ERROR", `Failed to start functions in ${emulatableBackend.functionsDir}: ${e}`);
425
+ }
426
+ }
391
427
  }
392
428
  }
393
429
  addEventarcTrigger(projectId, key, eventTrigger) {
@@ -632,43 +668,6 @@ class FunctionsEmulator {
632
668
  this.triggers = {};
633
669
  triggers.forEach((def) => this.addTriggerRecord(def, { backend, ignored: false }));
634
670
  }
635
- getNodeBinary(backend) {
636
- const pkg = require(path.join(backend.functionsDir, "package.json"));
637
- if ((!pkg.engines || !pkg.engines.node) && !backend.nodeMajorVersion) {
638
- this.logger.log("WARN", `Your functions directory ${backend.functionsDir} does not specify a Node version.\n ` +
639
- "- Learn more at https://firebase.google.com/docs/functions/manage-functions#set_runtime_options");
640
- return process.execPath;
641
- }
642
- const hostMajorVersion = process.versions.node.split(".")[0];
643
- const requestedMajorVersion = backend.nodeMajorVersion
644
- ? `${backend.nodeMajorVersion}`
645
- : pkg.engines.node;
646
- let localMajorVersion = "0";
647
- const localNodePath = path.join(backend.functionsDir, "node_modules/.bin/node");
648
- try {
649
- const localNodeOutput = spawn.sync(localNodePath, ["--version"]).stdout.toString();
650
- localMajorVersion = localNodeOutput.slice(1).split(".")[0];
651
- }
652
- catch (err) {
653
- }
654
- if (requestedMajorVersion === localMajorVersion) {
655
- this.logger.logLabeled("SUCCESS", "functions", `Using node@${requestedMajorVersion} from local cache.`);
656
- return localNodePath;
657
- }
658
- if (requestedMajorVersion === hostMajorVersion) {
659
- this.logger.logLabeled("SUCCESS", "functions", `Using node@${requestedMajorVersion} from host.`);
660
- }
661
- else {
662
- if (process.env.FIREPIT_VERSION) {
663
- this.logger.log("WARN", `You've requested "node" version "${requestedMajorVersion}", but the standalone Firebase CLI comes with bundled Node "${hostMajorVersion}".`);
664
- this.logger.log("INFO", `To use a different Node.js version, consider removing the standalone Firebase CLI and switching to "firebase-tools" on npm.`);
665
- }
666
- else {
667
- this.logger.log("WARN", `Your requested "node" version "${requestedMajorVersion}" doesn't match your global version "${hostMajorVersion}". Using node@${hostMajorVersion} from host.`);
668
- }
669
- }
670
- return process.execPath;
671
- }
672
671
  getRuntimeConfig(backend) {
673
672
  const configPath = `${backend.functionsDir}/.runtimeconfig.json`;
674
673
  try {
@@ -791,13 +790,11 @@ class FunctionsEmulator {
791
790
  }
792
791
  return secretEnvs;
793
792
  }
794
- async startRuntime(backend, trigger) {
795
- var _a;
796
- const emitter = new events_1.EventEmitter();
793
+ async startNode(backend, envs) {
797
794
  const args = [path.join(__dirname, "functionsEmulatorRuntime")];
798
795
  if (this.args.debugPort) {
799
- if (process.env.FIREPIT_VERSION && process.execPath === backend.nodeBinary) {
800
- this.logger.log("WARN", `To enable function inspection, please run "${process.execPath} is:npm i node@${backend.nodeMajorVersion} --save-dev" in your functions directory`);
796
+ if (process.env.FIREPIT_VERSION) {
797
+ this.logger.log("WARN", `To enable function inspection, please run "npm i node@${semver.coerce(backend.runtime || "18.0.0")} --save-dev" in your functions directory`);
801
798
  }
802
799
  else {
803
800
  const { host } = this.getInfo();
@@ -810,20 +807,51 @@ class FunctionsEmulator {
810
807
  "Cloud Functions for Firebase requires a node_modules folder to work correctly and is therefore incompatible with PnP. " +
811
808
  "See https://yarnpkg.com/getting-started/migration#step-by-step for more information.");
812
809
  }
813
- const runtimeEnv = this.getRuntimeEnvs(backend, trigger);
814
- const secretEnvs = await this.resolveSecretEnvs(backend, trigger);
810
+ const bin = backend.bin;
811
+ if (!bin) {
812
+ throw new Error(`No binary associated with ${backend.functionsDir}. ` +
813
+ "Make sure function runtime is configured correctly in firebase.json.");
814
+ }
815
815
  const socketPath = (0, functionsEmulatorShared_1.getTemporarySocketPath)();
816
- const childProcess = spawn(backend.nodeBinary, args, {
816
+ const childProcess = spawn(bin, args, {
817
817
  cwd: backend.functionsDir,
818
- env: Object.assign(Object.assign(Object.assign(Object.assign({ node: backend.nodeBinary }, process.env), runtimeEnv), secretEnvs), { PORT: socketPath }),
818
+ env: Object.assign(Object.assign(Object.assign({ node: backend.bin }, process.env), envs), { PORT: socketPath }),
819
819
  stdio: ["pipe", "pipe", "pipe", "ipc"],
820
820
  });
821
- const runtime = {
821
+ return Promise.resolve({
822
+ process: childProcess,
823
+ events: new events_1.EventEmitter(),
824
+ cwd: backend.functionsDir,
825
+ conn: new IPCConn(socketPath),
826
+ });
827
+ }
828
+ async startPython(backend, envs) {
829
+ const args = ["functions-framework"];
830
+ if (this.args.debugPort) {
831
+ this.logger.log("WARN", "--inspect-functions not supported for Python functions. Ignored.");
832
+ }
833
+ const port = await portfinder.getPortPromise({
834
+ port: 8081 + (0, utils_1.randomInt)(0, 1000),
835
+ });
836
+ const childProcess = (0, python_1.runWithVirtualEnv)(args, backend.functionsDir, Object.assign(Object.assign(Object.assign({}, process.env), envs), { PYTHONUNBUFFERED: "1", DEBUG: "False", HOST: "127.0.0.1", PORT: port.toString() }));
837
+ return {
822
838
  process: childProcess,
823
- events: emitter,
839
+ events: new events_1.EventEmitter(),
824
840
  cwd: backend.functionsDir,
825
- socketPath,
841
+ conn: new TCPConn("127.0.0.1", port),
826
842
  };
843
+ }
844
+ async startRuntime(backend, trigger) {
845
+ var _a;
846
+ const runtimeEnv = this.getRuntimeEnvs(backend, trigger);
847
+ const secretEnvs = await this.resolveSecretEnvs(backend, trigger);
848
+ let runtime;
849
+ if (backend.runtime.startsWith("python")) {
850
+ runtime = await this.startPython(backend, Object.assign(Object.assign({}, runtimeEnv), secretEnvs));
851
+ }
852
+ else {
853
+ runtime = await this.startNode(backend, Object.assign(Object.assign({}, runtimeEnv), secretEnvs));
854
+ }
827
855
  const extensionLogInfo = {
828
856
  instanceId: backend.extensionInstanceId,
829
857
  ref: (_a = backend.extensionVersion) === null || _a === void 0 ? void 0 : _a.ref,
@@ -927,7 +955,14 @@ class FunctionsEmulator {
927
955
  this.logger.log("DEBUG", `[functions] Got req.url=${req.url}, mapping to path=${path}`);
928
956
  const pool = this.workerPools[record.backend.codebase];
929
957
  if (!pool.readyForWork(trigger.id)) {
930
- await this.startRuntime(record.backend, trigger);
958
+ try {
959
+ await this.startRuntime(record.backend, trigger);
960
+ }
961
+ catch (e) {
962
+ this.logger.logLabeled("ERROR", `Failed to handle request for function ${trigger.id}`);
963
+ this.logger.logLabeled("ERROR", `Failed to start functions in ${record.backend.functionsDir}: ${e}`);
964
+ return;
965
+ }
931
966
  }
932
967
  const debugBundle = this.args.debugPort
933
968
  ? {
@@ -86,12 +86,7 @@ class RuntimeWorker {
86
86
  }
87
87
  };
88
88
  return new Promise((resolve) => {
89
- const proxy = http.request({
90
- method: req.method,
91
- path: req.path,
92
- headers: req.headers,
93
- socketPath: this.runtime.socketPath,
94
- }, (_resp) => {
89
+ const proxy = http.request(Object.assign(Object.assign({}, this.runtime.conn.httpReqOpts()), { method: req.method, path: req.path, headers: req.headers }), (_resp) => {
95
90
  resp.writeHead(_resp.statusCode || 200, _resp.headers);
96
91
  const piped = _resp.pipe(resp);
97
92
  piped.on("finish", () => {
@@ -137,16 +132,11 @@ class RuntimeWorker {
137
132
  }
138
133
  isSocketReady() {
139
134
  return new Promise((resolve, reject) => {
140
- const req = http
141
- .request({
142
- method: "GET",
143
- path: "/__/health",
144
- socketPath: this.runtime.socketPath,
145
- }, () => {
135
+ const req = http.request(Object.assign(Object.assign({}, this.runtime.conn.httpReqOpts()), { method: "GET", path: "/__/health" }), () => {
146
136
  this.readyForWork();
147
137
  resolve();
148
- })
149
- .end();
138
+ });
139
+ req.end();
150
140
  req.on("error", (error) => {
151
141
  reject(error);
152
142
  });
@@ -13,6 +13,7 @@ const logger_1 = require("../logger");
13
13
  const prompt_1 = require("../prompt");
14
14
  const utils = require("../utils");
15
15
  const projectUtils_1 = require("../projectUtils");
16
+ const functional_1 = require("../functional");
16
17
  var SecretLocation;
17
18
  (function (SecretLocation) {
18
19
  SecretLocation[SecretLocation["CLOUD"] = 1] = "CLOUD";
@@ -67,8 +68,9 @@ async function ask(args) {
67
68
  }
68
69
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, "answer the questions below to configure your extension:");
69
70
  const substituted = (0, extensionsHelper_1.substituteParams)(args.paramSpecs, args.firebaseProjectParams);
71
+ const [advancedParams, standardParams] = (0, functional_1.partition)(substituted, (p) => { var _a; return (_a = p.advanced) !== null && _a !== void 0 ? _a : false; });
70
72
  const result = {};
71
- const promises = substituted.map((paramSpec) => {
73
+ const promises = standardParams.map((paramSpec) => {
72
74
  return async () => {
73
75
  result[paramSpec.param] = await askForParam({
74
76
  projectId: args.projectId,
@@ -78,6 +80,35 @@ async function ask(args) {
78
80
  });
79
81
  };
80
82
  });
83
+ if (advancedParams.length) {
84
+ promises.push(async () => {
85
+ const shouldPrompt = await (0, prompt_1.promptOnce)({
86
+ type: "confirm",
87
+ message: "Do you want to configure any advanced parameters for this instance?",
88
+ default: false,
89
+ });
90
+ if (shouldPrompt) {
91
+ const advancedPromises = advancedParams.map((paramSpec) => {
92
+ return async () => {
93
+ result[paramSpec.param] = await askForParam({
94
+ projectId: args.projectId,
95
+ instanceId: args.instanceId,
96
+ paramSpec: paramSpec,
97
+ reconfiguring: args.reconfiguring,
98
+ });
99
+ };
100
+ });
101
+ await advancedPromises.reduce((prev, cur) => prev.then(cur), Promise.resolve());
102
+ }
103
+ else {
104
+ for (const paramSpec of advancedParams) {
105
+ if (paramSpec.required && paramSpec.default) {
106
+ result[paramSpec.param] = { baseValue: paramSpec.default };
107
+ }
108
+ }
109
+ }
110
+ });
111
+ }
81
112
  await promises.reduce((prev, cur) => prev.then(cur), Promise.resolve());
82
113
  logger_1.logger.info();
83
114
  return result;
@@ -32,7 +32,7 @@ async function buildOptions(options) {
32
32
  options.extDevEnv = params;
33
33
  const functionEmuTriggerDefs = functionResources.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r));
34
34
  options.extDevTriggers = functionEmuTriggerDefs;
35
- options.extDevNodeVersion = specHelper.getNodeVersion(functionResources);
35
+ options.extDevRuntime = specHelper.getRuntime(functionResources);
36
36
  return options;
37
37
  }
38
38
  exports.buildOptions = buildOptions;
@@ -45,12 +45,12 @@ async function getExtensionFunctionInfo(instance, paramValues) {
45
45
  trigger.name = `ext-${instance.instanceId}-${trigger.name}`;
46
46
  return trigger;
47
47
  });
48
- const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
48
+ const runtime = specHelper.getRuntime(functionResources);
49
49
  const nonSecretEnv = getNonSecretEnv(spec.params, paramValues);
50
50
  const secretEnvVariables = getSecretEnvVars(spec.params, paramValues);
51
51
  return {
52
52
  extensionTriggers,
53
- nodeMajorVersion,
53
+ runtime,
54
54
  nonSecretEnv,
55
55
  secretEnvVariables,
56
56
  };
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getNodeVersion = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readPostinstall = exports.readExtensionYaml = void 0;
3
+ exports.getRuntime = exports.DEFAULT_RUNTIME = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readPostinstall = exports.readExtensionYaml = void 0;
4
4
  const yaml = require("js-yaml");
5
5
  const path = require("path");
6
6
  const fs = require("fs-extra");
7
7
  const error_1 = require("../../error");
8
8
  const extensionsHelper_1 = require("../extensionsHelper");
9
9
  const utils_1 = require("../utils");
10
- const functionsEmulatorUtils_1 = require("../../emulator/functionsEmulatorUtils");
11
10
  const SPEC_FILE = "extension.yaml";
12
11
  const POSTINSTALL_FILE = "POSTINSTALL.md";
13
12
  const validFunctionTypes = [
@@ -67,24 +66,26 @@ function getFunctionProperties(resources) {
67
66
  return resources.map((r) => r.properties);
68
67
  }
69
68
  exports.getFunctionProperties = getFunctionProperties;
70
- function getNodeVersion(resources) {
69
+ exports.DEFAULT_RUNTIME = "nodejs14";
70
+ function getRuntime(resources) {
71
+ if (resources.length === 0) {
72
+ return exports.DEFAULT_RUNTIME;
73
+ }
71
74
  const invalidRuntimes = [];
72
- const versions = resources.map((r) => {
73
- if ((0, utils_1.getResourceRuntime)(r)) {
74
- const runtimeName = (0, utils_1.getResourceRuntime)(r);
75
- const runtime = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(runtimeName);
76
- if (!runtime) {
77
- invalidRuntimes.push(runtimeName);
78
- }
79
- else {
80
- return runtime;
81
- }
75
+ const runtimes = resources.map((r) => {
76
+ const runtime = (0, utils_1.getResourceRuntime)(r);
77
+ if (!runtime) {
78
+ return exports.DEFAULT_RUNTIME;
79
+ }
80
+ if (!/^(nodejs)?([0-9]+)/.test(runtime)) {
81
+ invalidRuntimes.push(runtime);
82
+ return exports.DEFAULT_RUNTIME;
82
83
  }
83
- return 14;
84
+ return runtime;
84
85
  });
85
86
  if (invalidRuntimes.length) {
86
87
  throw new error_1.FirebaseError(`The following runtimes are not supported by the Emulator Suite: ${invalidRuntimes.join(", ")}. \n Only Node runtimes are supported.`);
87
88
  }
88
- return Math.max(...versions);
89
+ return runtimes.sort()[runtimes.length - 1];
89
90
  }
90
- exports.getNodeVersion = getNodeVersion;
91
+ exports.getRuntime = getRuntime;
@@ -6,9 +6,9 @@ const apiv2_1 = require("../apiv2");
6
6
  const logger_1 = require("../logger");
7
7
  async function checkDatabaseType(projectId) {
8
8
  try {
9
- const client = new apiv2_1.Client({ urlPrefix: api_1.appengineOrigin, apiVersion: "v1" });
10
- const resp = await client.get(`/apps/${projectId}`);
11
- return resp.body.databaseType;
9
+ const client = new apiv2_1.Client({ urlPrefix: api_1.firestoreOrigin, apiVersion: "v1" });
10
+ const resp = await client.get(`/projects/${projectId}/databases/(default)`);
11
+ return resp.body.type;
12
12
  }
13
13
  catch (err) {
14
14
  logger_1.logger.debug("error getting database type", err);
@@ -120,8 +120,8 @@ function findDependency(name, options = {}) {
120
120
  }
121
121
  exports.findDependency = findDependency;
122
122
  async function prepareFrameworks(targetNames, context, options, emulators = []) {
123
- var _a;
124
- var _b, _c, _d, _e;
123
+ var _a, _b;
124
+ var _c, _d, _e, _f;
125
125
  const nodeVersion = process.version;
126
126
  if (!semver.satisfies(nodeVersion, ">=16.0.0")) {
127
127
  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.`);
@@ -133,7 +133,7 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
133
133
  try {
134
134
  await (0, requireHostingSite_1.requireHostingSite)(options);
135
135
  }
136
- catch (_f) {
136
+ catch (_g) {
137
137
  options.site = project;
138
138
  }
139
139
  }
@@ -243,10 +243,11 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
243
243
  }
244
244
  }
245
245
  else {
246
- const { wantsBackend = false, rewrites = [], redirects = [], headers = [], } = (await build(getProjectPath())) || {};
246
+ const { wantsBackend = false, rewrites = [], redirects = [], headers = [], trailingSlash, } = (await build(getProjectPath())) || {};
247
247
  config.rewrites.push(...rewrites);
248
248
  config.redirects.push(...redirects);
249
249
  config.headers.push(...headers);
250
+ (_b = config.trailingSlash) !== null && _b !== void 0 ? _b : (config.trailingSlash = trailingSlash);
250
251
  if (await (0, fs_extra_1.pathExists)(hostingDist))
251
252
  await (0, promises_1.rm)(hostingDist, { recursive: true });
252
253
  await (0, fs_extra_1.mkdirp)(hostingDist);
@@ -319,11 +320,11 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
319
320
  packageJson.main = "server.js";
320
321
  delete packageJson.devDependencies;
321
322
  packageJson.dependencies || (packageJson.dependencies = {});
322
- (_b = packageJson.dependencies)["firebase-frameworks"] || (_b["firebase-frameworks"] = exports.FIREBASE_FRAMEWORKS_VERSION);
323
- (_c = packageJson.dependencies)["firebase-functions"] || (_c["firebase-functions"] = exports.FIREBASE_FUNCTIONS_VERSION);
324
- (_d = packageJson.dependencies)["firebase-admin"] || (_d["firebase-admin"] = exports.FIREBASE_ADMIN_VERSION);
323
+ (_c = packageJson.dependencies)["firebase-frameworks"] || (_c["firebase-frameworks"] = exports.FIREBASE_FRAMEWORKS_VERSION);
324
+ (_d = packageJson.dependencies)["firebase-functions"] || (_d["firebase-functions"] = exports.FIREBASE_FUNCTIONS_VERSION);
325
+ (_e = packageJson.dependencies)["firebase-admin"] || (_e["firebase-admin"] = exports.FIREBASE_ADMIN_VERSION);
325
326
  packageJson.engines || (packageJson.engines = {});
326
- (_e = packageJson.engines).node || (_e.node = exports.NODE_VERSION);
327
+ (_f = packageJson.engines).node || (_f.node = exports.NODE_VERSION);
327
328
  await (0, promises_1.writeFile)((0, path_1.join)(functionsDist, "package.json"), JSON.stringify(packageJson, null, 2));
328
329
  await (0, promises_1.writeFile)((0, path_1.join)(functionsDist, ".env"), `__FIREBASE_FRAMEWORKS_ENTRY__=${frameworksEntry}
329
330
  ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\n` : ""}`);
@@ -52,7 +52,7 @@ async function build(dir) {
52
52
  throw e;
53
53
  });
54
54
  const reasonsForBackend = [];
55
- const { distDir } = await getConfig(dir);
55
+ const { distDir, trailingSlash } = await getConfig(dir);
56
56
  if (await (0, utils_1.isUsingMiddleware)((0, path_1.join)(dir, distDir), false)) {
57
57
  reasonsForBackend.push("middleware");
58
58
  }
@@ -96,7 +96,9 @@ async function build(dir) {
96
96
  source: (0, utils_1.cleanEscapedChars)(source),
97
97
  headers,
98
98
  }));
99
- const isEveryRedirectSupported = nextJsRedirects.every(utils_1.isRedirectSupportedByHosting);
99
+ const isEveryRedirectSupported = nextJsRedirects
100
+ .filter((it) => !it.internal)
101
+ .every(utils_1.isRedirectSupportedByHosting);
100
102
  if (!isEveryRedirectSupported) {
101
103
  reasonsForBackend.push("advanced redirects");
102
104
  }
@@ -134,7 +136,7 @@ async function build(dir) {
134
136
  }
135
137
  console.log("");
136
138
  }
137
- return { wantsBackend, headers, redirects, rewrites };
139
+ return { wantsBackend, headers, redirects, rewrites, trailingSlash };
138
140
  }
139
141
  exports.build = build;
140
142
  async function init(setup) {
@@ -284,5 +286,5 @@ async function getConfig(dir) {
284
286
  }
285
287
  }
286
288
  }
287
- return Object.assign({ distDir: ".next" }, config);
289
+ return Object.assign({ distDir: ".next", trailingSlash: false }, config);
288
290
  }
@@ -10,30 +10,34 @@ const utils_1 = require("../utils");
10
10
  exports.name = "Nuxt";
11
11
  exports.support = "experimental";
12
12
  exports.type = 4;
13
+ const utils_2 = require("./utils");
13
14
  const DEFAULT_BUILD_SCRIPT = ["nuxt build"];
14
15
  async function discover(dir) {
15
16
  if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
16
17
  return;
17
- const nuxtDependency = (0, __1.findDependency)("nuxt", { cwd: dir, depth: 0, omitDev: false });
18
- const configFilesExist = await Promise.all([
19
- (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "nuxt.config.js")),
20
- (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "nuxt.config.ts")),
21
- ]);
22
- const anyConfigFileExists = configFilesExist.some((it) => it);
18
+ const nuxtDependency = (0, __1.findDependency)("nuxt", {
19
+ cwd: dir,
20
+ depth: 0,
21
+ omitDev: false,
22
+ });
23
+ const version = nuxtDependency === null || nuxtDependency === void 0 ? void 0 : nuxtDependency.version;
24
+ const anyConfigFileExists = await (0, utils_2.nuxtConfigFilesExist)(dir);
23
25
  if (!anyConfigFileExists && !nuxtDependency)
24
26
  return;
25
- return { mayWantBackend: true };
27
+ if (version && (0, semver_1.gte)(version, "3.0.0-0"))
28
+ return { mayWantBackend: true };
29
+ return;
26
30
  }
27
31
  exports.discover = discover;
28
32
  async function build(root) {
29
33
  const { buildNuxt } = await (0, __1.relativeRequire)(root, "@nuxt/kit");
30
- const nuxtApp = await getNuxtApp(root);
34
+ const nuxtApp = await getNuxt3App(root);
31
35
  await (0, utils_1.warnIfCustomBuildScript)(root, exports.name, DEFAULT_BUILD_SCRIPT);
32
36
  await buildNuxt(nuxtApp);
33
37
  return { wantsBackend: true };
34
38
  }
35
39
  exports.build = build;
36
- async function getNuxtApp(cwd) {
40
+ async function getNuxt3App(cwd) {
37
41
  const { loadNuxt } = await (0, __1.relativeRequire)(cwd, "@nuxt/kit");
38
42
  return await loadNuxt({
39
43
  cwd,
@@ -42,29 +46,17 @@ async function getNuxtApp(cwd) {
42
46
  },
43
47
  });
44
48
  }
45
- function isNuxt3(cwd) {
46
- const { version } = (0, __1.findDependency)("nuxt", { cwd, depth: 0, omitDev: false });
47
- return (0, semver_1.gte)(version, "3.0.0-0");
48
- }
49
49
  async function ɵcodegenPublicDirectory(root, dest) {
50
- const app = await getNuxtApp(root);
51
- const distPath = isNuxt3(root) ? (0, path_1.join)(root, ".output", "public") : app.options.generate.dir;
50
+ const distPath = (0, path_1.join)(root, ".output", "public");
52
51
  await (0, fs_extra_1.copy)(distPath, dest);
53
52
  }
54
53
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
55
54
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
56
55
  const packageJsonBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, "package.json"));
57
56
  const packageJson = JSON.parse(packageJsonBuffer.toString());
58
- if (isNuxt3(sourceDir)) {
59
- const outputPackageJsonBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, ".output", "server", "package.json"));
60
- const outputPackageJson = JSON.parse(outputPackageJsonBuffer.toString());
61
- await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, ".output", "server"), destDir);
62
- return { packageJson: Object.assign(Object.assign({}, packageJson), outputPackageJson), frameworksEntry: "nuxt3" };
63
- }
64
- else {
65
- const { options: { buildDir }, } = await getNuxtApp(sourceDir);
66
- await (0, fs_extra_1.copy)(buildDir, (0, path_1.join)(destDir, (0, path_1.basename)(buildDir)));
67
- return { packageJson };
68
- }
57
+ const outputPackageJsonBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, ".output", "server", "package.json"));
58
+ const outputPackageJson = JSON.parse(outputPackageJsonBuffer.toString());
59
+ await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, ".output", "server"), destDir);
60
+ return { packageJson: Object.assign(Object.assign({}, packageJson), outputPackageJson), frameworksEntry: "nuxt3" };
69
61
  }
70
62
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });