firebase-tools 10.7.0 → 10.8.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 +26 -15
- package/lib/commands/ext-export.js +14 -5
- package/lib/commands/ext-install.js +31 -2
- package/lib/commands/ext-update.js +17 -10
- package/lib/commands/functions-delete.js +9 -2
- package/lib/commands/functions-secrets-set.js +1 -13
- package/lib/deploy/extensions/planner.js +12 -0
- package/lib/deploy/extensions/tasks.js +13 -0
- package/lib/deploy/functions/backend.js +67 -10
- package/lib/deploy/functions/build.js +28 -9
- package/lib/deploy/functions/checkIam.js +71 -56
- package/lib/deploy/functions/containerCleaner.js +8 -7
- package/lib/deploy/functions/deploy.js +49 -27
- package/lib/deploy/functions/functionsDeployHelper.js +48 -4
- package/lib/deploy/functions/prepare.js +125 -74
- package/lib/deploy/functions/pricing.js +2 -2
- package/lib/deploy/functions/release/executor.js +1 -1
- package/lib/deploy/functions/release/fabricator.js +94 -36
- package/lib/deploy/functions/release/index.js +16 -27
- package/lib/deploy/functions/release/planner.js +12 -7
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +13 -1
- package/lib/deploy/functions/runtimes/golang/index.js +3 -0
- package/lib/deploy/functions/runtimes/node/index.js +7 -0
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +108 -1
- package/lib/deploy/functions/services/storage.js +6 -12
- package/lib/deploy/functions/validate.js +58 -8
- package/lib/deploy/hosting/convertConfig.js +6 -4
- package/lib/emulator/auth/cloudFunctions.js +6 -2
- package/lib/emulator/auth/operations.js +0 -1
- package/lib/emulator/auth/server.js +8 -1
- package/lib/emulator/auth/state.js +27 -24
- package/lib/emulator/controller.js +12 -9
- package/lib/emulator/databaseEmulator.js +36 -3
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/extensionsEmulator.js +3 -0
- package/lib/emulator/functionsEmulator.js +11 -9
- package/lib/emulator/functionsEmulatorRuntime.js +1 -1
- package/lib/emulator/functionsEmulatorShared.js +5 -1
- package/lib/emulator/functionsEmulatorShell.js +2 -3
- package/lib/emulator/functionsEmulatorUtils.js +5 -1
- package/lib/emulator/pubsubEmulator.js +13 -9
- package/lib/emulator/storage/apis/firebase.js +26 -4
- package/lib/ensureApiEnabled.js +1 -1
- package/lib/extensions/askUserForEventsConfig.js +97 -0
- package/lib/extensions/export.js +7 -0
- package/lib/extensions/extensionsApi.js +47 -7
- package/lib/extensions/manifest.js +1 -1
- package/lib/extensions/paramHelper.js +2 -0
- package/lib/extensions/updateHelper.js +7 -1
- package/lib/extensions/warnings.js +11 -4
- package/lib/functions/projectConfig.js +13 -8
- package/lib/functionsShellCommandAction.js +1 -1
- package/lib/gcp/cloudfunctions.js +9 -2
- package/lib/gcp/cloudfunctionsv2.js +28 -10
- package/lib/gcp/serviceusage.js +24 -0
- package/lib/previews.js +1 -1
- package/lib/serve/functions.js +16 -19
- package/lib/throttler/throttler.js +2 -1
- package/npm-shrinkwrap.json +214 -527
- package/package.json +3 -3
- package/templates/extensions/typescript/package.lint.json +2 -1
- package/templates/extensions/typescript/package.nolint.json +2 -1
- package/templates/init/functions/typescript/package.lint.json +1 -0
- package/templates/init/functions/typescript/package.nolint.json +1 -0
|
@@ -19,6 +19,7 @@ const refs = require("../extensions/refs");
|
|
|
19
19
|
const manifest = require("../extensions/manifest");
|
|
20
20
|
const functional_1 = require("../functional");
|
|
21
21
|
const paramHelper_1 = require("../extensions/paramHelper");
|
|
22
|
+
const askUserForEventsConfig = require("../extensions/askUserForEventsConfig");
|
|
22
23
|
marked.setOptions({
|
|
23
24
|
renderer: new TerminalRenderer(),
|
|
24
25
|
});
|
|
@@ -67,6 +68,15 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
67
68
|
instanceId,
|
|
68
69
|
reconfiguring: true,
|
|
69
70
|
});
|
|
71
|
+
const eventsConfig = spec.events
|
|
72
|
+
? await askUserForEventsConfig.askForEventsConfig(spec.events, "${param:PROJECT_ID}", instanceId)
|
|
73
|
+
: undefined;
|
|
74
|
+
if (eventsConfig) {
|
|
75
|
+
mutableParamsBindingOptions.EVENTARC_CHANNEL = { baseValue: eventsConfig.channel };
|
|
76
|
+
mutableParamsBindingOptions.ALLOWED_EVENT_TYPES = {
|
|
77
|
+
baseValue: eventsConfig.allowedEventTypes.join(","),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
70
80
|
const newParamOptions = Object.assign(Object.assign({}, (0, paramHelper_1.buildBindingOptionsWithBaseValue)(oldParamValues)), mutableParamsBindingOptions);
|
|
71
81
|
await manifest.writeToManifest([
|
|
72
82
|
{
|
|
@@ -83,20 +93,12 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
83
93
|
manifest.showPreviewWarning();
|
|
84
94
|
return;
|
|
85
95
|
}
|
|
96
|
+
if (!projectId) {
|
|
97
|
+
throw new error_1.FirebaseError(`Project ID must be provided when re-configuring an instance outside of local mode.`);
|
|
98
|
+
}
|
|
86
99
|
const spinner = ora(`Configuring ${clc.bold(instanceId)}. This usually takes 3 to 5 minutes...`);
|
|
87
100
|
try {
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
existingInstance = await extensionsApi.getInstance((0, projectUtils_1.needProjectId)({ projectId }), instanceId);
|
|
91
|
-
}
|
|
92
|
-
catch (err) {
|
|
93
|
-
if (err.status === 404) {
|
|
94
|
-
return utils.reject(`No extension instance ${instanceId} found in project ${projectId}.`, {
|
|
95
|
-
exit: 1,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
throw err;
|
|
99
|
-
}
|
|
101
|
+
const existingInstance = await extensionsApi.getInstance((0, projectUtils_1.needProjectId)({ projectId }), instanceId);
|
|
100
102
|
const paramSpecWithNewDefaults = paramHelper.getParamsWithCurrentValuesAsDefaults(existingInstance);
|
|
101
103
|
const immutableParams = _.remove(paramSpecWithNewDefaults, (param) => param.immutable);
|
|
102
104
|
const paramBindingOptions = await paramHelper.getParams({
|
|
@@ -121,12 +123,21 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
121
123
|
: "To set a different value for this param") +
|
|
122
124
|
", uninstall the extension, then install a new instance of this extension.");
|
|
123
125
|
}
|
|
126
|
+
const pId = (0, projectUtils_1.needProjectId)({ projectId });
|
|
127
|
+
const spec = existingInstance ? existingInstance.config.source.spec : undefined;
|
|
128
|
+
const eventsConfig = spec.events
|
|
129
|
+
? await askUserForEventsConfig.askForEventsConfig(spec.events, pId, instanceId)
|
|
130
|
+
: undefined;
|
|
124
131
|
spinner.start();
|
|
125
|
-
const
|
|
126
|
-
projectId:
|
|
132
|
+
const configureOptions = {
|
|
133
|
+
projectId: pId,
|
|
127
134
|
instanceId,
|
|
128
135
|
params: paramBindings,
|
|
129
|
-
|
|
136
|
+
canEmitEvents: eventsConfig ? true : false,
|
|
137
|
+
eventarcChannel: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.channel,
|
|
138
|
+
allowedEventTypes: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.allowedEventTypes,
|
|
139
|
+
};
|
|
140
|
+
const res = await extensionsApi.configureInstance(configureOptions);
|
|
130
141
|
spinner.stop();
|
|
131
142
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully configured ${clc.bold(instanceId)}.`);
|
|
132
143
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your reconfigured instance in the Firebase console: ${utils.consoleUrl((0, projectUtils_1.needProjectId)({ projectId }), `/extensions/instances/${instanceId}?tab=config`)}`));
|
|
@@ -43,11 +43,20 @@ module.exports = new command_1.Command("ext:export")
|
|
|
43
43
|
logger_1.logger.info("Exiting. No changes made.");
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
-
const manifestSpecs =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
const manifestSpecs = withRefSubbed.map((spec) => {
|
|
47
|
+
const paramCopy = Object.assign({}, spec.params);
|
|
48
|
+
if (spec.eventarcChannel) {
|
|
49
|
+
paramCopy.EVENTARC_CHANNEL = spec.eventarcChannel;
|
|
50
|
+
}
|
|
51
|
+
if (spec.allowedEventTypes) {
|
|
52
|
+
paramCopy.ALLOWED_EVENT_TYPES = spec.allowedEventTypes.join(",");
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
instanceId: spec.instanceId,
|
|
56
|
+
ref: spec.ref,
|
|
57
|
+
params: (0, paramHelper_1.buildBindingOptionsWithBaseValue)(paramCopy),
|
|
58
|
+
};
|
|
59
|
+
});
|
|
51
60
|
const existingConfig = manifest.loadConfig(options);
|
|
52
61
|
await manifest.writeToManifest(manifestSpecs, existingConfig, {
|
|
53
62
|
nonInteractive: options.nonInteractive,
|
|
@@ -6,6 +6,7 @@ const ora = require("ora");
|
|
|
6
6
|
const TerminalRenderer = require("marked-terminal");
|
|
7
7
|
const askUserForConsent = require("../extensions/askUserForConsent");
|
|
8
8
|
const displayExtensionInfo_1 = require("../extensions/displayExtensionInfo");
|
|
9
|
+
const askUserForEventsConfig = require("../extensions/askUserForEventsConfig");
|
|
9
10
|
const billingMigrationHelper_1 = require("../extensions/billingMigrationHelper");
|
|
10
11
|
const checkProjectBilling_1 = require("../extensions/checkProjectBilling");
|
|
11
12
|
const cloudbilling_1 = require("../gcp/cloudbilling");
|
|
@@ -166,6 +167,15 @@ async function installToManifest(options) {
|
|
|
166
167
|
paramsEnvPath,
|
|
167
168
|
instanceId,
|
|
168
169
|
});
|
|
170
|
+
const eventsConfig = spec.events
|
|
171
|
+
? await askUserForEventsConfig.askForEventsConfig(spec.events, "${param:PROJECT_ID}", instanceId)
|
|
172
|
+
: undefined;
|
|
173
|
+
if (eventsConfig) {
|
|
174
|
+
paramBindingOptions.EVENTARC_CHANNEL = { baseValue: eventsConfig.channel };
|
|
175
|
+
paramBindingOptions.ALLOWED_EVENT_TYPES = {
|
|
176
|
+
baseValue: eventsConfig.allowedEventTypes.join(","),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
169
179
|
const ref = extVersion ? refs.parse(extVersion.ref) : undefined;
|
|
170
180
|
await manifest.writeToManifest([
|
|
171
181
|
{
|
|
@@ -210,6 +220,12 @@ async function installExtension(options) {
|
|
|
210
220
|
reason: `To access and manage secrets which are used by this extension. By using this product you agree to the terms and conditions of the following license: https://console.cloud.google.com/tos?id=cloud&project=${projectId}`,
|
|
211
221
|
});
|
|
212
222
|
}
|
|
223
|
+
if (spec.events && spec.events.length > 0) {
|
|
224
|
+
apis.push({
|
|
225
|
+
apiName: "eventarc.googleapis.com",
|
|
226
|
+
reason: `When events are enabled, the Eventarc API is required to provision an event channel and publish events.`,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
213
229
|
if (apis.length) {
|
|
214
230
|
askUserForConsent.displayApis(spec.displayName || spec.name, projectId, apis);
|
|
215
231
|
const consented = await (0, extensionsHelper_1.confirm)({ nonInteractive, force, default: true });
|
|
@@ -248,6 +264,7 @@ async function installExtension(options) {
|
|
|
248
264
|
}
|
|
249
265
|
let paramBindingOptions;
|
|
250
266
|
let paramBindings;
|
|
267
|
+
let eventsConfig;
|
|
251
268
|
switch (choice) {
|
|
252
269
|
case "installNew":
|
|
253
270
|
instanceId = await (0, extensionsHelper_1.promptForValidInstanceId)(`${instanceId}-${(0, utils_1.getRandomString)(4)}`);
|
|
@@ -258,6 +275,9 @@ async function installExtension(options) {
|
|
|
258
275
|
paramsEnvPath,
|
|
259
276
|
instanceId,
|
|
260
277
|
});
|
|
278
|
+
eventsConfig = spec.events
|
|
279
|
+
? await askUserForEventsConfig.askForEventsConfig(spec.events, projectId, instanceId)
|
|
280
|
+
: undefined;
|
|
261
281
|
paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
|
|
262
282
|
spinner.text = "Installing your extension instance. This usually takes 3 to 5 minutes...";
|
|
263
283
|
spinner.start();
|
|
@@ -267,6 +287,8 @@ async function installExtension(options) {
|
|
|
267
287
|
extensionSource: source,
|
|
268
288
|
extensionVersionRef: extVersion === null || extVersion === void 0 ? void 0 : extVersion.ref,
|
|
269
289
|
params: paramBindings,
|
|
290
|
+
allowedEventTypes: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.allowedEventTypes,
|
|
291
|
+
eventarcChannel: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.channel,
|
|
270
292
|
});
|
|
271
293
|
spinner.stop();
|
|
272
294
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Successfully installed your instance of ${clc.bold(spec.displayName || spec.name)}! ` +
|
|
@@ -280,16 +302,23 @@ async function installExtension(options) {
|
|
|
280
302
|
paramsEnvPath,
|
|
281
303
|
instanceId,
|
|
282
304
|
});
|
|
305
|
+
eventsConfig = spec.events
|
|
306
|
+
? await askUserForEventsConfig.askForEventsConfig(spec.events, projectId, instanceId)
|
|
307
|
+
: undefined;
|
|
283
308
|
paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
|
|
284
309
|
spinner.text = "Updating your extension instance. This usually takes 3 to 5 minutes...";
|
|
285
310
|
spinner.start();
|
|
286
|
-
|
|
311
|
+
const updateOptions = {
|
|
287
312
|
projectId,
|
|
288
313
|
instanceId,
|
|
289
314
|
source,
|
|
315
|
+
canEmitEvents: eventsConfig ? true : false,
|
|
316
|
+
eventarcChannel: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.channel,
|
|
317
|
+
allowedEventTypes: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.allowedEventTypes,
|
|
290
318
|
extRef: extVersion === null || extVersion === void 0 ? void 0 : extVersion.ref,
|
|
291
319
|
params: paramBindings,
|
|
292
|
-
}
|
|
320
|
+
};
|
|
321
|
+
await (0, updateHelper_1.update)(updateOptions);
|
|
293
322
|
spinner.stop();
|
|
294
323
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Successfully updated your instance of ${clc.bold(spec.displayName || spec.name)}! ` +
|
|
295
324
|
`Its Instance ID is ${clc.bold(instanceId)}.`);
|
|
@@ -23,6 +23,7 @@ const requirePermissions_1 = require("../requirePermissions");
|
|
|
23
23
|
const utils = require("../utils");
|
|
24
24
|
const previews_1 = require("../previews");
|
|
25
25
|
const manifest = require("../extensions/manifest");
|
|
26
|
+
const askUserForEventsConfig = require("../extensions/askUserForEventsConfig");
|
|
26
27
|
marked.setOptions({
|
|
27
28
|
renderer: new TerminalRenderer(),
|
|
28
29
|
});
|
|
@@ -86,6 +87,15 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
|
|
|
86
87
|
nonInteractive: options.nonInteractive,
|
|
87
88
|
instanceId,
|
|
88
89
|
});
|
|
90
|
+
const eventsConfig = newExtensionVersion.spec.events
|
|
91
|
+
? await askUserForEventsConfig.askForEventsConfig(newExtensionVersion.spec.events, "${param:PROJECT_ID}", instanceId)
|
|
92
|
+
: undefined;
|
|
93
|
+
if (eventsConfig) {
|
|
94
|
+
newParamBindingOptions.EVENTARC_CHANNEL = { baseValue: eventsConfig.channel };
|
|
95
|
+
newParamBindingOptions.ALLOWED_EVENT_TYPES = {
|
|
96
|
+
baseValue: eventsConfig.allowedEventTypes.join(","),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
89
99
|
await manifest.writeToManifest([
|
|
90
100
|
{
|
|
91
101
|
instanceId,
|
|
@@ -104,16 +114,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
|
|
|
104
114
|
const spinner = ora(`Updating ${clc.bold(instanceId)}. This usually takes 3 to 5 minutes...`);
|
|
105
115
|
try {
|
|
106
116
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
existingInstance = await extensionsApi.getInstance(projectId, instanceId);
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
if (err.status === 404) {
|
|
113
|
-
throw new error_1.FirebaseError(`Extension instance '${clc.bold(instanceId)}' not found in project '${clc.bold(projectId)}'.`);
|
|
114
|
-
}
|
|
115
|
-
throw err;
|
|
116
|
-
}
|
|
117
|
+
const existingInstance = await extensionsApi.getInstance(projectId, instanceId);
|
|
117
118
|
const existingSpec = existingInstance.config.source.spec;
|
|
118
119
|
if (existingInstance.config.source.state === "DELETED") {
|
|
119
120
|
throw new error_1.FirebaseError(`Instance '${clc.bold(instanceId)}' cannot be updated anymore because the underlying extension was unpublished from Firebase's registry of extensions. Going forward, you will only be able to re-configure or uninstall this instance.`);
|
|
@@ -214,11 +215,17 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
|
|
|
214
215
|
nonInteractive: options.nonInteractive,
|
|
215
216
|
instanceId,
|
|
216
217
|
});
|
|
218
|
+
const eventsConfig = newSpec.events
|
|
219
|
+
? await askUserForEventsConfig.askForEventsConfig(newSpec.events, projectId, instanceId)
|
|
220
|
+
: undefined;
|
|
217
221
|
const newParams = paramHelper.getBaseParamBindings(newParamBindings);
|
|
218
222
|
spinner.start();
|
|
219
223
|
const updateOptions = {
|
|
220
224
|
projectId,
|
|
221
225
|
instanceId,
|
|
226
|
+
canEmitEvents: eventsConfig ? true : false,
|
|
227
|
+
eventarcChannel: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.channel,
|
|
228
|
+
allowedEventTypes: eventsConfig === null || eventsConfig === void 0 ? void 0 : eventsConfig.allowedEventTypes,
|
|
222
229
|
};
|
|
223
230
|
if (newSourceName.includes("publisher")) {
|
|
224
231
|
updateOptions.extRef = refs.toExtensionVersionRef(refs.parse(newSourceName));
|
|
@@ -40,7 +40,13 @@ exports.default = new command_1.Command("functions:delete [filters...]")
|
|
|
40
40
|
if (options.region) {
|
|
41
41
|
existingBackend.endpoints = { [options.region]: existingBackend.endpoints[options.region] };
|
|
42
42
|
}
|
|
43
|
-
const plan = planner.createDeploymentPlan(
|
|
43
|
+
const plan = planner.createDeploymentPlan({
|
|
44
|
+
wantBackend: backend.empty(),
|
|
45
|
+
haveBackend: existingBackend,
|
|
46
|
+
codebase: "",
|
|
47
|
+
filters: context.filters,
|
|
48
|
+
deleteAll: true,
|
|
49
|
+
});
|
|
44
50
|
const allEpToDelete = Object.values(plan)
|
|
45
51
|
.map((changes) => changes.endpointsToDelete)
|
|
46
52
|
.reduce(functional_1.reduceFlat, [])
|
|
@@ -69,8 +75,9 @@ exports.default = new command_1.Command("functions:delete [filters...]")
|
|
|
69
75
|
try {
|
|
70
76
|
const fab = new fabricator.Fabricator({
|
|
71
77
|
functionExecutor,
|
|
72
|
-
executor: new executor.QueueExecutor({}),
|
|
73
78
|
appEngineLocation,
|
|
79
|
+
executor: new executor.QueueExecutor({}),
|
|
80
|
+
sources: {},
|
|
74
81
|
});
|
|
75
82
|
const summary = await fab.applyPlan(plan);
|
|
76
83
|
await reporter.logAndTrackDeployStats(summary);
|
|
@@ -77,17 +77,5 @@ exports.default = new command_1.Command("functions:secrets:set <KEY>")
|
|
|
77
77
|
(0, utils_1.logBullet)(`Updated function ${e.id}(${e.region}).`);
|
|
78
78
|
return updated;
|
|
79
79
|
});
|
|
80
|
-
|
|
81
|
-
(0, utils_1.logBullet)(`Pruning stale secrets...`);
|
|
82
|
-
const prunedResult = await (0, secrets_1.pruneAndDestroySecrets)({ projectId, projectNumber }, updatedEndpoints);
|
|
83
|
-
if (prunedResult.destroyed.length > 0) {
|
|
84
|
-
(0, utils_1.logBullet)(`Detroyed unused secret versions: ${prunedResult.destroyed
|
|
85
|
-
.map((s) => `${s.secret}@${s.version}`)
|
|
86
|
-
.join(", ")}`);
|
|
87
|
-
}
|
|
88
|
-
if (prunedResult.erred.length > 0) {
|
|
89
|
-
(0, utils_1.logWarning)(`Failed to destroy unused secret versions:\n\t${prunedResult.erred
|
|
90
|
-
.map((err) => err.message)
|
|
91
|
-
.join("\n\t")}`);
|
|
92
|
-
}
|
|
80
|
+
await Promise.all(updateOps);
|
|
93
81
|
});
|
|
@@ -52,6 +52,8 @@ async function have(projectId) {
|
|
|
52
52
|
const dep = {
|
|
53
53
|
instanceId: i.name.split("/").pop(),
|
|
54
54
|
params: i.config.params,
|
|
55
|
+
allowedEventTypes: i.config.allowedEventTypes,
|
|
56
|
+
eventarcChannel: i.config.eventarcChannel,
|
|
55
57
|
};
|
|
56
58
|
if (i.config.extensionRef) {
|
|
57
59
|
const ref = refs.parse(i.config.extensionRef);
|
|
@@ -78,11 +80,19 @@ async function want(args) {
|
|
|
78
80
|
});
|
|
79
81
|
const autoPopulatedParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId, args.emulatorMode);
|
|
80
82
|
const subbedParams = (0, extensionsHelper_1.substituteParams)(params, autoPopulatedParams);
|
|
83
|
+
const allowedEventTypes = subbedParams.ALLOWED_EVENT_TYPES !== undefined
|
|
84
|
+
? subbedParams.ALLOWED_EVENT_TYPES.split(",").filter((e) => e !== "")
|
|
85
|
+
: undefined;
|
|
86
|
+
const eventarcChannel = subbedParams.EVENTARC_CHANNEL;
|
|
87
|
+
delete subbedParams["EVENTARC_CHANNEL"];
|
|
88
|
+
delete subbedParams["ALLOWED_EVENT_TYPES"];
|
|
81
89
|
if ((0, extensionsHelper_1.isLocalPath)(e[1])) {
|
|
82
90
|
instanceSpecs.push({
|
|
83
91
|
instanceId,
|
|
84
92
|
localPath: e[1],
|
|
85
93
|
params: subbedParams,
|
|
94
|
+
allowedEventTypes: allowedEventTypes,
|
|
95
|
+
eventarcChannel: eventarcChannel,
|
|
86
96
|
});
|
|
87
97
|
}
|
|
88
98
|
else {
|
|
@@ -92,6 +102,8 @@ async function want(args) {
|
|
|
92
102
|
instanceId,
|
|
93
103
|
ref,
|
|
94
104
|
params: subbedParams,
|
|
105
|
+
allowedEventTypes: allowedEventTypes,
|
|
106
|
+
eventarcChannel: eventarcChannel,
|
|
95
107
|
});
|
|
96
108
|
}
|
|
97
109
|
}
|
|
@@ -33,6 +33,8 @@ function createExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
|
|
|
33
33
|
instanceId: instanceSpec.instanceId,
|
|
34
34
|
params: instanceSpec.params,
|
|
35
35
|
extensionVersionRef: refs.toExtensionVersionRef(instanceSpec.ref),
|
|
36
|
+
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
37
|
+
eventarcChannel: instanceSpec.eventarcChannel,
|
|
36
38
|
validateOnly,
|
|
37
39
|
});
|
|
38
40
|
}
|
|
@@ -43,6 +45,8 @@ function createExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
|
|
|
43
45
|
instanceId: instanceSpec.instanceId,
|
|
44
46
|
params: instanceSpec.params,
|
|
45
47
|
extensionSource,
|
|
48
|
+
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
49
|
+
eventarcChannel: instanceSpec.eventarcChannel,
|
|
46
50
|
validateOnly,
|
|
47
51
|
});
|
|
48
52
|
}
|
|
@@ -67,6 +71,9 @@ function updateExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
|
|
|
67
71
|
instanceId: instanceSpec.instanceId,
|
|
68
72
|
extRef: refs.toExtensionVersionRef(instanceSpec.ref),
|
|
69
73
|
params: instanceSpec.params,
|
|
74
|
+
canEmitEvents: !!instanceSpec.allowedEventTypes,
|
|
75
|
+
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
76
|
+
eventarcChannel: instanceSpec.eventarcChannel,
|
|
70
77
|
validateOnly,
|
|
71
78
|
});
|
|
72
79
|
}
|
|
@@ -77,6 +84,9 @@ function updateExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
|
|
|
77
84
|
instanceId: instanceSpec.instanceId,
|
|
78
85
|
extensionSource,
|
|
79
86
|
validateOnly,
|
|
87
|
+
canEmitEvents: !!instanceSpec.allowedEventTypes,
|
|
88
|
+
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
89
|
+
eventarcChannel: instanceSpec.eventarcChannel,
|
|
80
90
|
});
|
|
81
91
|
}
|
|
82
92
|
else {
|
|
@@ -99,6 +109,9 @@ function configureExtensionInstanceTask(projectId, instanceSpec, validateOnly =
|
|
|
99
109
|
projectId,
|
|
100
110
|
instanceId: instanceSpec.instanceId,
|
|
101
111
|
params: instanceSpec.params,
|
|
112
|
+
canEmitEvents: !!instanceSpec.allowedEventTypes,
|
|
113
|
+
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
114
|
+
eventarcChannel: instanceSpec.eventarcChannel,
|
|
102
115
|
validateOnly,
|
|
103
116
|
});
|
|
104
117
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.compareFunctions = exports.missingEndpoint = exports.hasEndpoint = exports.regionalEndpoints = exports.matchingBackend = exports.findEndpoint = exports.someEndpoint = exports.allEndpoints = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.functionName = exports.isEmptyBackend = exports.of = exports.empty = exports.isBlockingTriggered = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isCallableTriggered = exports.isHttpsTriggered = exports.AllFunctionsPlatforms = exports.secretVersionName = exports.SCHEDULED_FUNCTION_LABEL = exports.
|
|
3
|
+
exports.compareFunctions = exports.missingEndpoint = exports.hasEndpoint = exports.regionalEndpoints = exports.matchingBackend = exports.findEndpoint = exports.someEndpoint = exports.allEndpoints = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.functionName = exports.isEmptyBackend = exports.merge = exports.of = exports.empty = exports.isBlockingTriggered = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isCallableTriggered = exports.isHttpsTriggered = exports.AllFunctionsPlatforms = exports.secretVersionName = exports.SCHEDULED_FUNCTION_LABEL = exports.MIN_CPU_FOR_CONCURRENCY = exports.DEFAULT_MEMORY = exports.DEFAULT_CONCURRENCY = exports.memoryToGen2Cpu = exports.memoryToGen1Cpu = exports.memoryOptionDisplayName = exports.AllMemoryOptions = exports.AllIngressSettings = exports.AllVpcEgressSettings = exports.endpointTriggerType = void 0;
|
|
4
4
|
const gcf = require("../../gcp/cloudfunctions");
|
|
5
5
|
const gcfV2 = require("../../gcp/cloudfunctionsv2");
|
|
6
|
+
const run = require("../../gcp/run");
|
|
6
7
|
const utils = require("../../utils");
|
|
7
8
|
const error_1 = require("../../error");
|
|
8
9
|
const previews_1 = require("../../previews");
|
|
10
|
+
const functional_1 = require("../../functional");
|
|
9
11
|
function endpointTriggerType(endpoint) {
|
|
10
12
|
if (isScheduleTriggered(endpoint)) {
|
|
11
13
|
return "scheduled";
|
|
@@ -36,7 +38,9 @@ exports.AllIngressSettings = [
|
|
|
36
38
|
"ALLOW_INTERNAL_ONLY",
|
|
37
39
|
"ALLOW_INTERNAL_AND_GCLB",
|
|
38
40
|
];
|
|
39
|
-
exports.AllMemoryOptions = [
|
|
41
|
+
exports.AllMemoryOptions = [
|
|
42
|
+
128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
|
|
43
|
+
];
|
|
40
44
|
function memoryOptionDisplayName(option) {
|
|
41
45
|
return {
|
|
42
46
|
128: "128MB",
|
|
@@ -46,11 +50,42 @@ function memoryOptionDisplayName(option) {
|
|
|
46
50
|
2048: "2GB",
|
|
47
51
|
4096: "4GB",
|
|
48
52
|
8192: "8GB",
|
|
53
|
+
16384: "16GB",
|
|
54
|
+
32768: "32GB",
|
|
49
55
|
}[option];
|
|
50
56
|
}
|
|
51
57
|
exports.memoryOptionDisplayName = memoryOptionDisplayName;
|
|
58
|
+
function memoryToGen1Cpu(memory) {
|
|
59
|
+
return {
|
|
60
|
+
128: 0.0833,
|
|
61
|
+
256: 0.1666,
|
|
62
|
+
512: 0.3333,
|
|
63
|
+
1024: 0.5833,
|
|
64
|
+
2048: 1,
|
|
65
|
+
4096: 2,
|
|
66
|
+
8192: 2,
|
|
67
|
+
16384: 3,
|
|
68
|
+
32768: 4,
|
|
69
|
+
}[memory];
|
|
70
|
+
}
|
|
71
|
+
exports.memoryToGen1Cpu = memoryToGen1Cpu;
|
|
72
|
+
function memoryToGen2Cpu(memory) {
|
|
73
|
+
return {
|
|
74
|
+
128: 1,
|
|
75
|
+
256: 1,
|
|
76
|
+
512: 1,
|
|
77
|
+
1024: 1,
|
|
78
|
+
2048: 1,
|
|
79
|
+
4096: 2,
|
|
80
|
+
8192: 2,
|
|
81
|
+
16384: 3,
|
|
82
|
+
32768: 4,
|
|
83
|
+
}[memory];
|
|
84
|
+
}
|
|
85
|
+
exports.memoryToGen2Cpu = memoryToGen2Cpu;
|
|
86
|
+
exports.DEFAULT_CONCURRENCY = 80;
|
|
52
87
|
exports.DEFAULT_MEMORY = 256;
|
|
53
|
-
exports.
|
|
88
|
+
exports.MIN_CPU_FOR_CONCURRENCY = 1;
|
|
54
89
|
exports.SCHEDULED_FUNCTION_LABEL = Object.freeze({ deployment: "firebase-schedule" });
|
|
55
90
|
function secretVersionName(s) {
|
|
56
91
|
var _a;
|
|
@@ -102,6 +137,25 @@ function of(...endpoints) {
|
|
|
102
137
|
return bkend;
|
|
103
138
|
}
|
|
104
139
|
exports.of = of;
|
|
140
|
+
function merge(...backends) {
|
|
141
|
+
const merged = of(...(0, functional_1.flattenArray)(backends.map((b) => allEndpoints(b))));
|
|
142
|
+
const apiToReasons = {};
|
|
143
|
+
for (const b of backends) {
|
|
144
|
+
for (const { api, reason } of b.requiredAPIs) {
|
|
145
|
+
const reasons = apiToReasons[api] || new Set();
|
|
146
|
+
if (reason) {
|
|
147
|
+
reasons.add(reason);
|
|
148
|
+
}
|
|
149
|
+
apiToReasons[api] = reasons;
|
|
150
|
+
}
|
|
151
|
+
merged.environmentVariables = Object.assign(Object.assign({}, merged.environmentVariables), b.environmentVariables);
|
|
152
|
+
}
|
|
153
|
+
for (const [api, reasons] of Object.entries(apiToReasons)) {
|
|
154
|
+
merged.requiredAPIs.push({ api, reason: Array.from(reasons).join(" ") });
|
|
155
|
+
}
|
|
156
|
+
return merged;
|
|
157
|
+
}
|
|
158
|
+
exports.merge = merge;
|
|
105
159
|
function isEmptyBackend(backend) {
|
|
106
160
|
return (Object.keys(backend.requiredAPIs).length === 0 && Object.keys(backend.endpoints).length === 0);
|
|
107
161
|
}
|
|
@@ -144,6 +198,16 @@ async function loadExistingBackend(ctx) {
|
|
|
144
198
|
let gcfV2Results;
|
|
145
199
|
try {
|
|
146
200
|
gcfV2Results = await gcfV2.listAllFunctions(ctx.projectId);
|
|
201
|
+
const runResults = await Promise.all(gcfV2Results.functions.map((fn) => run.getService(fn.serviceConfig.service)));
|
|
202
|
+
for (const [apiFunction, runService] of (0, functional_1.zip)(gcfV2Results.functions, runResults)) {
|
|
203
|
+
const endpoint = gcfV2.endpointFromFunction(apiFunction);
|
|
204
|
+
endpoint.concurrency = runService.spec.template.spec.containerConcurrency || 1;
|
|
205
|
+
endpoint.cpu = +runService.spec.template.spec.containers[0].resources.limits.cpu;
|
|
206
|
+
ctx.existingBackend.endpoints[endpoint.region] =
|
|
207
|
+
ctx.existingBackend.endpoints[endpoint.region] || {};
|
|
208
|
+
ctx.existingBackend.endpoints[endpoint.region][endpoint.id] = endpoint;
|
|
209
|
+
}
|
|
210
|
+
ctx.unreachableRegions.gcfV2 = gcfV2Results.unreachable;
|
|
147
211
|
}
|
|
148
212
|
catch (err) {
|
|
149
213
|
if (err.status === 404 && ((_a = err.message) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes("method not found"))) {
|
|
@@ -151,13 +215,6 @@ async function loadExistingBackend(ctx) {
|
|
|
151
215
|
}
|
|
152
216
|
throw err;
|
|
153
217
|
}
|
|
154
|
-
for (const apiFunction of gcfV2Results.functions) {
|
|
155
|
-
const endpoint = gcfV2.endpointFromFunction(apiFunction);
|
|
156
|
-
ctx.existingBackend.endpoints[endpoint.region] =
|
|
157
|
-
ctx.existingBackend.endpoints[endpoint.region] || {};
|
|
158
|
-
ctx.existingBackend.endpoints[endpoint.region][endpoint.id] = endpoint;
|
|
159
|
-
}
|
|
160
|
-
ctx.unreachableRegions.gcfV2 = gcfV2Results.unreachable;
|
|
161
218
|
}
|
|
162
219
|
async function checkAvailability(context, want) {
|
|
163
220
|
const ctx = context;
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveBackend = void 0;
|
|
3
|
+
exports.resolveBackend = exports.of = exports.empty = void 0;
|
|
4
4
|
const backend = require("./backend");
|
|
5
5
|
const proto = require("../../gcp/proto");
|
|
6
6
|
const api = require("../../.../../api");
|
|
7
7
|
const error_1 = require("../../error");
|
|
8
8
|
const functional_1 = require("../../functional");
|
|
9
|
+
function empty() {
|
|
10
|
+
return {
|
|
11
|
+
requiredAPIs: [],
|
|
12
|
+
endpoints: {},
|
|
13
|
+
params: [],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
exports.empty = empty;
|
|
17
|
+
function of(endpoints) {
|
|
18
|
+
const build = empty();
|
|
19
|
+
build.endpoints = endpoints;
|
|
20
|
+
return build;
|
|
21
|
+
}
|
|
22
|
+
exports.of = of;
|
|
9
23
|
function resolveInt(from) {
|
|
10
24
|
if (from == null) {
|
|
11
25
|
return 0;
|
|
@@ -36,7 +50,15 @@ function resolveBoolean(from) {
|
|
|
36
50
|
function isMemoryOption(value) {
|
|
37
51
|
return value == null || [128, 256, 512, 1024, 2048, 4096, 8192].includes(value);
|
|
38
52
|
}
|
|
39
|
-
function resolveBackend(build) {
|
|
53
|
+
function resolveBackend(build, userEnvs) {
|
|
54
|
+
for (const param of build.params) {
|
|
55
|
+
const expectedEnv = param.param;
|
|
56
|
+
if (!userEnvs.hasOwnProperty(expectedEnv)) {
|
|
57
|
+
throw new error_1.FirebaseError("Build specified parameter " +
|
|
58
|
+
expectedEnv +
|
|
59
|
+
" but it was not present in the user dotenv files");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
40
62
|
const bkEndpoints = [];
|
|
41
63
|
for (const endpointId of Object.keys(build.endpoints)) {
|
|
42
64
|
const endpoint = build.endpoints[endpointId];
|
|
@@ -59,23 +81,20 @@ function resolveBackend(build) {
|
|
|
59
81
|
else {
|
|
60
82
|
timeout = 60;
|
|
61
83
|
}
|
|
62
|
-
const bkEndpoint = Object.assign({ id: endpointId, project:
|
|
84
|
+
const bkEndpoint = Object.assign({ id: endpointId, project: endpoint.project, region: region, entryPoint: endpoint.entryPoint, platform: endpoint.platform, runtime: endpoint.runtime, timeoutSeconds: timeout }, trigger);
|
|
63
85
|
proto.renameIfPresent(bkEndpoint, endpoint, "maxInstances", "maxInstances", resolveInt);
|
|
64
86
|
proto.renameIfPresent(bkEndpoint, endpoint, "minInstances", "minInstances", resolveInt);
|
|
65
87
|
proto.renameIfPresent(bkEndpoint, endpoint, "concurrency", "concurrency", resolveInt);
|
|
66
|
-
proto.copyIfPresent(bkEndpoint, endpoint, "ingressSettings");
|
|
88
|
+
proto.copyIfPresent(bkEndpoint, endpoint, "ingressSettings", "availableMemoryMb", "environmentVariables", "labels");
|
|
67
89
|
if (endpoint.vpc) {
|
|
68
90
|
bkEndpoint.vpc = {
|
|
69
|
-
connector: resolveString(endpoint.vpc.connector),
|
|
70
|
-
egressSettings: endpoint.vpc.egressSettings,
|
|
91
|
+
connector: resolveString(endpoint.vpc.connector).replace("$REGION", region),
|
|
71
92
|
};
|
|
93
|
+
proto.copyIfPresent(bkEndpoint.vpc, endpoint.vpc, "egressSettings");
|
|
72
94
|
}
|
|
73
95
|
if (endpoint.serviceAccount) {
|
|
74
96
|
bkEndpoint.serviceAccountEmail = endpoint.serviceAccount;
|
|
75
97
|
}
|
|
76
|
-
else {
|
|
77
|
-
bkEndpoint.serviceAccountEmail = "default";
|
|
78
|
-
}
|
|
79
98
|
bkEndpoints.push(bkEndpoint);
|
|
80
99
|
}
|
|
81
100
|
}
|