firebase-tools 10.2.0 → 10.3.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 (139) hide show
  1. package/lib/apiv2.js +3 -0
  2. package/lib/appdistribution/options-parser-util.js +1 -1
  3. package/lib/auth.js +3 -3
  4. package/lib/command.js +1 -1
  5. package/lib/commands/apps-android-sha-create.js +2 -2
  6. package/lib/commands/apps-sdkconfig.js +1 -1
  7. package/lib/commands/auth-import.js +1 -1
  8. package/lib/commands/database-rules-list.js +2 -2
  9. package/lib/commands/emulators-start.js +1 -1
  10. package/lib/commands/ext-configure.js +58 -4
  11. package/lib/commands/ext-dev-init.js +49 -49
  12. package/lib/commands/ext-export.js +7 -2
  13. package/lib/commands/ext-install.js +163 -104
  14. package/lib/commands/ext-uninstall.js +17 -8
  15. package/lib/commands/ext-update.js +64 -11
  16. package/lib/commands/functions-config-clone.js +1 -1
  17. package/lib/commands/functions-config-export.js +1 -1
  18. package/lib/commands/hosting-clone.js +3 -3
  19. package/lib/commands/remoteconfig-get.js +1 -1
  20. package/lib/config.js +6 -3
  21. package/lib/deploy/extensions/deploymentSummary.js +3 -3
  22. package/lib/deploy/extensions/planner.js +7 -6
  23. package/lib/deploy/extensions/tasks.js +1 -1
  24. package/lib/deploy/functions/backend.js +21 -5
  25. package/lib/deploy/functions/checkIam.js +5 -5
  26. package/lib/deploy/functions/containerCleaner.js +3 -3
  27. package/lib/deploy/functions/ensure.js +3 -3
  28. package/lib/deploy/functions/functionsDeployHelper.js +2 -2
  29. package/lib/deploy/functions/prepare.js +5 -3
  30. package/lib/deploy/functions/pricing.js +1 -1
  31. package/lib/deploy/functions/prompts.js +2 -2
  32. package/lib/deploy/functions/release/fabricator.js +7 -7
  33. package/lib/deploy/functions/release/index.js +1 -1
  34. package/lib/deploy/functions/release/planner.js +43 -26
  35. package/lib/deploy/functions/release/reporter.js +3 -0
  36. package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
  37. package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
  38. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +22 -12
  39. package/lib/deploy/functions/runtimes/golang/index.js +2 -2
  40. package/lib/deploy/functions/runtimes/node/index.js +53 -0
  41. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
  42. package/lib/deploy/functions/runtimes/node/parseTriggers.js +52 -15
  43. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  44. package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
  45. package/lib/deploy/functions/services/index.js +9 -1
  46. package/lib/deploy/functions/services/storage.js +10 -4
  47. package/lib/deploy/functions/triggerRegionHelper.js +1 -1
  48. package/lib/deploy/functions/validate.js +3 -3
  49. package/lib/deploy/hosting/client.js +9 -0
  50. package/lib/deploy/hosting/convertConfig.js +6 -0
  51. package/lib/deploy/hosting/deploy.js +2 -2
  52. package/lib/deploy/hosting/hashcache.js +21 -19
  53. package/lib/deploy/hosting/index.js +5 -5
  54. package/lib/deploy/hosting/prepare.js +25 -25
  55. package/lib/deploy/hosting/release.js +21 -24
  56. package/lib/deploy/hosting/uploader.js +5 -5
  57. package/lib/deploy/remoteconfig/functions.js +2 -2
  58. package/lib/emulator/auth/cloudFunctions.js +1 -1
  59. package/lib/emulator/auth/operations.js +1 -1
  60. package/lib/emulator/commandUtils.js +5 -1
  61. package/lib/emulator/constants.js +4 -0
  62. package/lib/emulator/controller.js +54 -24
  63. package/lib/emulator/download.js +18 -1
  64. package/lib/emulator/downloadableEmulators.js +30 -13
  65. package/lib/emulator/emulatorLogger.js +12 -1
  66. package/lib/emulator/extensions/validation.js +70 -0
  67. package/lib/emulator/extensionsEmulator.js +175 -0
  68. package/lib/emulator/functionsEmulator.js +106 -44
  69. package/lib/emulator/functionsEmulatorRuntime.js +44 -36
  70. package/lib/emulator/functionsEmulatorShared.js +17 -10
  71. package/lib/emulator/functionsEmulatorShell.js +1 -1
  72. package/lib/emulator/functionsEmulatorUtils.js +4 -4
  73. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  74. package/lib/emulator/hub.js +4 -3
  75. package/lib/emulator/loggingEmulator.js +1 -1
  76. package/lib/emulator/pubsubEmulator.js +1 -1
  77. package/lib/emulator/registry.js +10 -2
  78. package/lib/emulator/storage/apis/firebase.js +314 -332
  79. package/lib/emulator/storage/apis/gcloud.js +241 -121
  80. package/lib/emulator/storage/crc.js +5 -1
  81. package/lib/emulator/storage/errors.js +9 -0
  82. package/lib/emulator/storage/files.js +159 -300
  83. package/lib/emulator/storage/index.js +27 -73
  84. package/lib/emulator/storage/metadata.js +65 -51
  85. package/lib/emulator/storage/multipart.js +62 -0
  86. package/lib/emulator/storage/persistence.js +78 -0
  87. package/lib/emulator/storage/rules/config.js +33 -0
  88. package/lib/emulator/storage/rules/manager.js +81 -0
  89. package/lib/emulator/storage/rules/runtime.js +8 -7
  90. package/lib/emulator/storage/rules/utils.js +48 -0
  91. package/lib/emulator/storage/server.js +2 -2
  92. package/lib/emulator/storage/upload.js +106 -0
  93. package/lib/emulator/types.js +3 -0
  94. package/lib/ensureApiEnabled.js +5 -1
  95. package/lib/error.js +1 -1
  96. package/lib/extensions/askUserForParam.js +1 -1
  97. package/lib/extensions/changelog.js +3 -1
  98. package/lib/extensions/checkProjectBilling.js +1 -1
  99. package/lib/extensions/displayExtensionInfo.js +1 -1
  100. package/lib/extensions/emulator/optionsHelper.js +56 -8
  101. package/lib/extensions/emulator/specHelper.js +10 -23
  102. package/lib/extensions/export.js +1 -51
  103. package/lib/extensions/extensionsApi.js +1 -1
  104. package/lib/extensions/extensionsHelper.js +32 -19
  105. package/lib/extensions/listExtensions.js +2 -0
  106. package/lib/extensions/manifest.js +144 -0
  107. package/lib/extensions/metricsUtils.js +4 -4
  108. package/lib/extensions/paramHelper.js +9 -8
  109. package/lib/extensions/refs.js +1 -1
  110. package/lib/extensions/secretsUtils.js +3 -3
  111. package/lib/functional.js +1 -1
  112. package/lib/functions/env.js +6 -7
  113. package/lib/functions/events/v2.js +11 -0
  114. package/lib/gcp/cloudfunctions.js +42 -11
  115. package/lib/gcp/cloudfunctionsv2.js +48 -17
  116. package/lib/gcp/cloudtasks.js +1 -1
  117. package/lib/gcp/docker.js +2 -2
  118. package/lib/gcp/resourceManager.js +4 -4
  119. package/lib/gcp/run.js +2 -2
  120. package/lib/gcp/storage.js +1 -0
  121. package/lib/hosting/api.js +1 -1
  122. package/lib/hosting/functionsProxy.js +15 -5
  123. package/lib/hosting/proxy.js +2 -2
  124. package/lib/init/features/account.js +1 -1
  125. package/lib/management/database.js +1 -1
  126. package/lib/previews.js +1 -1
  127. package/lib/responseToError.js +16 -7
  128. package/lib/serve/functions.js +2 -1
  129. package/lib/serve/hosting.js +1 -1
  130. package/lib/utils.js +15 -2
  131. package/npm-shrinkwrap.json +904 -412
  132. package/package.json +3 -3
  133. package/schema/firebase-config.json +32 -0
  134. package/templates/init/functions/javascript/package.lint.json +3 -3
  135. package/templates/init/functions/javascript/package.nolint.json +2 -2
  136. package/templates/init/functions/typescript/package.lint.json +7 -7
  137. package/templates/init/functions/typescript/package.nolint.json +3 -3
  138. package/lib/deploy/extensions/params.js +0 -39
  139. package/lib/deploy/functions/eventTypes.js +0 -10
