firebase-tools 12.5.4 → 12.6.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/experiments-list.js +3 -1
- package/lib/deploy/functions/release/fabricator.js +23 -15
- package/lib/deploy/functions/release/sourceTokenScraper.js +15 -3
- package/lib/emulator/controller.js +6 -4
- package/lib/frameworks/next/index.js +1 -1
- package/lib/frameworks/utils.js +11 -2
- package/lib/gcp/cloudfunctionsv2.js +9 -4
- package/package.json +1 -1
- package/standalone/package.json +2 -1
|
@@ -6,7 +6,9 @@ const Table = require("cli-table");
|
|
|
6
6
|
const experiments = require("../experiments");
|
|
7
7
|
const functional_1 = require("../functional");
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
|
-
exports.command = new command_1.Command("experiments:list")
|
|
9
|
+
exports.command = new command_1.Command("experiments:list")
|
|
10
|
+
.description("list all experiments, along with a description of each experiment and whether it is currently enabled")
|
|
11
|
+
.action(() => {
|
|
10
12
|
const table = new Table({
|
|
11
13
|
head: ["Enabled", "Name", "Description"],
|
|
12
14
|
style: { head: ["yellow"] },
|
|
@@ -95,17 +95,18 @@ class Fabricator {
|
|
|
95
95
|
deployResults.push(result);
|
|
96
96
|
};
|
|
97
97
|
const upserts = [];
|
|
98
|
-
const
|
|
98
|
+
const scraperV1 = new sourceTokenScraper_1.SourceTokenScraper();
|
|
99
|
+
const scraperV2 = new sourceTokenScraper_1.SourceTokenScraper();
|
|
99
100
|
for (const endpoint of changes.endpointsToCreate) {
|
|
100
101
|
this.logOpStart("creating", endpoint);
|
|
101
|
-
upserts.push(handle("create", endpoint, () => this.createEndpoint(endpoint,
|
|
102
|
+
upserts.push(handle("create", endpoint, () => this.createEndpoint(endpoint, scraperV1, scraperV2)));
|
|
102
103
|
}
|
|
103
104
|
for (const endpoint of changes.endpointsToSkip) {
|
|
104
105
|
utils.logSuccess(this.getLogSuccessMessage("skip", endpoint));
|
|
105
106
|
}
|
|
106
107
|
for (const update of changes.endpointsToUpdate) {
|
|
107
108
|
this.logOpStart("updating", update.endpoint);
|
|
108
|
-
upserts.push(handle("update", update.endpoint, () => this.updateEndpoint(update,
|
|
109
|
+
upserts.push(handle("update", update.endpoint, () => this.updateEndpoint(update, scraperV1, scraperV2)));
|
|
109
110
|
}
|
|
110
111
|
await utils.allSettled(upserts);
|
|
111
112
|
if (deployResults.find((r) => r.error)) {
|
|
@@ -126,31 +127,31 @@ class Fabricator {
|
|
|
126
127
|
await utils.allSettled(deletes);
|
|
127
128
|
return deployResults;
|
|
128
129
|
}
|
|
129
|
-
async createEndpoint(endpoint,
|
|
130
|
+
async createEndpoint(endpoint, scraperV1, scraperV2) {
|
|
130
131
|
endpoint.labels = Object.assign(Object.assign({}, endpoint.labels), deploymentTool.labels());
|
|
131
132
|
if (endpoint.platform === "gcfv1") {
|
|
132
|
-
await this.createV1Function(endpoint,
|
|
133
|
+
await this.createV1Function(endpoint, scraperV1);
|
|
133
134
|
}
|
|
134
135
|
else if (endpoint.platform === "gcfv2") {
|
|
135
|
-
await this.createV2Function(endpoint);
|
|
136
|
+
await this.createV2Function(endpoint, scraperV2);
|
|
136
137
|
}
|
|
137
138
|
else {
|
|
138
139
|
(0, functional_1.assertExhaustive)(endpoint.platform);
|
|
139
140
|
}
|
|
140
141
|
await this.setTrigger(endpoint);
|
|
141
142
|
}
|
|
142
|
-
async updateEndpoint(update,
|
|
143
|
+
async updateEndpoint(update, scraperV1, scraperV2) {
|
|
143
144
|
update.endpoint.labels = Object.assign(Object.assign({}, update.endpoint.labels), deploymentTool.labels());
|
|
144
145
|
if (update.deleteAndRecreate) {
|
|
145
146
|
await this.deleteEndpoint(update.deleteAndRecreate);
|
|
146
|
-
await this.createEndpoint(update.endpoint,
|
|
147
|
+
await this.createEndpoint(update.endpoint, scraperV1, scraperV2);
|
|
147
148
|
return;
|
|
148
149
|
}
|
|
149
150
|
if (update.endpoint.platform === "gcfv1") {
|
|
150
|
-
await this.updateV1Function(update.endpoint,
|
|
151
|
+
await this.updateV1Function(update.endpoint, scraperV1);
|
|
151
152
|
}
|
|
152
153
|
else if (update.endpoint.platform === "gcfv2") {
|
|
153
|
-
await this.updateV2Function(update.endpoint);
|
|
154
|
+
await this.updateV2Function(update.endpoint, scraperV2);
|
|
154
155
|
}
|
|
155
156
|
else {
|
|
156
157
|
(0, functional_1.assertExhaustive)(update.endpoint.platform);
|
|
@@ -221,7 +222,7 @@ class Fabricator {
|
|
|
221
222
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
222
223
|
}
|
|
223
224
|
}
|
|
224
|
-
async createV2Function(endpoint) {
|
|
225
|
+
async createV2Function(endpoint, scraper) {
|
|
225
226
|
var _a, _b, _c, _d, _e;
|
|
226
227
|
const storageSource = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
|
|
227
228
|
if (!storageSource) {
|
|
@@ -275,10 +276,12 @@ class Fabricator {
|
|
|
275
276
|
while (!resultFunction) {
|
|
276
277
|
resultFunction = await this.functionExecutor
|
|
277
278
|
.run(async () => {
|
|
279
|
+
apiFunction.buildConfig.sourceToken = await scraper.getToken();
|
|
278
280
|
const op = await gcfV2.createFunction(apiFunction);
|
|
279
|
-
return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name }));
|
|
281
|
+
return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name, onPoll: scraper.poller }));
|
|
280
282
|
})
|
|
281
283
|
.catch(async (err) => {
|
|
284
|
+
scraper.abort();
|
|
282
285
|
if (err.code === CLOUD_RUN_RESOURCE_EXHAUSTED_CODE) {
|
|
283
286
|
await this.deleteV2Function(endpoint);
|
|
284
287
|
return null;
|
|
@@ -366,7 +369,7 @@ class Fabricator {
|
|
|
366
369
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
367
370
|
}
|
|
368
371
|
}
|
|
369
|
-
async updateV2Function(endpoint) {
|
|
372
|
+
async updateV2Function(endpoint, scraper) {
|
|
370
373
|
var _a, _b, _c, _d;
|
|
371
374
|
const storageSource = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
|
|
372
375
|
if (!storageSource) {
|
|
@@ -379,10 +382,15 @@ class Fabricator {
|
|
|
379
382
|
}
|
|
380
383
|
const resultFunction = await this.functionExecutor
|
|
381
384
|
.run(async () => {
|
|
385
|
+
apiFunction.buildConfig.sourceToken = await scraper.getToken();
|
|
382
386
|
const op = await gcfV2.updateFunction(apiFunction);
|
|
383
|
-
return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `update-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name }));
|
|
387
|
+
return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `update-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name, onPoll: scraper.poller }));
|
|
384
388
|
}, { retryCodes: [...executor_1.DEFAULT_RETRY_CODES, CLOUD_RUN_RESOURCE_EXHAUSTED_CODE] })
|
|
385
|
-
.catch(
|
|
389
|
+
.catch((err) => {
|
|
390
|
+
scraper.abort();
|
|
391
|
+
logger_1.logger.error(err.message);
|
|
392
|
+
throw new reporter.DeploymentError(endpoint, "update", err);
|
|
393
|
+
});
|
|
386
394
|
endpoint.uri = (_c = resultFunction.serviceConfig) === null || _c === void 0 ? void 0 : _c.uri;
|
|
387
395
|
const serviceName = (_d = resultFunction.serviceConfig) === null || _d === void 0 ? void 0 : _d.service;
|
|
388
396
|
endpoint.runServiceId = utils.last(serviceName === null || serviceName === void 0 ? void 0 : serviceName.split("/"));
|
|
@@ -10,21 +10,30 @@ class SourceTokenScraper {
|
|
|
10
10
|
this.promise = new Promise((resolve) => (this.resolve = resolve));
|
|
11
11
|
this.fetchState = "NONE";
|
|
12
12
|
}
|
|
13
|
+
abort() {
|
|
14
|
+
this.resolve({ aborted: true });
|
|
15
|
+
}
|
|
13
16
|
async getToken() {
|
|
14
17
|
if (this.fetchState === "NONE") {
|
|
15
18
|
this.fetchState = "FETCHING";
|
|
16
19
|
return undefined;
|
|
17
20
|
}
|
|
18
21
|
else if (this.fetchState === "FETCHING") {
|
|
19
|
-
|
|
22
|
+
const tokenResult = await this.promise;
|
|
23
|
+
if (tokenResult.aborted) {
|
|
24
|
+
this.promise = new Promise((resolve) => (this.resolve = resolve));
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return tokenResult.token;
|
|
20
28
|
}
|
|
21
29
|
else if (this.fetchState === "VALID") {
|
|
30
|
+
const tokenResult = await this.promise;
|
|
22
31
|
if (this.isTokenExpired()) {
|
|
23
32
|
this.fetchState = "FETCHING";
|
|
24
33
|
this.promise = new Promise((resolve) => (this.resolve = resolve));
|
|
25
34
|
return undefined;
|
|
26
35
|
}
|
|
27
|
-
return
|
|
36
|
+
return tokenResult.token;
|
|
28
37
|
}
|
|
29
38
|
else {
|
|
30
39
|
(0, functional_1.assertExhaustive)(this.fetchState);
|
|
@@ -45,7 +54,10 @@ class SourceTokenScraper {
|
|
|
45
54
|
if (((_a = op.metadata) === null || _a === void 0 ? void 0 : _a.sourceToken) || op.done) {
|
|
46
55
|
const [, , , region] = ((_c = (_b = op.metadata) === null || _b === void 0 ? void 0 : _b.target) === null || _c === void 0 ? void 0 : _c.split("/")) || [];
|
|
47
56
|
logger_1.logger.debug(`Got source token ${(_d = op.metadata) === null || _d === void 0 ? void 0 : _d.sourceToken} for region ${region}`);
|
|
48
|
-
this.resolve(
|
|
57
|
+
this.resolve({
|
|
58
|
+
token: (_e = op.metadata) === null || _e === void 0 ? void 0 : _e.sourceToken,
|
|
59
|
+
aborted: false,
|
|
60
|
+
});
|
|
49
61
|
this.fetchState = "VALID";
|
|
50
62
|
this.expiry = Date.now() + this.tokenValidDurationMs;
|
|
51
63
|
}
|
|
@@ -620,13 +620,15 @@ async function exportEmulatorData(exportPath, options, initiatedBy) {
|
|
|
620
620
|
fs.mkdirSync(exportAbsPath);
|
|
621
621
|
}
|
|
622
622
|
const existingMetadata = hubExport_1.HubExport.readMetadata(exportAbsPath);
|
|
623
|
-
|
|
623
|
+
const isExportDirEmpty = fs.readdirSync(exportAbsPath).length === 0;
|
|
624
|
+
if ((existingMetadata || !isExportDirEmpty) && !(options.force || options.exportOnExit)) {
|
|
624
625
|
if (options.noninteractive) {
|
|
625
626
|
throw new error_1.FirebaseError("Export already exists in the target directory, re-run with --force to overwrite.", { exit: 1 });
|
|
626
627
|
}
|
|
627
|
-
const prompt = await (0, prompt_1.
|
|
628
|
-
|
|
629
|
-
|
|
628
|
+
const prompt = await (0, prompt_1.confirm)({
|
|
629
|
+
message: `The directory ${exportAbsPath} is not empty. Existing files in this directory will be overwritten. Do you want to continue?`,
|
|
630
|
+
nonInteractive: options.nonInteractive,
|
|
631
|
+
force: options.force,
|
|
630
632
|
default: false,
|
|
631
633
|
});
|
|
632
634
|
if (!prompt) {
|
|
@@ -387,7 +387,7 @@ async function getConfig(dir) {
|
|
|
387
387
|
if ((0, semver_1.gte)(version, "12.0.0")) {
|
|
388
388
|
const { default: loadConfig } = (0, utils_1.relativeRequire)(dir, "next/dist/server/config");
|
|
389
389
|
const { PHASE_PRODUCTION_BUILD } = (0, utils_1.relativeRequire)(dir, "next/constants");
|
|
390
|
-
config = await loadConfig(PHASE_PRODUCTION_BUILD, dir
|
|
390
|
+
config = await loadConfig(PHASE_PRODUCTION_BUILD, dir);
|
|
391
391
|
}
|
|
392
392
|
else {
|
|
393
393
|
try {
|
package/lib/frameworks/utils.js
CHANGED
|
@@ -13,7 +13,8 @@ const fsutils_1 = require("../fsutils");
|
|
|
13
13
|
const url_1 = require("url");
|
|
14
14
|
const constants_1 = require("./constants");
|
|
15
15
|
const { dynamicImport } = require(true && "../dynamicImport");
|
|
16
|
-
const NPM_ROOT_TIMEOUT_MILLIES =
|
|
16
|
+
const NPM_ROOT_TIMEOUT_MILLIES = 5000;
|
|
17
|
+
const NPM_ROOT_MEMO = new Map();
|
|
17
18
|
function isUrl(url) {
|
|
18
19
|
return /^https?:\/\//.test(url);
|
|
19
20
|
}
|
|
@@ -139,8 +140,16 @@ function scanDependencyTree(searchingFor, dependencies = {}) {
|
|
|
139
140
|
}
|
|
140
141
|
function getNpmRoot(cwd) {
|
|
141
142
|
var _a;
|
|
142
|
-
|
|
143
|
+
let npmRoot = NPM_ROOT_MEMO.get(cwd);
|
|
144
|
+
if (npmRoot)
|
|
145
|
+
return npmRoot;
|
|
146
|
+
npmRoot = (_a = (0, cross_spawn_1.sync)("npm", ["root"], {
|
|
147
|
+
cwd,
|
|
148
|
+
timeout: NPM_ROOT_TIMEOUT_MILLIES,
|
|
149
|
+
})
|
|
143
150
|
.stdout) === null || _a === void 0 ? void 0 : _a.toString().trim();
|
|
151
|
+
NPM_ROOT_MEMO.set(cwd, npmRoot);
|
|
152
|
+
return npmRoot;
|
|
144
153
|
}
|
|
145
154
|
exports.getNpmRoot = getNpmRoot;
|
|
146
155
|
function getNodeModuleBin(name, cwd) {
|
|
@@ -91,6 +91,7 @@ async function createFunction(cloudFunction) {
|
|
|
91
91
|
const components = cloudFunction.name.split("/");
|
|
92
92
|
const functionId = components.splice(-1, 1)[0];
|
|
93
93
|
cloudFunction.buildConfig.environmentVariables = Object.assign(Object.assign({}, cloudFunction.buildConfig.environmentVariables), { GOOGLE_NODE_RUN_SCRIPTS: "" });
|
|
94
|
+
cloudFunction.serviceConfig.environmentVariables = Object.assign(Object.assign({}, cloudFunction.serviceConfig.environmentVariables), { FUNCTION_TARGET: functionId });
|
|
94
95
|
try {
|
|
95
96
|
const res = await client.post(components.join("/"), cloudFunction, { queryParams: { functionId } });
|
|
96
97
|
return res.body;
|
|
@@ -143,9 +144,12 @@ async function listFunctionsInternal(projectId, region) {
|
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
async function updateFunction(cloudFunction) {
|
|
147
|
+
const components = cloudFunction.name.split("/");
|
|
148
|
+
const functionId = components.splice(-1, 1)[0];
|
|
146
149
|
const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "serviceConfig.environmentVariables", "serviceConfig.secretEnvironmentVariables");
|
|
147
150
|
cloudFunction.buildConfig.environmentVariables = Object.assign(Object.assign({}, cloudFunction.buildConfig.environmentVariables), { GOOGLE_NODE_RUN_SCRIPTS: "" });
|
|
148
151
|
fieldMasks.push("buildConfig.buildEnvironmentVariables");
|
|
152
|
+
cloudFunction.serviceConfig.environmentVariables = Object.assign(Object.assign({}, cloudFunction.serviceConfig.environmentVariables), { FUNCTION_TARGET: functionId });
|
|
149
153
|
try {
|
|
150
154
|
const queryParams = {
|
|
151
155
|
updateMask: fieldMasks.join(","),
|
|
@@ -211,6 +215,7 @@ function functionFromEndpoint(endpoint) {
|
|
|
211
215
|
if (backend.isEventTriggered(endpoint)) {
|
|
212
216
|
gcfFunction.eventTrigger = {
|
|
213
217
|
eventType: endpoint.eventTrigger.eventType,
|
|
218
|
+
retryPolicy: "RETRY_POLICY_UNSPECIFIED",
|
|
214
219
|
};
|
|
215
220
|
if (gcfFunction.eventTrigger.eventType === v2_1.PUBSUB_PUBLISH_EVENT) {
|
|
216
221
|
if (!((_b = endpoint.eventTrigger.eventFilters) === null || _b === void 0 ? void 0 : _b.topic)) {
|
|
@@ -240,9 +245,9 @@ function functionFromEndpoint(endpoint) {
|
|
|
240
245
|
}
|
|
241
246
|
proto.renameIfPresent(gcfFunction.eventTrigger, endpoint.eventTrigger, "triggerRegion", "region");
|
|
242
247
|
proto.copyIfPresent(gcfFunction.eventTrigger, endpoint.eventTrigger, "channel");
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
248
|
+
endpoint.eventTrigger.retry
|
|
249
|
+
? (gcfFunction.eventTrigger.retryPolicy = "RETRY_POLICY_RETRY")
|
|
250
|
+
: (gcfFunction.eventTrigger.retryPolicy = "RETRY_POLICY_DO_NOT_RETRY");
|
|
246
251
|
gcfFunction.serviceConfig.environmentVariables = Object.assign(Object.assign({}, gcfFunction.serviceConfig.environmentVariables), { FUNCTION_SIGNATURE_TYPE: "cloudevent" });
|
|
247
252
|
}
|
|
248
253
|
else if (backend.isScheduleTriggered(endpoint)) {
|
|
@@ -315,7 +320,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
315
320
|
trigger = {
|
|
316
321
|
eventTrigger: {
|
|
317
322
|
eventType: gcfFunction.eventTrigger.eventType,
|
|
318
|
-
retry: false,
|
|
323
|
+
retry: gcfFunction.eventTrigger.retryPolicy === "RETRY_POLICY_RETRY" ? true : false,
|
|
319
324
|
},
|
|
320
325
|
};
|
|
321
326
|
if (Object.keys(eventFilters).length) {
|
package/package.json
CHANGED