firebase-tools 10.2.1 → 10.3.1

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 (125) hide show
  1. package/lib/appdistribution/options-parser-util.js +1 -1
  2. package/lib/auth.js +3 -3
  3. package/lib/command.js +1 -1
  4. package/lib/commands/apps-android-sha-create.js +2 -2
  5. package/lib/commands/apps-sdkconfig.js +1 -1
  6. package/lib/commands/database-rules-list.js +2 -2
  7. package/lib/commands/emulators-start.js +1 -1
  8. package/lib/commands/ext-configure.js +67 -7
  9. package/lib/commands/ext-dev-init.js +49 -49
  10. package/lib/commands/ext-export.js +7 -2
  11. package/lib/commands/ext-install.js +173 -109
  12. package/lib/commands/ext-uninstall.js +17 -8
  13. package/lib/commands/ext-update.js +67 -12
  14. package/lib/commands/functions-config-export.js +1 -1
  15. package/lib/commands/hosting-clone.js +3 -3
  16. package/lib/commands/remoteconfig-get.js +1 -1
  17. package/lib/config.js +6 -3
  18. package/lib/deploy/extensions/deploymentSummary.js +3 -3
  19. package/lib/deploy/extensions/planner.js +7 -6
  20. package/lib/deploy/extensions/tasks.js +1 -1
  21. package/lib/deploy/functions/backend.js +21 -5
  22. package/lib/deploy/functions/checkIam.js +5 -5
  23. package/lib/deploy/functions/containerCleaner.js +3 -3
  24. package/lib/deploy/functions/ensure.js +3 -3
  25. package/lib/deploy/functions/functionsDeployHelper.js +2 -2
  26. package/lib/deploy/functions/prepare.js +5 -3
  27. package/lib/deploy/functions/pricing.js +1 -1
  28. package/lib/deploy/functions/prompts.js +2 -2
  29. package/lib/deploy/functions/release/fabricator.js +7 -7
  30. package/lib/deploy/functions/release/index.js +1 -1
  31. package/lib/deploy/functions/release/planner.js +43 -26
  32. package/lib/deploy/functions/release/reporter.js +3 -0
  33. package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
  34. package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
  35. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +22 -12
  36. package/lib/deploy/functions/runtimes/golang/index.js +2 -2
  37. package/lib/deploy/functions/runtimes/node/index.js +53 -0
  38. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
  39. package/lib/deploy/functions/runtimes/node/parseTriggers.js +64 -20
  40. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  41. package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
  42. package/lib/deploy/functions/services/index.js +9 -1
  43. package/lib/deploy/functions/services/storage.js +10 -4
  44. package/lib/deploy/functions/triggerRegionHelper.js +1 -1
  45. package/lib/deploy/functions/validate.js +3 -3
  46. package/lib/deploy/hosting/deploy.js +2 -2
  47. package/lib/deploy/hosting/hashcache.js +21 -19
  48. package/lib/deploy/hosting/uploader.js +5 -5
  49. package/lib/deploy/remoteconfig/functions.js +2 -2
  50. package/lib/emulator/auth/cloudFunctions.js +1 -1
  51. package/lib/emulator/auth/operations.js +1 -1
  52. package/lib/emulator/constants.js +4 -0
  53. package/lib/emulator/controller.js +54 -24
  54. package/lib/emulator/download.js +18 -1
  55. package/lib/emulator/downloadableEmulators.js +1 -1
  56. package/lib/emulator/emulatorLogger.js +12 -1
  57. package/lib/emulator/extensions/validation.js +70 -0
  58. package/lib/emulator/extensionsEmulator.js +175 -0
  59. package/lib/emulator/functionsEmulator.js +95 -43
  60. package/lib/emulator/functionsEmulatorRuntime.js +44 -36
  61. package/lib/emulator/functionsEmulatorShared.js +30 -11
  62. package/lib/emulator/functionsEmulatorShell.js +1 -1
  63. package/lib/emulator/functionsEmulatorUtils.js +4 -4
  64. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  65. package/lib/emulator/hub.js +4 -3
  66. package/lib/emulator/loggingEmulator.js +1 -1
  67. package/lib/emulator/pubsubEmulator.js +1 -1
  68. package/lib/emulator/registry.js +10 -2
  69. package/lib/emulator/storage/apis/firebase.js +314 -332
  70. package/lib/emulator/storage/apis/gcloud.js +241 -121
  71. package/lib/emulator/storage/crc.js +5 -1
  72. package/lib/emulator/storage/errors.js +9 -0
  73. package/lib/emulator/storage/files.js +159 -300
  74. package/lib/emulator/storage/index.js +27 -73
  75. package/lib/emulator/storage/metadata.js +65 -51
  76. package/lib/emulator/storage/multipart.js +62 -0
  77. package/lib/emulator/storage/persistence.js +78 -0
  78. package/lib/emulator/storage/rules/config.js +33 -0
  79. package/lib/emulator/storage/rules/manager.js +81 -0
  80. package/lib/emulator/storage/rules/runtime.js +8 -7
  81. package/lib/emulator/storage/rules/utils.js +48 -0
  82. package/lib/emulator/storage/server.js +2 -2
  83. package/lib/emulator/storage/upload.js +106 -0
  84. package/lib/emulator/types.js +3 -0
  85. package/lib/ensureApiEnabled.js +5 -1
  86. package/lib/error.js +1 -1
  87. package/lib/extensions/askUserForParam.js +31 -25
  88. package/lib/extensions/changelog.js +3 -1
  89. package/lib/extensions/checkProjectBilling.js +1 -1
  90. package/lib/extensions/displayExtensionInfo.js +1 -1
  91. package/lib/extensions/emulator/optionsHelper.js +56 -8
  92. package/lib/extensions/emulator/specHelper.js +10 -23
  93. package/lib/extensions/export.js +1 -51
  94. package/lib/extensions/extensionsApi.js +1 -1
  95. package/lib/extensions/extensionsHelper.js +32 -19
  96. package/lib/extensions/manifest.js +144 -0
  97. package/lib/extensions/metricsUtils.js +4 -4
  98. package/lib/extensions/paramHelper.js +34 -12
  99. package/lib/extensions/refs.js +1 -1
  100. package/lib/extensions/secretsUtils.js +3 -3
  101. package/lib/functional.js +1 -1
  102. package/lib/functions/env.js +6 -7
  103. package/lib/functions/events/v2.js +11 -0
  104. package/lib/gcp/cloudfunctions.js +43 -11
  105. package/lib/gcp/cloudfunctionsv2.js +48 -17
  106. package/lib/gcp/cloudtasks.js +1 -1
  107. package/lib/gcp/docker.js +2 -2
  108. package/lib/gcp/resourceManager.js +4 -4
  109. package/lib/gcp/run.js +2 -2
  110. package/lib/hosting/api.js +1 -1
  111. package/lib/hosting/proxy.js +2 -2
  112. package/lib/init/features/account.js +1 -1
  113. package/lib/management/database.js +1 -1
  114. package/lib/previews.js +1 -1
  115. package/lib/serve/functions.js +2 -1
  116. package/lib/utils.js +15 -2
  117. package/npm-shrinkwrap.json +786 -393
  118. package/package.json +1 -1
  119. package/schema/firebase-config.json +5 -0
  120. package/templates/init/functions/javascript/package.lint.json +3 -3
  121. package/templates/init/functions/javascript/package.nolint.json +2 -2
  122. package/templates/init/functions/typescript/package.lint.json +7 -7
  123. package/templates/init/functions/typescript/package.nolint.json +3 -3
  124. package/lib/deploy/extensions/params.js +0 -39
  125. package/lib/deploy/functions/eventTypes.js +0 -10
