firebase-tools 10.6.0 → 10.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/lib/command.js +4 -4
  2. package/lib/commands/deploy.js +1 -1
  3. package/lib/commands/emulators-start.js +7 -2
  4. package/lib/commands/ext-configure.js +15 -5
  5. package/lib/commands/ext-export.js +6 -5
  6. package/lib/commands/ext-install.js +28 -44
  7. package/lib/commands/ext-update.js +9 -1
  8. package/lib/commands/functions-delete.js +7 -3
  9. package/lib/commands/hosting-channel-deploy.js +2 -2
  10. package/lib/deploy/database/deploy.js +4 -0
  11. package/lib/deploy/database/index.js +1 -0
  12. package/lib/deploy/extensions/deploy.js +4 -4
  13. package/lib/deploy/extensions/deploymentSummary.js +8 -5
  14. package/lib/deploy/extensions/planner.js +36 -9
  15. package/lib/deploy/extensions/prepare.js +1 -1
  16. package/lib/deploy/extensions/secrets.js +2 -2
  17. package/lib/deploy/extensions/tasks.js +60 -21
  18. package/lib/deploy/functions/backend.js +37 -2
  19. package/lib/deploy/functions/build.js +173 -0
  20. package/lib/deploy/functions/checkIam.js +11 -14
  21. package/lib/deploy/functions/containerCleaner.js +8 -7
  22. package/lib/deploy/functions/deploy.js +49 -28
  23. package/lib/deploy/functions/ensure.js +4 -4
  24. package/lib/deploy/functions/functionsDeployHelper.js +99 -24
  25. package/lib/deploy/functions/prepare.js +129 -71
  26. package/lib/deploy/functions/prepareFunctionsUpload.js +16 -21
  27. package/lib/deploy/functions/pricing.js +6 -3
  28. package/lib/deploy/functions/prompts.js +1 -7
  29. package/lib/deploy/functions/release/executor.js +1 -1
  30. package/lib/deploy/functions/release/fabricator.js +69 -25
  31. package/lib/deploy/functions/release/index.js +20 -6
  32. package/lib/deploy/functions/release/planner.js +18 -10
  33. package/lib/deploy/functions/release/reporter.js +14 -11
  34. package/lib/deploy/functions/runtimes/discovery/parsing.js +12 -6
  35. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +50 -3
  36. package/lib/deploy/functions/runtimes/golang/index.js +3 -0
  37. package/lib/deploy/functions/runtimes/node/index.js +7 -0
  38. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
  39. package/lib/deploy/functions/runtimes/node/parseTriggers.js +132 -6
  40. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  41. package/lib/deploy/functions/services/auth.js +95 -0
  42. package/lib/deploy/functions/services/index.js +41 -21
  43. package/lib/deploy/functions/validate.js +33 -7
  44. package/lib/deploy/hosting/args.js +2 -0
  45. package/lib/deploy/hosting/convertConfig.js +39 -8
  46. package/lib/deploy/hosting/deploy.js +3 -3
  47. package/lib/deploy/hosting/prepare.js +2 -2
  48. package/lib/deploy/hosting/release.js +6 -2
  49. package/lib/deploy/index.js +82 -93
  50. package/lib/deploy/remoteconfig/deploy.js +4 -0
  51. package/lib/deploy/remoteconfig/index.js +3 -1
  52. package/lib/emulator/auth/cloudFunctions.js +6 -2
  53. package/lib/emulator/auth/operations.js +5 -1
  54. package/lib/emulator/auth/server.js +8 -1
  55. package/lib/emulator/auth/state.js +27 -24
  56. package/lib/emulator/auth/utils.js +3 -25
  57. package/lib/emulator/controller.js +17 -14
  58. package/lib/emulator/databaseEmulator.js +36 -3
  59. package/lib/emulator/downloadableEmulators.js +39 -23
  60. package/lib/emulator/extensions/validation.js +2 -2
  61. package/lib/emulator/extensionsEmulator.js +85 -21
  62. package/lib/emulator/functionsEmulator.js +89 -15
  63. package/lib/emulator/functionsEmulatorRuntime.js +1 -1
  64. package/lib/emulator/functionsEmulatorShared.js +25 -2
  65. package/lib/emulator/functionsEmulatorShell.js +2 -3
  66. package/lib/emulator/functionsEmulatorUtils.js +5 -1
  67. package/lib/emulator/pubsubEmulator.js +13 -9
  68. package/lib/emulator/registry.js +34 -12
  69. package/lib/emulator/storage/apis/firebase.js +33 -6
  70. package/lib/emulator/storage/apis/gcloud.js +6 -3
  71. package/lib/emulator/storage/files.js +9 -1
  72. package/lib/ensureApiEnabled.js +8 -4
  73. package/lib/extensions/changelog.js +1 -1
  74. package/lib/extensions/emulator/optionsHelper.js +4 -3
  75. package/lib/extensions/emulator/specHelper.js +7 -1
  76. package/lib/extensions/extensionsHelper.js +30 -24
  77. package/lib/extensions/manifest.js +27 -7
  78. package/lib/extensions/paramHelper.js +7 -5
  79. package/lib/extensions/provisioningHelper.js +2 -2
  80. package/lib/extensions/warnings.js +11 -4
  81. package/lib/functions/events/index.js +7 -0
  82. package/lib/functions/events/v1.js +6 -0
  83. package/lib/functions/projectConfig.js +32 -6
  84. package/lib/functionsShellCommandAction.js +1 -1
  85. package/lib/gcp/cloudfunctions.js +38 -5
  86. package/lib/gcp/cloudfunctionsv2.js +46 -7
  87. package/lib/gcp/identityPlatform.js +44 -0
  88. package/lib/gcp/secretManager.js +1 -1
  89. package/lib/metaprogramming.js +2 -0
  90. package/lib/previews.js +1 -1
  91. package/lib/serve/functions.js +16 -19
  92. package/lib/serve/hosting.js +25 -12
  93. package/lib/serve/index.js +6 -0
  94. package/lib/track.js +15 -21
  95. package/npm-shrinkwrap.json +256 -527
  96. package/package.json +6 -3
  97. package/schema/firebase-config.json +6 -0
