firebase-tools 10.2.0 → 10.3.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/apiv2.js +3 -0
- package/lib/appdistribution/options-parser-util.js +1 -1
- package/lib/auth.js +3 -3
- 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 +58 -4
- package/lib/commands/ext-dev-init.js +49 -49
- package/lib/commands/ext-export.js +7 -2
- package/lib/commands/ext-install.js +163 -104
- package/lib/commands/ext-uninstall.js +17 -8
- package/lib/commands/ext-update.js +64 -11
- package/lib/commands/functions-config-clone.js +1 -1
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/hosting-clone.js +3 -3
- package/lib/commands/remoteconfig-get.js +1 -1
- package/lib/config.js +6 -3
- package/lib/deploy/extensions/deploymentSummary.js +3 -3
- package/lib/deploy/extensions/planner.js +7 -6
- package/lib/deploy/extensions/tasks.js +1 -1
- package/lib/deploy/functions/backend.js +21 -5
- package/lib/deploy/functions/checkIam.js +5 -5
- package/lib/deploy/functions/containerCleaner.js +3 -3
- package/lib/deploy/functions/ensure.js +3 -3
- package/lib/deploy/functions/functionsDeployHelper.js +2 -2
- package/lib/deploy/functions/prepare.js +5 -3
- package/lib/deploy/functions/pricing.js +1 -1
- package/lib/deploy/functions/prompts.js +2 -2
- package/lib/deploy/functions/release/fabricator.js +7 -7
- package/lib/deploy/functions/release/index.js +1 -1
- package/lib/deploy/functions/release/planner.js +43 -26
- 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 +22 -12
- package/lib/deploy/functions/runtimes/golang/index.js +2 -2
- package/lib/deploy/functions/runtimes/node/index.js +53 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +52 -15
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
- package/lib/deploy/functions/services/index.js +9 -1
- package/lib/deploy/functions/services/storage.js +10 -4
- package/lib/deploy/functions/triggerRegionHelper.js +1 -1
- package/lib/deploy/functions/validate.js +3 -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 +4 -0
- package/lib/emulator/controller.js +54 -24
- package/lib/emulator/download.js +18 -1
- package/lib/emulator/downloadableEmulators.js +30 -13
- package/lib/emulator/emulatorLogger.js +12 -1
- package/lib/emulator/extensions/validation.js +70 -0
- package/lib/emulator/extensionsEmulator.js +175 -0
- package/lib/emulator/functionsEmulator.js +106 -44
- package/lib/emulator/functionsEmulatorRuntime.js +44 -36
- package/lib/emulator/functionsEmulatorShared.js +17 -10
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/functionsEmulatorUtils.js +4 -4
- package/lib/emulator/functionsRuntimeWorker.js +2 -2
- 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 +314 -332
- package/lib/emulator/storage/apis/gcloud.js +241 -121
- package/lib/emulator/storage/crc.js +5 -1
- package/lib/emulator/storage/errors.js +9 -0
- package/lib/emulator/storage/files.js +159 -300
- package/lib/emulator/storage/index.js +27 -73
- package/lib/emulator/storage/metadata.js +65 -51
- package/lib/emulator/storage/multipart.js +62 -0
- package/lib/emulator/storage/persistence.js +78 -0
- package/lib/emulator/storage/rules/config.js +33 -0
- package/lib/emulator/storage/rules/manager.js +81 -0
- package/lib/emulator/storage/rules/runtime.js +8 -7
- package/lib/emulator/storage/rules/utils.js +48 -0
- package/lib/emulator/storage/server.js +2 -2
- package/lib/emulator/storage/upload.js +106 -0
- package/lib/emulator/types.js +3 -0
- package/lib/ensureApiEnabled.js +5 -1
- package/lib/error.js +1 -1
- package/lib/extensions/askUserForParam.js +1 -1
- package/lib/extensions/changelog.js +3 -1
- package/lib/extensions/checkProjectBilling.js +1 -1
- package/lib/extensions/displayExtensionInfo.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +56 -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 +32 -19
- package/lib/extensions/listExtensions.js +2 -0
- package/lib/extensions/manifest.js +144 -0
- package/lib/extensions/metricsUtils.js +4 -4
- package/lib/extensions/paramHelper.js +9 -8
- package/lib/extensions/refs.js +1 -1
- package/lib/extensions/secretsUtils.js +3 -3
- package/lib/functional.js +1 -1
- package/lib/functions/env.js +6 -7
- package/lib/functions/events/v2.js +11 -0
- package/lib/gcp/cloudfunctions.js +42 -11
- package/lib/gcp/cloudfunctionsv2.js +48 -17
- package/lib/gcp/cloudtasks.js +1 -1
- package/lib/gcp/docker.js +2 -2
- package/lib/gcp/resourceManager.js +4 -4
- package/lib/gcp/run.js +2 -2
- 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 -1
- package/lib/serve/hosting.js +1 -1
- package/lib/utils.js +15 -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
- package/lib/deploy/extensions/params.js +0 -39
- package/lib/deploy/functions/eventTypes.js +0 -10
|
@@ -58,7 +58,7 @@ function createApp(defaultProjectId, emulator) {
|
|
|
58
58
|
}
|
|
59
59
|
const name = file.name;
|
|
60
60
|
const content = file.content;
|
|
61
|
-
const issues = await emulator.
|
|
61
|
+
const issues = await emulator.setRules({ name, content });
|
|
62
62
|
if (issues.errors.length > 0) {
|
|
63
63
|
res.status(400).json({
|
|
64
64
|
message: "There was an error updating rules, see logs for more details",
|
|
@@ -70,7 +70,7 @@ function createApp(defaultProjectId, emulator) {
|
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
app.post("/internal/reset", (req, res) => {
|
|
73
|
-
|
|
73
|
+
emulator.reset();
|
|
74
74
|
res.sendStatus(200);
|
|
75
75
|
});
|
|
76
76
|
app.use("/v0", (0, firebase_1.createFirebaseEndpoints)(emulator));
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UploadService = exports.NotCancellableError = exports.UploadNotActiveError = exports.UploadStatus = exports.UploadType = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
var UploadType;
|
|
7
|
+
(function (UploadType) {
|
|
8
|
+
UploadType[UploadType["MULTIPART"] = 0] = "MULTIPART";
|
|
9
|
+
UploadType[UploadType["RESUMABLE"] = 1] = "RESUMABLE";
|
|
10
|
+
})(UploadType = exports.UploadType || (exports.UploadType = {}));
|
|
11
|
+
var UploadStatus;
|
|
12
|
+
(function (UploadStatus) {
|
|
13
|
+
UploadStatus[UploadStatus["ACTIVE"] = 0] = "ACTIVE";
|
|
14
|
+
UploadStatus[UploadStatus["CANCELLED"] = 1] = "CANCELLED";
|
|
15
|
+
UploadStatus[UploadStatus["FINISHED"] = 2] = "FINISHED";
|
|
16
|
+
})(UploadStatus = exports.UploadStatus || (exports.UploadStatus = {}));
|
|
17
|
+
class UploadNotActiveError extends Error {
|
|
18
|
+
}
|
|
19
|
+
exports.UploadNotActiveError = UploadNotActiveError;
|
|
20
|
+
class NotCancellableError extends Error {
|
|
21
|
+
}
|
|
22
|
+
exports.NotCancellableError = NotCancellableError;
|
|
23
|
+
class UploadService {
|
|
24
|
+
constructor(_persistence) {
|
|
25
|
+
this._persistence = _persistence;
|
|
26
|
+
this.reset();
|
|
27
|
+
}
|
|
28
|
+
reset() {
|
|
29
|
+
this._uploads = new Map();
|
|
30
|
+
}
|
|
31
|
+
multipartUpload(request) {
|
|
32
|
+
const upload = this.startMultipartUpload(request, request.dataRaw.byteLength);
|
|
33
|
+
this._persistence.deleteFile(upload.path, true);
|
|
34
|
+
this._persistence.appendBytes(upload.path, request.dataRaw);
|
|
35
|
+
return upload;
|
|
36
|
+
}
|
|
37
|
+
startMultipartUpload(request, sizeInBytes) {
|
|
38
|
+
const id = (0, uuid_1.v4)();
|
|
39
|
+
const upload = {
|
|
40
|
+
id: (0, uuid_1.v4)(),
|
|
41
|
+
bucketId: request.bucketId,
|
|
42
|
+
objectId: request.objectId,
|
|
43
|
+
type: UploadType.MULTIPART,
|
|
44
|
+
path: this.getStagingFileName(id, request.bucketId, request.objectId),
|
|
45
|
+
status: UploadStatus.FINISHED,
|
|
46
|
+
metadata: JSON.parse(request.metadataRaw),
|
|
47
|
+
size: sizeInBytes,
|
|
48
|
+
authorization: request.authorization,
|
|
49
|
+
};
|
|
50
|
+
this._uploads.set(upload.id, upload);
|
|
51
|
+
return upload;
|
|
52
|
+
}
|
|
53
|
+
startResumableUpload(request) {
|
|
54
|
+
const id = (0, uuid_1.v4)();
|
|
55
|
+
const upload = {
|
|
56
|
+
id: id,
|
|
57
|
+
bucketId: request.bucketId,
|
|
58
|
+
objectId: request.objectId,
|
|
59
|
+
type: UploadType.RESUMABLE,
|
|
60
|
+
path: this.getStagingFileName(id, request.bucketId, request.objectId),
|
|
61
|
+
status: UploadStatus.ACTIVE,
|
|
62
|
+
metadata: JSON.parse(request.metadataRaw),
|
|
63
|
+
size: 0,
|
|
64
|
+
authorization: request.authorization,
|
|
65
|
+
};
|
|
66
|
+
this._uploads.set(upload.id, upload);
|
|
67
|
+
this._persistence.deleteFile(upload.path, true);
|
|
68
|
+
return upload;
|
|
69
|
+
}
|
|
70
|
+
continueResumableUpload(uploadId, dataRaw) {
|
|
71
|
+
const upload = this.getResumableUpload(uploadId);
|
|
72
|
+
if (upload.status !== UploadStatus.ACTIVE) {
|
|
73
|
+
throw new UploadNotActiveError();
|
|
74
|
+
}
|
|
75
|
+
this._persistence.appendBytes(upload.path, dataRaw);
|
|
76
|
+
upload.size += dataRaw.byteLength;
|
|
77
|
+
return upload;
|
|
78
|
+
}
|
|
79
|
+
getResumableUpload(uploadId) {
|
|
80
|
+
const upload = this._uploads.get(uploadId);
|
|
81
|
+
if (!upload || upload.type !== UploadType.RESUMABLE) {
|
|
82
|
+
throw new errors_1.NotFoundError();
|
|
83
|
+
}
|
|
84
|
+
return upload;
|
|
85
|
+
}
|
|
86
|
+
cancelResumableUpload(uploadId) {
|
|
87
|
+
const upload = this.getResumableUpload(uploadId);
|
|
88
|
+
if (upload.status === UploadStatus.FINISHED) {
|
|
89
|
+
throw new NotCancellableError();
|
|
90
|
+
}
|
|
91
|
+
upload.status = UploadStatus.CANCELLED;
|
|
92
|
+
return upload;
|
|
93
|
+
}
|
|
94
|
+
finalizeResumableUpload(uploadId) {
|
|
95
|
+
const upload = this.getResumableUpload(uploadId);
|
|
96
|
+
if (upload.status === UploadStatus.CANCELLED) {
|
|
97
|
+
throw new UploadNotActiveError();
|
|
98
|
+
}
|
|
99
|
+
upload.status = UploadStatus.FINISHED;
|
|
100
|
+
return upload;
|
|
101
|
+
}
|
|
102
|
+
getStagingFileName(uploadId, bucketId, objectId) {
|
|
103
|
+
return encodeURIComponent(`${uploadId}_b_${bucketId}_o_${objectId}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.UploadService = UploadService;
|
package/lib/emulator/types.js
CHANGED
|
@@ -13,6 +13,7 @@ var Emulators;
|
|
|
13
13
|
Emulators["UI"] = "ui";
|
|
14
14
|
Emulators["LOGGING"] = "logging";
|
|
15
15
|
Emulators["STORAGE"] = "storage";
|
|
16
|
+
Emulators["EXTENSIONS"] = "extensions";
|
|
16
17
|
})(Emulators = exports.Emulators || (exports.Emulators = {}));
|
|
17
18
|
exports.DOWNLOADABLE_EMULATORS = [
|
|
18
19
|
Emulators.FIRESTORE,
|
|
@@ -48,6 +49,7 @@ exports.EMULATORS_SUPPORTED_BY_UI = [
|
|
|
48
49
|
Emulators.FIRESTORE,
|
|
49
50
|
Emulators.FUNCTIONS,
|
|
50
51
|
Emulators.STORAGE,
|
|
52
|
+
Emulators.EXTENSIONS,
|
|
51
53
|
];
|
|
52
54
|
exports.EMULATORS_SUPPORTED_BY_USE_EMULATOR = [
|
|
53
55
|
Emulators.AUTH,
|
|
@@ -59,6 +61,7 @@ exports.ALL_EMULATORS = [
|
|
|
59
61
|
Emulators.HUB,
|
|
60
62
|
Emulators.UI,
|
|
61
63
|
Emulators.LOGGING,
|
|
64
|
+
Emulators.EXTENSIONS,
|
|
62
65
|
...exports.ALL_SERVICE_EMULATORS,
|
|
63
66
|
];
|
|
64
67
|
function isDownloadableEmulator(value) {
|
package/lib/ensureApiEnabled.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ensure = exports.check = exports.POLL_SETTINGS = void 0;
|
|
3
|
+
exports.enableApiURI = exports.ensure = exports.check = exports.POLL_SETTINGS = void 0;
|
|
4
4
|
const cli_color_1 = require("cli-color");
|
|
5
5
|
const track = require("./track");
|
|
6
6
|
const api_1 = require("./api");
|
|
@@ -75,3 +75,7 @@ async function ensure(projectId, apiName, prefix, silent = false) {
|
|
|
75
75
|
return enableApiWithRetries(projectId, apiName, prefix, silent);
|
|
76
76
|
}
|
|
77
77
|
exports.ensure = ensure;
|
|
78
|
+
function enableApiURI(projectId, apiName) {
|
|
79
|
+
return `https://console.cloud.google.com/apis/library/${apiName}?project=${projectId}`;
|
|
80
|
+
}
|
|
81
|
+
exports.enableApiURI = enableApiURI;
|
package/lib/error.js
CHANGED
|
@@ -23,7 +23,7 @@ function isBillingError(e) {
|
|
|
23
23
|
return !!((_d = (_c = (_b = (_a = e.context) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.find((d) => {
|
|
24
24
|
var _a;
|
|
25
25
|
return (((_a = d.violations) === null || _a === void 0 ? void 0 : _a.find((v) => v.type === "serviceusage/billing-enabled")) ||
|
|
26
|
-
d.reason
|
|
26
|
+
d.reason === "UREQ_PROJECT_BILLING_NOT_FOUND");
|
|
27
27
|
}));
|
|
28
28
|
}
|
|
29
29
|
exports.isBillingError = isBillingError;
|
|
@@ -20,7 +20,7 @@ var SecretUpdateAction;
|
|
|
20
20
|
function checkResponse(response, spec) {
|
|
21
21
|
let valid = true;
|
|
22
22
|
let responses;
|
|
23
|
-
if (spec.required && (response
|
|
23
|
+
if (spec.required && (response === "" || response === undefined)) {
|
|
24
24
|
utils.logWarning(`Param ${spec.param} is required, but no value was provided.`);
|
|
25
25
|
return false;
|
|
26
26
|
}
|
|
@@ -58,7 +58,9 @@ function breakingChangesInUpdate(versionsInUpdate) {
|
|
|
58
58
|
const semvers = versionsInUpdate.map((v) => semver.parse(v)).sort(semver.compare);
|
|
59
59
|
for (let i = 1; i < semvers.length; i++) {
|
|
60
60
|
const hasMajorBump = semvers[i - 1].major < semvers[i].major;
|
|
61
|
-
const hasMinorBumpInPreview = semvers[i - 1].major
|
|
61
|
+
const hasMinorBumpInPreview = semvers[i - 1].major === 0 &&
|
|
62
|
+
semvers[i].major === 0 &&
|
|
63
|
+
semvers[i - 1].minor < semvers[i].minor;
|
|
62
64
|
if (hasMajorBump || hasMinorBumpInPreview) {
|
|
63
65
|
breakingVersions.push(semvers[i].raw);
|
|
64
66
|
}
|
|
@@ -49,7 +49,7 @@ Please select the one that you would like to associate with this project:`,
|
|
|
49
49
|
billingEnabled = await openBillingAccount(projectId, billingURL, true);
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
|
-
const billingAccount = accounts.find((a) => a.displayName
|
|
52
|
+
const billingAccount = accounts.find((a) => a.displayName === answer);
|
|
53
53
|
billingEnabled = await cloudbilling.setBillingAccount(projectId, billingAccount.name);
|
|
54
54
|
}
|
|
55
55
|
return logBillingStatus(billingEnabled, projectId);
|
|
@@ -136,7 +136,7 @@ async function displayUpdateChangesRequiringConfirmation(args) {
|
|
|
136
136
|
}
|
|
137
137
|
exports.displayUpdateChangesRequiringConfirmation = displayUpdateChangesRequiringConfirmation;
|
|
138
138
|
function compareResources(resource1, resource2) {
|
|
139
|
-
return resource1.name
|
|
139
|
+
return resource1.name === resource2.name && resource1.type === resource2.type;
|
|
140
140
|
}
|
|
141
141
|
function getResourceReadableName(resource) {
|
|
142
142
|
return resource.type === "firebaseextensions.v1beta.function"
|
|
@@ -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.getSecretEnvVars = exports.getNonSecretEnv = exports.getExtensionFunctionInfo = exports.buildOptions = void 0;
|
|
4
4
|
const fs = require("fs-extra");
|
|
5
5
|
const _ = require("lodash");
|
|
6
6
|
const path = require("path");
|
|
@@ -8,6 +8,7 @@ const paramHelper = require("../paramHelper");
|
|
|
8
8
|
const specHelper = require("./specHelper");
|
|
9
9
|
const localHelper = require("../localHelper");
|
|
10
10
|
const triggerHelper = require("./triggerHelper");
|
|
11
|
+
const extensionsApi_1 = require("../extensionsApi");
|
|
11
12
|
const extensionsHelper = require("../extensionsHelper");
|
|
12
13
|
const config_1 = require("../../config");
|
|
13
14
|
const error_1 = require("../../error");
|
|
@@ -15,9 +16,9 @@ const emulatorLogger_1 = require("../../emulator/emulatorLogger");
|
|
|
15
16
|
const projectUtils_1 = require("../../projectUtils");
|
|
16
17
|
const types_1 = require("../../emulator/types");
|
|
17
18
|
async function buildOptions(options) {
|
|
18
|
-
const
|
|
19
|
-
options.
|
|
20
|
-
const spec = await specHelper.readExtensionYaml(
|
|
19
|
+
const extDevDir = localHelper.findExtensionYaml(process.cwd());
|
|
20
|
+
options.extDevDir = extDevDir;
|
|
21
|
+
const spec = await specHelper.readExtensionYaml(extDevDir);
|
|
21
22
|
extensionsHelper.validateSpec(spec);
|
|
22
23
|
const params = getParams(options, spec);
|
|
23
24
|
extensionsHelper.validateCommandLineParams(params, spec.params);
|
|
@@ -28,13 +29,60 @@ async function buildOptions(options) {
|
|
|
28
29
|
checkTestConfig(testConfig, functionResources);
|
|
29
30
|
}
|
|
30
31
|
options.config = buildConfig(functionResources, testConfig);
|
|
31
|
-
options.
|
|
32
|
+
options.extDevEnv = params;
|
|
32
33
|
const functionEmuTriggerDefs = functionResources.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r));
|
|
33
|
-
options.
|
|
34
|
-
options.
|
|
34
|
+
options.extDevTriggers = functionEmuTriggerDefs;
|
|
35
|
+
options.extDevNodeVersion = specHelper.getNodeVersion(functionResources);
|
|
35
36
|
return options;
|
|
36
37
|
}
|
|
37
38
|
exports.buildOptions = buildOptions;
|
|
39
|
+
async function getExtensionFunctionInfo(extensionDir, instanceId, paramValues) {
|
|
40
|
+
const spec = await specHelper.readExtensionYaml(extensionDir);
|
|
41
|
+
const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, paramValues);
|
|
42
|
+
const extensionTriggers = functionResources
|
|
43
|
+
.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r))
|
|
44
|
+
.map((trigger) => {
|
|
45
|
+
trigger.name = `ext-${instanceId}-${trigger.name}`;
|
|
46
|
+
return trigger;
|
|
47
|
+
});
|
|
48
|
+
const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
|
|
49
|
+
const nonSecretEnv = getNonSecretEnv(spec.params, paramValues);
|
|
50
|
+
const secretEnvVariables = getSecretEnvVars(spec.params, paramValues);
|
|
51
|
+
return {
|
|
52
|
+
extensionTriggers,
|
|
53
|
+
nodeMajorVersion,
|
|
54
|
+
nonSecretEnv,
|
|
55
|
+
secretEnvVariables,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
exports.getExtensionFunctionInfo = getExtensionFunctionInfo;
|
|
59
|
+
const isSecretParam = (p) => p.type === extensionsHelper.SpecParamType.SECRET || p.type === extensionsApi_1.ParamType.SECRET;
|
|
60
|
+
function getNonSecretEnv(params, paramValues) {
|
|
61
|
+
const getNonSecretEnv = Object.assign({}, paramValues);
|
|
62
|
+
const secretParams = params.filter(isSecretParam);
|
|
63
|
+
for (const p of secretParams) {
|
|
64
|
+
delete getNonSecretEnv[p.param];
|
|
65
|
+
}
|
|
66
|
+
return getNonSecretEnv;
|
|
67
|
+
}
|
|
68
|
+
exports.getNonSecretEnv = getNonSecretEnv;
|
|
69
|
+
function getSecretEnvVars(params, paramValues) {
|
|
70
|
+
const secretEnvVar = [];
|
|
71
|
+
const secretParams = params.filter(isSecretParam);
|
|
72
|
+
for (const s of secretParams) {
|
|
73
|
+
if (paramValues[s.param]) {
|
|
74
|
+
const [, projectId, , secret, , version] = paramValues[s.param].split("/");
|
|
75
|
+
secretEnvVar.push({
|
|
76
|
+
key: s.param,
|
|
77
|
+
secret,
|
|
78
|
+
projectId,
|
|
79
|
+
version,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return secretEnvVar;
|
|
84
|
+
}
|
|
85
|
+
exports.getSecretEnvVars = getSecretEnvVars;
|
|
38
86
|
function getParams(options, extensionSpec) {
|
|
39
87
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
40
88
|
const userParams = paramHelper.readEnvFile(options.testParams);
|
|
@@ -120,7 +168,7 @@ function getFunctionSourceDirectory(functionResources) {
|
|
|
120
168
|
if (!sourceDirectory) {
|
|
121
169
|
sourceDirectory = dir;
|
|
122
170
|
}
|
|
123
|
-
else if (sourceDirectory
|
|
171
|
+
else if (sourceDirectory !== dir) {
|
|
124
172
|
throw new error_1.FirebaseError(`Found function resources with different sourceDirectories: '${sourceDirectory}' and '${dir}'. The extensions emulator only supports a single sourceDirectory.`);
|
|
125
173
|
}
|
|
126
174
|
}
|
|
@@ -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,
|
|
@@ -14,6 +14,7 @@ const api_1 = require("../api");
|
|
|
14
14
|
const archiveDirectory_1 = require("../archiveDirectory");
|
|
15
15
|
const utils_1 = require("./utils");
|
|
16
16
|
const functionsConfig_1 = require("../functionsConfig");
|
|
17
|
+
const adminSdkConfig_1 = require("../emulator/adminSdkConfig");
|
|
17
18
|
const resolveSource_1 = require("./resolveSource");
|
|
18
19
|
const error_1 = require("../error");
|
|
19
20
|
const diagnose_1 = require("./diagnose");
|
|
@@ -29,6 +30,7 @@ const logger_1 = require("../logger");
|
|
|
29
30
|
const utils_2 = require("../utils");
|
|
30
31
|
const changelog_1 = require("./changelog");
|
|
31
32
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
33
|
+
const constants_1 = require("../emulator/constants");
|
|
32
34
|
var SpecParamType;
|
|
33
35
|
(function (SpecParamType) {
|
|
34
36
|
SpecParamType["SELECT"] = "select";
|
|
@@ -76,21 +78,28 @@ function getDBInstanceFromURL(databaseUrl = "") {
|
|
|
76
78
|
return "";
|
|
77
79
|
}
|
|
78
80
|
exports.getDBInstanceFromURL = getDBInstanceFromURL;
|
|
79
|
-
async function getFirebaseProjectParams(projectId) {
|
|
80
|
-
|
|
81
|
-
const
|
|
81
|
+
async function getFirebaseProjectParams(projectId, emulatorMode = false) {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
const body = emulatorMode
|
|
84
|
+
? await (0, adminSdkConfig_1.getProjectAdminSdkConfigOrCached)(projectId)
|
|
85
|
+
: await (0, functionsConfig_1.getFirebaseConfig)({ project: projectId });
|
|
86
|
+
const projectNumber = emulatorMode && constants_1.Constants.isDemoProject(projectId)
|
|
87
|
+
? constants_1.Constants.FAKE_PROJECT_NUMBER
|
|
88
|
+
: await (0, getProjectNumber_1.getProjectNumber)({ projectId });
|
|
89
|
+
const databaseURL = (_a = body === null || body === void 0 ? void 0 : body.databaseURL) !== null && _a !== void 0 ? _a : `https://${projectId}.firebaseio.com`;
|
|
90
|
+
const storageBucket = (_b = body === null || body === void 0 ? void 0 : body.storageBucket) !== null && _b !== void 0 ? _b : `${projectId}.appspot.com`;
|
|
82
91
|
const FIREBASE_CONFIG = JSON.stringify({
|
|
83
|
-
projectId
|
|
84
|
-
databaseURL
|
|
85
|
-
storageBucket
|
|
92
|
+
projectId,
|
|
93
|
+
databaseURL,
|
|
94
|
+
storageBucket,
|
|
86
95
|
});
|
|
87
96
|
return {
|
|
88
|
-
PROJECT_ID:
|
|
97
|
+
PROJECT_ID: projectId,
|
|
89
98
|
PROJECT_NUMBER: projectNumber,
|
|
90
|
-
DATABASE_URL:
|
|
91
|
-
STORAGE_BUCKET:
|
|
99
|
+
DATABASE_URL: databaseURL,
|
|
100
|
+
STORAGE_BUCKET: storageBucket,
|
|
92
101
|
FIREBASE_CONFIG,
|
|
93
|
-
DATABASE_INSTANCE: getDBInstanceFromURL(
|
|
102
|
+
DATABASE_INSTANCE: getDBInstanceFromURL(databaseURL),
|
|
94
103
|
};
|
|
95
104
|
}
|
|
96
105
|
exports.getFirebaseProjectParams = getFirebaseProjectParams;
|
|
@@ -112,7 +121,7 @@ function populateDefaultParams(paramVars, paramSpecs) {
|
|
|
112
121
|
const newParams = paramVars;
|
|
113
122
|
for (const param of paramSpecs) {
|
|
114
123
|
if (!paramVars[param.param]) {
|
|
115
|
-
if (param.default
|
|
124
|
+
if (param.default !== undefined && param.required) {
|
|
116
125
|
newParams[param.param] = param.default;
|
|
117
126
|
}
|
|
118
127
|
else if (param.required) {
|
|
@@ -197,13 +206,13 @@ function validateSpec(spec) {
|
|
|
197
206
|
if (param.type && !_.includes(SpecParamType, param.type)) {
|
|
198
207
|
errors.push(`Invalid type ${param.type} for param${param.param ? ` ${param.param}` : ""}. Valid types are ${_.values(SpecParamType).join(", ")}`);
|
|
199
208
|
}
|
|
200
|
-
if (!param.type || param.type
|
|
209
|
+
if (!param.type || param.type === SpecParamType.STRING) {
|
|
201
210
|
if (param.options) {
|
|
202
211
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} cannot have options because it is type STRING`);
|
|
203
212
|
}
|
|
204
213
|
}
|
|
205
214
|
if (param.type &&
|
|
206
|
-
(param.type
|
|
215
|
+
(param.type === SpecParamType.SELECT || param.type === SpecParamType.MULTISELECT)) {
|
|
207
216
|
if (param.validationRegex) {
|
|
208
217
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} cannot have validationRegex because it is type ${param.type}`);
|
|
209
218
|
}
|
|
@@ -211,12 +220,12 @@ function validateSpec(spec) {
|
|
|
211
220
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} requires options because it is type ${param.type}`);
|
|
212
221
|
}
|
|
213
222
|
for (const opt of param.options || []) {
|
|
214
|
-
if (opt.value
|
|
223
|
+
if (opt.value === undefined) {
|
|
215
224
|
errors.push(`Option for param${param.param ? ` ${param.param}` : ""} is missing required field: value`);
|
|
216
225
|
}
|
|
217
226
|
}
|
|
218
227
|
}
|
|
219
|
-
if (param.type && param.type
|
|
228
|
+
if (param.type && param.type === SpecParamType.SELECTRESOURCE) {
|
|
220
229
|
if (!param.resourceType) {
|
|
221
230
|
errors.push(`Param${param.param ? ` ${param.param}` : ""} must have resourceType because it is type ${param.type}`);
|
|
222
231
|
}
|
|
@@ -268,7 +277,7 @@ async function archiveAndUploadSource(extPath, bucketName) {
|
|
|
268
277
|
}
|
|
269
278
|
async function publishExtensionVersionFromLocalSource(args) {
|
|
270
279
|
const extensionSpec = await (0, localHelper_1.getLocalExtensionSpec)(args.rootDirectory);
|
|
271
|
-
if (extensionSpec.name
|
|
280
|
+
if (extensionSpec.name !== args.extensionId) {
|
|
272
281
|
throw new error_1.FirebaseError(`Extension ID '${clc.bold(args.extensionId)}' does not match the name in extension.yaml '${clc.bold(extensionSpec.name)}'.`);
|
|
273
282
|
}
|
|
274
283
|
const subbedSpec = JSON.parse(JSON.stringify(extensionSpec));
|
|
@@ -325,7 +334,9 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
325
334
|
}
|
|
326
335
|
catch (err) {
|
|
327
336
|
uploadSpinner.fail();
|
|
328
|
-
throw err
|
|
337
|
+
throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
|
|
338
|
+
original: err,
|
|
339
|
+
});
|
|
329
340
|
}
|
|
330
341
|
const publishSpinner = ora(`Publishing ${clc.bold(ref)}`);
|
|
331
342
|
let res;
|
|
@@ -336,7 +347,7 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
336
347
|
}
|
|
337
348
|
catch (err) {
|
|
338
349
|
publishSpinner.fail();
|
|
339
|
-
if (err.status
|
|
350
|
+
if (err.status === 404) {
|
|
340
351
|
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.`));
|
|
341
352
|
}
|
|
342
353
|
throw err;
|
|
@@ -360,7 +371,9 @@ async function createSourceFromLocation(projectId, sourceUri) {
|
|
|
360
371
|
}
|
|
361
372
|
catch (err) {
|
|
362
373
|
uploadSpinner.fail();
|
|
363
|
-
throw err
|
|
374
|
+
throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
|
|
375
|
+
original: err,
|
|
376
|
+
});
|
|
364
377
|
}
|
|
365
378
|
}
|
|
366
379
|
else {
|
|
@@ -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;
|