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
|
@@ -41,6 +41,27 @@ function requireResolveAsync(moduleName, opts) {
|
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
class Proxied {
|
|
44
|
+
static getOriginal(target, key) {
|
|
45
|
+
const value = target[key];
|
|
46
|
+
if (!Proxied.isExists(value)) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
else if (Proxied.isConstructor(value) || typeof value !== "function") {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return value.bind(target);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
static applyOriginal(target, thisArg, argArray) {
|
|
57
|
+
return target.apply(thisArg, argArray);
|
|
58
|
+
}
|
|
59
|
+
static isConstructor(obj) {
|
|
60
|
+
return !!obj.prototype && !!obj.prototype.constructor.name;
|
|
61
|
+
}
|
|
62
|
+
static isExists(obj) {
|
|
63
|
+
return obj !== undefined;
|
|
64
|
+
}
|
|
44
65
|
constructor(original) {
|
|
45
66
|
this.original = original;
|
|
46
67
|
this.rewrites = {};
|
|
@@ -65,27 +86,6 @@ class Proxied {
|
|
|
65
86
|
},
|
|
66
87
|
});
|
|
67
88
|
}
|
|
68
|
-
static getOriginal(target, key) {
|
|
69
|
-
const value = target[key];
|
|
70
|
-
if (!Proxied.isExists(value)) {
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
else if (Proxied.isConstructor(value) || typeof value !== "function") {
|
|
74
|
-
return value;
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
return value.bind(target);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
static applyOriginal(target, thisArg, argArray) {
|
|
81
|
-
return target.apply(thisArg, argArray);
|
|
82
|
-
}
|
|
83
|
-
static isConstructor(obj) {
|
|
84
|
-
return !!obj.prototype && !!obj.prototype.constructor.name;
|
|
85
|
-
}
|
|
86
|
-
static isExists(obj) {
|
|
87
|
-
return obj !== undefined;
|
|
88
|
-
}
|
|
89
89
|
when(key, value) {
|
|
90
90
|
this.rewrites[key] = value;
|
|
91
91
|
return this;
|
|
@@ -395,7 +395,8 @@ async function initializeFirebaseAdminStubs() {
|
|
|
395
395
|
return Proxied.getOriginal(target, "storage");
|
|
396
396
|
})
|
|
397
397
|
.finalize();
|
|
398
|
-
|
|
398
|
+
const v = require.cache[adminResolution.resolution];
|
|
399
|
+
require.cache[adminResolution.resolution] = Object.assign(v, {
|
|
399
400
|
exports: proxiedAdminModule,
|
|
400
401
|
path: path.dirname(adminResolution.resolution),
|
|
401
402
|
});
|
|
@@ -472,7 +473,8 @@ async function initializeFunctionsConfigHelper() {
|
|
|
472
473
|
return proxiedConfig;
|
|
473
474
|
})
|
|
474
475
|
.finalize();
|
|
475
|
-
|
|
476
|
+
const v = require.cache[functionsResolution.resolution];
|
|
477
|
+
require.cache[functionsResolution.resolution] = Object.assign(v, {
|
|
476
478
|
exports: proxiedFunctionsModule,
|
|
477
479
|
path: path.dirname(functionsResolution.resolution),
|
|
478
480
|
});
|
|
@@ -666,18 +668,12 @@ async function main() {
|
|
|
666
668
|
});
|
|
667
669
|
app.all(`/*`, async (req, res) => {
|
|
668
670
|
try {
|
|
669
|
-
new types_1.EmulatorLog("INFO", "runtime-status", `Beginning execution of "${FUNCTION_TARGET_NAME}"`).log();
|
|
670
671
|
const trigger = FUNCTION_TARGET_NAME.split(".").reduce((mod, functionTargetPart) => {
|
|
671
672
|
return mod === null || mod === void 0 ? void 0 : mod[functionTargetPart];
|
|
672
673
|
}, functionModule);
|
|
673
674
|
if (!trigger) {
|
|
674
675
|
throw new Error(`Failed to find function ${FUNCTION_TARGET_NAME} in the loaded module`);
|
|
675
676
|
}
|
|
676
|
-
const startHrTime = process.hrtime();
|
|
677
|
-
res.on("finish", () => {
|
|
678
|
-
const elapsedHrTime = process.hrtime(startHrTime);
|
|
679
|
-
new types_1.EmulatorLog("INFO", "runtime-status", `Finished "${FUNCTION_TARGET_NAME}" in ${elapsedHrTime[0] * 1000 + elapsedHrTime[1] / 1000000}ms`).log();
|
|
680
|
-
});
|
|
681
677
|
switch (FUNCTION_SIGNATURE) {
|
|
682
678
|
case "event":
|
|
683
679
|
case "cloudevent":
|
|
@@ -699,21 +695,9 @@ async function main() {
|
|
|
699
695
|
res.status(500).send(err.message);
|
|
700
696
|
}
|
|
701
697
|
});
|
|
702
|
-
|
|
698
|
+
app.listen(process.env.PORT, () => {
|
|
703
699
|
logDebug(`Listening to port: ${process.env.PORT}`);
|
|
704
700
|
});
|
|
705
|
-
if (!FUNCTION_DEBUG_MODE) {
|
|
706
|
-
let timeout = process.env.FUNCTIONS_EMULATOR_TIMEOUT_SECONDS || "60";
|
|
707
|
-
if (timeout.endsWith("s")) {
|
|
708
|
-
timeout = timeout.slice(0, -1);
|
|
709
|
-
}
|
|
710
|
-
const timeoutMs = parseInt(timeout, 10) * 1000;
|
|
711
|
-
server.setTimeout(timeoutMs, () => {
|
|
712
|
-
new types_1.EmulatorLog("FATAL", "runtime-error", `Your function timed out after ~${timeout}s. To configure this timeout, see
|
|
713
|
-
https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation.`).log();
|
|
714
|
-
return flushAndExit(1);
|
|
715
|
-
});
|
|
716
|
-
}
|
|
717
701
|
let messageHandlePromise = Promise.resolve();
|
|
718
702
|
process.on("message", (message) => {
|
|
719
703
|
messageHandlePromise = messageHandlePromise
|
|
@@ -15,13 +15,17 @@ var RuntimeWorkerState;
|
|
|
15
15
|
RuntimeWorkerState["FINISHING"] = "FINISHING";
|
|
16
16
|
RuntimeWorkerState["FINISHED"] = "FINISHED";
|
|
17
17
|
})(RuntimeWorkerState = exports.RuntimeWorkerState || (exports.RuntimeWorkerState = {}));
|
|
18
|
+
const FREE_WORKER_KEY = "~free~";
|
|
18
19
|
class RuntimeWorker {
|
|
19
|
-
constructor(
|
|
20
|
+
constructor(triggerId, runtime, extensionLogInfo, timeoutSeconds) {
|
|
21
|
+
this.runtime = runtime;
|
|
22
|
+
this.extensionLogInfo = extensionLogInfo;
|
|
23
|
+
this.timeoutSeconds = timeoutSeconds;
|
|
20
24
|
this.stateEvents = new events_1.EventEmitter();
|
|
21
25
|
this.logListeners = [];
|
|
22
26
|
this._state = RuntimeWorkerState.CREATED;
|
|
23
27
|
this.id = uuid.v4();
|
|
24
|
-
this.
|
|
28
|
+
this.triggerKey = triggerId || FREE_WORKER_KEY;
|
|
25
29
|
this.runtime = runtime;
|
|
26
30
|
const childProc = this.runtime.process;
|
|
27
31
|
let msgBuffer = "";
|
|
@@ -39,8 +43,14 @@ class RuntimeWorker {
|
|
|
39
43
|
stdBuffer = this.processStream(data, stdBuffer);
|
|
40
44
|
});
|
|
41
45
|
}
|
|
46
|
+
this.logger = triggerId
|
|
47
|
+
? emulatorLogger_1.EmulatorLogger.forFunction(triggerId, extensionLogInfo)
|
|
48
|
+
: emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
|
|
49
|
+
this.onLogs((log) => {
|
|
50
|
+
this.logger.handleRuntimeLog(log);
|
|
51
|
+
}, true);
|
|
42
52
|
childProc.on("exit", () => {
|
|
43
|
-
this.
|
|
53
|
+
this.logDebug("exited");
|
|
44
54
|
this.state = RuntimeWorkerState.FINISHED;
|
|
45
55
|
});
|
|
46
56
|
}
|
|
@@ -75,23 +85,30 @@ class RuntimeWorker {
|
|
|
75
85
|
});
|
|
76
86
|
}
|
|
77
87
|
request(req, resp, body) {
|
|
88
|
+
if (this.triggerKey !== FREE_WORKER_KEY) {
|
|
89
|
+
this.logInfo(`Beginning execution of "${this.triggerKey}"`);
|
|
90
|
+
}
|
|
91
|
+
const startHrTime = process.hrtime();
|
|
78
92
|
this.state = RuntimeWorkerState.BUSY;
|
|
79
93
|
const onFinish = () => {
|
|
94
|
+
if (this.triggerKey !== FREE_WORKER_KEY) {
|
|
95
|
+
const elapsedHrTime = process.hrtime(startHrTime);
|
|
96
|
+
this.logInfo(`Finished "${this.triggerKey}" in ${elapsedHrTime[0] * 1000 + elapsedHrTime[1] / 1000000}ms`);
|
|
97
|
+
}
|
|
80
98
|
if (this.state === RuntimeWorkerState.BUSY) {
|
|
81
99
|
this.state = RuntimeWorkerState.IDLE;
|
|
82
100
|
}
|
|
83
101
|
else if (this.state === RuntimeWorkerState.FINISHING) {
|
|
84
|
-
this.
|
|
102
|
+
this.logDebug(`IDLE --> FINISHING`);
|
|
85
103
|
this.runtime.process.kill();
|
|
86
104
|
}
|
|
87
105
|
};
|
|
88
106
|
return new Promise((resolve) => {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}, (_resp) => {
|
|
107
|
+
const reqOpts = Object.assign(Object.assign({}, this.runtime.conn.httpReqOpts()), { method: req.method, path: req.path, headers: req.headers });
|
|
108
|
+
if (this.timeoutSeconds) {
|
|
109
|
+
reqOpts.timeout = this.timeoutSeconds * 1000;
|
|
110
|
+
}
|
|
111
|
+
const proxy = http.request(reqOpts, (_resp) => {
|
|
95
112
|
resp.writeHead(_resp.statusCode || 200, _resp.headers);
|
|
96
113
|
const piped = _resp.pipe(resp);
|
|
97
114
|
piped.on("finish", () => {
|
|
@@ -99,7 +116,13 @@ class RuntimeWorker {
|
|
|
99
116
|
resolve();
|
|
100
117
|
});
|
|
101
118
|
});
|
|
119
|
+
proxy.on("timeout", () => {
|
|
120
|
+
this.logger.log("ERROR", `Your function timed out after ~${this.timeoutSeconds}s. To configure this timeout, see
|
|
121
|
+
https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation.`);
|
|
122
|
+
proxy.destroy();
|
|
123
|
+
});
|
|
102
124
|
proxy.on("error", (err) => {
|
|
125
|
+
this.logger.log("ERROR", `Request to function failed: ${err}`);
|
|
103
126
|
resp.writeHead(500);
|
|
104
127
|
resp.write(JSON.stringify(err));
|
|
105
128
|
resp.end();
|
|
@@ -125,7 +148,7 @@ class RuntimeWorker {
|
|
|
125
148
|
if (state === RuntimeWorkerState.FINISHED) {
|
|
126
149
|
this.runtime.events.removeAllListeners();
|
|
127
150
|
}
|
|
128
|
-
this.
|
|
151
|
+
this.logDebug(state);
|
|
129
152
|
this._state = state;
|
|
130
153
|
this.stateEvents.emit(this._state);
|
|
131
154
|
}
|
|
@@ -137,16 +160,11 @@ class RuntimeWorker {
|
|
|
137
160
|
}
|
|
138
161
|
isSocketReady() {
|
|
139
162
|
return new Promise((resolve, reject) => {
|
|
140
|
-
const req = http
|
|
141
|
-
.request({
|
|
142
|
-
method: "GET",
|
|
143
|
-
path: "/__/health",
|
|
144
|
-
socketPath: this.runtime.socketPath,
|
|
145
|
-
}, () => {
|
|
163
|
+
const req = http.request(Object.assign(Object.assign({}, this.runtime.conn.httpReqOpts()), { method: "GET", path: "/__/health" }), () => {
|
|
146
164
|
this.readyForWork();
|
|
147
165
|
resolve();
|
|
148
|
-
})
|
|
149
|
-
|
|
166
|
+
});
|
|
167
|
+
req.end();
|
|
150
168
|
req.on("error", (error) => {
|
|
151
169
|
reject(error);
|
|
152
170
|
});
|
|
@@ -173,8 +191,11 @@ class RuntimeWorker {
|
|
|
173
191
|
}
|
|
174
192
|
}
|
|
175
193
|
}
|
|
176
|
-
|
|
177
|
-
|
|
194
|
+
logDebug(msg) {
|
|
195
|
+
this.logger.log("DEBUG", `[worker-${this.triggerKey}-${this.id}]: ${msg}`);
|
|
196
|
+
}
|
|
197
|
+
logInfo(msg) {
|
|
198
|
+
this.logger.logLabeled("BULLET", "functions", msg);
|
|
178
199
|
}
|
|
179
200
|
}
|
|
180
201
|
exports.RuntimeWorker = RuntimeWorker;
|
|
@@ -195,12 +216,12 @@ class RuntimeWorkerPool {
|
|
|
195
216
|
for (const arr of this.workers.values()) {
|
|
196
217
|
arr.forEach((w) => {
|
|
197
218
|
if (w.state === RuntimeWorkerState.IDLE) {
|
|
198
|
-
this.log(`Shutting down IDLE worker (${w.
|
|
219
|
+
this.log(`Shutting down IDLE worker (${w.triggerKey})`);
|
|
199
220
|
w.state = RuntimeWorkerState.FINISHING;
|
|
200
221
|
w.runtime.process.kill();
|
|
201
222
|
}
|
|
202
223
|
else if (w.state === RuntimeWorkerState.BUSY) {
|
|
203
|
-
this.log(`Marking BUSY worker to finish (${w.
|
|
224
|
+
this.log(`Marking BUSY worker to finish (${w.triggerKey})`);
|
|
204
225
|
w.state = RuntimeWorkerState.FINISHING;
|
|
205
226
|
}
|
|
206
227
|
});
|
|
@@ -247,19 +268,14 @@ class RuntimeWorkerPool {
|
|
|
247
268
|
}
|
|
248
269
|
return;
|
|
249
270
|
}
|
|
250
|
-
addWorker(
|
|
251
|
-
|
|
252
|
-
this.
|
|
253
|
-
const
|
|
271
|
+
addWorker(trigger, runtime, extensionLogInfo) {
|
|
272
|
+
this.log(`addWorker(${this.getKey(trigger === null || trigger === void 0 ? void 0 : trigger.id)})`);
|
|
273
|
+
const disableTimeout = !(trigger === null || trigger === void 0 ? void 0 : trigger.id) || this.mode === types_1.FunctionsExecutionMode.SEQUENTIAL;
|
|
274
|
+
const worker = new RuntimeWorker(trigger === null || trigger === void 0 ? void 0 : trigger.id, runtime, extensionLogInfo, disableTimeout ? undefined : trigger === null || trigger === void 0 ? void 0 : trigger.timeoutSeconds);
|
|
275
|
+
const keyWorkers = this.getTriggerWorkers(trigger === null || trigger === void 0 ? void 0 : trigger.id);
|
|
254
276
|
keyWorkers.push(worker);
|
|
255
|
-
this.setTriggerWorkers(
|
|
256
|
-
|
|
257
|
-
? emulatorLogger_1.EmulatorLogger.forFunction(triggerId, extensionLogInfo)
|
|
258
|
-
: emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
|
|
259
|
-
worker.onLogs((log) => {
|
|
260
|
-
logger.handleRuntimeLog(log);
|
|
261
|
-
}, true);
|
|
262
|
-
this.log(`Adding worker with key ${worker.key}, total=${keyWorkers.length}`);
|
|
277
|
+
this.setTriggerWorkers(trigger === null || trigger === void 0 ? void 0 : trigger.id, keyWorkers);
|
|
278
|
+
this.log(`Adding worker with key ${worker.triggerKey}, total=${keyWorkers.length}`);
|
|
263
279
|
return worker;
|
|
264
280
|
}
|
|
265
281
|
getTriggerWorkers(triggerId) {
|
package/lib/emulator/hub.js
CHANGED
|
@@ -12,12 +12,6 @@ const registry_1 = require("./registry");
|
|
|
12
12
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
13
13
|
const pkg = require("../../package.json");
|
|
14
14
|
class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
15
|
-
constructor(args) {
|
|
16
|
-
super({
|
|
17
|
-
listen: args.listen,
|
|
18
|
-
});
|
|
19
|
-
this.args = args;
|
|
20
|
-
}
|
|
21
15
|
static readLocatorFile(projectId) {
|
|
22
16
|
const locatorPath = this.getLocatorFilePath(projectId);
|
|
23
17
|
if (!fs.existsSync(locatorPath)) {
|
|
@@ -36,6 +30,12 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
36
30
|
const filename = `hub-${projectId}.json`;
|
|
37
31
|
return path.join(dir, filename);
|
|
38
32
|
}
|
|
33
|
+
constructor(args) {
|
|
34
|
+
super({
|
|
35
|
+
listen: args.listen,
|
|
36
|
+
});
|
|
37
|
+
this.args = args;
|
|
38
|
+
}
|
|
39
39
|
async start() {
|
|
40
40
|
await super.start();
|
|
41
41
|
await this.writeLocatorFile();
|
|
@@ -13,12 +13,6 @@ const child_process_1 = require("child_process");
|
|
|
13
13
|
const PUBSUB_KILL_COMMAND = "pubsub_pids=$(ps aux | grep '[p]ubsub-emulator' | awk '{print $2}');" +
|
|
14
14
|
" if [ ! -z '$pubsub_pids' ]; then kill -9 $pubsub_pids; fi;";
|
|
15
15
|
class PubsubEmulator {
|
|
16
|
-
constructor(args) {
|
|
17
|
-
this.args = args;
|
|
18
|
-
this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.PUBSUB);
|
|
19
|
-
this.triggersForTopic = new Map();
|
|
20
|
-
this.subscriptionForTopic = new Map();
|
|
21
|
-
}
|
|
22
16
|
get pubsub() {
|
|
23
17
|
if (!this._pubsub) {
|
|
24
18
|
this._pubsub = new pubsub_1.PubSub({
|
|
@@ -28,6 +22,12 @@ class PubsubEmulator {
|
|
|
28
22
|
}
|
|
29
23
|
return this._pubsub;
|
|
30
24
|
}
|
|
25
|
+
constructor(args) {
|
|
26
|
+
this.args = args;
|
|
27
|
+
this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.PUBSUB);
|
|
28
|
+
this.triggersForTopic = new Map();
|
|
29
|
+
this.subscriptionForTopic = new Map();
|
|
30
|
+
}
|
|
31
31
|
async start() {
|
|
32
32
|
return downloadableEmulators.start(types_1.Emulators.PUBSUB, this.args);
|
|
33
33
|
}
|
|
@@ -132,20 +132,23 @@ class PubsubEmulator {
|
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
createCloudEventRequestBody(topic, message) {
|
|
135
|
+
const truncatedPublishTime = new Date(message.publishTime.getMilliseconds()).toISOString();
|
|
135
136
|
const data = {
|
|
136
137
|
message: {
|
|
137
138
|
messageId: message.id,
|
|
138
|
-
publishTime:
|
|
139
|
+
publishTime: truncatedPublishTime,
|
|
139
140
|
attributes: message.attributes,
|
|
140
141
|
orderingKey: message.orderingKey,
|
|
141
142
|
data: message.data.toString("base64"),
|
|
143
|
+
message_id: message.id,
|
|
144
|
+
publish_time: truncatedPublishTime,
|
|
142
145
|
},
|
|
143
146
|
subscription: this.subscriptionForTopic.get(topic).name,
|
|
144
147
|
};
|
|
145
148
|
return {
|
|
146
|
-
specversion: "1",
|
|
149
|
+
specversion: "1.0",
|
|
147
150
|
id: uuid.v4(),
|
|
148
|
-
time:
|
|
151
|
+
time: truncatedPublishTime,
|
|
149
152
|
type: "google.cloud.pubsub.topic.v1.messagePublished",
|
|
150
153
|
source: `//pubsub.googleapis.com/projects/${this.args.projectId}/topics/${topic}`,
|
|
151
154
|
data,
|
|
@@ -15,7 +15,8 @@ function sendFileBytes(md, data, req, res) {
|
|
|
15
15
|
}
|
|
16
16
|
res.setHeader("Accept-Ranges", "bytes");
|
|
17
17
|
res.setHeader("Content-Type", md.contentType || "application/octet-stream");
|
|
18
|
-
|
|
18
|
+
const fileName = md.name.split("/").pop();
|
|
19
|
+
res.setHeader("Content-Disposition", `${md.contentDisposition || "attachment"}; filename=${fileName}`);
|
|
19
20
|
if (didGunzip) {
|
|
20
21
|
res.setHeader("Transfer-Encoding", "chunked");
|
|
21
22
|
}
|
|
@@ -76,7 +76,7 @@ class StorageCloudFunctions {
|
|
|
76
76
|
time = typeof data.updated === "string" ? data.updated : data.updated.toISOString();
|
|
77
77
|
}
|
|
78
78
|
return {
|
|
79
|
-
specversion: "1",
|
|
79
|
+
specversion: "1.0",
|
|
80
80
|
id: uuid.v4(),
|
|
81
81
|
type: `google.cloud.storage.object.v1.${ceAction}`,
|
|
82
82
|
source: `//storage.googleapis.com/projects/_/buckets/${objectMetadataPayload.bucket}/objects/${objectMetadataPayload.name}`,
|
|
@@ -20,15 +20,15 @@ const upload_1 = require("./upload");
|
|
|
20
20
|
const track_1 = require("../../track");
|
|
21
21
|
const types_2 = require("../types");
|
|
22
22
|
class StoredFile {
|
|
23
|
-
constructor(metadata) {
|
|
24
|
-
this.metadata = metadata;
|
|
25
|
-
}
|
|
26
23
|
get metadata() {
|
|
27
24
|
return this._metadata;
|
|
28
25
|
}
|
|
29
26
|
set metadata(value) {
|
|
30
27
|
this._metadata = value;
|
|
31
28
|
}
|
|
29
|
+
constructor(metadata) {
|
|
30
|
+
this.metadata = metadata;
|
|
31
|
+
}
|
|
32
32
|
}
|
|
33
33
|
exports.StoredFile = StoredFile;
|
|
34
34
|
const TRAILING_SLASHES_PATTERN = /\/+$/;
|
|
@@ -305,7 +305,7 @@ class StorageLayer {
|
|
|
305
305
|
return this._persistence.dirPath;
|
|
306
306
|
}
|
|
307
307
|
async export(storageExportPath, options) {
|
|
308
|
-
var e_1,
|
|
308
|
+
var _a, e_1, _b, _c;
|
|
309
309
|
const bucketsList = {
|
|
310
310
|
buckets: [],
|
|
311
311
|
};
|
|
@@ -324,18 +324,25 @@ class StorageLayer {
|
|
|
324
324
|
const metadataDirPath = path.join(storageExportPath, "metadata");
|
|
325
325
|
await fse.ensureDir(metadataDirPath);
|
|
326
326
|
try {
|
|
327
|
-
for (var
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
327
|
+
for (var _d = true, _e = __asyncValues(this._files.entries()), _f; _f = await _e.next(), _a = _f.done, !_a;) {
|
|
328
|
+
_c = _f.value;
|
|
329
|
+
_d = false;
|
|
330
|
+
try {
|
|
331
|
+
const [, file] = _c;
|
|
332
|
+
const diskFileName = this._persistence.getDiskFileName(this.path(file.metadata.bucket, file.metadata.name));
|
|
333
|
+
await fse.copy(path.join(this.dirPath, diskFileName), path.join(blobsDirPath, diskFileName));
|
|
334
|
+
const metadataExportPath = path.join(metadataDirPath, encodeURIComponent(diskFileName)) + ".json";
|
|
335
|
+
await fse.writeFile(metadataExportPath, metadata_1.StoredFileMetadata.toJSON(file.metadata));
|
|
336
|
+
}
|
|
337
|
+
finally {
|
|
338
|
+
_d = true;
|
|
339
|
+
}
|
|
333
340
|
}
|
|
334
341
|
}
|
|
335
342
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
336
343
|
finally {
|
|
337
344
|
try {
|
|
338
|
-
if (
|
|
345
|
+
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
|
|
339
346
|
}
|
|
340
347
|
finally { if (e_1) throw e_1.error; }
|
|
341
348
|
}
|
package/lib/emulator/types.js
CHANGED
|
@@ -82,15 +82,6 @@ var FunctionsExecutionMode;
|
|
|
82
82
|
FunctionsExecutionMode["SEQUENTIAL"] = "sequential";
|
|
83
83
|
})(FunctionsExecutionMode = exports.FunctionsExecutionMode || (exports.FunctionsExecutionMode = {}));
|
|
84
84
|
class EmulatorLog {
|
|
85
|
-
constructor(level, type, text, data, timestamp) {
|
|
86
|
-
this.level = level;
|
|
87
|
-
this.type = type;
|
|
88
|
-
this.text = text;
|
|
89
|
-
this.data = data;
|
|
90
|
-
this.timestamp = timestamp;
|
|
91
|
-
this.timestamp = this.timestamp || new Date().toISOString();
|
|
92
|
-
this.data = this.data || {};
|
|
93
|
-
}
|
|
94
85
|
get date() {
|
|
95
86
|
if (!this.timestamp) {
|
|
96
87
|
return new Date(0);
|
|
@@ -145,6 +136,15 @@ class EmulatorLog {
|
|
|
145
136
|
}
|
|
146
137
|
return new EmulatorLog(parsedLog.level, parsedLog.type, parsedLog.text, parsedLog.data, parsedLog.timestamp);
|
|
147
138
|
}
|
|
139
|
+
constructor(level, type, text, data, timestamp) {
|
|
140
|
+
this.level = level;
|
|
141
|
+
this.type = type;
|
|
142
|
+
this.text = text;
|
|
143
|
+
this.data = data;
|
|
144
|
+
this.timestamp = timestamp;
|
|
145
|
+
this.timestamp = this.timestamp || new Date().toISOString();
|
|
146
|
+
this.data = this.data || {};
|
|
147
|
+
}
|
|
148
148
|
toString() {
|
|
149
149
|
return this.toStringCore(false);
|
|
150
150
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.promptForPublisherTOS = void 0;
|
|
4
|
-
const
|
|
4
|
+
const marked_1 = require("marked");
|
|
5
5
|
const TerminalRenderer = require("marked-terminal");
|
|
6
6
|
const error_1 = require("../error");
|
|
7
7
|
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
8
8
|
const prompt_1 = require("../prompt");
|
|
9
9
|
const utils = require("../utils");
|
|
10
|
-
marked.setOptions({
|
|
10
|
+
marked_1.marked.setOptions({
|
|
11
11
|
renderer: new TerminalRenderer(),
|
|
12
12
|
});
|
|
13
13
|
async function promptForPublisherTOS() {
|
|
@@ -17,11 +17,11 @@ async function promptForPublisherTOS() {
|
|
|
17
17
|
" - If you become aware or should be aware of a critical security issue in your extension, you will provide either a resolution or a written resolution plan within 48 hours.\n" +
|
|
18
18
|
" - If Google requests a critical security matter to be patched for your extension, you will respond to Google within 48 hours with either a resolution or a written resolution plan.\n" +
|
|
19
19
|
" - Google may remove your extension or terminate the agreement, if you violate any terms.";
|
|
20
|
-
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(termsOfServiceMsg));
|
|
20
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(termsOfServiceMsg));
|
|
21
21
|
const consented = await (0, prompt_1.promptOnce)({
|
|
22
22
|
name: "consent",
|
|
23
23
|
type: "confirm",
|
|
24
|
-
message: marked("Do you accept the [Firebase Extensions Publisher Terms and Conditions](https://firebase.google.com/docs/extensions/alpha/terms-of-service) and acknowledge that your information will be used in accordance with [Google's Privacy Policy](https://policies.google.com/privacy?hl=en)?"),
|
|
24
|
+
message: (0, marked_1.marked)("Do you accept the [Firebase Extensions Publisher Terms and Conditions](https://firebase.google.com/docs/extensions/alpha/terms-of-service) and acknowledge that your information will be used in accordance with [Google's Privacy Policy](https://policies.google.com/privacy?hl=en)?"),
|
|
25
25
|
default: false,
|
|
26
26
|
});
|
|
27
27
|
if (!consented) {
|
|
@@ -6,7 +6,7 @@ const extensionsApi = require("../extensions/extensionsApi");
|
|
|
6
6
|
const utils = require("../utils");
|
|
7
7
|
const clc = require("colorette");
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
|
-
const
|
|
9
|
+
const marked_1 = require("marked");
|
|
10
10
|
function checkAllowedEventTypesResponse(response, validEvents) {
|
|
11
11
|
const validEventTypes = validEvents.map((e) => e.type);
|
|
12
12
|
if (response.length === 0) {
|
|
@@ -23,7 +23,7 @@ function checkAllowedEventTypesResponse(response, validEvents) {
|
|
|
23
23
|
exports.checkAllowedEventTypesResponse = checkAllowedEventTypesResponse;
|
|
24
24
|
async function askForEventsConfig(events, projectId, instanceId) {
|
|
25
25
|
var _a, _b;
|
|
26
|
-
logger_1.logger.info(`\n${clc.bold("Enable Events")}: ${marked("If you enable events, you can write custom event handlers ([https://firebase.google.com/docs/extensions/install-extensions#eventarc](https://firebase.google.com/docs/extensions/install-extensions#eventarc)) that respond to these events.\n\nYou can always enable or disable events later. Events will be emitted via Eventarc. Fees apply ([https://cloud.google.com/eventarc/pricing](https://cloud.google.com/eventarc/pricing)).")}`);
|
|
26
|
+
logger_1.logger.info(`\n${clc.bold("Enable Events")}: ${(0, marked_1.marked)("If you enable events, you can write custom event handlers ([https://firebase.google.com/docs/extensions/install-extensions#eventarc](https://firebase.google.com/docs/extensions/install-extensions#eventarc)) that respond to these events.\n\nYou can always enable or disable events later. Events will be emitted via Eventarc. Fees apply ([https://cloud.google.com/eventarc/pricing](https://cloud.google.com/eventarc/pricing)).")}`);
|
|
27
27
|
if (!(await askShouldCollectEventsConfig())) {
|
|
28
28
|
return undefined;
|
|
29
29
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getInquirerDefault = exports.promptCreateSecret = exports.askForParam = exports.ask = exports.checkResponse = exports.SecretLocation = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const clc = require("colorette");
|
|
6
|
-
const
|
|
6
|
+
const marked_1 = require("marked");
|
|
7
7
|
const types_1 = require("./types");
|
|
8
8
|
const secretManagerApi = require("../gcp/secretManager");
|
|
9
9
|
const secretsUtils = require("./secretsUtils");
|
|
@@ -13,6 +13,7 @@ const logger_1 = require("../logger");
|
|
|
13
13
|
const prompt_1 = require("../prompt");
|
|
14
14
|
const utils = require("../utils");
|
|
15
15
|
const projectUtils_1 = require("../projectUtils");
|
|
16
|
+
const functional_1 = require("../functional");
|
|
16
17
|
var SecretLocation;
|
|
17
18
|
(function (SecretLocation) {
|
|
18
19
|
SecretLocation[SecretLocation["CLOUD"] = 1] = "CLOUD";
|
|
@@ -67,8 +68,9 @@ async function ask(args) {
|
|
|
67
68
|
}
|
|
68
69
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, "answer the questions below to configure your extension:");
|
|
69
70
|
const substituted = (0, extensionsHelper_1.substituteParams)(args.paramSpecs, args.firebaseProjectParams);
|
|
71
|
+
const [advancedParams, standardParams] = (0, functional_1.partition)(substituted, (p) => { var _a; return (_a = p.advanced) !== null && _a !== void 0 ? _a : false; });
|
|
70
72
|
const result = {};
|
|
71
|
-
const promises =
|
|
73
|
+
const promises = standardParams.map((paramSpec) => {
|
|
72
74
|
return async () => {
|
|
73
75
|
result[paramSpec.param] = await askForParam({
|
|
74
76
|
projectId: args.projectId,
|
|
@@ -78,6 +80,35 @@ async function ask(args) {
|
|
|
78
80
|
});
|
|
79
81
|
};
|
|
80
82
|
});
|
|
83
|
+
if (advancedParams.length) {
|
|
84
|
+
promises.push(async () => {
|
|
85
|
+
const shouldPrompt = await (0, prompt_1.promptOnce)({
|
|
86
|
+
type: "confirm",
|
|
87
|
+
message: "Do you want to configure any advanced parameters for this instance?",
|
|
88
|
+
default: false,
|
|
89
|
+
});
|
|
90
|
+
if (shouldPrompt) {
|
|
91
|
+
const advancedPromises = advancedParams.map((paramSpec) => {
|
|
92
|
+
return async () => {
|
|
93
|
+
result[paramSpec.param] = await askForParam({
|
|
94
|
+
projectId: args.projectId,
|
|
95
|
+
instanceId: args.instanceId,
|
|
96
|
+
paramSpec: paramSpec,
|
|
97
|
+
reconfiguring: args.reconfiguring,
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
await advancedPromises.reduce((prev, cur) => prev.then(cur), Promise.resolve());
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
for (const paramSpec of advancedParams) {
|
|
105
|
+
if (paramSpec.required && paramSpec.default) {
|
|
106
|
+
result[paramSpec.param] = { baseValue: paramSpec.default };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
81
112
|
await promises.reduce((prev, cur) => prev.then(cur), Promise.resolve());
|
|
82
113
|
logger_1.logger.info();
|
|
83
114
|
return result;
|
|
@@ -91,7 +122,7 @@ async function askForParam(args) {
|
|
|
91
122
|
let secretLocations = [];
|
|
92
123
|
const description = paramSpec.description || "";
|
|
93
124
|
const label = paramSpec.label.trim();
|
|
94
|
-
logger_1.logger.info(`\n${clc.bold(label)}${clc.bold(paramSpec.required ? "" : " (Optional)")}: ${marked(description).trim()}`);
|
|
125
|
+
logger_1.logger.info(`\n${clc.bold(label)}${clc.bold(paramSpec.required ? "" : " (Optional)")}: ${(0, marked_1.marked)(description).trim()}`);
|
|
95
126
|
while (!valid) {
|
|
96
127
|
switch (paramSpec.type) {
|
|
97
128
|
case types_1.ParamType.SELECT:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.displayNode10CreateBillingNotice = exports.displayNode10UpdateBillingNotice = void 0;
|
|
4
|
-
const
|
|
4
|
+
const marked_1 = require("marked");
|
|
5
5
|
const TerminalRenderer = require("marked-terminal");
|
|
6
6
|
const error_1 = require("../error");
|
|
7
7
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
8
8
|
const prompt_1 = require("../prompt");
|
|
9
9
|
const utils = require("../utils");
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
|
-
marked.setOptions({
|
|
11
|
+
marked_1.marked.setOptions({
|
|
12
12
|
renderer: new TerminalRenderer(),
|
|
13
13
|
});
|
|
14
14
|
const urlPricingExamples = "https://cloud.google.com/functions/pricing#pricing_examples";
|
|
@@ -39,13 +39,13 @@ function hasRuntime(spec, runtime) {
|
|
|
39
39
|
}
|
|
40
40
|
function displayNode10UpdateBillingNotice(curSpec, newSpec) {
|
|
41
41
|
if (hasRuntime(curSpec, "nodejs8") && hasRuntime(newSpec, "nodejs10")) {
|
|
42
|
-
utils.logLabeledWarning(extensionsHelper_1.logPrefix, marked(billingMsgUpdate));
|
|
42
|
+
utils.logLabeledWarning(extensionsHelper_1.logPrefix, (0, marked_1.marked)(billingMsgUpdate));
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
exports.displayNode10UpdateBillingNotice = displayNode10UpdateBillingNotice;
|
|
46
46
|
async function displayNode10CreateBillingNotice(spec, prompt) {
|
|
47
47
|
if (hasRuntime(spec, "nodejs10")) {
|
|
48
|
-
utils.logLabeledWarning(extensionsHelper_1.logPrefix, marked(billingMsgCreate));
|
|
48
|
+
utils.logLabeledWarning(extensionsHelper_1.logPrefix, (0, marked_1.marked)(billingMsgCreate));
|
|
49
49
|
if (prompt) {
|
|
50
50
|
const continueUpdate = await (0, prompt_1.promptOnce)({
|
|
51
51
|
type: "confirm",
|