@@ -14,6 +14,7 @@ const api_1 = require("../api");
14
14
  const archiveDirectory_1 = require("../archiveDirectory");
15
15
  const utils_1 = require("./utils");
16
16
  const functionsConfig_1 = require("../functionsConfig");
17
+ const adminSdkConfig_1 = require("../emulator/adminSdkConfig");
17
18
  const resolveSource_1 = require("./resolveSource");
18
19
  const error_1 = require("../error");
19
20
  const diagnose_1 = require("./diagnose");
@@ -29,6 +30,7 @@ const logger_1 = require("../logger");
29
30
  const utils_2 = require("../utils");
30
31
  const changelog_1 = require("./changelog");
31
32
  const getProjectNumber_1 = require("../getProjectNumber");
33
+ const constants_1 = require("../emulator/constants");
32
34
  var SpecParamType;
33
35
  (function (SpecParamType) {
34
36
  SpecParamType["SELECT"] = "select";
@@ -76,21 +78,28 @@ function getDBInstanceFromURL(databaseUrl = "") {
76
78
  return "";
77
79
  }
78
80
  exports.getDBInstanceFromURL = getDBInstanceFromURL;
79
- async function getFirebaseProjectParams(projectId) {
80
- const body = await (0, functionsConfig_1.getFirebaseConfig)({ project: projectId });
81
- const projectNumber = await (0, getProjectNumber_1.getProjectNumber)({ projectId });
81
+ async function getFirebaseProjectParams(projectId, emulatorMode = false) {
82
+ var _a, _b;
83
+ const body = emulatorMode
84
+ ? await (0, adminSdkConfig_1.getProjectAdminSdkConfigOrCached)(projectId)
85
+ : await (0, functionsConfig_1.getFirebaseConfig)({ project: projectId });
86
+ const projectNumber = emulatorMode && constants_1.Constants.isDemoProject(projectId)
87
+ ? constants_1.Constants.FAKE_PROJECT_NUMBER
88
+ : await (0, getProjectNumber_1.getProjectNumber)({ projectId });
89
+ const databaseURL = (_a = body === null || body === void 0 ? void 0 : body.databaseURL) !== null && _a !== void 0 ? _a : `https://${projectId}.firebaseio.com`;
90
+ const storageBucket = (_b = body === null || body === void 0 ? void 0 : body.storageBucket) !== null && _b !== void 0 ? _b : `${projectId}.appspot.com`;
82
91
  const FIREBASE_CONFIG = JSON.stringify({
83
- projectId: body.projectId,
84
- databaseURL: body.databaseURL,
85
- storageBucket: body.storageBucket,
92
+ projectId,
93
+ databaseURL,
94
+ storageBucket,
86
95
  });
87
96
  return {
88
- PROJECT_ID: body.projectId,
97
+ PROJECT_ID: projectId,
89
98
  PROJECT_NUMBER: projectNumber,
90
- DATABASE_URL: body.databaseURL,
91
- STORAGE_BUCKET: body.storageBucket,
99
+ DATABASE_URL: databaseURL,
100
+ STORAGE_BUCKET: storageBucket,
92
101
  FIREBASE_CONFIG,
93
- DATABASE_INSTANCE: getDBInstanceFromURL(body.databaseURL),
102
+ DATABASE_INSTANCE: getDBInstanceFromURL(databaseURL),
94
103
  };
95
104
  }
96
105
  exports.getFirebaseProjectParams = getFirebaseProjectParams;
@@ -112,7 +121,7 @@ function populateDefaultParams(paramVars, paramSpecs) {
112
121
  const newParams = paramVars;
113
122
  for (const param of paramSpecs) {
114
123
  if (!paramVars[param.param]) {
115
- if (param.default != undefined && param.required) {
124
+ if (param.default !== undefined && param.required) {
116
125
  newParams[param.param] = param.default;
117
126
  }
118
127
  else if (param.required) {
@@ -197,13 +206,13 @@ function validateSpec(spec) {
197
206
  if (param.type && !_.includes(SpecParamType, param.type)) {
198
207
  errors.push(`Invalid type ${param.type} for param${param.param ? ` ${param.param}` : ""}. Valid types are ${_.values(SpecParamType).join(", ")}`);
199
208
  }
200
- if (!param.type || param.type == SpecParamType.STRING) {
209
+ if (!param.type || param.type === SpecParamType.STRING) {
201
210
  if (param.options) {
202
211
  errors.push(`Param${param.param ? ` ${param.param}` : ""} cannot have options because it is type STRING`);
203
212
  }
204
213
  }
205
214
  if (param.type &&
206
- (param.type == SpecParamType.SELECT || param.type == SpecParamType.MULTISELECT)) {
215
+ (param.type === SpecParamType.SELECT || param.type === SpecParamType.MULTISELECT)) {
207
216
  if (param.validationRegex) {
208
217
  errors.push(`Param${param.param ? ` ${param.param}` : ""} cannot have validationRegex because it is type ${param.type}`);
209
218
  }
@@ -211,12 +220,12 @@ function validateSpec(spec) {
211
220
  errors.push(`Param${param.param ? ` ${param.param}` : ""} requires options because it is type ${param.type}`);
212
221
  }
213
222
  for (const opt of param.options || []) {
214
- if (opt.value == undefined) {
223
+ if (opt.value === undefined) {
215
224
  errors.push(`Option for param${param.param ? ` ${param.param}` : ""} is missing required field: value`);
216
225
  }
217
226
  }
218
227
  }
219
- if (param.type && param.type == SpecParamType.SELECTRESOURCE) {
228
+ if (param.type && param.type === SpecParamType.SELECTRESOURCE) {
220
229
  if (!param.resourceType) {
221
230
  errors.push(`Param${param.param ? ` ${param.param}` : ""} must have resourceType because it is type ${param.type}`);
222
231
  }
@@ -268,7 +277,7 @@ async function archiveAndUploadSource(extPath, bucketName) {
268
277
  }
269
278
  async function publishExtensionVersionFromLocalSource(args) {
270
279
  const extensionSpec = await (0, localHelper_1.getLocalExtensionSpec)(args.rootDirectory);
271
- if (extensionSpec.name != args.extensionId) {
280
+ if (extensionSpec.name !== args.extensionId) {
272
281
  throw new error_1.FirebaseError(`Extension ID '${clc.bold(args.extensionId)}' does not match the name in extension.yaml '${clc.bold(extensionSpec.name)}'.`);
273
282
  }
274
283
  const subbedSpec = JSON.parse(JSON.stringify(extensionSpec));
@@ -325,7 +334,9 @@ async function publishExtensionVersionFromLocalSource(args) {
325
334
  }
326
335
  catch (err) {
327
336
  uploadSpinner.fail();
328
- throw err;
337
+ throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
338
+ original: err,
339
+ });
329
340
  }
330
341
  const publishSpinner = ora(`Publishing ${clc.bold(ref)}`);
331
342
  let res;
@@ -336,7 +347,7 @@ async function publishExtensionVersionFromLocalSource(args) {
336
347
  }
337
348
  catch (err) {
338
349
  publishSpinner.fail();
339
- if (err.status == 404) {
350
+ if (err.status === 404) {
340
351
  throw new error_1.FirebaseError(marked(`Couldn't find publisher ID '${clc.bold(args.publisherId)}'. Please ensure that you have registered this ID. To register as a publisher, you can check out the [Firebase documentation](https://firebase.google.com/docs/extensions/alpha/share#register_as_an_extensions_publisher) for step-by-step instructions.`));
341
352
  }
342
353
  throw err;
@@ -360,7 +371,9 @@ async function createSourceFromLocation(projectId, sourceUri) {
360
371
  }
361
372
  catch (err) {
362
373
  uploadSpinner.fail();
363
- throw err;
374
+ throw new error_1.FirebaseError(`Failed to archive and upload extension source, ${err}`, {
375
+ original: err,
376
+ });
364
377
  }
365
378
  }
366
379
  else {
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.showPreviewWarning = exports.showDeprecationWarning = exports.readInstanceParam = exports.getInstanceRef = exports.instanceExists = exports.loadConfig = exports.removeFromManifest = exports.writeToManifest = exports.ENV_DIRECTORY = void 0;
4
+ const clc = require("cli-color");
5
+ const path = require("path");
6
+ const refs = require("./refs");
7
+ const config_1 = require("../config");
8
+ const logger_1 = require("../logger");
9
+ const prompt_1 = require("../prompt");
10
+ const paramHelper_1 = require("./paramHelper");
11
+ const error_1 = require("../error");
12
+ const utils = require("../utils");
13
+ const extensionsHelper_1 = require("./extensionsHelper");
14
+ exports.ENV_DIRECTORY = "extensions";
15
+ async function writeToManifest(specs, config, options, allowOverwrite = false) {
16
+ if (config.has("extensions") &&
17
+ Object.keys(config.get("extensions")).length &&
18
+ !options.nonInteractive &&
19
+ !options.force) {
20
+ const currentExtensions = Object.entries(config.get("extensions"))
21
+ .map((i) => `${i[0]}: ${i[1]}`)
22
+ .join("\n\t");
23
+ if (allowOverwrite) {
24
+ const overwrite = await (0, prompt_1.promptOnce)({
25
+ type: "list",
26
+ message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite or merge?`,
27
+ choices: [
28
+ { name: "Overwrite", value: true },
29
+ { name: "Merge", value: false },
30
+ ],
31
+ });
32
+ if (overwrite) {
33
+ config.set("extensions", {});
34
+ }
35
+ }
36
+ }
37
+ writeExtensionsToFirebaseJson(specs, config);
38
+ await writeEnvFiles(specs, config, options.force);
39
+ }
40
+ exports.writeToManifest = writeToManifest;
41
+ function removeFromManifest(instanceId, config) {
42
+ if (!instanceExists(instanceId, config)) {
43
+ throw new error_1.FirebaseError(`Extension instance ${instanceId} not found in firebase.json.`);
44
+ }
45
+ const extensions = config.get("extensions", {});
46
+ extensions[instanceId] = undefined;
47
+ config.set("extensions", extensions);
48
+ config.writeProjectFile("firebase.json", config.src);
49
+ logger_1.logger.info(`Removed extension instance ${instanceId} from firebase.json`);
50
+ config.deleteProjectFile(`extensions/${instanceId}.env`);
51
+ logger_1.logger.info(`Removed extension instance environment config extensions/${instanceId}.env`);
52
+ config.deleteProjectFile(`extensions/${instanceId}.env.local`);
53
+ logger_1.logger.info(`Removed extension instance environment config extensions/${instanceId}.env.local`);
54
+ }
55
+ exports.removeFromManifest = removeFromManifest;
56
+ function loadConfig(options) {
57
+ const existingConfig = config_1.Config.load(options, true);
58
+ if (!existingConfig) {
59
+ throw new error_1.FirebaseError("Not currently in a Firebase directory. Run `firebase init` to create a Firebase directory.");
60
+ }
61
+ return existingConfig;
62
+ }
63
+ exports.loadConfig = loadConfig;
64
+ function instanceExists(instanceId, config) {
65
+ return !!config.get("extensions", {})[instanceId];
66
+ }
67
+ exports.instanceExists = instanceExists;
68
+ function getInstanceRef(instanceId, config) {
69
+ if (!instanceExists(instanceId, config)) {
70
+ throw new error_1.FirebaseError(`Could not find extension instance ${instanceId} in firebase.json`);
71
+ }
72
+ const ref = config.get("extensions", {})[instanceId];
73
+ return refs.parse(ref);
74
+ }
75
+ exports.getInstanceRef = getInstanceRef;
76
+ function writeExtensionsToFirebaseJson(specs, config) {
77
+ const extensions = config.get("extensions", {});
78
+ for (const s of specs) {
79
+ extensions[s.instanceId] = refs.toExtensionVersionRef(s.ref);
80
+ }
81
+ config.set("extensions", extensions);
82
+ config.writeProjectFile("firebase.json", config.src);
83
+ utils.logSuccess("Wrote extensions to " + clc.bold("firebase.json") + "...");
84
+ }
85
+ async function writeEnvFiles(specs, config, force) {
86
+ for (const spec of specs) {
87
+ const content = Object.entries(spec.params)
88
+ .sort((a, b) => {
89
+ return a[0].localeCompare(b[0]);
90
+ })
91
+ .map((r) => `${r[0]}=${r[1]}`)
92
+ .join("\n");
93
+ await config.askWriteProjectFile(`extensions/${spec.instanceId}.env`, content, force);
94
+ }
95
+ }
96
+ function readInstanceParam(args) {
97
+ var _a;
98
+ const aliases = (_a = args.aliases) !== null && _a !== void 0 ? _a : [];
99
+ const filesToCheck = [
100
+ `${args.instanceId}.env`,
101
+ ...aliases.map((alias) => `${args.instanceId}.env.${alias}`),
102
+ ...(args.projectNumber ? [`${args.instanceId}.env.${args.projectNumber}`] : []),
103
+ ...(args.projectId ? [`${args.instanceId}.env.${args.projectId}`] : []),
104
+ ];
105
+ if (args.checkLocal) {
106
+ filesToCheck.push(`${args.instanceId}.env.local`);
107
+ }
108
+ let noFilesFound = true;
109
+ const combinedParams = {};
110
+ for (const fileToCheck of filesToCheck) {
111
+ try {
112
+ const params = readParamsFile(args.projectDir, fileToCheck);
113
+ logger_1.logger.debug(`Successfully read params from ${fileToCheck}`);
114
+ noFilesFound = false;
115
+ Object.assign(combinedParams, params);
116
+ }
117
+ catch (err) {
118
+ logger_1.logger.debug(`${err}`);
119
+ }
120
+ }
121
+ if (noFilesFound) {
122
+ throw new error_1.FirebaseError(`No params file found for ${args.instanceId}`);
123
+ }
124
+ return combinedParams;
125
+ }
126
+ exports.readInstanceParam = readInstanceParam;
127
+ function readParamsFile(projectDir, fileName) {
128
+ const paramPath = path.join(projectDir, exports.ENV_DIRECTORY, fileName);
129
+ const params = (0, paramHelper_1.readEnvFile)(paramPath);
130
+ return params;
131
+ }
132
+ function showDeprecationWarning() {
133
+ utils.logLabeledWarning(extensionsHelper_1.logPrefix, "The behavior of ext:install, ext:update, ext:configure, and ext:uninstall will change in firebase-tools@11.0.0. " +
134
+ "Instead of deploying extensions directly, " +
135
+ "changes to extension instances will be written to firebase.json and ./extensions/*.env. " +
136
+ `Then ${clc.bold("firebase deploy (--only extensions)")} will deploy the changes to your Firebase project. ` +
137
+ `To access this behavior now, pass the ${clc.bold("--local")} flag.`);
138
+ }
139
+ exports.showDeprecationWarning = showDeprecationWarning;
140
+ function showPreviewWarning() {
141
+ utils.logLabeledWarning(extensionsHelper_1.logPrefix, "These changes will be reflected in your Firebase Emulator after restart. " +
142
+ `Run ${clc.bold("firebase deploy (--only extensions)")} to deploy the changes to your Firebase project. `);
143
+ }
144
+ exports.showPreviewWarning = showPreviewWarning;
@@ -7,19 +7,19 @@ function parseTimeseriesResponse(series) {
7
7
  const ret = [];
8
8
  for (const s of series) {
9
9
  const ref = buildRef(s);
10
- if (ref == undefined) {
10
+ if (ref === undefined) {
11
11
  continue;
12
12
  }
13
13
  let valueToday;
14
14
  let value7dAgo;
15
15
  let value28dAgo;
16
- if (s.points.length >= 28 && s.points[27].value.int64Value != undefined) {
16
+ if (s.points.length >= 28 && s.points[27].value.int64Value !== undefined) {
17
17
  value28dAgo = parseBucket(s.points[27].value.int64Value);
18
18
  }
19
- if (s.points.length >= 7 && s.points[6].value.int64Value != undefined) {
19
+ if (s.points.length >= 7 && s.points[6].value.int64Value !== undefined) {
20
20
  value7dAgo = parseBucket(s.points[6].value.int64Value);
21
21
  }
22
- if (s.points.length >= 1 && s.points[0].value.int64Value != undefined) {
22
+ if (s.points.length >= 1 && s.points[0].value.int64Value !== undefined) {
23
23
  valueToday = parseBucket(s.points[0].value.int64Value);
24
24
  }
25
25
  ret.push({
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readEnvFile = exports.getParamsFromFile = exports.promptForNewParams = exports.getParamsForUpdate = exports.getParams = exports.getParamsWithCurrentValuesAsDefaults = void 0;
3
+ exports.readEnvFile = exports.promptForNewParams = exports.getParamsForUpdate = exports.getParams = exports.getParamsWithCurrentValuesAsDefaults = exports.setNewDefaults = exports.buildBindingOptionsWithBaseValue = exports.getBaseParamBindings = void 0;
4
4
  const _ = require("lodash");
5
5
  const path = require("path");
6
6
  const clc = require("cli-color");
@@ -11,6 +11,22 @@ const extensionsHelper_1 = require("./extensionsHelper");
11
11
  const askUserForParam = require("./askUserForParam");
12
12
  const track = require("../track");
13
13
  const env = require("../functions/env");
14
+ function getBaseParamBindings(params) {
15
+ let ret = {};
16
+ for (const [k, v] of Object.entries(params)) {
17
+ ret = Object.assign(Object.assign({}, ret), { [k]: v.baseValue });
18
+ }
19
+ return ret;
20
+ }
21
+ exports.getBaseParamBindings = getBaseParamBindings;
22
+ function buildBindingOptionsWithBaseValue(baseParams) {
23
+ let paramOptions = {};
24
+ for (const [k, v] of Object.entries(baseParams)) {
25
+ paramOptions = Object.assign(Object.assign({}, paramOptions), { [k]: { baseValue: v } });
26
+ }
27
+ return paramOptions;
28
+ }
29
+ exports.buildBindingOptionsWithBaseValue = buildBindingOptionsWithBaseValue;
14
30
  function setNewDefaults(params, newDefaults) {
15
31
  params.forEach((param) => {
16
32
  if (newDefaults[param.param.toUpperCase()]) {
@@ -19,6 +35,7 @@ function setNewDefaults(params, newDefaults) {
19
35
  });
20
36
  return params;
21
37
  }
38
+ exports.setNewDefaults = setNewDefaults;
22
39
  function getParamsWithCurrentValuesAsDefaults(extensionInstance) {
23
40
  const specParams = _.cloneDeep(_.get(extensionInstance, "config.source.spec.params", []));
24
41
  const currentParams = _.cloneDeep(_.get(extensionInstance, "config.params", {}));
@@ -49,7 +66,7 @@ async function getParams(args) {
49
66
  const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
50
67
  params = await askUserForParam.ask(args.projectId, args.instanceId, args.paramSpecs, firebaseProjectParams, !!args.reconfiguring);
51
68
  }
52
- track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
69
+ void track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
53
70
  return params;
54
71
  }
55
72
  exports.getParams = getParams;
@@ -82,7 +99,7 @@ async function getParamsForUpdate(args) {
82
99
  instanceId: args.instanceId,
83
100
  });
84
101
  }
85
- track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
102
+ void track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
86
103
  return params;
87
104
  }
88
105
  exports.getParamsForUpdate = getParamsForUpdate;
@@ -91,9 +108,10 @@ async function promptForNewParams(args) {
91
108
  const comparer = (param1, param2) => {
92
109
  return param1.type === param2.type && param1.param === param2.param;
93
110
  };
94
- let paramsDiffDeletions = _.differenceWith(args.spec.params, _.get(args.newSpec, "params", []), comparer);
111
+ const oldParams = args.spec.params.filter((p) => Object.keys(args.currentParams).includes(p.param));
112
+ let paramsDiffDeletions = _.differenceWith(oldParams, args.newSpec.params, comparer);
95
113
  paramsDiffDeletions = (0, extensionsHelper_1.substituteParams)(paramsDiffDeletions, firebaseProjectParams);
96
- let paramsDiffAdditions = _.differenceWith(args.newSpec.params, _.get(args.spec, "params", []), comparer);
114
+ let paramsDiffAdditions = _.differenceWith(args.newSpec.params, oldParams, comparer);
97
115
  paramsDiffAdditions = (0, extensionsHelper_1.substituteParams)(paramsDiffAdditions, firebaseProjectParams);
98
116
  if (paramsDiffDeletions.length) {
99
117
  logger_1.logger.info("The following params will no longer be used:");
@@ -105,29 +123,33 @@ async function promptForNewParams(args) {
105
123
  if (paramsDiffAdditions.length) {
106
124
  logger_1.logger.info("To update this instance, configure the following new parameters:");
107
125
  for (const param of paramsDiffAdditions) {
108
- const chosenValue = await askUserForParam.askForParam(args.projectId, args.instanceId, param, false);
109
- args.currentParams[param.param] = chosenValue;
126
+ const chosenValue = await askUserForParam.askForParam({
127
+ projectId: args.projectId,
128
+ instanceId: args.instanceId,
129
+ paramSpec: param,
130
+ reconfiguring: false,
131
+ });
132
+ args.currentParams[param.param] = chosenValue.baseValue;
110
133
  }
111
134
  }
112
- return args.currentParams;
135
+ return buildBindingOptionsWithBaseValue(args.currentParams);
113
136
  }
114
137
  exports.promptForNewParams = promptForNewParams;
115
138
  function getParamsFromFile(args) {
116
139
  let envParams;
117
140
  try {
118
141
  envParams = readEnvFile(args.paramsEnvPath);
119
- track("Extension Env File", "Present");
142
+ void track("Extension Env File", "Present");
120
143
  }
121
144
  catch (err) {
122
- track("Extension Env File", "Invalid");
145
+ void track("Extension Env File", "Invalid");
123
146
  throw new error_1.FirebaseError(`Error reading env file: ${err.message}\n`, { original: err });
124
147
  }
125
148
  const params = (0, extensionsHelper_1.populateDefaultParams)(envParams, args.paramSpecs);
126
149
  (0, extensionsHelper_1.validateCommandLineParams)(params, args.paramSpecs);
127
150
  logger_1.logger.info(`Using param values from ${args.paramsEnvPath}`);
128
- return params;
151
+ return buildBindingOptionsWithBaseValue(params);
129
152
  }
130
- exports.getParamsFromFile = getParamsFromFile;
131
153
  function readEnvFile(envPath) {
132
154
  const buf = fs.readFileSync(path.resolve(envPath), "utf8");
133
155
  const result = env.parse(buf.toString().trim());
@@ -20,7 +20,7 @@ function parse(refOrName) {
20
20
  exports.parse = parse;
21
21
  function parseRef(ref) {
22
22
  const parts = refRegex.exec(ref);
23
- if (parts && (parts.length == 5 || parts.length == 7)) {
23
+ if (parts && (parts.length === 5 || parts.length === 7)) {
24
24
  const publisherId = parts[1];
25
25
  const extensionId = parts[2];
26
26
  const version = parts[4];
@@ -15,7 +15,7 @@ async function ensureSecretManagerApiEnabled(options) {
15
15
  }
16
16
  exports.ensureSecretManagerApiEnabled = ensureSecretManagerApiEnabled;
17
17
  function usesSecrets(spec) {
18
- return spec.params && !!spec.params.find((p) => p.type == extensionsApi.ParamType.SECRET);
18
+ return spec.params && !!spec.params.find((p) => p.type === extensionsApi.ParamType.SECRET);
19
19
  }
20
20
  exports.usesSecrets = usesSecrets;
21
21
  async function grantFirexServiceAgentSecretAdminRole(secret) {
@@ -38,7 +38,7 @@ async function getManagedSecrets(instance) {
38
38
  exports.getManagedSecrets = getManagedSecrets;
39
39
  function getActiveSecrets(spec, params) {
40
40
  return spec.params
41
- .map((p) => (p.type == extensionsApi.ParamType.SECRET ? params[p.param] : ""))
41
+ .map((p) => (p.type === extensionsApi.ParamType.SECRET ? params[p.param] : ""))
42
42
  .filter((pv) => !!pv);
43
43
  }
44
44
  exports.getActiveSecrets = getActiveSecrets;
@@ -50,7 +50,7 @@ function getSecretLabels(instanceId) {
50
50
  exports.getSecretLabels = getSecretLabels;
51
51
  function prettySecretName(secretResourceName) {
52
52
  const nameTokens = secretResourceName.split("/");
53
- if (nameTokens.length != 4 && nameTokens.length != 6) {
53
+ if (nameTokens.length !== 4 && nameTokens.length !== 6) {
54
54
  logger_1.logger.debug(`unable to parse secret secretResourceName: ${secretResourceName}`);
55
55
  return secretResourceName;
56
56
  }
package/lib/functional.js CHANGED
@@ -40,7 +40,7 @@ function reduceFlat(accum, next) {
40
40
  }
41
41
  exports.reduceFlat = reduceFlat;
42
42
  function* zip(left, right) {
43
- if (left.length != right.length) {
43
+ if (left.length !== right.length) {
44
44
  throw new Error("Cannot zip between two lists of differen lengths");
45
45
  }
46
46
  for (let i = 0; i < left.length; i++) {
@@ -12,6 +12,7 @@ const RESERVED_PREFIXES = ["X_GOOGLE_", "FIREBASE_", "EXT_"];
12
12
  const RESERVED_KEYS = [
13
13
  "FIREBASE_CONFIG",
14
14
  "CLOUD_RUNTIME_CONFIG",
15
+ "EVENTARC_CLOUD_EVENT_SOURCE",
15
16
  "ENTRY_POINT",
16
17
  "GCP_PROJECT",
17
18
  "GCLOUD_PROJECT",
@@ -120,15 +121,13 @@ function parseStrict(data) {
120
121
  exports.parseStrict = parseStrict;
121
122
  function findEnvfiles(functionsSource, projectId, projectAlias, isEmulator) {
122
123
  const files = [".env"];
124
+ files.push(`.env.${projectId}`);
125
+ if (projectAlias) {
126
+ files.push(`.env.${projectAlias}`);
127
+ }
123
128
  if (isEmulator) {
124
129
  files.push(FUNCTIONS_EMULATOR_DOTENV);
125
130
  }
126
- else {
127
- files.push(`.env.${projectId}`);
128
- if (projectAlias && projectAlias.length) {
129
- files.push(`.env.${projectAlias}`);
130
- }
131
- }
132
131
  return files
133
132
  .map((f) => path.join(functionsSource, f))
134
133
  .filter(fs.existsSync)
@@ -141,7 +140,7 @@ exports.hasUserEnvs = hasUserEnvs;
141
140
  function loadUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, }) {
142
141
  var _a;
143
142
  const envFiles = findEnvfiles(functionsSource, projectId, projectAlias, isEmulator);
144
- if (envFiles.length == 0) {
143
+ if (envFiles.length === 0) {
145
144
  return {};
146
145
  }
147
146
  if (projectAlias) {
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
4
+ exports.PUBSUB_PUBLISH_EVENT = "google.cloud.pubsub.topic.v1.messagePublished";
5
+ exports.STORAGE_EVENTS = [
6
+ "google.cloud.storage.object.v1.finalized",
7
+ "google.cloud.storage.object.v1.archived",
8
+ "google.cloud.storage.object.v1.deleted",
9
+ "google.cloud.storage.object.v1.metadataUpdated",
10
+ ];
11
+ exports.FIREBASE_ALERTS_PUBLISH_EVENT = "google.firebase.firebasealerts.alerts.v1.published";
@@ -92,7 +92,7 @@ async function getIamPolicy(fnName) {
92
92
  }
93
93
  exports.getIamPolicy = getIamPolicy;
94
94
  async function setInvokerCreate(projectId, fnName, invoker) {
95
- if (invoker.length == 0) {
95
+ if (invoker.length === 0) {
96
96
  throw new error_1.FirebaseError("Invoker cannot be an empty array");
97
97
  }
98
98
  const invokerMembers = proto.getInvokerMembers(invoker, projectId);
@@ -108,7 +108,7 @@ async function setInvokerCreate(projectId, fnName, invoker) {
108
108
  exports.setInvokerCreate = setInvokerCreate;
109
109
  async function setInvokerUpdate(projectId, fnName, invoker) {
110
110
  var _a;
111
- if (invoker.length == 0) {
111
+ if (invoker.length === 0) {
112
112
  throw new error_1.FirebaseError("Invoker cannot be an empty array");
113
113
  }
114
114
  const invokerMembers = proto.getInvokerMembers(invoker, projectId);
@@ -202,10 +202,11 @@ async function listAllFunctions(projectId) {
202
202
  }
203
203
  exports.listAllFunctions = listAllFunctions;
204
204
  function endpointFromFunction(gcfFunction) {
205
- var _a, _b, _c;
205
+ var _a, _b, _c, _d, _e;
206
206
  const [, project, , region, , id] = gcfFunction.name.split("/");
207
207
  let trigger;
208
208
  let uri;
209
+ let securityLevel;
209
210
  if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
210
211
  trigger = {
211
212
  scheduleTrigger: {},
@@ -216,18 +217,28 @@ function endpointFromFunction(gcfFunction) {
216
217
  taskQueueTrigger: {},
217
218
  };
218
219
  }
220
+ else if (((_c = gcfFunction.labels) === null || _c === void 0 ? void 0 : _c["deployment-callable"]) ||
221
+ ((_d = gcfFunction.labels) === null || _d === void 0 ? void 0 : _d["deployment-callabled"])) {
222
+ trigger = {
223
+ callableTrigger: {},
224
+ };
225
+ }
219
226
  else if (gcfFunction.httpsTrigger) {
220
227
  trigger = { httpsTrigger: {} };
221
228
  uri = gcfFunction.httpsTrigger.url;
229
+ securityLevel = gcfFunction.httpsTrigger.securityLevel;
222
230
  }
223
231
  else {
224
232
  trigger = {
225
233
  eventTrigger: {
226
234
  eventType: gcfFunction.eventTrigger.eventType,
227
- eventFilters: {
228
- resource: gcfFunction.eventTrigger.resource,
229
- },
230
- retry: !!((_c = gcfFunction.eventTrigger.failurePolicy) === null || _c === void 0 ? void 0 : _c.retry),
235
+ eventFilters: [
236
+ {
237
+ attribute: "resource",
238
+ value: gcfFunction.eventTrigger.resource,
239
+ },
240
+ ],
241
+ retry: !!((_e = gcfFunction.eventTrigger.failurePolicy) === null || _e === void 0 ? void 0 : _e.retry),
231
242
  },
232
243
  };
233
244
  }
@@ -240,12 +251,19 @@ function endpointFromFunction(gcfFunction) {
240
251
  if (uri) {
241
252
  endpoint.uri = uri;
242
253
  }
243
- proto.copyIfPresent(endpoint, gcfFunction, "serviceAccountEmail", "availableMemoryMb", "timeout", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "labels", "environmentVariables", "secretEnvironmentVariables", "sourceUploadUrl");
254
+ if (securityLevel) {
255
+ endpoint.securityLevel = securityLevel;
256
+ }
257
+ proto.copyIfPresent(endpoint, gcfFunction, "serviceAccountEmail", "availableMemoryMb", "timeout", "minInstances", "maxInstances", "ingressSettings", "labels", "environmentVariables", "secretEnvironmentVariables", "sourceUploadUrl");
258
+ if (gcfFunction.vpcConnector) {
259
+ endpoint.vpc = { connector: gcfFunction.vpcConnector };
260
+ proto.renameIfPresent(endpoint.vpc, gcfFunction, "egressSettings", "vpcConnectorEgressSettings");
261
+ }
244
262
  return endpoint;
245
263
  }
246
264
  exports.endpointFromFunction = endpointFromFunction;
247
265
  function functionFromEndpoint(endpoint, sourceUploadUrl) {
248
- if (endpoint.platform != "gcfv1") {
266
+ if (endpoint.platform !== "gcfv1") {
249
267
  throw new error_1.FirebaseError("Trying to create a v1 CloudFunction with v2 API. This should never happen");
250
268
  }
251
269
  if (!runtimes.isValidRuntime(endpoint.runtime)) {
@@ -260,9 +278,13 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
260
278
  };
261
279
  proto.copyIfPresent(gcfFunction, endpoint, "labels");
262
280
  if (backend.isEventTriggered(endpoint)) {
281
+ const resourceFilter = backend.findEventFilter(endpoint, "resource");
282
+ if (!resourceFilter) {
283
+ throw new error_1.FirebaseError("Invalid event trigger definition. Expected event filter with 'resource' attribute.");
284
+ }
263
285
  gcfFunction.eventTrigger = {
264
286
  eventType: endpoint.eventTrigger.eventType,
265
- resource: endpoint.eventTrigger.eventFilters.resource,
287
+ resource: resourceFilter.value,
266
288
  };
267
289
  gcfFunction.eventTrigger.failurePolicy = endpoint.eventTrigger.retry
268
290
  ? { retry: {} }
@@ -282,8 +304,18 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
282
304
  }
283
305
  else {
284
306
  gcfFunction.httpsTrigger = {};
307
+ if (backend.isCallableTriggered(endpoint)) {
308
+ gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callable": "true" });
309
+ }
310
+ if (endpoint.securityLevel) {
311
+ gcfFunction.httpsTrigger.securityLevel = endpoint.securityLevel;
312
+ }
313
+ }
314
+ proto.copyIfPresent(gcfFunction, endpoint, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "ingressSettings", "environmentVariables", "secretEnvironmentVariables");
315
+ if (endpoint.vpc) {
316
+ proto.renameIfPresent(gcfFunction, endpoint.vpc, "vpcConnector", "connector");
317
+ proto.renameIfPresent(gcfFunction, endpoint.vpc, "vpcConnectorEgressSettings", "egressSettings");
285
318
  }
286
- proto.copyIfPresent(gcfFunction, endpoint, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables", "secretEnvironmentVariables");
287
319
  return gcfFunction;
288
320
  }
289
321
  exports.functionFromEndpoint = functionFromEndpoint;