package/lib/command.js CHANGED
@@ -9,7 +9,7 @@ const rc_1 = require("./rc");
9
9
  const config_1 = require("./config");
10
10
  const configstore_1 = require("./configstore");
11
11
  const detectProjectRoot_1 = require("./detectProjectRoot");
12
- const track = require("./track");
12
+ const track_1 = require("./track");
13
13
  const clc = require("cli-color");
14
14
  const auth_1 = require("./auth");
15
15
  const projects_1 = require("./management/projects");
@@ -85,7 +85,7 @@ class Command {
85
85
  }, null, 2));
86
86
  }
87
87
  const duration = new Date().getTime() - start;
88
- void track(this.name, "success", duration).then(() => process.exit());
88
+ void (0, track_1.track)(this.name, "success", duration).then(() => process.exit());
89
89
  })
90
90
  .catch(async (err) => {
91
91
  if ((0, utils_1.getInheritedOption)(options, "json")) {
@@ -96,7 +96,7 @@ class Command {
96
96
  }
97
97
  const duration = Date.now() - start;
98
98
  const errorEvent = err.exit === 1 ? "Error (User)" : "Error (Unexpected)";
99
- await Promise.all([track(this.name, "error", duration), track(errorEvent, "", duration)]);
99
+ await Promise.all([(0, track_1.track)(this.name, "error", duration), (0, track_1.track)(errorEvent, "", duration)]);
100
100
  client.errorOut(err);
101
101
  });
102
102
  });
