firebase-tools 10.1.5 → 10.2.2
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/api.js +1 -0
- package/lib/apiv2.js +3 -0
- package/lib/appdistribution/options-parser-util.js +1 -1
- package/lib/auth.js +62 -25
- package/lib/command.js +1 -1
- package/lib/commands/apps-android-sha-create.js +2 -2
- package/lib/commands/apps-sdkconfig.js +1 -1
- package/lib/commands/auth-import.js +1 -1
- package/lib/commands/database-rules-list.js +2 -2
- package/lib/commands/emulators-start.js +1 -1
- package/lib/commands/ext-configure.js +1 -0
- package/lib/commands/ext-dev-init.js +49 -49
- package/lib/commands/ext-export.js +12 -2
- package/lib/commands/ext-install.js +104 -103
- package/lib/commands/ext-uninstall.js +9 -8
- package/lib/commands/ext-update.js +10 -9
- package/lib/commands/functions-config-clone.js +1 -1
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/functions-secrets-access.js +17 -0
- package/lib/commands/functions-secrets-destroy.js +40 -0
- package/lib/commands/functions-secrets-get.js +21 -0
- package/lib/commands/functions-secrets-prune.js +50 -0
- package/lib/commands/functions-secrets-set.js +46 -0
- package/lib/commands/hosting-clone.js +3 -3
- package/lib/commands/index.js +7 -3
- package/lib/commands/login.js +1 -1
- package/lib/commands/remoteconfig-get.js +1 -1
- package/lib/deploy/extensions/deploymentSummary.js +3 -3
- package/lib/deploy/extensions/params.js +3 -0
- package/lib/deploy/extensions/planner.js +2 -1
- package/lib/deploy/extensions/tasks.js +1 -1
- package/lib/deploy/functions/backend.js +20 -5
- package/lib/deploy/functions/checkIam.js +1 -1
- package/lib/deploy/functions/containerCleaner.js +3 -3
- package/lib/deploy/functions/ensure.js +112 -0
- package/lib/deploy/functions/ensureCloudBuildEnabled.js +0 -49
- package/lib/deploy/functions/functionsDeployHelper.js +2 -2
- package/lib/deploy/functions/prepare.js +15 -20
- package/lib/deploy/functions/pricing.js +1 -1
- package/lib/deploy/functions/prompts.js +2 -2
- package/lib/deploy/functions/release/fabricator.js +3 -3
- package/lib/deploy/functions/release/index.js +1 -1
- package/lib/deploy/functions/release/planner.js +11 -8
- package/lib/deploy/functions/release/reporter.js +3 -0
- package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
- package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +17 -11
- package/lib/deploy/functions/runtimes/golang/index.js +2 -2
- package/lib/deploy/functions/runtimes/node/index.js +26 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +40 -7
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/validate.js +58 -3
- package/lib/deploy/hosting/client.js +9 -0
- package/lib/deploy/hosting/convertConfig.js +6 -0
- package/lib/deploy/hosting/deploy.js +2 -2
- package/lib/deploy/hosting/hashcache.js +21 -19
- package/lib/deploy/hosting/index.js +5 -5
- package/lib/deploy/hosting/prepare.js +25 -25
- package/lib/deploy/hosting/release.js +21 -24
- package/lib/deploy/hosting/uploader.js +5 -5
- package/lib/deploy/remoteconfig/functions.js +2 -2
- package/lib/emulator/auth/cloudFunctions.js +1 -1
- package/lib/emulator/auth/operations.js +1 -1
- package/lib/emulator/commandUtils.js +5 -1
- package/lib/emulator/constants.js +3 -0
- package/lib/emulator/controller.js +48 -18
- package/lib/emulator/download.js +18 -1
- package/lib/emulator/downloadableEmulators.js +30 -13
- package/lib/emulator/emulatorLogger.js +19 -1
- package/lib/emulator/extensions/validation.js +35 -0
- package/lib/emulator/extensionsEmulator.js +140 -0
- package/lib/emulator/functionsEmulator.js +175 -86
- package/lib/emulator/functionsEmulatorRuntime.js +108 -83
- package/lib/emulator/functionsEmulatorShared.js +51 -1
- package/lib/emulator/functionsEmulatorShell.js +1 -2
- package/lib/emulator/functionsEmulatorUtils.js +4 -4
- package/lib/emulator/functionsRuntimeWorker.js +3 -3
- package/lib/emulator/hub.js +4 -3
- package/lib/emulator/loggingEmulator.js +1 -1
- package/lib/emulator/pubsubEmulator.js +1 -1
- package/lib/emulator/registry.js +10 -2
- package/lib/emulator/storage/apis/firebase.js +31 -26
- package/lib/emulator/storage/apis/gcloud.js +7 -12
- package/lib/emulator/storage/files.js +36 -34
- package/lib/emulator/storage/index.js +2 -2
- package/lib/emulator/storage/metadata.js +2 -2
- package/lib/emulator/storage/rules/runtime.js +8 -7
- package/lib/emulator/types.js +3 -0
- package/lib/ensureApiEnabled.js +5 -1
- package/lib/error.js +1 -1
- package/lib/extensions/askUserForParam.js +2 -2
- package/lib/extensions/changelog.js +3 -1
- package/lib/extensions/checkProjectBilling.js +1 -1
- package/lib/extensions/diagnose.js +56 -0
- package/lib/extensions/displayExtensionInfo.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +24 -8
- package/lib/extensions/emulator/specHelper.js +10 -23
- package/lib/extensions/export.js +1 -51
- package/lib/extensions/extensionsApi.js +1 -1
- package/lib/extensions/extensionsHelper.js +23 -10
- package/lib/extensions/listExtensions.js +2 -0
- package/lib/extensions/manifest.js +48 -0
- package/lib/extensions/metricsUtils.js +4 -4
- package/lib/extensions/paramHelper.js +4 -4
- package/lib/extensions/refs.js +1 -1
- package/lib/extensions/secretsUtils.js +4 -4
- package/lib/functional.js +1 -1
- package/lib/functions/env.js +7 -8
- package/lib/functions/secrets.js +112 -0
- package/lib/gcp/cloudfunctions.js +24 -5
- package/lib/gcp/cloudfunctionsv2.js +18 -5
- package/lib/gcp/cloudtasks.js +1 -1
- package/lib/gcp/docker.js +2 -2
- package/lib/gcp/run.js +2 -2
- package/lib/gcp/secretManager.js +128 -46
- package/lib/gcp/storage.js +1 -0
- package/lib/hosting/api.js +1 -1
- package/lib/hosting/functionsProxy.js +15 -5
- package/lib/hosting/proxy.js +2 -2
- package/lib/init/features/account.js +1 -1
- package/lib/management/database.js +1 -1
- package/lib/previews.js +1 -1
- package/lib/responseToError.js +16 -7
- package/lib/serve/functions.js +2 -2
- package/lib/serve/hosting.js +1 -1
- package/lib/utils.js +7 -2
- package/npm-shrinkwrap.json +904 -412
- package/package.json +3 -3
- package/schema/firebase-config.json +32 -0
- package/templates/init/functions/javascript/package.lint.json +3 -3
- package/templates/init/functions/javascript/package.nolint.json +2 -2
- package/templates/init/functions/typescript/package.lint.json +7 -7
- package/templates/init/functions/typescript/package.nolint.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getParams = exports.buildOptions = void 0;
|
|
3
|
+
exports.getParams = exports.getExtensionFunctionInfo = exports.buildOptions = void 0;
|
|
4
4
|
const fs = require("fs-extra");
|
|
5
5
|
const _ = require("lodash");
|
|
6
6
|
const path = require("path");
|
|
@@ -15,9 +15,9 @@ const emulatorLogger_1 = require("../../emulator/emulatorLogger");
|
|
|
15
15
|
const projectUtils_1 = require("../../projectUtils");
|
|
16
16
|
const types_1 = require("../../emulator/types");
|
|
17
17
|
async function buildOptions(options) {
|
|
18
|
-
const
|
|
19
|
-
options.
|
|
20
|
-
const spec = await specHelper.readExtensionYaml(
|
|
18
|
+
const extDevDir = localHelper.findExtensionYaml(process.cwd());
|
|
19
|
+
options.extDevDir = extDevDir;
|
|
20
|
+
const spec = await specHelper.readExtensionYaml(extDevDir);
|
|
21
21
|
extensionsHelper.validateSpec(spec);
|
|
22
22
|
const params = getParams(options, spec);
|
|
23
23
|
extensionsHelper.validateCommandLineParams(params, spec.params);
|
|
@@ -28,13 +28,29 @@ async function buildOptions(options) {
|
|
|
28
28
|
checkTestConfig(testConfig, functionResources);
|
|
29
29
|
}
|
|
30
30
|
options.config = buildConfig(functionResources, testConfig);
|
|
31
|
-
options.
|
|
31
|
+
options.extDevEnv = params;
|
|
32
32
|
const functionEmuTriggerDefs = functionResources.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r));
|
|
33
|
-
options.
|
|
34
|
-
options.
|
|
33
|
+
options.extDevTriggers = functionEmuTriggerDefs;
|
|
34
|
+
options.extDevNodeVersion = specHelper.getNodeVersion(functionResources);
|
|
35
35
|
return options;
|
|
36
36
|
}
|
|
37
37
|
exports.buildOptions = buildOptions;
|
|
38
|
+
async function getExtensionFunctionInfo(extensionDir, instanceId, params) {
|
|
39
|
+
const spec = await specHelper.readExtensionYaml(extensionDir);
|
|
40
|
+
const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, params);
|
|
41
|
+
const extensionTriggers = functionResources
|
|
42
|
+
.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r))
|
|
43
|
+
.map((trigger) => {
|
|
44
|
+
trigger.name = `ext-${instanceId}-${trigger.name}`;
|
|
45
|
+
return trigger;
|
|
46
|
+
});
|
|
47
|
+
const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
|
|
48
|
+
return {
|
|
49
|
+
extensionTriggers,
|
|
50
|
+
nodeMajorVersion,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.getExtensionFunctionInfo = getExtensionFunctionInfo;
|
|
38
54
|
function getParams(options, extensionSpec) {
|
|
39
55
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
40
56
|
const userParams = paramHelper.readEnvFile(options.testParams);
|
|
@@ -120,7 +136,7 @@ function getFunctionSourceDirectory(functionResources) {
|
|
|
120
136
|
if (!sourceDirectory) {
|
|
121
137
|
sourceDirectory = dir;
|
|
122
138
|
}
|
|
123
|
-
else if (sourceDirectory
|
|
139
|
+
else if (sourceDirectory !== dir) {
|
|
124
140
|
throw new error_1.FirebaseError(`Found function resources with different sourceDirectories: '${sourceDirectory}' and '${dir}'. The extensions emulator only supports a single sourceDirectory.`);
|
|
125
141
|
}
|
|
126
142
|
}
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getNodeVersion = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readExtensionYaml = void 0;
|
|
4
4
|
const yaml = require("js-yaml");
|
|
5
|
-
const _ = require("lodash");
|
|
6
5
|
const path = require("path");
|
|
7
6
|
const fs = require("fs-extra");
|
|
8
7
|
const error_1 = require("../../error");
|
|
9
8
|
const extensionsHelper_1 = require("../extensionsHelper");
|
|
10
|
-
const
|
|
11
|
-
const types_1 = require("../../emulator/types");
|
|
9
|
+
const functionsEmulatorUtils_1 = require("../../emulator/functionsEmulatorUtils");
|
|
12
10
|
const SPEC_FILE = "extension.yaml";
|
|
13
11
|
const validFunctionTypes = [
|
|
14
12
|
"firebaseextensions.v1beta.function",
|
|
@@ -62,35 +60,24 @@ function getFunctionProperties(resources) {
|
|
|
62
60
|
}
|
|
63
61
|
exports.getFunctionProperties = getFunctionProperties;
|
|
64
62
|
function getNodeVersion(resources) {
|
|
65
|
-
const
|
|
63
|
+
const invalidRuntimes = [];
|
|
66
64
|
const versions = resources.map((r) => {
|
|
67
65
|
var _a, _b;
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
if ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.runtime) {
|
|
67
|
+
const runtimeName = (_b = r.properties) === null || _b === void 0 ? void 0 : _b.runtime;
|
|
68
|
+
const runtime = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(runtimeName);
|
|
69
|
+
if (!runtime) {
|
|
70
|
+
invalidRuntimes.push(runtimeName);
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
|
-
|
|
73
|
+
return runtime;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
return
|
|
77
|
-
});
|
|
78
|
-
if (functionNamesWithoutRuntime.length) {
|
|
79
|
-
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN", "extensions", `No 'runtime' property found for the following functions, defaulting to nodejs8: ${functionNamesWithoutRuntime.join(", ")}`);
|
|
80
|
-
}
|
|
81
|
-
const invalidRuntimes = _.filter(versions, (v) => {
|
|
82
|
-
return !_.includes(v, "nodejs");
|
|
76
|
+
return 14;
|
|
83
77
|
});
|
|
84
78
|
if (invalidRuntimes.length) {
|
|
85
79
|
throw new error_1.FirebaseError(`The following runtimes are not supported by the Emulator Suite: ${invalidRuntimes.join(", ")}. \n Only Node runtimes are supported.`);
|
|
86
80
|
}
|
|
87
|
-
|
|
88
|
-
return "10";
|
|
89
|
-
}
|
|
90
|
-
if (_.includes(versions, "nodejs6")) {
|
|
91
|
-
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN", "extensions", "Node 6 is deprecated. We recommend upgrading to a newer version.");
|
|
92
|
-
return "6";
|
|
93
|
-
}
|
|
94
|
-
return "8";
|
|
81
|
+
return Math.max(...versions);
|
|
95
82
|
}
|
|
96
83
|
exports.getNodeVersion = getNodeVersion;
|
package/lib/extensions/export.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const clc = require("cli-color");
|
|
5
|
-
const refs = require("./refs");
|
|
6
|
-
const config_1 = require("../config");
|
|
3
|
+
exports.displayExportInfo = exports.setSecretParamsToLatest = exports.parameterizeProject = void 0;
|
|
7
4
|
const planner_1 = require("../deploy/extensions/planner");
|
|
8
5
|
const deploymentSummary_1 = require("../deploy/extensions/deploymentSummary");
|
|
9
6
|
const logger_1 = require("../logger");
|
|
10
|
-
const error_1 = require("../error");
|
|
11
|
-
const prompt_1 = require("../prompt");
|
|
12
7
|
const secretManager_1 = require("../gcp/secretManager");
|
|
13
8
|
const secretsUtils_1 = require("./secretsUtils");
|
|
14
9
|
function parameterizeProject(projectId, projectNumber, spec) {
|
|
@@ -60,48 +55,3 @@ function displaySpecs(specs) {
|
|
|
60
55
|
logger_1.logger.info("");
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
|
-
function writeExtensionsToFirebaseJson(have, existingConfig) {
|
|
64
|
-
const extensions = existingConfig.get("extensions", {});
|
|
65
|
-
for (const s of have) {
|
|
66
|
-
extensions[s.instanceId] = refs.toExtensionVersionRef(s.ref);
|
|
67
|
-
}
|
|
68
|
-
existingConfig.set("extensions", extensions);
|
|
69
|
-
logger_1.logger.info("Adding Extensions to " + clc.bold("firebase.json") + "...");
|
|
70
|
-
existingConfig.writeProjectFile("firebase.json", existingConfig.src);
|
|
71
|
-
}
|
|
72
|
-
async function writeEnvFile(spec, existingConfig, force) {
|
|
73
|
-
const content = Object.entries(spec.params)
|
|
74
|
-
.map((r) => `${r[0]}=${r[1]}`)
|
|
75
|
-
.join("\n");
|
|
76
|
-
await existingConfig.askWriteProjectFile(`extensions/${spec.instanceId}.env`, content, force);
|
|
77
|
-
}
|
|
78
|
-
async function writeFiles(have, options) {
|
|
79
|
-
const existingConfig = config_1.Config.load(options, true);
|
|
80
|
-
if (!existingConfig) {
|
|
81
|
-
throw new error_1.FirebaseError("Not currently in a Firebase directory. Please run `firebase init` to create a Firebase directory.");
|
|
82
|
-
}
|
|
83
|
-
if (existingConfig.has("extensions") &&
|
|
84
|
-
Object.keys(existingConfig.get("extensions")).length &&
|
|
85
|
-
!options.nonInteractive &&
|
|
86
|
-
!options.force) {
|
|
87
|
-
const currentExtensions = Object.entries(existingConfig.get("extensions"))
|
|
88
|
-
.map((i) => `${i[0]}: ${i[1]}`)
|
|
89
|
-
.join("\n\t");
|
|
90
|
-
const overwrite = await (0, prompt_1.promptOnce)({
|
|
91
|
-
type: "list",
|
|
92
|
-
message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite or merge?`,
|
|
93
|
-
choices: [
|
|
94
|
-
{ name: "Overwrite", value: true },
|
|
95
|
-
{ name: "Merge", value: false },
|
|
96
|
-
],
|
|
97
|
-
});
|
|
98
|
-
if (overwrite) {
|
|
99
|
-
existingConfig.set("extensions", {});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
writeExtensionsToFirebaseJson(have, existingConfig);
|
|
103
|
-
for (const spec of have) {
|
|
104
|
-
await writeEnvFile(spec, existingConfig, options.force);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
exports.writeFiles = writeFiles;
|
|
@@ -295,7 +295,7 @@ async function listExtensionVersions(ref, filter = "") {
|
|
|
295
295
|
exports.listExtensionVersions = listExtensionVersions;
|
|
296
296
|
async function getPublisherProfile(projectId, publisherId) {
|
|
297
297
|
const res = await apiClient.get(`/projects/${projectId}/publisherProfile`, {
|
|
298
|
-
queryParams: publisherId
|
|
298
|
+
queryParams: publisherId === undefined
|
|
299
299
|
? undefined
|
|
300
300
|
: {
|
|
301
301
|
publisherId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
3
|
+
exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const ora = require("ora");
|
|
@@ -16,6 +16,7 @@ const utils_1 = require("./utils");
|
|
|
16
16
|
const functionsConfig_1 = require("../functionsConfig");
|
|
17
17
|
const resolveSource_1 = require("./resolveSource");
|
|
18
18
|
const error_1 = require("../error");
|
|
19
|
+
const diagnose_1 = require("./diagnose");
|
|
19
20
|
const askUserForParam_1 = require("./askUserForParam");
|
|
20
21
|
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
21
22
|
const storage_1 = require("../gcp/storage");
|
|
@@ -111,7 +112,7 @@ function populateDefaultParams(paramVars, paramSpecs) {
|
|
|
111
112
|
const newParams = paramVars;
|
|
112
113
|
for (const param of paramSpecs) {
|
|
113
114
|
if (!paramVars[param.param]) {
|
|
114
|
-
if (param.default
|
|
115
|
+
if (param.default !== undefined && param.required) {
|
|
115
116
|
newParams[param.param] = param.default;
|
|
116
117
|
}
|
|
117
118
|
else if (param.required) {
|
|
@@ -196,13 +197,13 @@ function validateSpec(spec) {
|
|
|
196
197
|
if (param.type && !_.includes(SpecParamType, param.type)) {
|
|
197
198
|
errors.push(`Invalid type ${param.type} for param${param.param ? ` ${param.param}` : ""}. Valid types are ${_.values(SpecParamType).join(", ")}`);
|
|
198
199
|
}
|
|
199
|
-
if (!param.type || param.type
|
|
200
|
+
if (!param.type || param.type === SpecParamType.STRING) {
|
|
200
201
|
if (param.options) {
|
|
201
202
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} cannot have options because it is type STRING`);
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
if (param.type &&
|
|
205
|
-
(param.type
|
|
206
|
+
(param.type === SpecParamType.SELECT || param.type === SpecParamType.MULTISELECT)) {
|
|
206
207
|
if (param.validationRegex) {
|
|
207
208
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} cannot have validationRegex because it is type ${param.type}`);
|
|
208
209
|
}
|
|
@@ -210,12 +211,12 @@ function validateSpec(spec) {
|
|
|
210
211
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} requires options because it is type ${param.type}`);
|
|
211
212
|
}
|
|
212
213
|
for (const opt of param.options || []) {
|
|
213
|
-
if (opt.value
|
|
214
|
+
if (opt.value === undefined) {
|
|
214
215
|
errors.push(`Option for param${param.param ? ` ${param.param}` : ""} is missing required field: value`);
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
|
-
if (param.type && param.type
|
|
219
|
+
if (param.type && param.type === SpecParamType.SELECTRESOURCE) {
|
|
219
220
|
if (!param.resourceType) {
|
|
220
221
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} must have resourceType because it is type ${param.type}`);
|
|
221
222
|
}
|
|
@@ -267,7 +268,7 @@ async function archiveAndUploadSource(extPath, bucketName) {
|
|
|
267
268
|
}
|
|
268
269
|
async function publishExtensionVersionFromLocalSource(args) {
|
|
269
270
|
const extensionSpec = await (0, localHelper_1.getLocalExtensionSpec)(args.rootDirectory);
|
|
270
|
-
if (extensionSpec.name
|
|
271
|
+
if (extensionSpec.name !== args.extensionId) {
|
|
271
272
|
throw new error_1.FirebaseError(`Extension ID '${clc.bold(args.extensionId)}' does not match the name in extension.yaml '${clc.bold(extensionSpec.name)}'.`);
|
|
272
273
|
}
|
|
273
274
|
const subbedSpec = JSON.parse(JSON.stringify(extensionSpec));
|
|
@@ -324,7 +325,9 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
324
325
|
}
|
|
325
326
|
catch (err) {
|
|
326
327
|
uploadSpinner.fail();
|
|
327
|
-
throw err
|
|
328
|
+
throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
|
|
329
|
+
original: err,
|
|
330
|
+
});
|
|
328
331
|
}
|
|
329
332
|
const publishSpinner = ora(`Publishing ${clc.bold(ref)}`);
|
|
330
333
|
let res;
|
|
@@ -335,7 +338,7 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
335
338
|
}
|
|
336
339
|
catch (err) {
|
|
337
340
|
publishSpinner.fail();
|
|
338
|
-
if (err.status
|
|
341
|
+
if (err.status === 404) {
|
|
339
342
|
throw new error_1.FirebaseError(marked(`Couldn't find publisher ID '${clc.bold(args.publisherId)}'. Please ensure that you have registered this ID. To register as a publisher, you can check out the [Firebase documentation](https://firebase.google.com/docs/extensions/alpha/share#register_as_an_extensions_publisher) for step-by-step instructions.`));
|
|
340
343
|
}
|
|
341
344
|
throw err;
|
|
@@ -359,7 +362,9 @@ async function createSourceFromLocation(projectId, sourceUri) {
|
|
|
359
362
|
}
|
|
360
363
|
catch (err) {
|
|
361
364
|
uploadSpinner.fail();
|
|
362
|
-
throw err
|
|
365
|
+
throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
|
|
366
|
+
original: err,
|
|
367
|
+
});
|
|
363
368
|
}
|
|
364
369
|
}
|
|
365
370
|
else {
|
|
@@ -504,3 +509,11 @@ async function confirm(args) {
|
|
|
504
509
|
}
|
|
505
510
|
}
|
|
506
511
|
exports.confirm = confirm;
|
|
512
|
+
async function diagnoseAndFixProject(options) {
|
|
513
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
514
|
+
const ok = await (0, diagnose_1.diagnose)(projectId);
|
|
515
|
+
if (!ok) {
|
|
516
|
+
throw new error_1.FirebaseError("Unable to proceed until all issues are resolved.");
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
exports.diagnoseAndFixProject = diagnoseAndFixProject;
|
|
@@ -8,6 +8,7 @@ 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");
|
|
11
12
|
async function listExtensions(projectId) {
|
|
12
13
|
const instances = await (0, extensionsApi_1.listInstances)(projectId);
|
|
13
14
|
if (instances.length < 1) {
|
|
@@ -47,6 +48,7 @@ async function listExtensions(projectId) {
|
|
|
47
48
|
});
|
|
48
49
|
});
|
|
49
50
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `list of extensions installed in ${clc.bold(projectId)}:`);
|
|
51
|
+
logger_1.logger.info(table.toString());
|
|
50
52
|
return formatted;
|
|
51
53
|
}
|
|
52
54
|
exports.listExtensions = listExtensions;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeToManifest = void 0;
|
|
4
|
+
const clc = require("cli-color");
|
|
5
|
+
const refs = require("./refs");
|
|
6
|
+
const logger_1 = require("../logger");
|
|
7
|
+
const prompt_1 = require("../prompt");
|
|
8
|
+
async function writeToManifest(specs, config, options) {
|
|
9
|
+
if (config.has("extensions") &&
|
|
10
|
+
Object.keys(config.get("extensions")).length &&
|
|
11
|
+
!options.nonInteractive &&
|
|
12
|
+
!options.force) {
|
|
13
|
+
const currentExtensions = Object.entries(config.get("extensions"))
|
|
14
|
+
.map((i) => `${i[0]}: ${i[1]}`)
|
|
15
|
+
.join("\n\t");
|
|
16
|
+
const overwrite = await (0, prompt_1.promptOnce)({
|
|
17
|
+
type: "list",
|
|
18
|
+
message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite or merge?`,
|
|
19
|
+
choices: [
|
|
20
|
+
{ name: "Overwrite", value: true },
|
|
21
|
+
{ name: "Merge", value: false },
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
if (overwrite) {
|
|
25
|
+
config.set("extensions", {});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
writeExtensionsToFirebaseJson(specs, config);
|
|
29
|
+
await writeEnvFiles(specs, config, options.force);
|
|
30
|
+
}
|
|
31
|
+
exports.writeToManifest = writeToManifest;
|
|
32
|
+
function writeExtensionsToFirebaseJson(specs, config) {
|
|
33
|
+
const extensions = config.get("extensions", {});
|
|
34
|
+
for (const s of specs) {
|
|
35
|
+
extensions[s.instanceId] = refs.toExtensionVersionRef(s.ref);
|
|
36
|
+
}
|
|
37
|
+
config.set("extensions", extensions);
|
|
38
|
+
logger_1.logger.info("Adding Extensions to " + clc.bold("firebase.json") + "...");
|
|
39
|
+
config.writeProjectFile("firebase.json", config.src);
|
|
40
|
+
}
|
|
41
|
+
async function writeEnvFiles(specs, config, force) {
|
|
42
|
+
for (const spec of specs) {
|
|
43
|
+
const content = Object.entries(spec.params)
|
|
44
|
+
.map((r) => `${r[0]}=${r[1]}`)
|
|
45
|
+
.join("\n");
|
|
46
|
+
await config.askWriteProjectFile(`extensions/${spec.instanceId}.env`, content, force);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -7,19 +7,19 @@ function parseTimeseriesResponse(series) {
|
|
|
7
7
|
const ret = [];
|
|
8
8
|
for (const s of series) {
|
|
9
9
|
const ref = buildRef(s);
|
|
10
|
-
if (ref
|
|
10
|
+
if (ref === undefined) {
|
|
11
11
|
continue;
|
|
12
12
|
}
|
|
13
13
|
let valueToday;
|
|
14
14
|
let value7dAgo;
|
|
15
15
|
let value28dAgo;
|
|
16
|
-
if (s.points.length >= 28 && s.points[27].value.int64Value
|
|
16
|
+
if (s.points.length >= 28 && s.points[27].value.int64Value !== undefined) {
|
|
17
17
|
value28dAgo = parseBucket(s.points[27].value.int64Value);
|
|
18
18
|
}
|
|
19
|
-
if (s.points.length >= 7 && s.points[6].value.int64Value
|
|
19
|
+
if (s.points.length >= 7 && s.points[6].value.int64Value !== undefined) {
|
|
20
20
|
value7dAgo = parseBucket(s.points[6].value.int64Value);
|
|
21
21
|
}
|
|
22
|
-
if (s.points.length >= 1 && s.points[0].value.int64Value
|
|
22
|
+
if (s.points.length >= 1 && s.points[0].value.int64Value !== undefined) {
|
|
23
23
|
valueToday = parseBucket(s.points[0].value.int64Value);
|
|
24
24
|
}
|
|
25
25
|
ret.push({
|
|
@@ -49,7 +49,7 @@ async function getParams(args) {
|
|
|
49
49
|
const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
|
|
50
50
|
params = await askUserForParam.ask(args.projectId, args.instanceId, args.paramSpecs, firebaseProjectParams, !!args.reconfiguring);
|
|
51
51
|
}
|
|
52
|
-
track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
|
|
52
|
+
void track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
|
|
53
53
|
return params;
|
|
54
54
|
}
|
|
55
55
|
exports.getParams = getParams;
|
|
@@ -82,7 +82,7 @@ async function getParamsForUpdate(args) {
|
|
|
82
82
|
instanceId: args.instanceId,
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
|
-
track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
|
|
85
|
+
void track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
|
|
86
86
|
return params;
|
|
87
87
|
}
|
|
88
88
|
exports.getParamsForUpdate = getParamsForUpdate;
|
|
@@ -116,10 +116,10 @@ function getParamsFromFile(args) {
|
|
|
116
116
|
let envParams;
|
|
117
117
|
try {
|
|
118
118
|
envParams = readEnvFile(args.paramsEnvPath);
|
|
119
|
-
track("Extension Env File", "Present");
|
|
119
|
+
void track("Extension Env File", "Present");
|
|
120
120
|
}
|
|
121
121
|
catch (err) {
|
|
122
|
-
track("Extension Env File", "Invalid");
|
|
122
|
+
void track("Extension Env File", "Invalid");
|
|
123
123
|
throw new error_1.FirebaseError(`Error reading env file: ${err.message}\n`, { original: err });
|
|
124
124
|
}
|
|
125
125
|
const params = (0, extensionsHelper_1.populateDefaultParams)(envParams, args.paramSpecs);
|
package/lib/extensions/refs.js
CHANGED
|
@@ -20,7 +20,7 @@ function parse(refOrName) {
|
|
|
20
20
|
exports.parse = parse;
|
|
21
21
|
function parseRef(ref) {
|
|
22
22
|
const parts = refRegex.exec(ref);
|
|
23
|
-
if (parts && (parts.length
|
|
23
|
+
if (parts && (parts.length === 5 || parts.length === 7)) {
|
|
24
24
|
const publisherId = parts[1];
|
|
25
25
|
const extensionId = parts[2];
|
|
26
26
|
const version = parts[4];
|
|
@@ -15,14 +15,14 @@ async function ensureSecretManagerApiEnabled(options) {
|
|
|
15
15
|
}
|
|
16
16
|
exports.ensureSecretManagerApiEnabled = ensureSecretManagerApiEnabled;
|
|
17
17
|
function usesSecrets(spec) {
|
|
18
|
-
return spec.params && !!spec.params.find((p) => p.type
|
|
18
|
+
return spec.params && !!spec.params.find((p) => p.type === extensionsApi.ParamType.SECRET);
|
|
19
19
|
}
|
|
20
20
|
exports.usesSecrets = usesSecrets;
|
|
21
21
|
async function grantFirexServiceAgentSecretAdminRole(secret) {
|
|
22
22
|
const projectNumber = await (0, getProjectNumber_1.getProjectNumber)({ projectId: secret.projectId });
|
|
23
23
|
const firexSaProjectId = utils.envOverride("FIREBASE_EXTENSIONS_SA_PROJECT_ID", "gcp-sa-firebasemods");
|
|
24
24
|
const saEmail = `service-${projectNumber}@${firexSaProjectId}.iam.gserviceaccount.com`;
|
|
25
|
-
return secretManagerApi.
|
|
25
|
+
return secretManagerApi.ensureServiceAgentRole(secret, [saEmail], "roles/secretmanager.admin");
|
|
26
26
|
}
|
|
27
27
|
exports.grantFirexServiceAgentSecretAdminRole = grantFirexServiceAgentSecretAdminRole;
|
|
28
28
|
async function getManagedSecrets(instance) {
|
|
@@ -38,7 +38,7 @@ async function getManagedSecrets(instance) {
|
|
|
38
38
|
exports.getManagedSecrets = getManagedSecrets;
|
|
39
39
|
function getActiveSecrets(spec, params) {
|
|
40
40
|
return spec.params
|
|
41
|
-
.map((p) => (p.type
|
|
41
|
+
.map((p) => (p.type === extensionsApi.ParamType.SECRET ? params[p.param] : ""))
|
|
42
42
|
.filter((pv) => !!pv);
|
|
43
43
|
}
|
|
44
44
|
exports.getActiveSecrets = getActiveSecrets;
|
|
@@ -50,7 +50,7 @@ function getSecretLabels(instanceId) {
|
|
|
50
50
|
exports.getSecretLabels = getSecretLabels;
|
|
51
51
|
function prettySecretName(secretResourceName) {
|
|
52
52
|
const nameTokens = secretResourceName.split("/");
|
|
53
|
-
if (nameTokens.length
|
|
53
|
+
if (nameTokens.length !== 4 && nameTokens.length !== 6) {
|
|
54
54
|
logger_1.logger.debug(`unable to parse secret secretResourceName: ${secretResourceName}`);
|
|
55
55
|
return secretResourceName;
|
|
56
56
|
}
|
package/lib/functional.js
CHANGED
|
@@ -40,7 +40,7 @@ function reduceFlat(accum, next) {
|
|
|
40
40
|
}
|
|
41
41
|
exports.reduceFlat = reduceFlat;
|
|
42
42
|
function* zip(left, right) {
|
|
43
|
-
if (left.length
|
|
43
|
+
if (left.length !== right.length) {
|
|
44
44
|
throw new Error("Cannot zip between two lists of differen lengths");
|
|
45
45
|
}
|
|
46
46
|
for (let i = 0; i < left.length; i++) {
|
package/lib/functions/env.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
3
|
+
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const error_1 = require("../error");
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
|
-
const previews_1 = require("../previews");
|
|
10
9
|
const utils_1 = require("../utils");
|
|
11
10
|
const FUNCTIONS_EMULATOR_DOTENV = ".env.local";
|
|
11
|
+
const RESERVED_PREFIXES = ["X_GOOGLE_", "FIREBASE_", "EXT_"];
|
|
12
12
|
const RESERVED_KEYS = [
|
|
13
13
|
"FIREBASE_CONFIG",
|
|
14
14
|
"CLOUD_RUNTIME_CONFIG",
|
|
15
|
+
"EVENTARC_CLOUD_EVENT_SOURCE",
|
|
15
16
|
"ENTRY_POINT",
|
|
16
17
|
"GCP_PROJECT",
|
|
17
18
|
"GCLOUD_PROJECT",
|
|
@@ -87,8 +88,8 @@ function validateKey(key) {
|
|
|
87
88
|
throw new KeyValidationError(key, `Key ${key} must start with an uppercase ASCII letter or underscore` +
|
|
88
89
|
", and then consist of uppercase ASCII letters, digits, and underscores.");
|
|
89
90
|
}
|
|
90
|
-
if (
|
|
91
|
-
throw new KeyValidationError(key, `Key ${key} starts with a reserved prefix (
|
|
91
|
+
if (RESERVED_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
92
|
+
throw new KeyValidationError(key, `Key ${key} starts with a reserved prefix (${RESERVED_PREFIXES.join(" ")})`);
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
exports.validateKey = validateKey;
|
|
@@ -117,6 +118,7 @@ function parseStrict(data) {
|
|
|
117
118
|
}
|
|
118
119
|
return envs;
|
|
119
120
|
}
|
|
121
|
+
exports.parseStrict = parseStrict;
|
|
120
122
|
function findEnvfiles(functionsSource, projectId, projectAlias, isEmulator) {
|
|
121
123
|
const files = [".env"];
|
|
122
124
|
if (isEmulator) {
|
|
@@ -139,11 +141,8 @@ function hasUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, })
|
|
|
139
141
|
exports.hasUserEnvs = hasUserEnvs;
|
|
140
142
|
function loadUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, }) {
|
|
141
143
|
var _a;
|
|
142
|
-
if (!previews_1.previews.dotenv) {
|
|
143
|
-
return {};
|
|
144
|
-
}
|
|
145
144
|
const envFiles = findEnvfiles(functionsSource, projectId, projectAlias, isEmulator);
|
|
146
|
-
if (envFiles.length
|
|
145
|
+
if (envFiles.length === 0) {
|
|
147
146
|
return {};
|
|
148
147
|
}
|
|
149
148
|
if (projectAlias) {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pruneSecrets = exports.of = exports.ensureSecret = exports.ensureValidKey = exports.labels = exports.isFirebaseManaged = void 0;
|
|
4
|
+
const secretManager_1 = require("../gcp/secretManager");
|
|
5
|
+
const error_1 = require("../error");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const prompt_1 = require("../prompt");
|
|
8
|
+
const env_1 = require("./env");
|
|
9
|
+
const FIREBASE_MANGED = "firebase-managed";
|
|
10
|
+
function isFirebaseManaged(secret) {
|
|
11
|
+
return Object.keys(secret.labels || []).includes(FIREBASE_MANGED);
|
|
12
|
+
}
|
|
13
|
+
exports.isFirebaseManaged = isFirebaseManaged;
|
|
14
|
+
function labels() {
|
|
15
|
+
return { [FIREBASE_MANGED]: "true" };
|
|
16
|
+
}
|
|
17
|
+
exports.labels = labels;
|
|
18
|
+
function toUpperSnakeCase(key) {
|
|
19
|
+
return key
|
|
20
|
+
.replace("-", "_")
|
|
21
|
+
.replace(".", "_")
|
|
22
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
23
|
+
.toUpperCase();
|
|
24
|
+
}
|
|
25
|
+
async function ensureValidKey(key, options) {
|
|
26
|
+
const transformedKey = toUpperSnakeCase(key);
|
|
27
|
+
if (transformedKey !== key) {
|
|
28
|
+
if (options.force) {
|
|
29
|
+
throw new error_1.FirebaseError("Secret key must be in UPPER_SNAKE_CASE.");
|
|
30
|
+
}
|
|
31
|
+
(0, utils_1.logWarning)(`By convention, secret key must be in UPPER_SNAKE_CASE.`);
|
|
32
|
+
const confirm = await (0, prompt_1.promptOnce)({
|
|
33
|
+
name: "updateKey",
|
|
34
|
+
type: "confirm",
|
|
35
|
+
default: true,
|
|
36
|
+
message: `Would you like to use ${transformedKey} as key instead?`,
|
|
37
|
+
}, options);
|
|
38
|
+
if (!confirm) {
|
|
39
|
+
throw new error_1.FirebaseError("Secret key must be in UPPER_SNAKE_CASE.");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
(0, env_1.validateKey)(transformedKey);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
throw new error_1.FirebaseError(`Invalid secret key ${transformedKey}`, { children: [err] });
|
|
47
|
+
}
|
|
48
|
+
return transformedKey;
|
|
49
|
+
}
|
|
50
|
+
exports.ensureValidKey = ensureValidKey;
|
|
51
|
+
async function ensureSecret(projectId, name, options) {
|
|
52
|
+
try {
|
|
53
|
+
const secret = await (0, secretManager_1.getSecret)(projectId, name);
|
|
54
|
+
if (!isFirebaseManaged(secret)) {
|
|
55
|
+
if (!options.force) {
|
|
56
|
+
(0, utils_1.logWarning)("Your secret is not managed by Firebase. " +
|
|
57
|
+
"Firebase managed secrets are automatically pruned to reduce your monthly cost for using Secret Manager. ");
|
|
58
|
+
const confirm = await (0, prompt_1.promptOnce)({
|
|
59
|
+
name: "updateLabels",
|
|
60
|
+
type: "confirm",
|
|
61
|
+
default: true,
|
|
62
|
+
message: `Would you like to have your secret ${secret.name} managed by Firebase?`,
|
|
63
|
+
}, options);
|
|
64
|
+
if (confirm) {
|
|
65
|
+
return (0, secretManager_1.patchSecret)(projectId, secret.name, Object.assign(Object.assign({}, secret.labels), labels()));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return secret;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
if (err.status !== 404) {
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return await (0, secretManager_1.createSecret)(projectId, name, labels());
|
|
77
|
+
}
|
|
78
|
+
exports.ensureSecret = ensureSecret;
|
|
79
|
+
function of(endpoints) {
|
|
80
|
+
return endpoints.reduce((envs, endpoint) => [...envs, ...(endpoint.secretEnvironmentVariables || [])], []);
|
|
81
|
+
}
|
|
82
|
+
exports.of = of;
|
|
83
|
+
async function pruneSecrets(projectInfo, endpoints) {
|
|
84
|
+
const { projectId, projectNumber } = projectInfo;
|
|
85
|
+
const pruneKey = (name, version) => `${name}@${version}`;
|
|
86
|
+
const prunedSecrets = new Set();
|
|
87
|
+
const haveSecrets = await (0, secretManager_1.listSecrets)(projectId, `labels.${FIREBASE_MANGED}=true`);
|
|
88
|
+
for (const secret of haveSecrets) {
|
|
89
|
+
const versions = await (0, secretManager_1.listSecretVersions)(projectId, secret.name, `state: ENABLED`);
|
|
90
|
+
for (const version of versions) {
|
|
91
|
+
prunedSecrets.add(pruneKey(secret.name, version.versionId));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const sevs = of(endpoints).filter((sev) => sev.projectId === projectId || sev.projectId === projectNumber);
|
|
95
|
+
for (const sev of sevs) {
|
|
96
|
+
let name = sev.secret;
|
|
97
|
+
if (name.includes("/")) {
|
|
98
|
+
const secret = (0, secretManager_1.parseSecretResourceName)(name);
|
|
99
|
+
name = secret.name;
|
|
100
|
+
}
|
|
101
|
+
let version = sev.version;
|
|
102
|
+
if (version === "latest") {
|
|
103
|
+
const resolved = await (0, secretManager_1.getSecretVersion)(projectId, name, version);
|
|
104
|
+
version = resolved.versionId;
|
|
105
|
+
}
|
|
106
|
+
prunedSecrets.delete(pruneKey(name, version));
|
|
107
|
+
}
|
|
108
|
+
return Array.from(prunedSecrets)
|
|
109
|
+
.map((key) => key.split("@"))
|
|
110
|
+
.map(([secret, version]) => ({ projectId, version, secret, key: secret }));
|
|
111
|
+
}
|
|
112
|
+
exports.pruneSecrets = pruneSecrets;
|