firebase-tools 9.16.6 → 9.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -3
- package/lib/api.js +1 -0
- package/lib/apiv2.js +1 -1
- package/lib/appdistribution/client.js +84 -72
- package/lib/appdistribution/distribution.js +8 -26
- package/lib/appdistribution/options-parser-util.js +51 -0
- package/lib/command.js +8 -6
- package/lib/commands/appdistribution-distribute.js +74 -91
- package/lib/commands/appdistribution-testers-add.js +18 -0
- package/lib/commands/appdistribution-testers-remove.js +32 -0
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/ext-configure.js +9 -1
- package/lib/commands/ext-dev-extension-delete.js +2 -1
- package/lib/commands/ext-dev-init.js +18 -9
- package/lib/commands/ext-dev-publish.js +11 -4
- package/lib/commands/ext-dev-unpublish.js +2 -1
- package/lib/commands/ext-install.js +115 -48
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +67 -43
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +44 -35
- package/lib/commands/functions-list.js +54 -0
- package/lib/commands/functions-log.js +5 -22
- package/lib/commands/hosting-channel-deploy.js +6 -4
- package/lib/commands/index.js +12 -0
- package/lib/deploy/functions/backend.js +47 -12
- package/lib/deploy/functions/containerCleaner.js +5 -1
- package/lib/deploy/functions/deploy.js +7 -5
- package/lib/deploy/functions/prepare.js +9 -7
- package/lib/deploy/functions/prompts.js +3 -21
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +2 -1
- package/lib/deploy/functions/runtimes/index.js +2 -1
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +4 -3
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +14 -9
- package/lib/deploy/functions/triggerRegionHelper.js +32 -0
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +1758 -404
- package/lib/emulator/auth/handlers.js +6 -5
- package/lib/emulator/auth/operations.js +429 -40
- package/lib/emulator/auth/server.js +18 -11
- package/lib/emulator/auth/state.js +186 -5
- package/lib/emulator/auth/widget_ui.js +2 -2
- package/lib/emulator/download.js +2 -31
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/emulatorLogger.js +0 -3
- package/lib/emulator/events/types.js +16 -0
- package/lib/emulator/functionsEmulator.js +102 -17
- package/lib/emulator/functionsEmulatorRuntime.js +46 -121
- package/lib/emulator/functionsEmulatorShared.js +51 -7
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/pubsubEmulator.js +61 -40
- package/lib/extensions/askUserForConsent.js +16 -13
- package/lib/extensions/askUserForParam.js +72 -3
- package/lib/extensions/billingMigrationHelper.js +1 -11
- package/lib/extensions/changelog.js +93 -0
- package/lib/extensions/displayExtensionInfo.js +38 -38
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/triggerHelper.js +2 -32
- package/lib/extensions/extensionsApi.js +69 -95
- package/lib/extensions/extensionsHelper.js +75 -50
- package/lib/extensions/paramHelper.js +79 -36
- package/lib/extensions/refs.js +59 -0
- package/lib/extensions/resolveSource.js +2 -20
- package/lib/extensions/secretsUtils.js +58 -0
- package/lib/extensions/updateHelper.js +39 -105
- package/lib/extensions/warnings.js +1 -7
- package/lib/functional.js +64 -0
- package/lib/functions/env.js +26 -13
- package/lib/functions/functionslog.js +40 -0
- package/lib/functions/listFunctions.js +10 -0
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/cloudfunctions.js +84 -9
- package/lib/gcp/cloudfunctionsv2.js +99 -7
- package/lib/gcp/cloudlogging.js +27 -21
- package/lib/gcp/secretManager.js +111 -0
- package/lib/gcp/storage.js +16 -0
- package/lib/previews.js +1 -1
- package/lib/requireInteractive.js +12 -0
- package/package.json +5 -4
- package/schema/firebase-config.json +2 -1
- package/templates/extensions/CHANGELOG.md +7 -0
- package/templates/init/hosting/index.html +10 -10
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseChangelog = exports.getLocalChangelog = exports.breakingChangesInUpdate = exports.displayReleaseNotes = exports.getReleaseNotesForUpdate = void 0;
|
|
4
|
+
const clc = require("cli-color");
|
|
5
|
+
const marked = require("marked");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const semver = require("semver");
|
|
8
|
+
const TerminalRenderer = require("marked-terminal");
|
|
9
|
+
const Table = require("cli-table");
|
|
10
|
+
const extensionsApi_1 = require("./extensionsApi");
|
|
11
|
+
const localHelper_1 = require("./localHelper");
|
|
12
|
+
const logger_1 = require("../logger");
|
|
13
|
+
const refs = require("./refs");
|
|
14
|
+
const utils_1 = require("../utils");
|
|
15
|
+
marked.setOptions({
|
|
16
|
+
renderer: new TerminalRenderer(),
|
|
17
|
+
});
|
|
18
|
+
const EXTENSIONS_CHANGELOG = "CHANGELOG.md";
|
|
19
|
+
const VERSION_LINE_REGEX = /##.*(\d+\.\d+\.\d+).*/;
|
|
20
|
+
async function getReleaseNotesForUpdate(args) {
|
|
21
|
+
const releaseNotes = {};
|
|
22
|
+
const filter = `id<="${args.toVersion}" AND id>"${args.fromVersion}"`;
|
|
23
|
+
const extensionVersions = await extensionsApi_1.listExtensionVersions(args.extensionRef, filter);
|
|
24
|
+
extensionVersions.sort((ev1, ev2) => {
|
|
25
|
+
return -semver.compare(ev1.spec.version, ev2.spec.version);
|
|
26
|
+
});
|
|
27
|
+
for (const extensionVersion of extensionVersions) {
|
|
28
|
+
if (extensionVersion.releaseNotes) {
|
|
29
|
+
const version = refs.parse(extensionVersion.ref).version;
|
|
30
|
+
releaseNotes[version] = extensionVersion.releaseNotes;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return releaseNotes;
|
|
34
|
+
}
|
|
35
|
+
exports.getReleaseNotesForUpdate = getReleaseNotesForUpdate;
|
|
36
|
+
function displayReleaseNotes(releaseNotes, fromVersion) {
|
|
37
|
+
const versions = [fromVersion].concat(Object.keys(releaseNotes));
|
|
38
|
+
const breakingVersions = breakingChangesInUpdate(versions);
|
|
39
|
+
const table = new Table({ head: ["Version", "What's New"], style: { head: ["yellow", "bold"] } });
|
|
40
|
+
for (const [version, note] of Object.entries(releaseNotes)) {
|
|
41
|
+
if (breakingVersions.includes(version)) {
|
|
42
|
+
table.push([clc.yellow.bold(version), marked(note)]);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
table.push([version, marked(note)]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
logger_1.logger.info(clc.bold("What's new with this update:"));
|
|
49
|
+
if (breakingVersions.length) {
|
|
50
|
+
utils_1.logLabeledWarning("warning", "This is a major version update, which means it may contain breaking changes." +
|
|
51
|
+
" Read the release notes carefully before continuing with this update.");
|
|
52
|
+
}
|
|
53
|
+
logger_1.logger.info(table.toString());
|
|
54
|
+
}
|
|
55
|
+
exports.displayReleaseNotes = displayReleaseNotes;
|
|
56
|
+
function breakingChangesInUpdate(versionsInUpdate) {
|
|
57
|
+
const breakingVersions = [];
|
|
58
|
+
const semvers = versionsInUpdate.map((v) => semver.parse(v)).sort(semver.compare);
|
|
59
|
+
for (let i = 1; i < semvers.length; i++) {
|
|
60
|
+
const hasMajorBump = semvers[i - 1].major < semvers[i].major;
|
|
61
|
+
const hasMinorBumpInPreview = semvers[i - 1].major == 0 && semvers[i].major == 0 && semvers[i - 1].minor < semvers[i].minor;
|
|
62
|
+
if (hasMajorBump || hasMinorBumpInPreview) {
|
|
63
|
+
breakingVersions.push(semvers[i].raw);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return breakingVersions;
|
|
67
|
+
}
|
|
68
|
+
exports.breakingChangesInUpdate = breakingChangesInUpdate;
|
|
69
|
+
function getLocalChangelog(directory) {
|
|
70
|
+
const rawChangelog = localHelper_1.readFile(path.resolve(directory, EXTENSIONS_CHANGELOG));
|
|
71
|
+
return parseChangelog(rawChangelog);
|
|
72
|
+
}
|
|
73
|
+
exports.getLocalChangelog = getLocalChangelog;
|
|
74
|
+
function parseChangelog(rawChangelog) {
|
|
75
|
+
const changelog = {};
|
|
76
|
+
let currentVersion = "";
|
|
77
|
+
for (const line of rawChangelog.split("\n")) {
|
|
78
|
+
const matches = line.match(VERSION_LINE_REGEX);
|
|
79
|
+
if (matches) {
|
|
80
|
+
currentVersion = matches[1];
|
|
81
|
+
}
|
|
82
|
+
else if (currentVersion) {
|
|
83
|
+
if (!changelog[currentVersion]) {
|
|
84
|
+
changelog[currentVersion] = line;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
changelog[currentVersion] += `\n${line}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return changelog;
|
|
92
|
+
}
|
|
93
|
+
exports.parseChangelog = parseChangelog;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.printSourceDownloadLink = exports.
|
|
3
|
+
exports.printSourceDownloadLink = exports.displayUpdateChangesRequiringConfirmation = exports.displayUpdateChangesNoInput = exports.displayExtInfo = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const marked = require("marked");
|
|
@@ -9,7 +9,6 @@ const utils = require("../utils");
|
|
|
9
9
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
10
10
|
const logger_1 = require("../logger");
|
|
11
11
|
const error_1 = require("../error");
|
|
12
|
-
const prompt_1 = require("../prompt");
|
|
13
12
|
marked.setOptions({
|
|
14
13
|
renderer: new TerminalRenderer(),
|
|
15
14
|
});
|
|
@@ -47,7 +46,7 @@ function displayExtInfo(extensionName, publisher, spec, published = false) {
|
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
exports.displayExtInfo = displayExtInfo;
|
|
50
|
-
function displayUpdateChangesNoInput(spec, newSpec
|
|
49
|
+
function displayUpdateChangesNoInput(spec, newSpec) {
|
|
51
50
|
var _a, _b, _c, _d;
|
|
52
51
|
const lines = [];
|
|
53
52
|
if (spec.displayName !== newSpec.displayName) {
|
|
@@ -59,10 +58,8 @@ function displayUpdateChangesNoInput(spec, newSpec, isOfficial = true) {
|
|
|
59
58
|
if (spec.description !== newSpec.description) {
|
|
60
59
|
lines.push("", "**Description:**", deletionColor(`- ${spec.description}`), additionColor(`+ ${newSpec.description}`));
|
|
61
60
|
}
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
lines.push("", "**Source code:**", deletionColor(`- ${spec.sourceUrl}`), additionColor(`+ ${newSpec.sourceUrl}`));
|
|
65
|
-
}
|
|
61
|
+
if (spec.sourceUrl !== newSpec.sourceUrl) {
|
|
62
|
+
lines.push("", "**Source code:**", deletionColor(`- ${spec.sourceUrl}`), additionColor(`+ ${newSpec.sourceUrl}`));
|
|
66
63
|
}
|
|
67
64
|
if (spec.billingRequired && !newSpec.billingRequired) {
|
|
68
65
|
lines.push("", "**Billing is no longer required for this extension.**");
|
|
@@ -71,17 +68,22 @@ function displayUpdateChangesNoInput(spec, newSpec, isOfficial = true) {
|
|
|
71
68
|
return lines;
|
|
72
69
|
}
|
|
73
70
|
exports.displayUpdateChangesNoInput = displayUpdateChangesNoInput;
|
|
74
|
-
async function displayUpdateChangesRequiringConfirmation(
|
|
75
|
-
|
|
71
|
+
async function displayUpdateChangesRequiringConfirmation(args) {
|
|
72
|
+
const equals = (a, b) => {
|
|
73
|
+
return _.isEqual(a, b);
|
|
74
|
+
};
|
|
75
|
+
if (args.spec.license !== args.newSpec.license) {
|
|
76
76
|
const message = "\n" +
|
|
77
77
|
"**License**\n" +
|
|
78
|
-
deletionColor(spec.license ? `- ${spec.license}\n` : "- None\n") +
|
|
79
|
-
additionColor(newSpec.license ? `+ ${newSpec.license}\n` : "+ None\n")
|
|
80
|
-
|
|
81
|
-
await
|
|
78
|
+
deletionColor(args.spec.license ? `- ${args.spec.license}\n` : "- None\n") +
|
|
79
|
+
additionColor(args.newSpec.license ? `+ ${args.newSpec.license}\n` : "+ None\n");
|
|
80
|
+
logger_1.logger.info(message);
|
|
81
|
+
if (!(await extensionsHelper_1.confirm({ nonInteractive: args.nonInteractive, force: args.force, default: true }))) {
|
|
82
|
+
throw new error_1.FirebaseError("Unable to update this extension instance without explicit consent for the change to 'License'.");
|
|
83
|
+
}
|
|
82
84
|
}
|
|
83
|
-
const apisDiffDeletions = _.differenceWith(spec.apis, _.get(newSpec, "apis", []),
|
|
84
|
-
const apisDiffAdditions = _.differenceWith(newSpec.apis, _.get(spec, "apis", []),
|
|
85
|
+
const apisDiffDeletions = _.differenceWith(args.spec.apis, _.get(args.newSpec, "apis", []), equals);
|
|
86
|
+
const apisDiffAdditions = _.differenceWith(args.newSpec.apis, _.get(args.spec, "apis", []), equals);
|
|
85
87
|
if (apisDiffDeletions.length || apisDiffAdditions.length) {
|
|
86
88
|
let message = "\n**APIs:**\n";
|
|
87
89
|
apisDiffDeletions.forEach((api) => {
|
|
@@ -90,11 +92,13 @@ async function displayUpdateChangesRequiringConfirmation(spec, newSpec) {
|
|
|
90
92
|
apisDiffAdditions.forEach((api) => {
|
|
91
93
|
message += additionColor(`+ ${api.apiName} (${api.reason})\n`);
|
|
92
94
|
});
|
|
93
|
-
message
|
|
94
|
-
await
|
|
95
|
+
logger_1.logger.info(message);
|
|
96
|
+
if (!(await extensionsHelper_1.confirm({ nonInteractive: args.nonInteractive, force: args.force, default: true }))) {
|
|
97
|
+
throw new error_1.FirebaseError("Unable to update this extension instance without explicit consent for the change to 'APIs'.");
|
|
98
|
+
}
|
|
95
99
|
}
|
|
96
|
-
const resourcesDiffDeletions = _.differenceWith(spec.resources, _.get(newSpec, "resources", []), compareResources);
|
|
97
|
-
const resourcesDiffAdditions = _.differenceWith(newSpec.resources, _.get(spec, "resources", []), compareResources);
|
|
100
|
+
const resourcesDiffDeletions = _.differenceWith(args.spec.resources, _.get(args.newSpec, "resources", []), compareResources);
|
|
101
|
+
const resourcesDiffAdditions = _.differenceWith(args.newSpec.resources, _.get(args.spec, "resources", []), compareResources);
|
|
98
102
|
if (resourcesDiffDeletions.length || resourcesDiffAdditions.length) {
|
|
99
103
|
let message = "\n**Resources:**\n";
|
|
100
104
|
resourcesDiffDeletions.forEach((resource) => {
|
|
@@ -103,11 +107,13 @@ async function displayUpdateChangesRequiringConfirmation(spec, newSpec) {
|
|
|
103
107
|
resourcesDiffAdditions.forEach((resource) => {
|
|
104
108
|
message += additionColor(`+ ${getResourceReadableName(resource)}`);
|
|
105
109
|
});
|
|
106
|
-
message
|
|
107
|
-
await
|
|
110
|
+
logger_1.logger.info(message);
|
|
111
|
+
if (!(await extensionsHelper_1.confirm({ nonInteractive: args.nonInteractive, force: args.force, default: true }))) {
|
|
112
|
+
throw new error_1.FirebaseError("Unable to update this extension instance without explicit consent for the change to 'Resources'.");
|
|
113
|
+
}
|
|
108
114
|
}
|
|
109
|
-
const rolesDiffDeletions = _.differenceWith(spec.roles, _.get(newSpec, "roles", []),
|
|
110
|
-
const rolesDiffAdditions = _.differenceWith(newSpec.roles, _.get(spec, "roles", []),
|
|
115
|
+
const rolesDiffDeletions = _.differenceWith(args.spec.roles, _.get(args.newSpec, "roles", []), equals);
|
|
116
|
+
const rolesDiffAdditions = _.differenceWith(args.newSpec.roles, _.get(args.spec, "roles", []), equals);
|
|
111
117
|
if (rolesDiffDeletions.length || rolesDiffAdditions.length) {
|
|
112
118
|
let message = "\n**Permissions:**\n";
|
|
113
119
|
rolesDiffDeletions.forEach((role) => {
|
|
@@ -116,11 +122,16 @@ async function displayUpdateChangesRequiringConfirmation(spec, newSpec) {
|
|
|
116
122
|
rolesDiffAdditions.forEach((role) => {
|
|
117
123
|
message += additionColor(`+ ${role.role} (${role.reason})\n`);
|
|
118
124
|
});
|
|
119
|
-
message
|
|
120
|
-
await
|
|
125
|
+
logger_1.logger.info(message);
|
|
126
|
+
if (!(await extensionsHelper_1.confirm({ nonInteractive: args.nonInteractive, force: args.force, default: true }))) {
|
|
127
|
+
throw new error_1.FirebaseError("Unable to update this extension instance without explicit consent for the change to 'Permissions'.");
|
|
128
|
+
}
|
|
121
129
|
}
|
|
122
|
-
if (!spec.billingRequired && newSpec.billingRequired) {
|
|
123
|
-
|
|
130
|
+
if (!args.spec.billingRequired && args.newSpec.billingRequired) {
|
|
131
|
+
logger_1.logger.info("Billing is now required for the new version of this extension.");
|
|
132
|
+
if (!(await extensionsHelper_1.confirm({ nonInteractive: args.nonInteractive, force: args.force, default: true }))) {
|
|
133
|
+
throw new error_1.FirebaseError("Unable to update this extension instance without explicit consent for the change to 'BillingRequired'.");
|
|
134
|
+
}
|
|
124
135
|
}
|
|
125
136
|
}
|
|
126
137
|
exports.displayUpdateChangesRequiringConfirmation = displayUpdateChangesRequiringConfirmation;
|
|
@@ -132,17 +143,6 @@ function getResourceReadableName(resource) {
|
|
|
132
143
|
? `${resource.name} (Cloud Function): ${resource.description}\n`
|
|
133
144
|
: `${resource.name} (${resource.type})\n`;
|
|
134
145
|
}
|
|
135
|
-
async function getConsent(field, message) {
|
|
136
|
-
const consent = await prompt_1.promptOnce({
|
|
137
|
-
type: "confirm",
|
|
138
|
-
message,
|
|
139
|
-
default: true,
|
|
140
|
-
});
|
|
141
|
-
if (!consent) {
|
|
142
|
-
throw new error_1.FirebaseError(`Without explicit consent for the change to ${field}, we cannot update this extension instance.`, { exit: 2 });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
exports.getConsent = getConsent;
|
|
146
146
|
function printSourceDownloadLink(sourceDownloadUri) {
|
|
147
147
|
const sourceDownloadMsg = `Want to review the source code that will be installed? Download it here: ${sourceDownloadUri}`;
|
|
148
148
|
utils.logBullet(marked(sourceDownloadMsg));
|
|
@@ -19,7 +19,7 @@ async function buildOptions(options) {
|
|
|
19
19
|
options.extensionDir = extensionDir;
|
|
20
20
|
const spec = await specHelper.readExtensionYaml(extensionDir);
|
|
21
21
|
extensionsHelper.validateSpec(spec);
|
|
22
|
-
const params =
|
|
22
|
+
const params = getParams(options, spec);
|
|
23
23
|
extensionsHelper.validateCommandLineParams(params, spec.params);
|
|
24
24
|
const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, params);
|
|
25
25
|
let testConfig;
|
|
@@ -35,9 +35,9 @@ async function buildOptions(options) {
|
|
|
35
35
|
return options;
|
|
36
36
|
}
|
|
37
37
|
exports.buildOptions = buildOptions;
|
|
38
|
-
|
|
38
|
+
function getParams(options, extensionSpec) {
|
|
39
39
|
const projectId = projectUtils_1.needProjectId(options);
|
|
40
|
-
const userParams =
|
|
40
|
+
const userParams = paramHelper.readEnvFile(options.testParams);
|
|
41
41
|
const autoParams = {
|
|
42
42
|
PROJECT_ID: projectId,
|
|
43
43
|
EXT_INSTANCE_ID: extensionSpec.name,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.functionResourceToEmulatedTriggerDefintion = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
|
-
const
|
|
5
|
+
const functionsEmulatorShared_1 = require("../../emulator/functionsEmulatorShared");
|
|
6
6
|
const emulatorLogger_1 = require("../../emulator/emulatorLogger");
|
|
7
7
|
const types_1 = require("../../emulator/types");
|
|
8
8
|
function functionResourceToEmulatedTriggerDefintion(resource) {
|
|
@@ -24,7 +24,7 @@ function functionResourceToEmulatedTriggerDefintion(resource) {
|
|
|
24
24
|
etd.httpsTrigger = properties.httpsTrigger;
|
|
25
25
|
}
|
|
26
26
|
else if (properties.eventTrigger) {
|
|
27
|
-
properties.eventTrigger.service = getServiceFromEventType(properties.eventTrigger.eventType);
|
|
27
|
+
properties.eventTrigger.service = functionsEmulatorShared_1.getServiceFromEventType(properties.eventTrigger.eventType);
|
|
28
28
|
etd.eventTrigger = properties.eventTrigger;
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
@@ -33,33 +33,3 @@ function functionResourceToEmulatedTriggerDefintion(resource) {
|
|
|
33
33
|
return etd;
|
|
34
34
|
}
|
|
35
35
|
exports.functionResourceToEmulatedTriggerDefintion = functionResourceToEmulatedTriggerDefintion;
|
|
36
|
-
function getServiceFromEventType(eventType) {
|
|
37
|
-
if (eventType.includes("firestore")) {
|
|
38
|
-
return constants_1.Constants.SERVICE_FIRESTORE;
|
|
39
|
-
}
|
|
40
|
-
if (eventType.includes("database")) {
|
|
41
|
-
return constants_1.Constants.SERVICE_REALTIME_DATABASE;
|
|
42
|
-
}
|
|
43
|
-
if (eventType.includes("pubsub")) {
|
|
44
|
-
return constants_1.Constants.SERVICE_PUBSUB;
|
|
45
|
-
}
|
|
46
|
-
if (eventType.includes("storage")) {
|
|
47
|
-
return constants_1.Constants.SERVICE_STORAGE;
|
|
48
|
-
}
|
|
49
|
-
if (eventType.includes("analytics")) {
|
|
50
|
-
return constants_1.Constants.SERVICE_ANALYTICS;
|
|
51
|
-
}
|
|
52
|
-
if (eventType.includes("auth")) {
|
|
53
|
-
return constants_1.Constants.SERVICE_AUTH;
|
|
54
|
-
}
|
|
55
|
-
if (eventType.includes("crashlytics")) {
|
|
56
|
-
return constants_1.Constants.SERVICE_CRASHLYTICS;
|
|
57
|
-
}
|
|
58
|
-
if (eventType.includes("remoteconfig")) {
|
|
59
|
-
return constants_1.Constants.SERVICE_REMOTE_CONFIG;
|
|
60
|
-
}
|
|
61
|
-
if (eventType.includes("testing")) {
|
|
62
|
-
return constants_1.Constants.SERVICE_TEST_LAB;
|
|
63
|
-
}
|
|
64
|
-
return "";
|
|
65
|
-
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const semver = require("semver");
|
|
3
|
+
exports.getExtension = exports.deleteExtension = exports.unpublishExtension = exports.publishExtensionVersion = exports.registerPublisherProfile = exports.listExtensionVersions = exports.listExtensions = exports.getExtensionVersion = exports.getSource = exports.createSource = exports.updateInstanceFromRegistry = exports.updateInstance = exports.configureInstance = exports.listInstances = exports.getInstance = exports.deleteInstance = exports.createInstance = exports.ParamType = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
5
4
|
const yaml = require("js-yaml");
|
|
6
5
|
const _ = require("lodash");
|
|
7
6
|
const clc = require("cli-color");
|
|
8
7
|
const marked = require("marked");
|
|
9
8
|
const api = require("../api");
|
|
9
|
+
const refs = require("./refs");
|
|
10
10
|
const logger_1 = require("../logger");
|
|
11
11
|
const operationPoller = require("../operation-poller");
|
|
12
12
|
const error_1 = require("../error");
|
|
13
13
|
const VERSION = "v1beta";
|
|
14
14
|
const PAGE_SIZE_MAX = 100;
|
|
15
|
-
const refRegex = new RegExp(/^([^/@\n]+)\/{1}([^/@\n]+)(@{1}([a-z0-9.-]+)|)$/);
|
|
16
15
|
var RegistryLaunchStage;
|
|
17
16
|
(function (RegistryLaunchStage) {
|
|
18
17
|
RegistryLaunchStage["EXPERIMENTAL"] = "EXPERIMENTAL";
|
|
@@ -31,8 +30,9 @@ var ParamType;
|
|
|
31
30
|
ParamType["STRING"] = "STRING";
|
|
32
31
|
ParamType["SELECT"] = "SELECT";
|
|
33
32
|
ParamType["MULTISELECT"] = "MULTISELECT";
|
|
33
|
+
ParamType["SECRET"] = "SECRET";
|
|
34
34
|
})(ParamType = exports.ParamType || (exports.ParamType = {}));
|
|
35
|
-
async function
|
|
35
|
+
async function createInstanceHelper(projectId, instanceId, config) {
|
|
36
36
|
const createRes = await api.request("POST", `/${VERSION}/projects/${projectId}/instances/`, {
|
|
37
37
|
auth: true,
|
|
38
38
|
origin: api.extensionsOrigin,
|
|
@@ -49,25 +49,28 @@ async function createInstance(projectId, instanceId, config) {
|
|
|
49
49
|
});
|
|
50
50
|
return pollRes;
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const config = {
|
|
55
|
-
source: { name: extensionSource.name },
|
|
56
|
-
params,
|
|
57
|
-
};
|
|
58
|
-
return createInstance(projectId, instanceId, config);
|
|
59
|
-
}
|
|
60
|
-
exports.createInstanceFromSource = createInstanceFromSource;
|
|
61
|
-
async function createInstanceFromExtensionVersion(projectId, instanceId, extensionVersion, params) {
|
|
62
|
-
const { publisherId, extensionId, version } = parseRef(extensionVersion.ref);
|
|
52
|
+
async function createInstance(args) {
|
|
53
|
+
var _a, _b;
|
|
63
54
|
const config = {
|
|
64
|
-
|
|
65
|
-
extensionVersion: version || "",
|
|
66
|
-
params,
|
|
55
|
+
params: args.params,
|
|
67
56
|
};
|
|
68
|
-
|
|
57
|
+
if (args.extensionSource && args.extensionVersionRef) {
|
|
58
|
+
throw new error_1.FirebaseError("ExtensionSource and ExtensionVersion both provided, but only one should be.");
|
|
59
|
+
}
|
|
60
|
+
else if (args.extensionSource) {
|
|
61
|
+
config.source = { name: (_a = args.extensionSource) === null || _a === void 0 ? void 0 : _a.name };
|
|
62
|
+
}
|
|
63
|
+
else if (args.extensionVersionRef) {
|
|
64
|
+
const ref = refs.parse(args.extensionVersionRef);
|
|
65
|
+
config.extensionRef = refs.toExtensionRef(ref);
|
|
66
|
+
config.extensionVersion = (_b = ref.version) !== null && _b !== void 0 ? _b : "";
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new error_1.FirebaseError("No ExtensionVersion or ExtensionSource provided but one is required.");
|
|
70
|
+
}
|
|
71
|
+
return createInstanceHelper(args.projectId, args.instanceId, config);
|
|
69
72
|
}
|
|
70
|
-
exports.
|
|
73
|
+
exports.createInstance = createInstance;
|
|
71
74
|
async function deleteInstance(projectId, instanceId) {
|
|
72
75
|
const deleteRes = await api.request("DELETE", `/${VERSION}/projects/${projectId}/instances/${instanceId}`, {
|
|
73
76
|
auth: true,
|
|
@@ -129,23 +132,23 @@ async function updateInstance(projectId, instanceId, extensionSource, params) {
|
|
|
129
132
|
};
|
|
130
133
|
let updateMask = "config.source.name";
|
|
131
134
|
if (params) {
|
|
132
|
-
body.params = params;
|
|
135
|
+
body.config.params = params;
|
|
133
136
|
updateMask += ",config.params";
|
|
134
137
|
}
|
|
135
138
|
return await patchInstance(projectId, instanceId, updateMask, body);
|
|
136
139
|
}
|
|
137
140
|
exports.updateInstance = updateInstance;
|
|
138
141
|
async function updateInstanceFromRegistry(projectId, instanceId, extRef, params) {
|
|
139
|
-
const
|
|
142
|
+
const ref = refs.parse(extRef);
|
|
140
143
|
const body = {
|
|
141
144
|
config: {
|
|
142
|
-
extensionRef:
|
|
143
|
-
extensionVersion: version,
|
|
145
|
+
extensionRef: refs.toExtensionRef(ref),
|
|
146
|
+
extensionVersion: ref.version,
|
|
144
147
|
},
|
|
145
148
|
};
|
|
146
149
|
let updateMask = "config.extension_ref,config.extension_version";
|
|
147
150
|
if (params) {
|
|
148
|
-
body.params = params;
|
|
151
|
+
body.config.params = params;
|
|
149
152
|
updateMask += ",config.params";
|
|
150
153
|
}
|
|
151
154
|
return await patchInstance(projectId, instanceId, updateMask, body);
|
|
@@ -217,13 +220,13 @@ function getSource(sourceName) {
|
|
|
217
220
|
});
|
|
218
221
|
}
|
|
219
222
|
exports.getSource = getSource;
|
|
220
|
-
async function getExtensionVersion(
|
|
221
|
-
const
|
|
222
|
-
if (!version) {
|
|
223
|
-
throw new error_1.FirebaseError(`ExtensionVersion ref "${
|
|
223
|
+
async function getExtensionVersion(extensionVersionRef) {
|
|
224
|
+
const ref = refs.parse(extensionVersionRef);
|
|
225
|
+
if (!ref.version) {
|
|
226
|
+
throw new error_1.FirebaseError(`ExtensionVersion ref "${extensionVersionRef}" must supply a version.`);
|
|
224
227
|
}
|
|
225
228
|
try {
|
|
226
|
-
const res = await api.request("GET", `/${VERSION}
|
|
229
|
+
const res = await api.request("GET", `/${VERSION}/${refs.toExtensionVersionName(ref)}`, {
|
|
227
230
|
auth: true,
|
|
228
231
|
origin: api.extensionsOrigin,
|
|
229
232
|
});
|
|
@@ -234,12 +237,12 @@ async function getExtensionVersion(ref) {
|
|
|
234
237
|
}
|
|
235
238
|
catch (err) {
|
|
236
239
|
if (err.status === 404) {
|
|
237
|
-
throw refNotFoundError(
|
|
240
|
+
throw refNotFoundError(ref);
|
|
238
241
|
}
|
|
239
242
|
else if (err instanceof error_1.FirebaseError) {
|
|
240
243
|
throw err;
|
|
241
244
|
}
|
|
242
|
-
throw new error_1.FirebaseError(`Failed to query the extension version '${clc.bold(
|
|
245
|
+
throw new error_1.FirebaseError(`Failed to query the extension version '${clc.bold(extensionVersionRef)}': ${err}`);
|
|
243
246
|
}
|
|
244
247
|
}
|
|
245
248
|
exports.getExtensionVersion = getExtensionVersion;
|
|
@@ -266,14 +269,15 @@ async function listExtensions(publisherId) {
|
|
|
266
269
|
return extensions;
|
|
267
270
|
}
|
|
268
271
|
exports.listExtensions = listExtensions;
|
|
269
|
-
async function listExtensionVersions(ref) {
|
|
270
|
-
const { publisherId, extensionId } =
|
|
272
|
+
async function listExtensionVersions(ref, filter) {
|
|
273
|
+
const { publisherId, extensionId } = refs.parse(ref);
|
|
271
274
|
const extensionVersions = [];
|
|
272
275
|
const getNextPage = async (pageToken) => {
|
|
273
276
|
const res = await api.request("GET", `/${VERSION}/publishers/${publisherId}/extensions/${extensionId}/versions`, {
|
|
274
277
|
auth: true,
|
|
275
278
|
origin: api.extensionsOrigin,
|
|
276
279
|
query: {
|
|
280
|
+
filter,
|
|
277
281
|
pageSize: PAGE_SIZE_MAX,
|
|
278
282
|
pageToken,
|
|
279
283
|
},
|
|
@@ -298,18 +302,18 @@ async function registerPublisherProfile(projectId, publisherId) {
|
|
|
298
302
|
return res.body;
|
|
299
303
|
}
|
|
300
304
|
exports.registerPublisherProfile = registerPublisherProfile;
|
|
301
|
-
async function publishExtensionVersion(
|
|
302
|
-
const
|
|
303
|
-
if (!version) {
|
|
304
|
-
throw new error_1.FirebaseError(`ExtensionVersion ref "${
|
|
305
|
+
async function publishExtensionVersion(extensionVersionRef, packageUri, extensionRoot) {
|
|
306
|
+
const ref = refs.parse(extensionVersionRef);
|
|
307
|
+
if (!ref.version) {
|
|
308
|
+
throw new error_1.FirebaseError(`ExtensionVersion ref "${extensionVersionRef}" must supply a version.`);
|
|
305
309
|
}
|
|
306
|
-
const publishRes = await api.request("POST", `/${VERSION}
|
|
310
|
+
const publishRes = await api.request("POST", `/${VERSION}/${refs.toExtensionName(ref)}/versions:publish`, {
|
|
307
311
|
auth: true,
|
|
308
312
|
origin: api.extensionsOrigin,
|
|
309
313
|
data: {
|
|
310
|
-
versionId: version,
|
|
314
|
+
versionId: ref.version,
|
|
311
315
|
packageUri,
|
|
312
|
-
extensionRoot: extensionRoot
|
|
316
|
+
extensionRoot: extensionRoot !== null && extensionRoot !== void 0 ? extensionRoot : "/",
|
|
313
317
|
},
|
|
314
318
|
});
|
|
315
319
|
const pollRes = await operationPoller.pollOperation({
|
|
@@ -321,12 +325,12 @@ async function publishExtensionVersion(ref, packageUri, extensionRoot) {
|
|
|
321
325
|
return pollRes;
|
|
322
326
|
}
|
|
323
327
|
exports.publishExtensionVersion = publishExtensionVersion;
|
|
324
|
-
async function unpublishExtension(
|
|
325
|
-
const
|
|
326
|
-
if (version) {
|
|
327
|
-
throw new error_1.FirebaseError(`Extension reference "${
|
|
328
|
+
async function unpublishExtension(extensionRef) {
|
|
329
|
+
const ref = refs.parse(extensionRef);
|
|
330
|
+
if (ref.version) {
|
|
331
|
+
throw new error_1.FirebaseError(`Extension reference "${extensionRef}" must not contain a version.`);
|
|
328
332
|
}
|
|
329
|
-
const url = `/${VERSION}
|
|
333
|
+
const url = `/${VERSION}/${refs.toExtensionName(ref)}:unpublish`;
|
|
330
334
|
try {
|
|
331
335
|
await api.request("POST", url, {
|
|
332
336
|
auth: true,
|
|
@@ -335,23 +339,23 @@ async function unpublishExtension(ref) {
|
|
|
335
339
|
}
|
|
336
340
|
catch (err) {
|
|
337
341
|
if (err.status === 403) {
|
|
338
|
-
throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(
|
|
342
|
+
throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to unpublish this extension.`, { status: err.status });
|
|
339
343
|
}
|
|
340
344
|
else if (err instanceof error_1.FirebaseError) {
|
|
341
345
|
throw err;
|
|
342
346
|
}
|
|
343
|
-
throw new error_1.FirebaseError(`Error occurred unpublishing extension '${
|
|
347
|
+
throw new error_1.FirebaseError(`Error occurred unpublishing extension '${extensionRef}': ${err}`, {
|
|
344
348
|
status: err.status,
|
|
345
349
|
});
|
|
346
350
|
}
|
|
347
351
|
}
|
|
348
352
|
exports.unpublishExtension = unpublishExtension;
|
|
349
|
-
async function deleteExtension(
|
|
350
|
-
const
|
|
351
|
-
if (version) {
|
|
352
|
-
throw new error_1.FirebaseError(`Extension reference "${
|
|
353
|
+
async function deleteExtension(extensionRef) {
|
|
354
|
+
const ref = refs.parse(extensionRef);
|
|
355
|
+
if (ref.version) {
|
|
356
|
+
throw new error_1.FirebaseError(`Extension reference "${extensionRef}" must not contain a version.`);
|
|
353
357
|
}
|
|
354
|
-
const url = `/${VERSION}
|
|
358
|
+
const url = `/${VERSION}/${refs.toExtensionName(ref)}`;
|
|
355
359
|
try {
|
|
356
360
|
await api.request("DELETE", url, {
|
|
357
361
|
auth: true,
|
|
@@ -360,24 +364,24 @@ async function deleteExtension(ref) {
|
|
|
360
364
|
}
|
|
361
365
|
catch (err) {
|
|
362
366
|
if (err.status === 403) {
|
|
363
|
-
throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(
|
|
367
|
+
throw new error_1.FirebaseError(`You are not the owner of extension '${clc.bold(extensionRef)}' and don’t have the correct permissions to delete this extension.`, { status: err.status });
|
|
364
368
|
}
|
|
365
369
|
else if (err.status === 404) {
|
|
366
|
-
throw new error_1.FirebaseError(`Extension ${clc.bold(
|
|
370
|
+
throw new error_1.FirebaseError(`Extension ${clc.bold(extensionRef)} was not found.`);
|
|
367
371
|
}
|
|
368
372
|
else if (err instanceof error_1.FirebaseError) {
|
|
369
373
|
throw err;
|
|
370
374
|
}
|
|
371
|
-
throw new error_1.FirebaseError(`Error occurred delete extension '${
|
|
375
|
+
throw new error_1.FirebaseError(`Error occurred delete extension '${extensionRef}': ${err}`, {
|
|
372
376
|
status: err.status,
|
|
373
377
|
});
|
|
374
378
|
}
|
|
375
379
|
}
|
|
376
380
|
exports.deleteExtension = deleteExtension;
|
|
377
|
-
async function getExtension(
|
|
378
|
-
const
|
|
381
|
+
async function getExtension(extensionRef) {
|
|
382
|
+
const ref = refs.parse(extensionRef);
|
|
379
383
|
try {
|
|
380
|
-
const res = await api.request("GET", `/${VERSION}
|
|
384
|
+
const res = await api.request("GET", `/${VERSION}/${refs.toExtensionName(ref)}`, {
|
|
381
385
|
auth: true,
|
|
382
386
|
origin: api.extensionsOrigin,
|
|
383
387
|
});
|
|
@@ -385,50 +389,20 @@ async function getExtension(ref) {
|
|
|
385
389
|
}
|
|
386
390
|
catch (err) {
|
|
387
391
|
if (err.status === 404) {
|
|
388
|
-
throw refNotFoundError(
|
|
392
|
+
throw refNotFoundError(ref);
|
|
389
393
|
}
|
|
390
394
|
else if (err instanceof error_1.FirebaseError) {
|
|
391
395
|
throw err;
|
|
392
396
|
}
|
|
393
|
-
throw new error_1.FirebaseError(`Failed to query the extension '${clc.bold(
|
|
397
|
+
throw new error_1.FirebaseError(`Failed to query the extension '${clc.bold(extensionRef)}': ${err}`, {
|
|
394
398
|
status: err.status,
|
|
395
399
|
});
|
|
396
400
|
}
|
|
397
401
|
}
|
|
398
402
|
exports.getExtension = getExtension;
|
|
399
|
-
function refNotFoundError(
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
` -The publisher ID '${clc.bold(publisherId)}' doesn't exist or could be misspelled\n` +
|
|
404
|
-
` -The name of the ${versionId ? "extension version" : "extension"} '${clc.bold(versionId ? `${extensionId}@${versionId}` : extensionId)}' doesn't exist or could be misspelled\n\n` +
|
|
403
|
+
function refNotFoundError(ref) {
|
|
404
|
+
return new error_1.FirebaseError(`The extension reference '${clc.bold(ref.version ? refs.toExtensionVersionRef(ref) : refs.toExtensionRef(ref))}' doesn't exist. This could happen for two reasons:\n` +
|
|
405
|
+
` -The publisher ID '${clc.bold(ref.publisherId)}' doesn't exist or could be misspelled\n` +
|
|
406
|
+
` -The name of the ${ref.version ? "extension version" : "extension"} '${clc.bold(ref.version ? `${ref.extensionId}@${ref.version}` : ref.extensionId)}' doesn't exist or could be misspelled\n\n` +
|
|
405
407
|
`Please correct the extension reference and try again. If you meant to install an extension from a local source, please provide a relative path prefixed with '${clc.bold("./")}', '${clc.bold("../")}', or '${clc.bold("~/")}'. Learn more about local extension installation at ${marked("[https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install](https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install).")}`, { status: 404 });
|
|
406
408
|
}
|
|
407
|
-
function parseRef(ref) {
|
|
408
|
-
const parts = refRegex.exec(ref);
|
|
409
|
-
if (parts && (parts.length == 5 || parts.length == 7)) {
|
|
410
|
-
const publisherId = parts[1];
|
|
411
|
-
const extensionId = parts[2];
|
|
412
|
-
const version = parts[4];
|
|
413
|
-
if (version && !semver.valid(version) && version !== "latest") {
|
|
414
|
-
throw new error_1.FirebaseError(`Extension reference ${ref} contains an invalid version ${version}.`);
|
|
415
|
-
}
|
|
416
|
-
return { publisherId, extensionId, version };
|
|
417
|
-
}
|
|
418
|
-
throw new error_1.FirebaseError("Extension reference must be in format '{publisher}/{extension}(@{version})'.");
|
|
419
|
-
}
|
|
420
|
-
exports.parseRef = parseRef;
|
|
421
|
-
function parseExtensionVersionName(extensionVersionName) {
|
|
422
|
-
const parts = extensionVersionName.split("/");
|
|
423
|
-
if (parts.length !== 6 ||
|
|
424
|
-
parts[0] !== "publishers" ||
|
|
425
|
-
parts[2] !== "extensions" ||
|
|
426
|
-
parts[4] !== "versions") {
|
|
427
|
-
throw new error_1.FirebaseError("Extension version name must be in the format `publishers/<publisherID>/extensions/<extensionID>/versions/<versionID>`.");
|
|
428
|
-
}
|
|
429
|
-
const publisherId = parts[1];
|
|
430
|
-
const extensionId = parts[3];
|
|
431
|
-
const version = parts[5];
|
|
432
|
-
return { publisherId, extensionId, version };
|
|
433
|
-
}
|
|
434
|
-
exports.parseExtensionVersionName = parseExtensionVersionName;
|