@@ -197,7 +197,7 @@ function validateProjectId(project) {
197
197
  if (PROJECT_ID_REGEX.test(project)) {
198
198
  return;
199
199
  }
200
- track("Project ID Check", "invalid");
200
+ (0, track_1.track)("Project ID Check", "invalid");
201
201
  const invalidMessage = "Invalid project id: " + clc.bold(project) + ".";
202
202
  if (project.toLowerCase() !== project) {
203
203
  throw new error_1.FirebaseError(invalidMessage + "\nNote: Project id must be all lowercase.");
@@ -5,7 +5,7 @@ const { requirePermissions } = require("../requirePermissions");
5
5
  const { checkServiceAccountIam } = require("../deploy/functions/checkIam");
6
6
  const checkValidTargetFilters = require("../checkValidTargetFilters");
7
7
  const { Command } = require("../command");
8
- const deploy = require("../deploy");
8
+ const { deploy } = require("../deploy");
9
9
  const { requireConfig } = require("../requireConfig");
10
10
  const { filterTargets } = require("../filterTargets");
11
11
  const { requireHostingSite } = require("../requireHostingSite");
@@ -63,7 +63,7 @@ module.exports = new command_1.Command("emulators:start")
63
63
  .map((emulator) => {
64
64
  const emulatorName = constants_1.Constants.description(emulator).replace(/ emulator/i, "");
65
65
  const isSupportedByUi = types_1.EMULATORS_SUPPORTED_BY_UI.includes(emulator);
66
- const info = registry_1.EmulatorRegistry.getInfo(emulator === types_1.Emulators.EXTENSIONS ? types_1.Emulators.FUNCTIONS : emulator);
66
+ const info = registry_1.EmulatorRegistry.getInfo(emulator);
67
67
  if (!info) {
68
68
  return [emulatorName, "Failed to initialize (see above)", "", ""];
69
69
  }
@@ -77,6 +77,11 @@ module.exports = new command_1.Command("emulators:start")
77
77
  })
78
78
  .map((col) => col.slice(0, head.length))
79
79
  .filter((v) => v));
80
+ let extensionsTable = "";
81
+ if (registry_1.EmulatorRegistry.isRunning(types_1.Emulators.EXTENSIONS)) {
82
+ const extensionsEmulatorInstance = registry_1.EmulatorRegistry.get(types_1.Emulators.EXTENSIONS);
83
+ extensionsTable = extensionsEmulatorInstance.extensionsInfoTable(options);
84
+ }
80
85
  logger_1.logger.info(`\n${successMessageTable}
81
86
 
82
87
  ${emulatorsTable}
@@ -84,7 +89,7 @@ ${hubInfo
84
89
  ? clc.blackBright(" Emulator Hub running at ") + registry_1.EmulatorRegistry.getInfoHostString(hubInfo)
85
90
  : clc.blackBright(" Emulator Hub not running.")}
86
91
  ${clc.blackBright(" Other reserved ports:")} ${reservedPortsString}
87
-
92
+ ${extensionsTable}
88
93
  Issues? Report them at ${stylizeLink("https://github.com/firebase/firebase-tools/issues")} and attach the *-debug.log files.
89
94
  `);
90
95
  for (const notice of deprecationNotices) {
@@ -41,13 +41,22 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
41
41
  throw new error_1.FirebaseError(`Command not supported in non-interactive mode, edit ./extensions/${instanceId}.env directly instead`);
42
42
  }
43
43
  const config = manifest.loadConfig(options);
44
- const targetRef = manifest.getInstanceRef(instanceId, config);
45
- const extensionVersion = await extensionsApi.getExtensionVersion(refs.toExtensionVersionRef(targetRef));
44
+ const refOrPath = manifest.getInstanceTarget(instanceId, config);
45
+ const isLocalSource = (0, extensionsHelper_1.isLocalPath)(refOrPath);
46
+ let spec;
47
+ if (isLocalSource) {
48
+ const source = await (0, extensionsHelper_1.createSourceFromLocation)((0, projectUtils_1.needProjectId)({ projectId }), refOrPath);
49
+ spec = source.spec;
50
+ }
51
+ else {
52
+ const extensionVersion = await extensionsApi.getExtensionVersion(refOrPath);
53
+ spec = extensionVersion.spec;
54
+ }
46
55
  const oldParamValues = manifest.readInstanceParam({
47
56
  instanceId,
48
57
  projectDir: config.projectDir,
49
58
  });
50
- const [immutableParams, tbdParams] = (0, functional_1.partition)(extensionVersion.spec.params, (param) => { var _a; return (_a = param.immutable) !== null && _a !== void 0 ? _a : false; });
59
+ const [immutableParams, tbdParams] = (0, functional_1.partition)(spec.params, (param) => { var _a; return (_a = param.immutable) !== null && _a !== void 0 ? _a : false; });
51
60
  infoImmutableParams(immutableParams, oldParamValues);
52
61
  paramHelper.setNewDefaults(tbdParams, oldParamValues);
53
62
  const mutableParamsBindingOptions = await paramHelper.getParams({
@@ -62,9 +71,10 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
62
71
  await manifest.writeToManifest([
63
72
  {
64
73
  instanceId,
65
- ref: targetRef,
74
+ ref: !isLocalSource ? refs.parse(refOrPath) : undefined,
75
+ localPath: isLocalSource ? refOrPath : undefined,
66
76
  params: newParamOptions,
67
- paramSpecs: extensionVersion.spec.params,
77
+ extensionSpec: spec,
68
78
  },
69
79
  ], config, {
70
80
  nonInteractive: false,
@@ -22,16 +22,17 @@ module.exports = new command_1.Command("ext:export")
22
22
  .action(async (options) => {
23
23
  const projectId = (0, projectUtils_1.needProjectId)(options);
24
24
  const projectNumber = await (0, getProjectNumber_1.getProjectNumber)(options);
25
- const have = await Promise.all((await planner.have(projectId)).map(async (i) => {
26
- const subbed = await (0, export_1.setSecretParamsToLatest)(i);
27
- return (0, export_1.parameterizeProject)(projectId, projectNumber, subbed);
28
- }));
25
+ const have = await Promise.all(await planner.have(projectId));
29
26
  if (have.length === 0) {
30
27
  logger_1.logger.info(`No extension instances installed on ${projectId}, so there is nothing to export.`);
31
28
  return;
32
29
  }
33
30
  const [withRef, withoutRef] = (0, functional_1.partition)(have, (s) => !!s.ref);
34
- (0, export_1.displayExportInfo)(withRef, withoutRef);
31
+ const withRefSubbed = await Promise.all(withRef.map(async (i) => {
32
+ const subbed = await (0, export_1.setSecretParamsToLatest)(i);
33
+ return (0, export_1.parameterizeProject)(projectId, projectNumber, subbed);
34
+ }));
35
+ (0, export_1.displayExportInfo)(withRefSubbed, withoutRef);
35
36
  if (!options.nonInteractive &&
36
37
  !options.force &&
37
38
  !(await (0, prompt_1.promptOnce)({
@@ -46,7 +46,7 @@ exports.default = new command_1.Command("ext:install [extensionName]")
46
46
  .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
47
47
  .before(extensionsHelper_1.diagnoseAndFixProject)
48
48
  .action(async (extensionName, options) => {
49
- var _a;
49
+ var _a, _b;
50
50
  const projectId = (0, projectUtils_1.getProjectId)(options);
51
51
  const paramsEnvPath = ((_a = options.params) !== null && _a !== void 0 ? _a : "");
52
52
  let learnMore = false;
@@ -62,20 +62,23 @@ exports.default = new command_1.Command("ext:install [extensionName]")
62
62
  }
63
63
  }
64
64
  let source;
65
- let extVersion;
65
+ let extensionVersion;
66
66
  if ((0, extensionsHelper_1.isUrlPath)(extensionName)) {
67
- void (0, track_1.track)("Extension Install", "Install by url path", options.interactive ? 1 : 0);
67
+ throw new error_1.FirebaseError(`Installing with a source url is no longer supported in the CLI. Please use Firebase Console instead.`);
68
68
  }
69
- if ((0, extensionsHelper_1.isLocalOrURLPath)(extensionName)) {
69
+ if ((0, extensionsHelper_1.isLocalPath)(extensionName)) {
70
+ source = await (0, extensionsHelper_1.createSourceFromLocation)((0, projectUtils_1.needProjectId)({ projectId }), extensionName);
71
+ (0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
70
72
  void (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
71
- if (options.local) {
72
- throw new error_1.FirebaseError("Installing a local source locally is not supported yet, please use ext:dev:emulator commands");
73
- }
74
- source = await infoInstallBySource((0, projectUtils_1.needProjectId)({ projectId }), extensionName);
75
73
  }
76
74
  else {
77
75
  void (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
78
- extVersion = await infoInstallByReference(extensionName, options.interactive);
76
+ extensionName = (0, extensionsHelper_1.canonicalizeRefInput)(extensionName);
77
+ extensionVersion = await extensionsApi.getExtensionVersion(extensionName);
78
+ await infoExtensionVersion({
79
+ extensionName,
80
+ extensionVersion,
81
+ });
79
82
  }
80
83
  if (!(await (0, extensionsHelper_1.confirm)({
81
84
  nonInteractive: options.nonInteractive,
@@ -84,10 +87,10 @@ exports.default = new command_1.Command("ext:install [extensionName]")
84
87
  }))) {
85
88
  return;
86
89
  }
87
- if (!source && !extVersion) {
90
+ if (!source && !extensionVersion) {
88
91
  throw new error_1.FirebaseError("Could not find a source. Please specify a valid source to continue.");
89
92
  }
90
- const spec = (source === null || source === void 0 ? void 0 : source.spec) || (extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec);
93
+ const spec = (_b = source === null || source === void 0 ? void 0 : source.spec) !== null && _b !== void 0 ? _b : extensionVersion === null || extensionVersion === void 0 ? void 0 : extensionVersion.spec;
91
94
  if (!spec) {
92
95
  throw new error_1.FirebaseError(`Could not find the extension.yaml for extension '${clc.bold(extensionName)}'. Please make sure this is a valid extension and try again.`);
93
96
  }
@@ -103,7 +106,7 @@ exports.default = new command_1.Command("ext:install [extensionName]")
103
106
  projectId,
104
107
  extensionName,
105
108
  source,
106
- extVersion,
109
+ extVersion: extensionVersion,
107
110
  nonInteractive: options.nonInteractive,
108
111
  force: options.force,
109
112
  });
@@ -123,7 +126,7 @@ exports.default = new command_1.Command("ext:install [extensionName]")
123
126
  projectId: projectId,
124
127
  extensionName,
125
128
  source,
126
- extVersion,
129
+ extVersion: extensionVersion,
127
130
  nonInteractive: options.nonInteractive,
128
131
  force: options.force,
129
132
  });
@@ -137,37 +140,17 @@ exports.default = new command_1.Command("ext:install [extensionName]")
137
140
  throw err;
138
141
  }
139
142
  });
140
- async function infoInstallBySource(projectId, extensionName) {
141
- let source;
142
- try {
143
- source = await (0, extensionsHelper_1.createSourceFromLocation)(projectId, extensionName);
144
- }
145
- catch (err) {
146
- throw new error_1.FirebaseError(`Unable to find published extension '${clc.bold(extensionName)}', ` +
147
- `and encountered the following error when trying to create an instance of extension '${clc.bold(extensionName)}':\n ${err.message}`);
148
- }
149
- (0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
150
- return source;
151
- }
152
- async function infoInstallByReference(extensionName, interactive) {
153
- if (extensionName.split("/").length < 2) {
154
- const [extensionID, version] = extensionName.split("@");
155
- extensionName = `firebase/${extensionID}@${version || "latest"}`;
156
- }
157
- const ref = refs.parse(extensionName);
143
+ async function infoExtensionVersion(args) {
144
+ const ref = refs.parse(args.extensionName);
158
145
  const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
159
- if (!ref.version) {
160
- void (0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
161
- extensionName = `${extensionName}@latest`;
162
- }
163
- const extVersion = await extensionsApi.getExtensionVersion(extensionName);
164
- (0, displayExtensionInfo_1.displayExtInfo)(extensionName, ref.publisherId, extVersion.spec, true);
165
- await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, extVersion);
166
- return extVersion;
146
+ (0, displayExtensionInfo_1.displayExtInfo)(args.extensionName, ref.publisherId, args.extensionVersion.spec, true);
147
+ await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, args.extensionVersion);
167
148
  }
168
149
  async function installToManifest(options) {
169
- const { projectId, extensionName, extVersion, paramsEnvPath, nonInteractive, force } = options;
170
- const spec = extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec;
150
+ var _a;
151
+ const { projectId, extensionName, extVersion, source, paramsEnvPath, nonInteractive, force } = options;
152
+ const isLocalSource = (0, extensionsHelper_1.isLocalPath)(extensionName);
153
+ const spec = (_a = extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec) !== null && _a !== void 0 ? _a : source === null || source === void 0 ? void 0 : source.spec;
171
154
  if (!spec) {
172
155
  throw new error_1.FirebaseError(`Could not find the extension.yaml for ${extensionName}. Please make sure this is a valid extension and try again.`);
173
156
  }
@@ -183,13 +166,14 @@ async function installToManifest(options) {
183
166
  paramsEnvPath,
184
167
  instanceId,
185
168
  });
186
- const ref = refs.parse(extVersion.ref);
169
+ const ref = extVersion ? refs.parse(extVersion.ref) : undefined;
187
170
  await manifest.writeToManifest([
188
171
  {
189
172
  instanceId,
190
- ref,
173
+ ref: !isLocalSource ? ref : undefined,
174
+ localPath: isLocalSource ? extensionName : undefined,
191
175
  params: paramBindingOptions,
192
- paramSpecs: spec.params,
176
+ extensionSpec: spec,
193
177
  },
194
178
  ], config, { nonInteractive, force: force !== null && force !== void 0 ? force : false });
195
179
  manifest.showPreviewWarning();
@@ -45,6 +45,13 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
45
45
  if (options.local) {
46
46
  const projectId = (0, projectUtils_1.getProjectId)(options);
47
47
  const config = manifest.loadConfig(options);
48
+ const oldRefOrPath = manifest.getInstanceTarget(instanceId, config);
49
+ if ((0, extensionsHelper_1.isLocalPath)(oldRefOrPath)) {
50
+ throw new error_1.FirebaseError(`Updating an extension with local source is not neccessary. ` +
51
+ `Rerun "firebase deploy" or restart the emulator after making changes to your local extension source. ` +
52
+ `If you've edited the extension param spec, you can edit an extension instance's params ` +
53
+ `interactively by running "firebase ext:configure --local {instance-id}"`);
54
+ }
48
55
  const oldRef = manifest.getInstanceRef(instanceId, config);
49
56
  const oldExtensionVersion = await extensionsApi.getExtensionVersion(refs.toExtensionVersionRef(oldRef));
50
57
  updateSource = (0, updateHelper_1.inferUpdateSource)(updateSource, refs.toExtensionRef(oldRef));
@@ -84,7 +91,8 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
84
91
  instanceId,
85
92
  ref: refs.parse(newExtensionVersion.ref),
86
93
  params: newParamBindingOptions,
87
- paramSpecs: newExtensionVersion.spec.params,
94
+ extensionSpec: newExtensionVersion.spec,
95
+ extensionVersion: newExtensionVersion,
88
96
  },
89
97
  ], config, {
90
98
  nonInteractive: options.nonInteractive,
@@ -29,7 +29,7 @@ exports.default = new command_1.Command("functions:delete [filters...]")
29
29
  }
30
30
  const context = {
31
31
  projectId: (0, projectUtils_1.needProjectId)(options),
32
- filters: filters.map((f) => f.split(".")),
32
+ filters: filters.map((f) => ({ idChunks: f.split(".") })),
33
33
  };
34
34
  const [config, existingBackend] = await Promise.all([
35
35
  functionsConfig.getFirebaseConfig(options),
@@ -40,7 +40,10 @@ exports.default = new command_1.Command("functions:delete [filters...]")
40
40
  if (options.region) {
41
41
  existingBackend.endpoints = { [options.region]: existingBackend.endpoints[options.region] };
42
42
  }
43
- const plan = planner.createDeploymentPlan(backend.empty(), existingBackend, {
43
+ const plan = planner.createDeploymentPlan({
44
+ wantBackend: backend.empty(),
45
+ haveBackend: existingBackend,
46
+ codebase: "",
44
47
  filters: context.filters,
45
48
  deleteAll: true,
46
49
  });
@@ -72,8 +75,9 @@ exports.default = new command_1.Command("functions:delete [filters...]")
72
75
  try {
73
76
  const fab = new fabricator.Fabricator({
74
77
  functionExecutor,
75
- executor: new executor.QueueExecutor({}),
76
78
  appEngineLocation,
79
+ executor: new executor.QueueExecutor({}),
80
+ sources: {},
77
81
  });
78
82
  const summary = await fab.applyPlan(plan);
79
83
  await reporter.logAndTrackDeployStats(summary);
@@ -6,7 +6,7 @@ const error_1 = require("../error");
6
6
  const api_1 = require("../hosting/api");
7
7
  const normalizedHostingConfigs_1 = require("../hosting/normalizedHostingConfigs");
8
8
  const requirePermissions_1 = require("../requirePermissions");
9
- const deploy = require("../deploy");
9
+ const deploy_1 = require("../deploy");
10
10
  const projectUtils_1 = require("../projectUtils");
11
11
  const logger_1 = require("../logger");
12
12
  const requireConfig_1 = require("../requireConfig");
@@ -82,7 +82,7 @@ exports.default = new command_1.Command("hosting:channel:deploy [channelId]")
82
82
  siteInfo.expireTime = chan.expireTime;
83
83
  return;
84
84
  }));
85
- const { hosting } = await deploy(["hosting"], options, { hostingChannel: channelId });
85
+ const { hosting } = await (0, deploy_1.deploy)(["hosting"], options, { hostingChannel: channelId });
86
86
  const versionNames = [];
87
87
  if (typeof hosting === "string") {
88
88
  versionNames.push(hosting);
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function default_1() { }
4
+ exports.default = default_1;
@@ -2,4 +2,5 @@
2
2
  module.exports = {
3
3
  prepare: require("./prepare"),
4
4
  release: require("./release"),
5
+ deploy: require("./deploy").default,
5
6
  };
@@ -10,7 +10,7 @@ const provisioningHelper_1 = require("../../extensions/provisioningHelper");
10
10
  const secrets_1 = require("./secrets");
11
11
  const validate_1 = require("./validate");
12
12
  async function deploy(context, options, payload) {
13
- var _a, _b, _c, _d, _e, _f;
13
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
14
14
  const projectId = (0, projectUtils_1.needProjectId)(options);
15
15
  await (0, validate_1.checkBilling)(projectId, options.nonInteractive);
16
16
  await (0, provisioningHelper_1.bulkCheckProductsProvisioned)(projectId, [
@@ -25,15 +25,15 @@ async function deploy(context, options, payload) {
25
25
  concurrency: 5,
26
26
  handler: tasks.extensionsDeploymentHandler(errorHandler),
27
27
  });
28
- for (const create of (_d = payload.instancesToCreate) !== null && _d !== void 0 ? _d : []) {
28
+ for (const create of (_e = (_d = payload.instancesToCreate) === null || _d === void 0 ? void 0 : _d.filter((i) => !!i.ref)) !== null && _e !== void 0 ? _e : []) {
29
29
  const task = tasks.createExtensionInstanceTask(projectId, create, true);
30
30
  void validationQueue.run(task);
31
31
  }
32
- for (const update of (_e = payload.instancesToUpdate) !== null && _e !== void 0 ? _e : []) {
32
+ for (const update of (_g = (_f = payload.instancesToUpdate) === null || _f === void 0 ? void 0 : _f.filter((i) => !!i.ref)) !== null && _g !== void 0 ? _g : []) {
33
33
  const task = tasks.updateExtensionInstanceTask(projectId, update, true);
34
34
  void validationQueue.run(task);
35
35
  }
36
- for (const configure of (_f = payload.instancesToConfigure) !== null && _f !== void 0 ? _f : []) {
36
+ for (const configure of (_j = (_h = payload.instancesToConfigure) === null || _h === void 0 ? void 0 : _h.filter((i) => !!i.ref)) !== null && _j !== void 0 ? _j : []) {
37
37
  const task = tasks.configureExtensionInstanceTask(projectId, configure, true);
38
38
  void validationQueue.run(task);
39
39
  }
@@ -6,16 +6,19 @@ const refs = require("../../extensions/refs");
6
6
  const humanReadable = (dep) => `${clc.bold(dep.instanceId)} (${dep.ref ? `${refs.toExtensionVersionRef(dep.ref)}` : `Installed from local source`})`;
7
7
  exports.humanReadable = humanReadable;
8
8
  const humanReadableUpdate = (from, to) => {
9
- var _a, _b, _c, _d, _e;
10
- if (((_a = from.ref) === null || _a === void 0 ? void 0 : _a.publisherId) === ((_b = to.ref) === null || _b === void 0 ? void 0 : _b.publisherId) &&
11
- ((_c = from.ref) === null || _c === void 0 ? void 0 : _c.extensionId) === ((_d = to.ref) === null || _d === void 0 ? void 0 : _d.extensionId)) {
12
- return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${(_e = to.ref) === null || _e === void 0 ? void 0 : _e.version})`;
9
+ var _a;
10
+ if (from.ref &&
11
+ to.ref &&
12
+ from.ref.publisherId === to.ref.publisherId &&
13
+ from.ref.extensionId === to.ref.extensionId) {
14
+ return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${(_a = to.ref) === null || _a === void 0 ? void 0 : _a.version})`;
13
15
  }
14
16
  else {
15
17
  const fromRef = from.ref
16
18
  ? `${refs.toExtensionVersionRef(from.ref)}`
17
19
  : `Installed from local source`;
18
- return `\t${clc.bold(from.instanceId)} (${fromRef} => ${refs.toExtensionVersionRef(to.ref)})`;
20
+ const toRef = to.ref ? `${refs.toExtensionVersionRef(to.ref)}` : `Installed from local source`;
21
+ return `\t${clc.bold(from.instanceId)} (${fromRef} => ${toRef})`;
19
22
  }
20
23
  };
21
24
  function createsSummary(toCreate) {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveVersion = exports.want = exports.have = exports.getExtension = exports.getExtensionVersion = void 0;
3
+ exports.resolveVersion = exports.want = exports.have = exports.getExtensionSpec = exports.getExtension = exports.getExtensionVersion = void 0;
4
4
  const semver = require("semver");
5
5
  const extensionsApi = require("../../extensions/extensionsApi");
6
6
  const refs = require("../../extensions/refs");
@@ -8,6 +8,7 @@ const error_1 = require("../../error");
8
8
  const extensionsHelper_1 = require("../../extensions/extensionsHelper");
9
9
  const logger_1 = require("../../logger");
10
10
  const manifest_1 = require("../../extensions/manifest");
11
+ const specHelper_1 = require("../../extensions/emulator/specHelper");
11
12
  async function getExtensionVersion(i) {
12
13
  if (!i.extensionVersion) {
13
14
  if (!i.ref) {
@@ -20,7 +21,7 @@ async function getExtensionVersion(i) {
20
21
  exports.getExtensionVersion = getExtensionVersion;
21
22
  async function getExtension(i) {
22
23
  if (!i.ref) {
23
- throw new error_1.FirebaseError(`Can't get Extensionfor ${i.instanceId} because it has no ref`);
24
+ throw new error_1.FirebaseError(`Can't get Extension for ${i.instanceId} because it has no ref`);
24
25
  }
25
26
  if (!i.extension) {
26
27
  i.extension = await extensionsApi.getExtension(refs.toExtensionRef(i.ref));
@@ -28,6 +29,23 @@ async function getExtension(i) {
28
29
  return i.extension;
29
30
  }
30
31
  exports.getExtension = getExtension;
32
+ async function getExtensionSpec(i) {
33
+ if (!i.extensionSpec) {
34
+ if (i.ref) {
35
+ const extensionVersion = await getExtensionVersion(i);
36
+ i.extensionSpec = extensionVersion.spec;
37
+ }
38
+ else if (i.localPath) {
39
+ i.extensionSpec = await (0, specHelper_1.readExtensionYaml)(i.localPath);
40
+ i.extensionSpec.postinstallContent = await (0, specHelper_1.readPostinstall)(i.localPath);
41
+ }
42
+ else {
43
+ throw new error_1.FirebaseError("InstanceSpec had no ref or localPath, unable to get extensionSpec");
44
+ }
45
+ }
46
+ return i.extensionSpec;
47
+ }
48
+ exports.getExtensionSpec = getExtensionSpec;
31
49
  async function have(projectId) {
32
50
  const instances = await extensionsApi.listInstances(projectId);
33
51
  return instances.map((i) => {
@@ -50,8 +68,6 @@ async function want(args) {
50
68
  for (const e of Object.entries(args.extensions)) {
51
69
  try {
52
70
  const instanceId = e[0];
53
- const ref = refs.parse(e[1]);
54
- ref.version = await resolveVersion(ref);
55
71
  const params = (0, manifest_1.readInstanceParam)({
56
72
  projectDir: args.projectDir,
57
73
  instanceId,
@@ -62,11 +78,22 @@ async function want(args) {
62
78
  });
63
79
  const autoPopulatedParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId, args.emulatorMode);
64
80
  const subbedParams = (0, extensionsHelper_1.substituteParams)(params, autoPopulatedParams);
65
- instanceSpecs.push({
66
- instanceId,
67
- ref,
68
- params: subbedParams,
69
- });
81
+ if ((0, extensionsHelper_1.isLocalPath)(e[1])) {
82
+ instanceSpecs.push({
83
+ instanceId,
84
+ localPath: e[1],
85
+ params: subbedParams,
86
+ });
87
+ }
88
+ else {
89
+ const ref = refs.parse(e[1]);
90
+ ref.version = await resolveVersion(ref);
91
+ instanceSpecs.push({
92
+ instanceId,
93
+ ref,
94
+ params: subbedParams,
95
+ });
96
+ }
70
97
  }
71
98
  catch (err) {
72
99
  logger_1.logger.debug(`Got error reading extensions entry ${e}: ${err}`);
@@ -28,7 +28,7 @@ async function prepare(context, options, payload) {
28
28
  projectDir: options.config.projectDir,
29
29
  extensions: options.config.get("extensions"),
30
30
  });
31
- const usingSecrets = await Promise.all((_a = context.have) === null || _a === void 0 ? void 0 : _a.map(secrets_1.checkSpecForSecrets));
31
+ const usingSecrets = await Promise.all((_a = context.want) === null || _a === void 0 ? void 0 : _a.map(secrets_1.checkSpecForSecrets));
32
32
  if (usingSecrets.some((i) => i)) {
33
33
  await (0, secretsUtils_1.ensureSecretManagerApiEnabled)(options);
34
34
  }
@@ -29,8 +29,8 @@ async function handleSecretParams(payload, have, nonInteractive) {
29
29
  }
30
30
  exports.handleSecretParams = handleSecretParams;
31
31
  async function checkSpecForSecrets(i) {
32
- const extensionVersion = await (0, planner_1.getExtensionVersion)(i);
33
- return secretUtils.usesSecrets(extensionVersion.spec);
32
+ const extensionSpec = await (0, planner_1.getExtensionSpec)(i);
33
+ return secretUtils.usesSecrets(extensionSpec);
34
34
  }
35
35
  exports.checkSpecForSecrets = checkSpecForSecrets;
36
36
  const secretsInSpec = (spec) => {
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deleteExtensionInstanceTask = exports.configureExtensionInstanceTask = exports.updateExtensionInstanceTask = exports.createExtensionInstanceTask = exports.extensionsDeploymentHandler = void 0;
4
4
  const clc = require("cli-color");
5
+ const error_1 = require("../../error");
5
6
  const extensionsApi = require("../../extensions/extensionsApi");
7
+ const extensionsHelper_1 = require("../../extensions/extensionsHelper");
6
8
  const refs = require("../../extensions/refs");
7
9
  const utils = require("../../utils");
8
10
  const isRetryable = (err) => err.status === 429 || err.status === 409;
@@ -25,13 +27,28 @@ function extensionsDeploymentHandler(errorHandler) {
25
27
  exports.extensionsDeploymentHandler = extensionsDeploymentHandler;
26
28
  function createExtensionInstanceTask(projectId, instanceSpec, validateOnly = false) {
27
29
  const run = async () => {
28
- const res = await extensionsApi.createInstance({
29
- projectId,
30
- instanceId: instanceSpec.instanceId,
31
- params: instanceSpec.params,
32
- extensionVersionRef: refs.toExtensionVersionRef(instanceSpec.ref),
33
- validateOnly,
34
- });
30
+ if (instanceSpec.ref) {
31
+ await extensionsApi.createInstance({
32
+ projectId,
33
+ instanceId: instanceSpec.instanceId,
34
+ params: instanceSpec.params,
35
+ extensionVersionRef: refs.toExtensionVersionRef(instanceSpec.ref),
36
+ validateOnly,
37
+ });
38
+ }
39
+ else if (instanceSpec.localPath) {
40
+ const extensionSource = await (0, extensionsHelper_1.createSourceFromLocation)(projectId, instanceSpec.localPath);
41
+ await extensionsApi.createInstance({
42
+ projectId,
43
+ instanceId: instanceSpec.instanceId,
44
+ params: instanceSpec.params,
45
+ extensionSource,
46
+ validateOnly,
47
+ });
48
+ }
49
+ else {
50
+ throw new error_1.FirebaseError(`Tried to create extension instance ${instanceSpec.instanceId} without a ref or a local path. This should never happen.`);
51
+ }
35
52
  printSuccess(instanceSpec.instanceId, "create", validateOnly);
36
53
  return;
37
54
  };
@@ -44,13 +61,27 @@ function createExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
44
61
  exports.createExtensionInstanceTask = createExtensionInstanceTask;
45
62
  function updateExtensionInstanceTask(projectId, instanceSpec, validateOnly = false) {
46
63
  const run = async () => {
47
- const res = await extensionsApi.updateInstanceFromRegistry({
48
- projectId,
49
- instanceId: instanceSpec.instanceId,
50
- extRef: refs.toExtensionVersionRef(instanceSpec.ref),
51
- params: instanceSpec.params,
52
- validateOnly,
53
- });
64
+ if (instanceSpec.ref) {
65
+ await extensionsApi.updateInstanceFromRegistry({
66
+ projectId,
67
+ instanceId: instanceSpec.instanceId,
68
+ extRef: refs.toExtensionVersionRef(instanceSpec.ref),
69
+ params: instanceSpec.params,
70
+ validateOnly,
71
+ });
72
+ }
73
+ else if (instanceSpec.localPath) {
74
+ const extensionSource = await (0, extensionsHelper_1.createSourceFromLocation)(projectId, instanceSpec.localPath);
75
+ await extensionsApi.updateInstance({
76
+ projectId,
77
+ instanceId: instanceSpec.instanceId,
78
+ extensionSource,
79
+ validateOnly,
80
+ });
81
+ }
82
+ else {
83
+ throw new error_1.FirebaseError(`Tried to update extension instance ${instanceSpec.instanceId} without a ref or a local path. This should never happen.`);
84
+ }
54
85
  printSuccess(instanceSpec.instanceId, "update", validateOnly);
55
86
  return;
56
87
  };
@@ -63,12 +94,20 @@ function updateExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
63
94
  exports.updateExtensionInstanceTask = updateExtensionInstanceTask;
64
95
  function configureExtensionInstanceTask(projectId, instanceSpec, validateOnly = false) {
65
96
  const run = async () => {
66
- const res = await extensionsApi.configureInstance({
67
- projectId,
68
- instanceId: instanceSpec.instanceId,
69
- params: instanceSpec.params,
70
- validateOnly,
71
- });
97
+ if (instanceSpec.ref) {
98
+ await extensionsApi.configureInstance({
99
+ projectId,
100
+ instanceId: instanceSpec.instanceId,
101
+ params: instanceSpec.params,
102
+ validateOnly,
103
+ });
104
+ }
105
+ else if (instanceSpec.localPath) {
106
+ throw new error_1.FirebaseError(`Tried to configure extension instance ${instanceSpec.instanceId} from a local path. This should never happen.`);
107
+ }
108
+ else {
109
+ throw new error_1.FirebaseError(`Tried to configure extension instance ${instanceSpec.instanceId} without a ref or a local path. This should never happen.`);
110
+ }
72
111
  printSuccess(instanceSpec.instanceId, "configure", validateOnly);
73
112
  return;
74
113
  };
@@ -81,7 +120,7 @@ function configureExtensionInstanceTask(projectId, instanceSpec, validateOnly =
81
120
  exports.configureExtensionInstanceTask = configureExtensionInstanceTask;
82
121
  function deleteExtensionInstanceTask(projectId, instanceSpec) {
83
122
  const run = async () => {
84
- const res = await extensionsApi.deleteInstance(projectId, instanceSpec.instanceId);
123
+ await extensionsApi.deleteInstance(projectId, instanceSpec.instanceId);
85
124
  printSuccess(instanceSpec.instanceId, "delete", false);
86
125
  return;
87
126
  };