@@ -58,7 +58,7 @@ function createApp(defaultProjectId, emulator) {
58
58
  }
59
59
  const name = file.name;
60
60
  const content = file.content;
61
- const issues = await emulator.loadRuleset({ files: [{ name, content }] });
61
+ const issues = await emulator.setRules({ name, content });
62
62
  if (issues.errors.length > 0) {
63
63
  res.status(400).json({
64
64
  message: "There was an error updating rules, see logs for more details",
@@ -70,7 +70,7 @@ function createApp(defaultProjectId, emulator) {
70
70
  });
71
71
  });
72
72
  app.post("/internal/reset", (req, res) => {
73
- storageLayer.reset();
73
+ emulator.reset();
74
74
  res.sendStatus(200);
75
75
  });
76
76
  app.use("/v0", (0, firebase_1.createFirebaseEndpoints)(emulator));
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UploadService = exports.NotCancellableError = exports.UploadNotActiveError = exports.UploadStatus = exports.UploadType = void 0;
4
+ const uuid_1 = require("uuid");
5
+ const errors_1 = require("./errors");
6
+ var UploadType;
7
+ (function (UploadType) {
8
+ UploadType[UploadType["MULTIPART"] = 0] = "MULTIPART";
9
+ UploadType[UploadType["RESUMABLE"] = 1] = "RESUMABLE";
10
+ })(UploadType = exports.UploadType || (exports.UploadType = {}));
11
+ var UploadStatus;
12
+ (function (UploadStatus) {
13
+ UploadStatus[UploadStatus["ACTIVE"] = 0] = "ACTIVE";
14
+ UploadStatus[UploadStatus["CANCELLED"] = 1] = "CANCELLED";
15
+ UploadStatus[UploadStatus["FINISHED"] = 2] = "FINISHED";
16
+ })(UploadStatus = exports.UploadStatus || (exports.UploadStatus = {}));
17
+ class UploadNotActiveError extends Error {
18
+ }
19
+ exports.UploadNotActiveError = UploadNotActiveError;
20
+ class NotCancellableError extends Error {
21
+ }
22
+ exports.NotCancellableError = NotCancellableError;
23
+ class UploadService {
24
+ constructor(_persistence) {
25
+ this._persistence = _persistence;
26
+ this.reset();
27
+ }
28
+ reset() {
29
+ this._uploads = new Map();
30
+ }
31
+ multipartUpload(request) {
32
+ const upload = this.startMultipartUpload(request, request.dataRaw.byteLength);
33
+ this._persistence.deleteFile(upload.path, true);
34
+ this._persistence.appendBytes(upload.path, request.dataRaw);
35
+ return upload;
36
+ }
37
+ startMultipartUpload(request, sizeInBytes) {
38
+ const id = (0, uuid_1.v4)();
39
+ const upload = {
40
+ id: (0, uuid_1.v4)(),
41
+ bucketId: request.bucketId,
42
+ objectId: request.objectId,
43
+ type: UploadType.MULTIPART,
44
+ path: this.getStagingFileName(id, request.bucketId, request.objectId),
45
+ status: UploadStatus.FINISHED,
46
+ metadata: JSON.parse(request.metadataRaw),
47
+ size: sizeInBytes,
48
+ authorization: request.authorization,
49
+ };
50
+ this._uploads.set(upload.id, upload);
51
+ return upload;
52
+ }
53
+ startResumableUpload(request) {
54
+ const id = (0, uuid_1.v4)();
55
+ const upload = {
56
+ id: id,
57
+ bucketId: request.bucketId,
58
+ objectId: request.objectId,
59
+ type: UploadType.RESUMABLE,
60
+ path: this.getStagingFileName(id, request.bucketId, request.objectId),
61
+ status: UploadStatus.ACTIVE,
62
+ metadata: JSON.parse(request.metadataRaw),
63
+ size: 0,
64
+ authorization: request.authorization,
65
+ };
66
+ this._uploads.set(upload.id, upload);
67
+ this._persistence.deleteFile(upload.path, true);
68
+ return upload;
69
+ }
70
+ continueResumableUpload(uploadId, dataRaw) {
71
+ const upload = this.getResumableUpload(uploadId);
72
+ if (upload.status !== UploadStatus.ACTIVE) {
73
+ throw new UploadNotActiveError();
74
+ }
75
+ this._persistence.appendBytes(upload.path, dataRaw);
76
+ upload.size += dataRaw.byteLength;
77
+ return upload;
78
+ }
79
+ getResumableUpload(uploadId) {
80
+ const upload = this._uploads.get(uploadId);
81
+ if (!upload || upload.type !== UploadType.RESUMABLE) {
82
+ throw new errors_1.NotFoundError();
83
+ }
84
+ return upload;
85
+ }
86
+ cancelResumableUpload(uploadId) {
87
+ const upload = this.getResumableUpload(uploadId);
88
+ if (upload.status === UploadStatus.FINISHED) {
89
+ throw new NotCancellableError();
90
+ }
91
+ upload.status = UploadStatus.CANCELLED;
92
+ return upload;
93
+ }
94
+ finalizeResumableUpload(uploadId) {
95
+ const upload = this.getResumableUpload(uploadId);
96
+ if (upload.status === UploadStatus.CANCELLED) {
97
+ throw new UploadNotActiveError();
98
+ }
99
+ upload.status = UploadStatus.FINISHED;
100
+ return upload;
101
+ }
102
+ getStagingFileName(uploadId, bucketId, objectId) {
103
+ return encodeURIComponent(`${uploadId}_b_${bucketId}_o_${objectId}`);
104
+ }
105
+ }
106
+ exports.UploadService = UploadService;
@@ -13,6 +13,7 @@ var Emulators;
13
13
  Emulators["UI"] = "ui";
