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.
- package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
- package/lib/deploy/functions/runtimes/index.js +5 -2
- package/lib/deploy/functions/runtimes/node/index.js +70 -27
- package/lib/deploy/functions/runtimes/node/versioning.js +4 -2
- package/lib/deploy/functions/runtimes/python/index.js +119 -0
- package/lib/emulator/auth/apiSpec.js +4 -0
- package/lib/emulator/controller.js +5 -5
- package/lib/emulator/extensionsEmulator.js +3 -2
- package/lib/emulator/functionsEmulator.js +107 -72
- package/lib/emulator/functionsRuntimeWorker.js +4 -14
- package/lib/extensions/askUserForParam.js +32 -1
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/specHelper.js +17 -16
- package/lib/firestore/checkDatabaseType.js +3 -3
- package/lib/frameworks/index.js +9 -8
- package/lib/frameworks/next/index.js +6 -4
- package/lib/frameworks/nuxt/index.js +18 -26
- package/lib/frameworks/nuxt/interfaces.js +2 -0
- package/lib/frameworks/nuxt/utils.js +13 -0
- package/lib/frameworks/nuxt2/index.js +91 -0
- package/lib/functions/python.js +21 -0
- package/lib/init/features/firestore/index.js +1 -3
- package/lib/serve/functions.js +1 -3
- package/npm-shrinkwrap.json +1196 -185
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
|
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
|
|
800
|
-
this.logger.log("WARN", `To enable function inspection, please run "
|
|
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
|
|
814
|
-
|
|
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(
|
|
816
|
+
const childProcess = spawn(bin, args, {
|
|
817
817
|
cwd: backend.functionsDir,
|
|
818
|
-
env: Object.assign(Object.assign(Object.assign(
|
|
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
|
-
|
|
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:
|
|
839
|
+
events: new events_1.EventEmitter(),
|
|
824
840
|
cwd: backend.functionsDir,
|
|
825
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
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
|
|
89
|
+
return runtimes.sort()[runtimes.length - 1];
|
|
89
90
|
}
|
|
90
|
-
exports.
|
|
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.
|
|
10
|
-
const resp = await client.get(`/
|
|
11
|
-
return resp.body.
|
|
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);
|
package/lib/frameworks/index.js
CHANGED
|
@@ -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
|
|
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 (
|
|
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
|
-
(
|
|
323
|
-
(
|
|
324
|
-
(
|
|
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
|
-
(
|
|
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
|
|
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", {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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;
|