firebase-tools 9.18.0 → 9.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/CHANGELOG.md +3 -6
- package/lib/api.js +3 -0
- package/lib/apiv2.js +8 -5
- package/lib/command.js +1 -1
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/deploy.js +9 -1
- package/lib/commands/ext-configure.js +9 -2
- package/lib/commands/ext-dev-deprecate.js +63 -0
- package/lib/commands/ext-dev-extension-delete.js +2 -1
- package/lib/commands/ext-dev-publish.js +10 -4
- package/lib/commands/ext-dev-undeprecate.js +56 -0
- package/lib/commands/ext-dev-unpublish.js +12 -4
- package/lib/commands/ext-export.js +44 -0
- package/lib/commands/ext-install.js +50 -13
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +60 -18
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +47 -25
- package/lib/commands/functions-list.js +12 -12
- package/lib/commands/index.js +9 -0
- package/lib/commands/init.js +3 -0
- package/lib/config.js +3 -2
- package/lib/deploy/extensions/args.js +2 -0
- package/lib/deploy/extensions/deploy.js +49 -0
- package/lib/deploy/extensions/deploymentSummary.js +52 -0
- package/lib/deploy/extensions/errors.js +31 -0
- package/lib/deploy/extensions/index.js +8 -0
- package/lib/deploy/extensions/planner.js +95 -0
- package/lib/deploy/extensions/prepare.js +103 -0
- package/lib/deploy/extensions/release.js +43 -0
- package/lib/deploy/extensions/secrets.js +150 -0
- package/lib/deploy/extensions/tasks.js +98 -0
- package/lib/deploy/extensions/validate.js +17 -0
- package/lib/deploy/functions/backend.js +93 -115
- package/lib/deploy/functions/checkIam.js +8 -8
- package/lib/deploy/functions/containerCleaner.js +82 -22
- package/lib/deploy/functions/deploy.js +4 -10
- package/lib/deploy/functions/functionsDeployHelper.js +3 -68
- package/lib/deploy/functions/prepare.js +62 -27
- package/lib/deploy/functions/pricing.js +17 -17
- package/lib/deploy/functions/prompts.js +22 -21
- package/lib/deploy/functions/release/executor.js +39 -0
- package/lib/deploy/functions/release/fabricator.js +422 -0
- package/lib/deploy/functions/release/index.js +73 -0
- package/lib/deploy/functions/release/planner.js +162 -0
- package/lib/deploy/functions/release/reporter.js +165 -0
- package/lib/deploy/functions/release/sourceTokenScraper.js +28 -0
- package/lib/deploy/functions/release/timer.js +14 -0
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +129 -126
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +41 -45
- package/lib/deploy/functions/triggerRegionHelper.js +40 -0
- package/lib/deploy/functions/validate.js +1 -24
- package/lib/deploy/index.js +1 -0
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +1788 -403
- package/lib/emulator/auth/handlers.js +6 -5
- package/lib/emulator/auth/operations.js +439 -40
- package/lib/emulator/auth/server.js +32 -11
- package/lib/emulator/auth/state.js +205 -5
- package/lib/emulator/auth/widget_ui.js +2 -2
- package/lib/emulator/download.js +2 -31
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/emulatorLogger.js +0 -3
- package/lib/emulator/events/types.js +16 -0
- package/lib/emulator/functionsEmulator.js +120 -21
- package/lib/emulator/functionsEmulatorRuntime.js +46 -121
- package/lib/emulator/functionsEmulatorShared.js +51 -7
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/pubsubEmulator.js +61 -40
- package/lib/emulator/storage/cloudFunctions.js +37 -7
- package/lib/extensions/askUserForConsent.js +14 -1
- package/lib/extensions/askUserForParam.js +81 -4
- package/lib/extensions/billingMigrationHelper.js +1 -11
- package/lib/extensions/changelog.js +2 -1
- package/lib/extensions/checkProjectBilling.js +7 -7
- package/lib/extensions/displayExtensionInfo.js +35 -33
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/triggerHelper.js +2 -32
- package/lib/extensions/export.js +107 -0
- package/lib/extensions/extensionsApi.js +149 -97
- package/lib/extensions/extensionsHelper.js +36 -32
- package/lib/extensions/listExtensions.js +16 -11
- package/lib/extensions/paramHelper.js +73 -40
- package/lib/extensions/provisioningHelper.js +16 -3
- package/lib/extensions/refs.js +67 -0
- package/lib/extensions/secretsUtils.js +59 -0
- package/lib/extensions/updateHelper.js +33 -47
- package/lib/extensions/versionHelper.js +14 -0
- package/lib/extensions/warnings.js +33 -1
- package/lib/functional.js +64 -0
- package/lib/functions/env.js +26 -13
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/artifactregistry.js +16 -0
- package/lib/gcp/cloudfunctions.js +65 -35
- package/lib/gcp/cloudfunctionsv2.js +56 -43
- package/lib/gcp/cloudscheduler.js +22 -16
- package/lib/gcp/cloudtasks.js +143 -0
- package/lib/gcp/docker.js +7 -1
- package/lib/gcp/proto.js +2 -2
- package/lib/gcp/pubsub.js +1 -9
- package/lib/gcp/secretManager.js +132 -0
- package/lib/gcp/storage.js +16 -0
- package/lib/previews.js +1 -1
- package/lib/requireInteractive.js +12 -0
- package/lib/utils.js +30 -1
- package/package.json +6 -4
- package/schema/firebase-config.json +9 -0
- package/lib/deploy/functions/deploymentPlanner.js +0 -113
- package/lib/deploy/functions/deploymentTimer.js +0 -23
- package/lib/deploy/functions/errorHandler.js +0 -75
- package/lib/deploy/functions/release.js +0 -116
- package/lib/deploy/functions/tasks.js +0 -324
- package/lib/functions/listFunctions.js +0 -10
- package/lib/functionsDelete.js +0 -60
|
@@ -8,6 +8,7 @@ const express = require("express");
|
|
|
8
8
|
const clc = require("cli-color");
|
|
9
9
|
const http = require("http");
|
|
10
10
|
const jwt = require("jsonwebtoken");
|
|
11
|
+
const url_1 = require("url");
|
|
11
12
|
const api = require("../api");
|
|
12
13
|
const logger_1 = require("../logger");
|
|
13
14
|
const track = require("../track");
|
|
@@ -26,6 +27,8 @@ const workQueue_1 = require("./workQueue");
|
|
|
26
27
|
const utils_1 = require("../utils");
|
|
27
28
|
const defaultCredentials_1 = require("../defaultCredentials");
|
|
28
29
|
const adminSdkConfig_1 = require("./adminSdkConfig");
|
|
30
|
+
const functionsEnv = require("../functions/env");
|
|
31
|
+
const types_2 = require("./events/types");
|
|
29
32
|
const EVENT_INVOKE = "functions:invoke";
|
|
30
33
|
const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
|
|
31
34
|
class FunctionsEmulator {
|
|
@@ -88,11 +91,18 @@ class FunctionsEmulator {
|
|
|
88
91
|
const multicastFunctionRoute = `/functions/projects/:project_id/trigger_multicast`;
|
|
89
92
|
const httpsFunctionRoutes = [httpsFunctionRoute, `${httpsFunctionRoute}/*`];
|
|
90
93
|
const backgroundHandler = (req, res) => {
|
|
94
|
+
var _a;
|
|
91
95
|
const region = req.params.region;
|
|
92
96
|
const triggerId = req.params.trigger_name;
|
|
93
97
|
const projectId = req.params.project_id;
|
|
94
98
|
const reqBody = req.rawBody;
|
|
95
|
-
|
|
99
|
+
let proto = JSON.parse(reqBody.toString());
|
|
100
|
+
if ((_a = req.headers["content-type"]) === null || _a === void 0 ? void 0 : _a.includes("cloudevent")) {
|
|
101
|
+
if (types_2.EventUtils.isBinaryCloudEvent(req)) {
|
|
102
|
+
proto = types_2.EventUtils.extractBinaryCloudEventContext(req);
|
|
103
|
+
proto.data = req.body;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
96
106
|
this.workQueue.submit(() => {
|
|
97
107
|
this.logger.log("DEBUG", `Accepted request ${req.method} ${req.url} --> ${triggerId}`);
|
|
98
108
|
return this.handleBackgroundTrigger(projectId, triggerId, proto)
|
|
@@ -113,10 +123,22 @@ class FunctionsEmulator {
|
|
|
113
123
|
});
|
|
114
124
|
};
|
|
115
125
|
const multicastHandler = (req, res) => {
|
|
116
|
-
|
|
117
|
-
const proto = JSON.parse(reqBody.toString());
|
|
118
|
-
const triggers = this.multicastTriggers[`${this.args.projectId}:${proto.eventType}`] || [];
|
|
126
|
+
var _a;
|
|
119
127
|
const projectId = req.params.project_id;
|
|
128
|
+
const reqBody = req.rawBody;
|
|
129
|
+
let proto = JSON.parse(reqBody.toString());
|
|
130
|
+
let triggerKey;
|
|
131
|
+
if ((_a = req.headers["content-type"]) === null || _a === void 0 ? void 0 : _a.includes("cloudevent")) {
|
|
132
|
+
triggerKey = `${this.args.projectId}:${proto.type}`;
|
|
133
|
+
if (types_2.EventUtils.isBinaryCloudEvent(req)) {
|
|
134
|
+
proto = types_2.EventUtils.extractBinaryCloudEventContext(req);
|
|
135
|
+
proto.data = req.body;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
triggerKey = `${this.args.projectId}:${proto.eventType}`;
|
|
140
|
+
}
|
|
141
|
+
const triggers = this.multicastTriggers[triggerKey] || [];
|
|
120
142
|
triggers.forEach((triggerId) => {
|
|
121
143
|
this.workQueue.submit(() => {
|
|
122
144
|
this.logger.log("DEBUG", `Accepted multicast request ${req.method} ${req.url} --> ${triggerId}`);
|
|
@@ -134,7 +156,7 @@ class FunctionsEmulator {
|
|
|
134
156
|
});
|
|
135
157
|
return hub;
|
|
136
158
|
}
|
|
137
|
-
startFunctionRuntime(triggerId, targetName,
|
|
159
|
+
startFunctionRuntime(triggerId, targetName, signatureType, proto, runtimeOpts) {
|
|
138
160
|
const bundleTemplate = this.getBaseBundle();
|
|
139
161
|
const runtimeBundle = Object.assign(Object.assign({}, bundleTemplate), { emulators: {
|
|
140
162
|
firestore: this.getEmulatorInfo(types_1.Emulators.FIRESTORE),
|
|
@@ -144,14 +166,12 @@ class FunctionsEmulator {
|
|
|
144
166
|
storage: this.getEmulatorInfo(types_1.Emulators.STORAGE),
|
|
145
167
|
}, nodeMajorVersion: this.args.nodeMajorVersion, proto,
|
|
146
168
|
triggerId,
|
|
147
|
-
targetName
|
|
148
|
-
triggerType });
|
|
169
|
+
targetName });
|
|
149
170
|
const opts = runtimeOpts || {
|
|
150
171
|
nodeBinary: this.nodeBinary,
|
|
151
|
-
env: this.args.env,
|
|
152
172
|
extensionTriggers: this.args.predefinedTriggers,
|
|
153
173
|
};
|
|
154
|
-
const worker = this.invokeRuntime(runtimeBundle, opts);
|
|
174
|
+
const worker = this.invokeRuntime(runtimeBundle, opts, this.getRuntimeEnvs({ targetName, signatureType }));
|
|
155
175
|
return worker;
|
|
156
176
|
}
|
|
157
177
|
async start() {
|
|
@@ -206,9 +226,8 @@ class FunctionsEmulator {
|
|
|
206
226
|
this.workerPool.refresh();
|
|
207
227
|
const worker = this.invokeRuntime(this.getBaseBundle(), {
|
|
208
228
|
nodeBinary: this.nodeBinary,
|
|
209
|
-
env: this.args.env,
|
|
210
229
|
extensionTriggers: this.args.predefinedTriggers,
|
|
211
|
-
});
|
|
230
|
+
}, Object.assign(Object.assign(Object.assign(Object.assign({}, this.getSystemEnvs()), this.getEmulatorEnvs()), { FIREBASE_CONFIG: this.getFirebaseConfig() }), this.args.env));
|
|
212
231
|
const triggerParseEvent = await types_1.EmulatorLog.waitForLog(worker.runtime.events, "SYSTEM", "triggers-parsed");
|
|
213
232
|
const parsedDefinitions = triggerParseEvent.data
|
|
214
233
|
.triggerDefinitions;
|
|
@@ -238,6 +257,7 @@ class FunctionsEmulator {
|
|
|
238
257
|
else if (definition.eventTrigger) {
|
|
239
258
|
const service = functionsEmulatorShared_1.getFunctionService(definition);
|
|
240
259
|
const key = this.getTriggerKey(definition);
|
|
260
|
+
const signature = functionsEmulatorShared_1.getSignatureType(definition);
|
|
241
261
|
switch (service) {
|
|
242
262
|
case constants_1.Constants.SERVICE_FIRESTORE:
|
|
243
263
|
added = await this.addFirestoreTrigger(this.args.projectId, key, definition.eventTrigger);
|
|
@@ -246,7 +266,7 @@ class FunctionsEmulator {
|
|
|
246
266
|
added = await this.addRealtimeDatabaseTrigger(this.args.projectId, key, definition.eventTrigger);
|
|
247
267
|
break;
|
|
248
268
|
case constants_1.Constants.SERVICE_PUBSUB:
|
|
249
|
-
added = await this.addPubsubTrigger(definition.name, key, definition.eventTrigger, definition.schedule);
|
|
269
|
+
added = await this.addPubsubTrigger(definition.name, key, definition.eventTrigger, signature, definition.schedule);
|
|
250
270
|
break;
|
|
251
271
|
case constants_1.Constants.SERVICE_AUTH:
|
|
252
272
|
added = this.addAuthTrigger(this.args.projectId, key, definition.eventTrigger);
|
|
@@ -342,7 +362,7 @@ class FunctionsEmulator {
|
|
|
342
362
|
throw err;
|
|
343
363
|
});
|
|
344
364
|
}
|
|
345
|
-
async addPubsubTrigger(triggerName, key, eventTrigger, schedule) {
|
|
365
|
+
async addPubsubTrigger(triggerName, key, eventTrigger, signatureType, schedule) {
|
|
346
366
|
const pubsubPort = registry_1.EmulatorRegistry.getPort(types_1.Emulators.PUBSUB);
|
|
347
367
|
if (!pubsubPort) {
|
|
348
368
|
return false;
|
|
@@ -359,7 +379,7 @@ class FunctionsEmulator {
|
|
|
359
379
|
topic = resourceParts[resourceParts.length - 1];
|
|
360
380
|
}
|
|
361
381
|
try {
|
|
362
|
-
await pubsubEmulator.addTrigger(topic, key);
|
|
382
|
+
await pubsubEmulator.addTrigger(topic, key, signatureType);
|
|
363
383
|
return true;
|
|
364
384
|
}
|
|
365
385
|
catch (e) {
|
|
@@ -424,7 +444,6 @@ class FunctionsEmulator {
|
|
|
424
444
|
projectId: this.args.projectId,
|
|
425
445
|
triggerId: "",
|
|
426
446
|
targetName: "",
|
|
427
|
-
triggerType: undefined,
|
|
428
447
|
emulators: {
|
|
429
448
|
firestore: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.FIRESTORE),
|
|
430
449
|
database: registry_1.EmulatorRegistry.getInfo(types_1.Emulators.DATABASE),
|
|
@@ -473,7 +492,87 @@ class FunctionsEmulator {
|
|
|
473
492
|
this.logger.log("WARN", `Your requested "node" version "${requestedMajorVersion}" doesn't match your global version "${hostMajorVersion}"`);
|
|
474
493
|
return process.execPath;
|
|
475
494
|
}
|
|
476
|
-
|
|
495
|
+
getUserEnvs() {
|
|
496
|
+
const projectInfo = {
|
|
497
|
+
functionsSource: this.args.functionsDir,
|
|
498
|
+
projectId: this.args.projectId,
|
|
499
|
+
isEmulator: true,
|
|
500
|
+
};
|
|
501
|
+
if (functionsEnv.hasUserEnvs(projectInfo)) {
|
|
502
|
+
try {
|
|
503
|
+
return functionsEnv.loadUserEnvs(projectInfo);
|
|
504
|
+
}
|
|
505
|
+
catch (e) {
|
|
506
|
+
logger_1.logger.debug("Failed to load local environment variables", e);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return {};
|
|
510
|
+
}
|
|
511
|
+
getSystemEnvs(triggerDef) {
|
|
512
|
+
const envs = {};
|
|
513
|
+
envs.GCLOUD_PROJECT = this.args.projectId;
|
|
514
|
+
envs.K_REVISION = "1";
|
|
515
|
+
envs.PORT = "80";
|
|
516
|
+
if (triggerDef) {
|
|
517
|
+
const service = triggerDef.targetName;
|
|
518
|
+
const target = service.replace(/-/g, ".");
|
|
519
|
+
envs.FUNCTION_TARGET = target;
|
|
520
|
+
envs.FUNCTION_SIGNATURE_TYPE = triggerDef.signatureType;
|
|
521
|
+
envs.K_SERVICE = service;
|
|
522
|
+
}
|
|
523
|
+
return envs;
|
|
524
|
+
}
|
|
525
|
+
getEmulatorEnvs() {
|
|
526
|
+
const envs = {};
|
|
527
|
+
envs.FUNCTIONS_EMULATOR = "true";
|
|
528
|
+
envs.TZ = "UTC";
|
|
529
|
+
envs.FIREBASE_DEBUG_MODE = "true";
|
|
530
|
+
envs.FIREBASE_DEBUG_FEATURES = JSON.stringify({ skipTokenVerification: true });
|
|
531
|
+
const firestoreEmulator = this.getEmulatorInfo(types_1.Emulators.FIRESTORE);
|
|
532
|
+
if (firestoreEmulator != null) {
|
|
533
|
+
envs[constants_1.Constants.FIRESTORE_EMULATOR_HOST] = functionsEmulatorShared_1.formatHost(firestoreEmulator);
|
|
534
|
+
}
|
|
535
|
+
const databaseEmulator = this.getEmulatorInfo(types_1.Emulators.DATABASE);
|
|
536
|
+
if (databaseEmulator) {
|
|
537
|
+
envs[constants_1.Constants.FIREBASE_DATABASE_EMULATOR_HOST] = functionsEmulatorShared_1.formatHost(databaseEmulator);
|
|
538
|
+
}
|
|
539
|
+
const authEmulator = this.getEmulatorInfo(types_1.Emulators.AUTH);
|
|
540
|
+
if (authEmulator) {
|
|
541
|
+
envs[constants_1.Constants.FIREBASE_AUTH_EMULATOR_HOST] = functionsEmulatorShared_1.formatHost(authEmulator);
|
|
542
|
+
}
|
|
543
|
+
const storageEmulator = this.getEmulatorInfo(types_1.Emulators.STORAGE);
|
|
544
|
+
if (storageEmulator) {
|
|
545
|
+
envs[constants_1.Constants.FIREBASE_STORAGE_EMULATOR_HOST] = functionsEmulatorShared_1.formatHost(storageEmulator);
|
|
546
|
+
envs[constants_1.Constants.CLOUD_STORAGE_EMULATOR_HOST] = `http://${functionsEmulatorShared_1.formatHost(storageEmulator)}`;
|
|
547
|
+
}
|
|
548
|
+
const pubsubEmulator = this.getEmulatorInfo(types_1.Emulators.PUBSUB);
|
|
549
|
+
if (pubsubEmulator) {
|
|
550
|
+
const pubsubHost = functionsEmulatorShared_1.formatHost(pubsubEmulator);
|
|
551
|
+
process.env.PUBSUB_EMULATOR_HOST = pubsubHost;
|
|
552
|
+
}
|
|
553
|
+
return envs;
|
|
554
|
+
}
|
|
555
|
+
getFirebaseConfig() {
|
|
556
|
+
const databaseEmulator = this.getEmulatorInfo(types_1.Emulators.DATABASE);
|
|
557
|
+
let emulatedDatabaseURL = undefined;
|
|
558
|
+
if (databaseEmulator) {
|
|
559
|
+
let ns = this.args.projectId;
|
|
560
|
+
if (this.adminSdkConfig.databaseURL) {
|
|
561
|
+
const asUrl = new url_1.URL(this.adminSdkConfig.databaseURL);
|
|
562
|
+
ns = asUrl.hostname.split(".")[0];
|
|
563
|
+
}
|
|
564
|
+
emulatedDatabaseURL = `http://${functionsEmulatorShared_1.formatHost(databaseEmulator)}/?ns=${ns}`;
|
|
565
|
+
}
|
|
566
|
+
return JSON.stringify({
|
|
567
|
+
storageBucket: this.adminSdkConfig.storageBucket,
|
|
568
|
+
databaseURL: emulatedDatabaseURL || this.adminSdkConfig.databaseURL,
|
|
569
|
+
projectId: this.args.projectId,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
getRuntimeEnvs(triggerDef) {
|
|
573
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.getUserEnvs()), this.getSystemEnvs(triggerDef)), this.getEmulatorEnvs()), { FIREBASE_CONFIG: this.getFirebaseConfig() }), this.args.env);
|
|
574
|
+
}
|
|
575
|
+
invokeRuntime(frb, opts, runtimeEnv) {
|
|
477
576
|
if (this.workerPool.readyForWork(frb.triggerId)) {
|
|
478
577
|
return this.workerPool.submitWork(frb.triggerId, frb, opts);
|
|
479
578
|
}
|
|
@@ -499,7 +598,7 @@ class FunctionsEmulator {
|
|
|
499
598
|
"See https://yarnpkg.com/getting-started/migration#step-by-step for more information.");
|
|
500
599
|
}
|
|
501
600
|
const childProcess = spawn(opts.nodeBinary, args, {
|
|
502
|
-
env: Object.assign(Object.assign({ node: opts.nodeBinary },
|
|
601
|
+
env: Object.assign(Object.assign({ node: opts.nodeBinary }, process.env), (runtimeEnv !== null && runtimeEnv !== void 0 ? runtimeEnv : {})),
|
|
503
602
|
cwd: frb.cwd,
|
|
504
603
|
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
505
604
|
});
|
|
@@ -559,7 +658,7 @@ class FunctionsEmulator {
|
|
|
559
658
|
}
|
|
560
659
|
const trigger = this.getTriggerDefinitionByKey(triggerKey);
|
|
561
660
|
const service = functionsEmulatorShared_1.getFunctionService(trigger);
|
|
562
|
-
const worker = this.startFunctionRuntime(trigger.id, trigger.name, functionsEmulatorShared_1.
|
|
661
|
+
const worker = this.startFunctionRuntime(trigger.id, trigger.name, functionsEmulatorShared_1.getSignatureType(trigger), proto);
|
|
563
662
|
return new Promise((resolve, reject) => {
|
|
564
663
|
if (projectId !== this.args.projectId) {
|
|
565
664
|
if (service !== constants_1.Constants.SERVICE_REALTIME_DATABASE) {
|
|
@@ -633,7 +732,7 @@ class FunctionsEmulator {
|
|
|
633
732
|
const reqBody = req.rawBody;
|
|
634
733
|
const isCallable = trigger.labels && trigger.labels["deployment-callable"] === "true";
|
|
635
734
|
const authHeader = req.header("Authorization");
|
|
636
|
-
if (authHeader && isCallable) {
|
|
735
|
+
if (authHeader && isCallable && trigger.platform !== "gcfv2") {
|
|
637
736
|
const token = this.tokenFromAuthHeader(authHeader);
|
|
638
737
|
if (token) {
|
|
639
738
|
const contextAuth = {
|
|
@@ -645,7 +744,7 @@ class FunctionsEmulator {
|
|
|
645
744
|
req.headers[functionsEmulatorShared_1.HttpConstants.CALLABLE_AUTH_HEADER] = encodeURIComponent(JSON.stringify(contextAuth));
|
|
646
745
|
}
|
|
647
746
|
}
|
|
648
|
-
const worker = this.startFunctionRuntime(trigger.id, trigger.name,
|
|
747
|
+
const worker = this.startFunctionRuntime(trigger.id, trigger.name, "http", undefined);
|
|
649
748
|
worker.onLogs((el) => {
|
|
650
749
|
if (el.level === "FATAL") {
|
|
651
750
|
res.status(500).send(el.text);
|
|
@@ -660,7 +759,7 @@ class FunctionsEmulator {
|
|
|
660
759
|
if (!worker.lastArgs.frb.socketPath) {
|
|
661
760
|
throw new error_1.FirebaseError(`Cannot execute on a worker without a socketPath: ${JSON.stringify(worker.lastArgs)}`);
|
|
662
761
|
}
|
|
663
|
-
const url = new URL(`${req.protocol}://${req.hostname}${req.url}`);
|
|
762
|
+
const url = new url_1.URL(`${req.protocol}://${req.hostname}${req.url}`);
|
|
664
763
|
const path = `${url.pathname}${url.search}`.replace(new RegExp(`\/${this.args.projectId}\/[^\/]*\/${triggerName}\/?`), "/");
|
|
665
764
|
this.logger.log("DEBUG", `[functions] Got req.url=${req.url}, mapping to path=${path}`);
|
|
666
765
|
const runtimeReq = http.request({
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const functionsEnv = require("../functions/env");
|
|
4
|
-
const error_1 = require("../error");
|
|
5
3
|
const types_1 = require("./types");
|
|
6
4
|
const functionsEmulatorShared_1 = require("./functionsEmulatorShared");
|
|
7
|
-
const constants_1 = require("./constants");
|
|
8
5
|
const functionsEmulatorUtils_1 = require("./functionsEmulatorUtils");
|
|
9
6
|
const express = require("express");
|
|
10
7
|
const path = require("path");
|
|
11
8
|
const bodyParser = require("body-parser");
|
|
12
|
-
const fs = require("fs");
|
|
13
9
|
const url_1 = require("url");
|
|
14
10
|
const _ = require("lodash");
|
|
15
11
|
let triggers;
|
|
@@ -263,13 +259,35 @@ async function initializeFirebaseFunctionsStubs(frb) {
|
|
|
263
259
|
};
|
|
264
260
|
const onCallInnerMethodName = "_onCallWithOptions";
|
|
265
261
|
const onCallMethodOriginal = httpsProvider[onCallInnerMethodName];
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
262
|
+
if (onCallMethodOriginal.length === 3) {
|
|
263
|
+
httpsProvider[onCallInnerMethodName] = (opts, handler, deployOpts) => {
|
|
264
|
+
const wrapped = wrapCallableHandler(handler);
|
|
265
|
+
const cf = onCallMethodOriginal(opts, wrapped, deployOpts);
|
|
266
|
+
return cf;
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
httpsProvider[onCallInnerMethodName] = (handler, opts) => {
|
|
271
|
+
const wrapped = wrapCallableHandler(handler);
|
|
272
|
+
const cf = onCallMethodOriginal(wrapped, opts);
|
|
273
|
+
return cf;
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
httpsProvider.onCall = function (optsOrHandler, handler) {
|
|
277
|
+
if (onCallMethodOriginal.length === 3) {
|
|
278
|
+
let opts;
|
|
279
|
+
if (arguments.length === 1) {
|
|
280
|
+
opts = {};
|
|
281
|
+
handler = optsOrHandler;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
opts = optsOrHandler;
|
|
285
|
+
}
|
|
286
|
+
return httpsProvider[onCallInnerMethodName](opts, handler, {});
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
return httpsProvider[onCallInnerMethodName](optsOrHandler, {});
|
|
290
|
+
}
|
|
273
291
|
};
|
|
274
292
|
}
|
|
275
293
|
function wrapCallableHandler(handler) {
|
|
@@ -393,108 +411,6 @@ function warnAboutAuthProd(frb) {
|
|
|
393
411
|
}
|
|
394
412
|
new types_1.EmulatorLog("WARN_ONCE", "runtime-status", "The Firebase Authentication emulator is not running, so calls to Firebase Authentication will affect production.").log();
|
|
395
413
|
}
|
|
396
|
-
async function initializeEnvironmentalVariables(frb) {
|
|
397
|
-
var _a;
|
|
398
|
-
process.env.TZ = "UTC";
|
|
399
|
-
process.env.GCLOUD_PROJECT = frb.projectId;
|
|
400
|
-
process.env.FUNCTIONS_EMULATOR = "true";
|
|
401
|
-
if (functionsEnv.hasUserEnvs({ functionsSource: frb.cwd, projectId: "local" })) {
|
|
402
|
-
try {
|
|
403
|
-
const userEnvs = functionsEnv.loadUserEnvs({ functionsSource: frb.cwd, projectId: "local" });
|
|
404
|
-
for (const [k, v] of Object.entries(userEnvs)) {
|
|
405
|
-
process.env[k] = v;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
catch (e) {
|
|
409
|
-
let message = e.message || `${e}`;
|
|
410
|
-
if (e instanceof error_1.FirebaseError) {
|
|
411
|
-
for (const child of e.children) {
|
|
412
|
-
if (child instanceof Error) {
|
|
413
|
-
message += `\n- ${child.message}`;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
new types_1.EmulatorLog("SYSTEM", "function-env-load-failed", message).log();
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
const configPath = `${frb.cwd}/.runtimeconfig.json`;
|
|
421
|
-
try {
|
|
422
|
-
const configContent = fs.readFileSync(configPath, "utf8");
|
|
423
|
-
if (configContent) {
|
|
424
|
-
try {
|
|
425
|
-
JSON.parse(configContent.toString());
|
|
426
|
-
logDebug(`Found local functions config: ${configPath}`);
|
|
427
|
-
process.env.CLOUD_RUNTIME_CONFIG = configContent.toString();
|
|
428
|
-
}
|
|
429
|
-
catch (e) {
|
|
430
|
-
new types_1.EmulatorLog("SYSTEM", "function-runtimeconfig-json-invalid", "").log();
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
catch (e) {
|
|
435
|
-
}
|
|
436
|
-
const functionsResolution = await assertResolveDeveloperNodeModule(frb, "firebase-functions");
|
|
437
|
-
const functionsGt380 = functionsEmulatorUtils_1.compareVersionStrings(functionsResolution.version, "3.8.0") >= 0;
|
|
438
|
-
let emulatedDatabaseURL = undefined;
|
|
439
|
-
if (frb.emulators.database && functionsGt380) {
|
|
440
|
-
let ns = frb.projectId;
|
|
441
|
-
if (frb.adminSdkConfig.databaseURL) {
|
|
442
|
-
const asUrl = new url_1.URL(frb.adminSdkConfig.databaseURL);
|
|
443
|
-
ns = asUrl.hostname.split(".")[0];
|
|
444
|
-
}
|
|
445
|
-
emulatedDatabaseURL = `http://${formatHost(frb.emulators.database)}/?ns=${ns}`;
|
|
446
|
-
}
|
|
447
|
-
process.env.FIREBASE_CONFIG = JSON.stringify({
|
|
448
|
-
storageBucket: frb.adminSdkConfig.storageBucket,
|
|
449
|
-
databaseURL: emulatedDatabaseURL || frb.adminSdkConfig.databaseURL,
|
|
450
|
-
projectId: frb.projectId,
|
|
451
|
-
});
|
|
452
|
-
if (frb.triggerId) {
|
|
453
|
-
const service = frb.targetName || "";
|
|
454
|
-
const target = service.replace(/-/g, ".");
|
|
455
|
-
const mode = frb.triggerType === functionsEmulatorShared_1.EmulatedTriggerType.BACKGROUND ? "event" : "http";
|
|
456
|
-
let nodeVersion = 0;
|
|
457
|
-
if (frb.nodeMajorVersion) {
|
|
458
|
-
nodeVersion = frb.nodeMajorVersion;
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
const pkg = requirePackageJson(frb);
|
|
462
|
-
if ((_a = pkg === null || pkg === void 0 ? void 0 : pkg.engines) === null || _a === void 0 ? void 0 : _a.node) {
|
|
463
|
-
const nodeSemVer = functionsEmulatorUtils_1.parseVersionString(pkg.engines.node);
|
|
464
|
-
nodeVersion = nodeSemVer.major;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
if (nodeVersion >= 10) {
|
|
468
|
-
setNode10EnvVars(target, mode, service);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
if (frb.emulators.firestore) {
|
|
472
|
-
process.env[constants_1.Constants.FIRESTORE_EMULATOR_HOST] = formatHost(frb.emulators.firestore);
|
|
473
|
-
}
|
|
474
|
-
if (frb.emulators.database) {
|
|
475
|
-
process.env[constants_1.Constants.FIREBASE_DATABASE_EMULATOR_HOST] = formatHost(frb.emulators.database);
|
|
476
|
-
}
|
|
477
|
-
if (frb.emulators.auth) {
|
|
478
|
-
process.env[constants_1.Constants.FIREBASE_AUTH_EMULATOR_HOST] = formatHost(frb.emulators.auth);
|
|
479
|
-
}
|
|
480
|
-
if (frb.emulators.storage) {
|
|
481
|
-
process.env[constants_1.Constants.FIREBASE_STORAGE_EMULATOR_HOST] = formatHost(frb.emulators.storage);
|
|
482
|
-
process.env[constants_1.Constants.CLOUD_STORAGE_EMULATOR_HOST] = `http://${formatHost(frb.emulators.storage)}`;
|
|
483
|
-
}
|
|
484
|
-
if (frb.emulators.pubsub) {
|
|
485
|
-
const pubsubHost = formatHost(frb.emulators.pubsub);
|
|
486
|
-
process.env.PUBSUB_EMULATOR_HOST = pubsubHost;
|
|
487
|
-
logDebug(`Set PUBSUB_EMULATOR_HOST to ${pubsubHost}`);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
function formatHost(info) {
|
|
491
|
-
if (info.host.includes(":")) {
|
|
492
|
-
return `[${info.host}]:${info.port}`;
|
|
493
|
-
}
|
|
494
|
-
else {
|
|
495
|
-
return `${info.host}:${info.port}`;
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
414
|
async function initializeFunctionsConfigHelper(frb) {
|
|
499
415
|
const functionsResolution = await assertResolveDeveloperNodeModule(frb, "firebase-functions");
|
|
500
416
|
const localFunctionsModule = require(functionsResolution.resolution);
|
|
@@ -594,9 +510,12 @@ async function processHTTPS(frb, trigger) {
|
|
|
594
510
|
instance.on("error", rejectEphemeralServer);
|
|
595
511
|
});
|
|
596
512
|
}
|
|
597
|
-
async function processBackground(frb, trigger) {
|
|
513
|
+
async function processBackground(frb, trigger, signature) {
|
|
598
514
|
const proto = frb.proto;
|
|
599
515
|
logDebug("ProcessBackground", proto);
|
|
516
|
+
if (signature === "cloudevent") {
|
|
517
|
+
return runCloudEvent(proto, trigger.getRawFunction());
|
|
518
|
+
}
|
|
600
519
|
const data = proto.data;
|
|
601
520
|
delete proto.data;
|
|
602
521
|
const context = proto.context ? proto.context : proto;
|
|
@@ -627,6 +546,12 @@ async function runBackground(proto, func) {
|
|
|
627
546
|
return func(proto.data, proto.context);
|
|
628
547
|
});
|
|
629
548
|
}
|
|
549
|
+
async function runCloudEvent(event, func) {
|
|
550
|
+
logDebug("RunCloudEvent", event);
|
|
551
|
+
await runFunction(() => {
|
|
552
|
+
return func(event);
|
|
553
|
+
});
|
|
554
|
+
}
|
|
630
555
|
async function runHTTPS(args, func) {
|
|
631
556
|
if (args.length < 2) {
|
|
632
557
|
throw new Error("Function must be passed 2 args.");
|
|
@@ -665,8 +590,8 @@ async function invokeTrigger(frb, triggers) {
|
|
|
665
590
|
}).log();
|
|
666
591
|
const trigger = triggers[frb.triggerId];
|
|
667
592
|
logDebug("triggerDefinition", trigger.definition);
|
|
668
|
-
const
|
|
669
|
-
logDebug(`Running ${frb.triggerId} in
|
|
593
|
+
const signature = functionsEmulatorShared_1.getSignatureType(trigger.definition);
|
|
594
|
+
logDebug(`Running ${frb.triggerId} in signature ${signature}`);
|
|
670
595
|
let seconds = 0;
|
|
671
596
|
const timerId = setInterval(() => {
|
|
672
597
|
seconds++;
|
|
@@ -679,11 +604,12 @@ async function invokeTrigger(frb, triggers) {
|
|
|
679
604
|
throw new Error("Function timed out.");
|
|
680
605
|
}, trigger.timeoutMs);
|
|
681
606
|
}
|
|
682
|
-
switch (
|
|
683
|
-
case "
|
|
684
|
-
|
|
607
|
+
switch (signature) {
|
|
608
|
+
case "event":
|
|
609
|
+
case "cloudevent":
|
|
610
|
+
await processBackground(frb, triggers[frb.triggerId], signature);
|
|
685
611
|
break;
|
|
686
|
-
case "
|
|
612
|
+
case "http":
|
|
687
613
|
await processHTTPS(frb, triggers[frb.triggerId]);
|
|
688
614
|
break;
|
|
689
615
|
}
|
|
@@ -700,7 +626,6 @@ async function initializeRuntime(frb, serializedFunctionTrigger, extensionTrigge
|
|
|
700
626
|
new types_1.EmulatorLog("INFO", "runtime-status", `Your functions could not be parsed due to an issue with your node_modules (see above)`).log();
|
|
701
627
|
return;
|
|
702
628
|
}
|
|
703
|
-
await initializeEnvironmentalVariables(frb);
|
|
704
629
|
initializeNetworkFiltering(frb);
|
|
705
630
|
await initializeFunctionsConfigHelper(frb);
|
|
706
631
|
await initializeFirebaseFunctionsStubs(frb);
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findModuleRoot = exports.waitForBody = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.EmulatedTrigger = exports.HttpConstants =
|
|
3
|
+
exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.EmulatedTrigger = exports.HttpConstants = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const fs = require("fs");
|
|
8
|
-
|
|
9
|
-
(function (EmulatedTriggerType) {
|
|
10
|
-
EmulatedTriggerType["BACKGROUND"] = "BACKGROUND";
|
|
11
|
-
EmulatedTriggerType["HTTPS"] = "HTTPS";
|
|
12
|
-
})(EmulatedTriggerType = exports.EmulatedTriggerType || (exports.EmulatedTriggerType = {}));
|
|
8
|
+
const constants_1 = require("./constants");
|
|
13
9
|
const memoryLookup = {
|
|
14
10
|
"128MB": 128,
|
|
15
11
|
"256MB": 256,
|
|
@@ -82,12 +78,44 @@ function getTemporarySocketPath(pid, cwd) {
|
|
|
82
78
|
}
|
|
83
79
|
exports.getTemporarySocketPath = getTemporarySocketPath;
|
|
84
80
|
function getFunctionService(def) {
|
|
81
|
+
var _a;
|
|
85
82
|
if (def.eventTrigger) {
|
|
86
|
-
return def.eventTrigger.service;
|
|
83
|
+
return (_a = def.eventTrigger.service) !== null && _a !== void 0 ? _a : getServiceFromEventType(def.eventTrigger.eventType);
|
|
87
84
|
}
|
|
88
85
|
return "unknown";
|
|
89
86
|
}
|
|
90
87
|
exports.getFunctionService = getFunctionService;
|
|
88
|
+
function getServiceFromEventType(eventType) {
|
|
89
|
+
if (eventType.includes("firestore")) {
|
|
90
|
+
return constants_1.Constants.SERVICE_FIRESTORE;
|
|
91
|
+
}
|
|
92
|
+
if (eventType.includes("database")) {
|
|
93
|
+
return constants_1.Constants.SERVICE_REALTIME_DATABASE;
|
|
94
|
+
}
|
|
95
|
+
if (eventType.includes("pubsub")) {
|
|
96
|
+
return constants_1.Constants.SERVICE_PUBSUB;
|
|
97
|
+
}
|
|
98
|
+
if (eventType.includes("storage")) {
|
|
99
|
+
return constants_1.Constants.SERVICE_STORAGE;
|
|
100
|
+
}
|
|
101
|
+
if (eventType.includes("analytics")) {
|
|
102
|
+
return constants_1.Constants.SERVICE_ANALYTICS;
|
|
103
|
+
}
|
|
104
|
+
if (eventType.includes("auth")) {
|
|
105
|
+
return constants_1.Constants.SERVICE_AUTH;
|
|
106
|
+
}
|
|
107
|
+
if (eventType.includes("crashlytics")) {
|
|
108
|
+
return constants_1.Constants.SERVICE_CRASHLYTICS;
|
|
109
|
+
}
|
|
110
|
+
if (eventType.includes("remoteconfig")) {
|
|
111
|
+
return constants_1.Constants.SERVICE_REMOTE_CONFIG;
|
|
112
|
+
}
|
|
113
|
+
if (eventType.includes("testing")) {
|
|
114
|
+
return constants_1.Constants.SERVICE_TEST_LAB;
|
|
115
|
+
}
|
|
116
|
+
return "";
|
|
117
|
+
}
|
|
118
|
+
exports.getServiceFromEventType = getServiceFromEventType;
|
|
91
119
|
function waitForBody(req) {
|
|
92
120
|
let data = "";
|
|
93
121
|
return new Promise((resolve) => {
|
|
@@ -124,3 +152,19 @@ function findModuleRoot(moduleName, filepath) {
|
|
|
124
152
|
return "";
|
|
125
153
|
}
|
|
126
154
|
exports.findModuleRoot = findModuleRoot;
|
|
155
|
+
function formatHost(info) {
|
|
156
|
+
if (info.host.includes(":")) {
|
|
157
|
+
return `[${info.host}]:${info.port}`;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
return `${info.host}:${info.port}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.formatHost = formatHost;
|
|
164
|
+
function getSignatureType(def) {
|
|
165
|
+
if (def.httpsTrigger) {
|
|
166
|
+
return "http";
|
|
167
|
+
}
|
|
168
|
+
return def.platform === "gcfv2" ? "cloudevent" : "event";
|
|
169
|
+
}
|
|
170
|
+
exports.getSignatureType = getSignatureType;
|
|
@@ -42,7 +42,7 @@ class FunctionsEmulatorShell {
|
|
|
42
42
|
auth: opts.auth,
|
|
43
43
|
data,
|
|
44
44
|
};
|
|
45
|
-
this.emu.startFunctionRuntime(trigger.id, trigger.name, functionsEmulatorShared_1.
|
|
45
|
+
this.emu.startFunctionRuntime(trigger.id, trigger.name, functionsEmulatorShared_1.getSignatureType(trigger), proto);
|
|
46
46
|
}
|
|
47
47
|
getTrigger(name) {
|
|
48
48
|
const result = this.triggers.find((trigger) => {
|