14
14
  Emulators["LOGGING"] = "logging";
15
15
  Emulators["STORAGE"] = "storage";
16
+ Emulators["EXTENSIONS"] = "extensions";
16
17
  })(Emulators = exports.Emulators || (exports.Emulators = {}));
17
18
  exports.DOWNLOADABLE_EMULATORS = [
18
19
  Emulators.FIRESTORE,
@@ -48,6 +49,7 @@ exports.EMULATORS_SUPPORTED_BY_UI = [
48
49
  Emulators.FIRESTORE,
49
50
  Emulators.FUNCTIONS,
50
51
  Emulators.STORAGE,
52
+ Emulators.EXTENSIONS,
51
53
  ];
52
54
  exports.EMULATORS_SUPPORTED_BY_USE_EMULATOR = [
53
55
  Emulators.AUTH,
@@ -59,6 +61,7 @@ exports.ALL_EMULATORS = [
59
61
  Emulators.HUB,
60
62
  Emulators.UI,
61
63
  Emulators.LOGGING,
64
+ Emulators.EXTENSIONS,
62
65
  ...exports.ALL_SERVICE_EMULATORS,
63
66
  ];
64
67
  function isDownloadableEmulator(value) {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensure = exports.check = exports.POLL_SETTINGS = void 0;
3
+ exports.enableApiURI = exports.ensure = exports.check = exports.POLL_SETTINGS = void 0;
4
4
  const cli_color_1 = require("cli-color");
5
5
  const track = require("./track");
6
6
  const api_1 = require("./api");
@@ -75,3 +75,7 @@ async function ensure(projectId, apiName, prefix, silent = false) {
75
75
  return enableApiWithRetries(projectId, apiName, prefix, silent);
76
76
  }
77
77
  exports.ensure = ensure;
78
+ function enableApiURI(projectId, apiName) {
79
+ return `https://console.cloud.google.com/apis/library/${apiName}?project=${projectId}`;
80
+ }
81
+ exports.enableApiURI = enableApiURI;
package/lib/error.js CHANGED
@@ -23,7 +23,7 @@ function isBillingError(e) {
23
23
  return !!((_d = (_c = (_b = (_a = e.context) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.find((d) => {
24
24
  var _a;
25
25
  return (((_a = d.violations) === null || _a === void 0 ? void 0 : _a.find((v) => v.type === "serviceusage/billing-enabled")) ||
26
- d.reason == "UREQ_PROJECT_BILLING_NOT_FOUND");
26
+ d.reason === "UREQ_PROJECT_BILLING_NOT_FOUND");
27
27
  }));
28
28
  }
29
29
  exports.isBillingError = isBillingError;
@@ -20,7 +20,7 @@ var SecretUpdateAction;
20
20
  function checkResponse(response, spec) {
21
21
  let valid = true;
22
22
  let responses;
23
- if (spec.required && (response == "" || response == undefined)) {
23
+ if (spec.required && (response === "" || response === undefined)) {
24
24
  utils.logWarning(`Param ${spec.param} is required, but no value was provided.`);
25
25
  return false;
26
26
  }
@@ -58,7 +58,9 @@ function breakingChangesInUpdate(versionsInUpdate) {
58
58
  const semvers = versionsInUpdate.map((v) => semver.parse(v)).sort(semver.compare);
59
59
  for (let i = 1; i < semvers.length; i++) {
60
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;
61
+ const hasMinorBumpInPreview = semvers[i - 1].major === 0 &&
62
+ semvers[i].major === 0 &&
63
+ semvers[i - 1].minor < semvers[i].minor;
62
64
  if (hasMajorBump || hasMinorBumpInPreview) {
63
65
  breakingVersions.push(semvers[i].raw);
64
66
  }
@@ -49,7 +49,7 @@ Please select the one that you would like to associate with this project:`,
49
49
  billingEnabled = await openBillingAccount(projectId, billingURL, true);
50
50
  }
51
51
  else {
52
- const billingAccount = accounts.find((a) => a.displayName == answer);
52
+ const billingAccount = accounts.find((a) => a.displayName === answer);
53
53
  billingEnabled = await cloudbilling.setBillingAccount(projectId, billingAccount.name);
54
54
  }
55
55
  return logBillingStatus(billingEnabled, projectId);
@@ -136,7 +136,7 @@ async function displayUpdateChangesRequiringConfirmation(args) {
136
136
  }
137
137
  exports.displayUpdateChangesRequiringConfirmation = displayUpdateChangesRequiringConfirmation;
138
138
  function compareResources(resource1, resource2) {
139
- return resource1.name == resource2.name && resource1.type == resource2.type;
139
+ return resource1.name === resource2.name && resource1.type === resource2.type;
140
140
  }
141
141
  function getResourceReadableName(resource) {
142
142
  return resource.type === "firebaseextensions.v1beta.function"
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getParams = exports.buildOptions = void 0;
3
+ exports.getParams = exports.getSecretEnvVars = exports.getNonSecretEnv = exports.getExtensionFunctionInfo = exports.buildOptions = void 0;
4
4
  const fs = require("fs-extra");
5
5
  const _ = require("lodash");
6
6
  const path = require("path");
@@ -8,6 +8,7 @@ const paramHelper = require("../paramHelper");
8
8
  const specHelper = require("./specHelper");
9
9
  const localHelper = require("../localHelper");
10
10
  const triggerHelper = require("./triggerHelper");
11
+ const extensionsApi_1 = require("../extensionsApi");
11
12
  const extensionsHelper = require("../extensionsHelper");
12
13
  const config_1 = require("../../config");
13
14
  const error_1 = require("../../error");
@@ -15,9 +16,9 @@ const emulatorLogger_1 = require("../../emulator/emulatorLogger");
15
16
  const projectUtils_1 = require("../../projectUtils");
16
17
  const types_1 = require("../../emulator/types");
17
18
  async function buildOptions(options) {
18
- const extensionDir = localHelper.findExtensionYaml(process.cwd());
19
- options.extensionDir = extensionDir;
20
- const spec = await specHelper.readExtensionYaml(extensionDir);
19
+ const extDevDir = localHelper.findExtensionYaml(process.cwd());
20
+ options.extDevDir = extDevDir;
21
+ const spec = await specHelper.readExtensionYaml(extDevDir);
21
22
  extensionsHelper.validateSpec(spec);
22
23
  const params = getParams(options, spec);
23
24
  extensionsHelper.validateCommandLineParams(params, spec.params);
@@ -28,13 +29,60 @@ async function buildOptions(options) {
28
29
  checkTestConfig(testConfig, functionResources);
29
30
  }
30
31
  options.config = buildConfig(functionResources, testConfig);
31
- options.extensionEnv = params;
32
+ options.extDevEnv = params;
32
33
  const functionEmuTriggerDefs = functionResources.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r));
33
- options.extensionTriggers = functionEmuTriggerDefs;
34
- options.extensionNodeVersion = specHelper.getNodeVersion(functionResources);
34
+ options.extDevTriggers = functionEmuTriggerDefs;
35
+ options.extDevNodeVersion = specHelper.getNodeVersion(functionResources);
35
36
  return options;
36
37
  }
37
38
  exports.buildOptions = buildOptions;
39
+ async function getExtensionFunctionInfo(extensionDir, instanceId, paramValues) {
40
+ const spec = await specHelper.readExtensionYaml(extensionDir);
41
+ const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, paramValues);
42
+ const extensionTriggers = functionResources
43
+ .map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r))
44
+ .map((trigger) => {
45
+ trigger.name = `ext-${instanceId}-${trigger.name}`;
46
+ return trigger;
47
+ });
48
+ const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
49
+ const nonSecretEnv = getNonSecretEnv(spec.params, paramValues);
50
+ const secretEnvVariables = getSecretEnvVars(spec.params, paramValues);
51
+ return {
52
+ extensionTriggers,
53
+ nodeMajorVersion,
54
+ nonSecretEnv,
55
+ secretEnvVariables,
56
+ };
57
+ }
58
+ exports.getExtensionFunctionInfo = getExtensionFunctionInfo;
59
+ const isSecretParam = (p) => p.type === extensionsHelper.SpecParamType.SECRET || p.type === extensionsApi_1.ParamType.SECRET;
60
+ function getNonSecretEnv(params, paramValues) {
61
+ const getNonSecretEnv = Object.assign({}, paramValues);
62
+ const secretParams = params.filter(isSecretParam);
63
+ for (const p of secretParams) {
64
+ delete getNonSecretEnv[p.param];
65
+ }
66
+ return getNonSecretEnv;
67
+ }
68
+ exports.getNonSecretEnv = getNonSecretEnv;
69
+ function getSecretEnvVars(params, paramValues) {
70
+ const secretEnvVar = [];
71
+ const secretParams = params.filter(isSecretParam);
72
+ for (const s of secretParams) {
73
+ if (paramValues[s.param]) {
74
+ const [, projectId, , secret, , version] = paramValues[s.param].split("/");
75
+ secretEnvVar.push({
76
+ key: s.param,
77
+ secret,
78
+ projectId,
79
+ version,
80
+ });
81
+ }
82
+ }
83
+ return secretEnvVar;
84
+ }
85
+ exports.getSecretEnvVars = getSecretEnvVars;
38
86
  function getParams(options, extensionSpec) {
39
87
  const projectId = (0, projectUtils_1.needProjectId)(options);
40
88
  const userParams = paramHelper.readEnvFile(options.testParams);
@@ -120,7 +168,7 @@ function getFunctionSourceDirectory(functionResources) {
120
168
  if (!sourceDirectory) {
121
169
  sourceDirectory = dir;
122
170
  }
123
- else if (sourceDirectory != dir) {
171
+ else if (sourceDirectory !== dir) {
124
172
  throw new error_1.FirebaseError(`Found function resources with different sourceDirectories: '${sourceDirectory}' and '${dir}'. The extensions emulator only supports a single sourceDirectory.`);
125
173
  }
126
174
  }
@@ -2,13 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getNodeVersion = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readExtensionYaml = void 0;
4
4
  const yaml = require("js-yaml");
5
- const _ = require("lodash");
6
5
  const path = require("path");
7
6
  const fs = require("fs-extra");
8
7
  const error_1 = require("../../error");
9
8
  const extensionsHelper_1 = require("../extensionsHelper");
10
- const emulatorLogger_1 = require("../../emulator/emulatorLogger");
11
- const types_1 = require("../../emulator/types");
9
+ const functionsEmulatorUtils_1 = require("../../emulator/functionsEmulatorUtils");
12
10
  const SPEC_FILE = "extension.yaml";
13
11
  const validFunctionTypes = [
14
12
  "firebaseextensions.v1beta.function",
@@ -62,35 +60,24 @@ function getFunctionProperties(resources) {
62
60
  }
63
61
  exports.getFunctionProperties = getFunctionProperties;
64
62
  function getNodeVersion(resources) {
65
- const functionNamesWithoutRuntime = [];
63
+ const invalidRuntimes = [];
66
64
  const versions = resources.map((r) => {
67
65
  var _a, _b;
68
- if (_.includes(r.type, "function")) {
69
- if ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.runtime) {
70
- return (_b = r.properties) === null || _b === void 0 ? void 0 : _b.runtime;
66
+ if ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.runtime) {
67
+ const runtimeName = (_b = r.properties) === null || _b === void 0 ? void 0 : _b.runtime;
68
+ const runtime = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(runtimeName);
69
+ if (!runtime) {
70
+ invalidRuntimes.push(runtimeName);
71
71
  }
72
72
  else {
73
- functionNamesWithoutRuntime.push(r.name);
73
+ return runtime;
74
74
  }
75
75
  }
76
- return "nodejs8";
77
- });
78
- if (functionNamesWithoutRuntime.length) {
79
- emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN", "extensions", `No 'runtime' property found for the following functions, defaulting to nodejs8: ${functionNamesWithoutRuntime.join(", ")}`);
80
- }
81
- const invalidRuntimes = _.filter(versions, (v) => {
82
- return !_.includes(v, "nodejs");
76
+ return 14;
83
77
  });
84
78
  if (invalidRuntimes.length) {
85
79
  throw new error_1.FirebaseError(`The following runtimes are not supported by the Emulator Suite: ${invalidRuntimes.join(", ")}. \n Only Node runtimes are supported.`);
86
80
  }
87
- if (_.includes(versions, "nodejs10")) {
88
- return "10";
89
- }
90
- if (_.includes(versions, "nodejs6")) {
91
- emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN", "extensions", "Node 6 is deprecated. We recommend upgrading to a newer version.");
92
- return "6";
93
- }
94
- return "8";
81
+ return Math.max(...versions);
95
82
  }
96
83
  exports.getNodeVersion = getNodeVersion;
@@ -1,14 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.writeFiles = exports.displayExportInfo = exports.setSecretParamsToLatest = exports.parameterizeProject = void 0;
4
- const clc = require("cli-color");
5
- const refs = require("./refs");
6
- const config_1 = require("../config");
3
+ exports.displayExportInfo = exports.setSecretParamsToLatest = exports.parameterizeProject = void 0;
7
4
  const planner_1 = require("../deploy/extensions/planner");
8
5
  const deploymentSummary_1 = require("../deploy/extensions/deploymentSummary");
9
6
  const logger_1 = require("../logger");
10
- const error_1 = require("../error");
11
- const prompt_1 = require("../prompt");
12
7
  const secretManager_1 = require("../gcp/secretManager");
13
8
  const secretsUtils_1 = require("./secretsUtils");
14
9
  function parameterizeProject(projectId, projectNumber, spec) {
@@ -60,48 +55,3 @@ function displaySpecs(specs) {
60
55
  logger_1.logger.info("");
61
56
  }
62
57
  }
63
- function writeExtensionsToFirebaseJson(have, existingConfig) {
64
- const extensions = existingConfig.get("extensions", {});
65
- for (const s of have) {
66
- extensions[s.instanceId] = refs.toExtensionVersionRef(s.ref);
67
- }
68
- existingConfig.set("extensions", extensions);
69
- logger_1.logger.info("Adding Extensions to " + clc.bold("firebase.json") + "...");
70
- existingConfig.writeProjectFile("firebase.json", existingConfig.src);
71
- }
72
- async function writeEnvFile(spec, existingConfig, force) {
73
- const content = Object.entries(spec.params)
74
- .map((r) => `${r[0]}=${r[1]}`)
75
- .join("\n");
76
- await existingConfig.askWriteProjectFile(`extensions/${spec.instanceId}.env`, content, force);
77
- }
78
- async function writeFiles(have, options) {
79
- const existingConfig = config_1.Config.load(options, true);
80
- if (!existingConfig) {
81
- throw new error_1.FirebaseError("Not currently in a Firebase directory. Please run `firebase init` to create a Firebase directory.");
82
- }
83
- if (existingConfig.has("extensions") &&
84
- Object.keys(existingConfig.get("extensions")).length &&
85
- !options.nonInteractive &&
86
- !options.force) {
87
- const currentExtensions = Object.entries(existingConfig.get("extensions"))
88
- .map((i) => `${i[0]}: ${i[1]}`)
89
- .join("\n\t");
90
- const overwrite = await (0, prompt_1.promptOnce)({
91
- type: "list",
92
- message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite or merge?`,
93
- choices: [
94
- { name: "Overwrite", value: true },
95
- { name: "Merge", value: false },
96
- ],
97
- });
98
- if (overwrite) {
99
- existingConfig.set("extensions", {});
100
- }
101
- }
102
- writeExtensionsToFirebaseJson(have, existingConfig);
103
- for (const spec of have) {
104
- await writeEnvFile(spec, existingConfig, options.force);
105
- }
106
- }
107
- exports.writeFiles = writeFiles;
@@ -295,7 +295,7 @@ async function listExtensionVersions(ref, filter = "") {
295
295
  exports.listExtensionVersions = listExtensionVersions;
296
296
  async function getPublisherProfile(projectId, publisherId) {
297
297
  const res = await apiClient.get(`/projects/${projectId}/publisherProfile`, {
298
- queryParams: publisherId == undefined
298
+ queryParams: publisherId === undefined
299
299
  ? undefined
300
300
  : {
301
301
  publisherId,
@@ -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 {
@@ -8,6 +8,7 @@ const extensionsApi_1 = require("./extensionsApi");
8
8
  const extensionsHelper_1 = require("./extensionsHelper");
9
9
  const utils = require("../utils");
10
10
  const extensionsUtils = require("./utils");
11
+ const logger_1 = require("../logger");
11
12
  async function listExtensions(projectId) {
12
13
  const instances = await (0, extensionsApi_1.listInstances)(projectId);
13
14
  if (instances.length < 1) {
@@ -47,6 +48,7 @@ async function listExtensions(projectId) {
47
48
  });
48
49
  });
49
50
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, `list of extensions installed in ${clc.bold(projectId)}:`);
51
+ logger_1.logger.info(table.toString());
50
52
  return formatted;
51
53
  }
52
54
  exports.listExtensions = listExtensions;