firebase-tools 11.21.0 → 11.23.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/commands/ext-configure.js +3 -3
- package/lib/commands/ext-dev-init.js +16 -4
- package/lib/commands/ext-dev-publish.js +3 -3
- package/lib/commands/ext-dev-register.js +2 -2
- package/lib/commands/ext-info.js +3 -3
- package/lib/commands/ext-install.js +2 -2
- package/lib/commands/ext-uninstall.js +2 -2
- package/lib/commands/ext-update.js +2 -2
- package/lib/commands/hosting-channel-create.js +2 -2
- package/lib/commands/hosting-channel-delete.js +2 -2
- package/lib/commands/hosting-channel-deploy.js +2 -2
- package/lib/commands/hosting-clone.js +2 -2
- package/lib/deploy/functions/release/fabricator.js +3 -0
- 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 +132 -0
- package/lib/deploy/hosting/convertConfig.js +2 -1
- package/lib/emulator/auth/apiSpec.js +21 -1
- package/lib/emulator/controller.js +5 -5
- package/lib/emulator/downloadableEmulators.js +6 -6
- package/lib/emulator/extensionsEmulator.js +3 -2
- package/lib/emulator/functionsEmulator.js +119 -87
- package/lib/emulator/functionsEmulatorRuntime.js +26 -42
- package/lib/emulator/functionsRuntimeWorker.js +51 -35
- package/lib/emulator/hub.js +6 -6
- package/lib/emulator/pubsubEmulator.js +12 -9
- package/lib/emulator/storage/apis/shared.js +2 -1
- package/lib/emulator/storage/cloudFunctions.js +1 -1
- package/lib/emulator/storage/files.js +18 -11
- package/lib/emulator/types.js +9 -9
- package/lib/extensions/askUserForConsent.js +4 -4
- package/lib/extensions/askUserForEventsConfig.js +2 -2
- package/lib/extensions/askUserForParam.js +34 -3
- package/lib/extensions/billingMigrationHelper.js +4 -4
- package/lib/extensions/change-log.js +4 -4
- package/lib/extensions/displayExtensionInfo.js +4 -4
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/specHelper.js +17 -16
- package/lib/extensions/extensionsApi.js +2 -2
- package/lib/extensions/extensionsHelper.js +6 -6
- package/lib/extensions/provisioningHelper.js +2 -2
- package/lib/extensions/updateHelper.js +2 -2
- package/lib/extensions/warnings.js +5 -5
- package/lib/firestore/checkDatabaseType.js +3 -3
- package/lib/frameworks/angular/index.js +6 -4
- package/lib/frameworks/index.js +47 -11
- package/lib/frameworks/lit/index.js +5 -1
- package/lib/frameworks/next/index.js +48 -20
- package/lib/frameworks/next/utils.js +1 -1
- 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/frameworks/preact/index.js +5 -1
- package/lib/frameworks/react/index.js +5 -1
- package/lib/frameworks/svelte/index.js +5 -1
- package/lib/frameworks/vite/index.js +6 -4
- package/lib/functions/python.js +16 -0
- package/lib/gcp/cloudfunctionsv2.js +8 -0
- package/lib/getDefaultHostingSite.js +3 -1
- package/lib/init/features/firestore/index.js +1 -3
- package/lib/init/features/functions/index.js +10 -0
- package/lib/init/features/functions/python.js +48 -0
- package/lib/init/features/hosting/index.js +3 -2
- package/lib/projectUtils.js +2 -2
- package/lib/rc.js +4 -4
- package/lib/serve/functions.js +1 -3
- package/npm-shrinkwrap.json +1295 -276
- package/package.json +2 -2
- package/templates/extensions/extension.yaml +1 -1
- package/templates/extensions/integration-test.env +2 -0
- package/templates/extensions/integration-test.json +14 -0
- package/templates/extensions/javascript/WELCOME.md +14 -5
- package/templates/extensions/javascript/index.js +10 -10
- package/templates/extensions/javascript/integration-test.js +13 -0
- package/templates/extensions/javascript/package.lint.json +12 -4
- package/templates/extensions/javascript/package.nolint.json +11 -2
- package/templates/extensions/typescript/WELCOME.md +18 -5
- package/templates/extensions/typescript/_mocharc +10 -0
- package/templates/extensions/typescript/index.ts +16 -15
- package/templates/extensions/typescript/integration-test.ts +13 -0
- package/templates/extensions/typescript/package.lint.json +16 -4
- package/templates/extensions/typescript/package.nolint.json +12 -4
- package/templates/init/functions/javascript/_eslintrc +16 -2
- package/templates/init/functions/javascript/package.lint.json +4 -4
- package/templates/init/functions/javascript/package.nolint.json +3 -3
- package/templates/init/functions/python/_gitignore +0 -0
- package/templates/init/functions/python/main.py +13 -0
- package/templates/init/functions/python/requirements.txt +1 -0
- package/templates/init/functions/typescript/_eslintrc +1 -0
- package/templates/init/functions/typescript/package.lint.json +4 -4
- package/templates/init/functions/typescript/package.nolint.json +4 -3
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Delegate = exports.getPythonBinary = exports.tryCreateDelegate = exports.LATEST_VERSION = void 0;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const node_fetch_1 = require("node-fetch");
|
|
7
|
+
const util_1 = require("util");
|
|
8
|
+
const portfinder = require("portfinder");
|
|
9
|
+
const runtimes = require("..");
|
|
10
|
+
const discovery = require("../discovery");
|
|
11
|
+
const logger_1 = require("../../../../logger");
|
|
12
|
+
const python_1 = require("../../../../functions/python");
|
|
13
|
+
const error_1 = require("../../../../error");
|
|
14
|
+
exports.LATEST_VERSION = "python310";
|
|
15
|
+
async function tryCreateDelegate(context) {
|
|
16
|
+
const requirementsTextPath = path.join(context.sourceDir, "requirements.txt");
|
|
17
|
+
if (!(await (0, util_1.promisify)(fs.exists)(requirementsTextPath))) {
|
|
18
|
+
logger_1.logger.debug("Customer code is not Python code.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const runtime = context.runtime ? context.runtime : exports.LATEST_VERSION;
|
|
22
|
+
if (!runtimes.isValidRuntime(runtime)) {
|
|
23
|
+
throw new error_1.FirebaseError(`Runtime ${runtime} is not a valid Python runtime`);
|
|
24
|
+
}
|
|
25
|
+
return Promise.resolve(new Delegate(context.projectId, context.sourceDir, runtime));
|
|
26
|
+
}
|
|
27
|
+
exports.tryCreateDelegate = tryCreateDelegate;
|
|
28
|
+
function getPythonBinary(runtime) {
|
|
29
|
+
if (process.platform === "win32") {
|
|
30
|
+
return "python.exe";
|
|
31
|
+
}
|
|
32
|
+
if (runtime === "python310") {
|
|
33
|
+
return "python3.10";
|
|
34
|
+
}
|
|
35
|
+
else if (runtime === "python311") {
|
|
36
|
+
return "python3.11";
|
|
37
|
+
}
|
|
38
|
+
return "python";
|
|
39
|
+
}
|
|
40
|
+
exports.getPythonBinary = getPythonBinary;
|
|
41
|
+
class Delegate {
|
|
42
|
+
constructor(projectId, sourceDir, runtime) {
|
|
43
|
+
this.projectId = projectId;
|
|
44
|
+
this.sourceDir = sourceDir;
|
|
45
|
+
this.runtime = runtime;
|
|
46
|
+
this.name = "python";
|
|
47
|
+
this._bin = "";
|
|
48
|
+
this._modulesDir = "";
|
|
49
|
+
}
|
|
50
|
+
get bin() {
|
|
51
|
+
if (this._bin === "") {
|
|
52
|
+
this._bin = this.getPythonBinary();
|
|
53
|
+
}
|
|
54
|
+
return this._bin;
|
|
55
|
+
}
|
|
56
|
+
async modulesDir() {
|
|
57
|
+
var _a;
|
|
58
|
+
if (!this._modulesDir) {
|
|
59
|
+
const child = (0, python_1.runWithVirtualEnv)([
|
|
60
|
+
this.bin,
|
|
61
|
+
"-c",
|
|
62
|
+
'"import firebase_functions; import os; print(os.path.dirname(firebase_functions.__file__))"',
|
|
63
|
+
], this.sourceDir, {});
|
|
64
|
+
let out = "";
|
|
65
|
+
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (chunk) => {
|
|
66
|
+
const chunkString = chunk.toString();
|
|
67
|
+
out = out + chunkString;
|
|
68
|
+
logger_1.logger.debug(`stdout: ${chunkString}`);
|
|
69
|
+
});
|
|
70
|
+
await new Promise((resolve, reject) => {
|
|
71
|
+
child.on("exit", resolve);
|
|
72
|
+
child.on("error", reject);
|
|
73
|
+
});
|
|
74
|
+
this._modulesDir = out.trim();
|
|
75
|
+
}
|
|
76
|
+
return this._modulesDir;
|
|
77
|
+
}
|
|
78
|
+
getPythonBinary() {
|
|
79
|
+
return getPythonBinary(this.runtime);
|
|
80
|
+
}
|
|
81
|
+
validate() {
|
|
82
|
+
return Promise.resolve();
|
|
83
|
+
}
|
|
84
|
+
watch() {
|
|
85
|
+
return Promise.resolve(() => Promise.resolve());
|
|
86
|
+
}
|
|
87
|
+
async build() {
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
async serveAdmin(port, envs) {
|
|
91
|
+
var _a, _b;
|
|
92
|
+
const modulesDir = await this.modulesDir();
|
|
93
|
+
const envWithAdminPort = Object.assign(Object.assign({}, envs), { ADMIN_PORT: port.toString() });
|
|
94
|
+
const args = [this.bin, path.join(modulesDir, "private", "serving.py")];
|
|
95
|
+
logger_1.logger.debug(`Running admin server with args: ${JSON.stringify(args)} and env: ${JSON.stringify(envWithAdminPort)} in ${this.sourceDir}`);
|
|
96
|
+
const childProcess = (0, python_1.runWithVirtualEnv)(args, this.sourceDir, envWithAdminPort);
|
|
97
|
+
(_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (chunk) => {
|
|
98
|
+
const chunkString = chunk.toString();
|
|
99
|
+
logger_1.logger.debug(`stdout: ${chunkString}`);
|
|
100
|
+
});
|
|
101
|
+
(_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (chunk) => {
|
|
102
|
+
const chunkString = chunk.toString();
|
|
103
|
+
logger_1.logger.debug(`stderr: ${chunkString}`);
|
|
104
|
+
});
|
|
105
|
+
return Promise.resolve(async () => {
|
|
106
|
+
await (0, node_fetch_1.default)(`http://127.0.0.1:${port}/__/quitquitquit`);
|
|
107
|
+
const quitTimeout = setTimeout(() => {
|
|
108
|
+
if (!childProcess.killed) {
|
|
109
|
+
childProcess.kill("SIGKILL");
|
|
110
|
+
}
|
|
111
|
+
}, 10000);
|
|
112
|
+
clearTimeout(quitTimeout);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async discoverBuild(_configValues, envs) {
|
|
116
|
+
let discovered = await discovery.detectFromYaml(this.sourceDir, this.projectId, this.runtime);
|
|
117
|
+
if (!discovered) {
|
|
118
|
+
const adminPort = await portfinder.getPortPromise({
|
|
119
|
+
port: 8081,
|
|
120
|
+
});
|
|
121
|
+
const killProcess = await this.serveAdmin(adminPort, envs);
|
|
122
|
+
try {
|
|
123
|
+
discovered = await discovery.detectFromPort(adminPort, this.projectId, this.runtime);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
await killProcess();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return discovered;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.Delegate = Delegate;
|
|
@@ -81,6 +81,7 @@ async function convertConfig(context, functionsPayload, deploy) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
config.rewrites = (_b = deploy.config.rewrites) === null || _b === void 0 ? void 0 : _b.map((rewrite) => {
|
|
84
|
+
var _a;
|
|
84
85
|
const target = extractPattern("rewrite", rewrite);
|
|
85
86
|
if ("destination" in rewrite) {
|
|
86
87
|
return Object.assign(Object.assign({}, target), { path: rewrite.destination });
|
|
@@ -120,7 +121,7 @@ async function convertConfig(context, functionsPayload, deploy) {
|
|
|
120
121
|
return Object.assign(Object.assign({}, target), { function: endpoint.id, functionRegion: endpoint.region });
|
|
121
122
|
}
|
|
122
123
|
const apiRewrite = Object.assign(Object.assign({}, target), { run: {
|
|
123
|
-
serviceId: endpoint.id,
|
|
124
|
+
serviceId: (_a = endpoint.runServiceId) !== null && _a !== void 0 ? _a : endpoint.id,
|
|
124
125
|
region: endpoint.region,
|
|
125
126
|
} });
|
|
126
127
|
if (rewrite.function.pinTag) {
|
|
@@ -4562,6 +4562,10 @@ exports.default = {
|
|
|
4562
4562
|
description: "Response message for GetRecaptchaParam.",
|
|
4563
4563
|
properties: {
|
|
4564
4564
|
kind: { type: "string" },
|
|
4565
|
+
producerProjectNumber: {
|
|
4566
|
+
description: "The producer project number used to generate PIA tokens",
|
|
4567
|
+
type: "string",
|
|
4568
|
+
},
|
|
4565
4569
|
recaptchaSiteKey: {
|
|
4566
4570
|
description: "The reCAPTCHA v2 site key used to invoke the reCAPTCHA service. Always present.",
|
|
4567
4571
|
type: "string",
|
|
@@ -5188,6 +5192,10 @@ exports.default = {
|
|
|
5188
5192
|
description: "Request message for SignInWithGameCenter",
|
|
5189
5193
|
properties: {
|
|
5190
5194
|
displayName: { description: "The user's Game Center display name.", type: "string" },
|
|
5195
|
+
gamePlayerId: {
|
|
5196
|
+
description: "The user's Game Center game player ID. A unique identifier for a player of the game. https://developer.apple.com/documentation/gamekit/gkplayer/3113960-gameplayerid",
|
|
5197
|
+
type: "string",
|
|
5198
|
+
},
|
|
5191
5199
|
idToken: {
|
|
5192
5200
|
description: "A valid ID token for an Identity Platform account. If present, this request will link the Game Center player ID to the account represented by this ID token.",
|
|
5193
5201
|
type: "string",
|
|
@@ -5205,6 +5213,10 @@ exports.default = {
|
|
|
5205
5213
|
description: "Required. The verification signature data generated by Apple.",
|
|
5206
5214
|
type: "string",
|
|
5207
5215
|
},
|
|
5216
|
+
teamPlayerId: {
|
|
5217
|
+
description: "The user's Game Center team player ID. A unique identifier for a player of all the games that you distribute using your developer account. https://developer.apple.com/documentation/gamekit/gkplayer/3174857-teamplayerid",
|
|
5218
|
+
type: "string",
|
|
5219
|
+
},
|
|
5208
5220
|
tenantId: {
|
|
5209
5221
|
description: "The ID of the Identity Platform tenant the user is signing in to.",
|
|
5210
5222
|
type: "string",
|
|
@@ -5226,6 +5238,10 @@ exports.default = {
|
|
|
5226
5238
|
format: "int64",
|
|
5227
5239
|
type: "string",
|
|
5228
5240
|
},
|
|
5241
|
+
gamePlayerId: {
|
|
5242
|
+
description: "The user's Game Center game player ID. A unique identifier for a player of the game. https://developer.apple.com/documentation/gamekit/gkplayer/3113960-gameplayerid",
|
|
5243
|
+
type: "string",
|
|
5244
|
+
},
|
|
5229
5245
|
idToken: {
|
|
5230
5246
|
description: "An Identity Platform ID token for the authenticated user.",
|
|
5231
5247
|
type: "string",
|
|
@@ -5243,6 +5259,10 @@ exports.default = {
|
|
|
5243
5259
|
description: "An Identity Platform refresh token for the authenticated user.",
|
|
5244
5260
|
type: "string",
|
|
5245
5261
|
},
|
|
5262
|
+
teamPlayerId: {
|
|
5263
|
+
description: "The user's Game Center team player ID. A unique identifier for a player of all the games that you distribute using your developer account. https://developer.apple.com/documentation/gamekit/gkplayer/3174857-teamplayerid",
|
|
5264
|
+
type: "string",
|
|
5265
|
+
},
|
|
5246
5266
|
},
|
|
5247
5267
|
type: "object",
|
|
5248
5268
|
},
|
|
@@ -7054,7 +7074,7 @@ exports.default = {
|
|
|
7054
7074
|
properties: {
|
|
7055
7075
|
condition: { $ref: "#/components/schemas/GoogleTypeExpr" },
|
|
7056
7076
|
members: {
|
|
7057
|
-
description: "Specifies the principals requesting access for a Google Cloud resource. `members` can have the following values: * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google account. * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google account or a service account. Does not include identities that come from external identity providers (IdPs) through identity federation. * `user:{emailid}`: An email address that represents a specific Google account. For example, `alice@example.com` . * `serviceAccount:{emailid}`: An email address that represents a Google service account. For example, `my-other-app@appspot.gserviceaccount.com`. * `serviceAccount:{projectid}.svc.id.goog[{namespace}/{kubernetes-sa}]`: An identifier for a [Kubernetes service account](https://cloud.google.com/kubernetes-engine/docs/how-to/kubernetes-service-accounts). For example, `my-project.svc.id.goog[my-namespace/my-kubernetes-sa]`. * `group:{emailid}`: An email address that represents a Google group. For example, `admins@example.com`. * `deleted:user:{emailid}?uid={uniqueid}`: An email address (plus unique identifier) representing a user that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user is recovered, this value reverts to `user:{emailid}` and the recovered user retains the role in the binding. * `deleted:serviceAccount:{emailid}?uid={uniqueid}`: An email address (plus unique identifier) representing a service account that has been recently deleted. For example, `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted, this value reverts to `serviceAccount:{emailid}` and the undeleted service account retains the role in the binding. * `deleted:group:{emailid}?uid={uniqueid}`: An email address (plus unique identifier) representing a Google group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the group is recovered, this value reverts to `group:{emailid}` and the recovered group retains the role in the binding.
|
|
7077
|
+
description: "Specifies the principals requesting access for a Google Cloud resource. `members` can have the following values: * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google account. * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google account or a service account. Does not include identities that come from external identity providers (IdPs) through identity federation. * `user:{emailid}`: An email address that represents a specific Google account. For example, `alice@example.com` . * `serviceAccount:{emailid}`: An email address that represents a Google service account. For example, `my-other-app@appspot.gserviceaccount.com`. * `serviceAccount:{projectid}.svc.id.goog[{namespace}/{kubernetes-sa}]`: An identifier for a [Kubernetes service account](https://cloud.google.com/kubernetes-engine/docs/how-to/kubernetes-service-accounts). For example, `my-project.svc.id.goog[my-namespace/my-kubernetes-sa]`. * `group:{emailid}`: An email address that represents a Google group. For example, `admins@example.com`. * `domain:{domain}`: The G Suite domain (primary) that represents all the users of that domain. For example, `google.com` or `example.com`. * `deleted:user:{emailid}?uid={uniqueid}`: An email address (plus unique identifier) representing a user that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user is recovered, this value reverts to `user:{emailid}` and the recovered user retains the role in the binding. * `deleted:serviceAccount:{emailid}?uid={uniqueid}`: An email address (plus unique identifier) representing a service account that has been recently deleted. For example, `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted, this value reverts to `serviceAccount:{emailid}` and the undeleted service account retains the role in the binding. * `deleted:group:{emailid}?uid={uniqueid}`: An email address (plus unique identifier) representing a Google group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the group is recovered, this value reverts to `group:{emailid}` and the recovered group retains the role in the binding.",
|
|
7058
7078
|
items: { type: "string" },
|
|
7059
7079
|
type: "array",
|
|
7060
7080
|
},
|
|
@@ -11,7 +11,6 @@ const registry_1 = require("./registry");
|
|
|
11
11
|
const types_1 = require("./types");
|
|
12
12
|
const constants_1 = require("./constants");
|
|
13
13
|
const functionsEmulator_1 = require("./functionsEmulator");
|
|
14
|
-
const functionsEmulatorUtils_1 = require("./functionsEmulatorUtils");
|
|
15
14
|
const auth_1 = require("./auth");
|
|
16
15
|
const databaseEmulator_1 = require("./databaseEmulator");
|
|
17
16
|
const firestoreEmulator_1 = require("./firestoreEmulator");
|
|
@@ -152,7 +151,7 @@ function findExportMetadata(importPath) {
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
async function startAll(options, showUI = true) {
|
|
155
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
154
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
156
155
|
const targets = filterEmulatorTargets(options);
|
|
157
156
|
options.targets = targets;
|
|
158
157
|
const singleProjectModeEnabled = ((_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a.singleProjectMode) === undefined ||
|
|
@@ -301,13 +300,14 @@ async function startAll(options, showUI = true) {
|
|
|
301
300
|
utils.assertIsStringOrUndefined(options.extDevDir);
|
|
302
301
|
for (const cfg of functionsCfg) {
|
|
303
302
|
const functionsDir = path.join(projectDir, cfg.source);
|
|
303
|
+
const runtime = (_e = options.extDevRuntime) !== null && _e !== void 0 ? _e : cfg.runtime;
|
|
304
304
|
emulatableBackends.push({
|
|
305
305
|
functionsDir,
|
|
306
|
+
runtime,
|
|
306
307
|
codebase: cfg.codebase,
|
|
307
308
|
env: Object.assign({}, options.extDevEnv),
|
|
308
309
|
secretEnv: [],
|
|
309
310
|
predefinedTriggers: options.extDevTriggers,
|
|
310
|
-
nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion || cfg.runtime),
|
|
311
311
|
});
|
|
312
312
|
}
|
|
313
313
|
}
|
|
@@ -316,7 +316,7 @@ async function startAll(options, showUI = true) {
|
|
|
316
316
|
}
|
|
317
317
|
if (emulatableBackends.length) {
|
|
318
318
|
if (!listenForEmulator.functions || !listenForEmulator.eventarc) {
|
|
319
|
-
listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(Object.assign(Object.assign({}, listenForEmulator), { functions: (
|
|
319
|
+
listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(Object.assign(Object.assign({}, listenForEmulator), { functions: (_f = listenForEmulator.functions) !== null && _f !== void 0 ? _f : getListenConfig(options, types_1.Emulators.FUNCTIONS), eventarc: (_g = listenForEmulator.eventarc) !== null && _g !== void 0 ? _g : getListenConfig(options, types_1.Emulators.EVENTARC) }));
|
|
320
320
|
hubLogger.log("DEBUG", "late-assigned ports for functions and eventarc emulators", {
|
|
321
321
|
user: listenForEmulator,
|
|
322
322
|
});
|
|
@@ -377,7 +377,7 @@ async function startAll(options, showUI = true) {
|
|
|
377
377
|
});
|
|
378
378
|
}
|
|
379
379
|
const config = options.config;
|
|
380
|
-
const rulesLocalPath = (
|
|
380
|
+
const rulesLocalPath = (_h = config.src.firestore) === null || _h === void 0 ? void 0 : _h.rules;
|
|
381
381
|
let rulesFileFound = false;
|
|
382
382
|
if (rulesLocalPath) {
|
|
383
383
|
const rules = config.path(rulesLocalPath);
|
|
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
23
23
|
expectedChecksum: "311609538bd65666eb724ef47c2e6466",
|
|
24
24
|
},
|
|
25
25
|
firestore: {
|
|
26
|
-
version: "1.
|
|
27
|
-
expectedSize:
|
|
28
|
-
expectedChecksum: "
|
|
26
|
+
version: "1.16.0",
|
|
27
|
+
expectedSize: 63422812,
|
|
28
|
+
expectedChecksum: "6c1a43c1b327d534f83f7386c595d7ff",
|
|
29
29
|
},
|
|
30
30
|
storage: {
|
|
31
31
|
version: "1.1.3",
|
|
@@ -35,9 +35,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
35
35
|
ui: experiments.isEnabled("emulatoruisnapshot")
|
|
36
36
|
? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" }
|
|
37
37
|
: {
|
|
38
|
-
version: "1.11.
|
|
39
|
-
expectedSize:
|
|
40
|
-
expectedChecksum: "
|
|
38
|
+
version: "1.11.4",
|
|
39
|
+
expectedSize: 3062916,
|
|
40
|
+
expectedChecksum: "1773926323b07fdb9602d882a7682882",
|
|
41
41
|
},
|
|
42
42
|
pubsub: {
|
|
43
43
|
version: "0.7.1",
|
|
@@ -143,14 +143,15 @@ class ExtensionsEmulator {
|
|
|
143
143
|
const extensionDir = await this.ensureSourceCode(instance);
|
|
144
144
|
const functionsDir = path.join(extensionDir, "functions");
|
|
145
145
|
const env = Object.assign(this.autoPopulatedParams(instance), instance.params);
|
|
146
|
-
const { extensionTriggers,
|
|
146
|
+
const { extensionTriggers, runtime, nonSecretEnv, secretEnvVariables } = await (0, optionsHelper_1.getExtensionFunctionInfo)(instance, env);
|
|
147
147
|
const emulatableBackend = {
|
|
148
148
|
functionsDir,
|
|
149
|
+
runtime,
|
|
150
|
+
bin: process.execPath,
|
|
149
151
|
env: nonSecretEnv,
|
|
150
152
|
codebase: instance.instanceId,
|
|
151
153
|
secretEnv: secretEnvVariables,
|
|
152
154
|
predefinedTriggers: extensionTriggers,
|
|
153
|
-
nodeMajorVersion: nodeMajorVersion,
|
|
154
155
|
extensionInstanceId: instance.instanceId,
|
|
155
156
|
};
|
|
156
157
|
if (instance.ref) {
|
|
@@ -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,10 +35,46 @@ 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 {
|
|
67
|
+
static getHttpFunctionUrl(projectId, name, region, info) {
|
|
68
|
+
let url;
|
|
69
|
+
if (info) {
|
|
70
|
+
url = new url_1.URL("http://" + (0, functionsEmulatorShared_1.formatHost)(info));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
url = registry_1.EmulatorRegistry.url(types_1.Emulators.FUNCTIONS);
|
|
74
|
+
}
|
|
75
|
+
url.pathname = `/${projectId}/${region}/${name}`;
|
|
76
|
+
return url.toString();
|
|
77
|
+
}
|
|
40
78
|
constructor(args) {
|
|
41
79
|
this.args = args;
|
|
42
80
|
this.triggers = {};
|
|
@@ -60,17 +98,6 @@ class FunctionsEmulator {
|
|
|
60
98
|
}
|
|
61
99
|
this.workQueue = new workQueue_1.WorkQueue(mode);
|
|
62
100
|
}
|
|
63
|
-
static getHttpFunctionUrl(projectId, name, region, info) {
|
|
64
|
-
let url;
|
|
65
|
-
if (info) {
|
|
66
|
-
url = new url_1.URL("http://" + (0, functionsEmulatorShared_1.formatHost)(info));
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
url = registry_1.EmulatorRegistry.url(types_1.Emulators.FUNCTIONS);
|
|
70
|
-
}
|
|
71
|
-
url.pathname = `/${projectId}/${region}/${name}`;
|
|
72
|
-
return url.toString();
|
|
73
|
-
}
|
|
74
101
|
async getCredentialsEnvironment() {
|
|
75
102
|
const credentialEnv = {};
|
|
76
103
|
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
@@ -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 {
|
|
@@ -701,9 +700,6 @@ class FunctionsEmulator {
|
|
|
701
700
|
envs.GCLOUD_PROJECT = this.args.projectId;
|
|
702
701
|
envs.K_REVISION = "1";
|
|
703
702
|
envs.PORT = "80";
|
|
704
|
-
if (trigger === null || trigger === void 0 ? void 0 : trigger.timeoutSeconds) {
|
|
705
|
-
envs.FUNCTIONS_EMULATOR_TIMEOUT_SECONDS = trigger.timeoutSeconds.toString();
|
|
706
|
-
}
|
|
707
703
|
if (trigger) {
|
|
708
704
|
const target = trigger.entryPoint;
|
|
709
705
|
envs.FUNCTION_TARGET = target;
|
|
@@ -791,13 +787,11 @@ class FunctionsEmulator {
|
|
|
791
787
|
}
|
|
792
788
|
return secretEnvs;
|
|
793
789
|
}
|
|
794
|
-
async
|
|
795
|
-
var _a;
|
|
796
|
-
const emitter = new events_1.EventEmitter();
|
|
790
|
+
async startNode(backend, envs) {
|
|
797
791
|
const args = [path.join(__dirname, "functionsEmulatorRuntime")];
|
|
798
792
|
if (this.args.debugPort) {
|
|
799
|
-
if (process.env.FIREPIT_VERSION
|
|
800
|
-
this.logger.log("WARN", `To enable function inspection, please run "
|
|
793
|
+
if (process.env.FIREPIT_VERSION) {
|
|
794
|
+
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
795
|
}
|
|
802
796
|
else {
|
|
803
797
|
const { host } = this.getInfo();
|
|
@@ -810,26 +804,57 @@ class FunctionsEmulator {
|
|
|
810
804
|
"Cloud Functions for Firebase requires a node_modules folder to work correctly and is therefore incompatible with PnP. " +
|
|
811
805
|
"See https://yarnpkg.com/getting-started/migration#step-by-step for more information.");
|
|
812
806
|
}
|
|
813
|
-
const
|
|
814
|
-
|
|
807
|
+
const bin = backend.bin;
|
|
808
|
+
if (!bin) {
|
|
809
|
+
throw new Error(`No binary associated with ${backend.functionsDir}. ` +
|
|
810
|
+
"Make sure function runtime is configured correctly in firebase.json.");
|
|
811
|
+
}
|
|
815
812
|
const socketPath = (0, functionsEmulatorShared_1.getTemporarySocketPath)();
|
|
816
|
-
const childProcess = spawn(
|
|
813
|
+
const childProcess = spawn(bin, args, {
|
|
817
814
|
cwd: backend.functionsDir,
|
|
818
|
-
env: Object.assign(Object.assign(Object.assign(
|
|
815
|
+
env: Object.assign(Object.assign(Object.assign({ node: backend.bin }, process.env), envs), { PORT: socketPath }),
|
|
819
816
|
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
820
817
|
});
|
|
821
|
-
|
|
818
|
+
return Promise.resolve({
|
|
822
819
|
process: childProcess,
|
|
823
|
-
events:
|
|
820
|
+
events: new events_1.EventEmitter(),
|
|
824
821
|
cwd: backend.functionsDir,
|
|
825
|
-
socketPath,
|
|
822
|
+
conn: new IPCConn(socketPath),
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
async startPython(backend, envs) {
|
|
826
|
+
const args = ["functions-framework"];
|
|
827
|
+
if (this.args.debugPort) {
|
|
828
|
+
this.logger.log("WARN", "--inspect-functions not supported for Python functions. Ignored.");
|
|
829
|
+
}
|
|
830
|
+
const port = await portfinder.getPortPromise({
|
|
831
|
+
port: 8081 + (0, utils_1.randomInt)(0, 1000),
|
|
832
|
+
});
|
|
833
|
+
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() }));
|
|
834
|
+
return {
|
|
835
|
+
process: childProcess,
|
|
836
|
+
events: new events_1.EventEmitter(),
|
|
837
|
+
cwd: backend.functionsDir,
|
|
838
|
+
conn: new TCPConn("127.0.0.1", port),
|
|
826
839
|
};
|
|
840
|
+
}
|
|
841
|
+
async startRuntime(backend, trigger) {
|
|
842
|
+
var _a;
|
|
843
|
+
const runtimeEnv = this.getRuntimeEnvs(backend, trigger);
|
|
844
|
+
const secretEnvs = await this.resolveSecretEnvs(backend, trigger);
|
|
845
|
+
let runtime;
|
|
846
|
+
if (backend.runtime.startsWith("python")) {
|
|
847
|
+
runtime = await this.startPython(backend, Object.assign(Object.assign({}, runtimeEnv), secretEnvs));
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
runtime = await this.startNode(backend, Object.assign(Object.assign({}, runtimeEnv), secretEnvs));
|
|
851
|
+
}
|
|
827
852
|
const extensionLogInfo = {
|
|
828
853
|
instanceId: backend.extensionInstanceId,
|
|
829
854
|
ref: (_a = backend.extensionVersion) === null || _a === void 0 ? void 0 : _a.ref,
|
|
830
855
|
};
|
|
831
856
|
const pool = this.workerPools[backend.codebase];
|
|
832
|
-
const worker = pool.addWorker(trigger
|
|
857
|
+
const worker = pool.addWorker(trigger, runtime, extensionLogInfo);
|
|
833
858
|
await worker.waitForSocketReady();
|
|
834
859
|
return worker;
|
|
835
860
|
}
|
|
@@ -927,7 +952,14 @@ class FunctionsEmulator {
|
|
|
927
952
|
this.logger.log("DEBUG", `[functions] Got req.url=${req.url}, mapping to path=${path}`);
|
|
928
953
|
const pool = this.workerPools[record.backend.codebase];
|
|
929
954
|
if (!pool.readyForWork(trigger.id)) {
|
|
930
|
-
|
|
955
|
+
try {
|
|
956
|
+
await this.startRuntime(record.backend, trigger);
|
|
957
|
+
}
|
|
958
|
+
catch (e) {
|
|
959
|
+
this.logger.logLabeled("ERROR", `Failed to handle request for function ${trigger.id}`);
|
|
960
|
+
this.logger.logLabeled("ERROR", `Failed to start functions in ${record.backend.functionsDir}: ${e}`);
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
931
963
|
}
|
|
932
964
|
const debugBundle = this.args.debugPort
|
|
933
965
|
? {
|