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.
Files changed (82) hide show
  1. package/CHANGELOG.md +1 -3
  2. package/lib/api.js +1 -0
  3. package/lib/apiv2.js +1 -1
  4. package/lib/appdistribution/client.js +84 -72
  5. package/lib/appdistribution/distribution.js +8 -26
  6. package/lib/appdistribution/options-parser-util.js +51 -0
  7. package/lib/command.js +8 -6
  8. package/lib/commands/appdistribution-distribute.js +74 -91
  9. package/lib/commands/appdistribution-testers-add.js +18 -0
  10. package/lib/commands/appdistribution-testers-remove.js +32 -0
  11. package/lib/commands/crashlytics-symbols-upload.js +146 -0
  12. package/lib/commands/ext-configure.js +9 -1
  13. package/lib/commands/ext-dev-extension-delete.js +2 -1
  14. package/lib/commands/ext-dev-init.js +18 -9
  15. package/lib/commands/ext-dev-publish.js +11 -4
  16. package/lib/commands/ext-dev-unpublish.js +2 -1
  17. package/lib/commands/ext-install.js +115 -48
  18. package/lib/commands/ext-uninstall.js +6 -0
  19. package/lib/commands/ext-update.js +67 -43
  20. package/lib/commands/functions-config-export.js +115 -0
  21. package/lib/commands/functions-delete.js +44 -35
  22. package/lib/commands/functions-list.js +54 -0
  23. package/lib/commands/functions-log.js +5 -22
  24. package/lib/commands/hosting-channel-deploy.js +6 -4
  25. package/lib/commands/index.js +12 -0
  26. package/lib/deploy/functions/backend.js +47 -12
  27. package/lib/deploy/functions/containerCleaner.js +5 -1
  28. package/lib/deploy/functions/deploy.js +7 -5
  29. package/lib/deploy/functions/prepare.js +9 -7
  30. package/lib/deploy/functions/prompts.js +3 -21
  31. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +2 -1
  32. package/lib/deploy/functions/runtimes/index.js +2 -1
  33. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +4 -3
  34. package/lib/deploy/functions/runtimes/node/parseTriggers.js +14 -9
  35. package/lib/deploy/functions/triggerRegionHelper.js +32 -0
  36. package/lib/downloadUtils.js +37 -0
  37. package/lib/emulator/auth/apiSpec.js +1758 -404
  38. package/lib/emulator/auth/handlers.js +6 -5
  39. package/lib/emulator/auth/operations.js +429 -40
  40. package/lib/emulator/auth/server.js +18 -11
  41. package/lib/emulator/auth/state.js +186 -5
  42. package/lib/emulator/auth/widget_ui.js +2 -2
  43. package/lib/emulator/download.js +2 -31
  44. package/lib/emulator/downloadableEmulators.js +7 -7
  45. package/lib/emulator/emulatorLogger.js +0 -3
  46. package/lib/emulator/events/types.js +16 -0
  47. package/lib/emulator/functionsEmulator.js +102 -17
  48. package/lib/emulator/functionsEmulatorRuntime.js +46 -121
  49. package/lib/emulator/functionsEmulatorShared.js +51 -7
  50. package/lib/emulator/functionsEmulatorShell.js +1 -1
  51. package/lib/emulator/pubsubEmulator.js +61 -40
  52. package/lib/extensions/askUserForConsent.js +16 -13
  53. package/lib/extensions/askUserForParam.js +72 -3
  54. package/lib/extensions/billingMigrationHelper.js +1 -11
  55. package/lib/extensions/changelog.js +93 -0
  56. package/lib/extensions/displayExtensionInfo.js +38 -38
  57. package/lib/extensions/emulator/optionsHelper.js +3 -3
  58. package/lib/extensions/emulator/triggerHelper.js +2 -32
  59. package/lib/extensions/extensionsApi.js +69 -95
  60. package/lib/extensions/extensionsHelper.js +75 -50
  61. package/lib/extensions/paramHelper.js +79 -36
  62. package/lib/extensions/refs.js +59 -0
  63. package/lib/extensions/resolveSource.js +2 -20
  64. package/lib/extensions/secretsUtils.js +58 -0
  65. package/lib/extensions/updateHelper.js +39 -105
  66. package/lib/extensions/warnings.js +1 -7
  67. package/lib/functional.js +64 -0
  68. package/lib/functions/env.js +26 -13
  69. package/lib/functions/functionslog.js +40 -0
  70. package/lib/functions/listFunctions.js +10 -0
  71. package/lib/functions/runtimeConfigExport.js +137 -0
  72. package/lib/gcp/cloudfunctions.js +84 -9
  73. package/lib/gcp/cloudfunctionsv2.js +99 -7
  74. package/lib/gcp/cloudlogging.js +27 -21
  75. package/lib/gcp/secretManager.js +111 -0
  76. package/lib/gcp/storage.js +16 -0
  77. package/lib/previews.js +1 -1
  78. package/lib/requireInteractive.js +12 -0
  79. package/package.json +5 -4
  80. package/schema/firebase-config.json +2 -1
  81. package/templates/extensions/CHANGELOG.md +7 -0
  82. 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.getConsent = exports.displayUpdateChangesRequiringConfirmation = exports.displayUpdateChangesNoInput = exports.displayExtInfo = void 0;
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, isOfficial = true) {
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 (!isOfficial) {
63
- if (spec.sourceUrl !== newSpec.sourceUrl) {
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(spec, newSpec) {
75
- if (spec.license !== newSpec.license) {
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
- "Do you wish to continue?";
81
- await getConsent("license", marked(message));
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", []), _.isEqual);
84
- const apisDiffAdditions = _.differenceWith(newSpec.apis, _.get(spec, "apis", []), _.isEqual);
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 += "Do you wish to continue?";
94
- await getConsent("apis", marked(message));
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 += "Do you wish to continue?";
107
- await getConsent("resources", marked(message));
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", []), _.isEqual);
110
- const rolesDiffAdditions = _.differenceWith(newSpec.roles, _.get(spec, "roles", []), _.isEqual);
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 += "Do you wish to continue?";
120
- await getConsent("apis", marked(message));
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
- await getConsent("billingRequired", "Billing is now required for the new version of this extension. Would you like to continue?");
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 = await getParams(options, spec);
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
- async function getParams(options, extensionSpec) {
38
+ function getParams(options, extensionSpec) {
39
39
  const projectId = projectUtils_1.needProjectId(options);
40
- const userParams = await paramHelper.readParamsFile(options.testParams);
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 constants_1 = require("../../emulator/constants");
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.parseExtensionVersionName = exports.parseRef = 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.createInstanceFromExtensionVersion = exports.createInstanceFromSource = exports.createInstance = exports.ParamType = exports.Visibility = exports.RegistryLaunchStage = void 0;
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 createInstance(projectId, instanceId, config) {
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
- exports.createInstance = createInstance;
53
- async function createInstanceFromSource(projectId, instanceId, extensionSource, params) {
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
- extensionRef: `${publisherId}/${extensionId}`,
65
- extensionVersion: version || "",
66
- params,
55
+ params: args.params,
67
56
  };
68
- return createInstance(projectId, instanceId, config);
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.createInstanceFromExtensionVersion = createInstanceFromExtensionVersion;
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 { publisherId, extensionId, version } = parseRef(extRef);
142
+ const ref = refs.parse(extRef);
140
143
  const body = {
141
144
  config: {
142
- extensionRef: `${publisherId}/${extensionId}`,
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(ref) {
221
- const { publisherId, extensionId, version } = parseRef(ref);
222
- if (!version) {
223
- throw new error_1.FirebaseError(`ExtensionVersion ref "${ref}" must supply a version.`);
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}/publishers/${publisherId}/extensions/${extensionId}/versions/${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(publisherId, extensionId, version);
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(ref)}': ${err}`);
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 } = parseRef(ref);
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(ref, packageUri, extensionRoot) {
302
- const { publisherId, extensionId, version } = parseRef(ref);
303
- if (!version) {
304
- throw new error_1.FirebaseError(`ExtensionVersion ref "${ref}" must supply a version.`);
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}/publishers/${publisherId}/extensions/${extensionId}/versions:publish`, {
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(ref) {
325
- const { publisherId, extensionId, version } = parseRef(ref);
326
- if (version) {
327
- throw new error_1.FirebaseError(`Extension reference "${ref}" must not contain a version.`);
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}/publishers/${publisherId}/extensions/${extensionId}:unpublish`;
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(ref)}' and don’t have the correct permissions to unpublish this extension.`, { status: err.status });
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 '${ref}': ${err}`, {
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(ref) {
350
- const { publisherId, extensionId, version } = parseRef(ref);
351
- if (version) {
352
- throw new error_1.FirebaseError(`Extension reference "${ref}" must not contain a version.`);
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}/publishers/${publisherId}/extensions/${extensionId}`;
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(ref)}' and don’t have the correct permissions to delete this extension.`, { status: err.status });
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(ref)} was not found.`);
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 '${ref}': ${err}`, {
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(ref) {
378
- const { publisherId, extensionId } = parseRef(ref);
381
+ async function getExtension(extensionRef) {
382
+ const ref = refs.parse(extensionRef);
379
383
  try {
380
- const res = await api.request("GET", `/${VERSION}/publishers/${publisherId}/extensions/${extensionId}`, {
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(publisherId, extensionId);
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(ref)}': ${err}`, {
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(publisherId, extensionId, versionId) {
400
- const versionRef = `${publisherId}/${extensionId}@${versionId}`;
401
- const extensionRef = `${publisherId}/${extensionId}`;
402
- return new error_1.FirebaseError(`The extension reference '${clc.bold(versionId ? versionRef : extensionRef)}' doesn't exist. This could happen for two reasons:\n` +
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;