firebase-tools 11.2.0 → 11.3.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/checkValidTargetFilters.js +3 -3
- package/lib/commands/ext-export.js +2 -0
- package/lib/deploy/extensions/planner.js +1 -0
- package/lib/deploy/extensions/prepare.js +18 -1
- package/lib/deploy/extensions/release.js +4 -0
- package/lib/deploy/functions/build.js +43 -52
- package/lib/deploy/functions/params.js +189 -0
- package/lib/deploy/functions/prepare.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +2 -2
- package/lib/deploy/lifecycleHooks.js +1 -1
- package/lib/deploy/storage/prepare.js +1 -1
- package/lib/downloadUtils.js +1 -1
- package/lib/emulator/downloadableEmulators.js +14 -14
- package/lib/emulator/functionsEmulator.js +10 -9
- package/lib/emulator/functionsEmulatorRuntime.js +70 -64
- package/lib/emulator/functionsEmulatorShared.js +7 -5
- package/lib/emulator/functionsRuntimeWorker.js +35 -15
- package/lib/emulator/storage/apis/gcloud.js +1 -1
- package/lib/extensions/etags.js +28 -0
- package/lib/extensions/warnings.js +7 -1
- package/lib/functions/env.js +5 -1
- package/lib/functionsConfig.js +1 -1
- package/lib/gcp/rules.js +2 -3
- package/lib/gcp/runtimeconfig.js +1 -1
- package/lib/hosting/api.js +9 -11
- package/lib/hosting/expireUtils.js +2 -2
- package/lib/management/projects.js +6 -7
- package/lib/profileReport.js +16 -14
- package/lib/rc.js +11 -1
- package/lib/requireConfig.js +6 -6
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -104,7 +104,7 @@ class Proxied {
|
|
|
104
104
|
return this.proxy;
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
async function resolveDeveloperNodeModule(
|
|
107
|
+
async function resolveDeveloperNodeModule(name) {
|
|
108
108
|
const pkg = requirePackageJson();
|
|
109
109
|
if (!pkg) {
|
|
110
110
|
new types_1.EmulatorLog("SYSTEM", "missing-package-json", "").log();
|
|
@@ -130,20 +130,20 @@ async function resolveDeveloperNodeModule(frb, name) {
|
|
|
130
130
|
logDebug(`Resolved module ${name}`, moduleResolution);
|
|
131
131
|
return moduleResolution;
|
|
132
132
|
}
|
|
133
|
-
async function assertResolveDeveloperNodeModule(
|
|
134
|
-
const resolution = await resolveDeveloperNodeModule(
|
|
133
|
+
async function assertResolveDeveloperNodeModule(name) {
|
|
134
|
+
const resolution = await resolveDeveloperNodeModule(name);
|
|
135
135
|
if (!(resolution.installed && resolution.declared && resolution.resolution && resolution.version)) {
|
|
136
136
|
throw new Error(`Assertion failure: could not fully resolve ${name}: ${JSON.stringify(resolution)}`);
|
|
137
137
|
}
|
|
138
138
|
return resolution;
|
|
139
139
|
}
|
|
140
|
-
async function verifyDeveloperNodeModules(
|
|
140
|
+
async function verifyDeveloperNodeModules() {
|
|
141
141
|
const modBundles = [
|
|
142
142
|
{ name: "firebase-admin", isDev: false, minVersion: "8.9.0" },
|
|
143
143
|
{ name: "firebase-functions", isDev: false, minVersion: "3.13.1" },
|
|
144
144
|
];
|
|
145
145
|
for (const modBundle of modBundles) {
|
|
146
|
-
const resolution = await resolveDeveloperNodeModule(
|
|
146
|
+
const resolution = await resolveDeveloperNodeModule(modBundle.name);
|
|
147
147
|
if (!resolution.declared) {
|
|
148
148
|
new types_1.EmulatorLog("SYSTEM", "missing-module", "", modBundle).log();
|
|
149
149
|
return false;
|
|
@@ -240,8 +240,8 @@ function initializeNetworkFiltering() {
|
|
|
240
240
|
});
|
|
241
241
|
logDebug("Outgoing network have been stubbed.", results);
|
|
242
242
|
}
|
|
243
|
-
async function initializeFirebaseFunctionsStubs(
|
|
244
|
-
const firebaseFunctionsResolution = await assertResolveDeveloperNodeModule(
|
|
243
|
+
async function initializeFirebaseFunctionsStubs() {
|
|
244
|
+
const firebaseFunctionsResolution = await assertResolveDeveloperNodeModule("firebase-functions");
|
|
245
245
|
const firebaseFunctionsRoot = (0, functionsEmulatorShared_1.findModuleRoot)("firebase-functions", firebaseFunctionsResolution.resolution);
|
|
246
246
|
const httpsProviderResolution = path.join(firebaseFunctionsRoot, "lib/providers/https");
|
|
247
247
|
const httpsProviderV1Resolution = path.join(firebaseFunctionsRoot, "lib/v1/providers/https");
|
|
@@ -343,10 +343,10 @@ function initializeRuntimeConfig() {
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
|
-
async function initializeFirebaseAdminStubs(
|
|
347
|
-
const adminResolution = await assertResolveDeveloperNodeModule(
|
|
346
|
+
async function initializeFirebaseAdminStubs() {
|
|
347
|
+
const adminResolution = await assertResolveDeveloperNodeModule("firebase-admin");
|
|
348
348
|
const localAdminModule = require(adminResolution.resolution);
|
|
349
|
-
const functionsResolution = await assertResolveDeveloperNodeModule(
|
|
349
|
+
const functionsResolution = await assertResolveDeveloperNodeModule("firebase-functions");
|
|
350
350
|
const localFunctionsModule = require(functionsResolution.resolution);
|
|
351
351
|
const defaultConfig = getDefaultConfig();
|
|
352
352
|
const adminModuleProxy = new Proxied(localAdminModule);
|
|
@@ -360,7 +360,7 @@ async function initializeFirebaseAdminStubs(frb) {
|
|
|
360
360
|
new types_1.EmulatorLog("SYSTEM", "default-admin-app-used", `config=${defaultAppOptions}`, {
|
|
361
361
|
opts: defaultAppOptions,
|
|
362
362
|
}).log();
|
|
363
|
-
const defaultApp = makeProxiedFirebaseApp(
|
|
363
|
+
const defaultApp = makeProxiedFirebaseApp(adminModuleTarget.initializeApp(defaultAppOptions));
|
|
364
364
|
logDebug("initializeApp(DEFAULT)", defaultAppOptions);
|
|
365
365
|
localFunctionsModule.app.setEmulatedAdminApp(defaultApp);
|
|
366
366
|
if (process.env[constants_1.Constants.FIREBASE_AUTH_EMULATOR_HOST]) {
|
|
@@ -405,7 +405,7 @@ async function initializeFirebaseAdminStubs(frb) {
|
|
|
405
405
|
adminResolution,
|
|
406
406
|
});
|
|
407
407
|
}
|
|
408
|
-
function makeProxiedFirebaseApp(
|
|
408
|
+
function makeProxiedFirebaseApp(original) {
|
|
409
409
|
const appProxy = new Proxied(original);
|
|
410
410
|
return appProxy
|
|
411
411
|
.when("firestore", (target) => {
|
|
@@ -450,8 +450,8 @@ function warnAboutStorageProd() {
|
|
|
450
450
|
}
|
|
451
451
|
new types_1.EmulatorLog("WARN_ONCE", "runtime-status", "The Firebase Storage emulator is not running, so calls to Firebase Storage will affect production.").log();
|
|
452
452
|
}
|
|
453
|
-
async function initializeFunctionsConfigHelper(
|
|
454
|
-
const functionsResolution = await assertResolveDeveloperNodeModule(
|
|
453
|
+
async function initializeFunctionsConfigHelper() {
|
|
454
|
+
const functionsResolution = await assertResolveDeveloperNodeModule("firebase-functions");
|
|
455
455
|
const localFunctionsModule = require(functionsResolution.resolution);
|
|
456
456
|
logDebug("Checked functions.config()", {
|
|
457
457
|
config: localFunctionsModule.config(),
|
|
@@ -485,34 +485,9 @@ async function initializeFunctionsConfigHelper(frb) {
|
|
|
485
485
|
function rawBodySaver(req, res, buf) {
|
|
486
486
|
req.rawBody = buf;
|
|
487
487
|
}
|
|
488
|
-
async function processHTTPS(trigger
|
|
488
|
+
async function processHTTPS(trigger) {
|
|
489
489
|
const ephemeralServer = express();
|
|
490
|
-
const functionRouter = express.Router();
|
|
491
|
-
const socketPath = frb.socketPath;
|
|
492
|
-
if (!socketPath) {
|
|
493
|
-
new types_1.EmulatorLog("FATAL", "runtime-error", "Called processHTTPS with no socketPath").log();
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
490
|
await new Promise((resolveEphemeralServer, rejectEphemeralServer) => {
|
|
497
|
-
const handler = async (req, res) => {
|
|
498
|
-
try {
|
|
499
|
-
logDebug(`Ephemeral server handling ${req.method} request`);
|
|
500
|
-
res.on("finish", () => {
|
|
501
|
-
instance.close((err) => {
|
|
502
|
-
if (err) {
|
|
503
|
-
rejectEphemeralServer(err);
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
resolveEphemeralServer();
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
});
|
|
510
|
-
await runHTTPS(trigger, [req, res]);
|
|
511
|
-
}
|
|
512
|
-
catch (err) {
|
|
513
|
-
rejectEphemeralServer(err);
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
491
|
ephemeralServer.enable("trust proxy");
|
|
517
492
|
ephemeralServer.use(bodyParser.json({
|
|
518
493
|
limit: "10mb",
|
|
@@ -532,13 +507,39 @@ async function processHTTPS(trigger, frb) {
|
|
|
532
507
|
limit: "10mb",
|
|
533
508
|
verify: rawBodySaver,
|
|
534
509
|
}));
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
510
|
+
let server;
|
|
511
|
+
function closeServer() {
|
|
512
|
+
if (server) {
|
|
513
|
+
server.close((err) => {
|
|
514
|
+
if (err) {
|
|
515
|
+
rejectEphemeralServer(err);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
resolveEphemeralServer();
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
ephemeralServer.get("/__/health", (req, res) => {
|
|
524
|
+
res.status(200).send();
|
|
525
|
+
});
|
|
526
|
+
ephemeralServer.all("/favicon.ico|/robots.txt", (req, res) => {
|
|
527
|
+
res.on("finish", closeServer);
|
|
528
|
+
res.status(404).send();
|
|
529
|
+
});
|
|
530
|
+
ephemeralServer.all(`/*`, async (req, res) => {
|
|
531
|
+
try {
|
|
532
|
+
logDebug(`Ephemeral server handling ${req.method} request`);
|
|
533
|
+
res.on("finish", closeServer);
|
|
534
|
+
await runHTTPS(trigger, [req, res]);
|
|
535
|
+
}
|
|
536
|
+
catch (err) {
|
|
537
|
+
rejectEphemeralServer(err);
|
|
538
|
+
}
|
|
540
539
|
});
|
|
541
|
-
|
|
540
|
+
logDebug(`Attempting to listen to port: ${process.env.PORT}`);
|
|
541
|
+
server = ephemeralServer.listen(process.env.PORT);
|
|
542
|
+
server.on("error", rejectEphemeralServer);
|
|
542
543
|
});
|
|
543
544
|
}
|
|
544
545
|
async function processBackground(trigger, frb, signature) {
|
|
@@ -591,7 +592,7 @@ async function runHTTPS(trigger, args) {
|
|
|
591
592
|
return trigger(args[0], args[1]);
|
|
592
593
|
});
|
|
593
594
|
}
|
|
594
|
-
async function moduleResolutionDetective(
|
|
595
|
+
async function moduleResolutionDetective(error) {
|
|
595
596
|
const clues = {
|
|
596
597
|
tsconfigJSON: await requireAsync("./tsconfig.json", { paths: [process.cwd()] }).catch(noOp),
|
|
597
598
|
packageJSON: await requireAsync("./package.json", { paths: [process.cwd()] }).catch(noOp),
|
|
@@ -640,7 +641,7 @@ async function invokeTrigger(trigger, frb) {
|
|
|
640
641
|
await processBackground(trigger, frb, FUNCTION_SIGNATURE);
|
|
641
642
|
break;
|
|
642
643
|
case "http":
|
|
643
|
-
await processHTTPS(trigger
|
|
644
|
+
await processHTTPS(trigger);
|
|
644
645
|
break;
|
|
645
646
|
}
|
|
646
647
|
if (timeoutId) {
|
|
@@ -649,7 +650,7 @@ async function invokeTrigger(trigger, frb) {
|
|
|
649
650
|
clearInterval(timerId);
|
|
650
651
|
new types_1.EmulatorLog("INFO", "runtime-status", `Finished "${FUNCTION_TARGET_NAME}" in ~${Math.max(seconds, 1)}s`).log();
|
|
651
652
|
}
|
|
652
|
-
async function initializeRuntime(
|
|
653
|
+
async function initializeRuntime() {
|
|
653
654
|
FUNCTION_DEBUG_MODE = process.env.FUNCTION_DEBUG_MODE || "";
|
|
654
655
|
if (!FUNCTION_DEBUG_MODE) {
|
|
655
656
|
FUNCTION_TARGET_NAME = process.env.FUNCTION_TARGET || "";
|
|
@@ -663,19 +664,18 @@ async function initializeRuntime(frb) {
|
|
|
663
664
|
await flushAndExit(1);
|
|
664
665
|
}
|
|
665
666
|
}
|
|
666
|
-
|
|
667
|
-
const verified = await verifyDeveloperNodeModules(frb);
|
|
667
|
+
const verified = await verifyDeveloperNodeModules();
|
|
668
668
|
if (!verified) {
|
|
669
669
|
new types_1.EmulatorLog("INFO", "runtime-status", `Your functions could not be parsed due to an issue with your node_modules (see above)`).log();
|
|
670
670
|
return;
|
|
671
671
|
}
|
|
672
672
|
initializeRuntimeConfig();
|
|
673
673
|
initializeNetworkFiltering();
|
|
674
|
-
await initializeFunctionsConfigHelper(
|
|
675
|
-
await initializeFirebaseFunctionsStubs(
|
|
676
|
-
await initializeFirebaseAdminStubs(
|
|
674
|
+
await initializeFunctionsConfigHelper();
|
|
675
|
+
await initializeFirebaseFunctionsStubs();
|
|
676
|
+
await initializeFirebaseAdminStubs();
|
|
677
677
|
}
|
|
678
|
-
async function loadTriggers(
|
|
678
|
+
async function loadTriggers(serializedFunctionTrigger) {
|
|
679
679
|
let triggerModule;
|
|
680
680
|
if (serializedFunctionTrigger) {
|
|
681
681
|
triggerModule = eval(serializedFunctionTrigger)();
|
|
@@ -686,7 +686,7 @@ async function loadTriggers(frb, serializedFunctionTrigger) {
|
|
|
686
686
|
}
|
|
687
687
|
catch (err) {
|
|
688
688
|
if (err.code !== "ERR_REQUIRE_ESM") {
|
|
689
|
-
await moduleResolutionDetective(
|
|
689
|
+
await moduleResolutionDetective(err);
|
|
690
690
|
throw err;
|
|
691
691
|
}
|
|
692
692
|
const modulePath = require.resolve(process.cwd());
|
|
@@ -716,9 +716,8 @@ async function handleMessage(message) {
|
|
|
716
716
|
}
|
|
717
717
|
if (!functionModule) {
|
|
718
718
|
try {
|
|
719
|
-
await initializeRuntime(runtimeArgs.frb);
|
|
720
719
|
const serializedTriggers = runtimeArgs.opts ? runtimeArgs.opts.serializedTriggers : undefined;
|
|
721
|
-
functionModule = await loadTriggers(
|
|
720
|
+
functionModule = await loadTriggers(serializedTriggers);
|
|
722
721
|
}
|
|
723
722
|
catch (e) {
|
|
724
723
|
logDebug(e);
|
|
@@ -752,7 +751,7 @@ async function handleMessage(message) {
|
|
|
752
751
|
await flushAndExit(1);
|
|
753
752
|
}
|
|
754
753
|
}
|
|
755
|
-
function main() {
|
|
754
|
+
async function main() {
|
|
756
755
|
let lastSignal = new Date().getTime();
|
|
757
756
|
let signalCount = 0;
|
|
758
757
|
process.on("SIGINT", () => {
|
|
@@ -766,10 +765,7 @@ function main() {
|
|
|
766
765
|
process.exit(1);
|
|
767
766
|
}
|
|
768
767
|
});
|
|
769
|
-
|
|
770
|
-
cwd: process.cwd(),
|
|
771
|
-
node_version: process.versions.node,
|
|
772
|
-
});
|
|
768
|
+
await initializeRuntime();
|
|
773
769
|
let messageHandlePromise = Promise.resolve();
|
|
774
770
|
process.on("message", (message) => {
|
|
775
771
|
messageHandlePromise = messageHandlePromise
|
|
@@ -784,5 +780,15 @@ function main() {
|
|
|
784
780
|
});
|
|
785
781
|
}
|
|
786
782
|
if (require.main === module) {
|
|
787
|
-
main()
|
|
783
|
+
main()
|
|
784
|
+
.then(() => {
|
|
785
|
+
logDebug("Functions runtime initialized.", {
|
|
786
|
+
cwd: process.cwd(),
|
|
787
|
+
node_version: process.versions.node,
|
|
788
|
+
});
|
|
789
|
+
})
|
|
790
|
+
.catch((err) => {
|
|
791
|
+
new types_1.EmulatorLog("FATAL", "runtime-error", err.message || err, err).log();
|
|
792
|
+
return flushAndExit(1);
|
|
793
|
+
});
|
|
788
794
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toBackendInfo = exports.getSecretLocalPath = exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.prepareEndpoints = exports.EmulatedTrigger = exports.HttpConstants = void 0;
|
|
4
|
-
const _ = require("lodash");
|
|
5
4
|
const os = require("os");
|
|
6
5
|
const path = require("path");
|
|
7
6
|
const fs = require("fs");
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const _ = require("lodash");
|
|
8
9
|
const backend = require("../deploy/functions/backend");
|
|
9
10
|
const constants_1 = require("./constants");
|
|
10
11
|
const proto_1 = require("../gcp/proto");
|
|
@@ -142,12 +143,13 @@ function getEmulatedTriggersFromDefinitions(definitions, module) {
|
|
|
142
143
|
}, {});
|
|
143
144
|
}
|
|
144
145
|
exports.getEmulatedTriggersFromDefinitions = getEmulatedTriggersFromDefinitions;
|
|
145
|
-
function getTemporarySocketPath(
|
|
146
|
+
function getTemporarySocketPath() {
|
|
147
|
+
const rand = (0, crypto_1.randomBytes)(8).toString("hex");
|
|
146
148
|
if (process.platform === "win32") {
|
|
147
|
-
return path.join("\\\\?\\pipe",
|
|
149
|
+
return path.join("\\\\?\\pipe", `fire_emu_${rand}`);
|
|
148
150
|
}
|
|
149
151
|
else {
|
|
150
|
-
return path.join(os.tmpdir(), `fire_emu_${
|
|
152
|
+
return path.join(os.tmpdir(), `fire_emu_${rand}.sock`);
|
|
151
153
|
}
|
|
152
154
|
}
|
|
153
155
|
exports.getTemporarySocketPath = getTemporarySocketPath;
|
|
@@ -239,7 +241,7 @@ function formatHost(info) {
|
|
|
239
241
|
}
|
|
240
242
|
exports.formatHost = formatHost;
|
|
241
243
|
function getSignatureType(def) {
|
|
242
|
-
if (def.httpsTrigger) {
|
|
244
|
+
if (def.httpsTrigger || def.blockingTrigger) {
|
|
243
245
|
return "http";
|
|
244
246
|
}
|
|
245
247
|
return def.platform === "gcfv2" ? "cloudevent" : "event";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RuntimeWorkerPool = exports.RuntimeWorker = exports.RuntimeWorkerState = void 0;
|
|
4
|
+
const http = require("http");
|
|
4
5
|
const uuid = require("uuid");
|
|
5
6
|
const types_1 = require("./types");
|
|
6
|
-
const functionsEmulatorShared_1 = require("./functionsEmulatorShared");
|
|
7
7
|
const events_1 = require("events");
|
|
8
8
|
const emulatorLogger_1 = require("./emulatorLogger");
|
|
9
9
|
const error_1 = require("../error");
|
|
@@ -42,30 +42,19 @@ class RuntimeWorker {
|
|
|
42
42
|
}
|
|
43
43
|
execute(frb, opts) {
|
|
44
44
|
const execFrb = Object.assign({}, frb);
|
|
45
|
-
if (!execFrb.socketPath) {
|
|
46
|
-
execFrb.socketPath = (0, functionsEmulatorShared_1.getTemporarySocketPath)(this.runtime.pid, this.runtime.cwd);
|
|
47
|
-
this.log(`Assigning socketPath: ${execFrb.socketPath}`);
|
|
48
|
-
}
|
|
49
45
|
const args = { frb: execFrb, opts };
|
|
50
46
|
this.state = RuntimeWorkerState.BUSY;
|
|
51
|
-
this.lastArgs = args;
|
|
52
47
|
this.runtime.send(args);
|
|
53
48
|
}
|
|
54
49
|
get state() {
|
|
55
50
|
return this._state;
|
|
56
51
|
}
|
|
57
52
|
set state(state) {
|
|
58
|
-
if (state === RuntimeWorkerState.BUSY) {
|
|
59
|
-
this.socketReady = types_1.EmulatorLog.waitForLog(this.runtime.events, "SYSTEM", "runtime-status", (el) => {
|
|
60
|
-
return el.data.state === "ready";
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
53
|
if (state === RuntimeWorkerState.IDLE) {
|
|
64
54
|
for (const l of this.logListeners) {
|
|
65
55
|
this.runtime.events.removeListener("log", l);
|
|
66
56
|
}
|
|
67
57
|
this.logListeners = [];
|
|
68
|
-
this.socketReady = undefined;
|
|
69
58
|
}
|
|
70
59
|
if (state === RuntimeWorkerState.FINISHED) {
|
|
71
60
|
this.runtime.events.removeAllListeners();
|
|
@@ -94,9 +83,40 @@ class RuntimeWorker {
|
|
|
94
83
|
this.stateEvents.once(RuntimeWorkerState.FINISHED, listener);
|
|
95
84
|
});
|
|
96
85
|
}
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
|
|
86
|
+
isSocketReady() {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const req = http
|
|
89
|
+
.request({
|
|
90
|
+
method: "GET",
|
|
91
|
+
path: "/__/health",
|
|
92
|
+
socketPath: this.runtime.socketPath,
|
|
93
|
+
}, () => resolve())
|
|
94
|
+
.end();
|
|
95
|
+
req.on("error", (error) => {
|
|
96
|
+
reject(error);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async waitForSocketReady() {
|
|
101
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
102
|
+
const timeout = new Promise((resolve, reject) => {
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
reject(new error_1.FirebaseError("Failed to load function."));
|
|
105
|
+
}, 7000);
|
|
106
|
+
});
|
|
107
|
+
while (true) {
|
|
108
|
+
try {
|
|
109
|
+
await Promise.race([this.isSocketReady(), timeout]);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (["ECONNREFUSED", "ENOENT"].includes(err === null || err === void 0 ? void 0 : err.code)) {
|
|
114
|
+
await sleep(100);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
100
120
|
}
|
|
101
121
|
log(msg) {
|
|
102
122
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("DEBUG", `[worker-${this.key}-${this.id}]: ${msg}`);
|
|
@@ -324,7 +324,7 @@ function sendFileBytes(md, data, req, res) {
|
|
|
324
324
|
res.setHeader("Accept-Ranges", "bytes");
|
|
325
325
|
res.setHeader("Content-Type", md.contentType);
|
|
326
326
|
res.setHeader("Content-Disposition", md.contentDisposition);
|
|
327
|
-
res.setHeader("Content-Encoding", md.contentEncoding);
|
|
327
|
+
res.setHeader("Content-Encoding", isGZipped ? "identity" : md.contentEncoding);
|
|
328
328
|
res.setHeader("ETag", md.etag);
|
|
329
329
|
res.setHeader("Cache-Control", md.cacheControl);
|
|
330
330
|
res.setHeader("x-goog-generation", `${md.generation}`);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectEtagChanges = exports.saveEtags = void 0;
|
|
4
|
+
function saveEtags(rc, projectId, instances) {
|
|
5
|
+
rc.setEtags(projectId, "extensionInstances", etagsMap(instances));
|
|
6
|
+
}
|
|
7
|
+
exports.saveEtags = saveEtags;
|
|
8
|
+
function detectEtagChanges(rc, projectId, instances) {
|
|
9
|
+
const lastDeployedEtags = rc.getEtags(projectId).extensionInstances;
|
|
10
|
+
const currentEtags = etagsMap(instances);
|
|
11
|
+
if (!lastDeployedEtags || !Object.keys(lastDeployedEtags).length) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const changedExtensionInstances = Object.entries(lastDeployedEtags)
|
|
15
|
+
.filter(([instanceName, etag]) => etag !== currentEtags[instanceName])
|
|
16
|
+
.map((i) => i[0]);
|
|
17
|
+
const newExtensionInstances = Object.keys(currentEtags).filter((instanceName) => !lastDeployedEtags[instanceName]);
|
|
18
|
+
return newExtensionInstances.concat(changedExtensionInstances);
|
|
19
|
+
}
|
|
20
|
+
exports.detectEtagChanges = detectEtagChanges;
|
|
21
|
+
function etagsMap(instances) {
|
|
22
|
+
return instances.reduce((acc, i) => {
|
|
23
|
+
if (i.etag) {
|
|
24
|
+
acc[i.instanceId] = i.etag;
|
|
25
|
+
}
|
|
26
|
+
return acc;
|
|
27
|
+
}, {});
|
|
28
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.paramsFlagDeprecationWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
|
|
3
|
+
exports.outOfBandChangesWarning = exports.paramsFlagDeprecationWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
|
|
4
4
|
const { marked } = require("marked");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const types_1 = require("./types");
|
|
@@ -75,3 +75,9 @@ function paramsFlagDeprecationWarning() {
|
|
|
75
75
|
"See https://firebase.google.com/docs/extensions/manifest for more details");
|
|
76
76
|
}
|
|
77
77
|
exports.paramsFlagDeprecationWarning = paramsFlagDeprecationWarning;
|
|
78
|
+
function outOfBandChangesWarning(instanceIds) {
|
|
79
|
+
logger_1.logger.warn("The following instances may have been changed in the Firebase console or by another machine since the last deploy from this machine.\n\t" +
|
|
80
|
+
clc.bold(instanceIds.join("\n\t")) +
|
|
81
|
+
"\nIf you proceed with this deployment, those changes will be overwritten. To avoid this, run `firebase ext:export` to sync these changes to your local extensions manifest.");
|
|
82
|
+
}
|
|
83
|
+
exports.outOfBandChangesWarning = outOfBandChangesWarning;
|
package/lib/functions/env.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
3
|
+
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.writeUserEnvs = exports.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
@@ -145,6 +145,10 @@ function hasUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, })
|
|
|
145
145
|
return findEnvfiles(functionsSource, projectId, projectAlias, isEmulator).length > 0;
|
|
146
146
|
}
|
|
147
147
|
exports.hasUserEnvs = hasUserEnvs;
|
|
148
|
+
function writeUserEnvs(toWrite, envOpts) {
|
|
149
|
+
throw new error_1.FirebaseError("Persisting user-defined parameters to .env files is not yet implemented.");
|
|
150
|
+
}
|
|
151
|
+
exports.writeUserEnvs = writeUserEnvs;
|
|
148
152
|
function loadUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, }) {
|
|
149
153
|
var _a;
|
|
150
154
|
const envFiles = findEnvfiles(functionsSource, projectId, projectAlias, isEmulator);
|
package/lib/functionsConfig.js
CHANGED
|
@@ -70,7 +70,7 @@ async function setVariablesRecursive(projectId, configId, varPath, val) {
|
|
|
70
70
|
catch (e) {
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
if (
|
|
73
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
74
74
|
return Promise.all(Object.entries(parsed).map(([key, item]) => {
|
|
75
75
|
const newVarPath = varPath ? [varPath, key].join("/") : key;
|
|
76
76
|
return setVariablesRecursive(projectId, configId, newVarPath, item);
|
package/lib/gcp/rules.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.testRuleset = exports.updateOrCreateRelease = exports.updateRelease = exports.createRelease = exports.createRuleset = exports.deleteRuleset = exports.getRulesetId = exports.listAllRulesets = exports.listRulesets = exports.getRulesetContent = exports.listAllReleases = exports.listReleases = exports.getLatestRulesetName = void 0;
|
|
4
|
-
const _ = require("lodash");
|
|
5
4
|
const api_1 = require("../api");
|
|
6
5
|
const apiv2_1 = require("../apiv2");
|
|
7
6
|
const logger_1 = require("../logger");
|
|
@@ -51,7 +50,7 @@ async function listAllReleases(projectId) {
|
|
|
51
50
|
}
|
|
52
51
|
pageToken = response.nextPageToken;
|
|
53
52
|
} while (pageToken);
|
|
54
|
-
return
|
|
53
|
+
return releases.sort((a, b) => b.createTime.localeCompare(a.createTime));
|
|
55
54
|
}
|
|
56
55
|
exports.listAllReleases = listAllReleases;
|
|
57
56
|
async function getRulesetContent(name) {
|
|
@@ -90,7 +89,7 @@ async function listAllRulesets(projectId) {
|
|
|
90
89
|
}
|
|
91
90
|
pageToken = response.nextPageToken;
|
|
92
91
|
} while (pageToken);
|
|
93
|
-
return
|
|
92
|
+
return rulesets.sort((a, b) => b.createTime.localeCompare(a.createTime));
|
|
94
93
|
}
|
|
95
94
|
exports.listAllRulesets = listAllRulesets;
|
|
96
95
|
function getRulesetId(ruleset) {
|
package/lib/gcp/runtimeconfig.js
CHANGED
package/lib/hosting/api.js
CHANGED
|
@@ -43,7 +43,7 @@ async function getChannel(project = "-", site, channelId) {
|
|
|
43
43
|
return res.body;
|
|
44
44
|
}
|
|
45
45
|
catch (e) {
|
|
46
|
-
if (e.status === 404) {
|
|
46
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
throw e;
|
|
@@ -51,23 +51,22 @@ async function getChannel(project = "-", site, channelId) {
|
|
|
51
51
|
}
|
|
52
52
|
exports.getChannel = getChannel;
|
|
53
53
|
async function listChannels(project = "-", site) {
|
|
54
|
-
var _a, _b;
|
|
55
54
|
const channels = [];
|
|
56
55
|
let nextPageToken = "";
|
|
57
56
|
for (;;) {
|
|
58
57
|
try {
|
|
59
58
|
const res = await apiClient.get(`/projects/${project}/sites/${site}/channels`, { queryParams: { pageToken: nextPageToken, pageSize: 10 } });
|
|
60
|
-
const c =
|
|
59
|
+
const c = res.body.channels;
|
|
61
60
|
if (c) {
|
|
62
61
|
channels.push(...c);
|
|
63
62
|
}
|
|
64
|
-
nextPageToken =
|
|
63
|
+
nextPageToken = res.body.nextPageToken || "";
|
|
65
64
|
if (!nextPageToken) {
|
|
66
65
|
return channels;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
catch (e) {
|
|
70
|
-
if (e.status === 404) {
|
|
69
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
71
70
|
throw new error_1.FirebaseError(`could not find channels for site "${site}"`, {
|
|
72
71
|
original: e,
|
|
73
72
|
});
|
|
@@ -116,23 +115,22 @@ async function createRelease(site, channel, version) {
|
|
|
116
115
|
}
|
|
117
116
|
exports.createRelease = createRelease;
|
|
118
117
|
async function listSites(project) {
|
|
119
|
-
var _a, _b;
|
|
120
118
|
const sites = [];
|
|
121
119
|
let nextPageToken = "";
|
|
122
120
|
for (;;) {
|
|
123
121
|
try {
|
|
124
122
|
const res = await apiClient.get(`/projects/${project}/sites`, { queryParams: { pageToken: nextPageToken, pageSize: 10 } });
|
|
125
|
-
const c =
|
|
123
|
+
const c = res.body.sites;
|
|
126
124
|
if (c) {
|
|
127
125
|
sites.push(...c);
|
|
128
126
|
}
|
|
129
|
-
nextPageToken =
|
|
127
|
+
nextPageToken = res.body.nextPageToken || "";
|
|
130
128
|
if (!nextPageToken) {
|
|
131
129
|
return sites;
|
|
132
130
|
}
|
|
133
131
|
}
|
|
134
132
|
catch (e) {
|
|
135
|
-
if (e.status === 404) {
|
|
133
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
136
134
|
throw new error_1.FirebaseError(`could not find sites for project "${project}"`, {
|
|
137
135
|
original: e,
|
|
138
136
|
});
|
|
@@ -148,7 +146,7 @@ async function getSite(project, site) {
|
|
|
148
146
|
return res.body;
|
|
149
147
|
}
|
|
150
148
|
catch (e) {
|
|
151
|
-
if (e.status === 404) {
|
|
149
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
152
150
|
throw new error_1.FirebaseError(`could not find site "${site}" for project "${project}"`, {
|
|
153
151
|
original: e,
|
|
154
152
|
});
|
|
@@ -158,7 +156,7 @@ async function getSite(project, site) {
|
|
|
158
156
|
}
|
|
159
157
|
exports.getSite = getSite;
|
|
160
158
|
async function createSite(project, site, appId = "") {
|
|
161
|
-
const res = await apiClient.post(`/projects/${project}/sites`, { appId: appId }, { queryParams: {
|
|
159
|
+
const res = await apiClient.post(`/projects/${project}/sites`, { appId: appId }, { queryParams: { siteId: site } });
|
|
162
160
|
return res.body;
|
|
163
161
|
}
|
|
164
162
|
exports.createSite = createSite;
|
|
@@ -16,8 +16,8 @@ const DURATIONS = {
|
|
|
16
16
|
};
|
|
17
17
|
exports.MAX_DURATION = 30 * Duration.DAY;
|
|
18
18
|
exports.DEFAULT_DURATION = 7 * Duration.DAY;
|
|
19
|
-
function calculateChannelExpireTTL(flag) {
|
|
20
|
-
const match = exports.DURATION_REGEX.exec(flag
|
|
19
|
+
function calculateChannelExpireTTL(flag = "") {
|
|
20
|
+
const match = exports.DURATION_REGEX.exec(flag);
|
|
21
21
|
if (!match) {
|
|
22
22
|
throw new error_1.FirebaseError(`"expires" flag must be a duration string (e.g. 24h or 7d) at most 30d`);
|
|
23
23
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getFirebaseProject = exports.listFirebaseProjects = exports.getAvailableCloudProjectPage = exports.getFirebaseProjectPage = exports.addFirebaseToCloudProject = exports.createCloudProject = exports.promptAvailableProjectId = exports.getOrPromptProject = exports.addFirebaseToCloudProjectAndLog = exports.createFirebaseProjectAndLog = exports.PROJECTS_CREATE_QUESTIONS = exports.ProjectParentResourceType = void 0;
|
|
4
|
-
const _ = require("lodash");
|
|
5
4
|
const clc = require("cli-color");
|
|
6
5
|
const ora = require("ora");
|
|
7
6
|
const apiv2_1 = require("../apiv2");
|
|
@@ -110,15 +109,15 @@ async function selectProjectByPrompting() {
|
|
|
110
109
|
return await getFirebaseProject(projectId);
|
|
111
110
|
}
|
|
112
111
|
async function selectProjectFromList(projects = []) {
|
|
113
|
-
|
|
112
|
+
const choices = projects
|
|
114
113
|
.filter((p) => !!p)
|
|
115
114
|
.map((p) => {
|
|
116
115
|
return {
|
|
117
116
|
name: p.projectId + (p.displayName ? ` (${p.displayName})` : ""),
|
|
118
117
|
value: p.projectId,
|
|
119
118
|
};
|
|
120
|
-
})
|
|
121
|
-
|
|
119
|
+
})
|
|
120
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
122
121
|
if (choices.length >= 25) {
|
|
123
122
|
utils.logBullet(`Don't want to scroll through all your projects? If you know your project ID, ` +
|
|
124
123
|
`you can initialize it directly using ${clc.bold("firebase init --project <project_id>")}.\n`);
|
|
@@ -151,7 +150,7 @@ async function promptAvailableProjectId() {
|
|
|
151
150
|
});
|
|
152
151
|
}
|
|
153
152
|
else {
|
|
154
|
-
|
|
153
|
+
const choices = projects
|
|
155
154
|
.filter((p) => !!p)
|
|
156
155
|
.map((p) => {
|
|
157
156
|
const projectId = getProjectId(p);
|
|
@@ -159,8 +158,8 @@ async function promptAvailableProjectId() {
|
|
|
159
158
|
name: projectId + (p.displayName ? ` (${p.displayName})` : ""),
|
|
160
159
|
value: projectId,
|
|
161
160
|
};
|
|
162
|
-
})
|
|
163
|
-
|
|
161
|
+
})
|
|
162
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
164
163
|
return await (0, prompt_1.promptOnce)({
|
|
165
164
|
type: "list",
|
|
166
165
|
name: "id",
|