firebase-tools 9.21.0 → 9.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -3
- package/lib/api.js +2 -0
- package/lib/apiv2.js +3 -2
- package/lib/commands/crashlytics-symbols-upload.js +1 -1
- package/lib/commands/deploy.js +9 -1
- package/lib/commands/ext-configure.js +1 -1
- package/lib/commands/ext-dev-deprecate.js +63 -0
- package/lib/commands/ext-dev-undeprecate.js +56 -0
- package/lib/commands/ext-export.js +44 -0
- package/lib/commands/ext-install.js +1 -1
- package/lib/commands/ext-update.js +1 -1
- package/lib/commands/functions-delete.js +2 -0
- package/lib/commands/index.js +6 -5
- package/lib/commands/init.js +3 -0
- package/lib/config.js +3 -2
- package/lib/deploy/extensions/args.js +2 -0
- package/lib/deploy/extensions/deploy.js +49 -0
- package/lib/deploy/extensions/deploymentSummary.js +52 -0
- package/lib/deploy/extensions/errors.js +31 -0
- package/lib/deploy/extensions/index.js +8 -0
- package/lib/deploy/extensions/planner.js +95 -0
- package/lib/deploy/extensions/prepare.js +103 -0
- package/lib/deploy/extensions/release.js +43 -0
- package/lib/deploy/extensions/secrets.js +150 -0
- package/lib/deploy/extensions/tasks.js +98 -0
- package/lib/deploy/extensions/validate.js +17 -0
- package/lib/deploy/functions/backend.js +8 -1
- package/lib/deploy/functions/containerCleaner.js +77 -21
- package/lib/deploy/functions/release/fabricator.js +69 -9
- package/lib/deploy/functions/release/index.js +5 -1
- package/lib/deploy/functions/release/planner.js +3 -0
- package/lib/deploy/functions/release/reporter.js +4 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +28 -0
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +7 -2
- package/lib/deploy/index.js +1 -0
- package/lib/emulator/functionsEmulator.js +3 -1
- package/lib/extensions/askUserForParam.js +14 -6
- package/lib/extensions/checkProjectBilling.js +7 -7
- package/lib/extensions/export.js +107 -0
- package/lib/extensions/extensionsApi.js +103 -21
- package/lib/extensions/extensionsHelper.js +4 -1
- package/lib/extensions/listExtensions.js +16 -11
- package/lib/extensions/paramHelper.js +6 -4
- package/lib/extensions/provisioningHelper.js +16 -3
- package/lib/extensions/refs.js +9 -1
- package/lib/extensions/secretsUtils.js +10 -9
- package/lib/extensions/updateHelper.js +12 -2
- package/lib/extensions/versionHelper.js +14 -0
- package/lib/extensions/warnings.js +33 -1
- package/lib/gcp/artifactregistry.js +16 -0
- package/lib/gcp/cloudfunctions.js +25 -7
- package/lib/gcp/cloudfunctionsv2.js +10 -2
- package/lib/gcp/cloudtasks.js +143 -0
- package/lib/gcp/docker.js +7 -1
- package/lib/gcp/proto.js +2 -2
- package/lib/gcp/secretManager.js +27 -6
- package/lib/previews.js +1 -1
- package/package.json +2 -1
- package/schema/firebase-config.json +9 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getExtension = exports.deleteExtension = exports.unpublishExtension = exports.publishExtensionVersion = exports.registerPublisherProfile = exports.listExtensionVersions = exports.listExtensions = exports.getExtensionVersion = exports.getSource = exports.createSource = exports.updateInstanceFromRegistry = exports.updateInstance = exports.configureInstance = exports.listInstances = exports.getInstance = exports.deleteInstance = exports.createInstance = exports.ParamType = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
3
|
+
exports.getExtension = exports.deleteExtension = exports.unpublishExtension = exports.publishExtensionVersion = exports.undeprecateExtensionVersion = exports.deprecateExtensionVersion = exports.registerPublisherProfile = exports.listExtensionVersions = exports.listExtensions = exports.getExtensionVersion = exports.getSource = exports.createSource = exports.updateInstanceFromRegistry = exports.updateInstance = exports.configureInstance = exports.listInstances = exports.getInstance = exports.deleteInstance = exports.createInstance = exports.ParamType = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
4
4
|
const yaml = require("js-yaml");
|
|
5
5
|
const _ = require("lodash");
|
|
6
6
|
const clc = require("cli-color");
|
|
@@ -32,7 +32,7 @@ var ParamType;
|
|
|
32
32
|
ParamType["MULTISELECT"] = "MULTISELECT";
|
|
33
33
|
ParamType["SECRET"] = "SECRET";
|
|
34
34
|
})(ParamType = exports.ParamType || (exports.ParamType = {}));
|
|
35
|
-
async function createInstanceHelper(projectId, instanceId, config) {
|
|
35
|
+
async function createInstanceHelper(projectId, instanceId, config, validateOnly = false) {
|
|
36
36
|
const createRes = await api.request("POST", `/${VERSION}/projects/${projectId}/instances/`, {
|
|
37
37
|
auth: true,
|
|
38
38
|
origin: api.extensionsOrigin,
|
|
@@ -40,7 +40,13 @@ async function createInstanceHelper(projectId, instanceId, config) {
|
|
|
40
40
|
name: `projects/${projectId}/instances/${instanceId}`,
|
|
41
41
|
config: config,
|
|
42
42
|
},
|
|
43
|
+
query: {
|
|
44
|
+
validateOnly,
|
|
45
|
+
},
|
|
43
46
|
});
|
|
47
|
+
if (validateOnly) {
|
|
48
|
+
return createRes;
|
|
49
|
+
}
|
|
44
50
|
const pollRes = await operationPoller.pollOperation({
|
|
45
51
|
apiOrigin: api.extensionsOrigin,
|
|
46
52
|
apiVersion: VERSION,
|
|
@@ -68,7 +74,7 @@ async function createInstance(args) {
|
|
|
68
74
|
else {
|
|
69
75
|
throw new error_1.FirebaseError("No ExtensionVersion or ExtensionSource provided but one is required.");
|
|
70
76
|
}
|
|
71
|
-
return createInstanceHelper(args.projectId, args.instanceId, config);
|
|
77
|
+
return createInstanceHelper(args.projectId, args.instanceId, config, args.validateOnly);
|
|
72
78
|
}
|
|
73
79
|
exports.createInstance = createInstance;
|
|
74
80
|
async function deleteInstance(projectId, instanceId) {
|
|
@@ -115,31 +121,46 @@ async function listInstances(projectId) {
|
|
|
115
121
|
return instances;
|
|
116
122
|
}
|
|
117
123
|
exports.listInstances = listInstances;
|
|
118
|
-
async function configureInstance(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
async function configureInstance(args) {
|
|
125
|
+
var _a;
|
|
126
|
+
const res = await patchInstance({
|
|
127
|
+
projectId: args.projectId,
|
|
128
|
+
instanceId: args.instanceId,
|
|
129
|
+
updateMask: "config.params",
|
|
130
|
+
validateOnly: (_a = args.validateOnly) !== null && _a !== void 0 ? _a : false,
|
|
131
|
+
data: {
|
|
132
|
+
config: {
|
|
133
|
+
params: args.params,
|
|
134
|
+
},
|
|
122
135
|
},
|
|
123
136
|
});
|
|
124
137
|
return res;
|
|
125
138
|
}
|
|
126
139
|
exports.configureInstance = configureInstance;
|
|
127
|
-
async function updateInstance(
|
|
140
|
+
async function updateInstance(args) {
|
|
141
|
+
var _a;
|
|
128
142
|
const body = {
|
|
129
143
|
config: {
|
|
130
|
-
source: { name: extensionSource.name },
|
|
144
|
+
source: { name: args.extensionSource.name },
|
|
131
145
|
},
|
|
132
146
|
};
|
|
133
147
|
let updateMask = "config.source.name";
|
|
134
|
-
if (params) {
|
|
135
|
-
body.config.params = params;
|
|
148
|
+
if (args.params) {
|
|
149
|
+
body.config.params = args.params;
|
|
136
150
|
updateMask += ",config.params";
|
|
137
151
|
}
|
|
138
|
-
return await patchInstance(
|
|
152
|
+
return await patchInstance({
|
|
153
|
+
projectId: args.projectId,
|
|
154
|
+
instanceId: args.instanceId,
|
|
155
|
+
updateMask,
|
|
156
|
+
validateOnly: (_a = args.validateOnly) !== null && _a !== void 0 ? _a : false,
|
|
157
|
+
data: body,
|
|
158
|
+
});
|
|
139
159
|
}
|
|
140
160
|
exports.updateInstance = updateInstance;
|
|
141
|
-
async function updateInstanceFromRegistry(
|
|
142
|
-
|
|
161
|
+
async function updateInstanceFromRegistry(args) {
|
|
162
|
+
var _a;
|
|
163
|
+
const ref = refs.parse(args.extRef);
|
|
143
164
|
const body = {
|
|
144
165
|
config: {
|
|
145
166
|
extensionRef: refs.toExtensionRef(ref),
|
|
@@ -147,22 +168,32 @@ async function updateInstanceFromRegistry(projectId, instanceId, extRef, params)
|
|
|
147
168
|
},
|
|
148
169
|
};
|
|
149
170
|
let updateMask = "config.extension_ref,config.extension_version";
|
|
150
|
-
if (params) {
|
|
151
|
-
body.config.params = params;
|
|
171
|
+
if (args.params) {
|
|
172
|
+
body.config.params = args.params;
|
|
152
173
|
updateMask += ",config.params";
|
|
153
174
|
}
|
|
154
|
-
return await patchInstance(
|
|
175
|
+
return await patchInstance({
|
|
176
|
+
projectId: args.projectId,
|
|
177
|
+
instanceId: args.instanceId,
|
|
178
|
+
updateMask,
|
|
179
|
+
validateOnly: (_a = args.validateOnly) !== null && _a !== void 0 ? _a : false,
|
|
180
|
+
data: body,
|
|
181
|
+
});
|
|
155
182
|
}
|
|
156
183
|
exports.updateInstanceFromRegistry = updateInstanceFromRegistry;
|
|
157
|
-
async function patchInstance(
|
|
158
|
-
const updateRes = await api.request("PATCH", `/${VERSION}/projects/${projectId}/instances/${instanceId}`, {
|
|
184
|
+
async function patchInstance(args) {
|
|
185
|
+
const updateRes = await api.request("PATCH", `/${VERSION}/projects/${args.projectId}/instances/${args.instanceId}`, {
|
|
159
186
|
auth: true,
|
|
160
187
|
origin: api.extensionsOrigin,
|
|
161
188
|
query: {
|
|
162
|
-
updateMask,
|
|
189
|
+
updateMask: args.updateMask,
|
|
190
|
+
validateOnly: args.validateOnly,
|
|
163
191
|
},
|
|
164
|
-
data,
|
|
192
|
+
data: args.data,
|
|
165
193
|
});
|
|
194
|
+
if (args.validateOnly) {
|
|
195
|
+
return updateRes;
|
|
196
|
+
}
|
|
166
197
|
const pollRes = await operationPoller.pollOperation({
|
|
167
198
|
apiOrigin: api.extensionsOrigin,
|
|
168
199
|
apiVersion: VERSION,
|
|
@@ -302,6 +333,57 @@ async function registerPublisherProfile(projectId, publisherId) {
|
|
|
302
333
|
return res.body;
|
|
303
334
|
}
|
|
304
335
|
exports.registerPublisherProfile = registerPublisherProfile;
|
|
336
|
+
async function deprecateExtensionVersion(extensionRef, deprecationMessage) {
|
|
337
|
+
const ref = refs.parse(extensionRef);
|
|
338
|
+
try {
|
|
339
|
+
const res = await api.request("POST", `/${VERSION}/${refs.toExtensionVersionName(ref)}:deprecate`, {
|
|
340
|
+
auth: true,
|
|
341
|
+
origin: api.extensionsOrigin,
|
|
342
|
+
data: { deprecationMessage },
|
|
343
|
+
});
|
|
344
|
+
return res.body;
|
|
345
|
+
}
|
|
346
|
+
catch (err) {
|
|
347
|
+
if (err.status === 403) {
|
|
348
|
+
throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to deprecate this extension version.` + err, { status: err.status });
|
|
349
|
+
}
|
|
350
|
+
else if (err.status === 404) {
|
|
351
|
+
throw new error_1.FirebaseError(`Extension version ${clc.bold(extensionRef)} was not found.`);
|
|
352
|
+
}
|
|
353
|
+
else if (err instanceof error_1.FirebaseError) {
|
|
354
|
+
throw err;
|
|
355
|
+
}
|
|
356
|
+
throw new error_1.FirebaseError(`Error occurred deprecating extension version '${extensionRef}': ${err}`, {
|
|
357
|
+
status: err.status,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
exports.deprecateExtensionVersion = deprecateExtensionVersion;
|
|
362
|
+
async function undeprecateExtensionVersion(extensionRef) {
|
|
363
|
+
const ref = refs.parse(extensionRef);
|
|
364
|
+
try {
|
|
365
|
+
const res = await api.request("POST", `/${VERSION}/${refs.toExtensionVersionName(ref)}:undeprecate`, {
|
|
366
|
+
auth: true,
|
|
367
|
+
origin: api.extensionsOrigin,
|
|
368
|
+
});
|
|
369
|
+
return res.body;
|
|
370
|
+
}
|
|
371
|
+
catch (err) {
|
|
372
|
+
if (err.status === 403) {
|
|
373
|
+
throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to undeprecate this extension version.`, { status: err.status });
|
|
374
|
+
}
|
|
375
|
+
else if (err.status === 404) {
|
|
376
|
+
throw new error_1.FirebaseError(`Extension version ${clc.bold(extensionRef)} was not found.`);
|
|
377
|
+
}
|
|
378
|
+
else if (err instanceof error_1.FirebaseError) {
|
|
379
|
+
throw err;
|
|
380
|
+
}
|
|
381
|
+
throw new error_1.FirebaseError(`Error occurred undeprecating extension version '${extensionRef}': ${err}`, {
|
|
382
|
+
status: err.status,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
exports.undeprecateExtensionVersion = undeprecateExtensionVersion;
|
|
305
387
|
async function publishExtensionVersion(extensionVersionRef, packageUri, extensionRoot) {
|
|
306
388
|
const ref = refs.parse(extensionVersionRef);
|
|
307
389
|
if (!ref.version) {
|
|
@@ -27,6 +27,7 @@ const prompt_1 = require("../prompt");
|
|
|
27
27
|
const logger_1 = require("../logger");
|
|
28
28
|
const utils_2 = require("../utils");
|
|
29
29
|
const changelog_1 = require("./changelog");
|
|
30
|
+
const getProjectNumber_1 = require("../getProjectNumber");
|
|
30
31
|
var SpecParamType;
|
|
31
32
|
(function (SpecParamType) {
|
|
32
33
|
SpecParamType["SELECT"] = "select";
|
|
@@ -76,6 +77,7 @@ function getDBInstanceFromURL(databaseUrl = "") {
|
|
|
76
77
|
exports.getDBInstanceFromURL = getDBInstanceFromURL;
|
|
77
78
|
async function getFirebaseProjectParams(projectId) {
|
|
78
79
|
const body = await functionsConfig_1.getFirebaseConfig({ project: projectId });
|
|
80
|
+
const projectNumber = await getProjectNumber_1.getProjectNumber({ projectId });
|
|
79
81
|
const FIREBASE_CONFIG = JSON.stringify({
|
|
80
82
|
projectId: body.projectId,
|
|
81
83
|
databaseURL: body.databaseURL,
|
|
@@ -83,6 +85,7 @@ async function getFirebaseProjectParams(projectId) {
|
|
|
83
85
|
});
|
|
84
86
|
return {
|
|
85
87
|
PROJECT_ID: body.projectId,
|
|
88
|
+
PROJECT_NUMBER: projectNumber,
|
|
86
89
|
DATABASE_URL: body.databaseURL,
|
|
87
90
|
STORAGE_BUCKET: body.storageBucket,
|
|
88
91
|
FIREBASE_CONFIG,
|
|
@@ -108,7 +111,7 @@ function populateDefaultParams(paramVars, paramSpecs) {
|
|
|
108
111
|
const newParams = paramVars;
|
|
109
112
|
for (const param of paramSpecs) {
|
|
110
113
|
if (!paramVars[param.param]) {
|
|
111
|
-
if (param.default != undefined) {
|
|
114
|
+
if (param.default != undefined && param.required) {
|
|
112
115
|
newParams[param.param] = param.default;
|
|
113
116
|
}
|
|
114
117
|
else if (param.required) {
|
|
@@ -8,19 +8,20 @@ const extensionsApi_1 = require("./extensionsApi");
|
|
|
8
8
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
9
9
|
const utils = require("../utils");
|
|
10
10
|
const extensionsUtils = require("./utils");
|
|
11
|
-
const logger_1 = require("../logger");
|
|
12
11
|
async function listExtensions(projectId) {
|
|
13
12
|
const instances = await extensionsApi_1.listInstances(projectId);
|
|
14
13
|
if (instances.length < 1) {
|
|
15
14
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `there are no extensions installed on project ${clc.bold(projectId)}.`);
|
|
16
|
-
return
|
|
15
|
+
return [];
|
|
17
16
|
}
|
|
18
17
|
const table = new Table({
|
|
19
18
|
head: ["Extension", "Publisher", "Instance ID", "State", "Version", "Your last update"],
|
|
20
19
|
style: { head: ["yellow"] },
|
|
21
20
|
});
|
|
22
21
|
const sorted = _.sortBy(instances, "createTime", "asc").reverse();
|
|
22
|
+
const formatted = [];
|
|
23
23
|
sorted.forEach((instance) => {
|
|
24
|
+
var _a, _b, _c, _d;
|
|
24
25
|
let extension = _.get(instance, "config.extensionRef", "");
|
|
25
26
|
let publisher;
|
|
26
27
|
if (extension === "") {
|
|
@@ -30,18 +31,22 @@ async function listExtensions(projectId) {
|
|
|
30
31
|
else {
|
|
31
32
|
publisher = extension.split("/")[0];
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
+
const instanceId = (_a = _.last(instance.name.split("/"))) !== null && _a !== void 0 ? _a : "";
|
|
35
|
+
const state = instance.state +
|
|
36
|
+
(_.get(instance, "config.source.state", "ACTIVE") === "DELETED" ? " (UNPUBLISHED)" : "");
|
|
37
|
+
const version = (_d = (_c = (_b = instance === null || instance === void 0 ? void 0 : instance.config) === null || _b === void 0 ? void 0 : _b.source) === null || _c === void 0 ? void 0 : _c.spec) === null || _d === void 0 ? void 0 : _d.version;
|
|
38
|
+
const updateTime = extensionsUtils.formatTimestamp(instance.updateTime);
|
|
39
|
+
table.push([extension, publisher, instanceId, state, version, updateTime]);
|
|
40
|
+
formatted.push({
|
|
34
41
|
extension,
|
|
35
42
|
publisher,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
]);
|
|
43
|
+
instanceId,
|
|
44
|
+
state,
|
|
45
|
+
version,
|
|
46
|
+
updateTime,
|
|
47
|
+
});
|
|
42
48
|
});
|
|
43
49
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `list of extensions installed in ${clc.bold(projectId)}:`);
|
|
44
|
-
|
|
45
|
-
return { instances: sorted };
|
|
50
|
+
return formatted;
|
|
46
51
|
}
|
|
47
52
|
exports.listExtensions = listExtensions;
|
|
@@ -4,13 +4,13 @@ exports.readEnvFile = exports.getParamsFromFile = exports.promptForNewParams = e
|
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const clc = require("cli-color");
|
|
7
|
-
const dotenv = require("dotenv");
|
|
8
7
|
const fs = require("fs-extra");
|
|
9
8
|
const error_1 = require("../error");
|
|
10
9
|
const logger_1 = require("../logger");
|
|
11
10
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
12
11
|
const askUserForParam = require("./askUserForParam");
|
|
13
12
|
const track = require("../track");
|
|
13
|
+
const env = require("../functions/env");
|
|
14
14
|
function setNewDefaults(params, newDefaults) {
|
|
15
15
|
params.forEach((param) => {
|
|
16
16
|
if (newDefaults[param.param.toUpperCase()]) {
|
|
@@ -42,7 +42,6 @@ async function getParams(args) {
|
|
|
42
42
|
params = getParamsFromFile({
|
|
43
43
|
projectId: args.projectId,
|
|
44
44
|
paramSpecs: args.paramSpecs,
|
|
45
|
-
noninteractive: args.nonInteractive,
|
|
46
45
|
paramsEnvPath: args.paramsEnvPath,
|
|
47
46
|
});
|
|
48
47
|
}
|
|
@@ -71,7 +70,6 @@ async function getParamsForUpdate(args) {
|
|
|
71
70
|
params = getParamsFromFile({
|
|
72
71
|
projectId: args.projectId,
|
|
73
72
|
paramSpecs: args.newSpec.params,
|
|
74
|
-
noninteractive: args.nonInteractive,
|
|
75
73
|
paramsEnvPath: args.paramsEnvPath,
|
|
76
74
|
});
|
|
77
75
|
}
|
|
@@ -132,6 +130,10 @@ function getParamsFromFile(args) {
|
|
|
132
130
|
exports.getParamsFromFile = getParamsFromFile;
|
|
133
131
|
function readEnvFile(envPath) {
|
|
134
132
|
const buf = fs.readFileSync(path.resolve(envPath), "utf8");
|
|
135
|
-
|
|
133
|
+
const result = env.parse(buf.toString().trim());
|
|
134
|
+
if (result.errors.length) {
|
|
135
|
+
throw new error_1.FirebaseError(`Error while parsing ${envPath} - unable to parse following lines:\n${result.errors.join("\n")}`);
|
|
136
|
+
}
|
|
137
|
+
return result.envs;
|
|
136
138
|
}
|
|
137
139
|
exports.readEnvFile = readEnvFile;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUsedProducts = exports.checkProductsProvisioned = exports.DeferredProduct = void 0;
|
|
3
|
+
exports.getUsedProducts = exports.bulkCheckProductsProvisioned = exports.checkProductsProvisioned = exports.DeferredProduct = void 0;
|
|
4
4
|
const marked = require("marked");
|
|
5
5
|
const api = require("../api");
|
|
6
|
+
const functional_1 = require("../functional");
|
|
6
7
|
const error_1 = require("../error");
|
|
8
|
+
const planner_1 = require("../deploy/extensions/planner");
|
|
7
9
|
var DeferredProduct;
|
|
8
10
|
(function (DeferredProduct) {
|
|
9
11
|
DeferredProduct[DeferredProduct["STORAGE"] = 0] = "STORAGE";
|
|
@@ -11,6 +13,18 @@ var DeferredProduct;
|
|
|
11
13
|
})(DeferredProduct = exports.DeferredProduct || (exports.DeferredProduct = {}));
|
|
12
14
|
async function checkProductsProvisioned(projectId, spec) {
|
|
13
15
|
const usedProducts = getUsedProducts(spec);
|
|
16
|
+
await checkProducts(projectId, usedProducts);
|
|
17
|
+
}
|
|
18
|
+
exports.checkProductsProvisioned = checkProductsProvisioned;
|
|
19
|
+
async function bulkCheckProductsProvisioned(projectId, instanceSpecs) {
|
|
20
|
+
const usedProducts = await Promise.all(instanceSpecs.map(async (i) => {
|
|
21
|
+
const extensionVersion = await planner_1.getExtensionVersion(i);
|
|
22
|
+
return getUsedProducts(extensionVersion.spec);
|
|
23
|
+
}));
|
|
24
|
+
await checkProducts(projectId, [...functional_1.flattenArray(usedProducts)]);
|
|
25
|
+
}
|
|
26
|
+
exports.bulkCheckProductsProvisioned = bulkCheckProductsProvisioned;
|
|
27
|
+
async function checkProducts(projectId, usedProducts) {
|
|
14
28
|
const needProvisioning = [];
|
|
15
29
|
let isStorageProvisionedPromise;
|
|
16
30
|
let isAuthProvisionedPromise;
|
|
@@ -29,7 +43,7 @@ async function checkProductsProvisioned(projectId, spec) {
|
|
|
29
43
|
if (needProvisioning.length > 0) {
|
|
30
44
|
let errorMessage = "Some services used by this extension have not been set up on your " +
|
|
31
45
|
"Firebase project. To ensure this extension works as intended, you must enable these " +
|
|
32
|
-
"services by following the provided links, then retry
|
|
46
|
+
"services by following the provided links, then retry this command\n\n";
|
|
33
47
|
if (needProvisioning.includes(DeferredProduct.STORAGE)) {
|
|
34
48
|
errorMessage +=
|
|
35
49
|
" - Firebase Storage: store and retrieve user-generated files like images, audio, and " +
|
|
@@ -46,7 +60,6 @@ async function checkProductsProvisioned(projectId, spec) {
|
|
|
46
60
|
throw new error_1.FirebaseError(marked(errorMessage), { exit: 2 });
|
|
47
61
|
}
|
|
48
62
|
}
|
|
49
|
-
exports.checkProductsProvisioned = checkProductsProvisioned;
|
|
50
63
|
function getUsedProducts(spec) {
|
|
51
64
|
var _a, _b;
|
|
52
65
|
const usedProducts = [];
|
package/lib/extensions/refs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toExtensionVersionName = exports.toExtensionName = exports.toExtensionVersionRef = exports.toExtensionRef = exports.parse = void 0;
|
|
3
|
+
exports.equal = exports.toExtensionVersionName = exports.toExtensionName = exports.toExtensionVersionRef = exports.toExtensionRef = exports.parse = void 0;
|
|
4
4
|
const semver = require("semver");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const refRegex = new RegExp(/^([^/@\n]+)\/{1}([^/@\n]+)(@{1}([^\n]+)|)$/);
|
|
@@ -57,3 +57,11 @@ function toExtensionVersionName(ref) {
|
|
|
57
57
|
return `publishers/${ref.publisherId}/extensions/${ref.extensionId}/versions/${ref.version}`;
|
|
58
58
|
}
|
|
59
59
|
exports.toExtensionVersionName = toExtensionVersionName;
|
|
60
|
+
function equal(a, b) {
|
|
61
|
+
return (!!a &&
|
|
62
|
+
!!b &&
|
|
63
|
+
a.publisherId === b.publisherId &&
|
|
64
|
+
a.extensionId === b.extensionId &&
|
|
65
|
+
a.version === b.version);
|
|
66
|
+
}
|
|
67
|
+
exports.equal = equal;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prettySecretName = exports.getSecretLabels = exports.getManagedSecrets = exports.grantFirexServiceAgentSecretAdminRole = exports.usesSecrets = exports.ensureSecretManagerApiEnabled = void 0;
|
|
3
|
+
exports.prettySecretName = exports.getSecretLabels = exports.getActiveSecrets = exports.getManagedSecrets = exports.grantFirexServiceAgentSecretAdminRole = exports.usesSecrets = exports.ensureSecretManagerApiEnabled = exports.SECRET_LABEL = void 0;
|
|
4
4
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
5
5
|
const utils = require("../utils");
|
|
6
6
|
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
@@ -8,7 +8,7 @@ const projectUtils_1 = require("../projectUtils");
|
|
|
8
8
|
const extensionsApi = require("./extensionsApi");
|
|
9
9
|
const secretManagerApi = require("../gcp/secretManager");
|
|
10
10
|
const logger_1 = require("../logger");
|
|
11
|
-
|
|
11
|
+
exports.SECRET_LABEL = "firebase-extensions-managed";
|
|
12
12
|
async function ensureSecretManagerApiEnabled(options) {
|
|
13
13
|
const projectId = projectUtils_1.needProjectId(options);
|
|
14
14
|
return await ensureApiEnabled_1.ensure(projectId, "secretmanager.googleapis.com", "extensions", options.markdown);
|
|
@@ -26,24 +26,25 @@ async function grantFirexServiceAgentSecretAdminRole(secret) {
|
|
|
26
26
|
}
|
|
27
27
|
exports.grantFirexServiceAgentSecretAdminRole = grantFirexServiceAgentSecretAdminRole;
|
|
28
28
|
async function getManagedSecrets(instance) {
|
|
29
|
-
return (await Promise.all(getActiveSecrets(instance).map(async (secretResourceName) => {
|
|
29
|
+
return (await Promise.all(getActiveSecrets(instance.config.source.spec, instance.config.params).map(async (secretResourceName) => {
|
|
30
30
|
const secret = secretManagerApi.parseSecretResourceName(secretResourceName);
|
|
31
|
-
const labels = await secretManagerApi.
|
|
32
|
-
if (labels && labels[SECRET_LABEL]) {
|
|
31
|
+
const labels = (await secretManagerApi.getSecret(secret.projectId, secret.name)).labels;
|
|
32
|
+
if (labels && labels[exports.SECRET_LABEL]) {
|
|
33
33
|
return secretResourceName;
|
|
34
34
|
}
|
|
35
35
|
return Promise.resolve("");
|
|
36
36
|
}))).filter((secretId) => !!secretId);
|
|
37
37
|
}
|
|
38
38
|
exports.getManagedSecrets = getManagedSecrets;
|
|
39
|
-
function getActiveSecrets(
|
|
40
|
-
return
|
|
41
|
-
.map((p) => p.type == extensionsApi.ParamType.SECRET
|
|
39
|
+
function getActiveSecrets(spec, params) {
|
|
40
|
+
return spec.params
|
|
41
|
+
.map((p) => (p.type == extensionsApi.ParamType.SECRET ? params[p.param] : ""))
|
|
42
42
|
.filter((pv) => !!pv);
|
|
43
43
|
}
|
|
44
|
+
exports.getActiveSecrets = getActiveSecrets;
|
|
44
45
|
function getSecretLabels(instanceId) {
|
|
45
46
|
const labels = {};
|
|
46
|
-
labels[SECRET_LABEL] = instanceId;
|
|
47
|
+
labels[exports.SECRET_LABEL] = instanceId;
|
|
47
48
|
return labels;
|
|
48
49
|
}
|
|
49
50
|
exports.getSecretLabels = getSecretLabels;
|
|
@@ -62,10 +62,20 @@ exports.displayChanges = displayChanges;
|
|
|
62
62
|
async function update(updateOptions) {
|
|
63
63
|
const { projectId, instanceId, source, extRef, params } = updateOptions;
|
|
64
64
|
if (extRef) {
|
|
65
|
-
return await extensionsApi.updateInstanceFromRegistry(
|
|
65
|
+
return await extensionsApi.updateInstanceFromRegistry({
|
|
66
|
+
projectId,
|
|
67
|
+
instanceId,
|
|
68
|
+
extRef,
|
|
69
|
+
params,
|
|
70
|
+
});
|
|
66
71
|
}
|
|
67
72
|
else if (source) {
|
|
68
|
-
return await extensionsApi.updateInstance(
|
|
73
|
+
return await extensionsApi.updateInstance({
|
|
74
|
+
projectId,
|
|
75
|
+
instanceId,
|
|
76
|
+
extensionSource: source,
|
|
77
|
+
params,
|
|
78
|
+
});
|
|
69
79
|
}
|
|
70
80
|
throw new error_1.FirebaseError(`Neither a source nor a version of the extension was supplied for ${instanceId}. Please make sure this is a valid extension and try again.`);
|
|
71
81
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseVersionPredicate = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
5
|
+
function parseVersionPredicate(versionPredicate) {
|
|
6
|
+
const versionPredicateRegex = "^(?<comparator>>=|<=|>|<)?(?<targetSemVer>.*)";
|
|
7
|
+
const matches = versionPredicate.match(versionPredicateRegex);
|
|
8
|
+
if (!matches || !matches.groups.targetSemVer) {
|
|
9
|
+
throw new error_1.FirebaseError("Invalid version predicate.");
|
|
10
|
+
}
|
|
11
|
+
const comparator = matches.groups.comparator || "=";
|
|
12
|
+
return { comparator, targetSemVer: matches.groups.targetSemVer };
|
|
13
|
+
}
|
|
14
|
+
exports.parseVersionPredicate = parseVersionPredicate;
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.displayWarningPrompts = void 0;
|
|
3
|
+
exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
|
|
4
4
|
const marked = require("marked");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const extensionsApi_1 = require("./extensionsApi");
|
|
7
7
|
const displayExtensionInfo_1 = require("./displayExtensionInfo");
|
|
8
8
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
9
9
|
const resolveSource_1 = require("./resolveSource");
|
|
10
|
+
const deploymentSummary_1 = require("../deploy/extensions/deploymentSummary");
|
|
11
|
+
const planner_1 = require("../deploy/extensions/planner");
|
|
12
|
+
const functional_1 = require("../functional");
|
|
10
13
|
const utils = require("../utils");
|
|
11
14
|
function displayEAPWarning({ publisherId, sourceDownloadUri, githubLink, }) {
|
|
12
15
|
const publisherNameLink = githubLink ? `[${publisherId}](${githubLink})` : publisherId;
|
|
@@ -35,3 +38,32 @@ async function displayWarningPrompts(publisherId, launchStage, extensionVersion)
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
exports.displayWarningPrompts = displayWarningPrompts;
|
|
41
|
+
const toListEntry = (i) => {
|
|
42
|
+
var _a, _b, _c, _d;
|
|
43
|
+
const idAndRef = deploymentSummary_1.humanReadable(i);
|
|
44
|
+
const sourceCodeLink = `\n\t[Source Code](${(_a = i.extensionVersion) === null || _a === void 0 ? void 0 : _a.sourceDownloadUri})`;
|
|
45
|
+
const githubLink = ((_c = (_b = i.extensionVersion) === null || _b === void 0 ? void 0 : _b.spec) === null || _c === void 0 ? void 0 : _c.sourceUrl) ? `\n\t[Publisher Contact](${(_d = i.extensionVersion) === null || _d === void 0 ? void 0 : _d.spec.sourceUrl})`
|
|
46
|
+
: "";
|
|
47
|
+
return `${idAndRef}${sourceCodeLink}${githubLink}`;
|
|
48
|
+
};
|
|
49
|
+
async function displayWarningsForDeploy(instancesToCreate) {
|
|
50
|
+
const trustedPublishers = await resolveSource_1.getTrustedPublishers();
|
|
51
|
+
for (const i of instancesToCreate) {
|
|
52
|
+
await planner_1.getExtension(i);
|
|
53
|
+
await planner_1.getExtensionVersion(i);
|
|
54
|
+
}
|
|
55
|
+
const [eapExtensions, nonEapExtensions] = functional_1.partition(instancesToCreate, (i) => { var _a, _b; return !trustedPublishers.includes((_b = (_a = i.ref) === null || _a === void 0 ? void 0 : _a.publisherId) !== null && _b !== void 0 ? _b : ""); });
|
|
56
|
+
const experimental = nonEapExtensions.filter((i) => i.extension.registryLaunchStage === extensionsApi_1.RegistryLaunchStage.EXPERIMENTAL);
|
|
57
|
+
if (experimental.length) {
|
|
58
|
+
const humanReadableList = experimental.map((i) => `\t${deploymentSummary_1.humanReadable(i)}`).join("\n");
|
|
59
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`The following are instances of ${clc.bold("experimental")} extensions.They may not be production-ready. Their functionality may change in backward-incompatible ways before their official release, or they may be discontinued.\n${humanReadableList}\n`));
|
|
60
|
+
}
|
|
61
|
+
if (eapExtensions.length) {
|
|
62
|
+
const humanReadableList = eapExtensions.map(toListEntry).join("\n");
|
|
63
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`These extensions are in preview and are built by a developer in the Extensions Publisher Early Access Program (http://bit.ly/firex-provider. Their functionality might change in backwards-incompatible ways. Since these extensions aren't built by Firebase, reach out to their publisher with questions about them.` +
|
|
64
|
+
` They are provided “AS IS”, without any warranty, express or implied, from Google.` +
|
|
65
|
+
` Google disclaims all liability for any damages, direct or indirect, resulting from the use of these extensions\n${humanReadableList}`));
|
|
66
|
+
}
|
|
67
|
+
return experimental.length > 0 || eapExtensions.length > 0;
|
|
68
|
+
}
|
|
69
|
+
exports.displayWarningsForDeploy = displayWarningsForDeploy;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deletePackage = exports.API_VERSION = void 0;
|
|
4
|
+
const apiv2_1 = require("../apiv2");
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
exports.API_VERSION = "v1beta2";
|
|
7
|
+
const client = new apiv2_1.Client({
|
|
8
|
+
urlPrefix: api_1.artifactRegistryDomain,
|
|
9
|
+
auth: true,
|
|
10
|
+
apiVersion: exports.API_VERSION,
|
|
11
|
+
});
|
|
12
|
+
async function deletePackage(name) {
|
|
13
|
+
const res = await client.delete(name);
|
|
14
|
+
return res.body;
|
|
15
|
+
}
|
|
16
|
+
exports.deletePackage = deletePackage;
|
|
@@ -4,6 +4,7 @@ exports.functionFromEndpoint = exports.endpointFromFunction = exports.listAllFun
|
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const logger_1 = require("../logger");
|
|
7
|
+
const previews_1 = require("../previews");
|
|
7
8
|
const api = require("../api");
|
|
8
9
|
const backend = require("../deploy/functions/backend");
|
|
9
10
|
const utils = require("../utils");
|
|
@@ -50,7 +51,11 @@ async function createFunction(cloudFunction) {
|
|
|
50
51
|
const apiPath = cloudFunction.name.substring(0, cloudFunction.name.lastIndexOf("/"));
|
|
51
52
|
const endpoint = `/${exports.API_VERSION}/${apiPath}`;
|
|
52
53
|
try {
|
|
54
|
+
const headers = previews_1.previews.artifactregistry
|
|
55
|
+
? { "X-Firebase-Artifact-Registry": "optin" }
|
|
56
|
+
: undefined;
|
|
53
57
|
const res = await api.request("POST", endpoint, {
|
|
58
|
+
headers,
|
|
54
59
|
auth: true,
|
|
55
60
|
data: cloudFunction,
|
|
56
61
|
origin: api.functionsOrigin,
|
|
@@ -145,7 +150,11 @@ async function updateFunction(cloudFunction) {
|
|
|
145
150
|
const endpoint = `/${exports.API_VERSION}/${cloudFunction.name}`;
|
|
146
151
|
const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "environmentVariables");
|
|
147
152
|
try {
|
|
153
|
+
const headers = previews_1.previews.artifactregistry
|
|
154
|
+
? { "X-Firebase-Artifact-Registry": "optin" }
|
|
155
|
+
: undefined;
|
|
148
156
|
const res = await api.request("PATCH", endpoint, {
|
|
157
|
+
headers,
|
|
149
158
|
qs: {
|
|
150
159
|
updateMask: fieldMasks.join(","),
|
|
151
160
|
},
|
|
@@ -215,19 +224,24 @@ async function listAllFunctions(projectId) {
|
|
|
215
224
|
}
|
|
216
225
|
exports.listAllFunctions = listAllFunctions;
|
|
217
226
|
function endpointFromFunction(gcfFunction) {
|
|
218
|
-
var _a, _b;
|
|
227
|
+
var _a, _b, _c;
|
|
219
228
|
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
220
229
|
let trigger;
|
|
221
230
|
let uri;
|
|
222
|
-
if (gcfFunction.
|
|
223
|
-
trigger = { httpsTrigger: {} };
|
|
224
|
-
uri = gcfFunction.httpsTrigger.url;
|
|
225
|
-
}
|
|
226
|
-
else if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
|
|
231
|
+
if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
|
|
227
232
|
trigger = {
|
|
228
233
|
scheduleTrigger: {},
|
|
229
234
|
};
|
|
230
235
|
}
|
|
236
|
+
else if ((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) {
|
|
237
|
+
trigger = {
|
|
238
|
+
taskQueueTrigger: {},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
else if (gcfFunction.httpsTrigger) {
|
|
242
|
+
trigger = { httpsTrigger: {} };
|
|
243
|
+
uri = gcfFunction.httpsTrigger.url;
|
|
244
|
+
}
|
|
231
245
|
else {
|
|
232
246
|
trigger = {
|
|
233
247
|
eventTrigger: {
|
|
@@ -235,7 +249,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
235
249
|
eventFilters: {
|
|
236
250
|
resource: gcfFunction.eventTrigger.resource,
|
|
237
251
|
},
|
|
238
|
-
retry: !!((
|
|
252
|
+
retry: !!((_c = gcfFunction.eventTrigger.failurePolicy) === null || _c === void 0 ? void 0 : _c.retry),
|
|
239
253
|
},
|
|
240
254
|
};
|
|
241
255
|
}
|
|
@@ -284,6 +298,10 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
|
284
298
|
};
|
|
285
299
|
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
|
|
286
300
|
}
|
|
301
|
+
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
302
|
+
gcfFunction.httpsTrigger = {};
|
|
303
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
|
|
304
|
+
}
|
|
287
305
|
else {
|
|
288
306
|
gcfFunction.httpsTrigger = {};
|
|
289
307
|
}
|