firebase-tools 10.4.2 → 10.7.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/bin/firebase.js +1 -1
- package/lib/command.js +4 -4
- package/lib/commands/deploy.js +1 -1
- package/lib/commands/emulators-start.js +13 -3
- package/lib/commands/ext-configure.js +15 -5
- package/lib/commands/ext-dev-emulators-start.js +5 -1
- package/lib/commands/ext-export.js +6 -5
- package/lib/commands/ext-install.js +28 -44
- package/lib/commands/ext-update.js +9 -1
- package/lib/commands/functions-delete.js +2 -5
- package/lib/commands/functions-secrets-destroy.js +23 -3
- package/lib/commands/functions-secrets-prune.js +15 -12
- package/lib/commands/functions-secrets-set.js +51 -4
- package/lib/commands/hosting-channel-deploy.js +2 -2
- package/lib/deploy/database/deploy.js +4 -0
- package/lib/deploy/database/index.js +1 -0
- package/lib/deploy/extensions/deploy.js +4 -4
- package/lib/deploy/extensions/deploymentSummary.js +8 -5
- package/lib/deploy/extensions/planner.js +36 -9
- package/lib/deploy/extensions/prepare.js +1 -1
- package/lib/deploy/extensions/secrets.js +2 -2
- package/lib/deploy/extensions/tasks.js +60 -21
- package/lib/deploy/functions/backend.js +17 -6
- package/lib/deploy/functions/build.js +162 -0
- package/lib/deploy/functions/checkIam.js +6 -5
- package/lib/deploy/functions/deploy.js +14 -15
- package/lib/deploy/functions/ensure.js +4 -4
- package/lib/deploy/functions/functionsDeployHelper.js +54 -23
- package/lib/deploy/functions/prepare.js +92 -39
- package/lib/deploy/functions/prepareFunctionsUpload.js +16 -21
- package/lib/deploy/functions/pricing.js +6 -3
- package/lib/deploy/functions/prompts.js +1 -7
- package/lib/deploy/functions/release/fabricator.js +44 -5
- package/lib/deploy/functions/release/index.js +31 -6
- package/lib/deploy/functions/release/planner.js +10 -8
- package/lib/deploy/functions/release/reporter.js +14 -11
- package/lib/deploy/functions/runtimes/discovery/parsing.js +12 -6
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +61 -13
- package/lib/deploy/functions/runtimes/node/index.js +1 -1
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +29 -24
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/services/auth.js +95 -0
- package/lib/deploy/functions/services/index.js +41 -21
- package/lib/deploy/functions/services/storage.js +1 -6
- package/lib/deploy/functions/validate.js +8 -5
- package/lib/deploy/hosting/args.js +2 -0
- package/lib/deploy/hosting/convertConfig.js +37 -8
- package/lib/deploy/hosting/deploy.js +3 -3
- package/lib/deploy/hosting/prepare.js +2 -2
- package/lib/deploy/hosting/release.js +6 -2
- package/lib/deploy/index.js +82 -93
- package/lib/deploy/remoteconfig/deploy.js +4 -0
- package/lib/deploy/remoteconfig/index.js +3 -1
- package/lib/emulator/auth/operations.js +26 -20
- package/lib/emulator/auth/state.js +79 -43
- package/lib/emulator/auth/utils.js +3 -25
- package/lib/emulator/commandUtils.js +72 -2
- package/lib/emulator/controller.js +14 -5
- package/lib/emulator/downloadableEmulators.js +47 -24
- package/lib/emulator/extensions/postinstall.js +41 -0
- package/lib/emulator/extensions/validation.js +2 -2
- package/lib/emulator/extensionsEmulator.js +85 -21
- package/lib/emulator/functionsEmulator.js +79 -7
- package/lib/emulator/functionsEmulatorShared.js +36 -21
- package/lib/emulator/registry.js +34 -12
- package/lib/emulator/shared/request.js +19 -0
- package/lib/emulator/storage/apis/firebase.js +32 -35
- package/lib/emulator/storage/apis/gcloud.js +84 -66
- package/lib/emulator/storage/files.js +56 -52
- package/lib/emulator/storage/index.js +23 -3
- package/lib/emulator/storage/metadata.js +18 -8
- package/lib/emulator/storage/rules/manager.js +7 -17
- package/lib/emulator/storage/rules/utils.js +11 -3
- package/lib/emulator/storage/server.js +38 -12
- package/lib/ensureApiEnabled.js +8 -4
- package/lib/extensions/askUserForParam.js +14 -11
- package/lib/extensions/changelog.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +9 -10
- package/lib/extensions/emulator/specHelper.js +7 -1
- package/lib/extensions/emulator/triggerHelper.js +11 -14
- package/lib/extensions/extensionsApi.js +2 -1
- package/lib/extensions/extensionsHelper.js +30 -24
- package/lib/extensions/manifest.js +28 -8
- package/lib/extensions/paramHelper.js +19 -13
- package/lib/extensions/provisioningHelper.js +2 -2
- package/lib/extensions/warnings.js +3 -3
- package/lib/functions/env.js +10 -2
- package/lib/functions/events/index.js +7 -0
- package/lib/functions/events/v1.js +6 -0
- package/lib/functions/projectConfig.js +24 -3
- package/lib/functions/runtimeConfigExport.js +10 -6
- package/lib/functions/secrets.js +99 -6
- package/lib/gcp/cloudfunctions.js +37 -18
- package/lib/gcp/cloudfunctionsv2.js +41 -25
- package/lib/gcp/cloudtasks.js +5 -3
- package/lib/gcp/identityPlatform.js +44 -0
- package/lib/gcp/secretManager.js +2 -2
- package/lib/metaprogramming.js +2 -0
- package/lib/previews.js +1 -1
- package/lib/serve/hosting.js +25 -12
- package/lib/serve/index.js +6 -0
- package/lib/track.js +15 -21
- package/lib/utils.js +30 -1
- package/npm-shrinkwrap.json +44 -2
- package/package.json +4 -1
- package/schema/firebase-config.json +6 -0
- package/lib/emulator/storage/list.js +0 -18
|
@@ -5,6 +5,7 @@ const chokidar = require("chokidar");
|
|
|
5
5
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
6
6
|
const types_1 = require("../../types");
|
|
7
7
|
const runtime_1 = require("./runtime");
|
|
8
|
+
const fsutils_1 = require("../../../fsutils");
|
|
8
9
|
function createStorageRulesManager(rules, runtime) {
|
|
9
10
|
return Array.isArray(rules)
|
|
10
11
|
? new ResourceBasedStorageRulesManager(rules, runtime)
|
|
@@ -18,31 +19,24 @@ class DefaultStorageRulesManager {
|
|
|
18
19
|
this._logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE);
|
|
19
20
|
this._rules = _rules;
|
|
20
21
|
}
|
|
21
|
-
start() {
|
|
22
|
-
|
|
22
|
+
async start() {
|
|
23
|
+
const issues = await this.loadRuleset();
|
|
24
|
+
this.updateWatcher(this._rules.name);
|
|
25
|
+
return issues;
|
|
23
26
|
}
|
|
24
27
|
getRuleset() {
|
|
25
28
|
return this._ruleset;
|
|
26
29
|
}
|
|
27
|
-
async updateSourceFile(rules) {
|
|
28
|
-
const prevRulesFile = this._rules.name;
|
|
29
|
-
this._rules = rules;
|
|
30
|
-
const issues = await this.loadRuleset();
|
|
31
|
-
this.updateWatcher(rules.name, prevRulesFile);
|
|
32
|
-
return issues;
|
|
33
|
-
}
|
|
34
30
|
async stop() {
|
|
35
31
|
await this._watcher.close();
|
|
36
32
|
}
|
|
37
|
-
updateWatcher(rulesFile
|
|
38
|
-
if (prevRulesFile) {
|
|
39
|
-
this._watcher.unwatch(prevRulesFile);
|
|
40
|
-
}
|
|
33
|
+
updateWatcher(rulesFile) {
|
|
41
34
|
this._watcher = chokidar
|
|
42
35
|
.watch(rulesFile, { persistent: true, ignoreInitial: true })
|
|
43
36
|
.on("change", async () => {
|
|
44
37
|
await new Promise((res) => setTimeout(res, 5));
|
|
45
38
|
this._logger.logLabeled("BULLET", "storage", "Change detected, updating rules for Cloud Storage...");
|
|
39
|
+
this._rules.content = (0, fsutils_1.readFile)(rulesFile);
|
|
46
40
|
await this.loadRuleset();
|
|
47
41
|
});
|
|
48
42
|
}
|
|
@@ -83,10 +77,6 @@ class ResourceBasedStorageRulesManager {
|
|
|
83
77
|
var _a;
|
|
84
78
|
return (_a = this._rulesManagers.get(resource)) === null || _a === void 0 ? void 0 : _a.getRuleset();
|
|
85
79
|
}
|
|
86
|
-
updateSourceFile(rules, resource) {
|
|
87
|
-
const rulesManager = this._rulesManagers.get(resource) || this.createRulesManager(resource, rules);
|
|
88
|
-
return rulesManager.updateSourceFile(rules);
|
|
89
|
-
}
|
|
90
80
|
async stop() {
|
|
91
81
|
await Promise.all(Array.from(this._rulesManagers.values(), async (rulesManager) => await rulesManager.stop()));
|
|
92
82
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isPermitted = exports.getAdminCredentialValidator = exports.
|
|
3
|
+
exports.isPermitted = exports.getAdminCredentialValidator = exports.getAdminOnlyFirebaseRulesValidator = exports.getFirebaseRulesValidator = void 0;
|
|
4
4
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
5
5
|
const types_1 = require("../../types");
|
|
6
|
-
function
|
|
6
|
+
function getFirebaseRulesValidator(rulesetProvider) {
|
|
7
7
|
return {
|
|
8
8
|
validate: async (path, bucketId, method, variableOverrides, authorization) => {
|
|
9
9
|
return await isPermitted({
|
|
@@ -16,7 +16,15 @@ function getRulesValidator(rulesetProvider) {
|
|
|
16
16
|
},
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
exports.
|
|
19
|
+
exports.getFirebaseRulesValidator = getFirebaseRulesValidator;
|
|
20
|
+
function getAdminOnlyFirebaseRulesValidator() {
|
|
21
|
+
return {
|
|
22
|
+
validate: (_path, _bucketId, _method, _variableOverrides, _authorization) => {
|
|
23
|
+
return Promise.resolve(true);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.getAdminOnlyFirebaseRulesValidator = getAdminOnlyFirebaseRulesValidator;
|
|
20
28
|
function getAdminCredentialValidator() {
|
|
21
29
|
return { validate: isValidAdminCredentials };
|
|
22
30
|
}
|
|
@@ -8,6 +8,7 @@ const types_1 = require("../types");
|
|
|
8
8
|
const bodyParser = require("body-parser");
|
|
9
9
|
const gcloud_1 = require("./apis/gcloud");
|
|
10
10
|
const firebase_1 = require("./apis/firebase");
|
|
11
|
+
const errors_1 = require("../auth/errors");
|
|
11
12
|
function createApp(defaultProjectId, emulator) {
|
|
12
13
|
const { storageLayer } = emulator;
|
|
13
14
|
const app = express();
|
|
@@ -44,21 +45,43 @@ function createApp(defaultProjectId, emulator) {
|
|
|
44
45
|
res.sendStatus(200);
|
|
45
46
|
});
|
|
46
47
|
app.put("/internal/setRules", async (req, res) => {
|
|
47
|
-
const
|
|
48
|
-
if (!(
|
|
49
|
-
res.status(400).
|
|
48
|
+
const rulesRaw = req.body.rules;
|
|
49
|
+
if (!(rulesRaw && Array.isArray(rulesRaw.files) && rulesRaw.files.length > 0)) {
|
|
50
|
+
res.status(400).json({
|
|
51
|
+
message: "Request body must include 'rules.files' array",
|
|
52
|
+
});
|
|
50
53
|
return;
|
|
51
54
|
}
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const { files } = rulesRaw;
|
|
56
|
+
function parseRulesFromFiles(files) {
|
|
57
|
+
if (files.length === 1) {
|
|
58
|
+
const file = files[0];
|
|
59
|
+
if (!isRulesFile(file)) {
|
|
60
|
+
throw new errors_1.InvalidArgumentError("Each member of 'rules.files' array must contain 'name' and 'content'");
|
|
61
|
+
}
|
|
62
|
+
return { name: file.name, content: file.content };
|
|
63
|
+
}
|
|
64
|
+
const rules = [];
|
|
65
|
+
for (const file of files) {
|
|
66
|
+
if (!isRulesFile(file) || !file.resource) {
|
|
67
|
+
throw new errors_1.InvalidArgumentError("Each member of 'rules.files' array must contain 'name', 'content', and 'resource'");
|
|
68
|
+
}
|
|
69
|
+
rules.push({ resource: file.resource, rules: { name: file.name, content: file.content } });
|
|
70
|
+
}
|
|
71
|
+
return rules;
|
|
58
72
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
let rules;
|
|
74
|
+
try {
|
|
75
|
+
rules = parseRulesFromFiles(files);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
if (err instanceof errors_1.InvalidArgumentError) {
|
|
79
|
+
res.status(400).json({ message: err.message });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
const issues = await emulator.replaceRules(rules);
|
|
62
85
|
if (issues.errors.length > 0) {
|
|
63
86
|
res.status(400).json({
|
|
64
87
|
message: "There was an error updating rules, see logs for more details",
|
|
@@ -78,3 +101,6 @@ function createApp(defaultProjectId, emulator) {
|
|
|
78
101
|
return Promise.resolve(app);
|
|
79
102
|
}
|
|
80
103
|
exports.createApp = createApp;
|
|
104
|
+
function isRulesFile(file) {
|
|
105
|
+
return (typeof file.name === "string" && typeof file.content === "string");
|
|
106
|
+
}
|
package/lib/ensureApiEnabled.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enableApiURI = exports.ensure = exports.check = exports.POLL_SETTINGS = void 0;
|
|
4
4
|
const cli_color_1 = require("cli-color");
|
|
5
|
-
const
|
|
5
|
+
const track_1 = require("./track");
|
|
6
6
|
const api_1 = require("./api");
|
|
7
7
|
const apiv2_1 = require("./apiv2");
|
|
8
8
|
const utils = require("./utils");
|
|
@@ -16,7 +16,9 @@ const apiClient = new apiv2_1.Client({
|
|
|
16
16
|
apiVersion: "v1",
|
|
17
17
|
});
|
|
18
18
|
async function check(projectId, apiName, prefix, silent = false) {
|
|
19
|
-
const res = await apiClient.get(`/projects/${projectId}/services/${apiName}
|
|
19
|
+
const res = await apiClient.get(`/projects/${projectId}/services/${apiName}`, {
|
|
20
|
+
skipLog: { resBody: true },
|
|
21
|
+
});
|
|
20
22
|
const isEnabled = res.body.state === "ENABLED";
|
|
21
23
|
if (isEnabled && !silent) {
|
|
22
24
|
utils.logLabeledSuccess(prefix, `required API ${(0, cli_color_1.bold)(apiName)} is enabled`);
|
|
@@ -26,7 +28,9 @@ async function check(projectId, apiName, prefix, silent = false) {
|
|
|
26
28
|
exports.check = check;
|
|
27
29
|
async function enable(projectId, apiName) {
|
|
28
30
|
try {
|
|
29
|
-
await apiClient.post(`/projects/${projectId}/services/${apiName}:enable
|
|
31
|
+
await apiClient.post(`/projects/${projectId}/services/${apiName}:enable`, {
|
|
32
|
+
skipLog: { resBody: true },
|
|
33
|
+
});
|
|
30
34
|
}
|
|
31
35
|
catch (err) {
|
|
32
36
|
if ((0, error_1.isBillingError)(err)) {
|
|
@@ -46,7 +50,7 @@ async function pollCheckEnabled(projectId, apiName, prefix, silent, enablementRe
|
|
|
46
50
|
});
|
|
47
51
|
const isEnabled = await check(projectId, apiName, prefix, silent);
|
|
48
52
|
if (isEnabled) {
|
|
49
|
-
void track("api_enabled", apiName);
|
|
53
|
+
void (0, track_1.track)("api_enabled", apiName);
|
|
50
54
|
return;
|
|
51
55
|
}
|
|
52
56
|
if (!silent) {
|
|
@@ -172,12 +172,12 @@ async function promptSecretLocations(paramSpec) {
|
|
|
172
172
|
choices: [
|
|
173
173
|
{
|
|
174
174
|
checked: true,
|
|
175
|
-
name: "Google Cloud Secret Manager",
|
|
175
|
+
name: "Google Cloud Secret Manager (Used by deployed extensions and emulator)",
|
|
176
176
|
value: SecretLocation.CLOUD.toString(),
|
|
177
177
|
},
|
|
178
178
|
{
|
|
179
179
|
checked: false,
|
|
180
|
-
name: "Local file (
|
|
180
|
+
name: "Local file (Used by emulator only)",
|
|
181
181
|
value: SecretLocation.LOCAL.toString(),
|
|
182
182
|
},
|
|
183
183
|
],
|
|
@@ -191,25 +191,28 @@ async function promptSecretLocations(paramSpec) {
|
|
|
191
191
|
choices: [
|
|
192
192
|
{
|
|
193
193
|
checked: false,
|
|
194
|
-
name: "Google Cloud Secret Manager",
|
|
194
|
+
name: "Google Cloud Secret Manager (Used by deployed extensions and emulator)",
|
|
195
195
|
value: SecretLocation.CLOUD.toString(),
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
checked: false,
|
|
199
|
-
name: "Local file (
|
|
199
|
+
name: "Local file (Used by emulator only)",
|
|
200
200
|
value: SecretLocation.LOCAL.toString(),
|
|
201
201
|
},
|
|
202
202
|
],
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
205
|
async function promptLocalSecret(instanceId, paramSpec) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
206
|
+
let value;
|
|
207
|
+
do {
|
|
208
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, "Configure a local secret value for Extensions Emulator");
|
|
209
|
+
value = await (0, prompt_1.promptOnce)({
|
|
210
|
+
name: paramSpec.param,
|
|
211
|
+
type: "input",
|
|
212
|
+
message: `This secret will be stored in ./extensions/${instanceId}.secret.local.\n` +
|
|
213
|
+
`Enter value for "${paramSpec.label.trim()}" to be used by Extensions Emulator:`,
|
|
214
|
+
});
|
|
215
|
+
} while (!value);
|
|
213
216
|
return value;
|
|
214
217
|
}
|
|
215
218
|
async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
@@ -16,7 +16,7 @@ marked.setOptions({
|
|
|
16
16
|
renderer: new TerminalRenderer(),
|
|
17
17
|
});
|
|
18
18
|
const EXTENSIONS_CHANGELOG = "CHANGELOG.md";
|
|
19
|
-
const VERSION_LINE_REGEX = /##.*(\d+\.\d+\.\d+).*/;
|
|
19
|
+
const VERSION_LINE_REGEX = /##.*(\d+\.\d+\.\d+(?:-((\d+|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(\d+|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?).*/;
|
|
20
20
|
async function getReleaseNotesForUpdate(args) {
|
|
21
21
|
const releaseNotes = {};
|
|
22
22
|
const filter = `id<="${args.toVersion}" AND id>"${args.fromVersion}"`;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getParams = exports.getSecretEnvVars = exports.getNonSecretEnv = exports.getExtensionFunctionInfo = exports.buildOptions = void 0;
|
|
4
4
|
const fs = require("fs-extra");
|
|
5
|
-
const _ = require("lodash");
|
|
6
5
|
const path = require("path");
|
|
7
6
|
const paramHelper = require("../paramHelper");
|
|
8
7
|
const specHelper = require("./specHelper");
|
|
@@ -10,6 +9,7 @@ const localHelper = require("../localHelper");
|
|
|
10
9
|
const triggerHelper = require("./triggerHelper");
|
|
11
10
|
const extensionsApi_1 = require("../extensionsApi");
|
|
12
11
|
const extensionsHelper = require("../extensionsHelper");
|
|
12
|
+
const planner = require("../../deploy/extensions/planner");
|
|
13
13
|
const config_1 = require("../../config");
|
|
14
14
|
const error_1 = require("../../error");
|
|
15
15
|
const emulatorLogger_1 = require("../../emulator/emulatorLogger");
|
|
@@ -36,13 +36,13 @@ async function buildOptions(options) {
|
|
|
36
36
|
return options;
|
|
37
37
|
}
|
|
38
38
|
exports.buildOptions = buildOptions;
|
|
39
|
-
async function getExtensionFunctionInfo(
|
|
40
|
-
const spec = await
|
|
39
|
+
async function getExtensionFunctionInfo(instance, paramValues) {
|
|
40
|
+
const spec = await planner.getExtensionSpec(instance);
|
|
41
41
|
const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, paramValues);
|
|
42
42
|
const extensionTriggers = functionResources
|
|
43
43
|
.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r))
|
|
44
44
|
.map((trigger) => {
|
|
45
|
-
trigger.name = `ext-${instanceId}-${trigger.name}`;
|
|
45
|
+
trigger.name = `ext-${instance.instanceId}-${trigger.name}`;
|
|
46
46
|
return trigger;
|
|
47
47
|
});
|
|
48
48
|
const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
|
|
@@ -159,12 +159,10 @@ function buildConfig(functionResources, testConfig) {
|
|
|
159
159
|
return config;
|
|
160
160
|
}
|
|
161
161
|
function getFunctionSourceDirectory(functionResources) {
|
|
162
|
+
var _a;
|
|
162
163
|
let sourceDirectory;
|
|
163
164
|
for (const r of functionResources) {
|
|
164
|
-
|
|
165
|
-
if (!dir) {
|
|
166
|
-
dir = "functions";
|
|
167
|
-
}
|
|
165
|
+
const dir = ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.sourceDirectory) || "functions";
|
|
168
166
|
if (!sourceDirectory) {
|
|
169
167
|
sourceDirectory = dir;
|
|
170
168
|
}
|
|
@@ -172,14 +170,15 @@ function getFunctionSourceDirectory(functionResources) {
|
|
|
172
170
|
throw new error_1.FirebaseError(`Found function resources with different sourceDirectories: '${sourceDirectory}' and '${dir}'. The extensions emulator only supports a single sourceDirectory.`);
|
|
173
171
|
}
|
|
174
172
|
}
|
|
175
|
-
return sourceDirectory;
|
|
173
|
+
return sourceDirectory || "functions";
|
|
176
174
|
}
|
|
177
175
|
function shouldEmulateFunctions(resources) {
|
|
178
176
|
return resources.length > 0;
|
|
179
177
|
}
|
|
180
178
|
function shouldEmulate(emulatorName, resources) {
|
|
179
|
+
var _a, _b;
|
|
181
180
|
for (const r of resources) {
|
|
182
|
-
const eventType =
|
|
181
|
+
const eventType = ((_b = (_a = r.properties) === null || _a === void 0 ? void 0 : _a.eventTrigger) === null || _b === void 0 ? void 0 : _b.eventType) || "";
|
|
183
182
|
if (eventType.includes(emulatorName)) {
|
|
184
183
|
return true;
|
|
185
184
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getNodeVersion = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readExtensionYaml = void 0;
|
|
3
|
+
exports.getNodeVersion = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readPostinstall = exports.readExtensionYaml = void 0;
|
|
4
4
|
const yaml = require("js-yaml");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const fs = require("fs-extra");
|
|
@@ -8,6 +8,7 @@ const error_1 = require("../../error");
|
|
|
8
8
|
const extensionsHelper_1 = require("../extensionsHelper");
|
|
9
9
|
const functionsEmulatorUtils_1 = require("../../emulator/functionsEmulatorUtils");
|
|
10
10
|
const SPEC_FILE = "extension.yaml";
|
|
11
|
+
const POSTINSTALL_FILE = "POSTINSTALL.md";
|
|
11
12
|
const validFunctionTypes = [
|
|
12
13
|
"firebaseextensions.v1beta.function",
|
|
13
14
|
"firebaseextensions.v1beta.scheduledFunction",
|
|
@@ -29,6 +30,11 @@ async function readExtensionYaml(directory) {
|
|
|
29
30
|
return wrappedSafeLoad(source);
|
|
30
31
|
}
|
|
31
32
|
exports.readExtensionYaml = readExtensionYaml;
|
|
33
|
+
async function readPostinstall(directory) {
|
|
34
|
+
const content = await readFileFromDirectory(directory, POSTINSTALL_FILE);
|
|
35
|
+
return content.source;
|
|
36
|
+
}
|
|
37
|
+
exports.readPostinstall = readPostinstall;
|
|
32
38
|
function readFileFromDirectory(directory, file) {
|
|
33
39
|
return new Promise((resolve, reject) => {
|
|
34
40
|
fs.readFile(path.resolve(directory, file), "utf8", (err, data) => {
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.functionResourceToEmulatedTriggerDefintion = void 0;
|
|
4
|
-
const _ = require("lodash");
|
|
5
4
|
const functionsEmulatorShared_1 = require("../../emulator/functionsEmulatorShared");
|
|
6
5
|
const emulatorLogger_1 = require("../../emulator/emulatorLogger");
|
|
7
6
|
const types_1 = require("../../emulator/types");
|
|
7
|
+
const proto = require("../../gcp/proto");
|
|
8
8
|
function functionResourceToEmulatedTriggerDefintion(resource) {
|
|
9
9
|
const etd = {
|
|
10
10
|
name: resource.name,
|
|
11
11
|
entryPoint: resource.name,
|
|
12
12
|
platform: "gcfv1",
|
|
13
13
|
};
|
|
14
|
-
const properties =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (properties.location) {
|
|
19
|
-
etd.regions = [properties.location];
|
|
20
|
-
}
|
|
21
|
-
if (properties.availableMemoryMb) {
|
|
22
|
-
etd.availableMemoryMb = properties.availableMemoryMb;
|
|
23
|
-
}
|
|
14
|
+
const properties = resource.properties || {};
|
|
15
|
+
proto.renameIfPresent(etd, properties, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
16
|
+
proto.renameIfPresent(etd, properties, "regions", "location", (str) => [str]);
|
|
17
|
+
proto.copyIfPresent(etd, properties, "availableMemoryMb");
|
|
24
18
|
if (properties.httpsTrigger) {
|
|
25
19
|
etd.httpsTrigger = properties.httpsTrigger;
|
|
26
20
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
if (properties.eventTrigger) {
|
|
22
|
+
etd.eventTrigger = {
|
|
23
|
+
eventType: properties.eventTrigger.eventType,
|
|
24
|
+
resource: properties.eventTrigger.resource,
|
|
25
|
+
service: (0, functionsEmulatorShared_1.getServiceFromEventType)(properties.eventTrigger.eventType),
|
|
26
|
+
};
|
|
30
27
|
}
|
|
31
28
|
else {
|
|
32
29
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("WARN", `Function '${resource.name} is missing a trigger in extension.yaml. Please add one, as triggers defined in code are ignored.`);
|
|
@@ -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.undeprecateExtensionVersion = exports.deprecateExtensionVersion = exports.registerPublisherProfile = exports.getPublisherProfile = 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.getPublisherProfile = 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.FUNCTIONS_RESOURCE_TYPE = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
4
4
|
const yaml = require("js-yaml");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const { marked } = require("marked");
|
|
@@ -26,6 +26,7 @@ var Visibility;
|
|
|
26
26
|
Visibility["UNLISTED"] = "unlisted";
|
|
27
27
|
Visibility["PUBLIC"] = "public";
|
|
28
28
|
})(Visibility = exports.Visibility || (exports.Visibility = {}));
|
|
29
|
+
exports.FUNCTIONS_RESOURCE_TYPE = "firebaseextensions.v1beta.function";
|
|
29
30
|
var ParamType;
|
|
30
31
|
(function (ParamType) {
|
|
31
32
|
ParamType["STRING"] = "STRING";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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;
|
|
3
|
+
exports.canonicalizeRefInput = 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");
|
|
@@ -305,7 +305,7 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
305
305
|
"Please create one and add an entry for this version. " +
|
|
306
306
|
marked("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
|
|
307
307
|
}
|
|
308
|
-
if (!notes && extension) {
|
|
308
|
+
if (!notes && !semver.prerelease(extensionSpec.version) && extension) {
|
|
309
309
|
throw new error_1.FirebaseError(`No entry for version ${extensionSpec.version} found in CHANGELOG.md. ` +
|
|
310
310
|
"Please add one so users know what has changed in this version. " +
|
|
311
311
|
marked("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
|
|
@@ -363,32 +363,26 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
363
363
|
}
|
|
364
364
|
exports.publishExtensionVersionFromLocalSource = publishExtensionVersionFromLocalSource;
|
|
365
365
|
async function createSourceFromLocation(projectId, sourceUri) {
|
|
366
|
+
const extensionRoot = "/";
|
|
366
367
|
let packageUri;
|
|
367
|
-
let extensionRoot;
|
|
368
368
|
let objectPath = "";
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
uploadSpinner.fail();
|
|
380
|
-
throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
|
|
381
|
-
original: err,
|
|
382
|
-
});
|
|
383
|
-
}
|
|
369
|
+
const spinner = ora(" Archiving and uploading extension source code");
|
|
370
|
+
try {
|
|
371
|
+
spinner.start();
|
|
372
|
+
objectPath = await archiveAndUploadSource(sourceUri, exports.EXTENSIONS_BUCKET_NAME);
|
|
373
|
+
spinner.succeed(" Uploaded extension source code");
|
|
374
|
+
packageUri = api_1.storageOrigin + objectPath + "?alt=media";
|
|
375
|
+
const res = await (0, extensionsApi_1.createSource)(projectId, packageUri, extensionRoot);
|
|
376
|
+
logger_1.logger.debug("Created new Extension Source %s", res.name);
|
|
377
|
+
await deleteUploadedSource(objectPath);
|
|
378
|
+
return res;
|
|
384
379
|
}
|
|
385
|
-
|
|
386
|
-
|
|
380
|
+
catch (err) {
|
|
381
|
+
spinner.fail();
|
|
382
|
+
throw new error_1.FirebaseError(`Failed to archive and upload extension source from ${sourceUri}, ${err}`, {
|
|
383
|
+
original: err,
|
|
384
|
+
});
|
|
387
385
|
}
|
|
388
|
-
const res = await (0, extensionsApi_1.createSource)(projectId, packageUri, extensionRoot);
|
|
389
|
-
logger_1.logger.debug("Created new Extension Source %s", res.name);
|
|
390
|
-
await deleteUploadedSource(objectPath);
|
|
391
|
-
return res;
|
|
392
386
|
}
|
|
393
387
|
exports.createSourceFromLocation = createSourceFromLocation;
|
|
394
388
|
async function deleteUploadedSource(objectPath) {
|
|
@@ -535,3 +529,15 @@ async function diagnoseAndFixProject(options) {
|
|
|
535
529
|
}
|
|
536
530
|
}
|
|
537
531
|
exports.diagnoseAndFixProject = diagnoseAndFixProject;
|
|
532
|
+
function canonicalizeRefInput(extensionName) {
|
|
533
|
+
if (extensionName.split("/").length < 2) {
|
|
534
|
+
const [extensionID, version] = extensionName.split("@");
|
|
535
|
+
extensionName = `firebase/${extensionID}@${version || "latest"}`;
|
|
536
|
+
}
|
|
537
|
+
const ref = refs.parse(extensionName);
|
|
538
|
+
if (!ref.version) {
|
|
539
|
+
extensionName = `${extensionName}@latest`;
|
|
540
|
+
}
|
|
541
|
+
return extensionName;
|
|
542
|
+
}
|
|
543
|
+
exports.canonicalizeRefInput = canonicalizeRefInput;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.showPreviewWarning = exports.showDeprecationWarning = exports.readInstanceParam = exports.getInstanceRef = exports.instanceExists = exports.loadConfig = exports.removeFromManifest = exports.writeLocalSecrets = exports.writeToManifest = exports.ENV_DIRECTORY = void 0;
|
|
3
|
+
exports.showPreviewWarning = exports.showDeprecationWarning = exports.readInstanceParam = exports.getInstanceRef = exports.getInstanceTarget = exports.instanceExists = exports.loadConfig = exports.removeFromManifest = exports.writeLocalSecrets = exports.writeToManifest = exports.ENV_DIRECTORY = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const refs = require("./refs");
|
|
7
7
|
const config_1 = require("../config");
|
|
8
|
+
const planner_1 = require("../deploy/extensions/planner");
|
|
8
9
|
const logger_1 = require("../logger");
|
|
9
10
|
const prompt_1 = require("../prompt");
|
|
10
11
|
const paramHelper_1 = require("./paramHelper");
|
|
@@ -42,11 +43,12 @@ async function writeToManifest(specs, config, options, allowOverwrite = false) {
|
|
|
42
43
|
exports.writeToManifest = writeToManifest;
|
|
43
44
|
async function writeLocalSecrets(specs, config, force) {
|
|
44
45
|
for (const spec of specs) {
|
|
45
|
-
|
|
46
|
+
const extensionSpec = await (0, planner_1.getExtensionSpec)(spec);
|
|
47
|
+
if (!extensionSpec.params) {
|
|
46
48
|
continue;
|
|
47
49
|
}
|
|
48
50
|
const writeBuffer = {};
|
|
49
|
-
const locallyOverridenSecretParams =
|
|
51
|
+
const locallyOverridenSecretParams = extensionSpec.params.filter((p) => p.type === extensionsApi_1.ParamType.SECRET && spec.params[p.param].local);
|
|
50
52
|
for (const paramSpec of locallyOverridenSecretParams) {
|
|
51
53
|
const key = paramSpec.param;
|
|
52
54
|
const localValue = spec.params[key].local;
|
|
@@ -97,18 +99,35 @@ function instanceExists(instanceId, config) {
|
|
|
97
99
|
return !!config.get("extensions", {})[instanceId];
|
|
98
100
|
}
|
|
99
101
|
exports.instanceExists = instanceExists;
|
|
100
|
-
function
|
|
102
|
+
function getInstanceTarget(instanceId, config) {
|
|
101
103
|
if (!instanceExists(instanceId, config)) {
|
|
102
104
|
throw new error_1.FirebaseError(`Could not find extension instance ${instanceId} in firebase.json`);
|
|
103
105
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
return config.get("extensions", {})[instanceId];
|
|
107
|
+
}
|
|
108
|
+
exports.getInstanceTarget = getInstanceTarget;
|
|
109
|
+
function getInstanceRef(instanceId, config) {
|
|
110
|
+
const source = getInstanceTarget(instanceId, config);
|
|
111
|
+
if ((0, extensionsHelper_1.isLocalPath)(source)) {
|
|
112
|
+
throw new error_1.FirebaseError(`Extension instance ${instanceId} doesn't have a ref because it is from a local source`);
|
|
113
|
+
}
|
|
114
|
+
return refs.parse(source);
|
|
106
115
|
}
|
|
107
116
|
exports.getInstanceRef = getInstanceRef;
|
|
108
117
|
function writeExtensionsToFirebaseJson(specs, config) {
|
|
109
118
|
const extensions = config.get("extensions", {});
|
|
110
119
|
for (const s of specs) {
|
|
111
|
-
|
|
120
|
+
let target;
|
|
121
|
+
if (s.ref) {
|
|
122
|
+
target = refs.toExtensionVersionRef(s.ref);
|
|
123
|
+
}
|
|
124
|
+
else if (s.localPath) {
|
|
125
|
+
target = s.localPath;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
throw new error_1.FirebaseError(`Unable to resolve ManifestInstanceSpec, make sure you provide either extension ref or a local path to extension source code`);
|
|
129
|
+
}
|
|
130
|
+
extensions[s.instanceId] = target;
|
|
112
131
|
}
|
|
113
132
|
config.set("extensions", extensions);
|
|
114
133
|
config.writeProjectFile("firebase.json", config.src);
|
|
@@ -117,6 +136,7 @@ function writeExtensionsToFirebaseJson(specs, config) {
|
|
|
117
136
|
async function writeEnvFiles(specs, config, force) {
|
|
118
137
|
for (const spec of specs) {
|
|
119
138
|
const content = Object.entries(spec.params)
|
|
139
|
+
.filter((r) => r[1].baseValue !== "")
|
|
120
140
|
.sort((a, b) => {
|
|
121
141
|
return a[0].localeCompare(b[0]);
|
|
122
142
|
})
|
|
@@ -170,7 +190,7 @@ function showDeprecationWarning() {
|
|
|
170
190
|
}
|
|
171
191
|
exports.showDeprecationWarning = showDeprecationWarning;
|
|
172
192
|
function showPreviewWarning() {
|
|
173
|
-
utils.logLabeledWarning(extensionsHelper_1.logPrefix,
|
|
193
|
+
utils.logLabeledWarning(extensionsHelper_1.logPrefix, `See these changes in your Firebase Emulator by running "firebase emulators:start". ` +
|
|
174
194
|
`Run ${clc.bold("firebase deploy (--only extensions)")} to deploy the changes to your Firebase project. `);
|
|
175
195
|
}
|
|
176
196
|
exports.showPreviewWarning = showPreviewWarning;
|