firebase-tools 10.1.3 → 10.2.1
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/api.js +1 -0
- package/lib/apiv2.js +4 -0
- package/lib/auth.js +62 -25
- package/lib/commands/auth-import.js +1 -1
- package/lib/commands/ext-configure.js +1 -0
- package/lib/commands/ext-install.js +1 -0
- package/lib/commands/ext-uninstall.js +1 -0
- package/lib/commands/ext-update.js +1 -0
- package/lib/commands/functions-config-clone.js +1 -1
- package/lib/commands/functions-secrets-access.js +17 -0
- package/lib/commands/functions-secrets-destroy.js +40 -0
- package/lib/commands/functions-secrets-get.js +21 -0
- package/lib/commands/functions-secrets-prune.js +50 -0
- package/lib/commands/functions-secrets-set.js +46 -0
- package/lib/commands/index.js +7 -3
- package/lib/commands/login.js +1 -1
- package/lib/deploy/functions/backend.js +9 -1
- package/lib/deploy/functions/ensure.js +112 -0
- package/lib/deploy/functions/ensureCloudBuildEnabled.js +0 -49
- package/lib/deploy/functions/prepare.js +12 -18
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +1 -0
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +12 -0
- package/lib/deploy/functions/validate.js +56 -1
- package/lib/deploy/hosting/client.js +9 -0
- package/lib/deploy/hosting/convertConfig.js +6 -0
- package/lib/deploy/hosting/index.js +5 -5
- package/lib/deploy/hosting/prepare.js +25 -25
- package/lib/deploy/hosting/release.js +21 -24
- package/lib/emulator/commandUtils.js +5 -1
- package/lib/emulator/controller.js +3 -1
- package/lib/emulator/downloadableEmulators.js +29 -12
- package/lib/emulator/emulatorLogger.js +7 -0
- package/lib/emulator/functionsEmulator.js +122 -80
- package/lib/emulator/functionsEmulatorRuntime.js +100 -83
- package/lib/emulator/functionsEmulatorShared.js +51 -1
- package/lib/emulator/functionsEmulatorShell.js +1 -2
- package/lib/emulator/functionsRuntimeWorker.js +1 -1
- package/lib/emulator/storage/apis/gcloud.js +2 -2
- package/lib/emulator/storage/files.js +8 -3
- package/lib/extensions/askUserForParam.js +1 -1
- package/lib/extensions/diagnose.js +56 -0
- package/lib/extensions/extensionsHelper.js +10 -17
- package/lib/extensions/listExtensions.js +2 -0
- package/lib/extensions/resolveSource.js +1 -53
- package/lib/extensions/secretsUtils.js +1 -1
- package/lib/extensions/updateHelper.js +0 -14
- package/lib/extensions/utils.js +4 -2
- package/lib/functions/env.js +5 -7
- package/lib/functions/secrets.js +112 -0
- package/lib/gcp/cloudfunctions.js +2 -2
- package/lib/gcp/secretManager.js +128 -46
- package/lib/gcp/storage.js +5 -3
- package/lib/hosting/functionsProxy.js +15 -5
- package/lib/previews.js +1 -1
- package/lib/responseToError.js +16 -7
- package/lib/serve/functions.js +2 -2
- package/lib/serve/hosting.js +1 -1
- package/lib/utils.js +6 -1
- package/npm-shrinkwrap.json +124 -45
- package/package.json +4 -4
- package/schema/firebase-config.json +27 -0
|
@@ -27,10 +27,14 @@ const workQueue_1 = require("./workQueue");
|
|
|
27
27
|
const utils_1 = require("../utils");
|
|
28
28
|
const defaultCredentials_1 = require("../defaultCredentials");
|
|
29
29
|
const adminSdkConfig_1 = require("./adminSdkConfig");
|
|
30
|
-
const functionsEnv = require("../functions/env");
|
|
31
30
|
const types_2 = require("./events/types");
|
|
32
31
|
const validate_1 = require("../deploy/functions/validate");
|
|
32
|
+
const runtimes_1 = require("../deploy/functions/runtimes");
|
|
33
|
+
const backend = require("../deploy/functions/backend");
|
|
34
|
+
const functionsEnv = require("../functions/env");
|
|
35
|
+
const secretManager_1 = require("../gcp/secretManager");
|
|
33
36
|
const EVENT_INVOKE = "functions:invoke";
|
|
37
|
+
const LOCAL_SECRETS_FILE = ".secret.local";
|
|
34
38
|
const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
|
|
35
39
|
class FunctionsEmulator {
|
|
36
40
|
constructor(args) {
|
|
@@ -44,9 +48,7 @@ class FunctionsEmulator {
|
|
|
44
48
|
this.args.disabledRuntimeFeatures = this.args.disabledRuntimeFeatures || {};
|
|
45
49
|
this.args.disabledRuntimeFeatures.timeout = true;
|
|
46
50
|
}
|
|
47
|
-
this.adminSdkConfig = {
|
|
48
|
-
projectId: this.args.projectId,
|
|
49
|
-
};
|
|
51
|
+
this.adminSdkConfig = Object.assign(Object.assign({}, this.args.adminSdkConfig), { projectId: this.args.projectId });
|
|
50
52
|
const mode = this.args.debugPort
|
|
51
53
|
? types_1.FunctionsExecutionMode.SEQUENTIAL
|
|
52
54
|
: types_1.FunctionsExecutionMode.AUTO;
|
|
@@ -159,25 +161,17 @@ class FunctionsEmulator {
|
|
|
159
161
|
});
|
|
160
162
|
return hub;
|
|
161
163
|
}
|
|
162
|
-
startFunctionRuntime(backend,
|
|
163
|
-
const bundleTemplate = this.getBaseBundle(
|
|
164
|
-
const runtimeBundle = Object.assign(Object.assign({}, bundleTemplate), {
|
|
165
|
-
firestore: this.getEmulatorInfo(types_1.Emulators.FIRESTORE),
|
|
166
|
-
database: this.getEmulatorInfo(types_1.Emulators.DATABASE),
|
|
167
|
-
pubsub: this.getEmulatorInfo(types_1.Emulators.PUBSUB),
|
|
168
|
-
auth: this.getEmulatorInfo(types_1.Emulators.AUTH),
|
|
169
|
-
storage: this.getEmulatorInfo(types_1.Emulators.STORAGE),
|
|
170
|
-
}, nodeMajorVersion: backend.nodeMajorVersion, proto,
|
|
171
|
-
triggerId,
|
|
172
|
-
targetName });
|
|
164
|
+
async startFunctionRuntime(backend, trigger, proto, runtimeOpts) {
|
|
165
|
+
const bundleTemplate = this.getBaseBundle();
|
|
166
|
+
const runtimeBundle = Object.assign(Object.assign({}, bundleTemplate), { proto });
|
|
173
167
|
if (!backend.nodeBinary) {
|
|
174
|
-
throw new error_1.FirebaseError(`No node binary for ${
|
|
168
|
+
throw new error_1.FirebaseError(`No node binary for ${trigger.id}. This should never happen.`);
|
|
175
169
|
}
|
|
176
170
|
const opts = runtimeOpts || {
|
|
177
171
|
nodeBinary: backend.nodeBinary,
|
|
178
172
|
extensionTriggers: backend.predefinedTriggers,
|
|
179
173
|
};
|
|
180
|
-
const worker = this.invokeRuntime(
|
|
174
|
+
const worker = await this.invokeRuntime(backend, trigger, runtimeBundle, opts);
|
|
181
175
|
return worker;
|
|
182
176
|
}
|
|
183
177
|
async start() {
|
|
@@ -188,13 +182,15 @@ class FunctionsEmulator {
|
|
|
188
182
|
for (const e of this.args.emulatableBackends) {
|
|
189
183
|
e.env = Object.assign(Object.assign({}, credentialEnv), e.env);
|
|
190
184
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
185
|
+
if (Object.keys(this.adminSdkConfig || {}).length <= 1) {
|
|
186
|
+
const adminSdkConfig = await (0, adminSdkConfig_1.getProjectAdminSdkConfigOrCached)(this.args.projectId);
|
|
187
|
+
if (adminSdkConfig) {
|
|
188
|
+
this.adminSdkConfig = adminSdkConfig;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
this.logger.logLabeled("WARN", "functions", "Unable to fetch project Admin SDK configuration, Admin SDK behavior in Cloud Functions emulator may be incorrect.");
|
|
192
|
+
this.adminSdkConfig = (0, adminSdkConfig_1.constructDefaultAdminSdkConfig)(this.args.projectId);
|
|
193
|
+
}
|
|
198
194
|
}
|
|
199
195
|
const { host, port } = this.getInfo();
|
|
200
196
|
this.workQueue.start();
|
|
@@ -242,14 +238,26 @@ class FunctionsEmulator {
|
|
|
242
238
|
if (!emulatableBackend.nodeBinary) {
|
|
243
239
|
throw new error_1.FirebaseError(`No node binary for ${emulatableBackend.functionsDir}. This should never happen.`);
|
|
244
240
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
.
|
|
252
|
-
|
|
241
|
+
let triggerDefinitions;
|
|
242
|
+
if (emulatableBackend.predefinedTriggers) {
|
|
243
|
+
triggerDefinitions = (0, functionsEmulatorShared_1.emulatedFunctionsByRegion)(emulatableBackend.predefinedTriggers);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
const runtimeConfig = this.getRuntimeConfig(emulatableBackend);
|
|
247
|
+
const runtimeDelegate = await (0, runtimes_1.getRuntimeDelegate)({
|
|
248
|
+
projectId: this.args.projectId,
|
|
249
|
+
projectDir: this.args.projectDir,
|
|
250
|
+
sourceDir: emulatableBackend.functionsDir,
|
|
251
|
+
});
|
|
252
|
+
logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
|
|
253
|
+
await runtimeDelegate.validate();
|
|
254
|
+
logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
|
|
255
|
+
await runtimeDelegate.build();
|
|
256
|
+
logger_1.logger.debug(`Analyzing ${runtimeDelegate.name} backend spec`);
|
|
257
|
+
const discoveredBackend = await runtimeDelegate.discoverSpec(runtimeConfig, Object.assign(Object.assign(Object.assign(Object.assign({}, this.getSystemEnvs()), this.getEmulatorEnvs()), { FIREBASE_CONFIG: this.getFirebaseConfig() }), emulatableBackend.env));
|
|
258
|
+
const endpoints = backend.allEndpoints(discoveredBackend);
|
|
259
|
+
triggerDefinitions = (0, functionsEmulatorShared_1.emulatedFunctionsFromEndpoints)(endpoints);
|
|
260
|
+
}
|
|
253
261
|
const toSetup = triggerDefinitions.filter((definition) => {
|
|
254
262
|
if (force) {
|
|
255
263
|
return true;
|
|
@@ -305,7 +313,7 @@ class FunctionsEmulator {
|
|
|
305
313
|
}
|
|
306
314
|
}
|
|
307
315
|
else {
|
|
308
|
-
this.logger.log("WARN", `
|
|
316
|
+
this.logger.log("WARN", `Unsupported function type on ${definition.name}. Expected either httpsTrigger or eventTrigger.`);
|
|
309
317
|
}
|
|
310
318
|
const ignored = !added;
|
|
311
319
|
this.addTriggerRecord(definition, { backend: emulatableBackend, ignored, url });
|
|
@@ -331,7 +339,7 @@ class FunctionsEmulator {
|
|
|
331
339
|
}
|
|
332
340
|
const result = DATABASE_PATH_PATTERN.exec(eventTrigger.resource);
|
|
333
341
|
if (result === null || result.length !== 3) {
|
|
334
|
-
this.logger.log("WARN", `Event
|
|
342
|
+
this.logger.log("WARN", `Event function "${key}" has malformed "resource" member. ` + `${eventTrigger.resource}`);
|
|
335
343
|
return Promise.reject();
|
|
336
344
|
}
|
|
337
345
|
const instance = result[1];
|
|
@@ -347,7 +355,7 @@ class FunctionsEmulator {
|
|
|
347
355
|
setTriggersPath += `?ns=${instance}`;
|
|
348
356
|
}
|
|
349
357
|
else {
|
|
350
|
-
this.logger.log("WARN", `No project in use. Registering function
|
|
358
|
+
this.logger.log("WARN", `No project in use. Registering function for sentinel namespace '${constants_1.Constants.DEFAULT_DATABASE_EMULATOR_NAMESPACE}'`);
|
|
351
359
|
}
|
|
352
360
|
return api
|
|
353
361
|
.request("POST", setTriggersPath, {
|
|
@@ -362,7 +370,7 @@ class FunctionsEmulator {
|
|
|
362
370
|
return true;
|
|
363
371
|
})
|
|
364
372
|
.catch((err) => {
|
|
365
|
-
this.logger.log("WARN", "Error adding
|
|
373
|
+
this.logger.log("WARN", "Error adding Realtime Database function: " + err);
|
|
366
374
|
throw err;
|
|
367
375
|
});
|
|
368
376
|
}
|
|
@@ -371,7 +379,9 @@ class FunctionsEmulator {
|
|
|
371
379
|
if (!firestoreEmu) {
|
|
372
380
|
return Promise.resolve(false);
|
|
373
381
|
}
|
|
374
|
-
const bundle = JSON.stringify({
|
|
382
|
+
const bundle = JSON.stringify({
|
|
383
|
+
eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "firestore.googleapis.com" }),
|
|
384
|
+
});
|
|
375
385
|
logger_1.logger.debug(`addFirestoreTrigger`, JSON.stringify(bundle));
|
|
376
386
|
return api
|
|
377
387
|
.request("PUT", `/emulator/v1/projects/${projectId}/triggers/${key}`, {
|
|
@@ -383,7 +393,7 @@ class FunctionsEmulator {
|
|
|
383
393
|
return true;
|
|
384
394
|
})
|
|
385
395
|
.catch((err) => {
|
|
386
|
-
this.logger.log("WARN", "Error adding
|
|
396
|
+
this.logger.log("WARN", "Error adding firestore function: " + err);
|
|
387
397
|
throw err;
|
|
388
398
|
});
|
|
389
399
|
}
|
|
@@ -452,7 +462,7 @@ class FunctionsEmulator {
|
|
|
452
462
|
const record = this.triggers[triggerKey];
|
|
453
463
|
if (!record) {
|
|
454
464
|
logger_1.logger.debug(`Could not find key=${triggerKey} in ${JSON.stringify(this.triggers)}`);
|
|
455
|
-
throw new error_1.FirebaseError(`No
|
|
465
|
+
throw new error_1.FirebaseError(`No function with key ${triggerKey}`);
|
|
456
466
|
}
|
|
457
467
|
return record;
|
|
458
468
|
}
|
|
@@ -475,30 +485,12 @@ class FunctionsEmulator {
|
|
|
475
485
|
setTriggersForTesting(triggers, backend) {
|
|
476
486
|
triggers.forEach((def) => this.addTriggerRecord(def, { backend, ignored: false }));
|
|
477
487
|
}
|
|
478
|
-
getBaseBundle(
|
|
488
|
+
getBaseBundle() {
|
|
479
489
|
return {
|
|
480
|
-
|
|
481
|
-
projectId: this.args.projectId,
|
|
482
|
-
triggerId: "",
|
|
483
|
-
targetName: "",
|
|
484
|
-
emulators: {
|
|
485
|
-
firestore: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.FIRESTORE),
|
|
486
|
-
database: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.DATABASE),
|
|
487
|
-
pubsub: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.PUBSUB),
|
|
488
|
-
auth: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.AUTH),
|
|
489
|
-
storage: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.STORAGE),
|
|
490
|
-
},
|
|
491
|
-
adminSdkConfig: {
|
|
492
|
-
databaseURL: this.adminSdkConfig.databaseURL,
|
|
493
|
-
storageBucket: this.adminSdkConfig.storageBucket,
|
|
494
|
-
},
|
|
490
|
+
proto: {},
|
|
495
491
|
disabled_features: this.args.disabledRuntimeFeatures,
|
|
496
492
|
};
|
|
497
493
|
}
|
|
498
|
-
getRequestedNodeRuntimeVersion(frb) {
|
|
499
|
-
const pkg = require(path.join(frb.cwd, "package.json"));
|
|
500
|
-
return frb.nodeMajorVersion || (pkg.engines && pkg.engines.node);
|
|
501
|
-
}
|
|
502
494
|
getNodeBinary(backend) {
|
|
503
495
|
const pkg = require(path.join(backend.functionsDir, "package.json"));
|
|
504
496
|
if ((!pkg.engines || !pkg.engines.node) && !backend.nodeMajorVersion) {
|
|
@@ -530,6 +522,16 @@ class FunctionsEmulator {
|
|
|
530
522
|
}
|
|
531
523
|
return process.execPath;
|
|
532
524
|
}
|
|
525
|
+
getRuntimeConfig(backend) {
|
|
526
|
+
const configPath = `${backend.functionsDir}/.runtimeconfig.json`;
|
|
527
|
+
try {
|
|
528
|
+
const configContent = fs.readFileSync(configPath, "utf8");
|
|
529
|
+
return JSON.parse(configContent.toString());
|
|
530
|
+
}
|
|
531
|
+
catch (e) {
|
|
532
|
+
}
|
|
533
|
+
return {};
|
|
534
|
+
}
|
|
533
535
|
getUserEnvs(backend) {
|
|
534
536
|
const projectInfo = {
|
|
535
537
|
functionsSource: backend.functionsDir,
|
|
@@ -546,17 +548,16 @@ class FunctionsEmulator {
|
|
|
546
548
|
}
|
|
547
549
|
return {};
|
|
548
550
|
}
|
|
549
|
-
getSystemEnvs(
|
|
551
|
+
getSystemEnvs(trigger) {
|
|
550
552
|
const envs = {};
|
|
551
553
|
envs.GCLOUD_PROJECT = this.args.projectId;
|
|
552
554
|
envs.K_REVISION = "1";
|
|
553
555
|
envs.PORT = "80";
|
|
554
|
-
if (
|
|
555
|
-
const
|
|
556
|
-
const target = service.replace(/-/g, ".");
|
|
556
|
+
if (trigger) {
|
|
557
|
+
const target = trigger.entryPoint;
|
|
557
558
|
envs.FUNCTION_TARGET = target;
|
|
558
|
-
envs.FUNCTION_SIGNATURE_TYPE =
|
|
559
|
-
envs.K_SERVICE =
|
|
559
|
+
envs.FUNCTION_SIGNATURE_TYPE = (0, functionsEmulatorShared_1.getSignatureType)(trigger);
|
|
560
|
+
envs.K_SERVICE = trigger.name;
|
|
560
561
|
}
|
|
561
562
|
return envs;
|
|
562
563
|
}
|
|
@@ -607,12 +608,50 @@ class FunctionsEmulator {
|
|
|
607
608
|
projectId: this.args.projectId,
|
|
608
609
|
});
|
|
609
610
|
}
|
|
610
|
-
getRuntimeEnvs(backend,
|
|
611
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.getUserEnvs(backend)), this.getSystemEnvs(
|
|
611
|
+
getRuntimeEnvs(backend, trigger) {
|
|
612
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.getUserEnvs(backend)), this.getSystemEnvs(trigger)), this.getEmulatorEnvs()), { FIREBASE_CONFIG: this.getFirebaseConfig() }), backend.env);
|
|
613
|
+
}
|
|
614
|
+
async resolveSecretEnvs(backend, trigger) {
|
|
615
|
+
let secretEnvs = {};
|
|
616
|
+
try {
|
|
617
|
+
const data = fs.readFileSync(path.join(backend.functionsDir, LOCAL_SECRETS_FILE), "utf8");
|
|
618
|
+
secretEnvs = functionsEnv.parseStrict(data);
|
|
619
|
+
}
|
|
620
|
+
catch (e) {
|
|
621
|
+
if (e.code !== "ENOENT") {
|
|
622
|
+
this.logger.logLabeled("ERROR", "functions", `Failed to read local secrets file ${LOCAL_SECRETS_FILE}: ${e.message}`);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
const secrets = trigger.secretEnvironmentVariables || [];
|
|
626
|
+
const accesses = secrets
|
|
627
|
+
.filter((s) => !secretEnvs[s.secret])
|
|
628
|
+
.map(async (s) => {
|
|
629
|
+
this.logger.logLabeled("INFO", "functions", `Trying to access secret ${s.key}@latest`);
|
|
630
|
+
const value = await (0, secretManager_1.accessSecretVersion)(this.getProjectId(), s.key, "latest");
|
|
631
|
+
return [s.secret, value];
|
|
632
|
+
});
|
|
633
|
+
const accessResults = await (0, utils_1.allSettled)(accesses);
|
|
634
|
+
const errs = [];
|
|
635
|
+
for (const result of accessResults) {
|
|
636
|
+
if (result.status === "rejected") {
|
|
637
|
+
errs.push(result.reason);
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
const [k, v] = result.value;
|
|
641
|
+
secretEnvs[k] = v;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (errs.length > 0) {
|
|
645
|
+
this.logger.logLabeled("ERROR", "functions", "Unable to access secret environment variables from Google Cloud Secret Manager. " +
|
|
646
|
+
"Make sure the credential used for the Functions Emulator have access " +
|
|
647
|
+
`or provide override values in ${LOCAL_SECRETS_FILE}:\n\t` +
|
|
648
|
+
errs.join("\n\t"));
|
|
649
|
+
}
|
|
650
|
+
return secretEnvs;
|
|
612
651
|
}
|
|
613
|
-
invokeRuntime(frb, opts
|
|
614
|
-
if (this.workerPool.readyForWork(
|
|
615
|
-
return this.workerPool.submitWork(
|
|
652
|
+
async invokeRuntime(backend, trigger, frb, opts) {
|
|
653
|
+
if (this.workerPool.readyForWork(trigger.id)) {
|
|
654
|
+
return this.workerPool.submitWork(trigger.id, frb, opts);
|
|
616
655
|
}
|
|
617
656
|
const emitter = new events_1.EventEmitter();
|
|
618
657
|
const args = [path.join(__dirname, "functionsEmulatorRuntime")];
|
|
@@ -621,7 +660,7 @@ class FunctionsEmulator {
|
|
|
621
660
|
}
|
|
622
661
|
if (this.args.debugPort) {
|
|
623
662
|
if (process.env.FIREPIT_VERSION && process.execPath == opts.nodeBinary) {
|
|
624
|
-
const requestedMajorNodeVersion = this.
|
|
663
|
+
const requestedMajorNodeVersion = this.getNodeBinary(backend);
|
|
625
664
|
this.logger.log("WARN", `To enable function inspection, please run "${process.execPath} is:npm i node@${requestedMajorNodeVersion} --save-dev" in your functions directory`);
|
|
626
665
|
}
|
|
627
666
|
else {
|
|
@@ -629,15 +668,17 @@ class FunctionsEmulator {
|
|
|
629
668
|
args.unshift(`--inspect=${host}:${this.args.debugPort}`);
|
|
630
669
|
}
|
|
631
670
|
}
|
|
632
|
-
const pnpPath = path.join(
|
|
671
|
+
const pnpPath = path.join(backend.functionsDir, ".pnp.js");
|
|
633
672
|
if (fs.existsSync(pnpPath)) {
|
|
634
673
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN_ONCE", "functions", "Detected yarn@2 with PnP. " +
|
|
635
674
|
"Cloud Functions for Firebase requires a node_modules folder to work correctly and is therefore incompatible with PnP. " +
|
|
636
675
|
"See https://yarnpkg.com/getting-started/migration#step-by-step for more information.");
|
|
637
676
|
}
|
|
677
|
+
const runtimeEnv = this.getRuntimeEnvs(backend, trigger);
|
|
678
|
+
const secretEnvs = await this.resolveSecretEnvs(backend, trigger);
|
|
638
679
|
const childProcess = spawn(opts.nodeBinary, args, {
|
|
639
|
-
|
|
640
|
-
|
|
680
|
+
cwd: backend.functionsDir,
|
|
681
|
+
env: Object.assign(Object.assign(Object.assign({ node: opts.nodeBinary }, process.env), runtimeEnv), secretEnvs),
|
|
641
682
|
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
642
683
|
});
|
|
643
684
|
if (!childProcess.stderr) {
|
|
@@ -668,6 +709,7 @@ class FunctionsEmulator {
|
|
|
668
709
|
childProcess.on("exit", resolve);
|
|
669
710
|
}),
|
|
670
711
|
events: emitter,
|
|
712
|
+
cwd: backend.functionsDir,
|
|
671
713
|
shutdown: () => {
|
|
672
714
|
childProcess.kill();
|
|
673
715
|
},
|
|
@@ -679,8 +721,8 @@ class FunctionsEmulator {
|
|
|
679
721
|
return childProcess.send(JSON.stringify(args));
|
|
680
722
|
},
|
|
681
723
|
};
|
|
682
|
-
this.workerPool.addWorker(
|
|
683
|
-
return this.workerPool.submitWork(
|
|
724
|
+
this.workerPool.addWorker(trigger.id, runtime);
|
|
725
|
+
return this.workerPool.submitWork(trigger.id, frb, opts);
|
|
684
726
|
}
|
|
685
727
|
async disableBackgroundTriggers() {
|
|
686
728
|
Object.values(this.triggers).forEach((record) => {
|
|
@@ -706,7 +748,7 @@ class FunctionsEmulator {
|
|
|
706
748
|
}
|
|
707
749
|
const trigger = record.def;
|
|
708
750
|
const service = (0, functionsEmulatorShared_1.getFunctionService)(trigger);
|
|
709
|
-
const worker = this.startFunctionRuntime(record.backend, trigger
|
|
751
|
+
const worker = await this.startFunctionRuntime(record.backend, trigger, proto);
|
|
710
752
|
return new Promise((resolve, reject) => {
|
|
711
753
|
if (projectId !== this.args.projectId) {
|
|
712
754
|
if (service !== constants_1.Constants.SERVICE_REALTIME_DATABASE) {
|
|
@@ -740,7 +782,7 @@ class FunctionsEmulator {
|
|
|
740
782
|
return registry_1.EmulatorRegistry.getInfo(emulator);
|
|
741
783
|
}
|
|
742
784
|
tokenFromAuthHeader(authHeader) {
|
|
743
|
-
const match =
|
|
785
|
+
const match = /^Bearer (.*)$/.exec(authHeader);
|
|
744
786
|
if (!match) {
|
|
745
787
|
return;
|
|
746
788
|
}
|
|
@@ -772,7 +814,7 @@ class FunctionsEmulator {
|
|
|
772
814
|
if (!this.triggers[triggerId]) {
|
|
773
815
|
res
|
|
774
816
|
.status(404)
|
|
775
|
-
.send(`Function ${triggerId} does not exist, valid
|
|
817
|
+
.send(`Function ${triggerId} does not exist, valid functions are: ${Object.keys(this.triggers).join(", ")}`);
|
|
776
818
|
return;
|
|
777
819
|
}
|
|
778
820
|
const record = this.getTriggerRecordByKey(triggerId);
|
|
@@ -793,7 +835,7 @@ class FunctionsEmulator {
|
|
|
793
835
|
req.headers[functionsEmulatorShared_1.HttpConstants.CALLABLE_AUTH_HEADER] = encodeURIComponent(JSON.stringify(contextAuth));
|
|
794
836
|
}
|
|
795
837
|
}
|
|
796
|
-
const worker = this.startFunctionRuntime(record.backend, trigger
|
|
838
|
+
const worker = await this.startFunctionRuntime(record.backend, trigger);
|
|
797
839
|
worker.onLogs((el) => {
|
|
798
840
|
if (el.level === "FATAL") {
|
|
799
841
|
res.status(500).send(el.text);
|