firebase-tools 10.4.2 → 10.7.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 (108) hide show
  1. package/lib/bin/firebase.js +1 -1
  2. package/lib/command.js +4 -4
  3. package/lib/commands/deploy.js +1 -1
  4. package/lib/commands/emulators-start.js +13 -3
  5. package/lib/commands/ext-configure.js +15 -5
  6. package/lib/commands/ext-dev-emulators-start.js +5 -1
  7. package/lib/commands/ext-export.js +6 -5
  8. package/lib/commands/ext-install.js +28 -44
  9. package/lib/commands/ext-update.js +9 -1
  10. package/lib/commands/functions-delete.js +2 -5
  11. package/lib/commands/functions-secrets-destroy.js +23 -3
  12. package/lib/commands/functions-secrets-prune.js +15 -12
  13. package/lib/commands/functions-secrets-set.js +51 -4
  14. package/lib/commands/hosting-channel-deploy.js +2 -2
  15. package/lib/deploy/database/deploy.js +4 -0
  16. package/lib/deploy/database/index.js +1 -0
  17. package/lib/deploy/extensions/deploy.js +4 -4
  18. package/lib/deploy/extensions/deploymentSummary.js +8 -5
  19. package/lib/deploy/extensions/planner.js +36 -9
  20. package/lib/deploy/extensions/prepare.js +1 -1
  21. package/lib/deploy/extensions/secrets.js +2 -2
  22. package/lib/deploy/extensions/tasks.js +60 -21
  23. package/lib/deploy/functions/backend.js +17 -6
  24. package/lib/deploy/functions/build.js +162 -0
  25. package/lib/deploy/functions/checkIam.js +6 -5
  26. package/lib/deploy/functions/deploy.js +14 -15
  27. package/lib/deploy/functions/ensure.js +4 -4
  28. package/lib/deploy/functions/functionsDeployHelper.js +54 -23
  29. package/lib/deploy/functions/prepare.js +92 -39
  30. package/lib/deploy/functions/prepareFunctionsUpload.js +16 -21
  31. package/lib/deploy/functions/pricing.js +6 -3
  32. package/lib/deploy/functions/prompts.js +1 -7
  33. package/lib/deploy/functions/release/fabricator.js +44 -5
  34. package/lib/deploy/functions/release/index.js +31 -6
  35. package/lib/deploy/functions/release/planner.js +10 -8
  36. package/lib/deploy/functions/release/reporter.js +14 -11
  37. package/lib/deploy/functions/runtimes/discovery/parsing.js +12 -6
  38. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +61 -13
  39. package/lib/deploy/functions/runtimes/node/index.js +1 -1
  40. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
  41. package/lib/deploy/functions/runtimes/node/parseTriggers.js +29 -24
  42. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  43. package/lib/deploy/functions/services/auth.js +95 -0
  44. package/lib/deploy/functions/services/index.js +41 -21
  45. package/lib/deploy/functions/services/storage.js +1 -6
  46. package/lib/deploy/functions/validate.js +8 -5
  47. package/lib/deploy/hosting/args.js +2 -0
  48. package/lib/deploy/hosting/convertConfig.js +37 -8
  49. package/lib/deploy/hosting/deploy.js +3 -3
  50. package/lib/deploy/hosting/prepare.js +2 -2
  51. package/lib/deploy/hosting/release.js +6 -2
  52. package/lib/deploy/index.js +82 -93
  53. package/lib/deploy/remoteconfig/deploy.js +4 -0
  54. package/lib/deploy/remoteconfig/index.js +3 -1
  55. package/lib/emulator/auth/operations.js +26 -20
  56. package/lib/emulator/auth/state.js +79 -43
  57. package/lib/emulator/auth/utils.js +3 -25
  58. package/lib/emulator/commandUtils.js +72 -2
  59. package/lib/emulator/controller.js +14 -5
  60. package/lib/emulator/downloadableEmulators.js +47 -24
  61. package/lib/emulator/extensions/postinstall.js +41 -0
  62. package/lib/emulator/extensions/validation.js +2 -2
  63. package/lib/emulator/extensionsEmulator.js +85 -21
  64. package/lib/emulator/functionsEmulator.js +79 -7
  65. package/lib/emulator/functionsEmulatorShared.js +36 -21
  66. package/lib/emulator/registry.js +34 -12
  67. package/lib/emulator/shared/request.js +19 -0
  68. package/lib/emulator/storage/apis/firebase.js +32 -35
  69. package/lib/emulator/storage/apis/gcloud.js +84 -66
  70. package/lib/emulator/storage/files.js +56 -52
  71. package/lib/emulator/storage/index.js +23 -3
  72. package/lib/emulator/storage/metadata.js +18 -8
  73. package/lib/emulator/storage/rules/manager.js +7 -17
  74. package/lib/emulator/storage/rules/utils.js +11 -3
  75. package/lib/emulator/storage/server.js +38 -12
  76. package/lib/ensureApiEnabled.js +8 -4
  77. package/lib/extensions/askUserForParam.js +14 -11
  78. package/lib/extensions/changelog.js +1 -1
  79. package/lib/extensions/emulator/optionsHelper.js +9 -10
  80. package/lib/extensions/emulator/specHelper.js +7 -1
  81. package/lib/extensions/emulator/triggerHelper.js +11 -14
  82. package/lib/extensions/extensionsApi.js +2 -1
  83. package/lib/extensions/extensionsHelper.js +30 -24
  84. package/lib/extensions/manifest.js +28 -8
  85. package/lib/extensions/paramHelper.js +19 -13
  86. package/lib/extensions/provisioningHelper.js +2 -2
  87. package/lib/extensions/warnings.js +3 -3
  88. package/lib/functions/env.js +10 -2
  89. package/lib/functions/events/index.js +7 -0
  90. package/lib/functions/events/v1.js +6 -0
  91. package/lib/functions/projectConfig.js +24 -3
  92. package/lib/functions/runtimeConfigExport.js +10 -6
  93. package/lib/functions/secrets.js +99 -6
  94. package/lib/gcp/cloudfunctions.js +37 -18
  95. package/lib/gcp/cloudfunctionsv2.js +41 -25
  96. package/lib/gcp/cloudtasks.js +5 -3
  97. package/lib/gcp/identityPlatform.js +44 -0
  98. package/lib/gcp/secretManager.js +2 -2
  99. package/lib/metaprogramming.js +2 -0
  100. package/lib/previews.js +1 -1
  101. package/lib/serve/hosting.js +25 -12
  102. package/lib/serve/index.js +6 -0
  103. package/lib/track.js +15 -21
  104. package/lib/utils.js +30 -1
  105. package/npm-shrinkwrap.json +44 -2
  106. package/package.json +4 -1
  107. package/schema/firebase-config.json +6 -0
  108. package/lib/emulator/storage/list.js +0 -18
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.megabytes = exports.API_VERSION = void 0;
3
+ exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.megabytes = exports.BLOCKING_LABEL = exports.CODEBASE_LABEL = exports.API_VERSION = void 0;
4
4
  const clc = require("cli-color");
5
5
  const apiv2_1 = require("../apiv2");
6
6
  const error_1 = require("../error");
@@ -11,12 +11,23 @@ const backend = require("../deploy/functions/backend");
11
11
  const runtimes = require("../deploy/functions/runtimes");
12
12
  const proto = require("./proto");
13
13
  const utils = require("../utils");
14
+ const projectConfig = require("../functions/projectConfig");
14
15
  exports.API_VERSION = "v2alpha";
16
+ exports.CODEBASE_LABEL = "firebase-functions-codebase";
15
17
  const client = new apiv2_1.Client({
16
18
  urlPrefix: api_1.functionsV2Origin,
17
19
  auth: true,
18
20
  apiVersion: exports.API_VERSION,
19
21
  });
22
+ exports.BLOCKING_LABEL = "deployment-blocking";
23
+ const BLOCKING_LABEL_KEY_TO_EVENT = {
24
+ "before-create": "providers/cloud.auth/eventTypes/user.beforeCreate",
25
+ "before-sign-in": "providers/cloud.auth/eventTypes/user.beforeSignIn",
26
+ };
27
+ const BLOCKING_EVENT_TO_LABEL_KEY = {
28
+ "providers/cloud.auth/eventTypes/user.beforeCreate": "before-create",
29
+ "providers/cloud.auth/eventTypes/user.beforeSignIn": "before-sign-in",
30
+ };
20
31
  const BYTES_PER_UNIT = {
21
32
  "": 1,
22
33
  k: 1e3,
@@ -166,9 +177,8 @@ function functionFromEndpoint(endpoint, source) {
166
177
  serviceConfig: {},
167
178
  };
168
179
  proto.copyIfPresent(gcfFunction, endpoint, "labels");
169
- proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "environmentVariables", "serviceAccountEmail", "ingressSettings");
180
+ proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "environmentVariables", "serviceAccountEmail", "ingressSettings", "timeoutSeconds");
170
181
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "availableMemory", "availableMemoryMb", (mb) => `${mb}M`);
171
- proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "timeoutSeconds", "timeout", proto.secondsFromDuration);
172
182
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "minInstanceCount", "minInstances");
173
183
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "maxInstanceCount", "maxInstances");
174
184
  if (endpoint.vpc) {
@@ -180,25 +190,22 @@ function functionFromEndpoint(endpoint, source) {
180
190
  eventType: endpoint.eventTrigger.eventType,
181
191
  };
182
192
  if (gcfFunction.eventTrigger.eventType === v2_1.PUBSUB_PUBLISH_EVENT) {
183
- const pubsubFilter = backend.findEventFilter(endpoint, "topic");
184
- if (!pubsubFilter) {
185
- throw new error_1.FirebaseError("Invalid pubsub endpoint. Expected eventFilter with 'topic' attribute but found none.");
186
- }
187
- gcfFunction.eventTrigger.pubsubTopic = pubsubFilter.value;
188
- for (const filter of endpoint.eventTrigger.eventFilters) {
189
- if (filter.attribute === "topic") {
193
+ gcfFunction.eventTrigger.pubsubTopic = endpoint.eventTrigger.eventFilters.topic;
194
+ gcfFunction.eventTrigger.eventFilters = [];
195
+ for (const [attribute, value] of Object.entries(endpoint.eventTrigger.eventFilters)) {
196
+ if (attribute === "topic")
190
197
  continue;
191
- }
192
- if (!gcfFunction.eventTrigger.eventFilters) {
193
- gcfFunction.eventTrigger.eventFilters = [];
194
- }
195
- gcfFunction.eventTrigger.eventFilters.push(filter);
198
+ gcfFunction.eventTrigger.eventFilters.push({ attribute, value });
196
199
  }
197
200
  }
198
201
  else {
199
- gcfFunction.eventTrigger.eventFilters = endpoint.eventTrigger.eventFilters;
202
+ gcfFunction.eventTrigger.eventFilters = [];
203
+ for (const [attribute, value] of Object.entries(endpoint.eventTrigger.eventFilters)) {
204
+ gcfFunction.eventTrigger.eventFilters.push({ attribute, value });
205
+ }
200
206
  }
201
207
  proto.renameIfPresent(gcfFunction.eventTrigger, endpoint.eventTrigger, "triggerRegion", "region");
208
+ proto.copyIfPresent(gcfFunction.eventTrigger, endpoint.eventTrigger, "channel");
202
209
  if (endpoint.eventTrigger.retry) {
203
210
  logger_1.logger.warn("Cannot set a retry policy on Cloud Function", endpoint.id);
204
211
  }
@@ -213,11 +220,15 @@ function functionFromEndpoint(endpoint, source) {
213
220
  else if (backend.isCallableTriggered(endpoint)) {
214
221
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callable": "true" });
215
222
  }
223
+ else if (backend.isBlockingTriggered(endpoint)) {
224
+ gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [exports.BLOCKING_LABEL]: BLOCKING_EVENT_TO_LABEL_KEY[endpoint.blockingTrigger.eventType] });
225
+ }
226
+ gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [exports.CODEBASE_LABEL]: endpoint.codebase || projectConfig.DEFAULT_CODEBASE });
216
227
  return gcfFunction;
217
228
  }
218
229
  exports.functionFromEndpoint = functionFromEndpoint;
219
230
  function endpointFromFunction(gcfFunction) {
220
- var _a, _b, _c;
231
+ var _a, _b, _c, _d, _e;
221
232
  const [, project, , region, , id] = gcfFunction.name.split("/");
222
233
  let trigger;
223
234
  if (((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) === "true") {
@@ -235,25 +246,30 @@ function endpointFromFunction(gcfFunction) {
235
246
  callableTrigger: {},
236
247
  };
237
248
  }
249
+ else if ((_d = gcfFunction.labels) === null || _d === void 0 ? void 0 : _d[exports.BLOCKING_LABEL]) {
250
+ trigger = {
251
+ blockingTrigger: {
252
+ eventType: BLOCKING_LABEL_KEY_TO_EVENT[gcfFunction.labels[exports.BLOCKING_LABEL]],
253
+ },
254
+ };
255
+ }
238
256
  else if (gcfFunction.eventTrigger) {
239
257
  trigger = {
240
258
  eventTrigger: {
241
259
  eventType: gcfFunction.eventTrigger.eventType,
242
- eventFilters: [],
260
+ eventFilters: {},
243
261
  retry: false,
244
262
  },
245
263
  };
246
264
  if (gcfFunction.eventTrigger.pubsubTopic) {
247
- trigger.eventTrigger.eventFilters.push({
248
- attribute: "topic",
249
- value: gcfFunction.eventTrigger.pubsubTopic,
250
- });
265
+ trigger.eventTrigger.eventFilters.topic = gcfFunction.eventTrigger.pubsubTopic;
251
266
  }
252
267
  else {
253
268
  for (const { attribute, value } of gcfFunction.eventTrigger.eventFilters || []) {
254
- trigger.eventTrigger.eventFilters.push({ attribute, value });
269
+ trigger.eventTrigger.eventFilters[attribute] = value;
255
270
  }
256
271
  }
272
+ proto.copyIfPresent(trigger.eventTrigger, gcfFunction.eventTrigger, "channel");
257
273
  proto.renameIfPresent(trigger.eventTrigger, gcfFunction.eventTrigger, "region", "triggerRegion");
258
274
  }
259
275
  else {
@@ -265,9 +281,8 @@ function endpointFromFunction(gcfFunction) {
265
281
  const endpoint = Object.assign(Object.assign({ platform: "gcfv2", id,
266
282
  project,
267
283
  region }, trigger), { entryPoint: gcfFunction.buildConfig.entryPoint, runtime: gcfFunction.buildConfig.runtime, uri: gcfFunction.serviceConfig.uri });
268
- proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "ingressSettings", "environmentVariables");
284
+ proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "ingressSettings", "environmentVariables", "timeoutSeconds");
269
285
  proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "availableMemoryMb", "availableMemory", megabytes);
270
- proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "timeout", "timeoutSeconds", proto.durationFromSeconds);
271
286
  proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "minInstances", "minInstanceCount");
272
287
  proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "maxInstances", "maxInstanceCount");
273
288
  proto.copyIfPresent(endpoint, gcfFunction, "labels");
@@ -275,6 +290,7 @@ function endpointFromFunction(gcfFunction) {
275
290
  endpoint.vpc = { connector: gcfFunction.serviceConfig.vpcConnector };
276
291
  proto.renameIfPresent(endpoint.vpc, gcfFunction.serviceConfig, "egressSettings", "vpcConnectorEgressSettings");
277
292
  }
293
+ endpoint.codebase = ((_e = gcfFunction.labels) === null || _e === void 0 ? void 0 : _e[exports.CODEBASE_LABEL]) || projectConfig.DEFAULT_CODEBASE;
278
294
  return endpoint;
279
295
  }
280
296
  exports.endpointFromFunction = endpointFromFunction;
@@ -13,7 +13,6 @@ const client = new apiv2_1.Client({
13
13
  exports.DEFAULT_SETTINGS = {
14
14
  rateLimits: {
15
15
  maxConcurrentDispatches: 1000,
16
- maxBurstSize: 100,
17
16
  maxDispatchesPerSecond: 500,
18
17
  },
19
18
  state: "RUNNING",
@@ -133,10 +132,13 @@ exports.queueNameForEndpoint = queueNameForEndpoint;
133
132
  function queueFromEndpoint(endpoint) {
134
133
  const queue = Object.assign(Object.assign({}, JSON.parse(JSON.stringify(exports.DEFAULT_SETTINGS))), { name: queueNameForEndpoint(endpoint) });
135
134
  if (endpoint.taskQueueTrigger.rateLimits) {
136
- proto.copyIfPresent(queue.rateLimits, endpoint.taskQueueTrigger.rateLimits, "maxBurstSize", "maxConcurrentDispatches", "maxDispatchesPerSecond");
135
+ proto.copyIfPresent(queue.rateLimits, endpoint.taskQueueTrigger.rateLimits, "maxConcurrentDispatches", "maxDispatchesPerSecond");
137
136
  }
138
137
  if (endpoint.taskQueueTrigger.retryConfig) {
139
- proto.copyIfPresent(queue.retryConfig, endpoint.taskQueueTrigger.retryConfig, "maxAttempts", "maxBackoff", "maxDoublings", "maxRetryDuration", "minBackoff");
138
+ proto.copyIfPresent(queue.retryConfig, endpoint.taskQueueTrigger.retryConfig, "maxAttempts", "maxDoublings");
139
+ proto.renameIfPresent(queue.retryConfig, endpoint.taskQueueTrigger.retryConfig, "maxRetryDuration", "maxRetrySeconds", proto.durationFromSeconds);
140
+ proto.renameIfPresent(queue.retryConfig, endpoint.taskQueueTrigger.retryConfig, "maxBackoff", "maxBackoffSeconds", proto.durationFromSeconds);
141
+ proto.renameIfPresent(queue.retryConfig, endpoint.taskQueueTrigger.retryConfig, "minBackoff", "minBackoffSeconds", proto.durationFromSeconds);
140
142
  }
141
143
  return queue;
142
144
  }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateConfig = exports.setBlockingFunctionsConfig = exports.getConfig = exports.getBlockingFunctionsConfig = void 0;
4
+ const proto = require("./proto");
5
+ const api_1 = require("../api");
6
+ const apiv2_1 = require("../apiv2");
7
+ const API_VERSION = "v2";
8
+ const adminApiClient = new apiv2_1.Client({
9
+ urlPrefix: api_1.identityOrigin + "/admin",
10
+ apiVersion: API_VERSION,
11
+ });
12
+ async function getBlockingFunctionsConfig(project) {
13
+ const config = (await getConfig(project)) || {};
14
+ if (!config.blockingFunctions) {
15
+ config.blockingFunctions = {};
16
+ }
17
+ return config.blockingFunctions;
18
+ }
19
+ exports.getBlockingFunctionsConfig = getBlockingFunctionsConfig;
20
+ async function getConfig(project) {
21
+ const response = await adminApiClient.get(`projects/${project}/config`);
22
+ return response.body;
23
+ }
24
+ exports.getConfig = getConfig;
25
+ async function setBlockingFunctionsConfig(project, blockingConfig) {
26
+ const config = (await updateConfig(project, { blockingFunctions: blockingConfig }, "blockingFunctions")) || {};
27
+ if (!config.blockingFunctions) {
28
+ config.blockingFunctions = {};
29
+ }
30
+ return config.blockingFunctions;
31
+ }
32
+ exports.setBlockingFunctionsConfig = setBlockingFunctionsConfig;
33
+ async function updateConfig(project, config, updateMask) {
34
+ if (!updateMask) {
35
+ updateMask = proto.fieldMasks(config).join(",");
36
+ }
37
+ const response = await adminApiClient.patch(`projects/${project}/config`, config, {
38
+ queryParams: {
39
+ updateMask,
40
+ },
41
+ });
42
+ return response.body;
43
+ }
44
+ exports.updateConfig = updateConfig;
@@ -33,7 +33,7 @@ async function listSecrets(projectId, filter) {
33
33
  ? baseOpts
34
34
  : Object.assign(Object.assign({}, baseOpts), { queryParams: Object.assign(Object.assign({}, baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.queryParams), { pageToken }) });
35
35
  const res = await client.get(path, opts);
36
- for (const s of res.body.secrets) {
36
+ for (const s of res.body.secrets || []) {
37
37
  secrets.push(Object.assign(Object.assign({}, parseSecretResourceName(s.name)), { labels: (_a = s.labels) !== null && _a !== void 0 ? _a : {} }));
38
38
  }
39
39
  if (!res.body.nextPageToken) {
@@ -133,7 +133,7 @@ async function createSecret(projectId, name, labels) {
133
133
  },
134
134
  labels,
135
135
  }, { queryParams: { secretId: name } });
136
- return parseSecretResourceName(createRes.body.name);
136
+ return Object.assign(Object.assign({}, parseSecretResourceName(createRes.body.name)), { labels });
137
137
  }
138
138
  exports.createSecret = createSecret;
139
139
  async function patchSecret(projectId, name, labels) {
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/lib/previews.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.previews = void 0;
4
4
  const lodash_1 = require("lodash");
5
5
  const configstore_1 = require("./configstore");
6
- exports.previews = Object.assign({ rtdbrules: false, ext: false, extdev: false, extensionsemulator: false, rtdbmanagement: false, functionsv2: false, golang: false, deletegcfartifacts: false, artifactregistry: false, emulatoruisnapshot: false }, configstore_1.configstore.get("previews"));
6
+ exports.previews = Object.assign({ rtdbrules: false, ext: false, extdev: false, extensionsemulator: false, rtdbmanagement: false, functionsv2: false, golang: false, deletegcfartifacts: false, artifactregistry: false, emulatoruisnapshot: false, frameworkawareness: false }, configstore_1.configstore.get("previews"));
7
7
  if (process.env.FIREBASE_CLI_PREVIEWS) {
8
8
  process.env.FIREBASE_CLI_PREVIEWS.split(",").forEach((feature) => {
9
9
  if ((0, lodash_1.has)(exports.previews, feature)) {
@@ -15,6 +15,7 @@ const stream_1 = require("stream");
15
15
  const emulatorLogger_1 = require("../emulator/emulatorLogger");
16
16
  const types_1 = require("../emulator/types");
17
17
  const utils_1 = require("../utils");
18
+ const child_process_1 = require("child_process");
18
19
  const MAX_PORT_ATTEMPTS = 10;
19
20
  let attempts = 0;
20
21
  let destroyServer = undefined;
@@ -31,6 +32,29 @@ function startServer(options, config, port, init) {
31
32
  const morganMiddleware = morgan("combined", {
32
33
  stream: morganStream,
33
34
  });
35
+ const portInUse = () => {
36
+ const message = "Port " + options.port + " is not available.";
37
+ logger.log("WARN", clc.yellow("hosting: ") + message + " Trying another port...");
38
+ if (attempts < MAX_PORT_ATTEMPTS) {
39
+ attempts++;
40
+ startServer(options, config, port + 5, init);
41
+ }
42
+ else {
43
+ logger.log("WARN", message);
44
+ throw new error_1.FirebaseError("Could not find an open port for hosting development server.", {
45
+ exit: 1,
46
+ });
47
+ }
48
+ };
49
+ if (process.platform === "darwin") {
50
+ try {
51
+ (0, child_process_1.execSync)(`lsof -i :${port}`);
52
+ portInUse();
53
+ return;
54
+ }
55
+ catch (e) {
56
+ }
57
+ }
34
58
  const server = superstatic({
35
59
  debug: false,
36
60
  port: port,
@@ -60,18 +84,7 @@ function startServer(options, config, port, init) {
60
84
  destroyServer = (0, utils_1.createDestroyer)(server);
61
85
  server.on("error", (err) => {
62
86
  if (err.code === "EADDRINUSE") {
63
- const message = "Port " + options.port + " is not available.";
64
- logger.log("WARN", clc.yellow("hosting: ") + message + " Trying another port...");
65
- if (attempts < MAX_PORT_ATTEMPTS) {
66
- attempts++;
67
- startServer(options, config, port + 5, init);
68
- }
69
- else {
70
- logger.log("WARN", message);
71
- throw new error_1.FirebaseError("Could not find an open port for hosting development server.", {
72
- exit: 1,
73
- });
74
- }
87
+ portInUse();
75
88
  }
76
89
  else {
77
90
  throw new error_1.FirebaseError("An error occurred while starting the hosting development server:\n\n" + err.toString(), { exit: 1 });
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.serve = void 0;
4
4
  const _ = require("lodash");
5
5
  const logger_1 = require("../logger");
6
+ const previews_1 = require("../previews");
6
7
  const { FunctionsServer } = require("./functions");
7
8
  const TARGETS = {
8
9
  hosting: require("./hosting"),
@@ -11,6 +12,11 @@ const TARGETS = {
11
12
  async function serve(options) {
12
13
  const targetNames = options.targets;
13
14
  options.port = parseInt(options.port, 10);
15
+ if (previews_1.previews.frameworkawareness &&
16
+ targetNames.includes("hosting") &&
17
+ [].concat(options.config.get("hosting")).some((it) => it.source)) {
18
+ await require("firebase-frameworks").prepare(targetNames, { project: options.projectId }, options);
19
+ }
14
20
  await Promise.all(_.map(targetNames, (targetName) => {
15
21
  return TARGETS[targetName].start(options);
16
22
  }));
package/lib/track.js CHANGED
@@ -1,31 +1,26 @@
1
1
  "use strict";
2
- var ua = require("universal-analytics");
3
- var _ = require("lodash");
4
- var { configstore } = require("./configstore");
5
- var pkg = require("../package.json");
6
- var uuid = require("uuid");
7
- const { logger } = require("./logger");
8
- var anonId = configstore.get("analytics-uuid");
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.track = void 0;
4
+ const ua = require("universal-analytics");
5
+ const uuid_1 = require("uuid");
6
+ const configstore_1 = require("./configstore");
7
+ const pkg = require("../package.json");
8
+ let anonId = configstore_1.configstore.get("analytics-uuid");
9
9
  if (!anonId) {
10
- anonId = uuid.v4();
11
- configstore.set("analytics-uuid", anonId);
10
+ anonId = (0, uuid_1.v4)();
11
+ configstore_1.configstore.set("analytics-uuid", anonId);
12
12
  }
13
- var visitor = ua(process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3", anonId, {
13
+ const visitor = ua(process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3", anonId, {
14
14
  strictCidFormat: false,
15
15
  https: true,
16
16
  });
17
17
  visitor.set("cd1", process.platform);
18
18
  visitor.set("cd2", process.version);
19
19
  visitor.set("cd3", process.env.FIREPIT_VERSION || "none");
20
- function track(action, label, duration) {
21
- return new Promise(function (resolve) {
22
- if (!_.isString(action) || !_.isString(label)) {
23
- logger.debug("track received non-string arguments:", action, label);
24
- resolve();
25
- }
26
- duration = duration || 0;
27
- if (configstore.get("tokens") && configstore.get("usage")) {
28
- visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(function () {
20
+ function track(action, label, duration = 0) {
21
+ return new Promise((resolve) => {
22
+ if (configstore_1.configstore.get("tokens") && configstore_1.configstore.get("usage")) {
23
+ visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(() => {
29
24
  resolve();
30
25
  });
31
26
  }
@@ -34,5 +29,4 @@ function track(action, label, duration) {
34
29
  }
35
30
  });
36
31
  }
37
- track.track = track;
38
- module.exports = track;
32
+ exports.track = track;
package/lib/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.assertDefined = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
3
+ exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.assertDefined = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
4
4
  const _ = require("lodash");
5
5
  const url = require("url");
6
6
  const clc = require("cli-color");
@@ -406,3 +406,32 @@ function groupBy(arr, f) {
406
406
  }, {});
407
407
  }
408
408
  exports.groupBy = groupBy;
409
+ function cloneArray(arr) {
410
+ return arr.map((e) => cloneDeep(e));
411
+ }
412
+ function cloneObject(obj) {
413
+ const clone = {};
414
+ for (const [k, v] of Object.entries(obj)) {
415
+ clone[k] = cloneDeep(v);
416
+ }
417
+ return clone;
418
+ }
419
+ function cloneDeep(obj) {
420
+ if (typeof obj !== "object" || !obj) {
421
+ return obj;
422
+ }
423
+ if (obj instanceof RegExp) {
424
+ return RegExp(obj, obj.flags);
425
+ }
426
+ if (obj instanceof Date) {
427
+ return new Date(obj);
428
+ }
429
+ if (Array.isArray(obj)) {
430
+ return cloneArray(obj);
431
+ }
432
+ if (obj instanceof Map) {
433
+ return new Map(obj.entries());
434
+ }
435
+ return cloneObject(obj);
436
+ }
437
+ exports.cloneDeep = cloneDeep;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "10.4.2",
3
+ "version": "10.7.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "firebase-tools",
9
- "version": "10.4.2",
9
+ "version": "10.7.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@google-cloud/pubsub": "^2.18.4",
@@ -30,6 +30,7 @@
30
30
  "exit-code": "^1.0.2",
31
31
  "express": "^4.16.4",
32
32
  "filesize": "^6.1.0",
33
+ "firebase-frameworks": "^0.3.0",
33
34
  "fs-extra": "^5.0.0",
34
35
  "glob": "^7.1.2",
35
36
  "google-auth-library": "^7.11.0",
@@ -114,6 +115,7 @@
114
115
  "@types/tcp-port-used": "^1.0.0",
115
116
  "@types/tmp": "^0.1.0",
116
117
  "@types/triple-beam": "^1.3.0",
118
+ "@types/universal-analytics": "^0.4.5",
117
119
  "@types/unzipper": "^0.10.0",
118
120
  "@types/uuid": "^8.3.1",
119
121
  "@types/ws": "^7.2.3",
@@ -2477,6 +2479,12 @@
2477
2479
  "integrity": "sha512-tl34wMtk3q+fSdRSJ+N83f47IyXLXPPuLjHm7cmAx0fE2Wml2TZCQV3FmQdSR5J6UEGV3qafG054e0cVVFCqPA==",
2478
2480
  "dev": true
2479
2481
  },
2482
+ "node_modules/@types/universal-analytics": {
2483
+ "version": "0.4.5",
2484
+ "resolved": "https://registry.npmjs.org/@types/universal-analytics/-/universal-analytics-0.4.5.tgz",
2485
+ "integrity": "sha512-Opb+Un786PS3te24VtJR/QPmX00P/pXaJQtLQYJklQefP4xP0Ic3mPc2z6SDz97OrITzR+RHTBEwjtNRjZ/nLQ==",
2486
+ "dev": true
2487
+ },
2480
2488
  "node_modules/@types/unzipper": {
2481
2489
  "version": "0.10.0",
2482
2490
  "resolved": "https://registry.npmjs.org/@types/unzipper/-/unzipper-0.10.0.tgz",
@@ -6106,6 +6114,19 @@
6106
6114
  "@firebase/app-types": "0.6.3"
6107
6115
  }
6108
6116
  },
6117
+ "node_modules/firebase-frameworks": {
6118
+ "version": "0.3.0",
6119
+ "resolved": "https://registry.npmjs.org/firebase-frameworks/-/firebase-frameworks-0.3.0.tgz",
6120
+ "integrity": "sha512-Zxtx5WsD8ZZdItIeDjjpM+JgaIWDdwBujmLYLKf2Ou6onyRsd8bNRrnVsqrnq4S3FN9TcNYliXdwMu7AwYdW7Q==",
6121
+ "dependencies": {
6122
+ "tslib": "^2.3.1"
6123
+ }
6124
+ },
6125
+ "node_modules/firebase-frameworks/node_modules/tslib": {
6126
+ "version": "2.3.1",
6127
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
6128
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
6129
+ },
6109
6130
  "node_modules/firebase-functions": {
6110
6131
  "version": "3.18.1",
6111
6132
  "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.18.1.tgz",
@@ -15801,6 +15822,12 @@
15801
15822
  "integrity": "sha512-tl34wMtk3q+fSdRSJ+N83f47IyXLXPPuLjHm7cmAx0fE2Wml2TZCQV3FmQdSR5J6UEGV3qafG054e0cVVFCqPA==",
15802
15823
  "dev": true
15803
15824
  },
15825
+ "@types/universal-analytics": {
15826
+ "version": "0.4.5",
15827
+ "resolved": "https://registry.npmjs.org/@types/universal-analytics/-/universal-analytics-0.4.5.tgz",
15828
+ "integrity": "sha512-Opb+Un786PS3te24VtJR/QPmX00P/pXaJQtLQYJklQefP4xP0Ic3mPc2z6SDz97OrITzR+RHTBEwjtNRjZ/nLQ==",
15829
+ "dev": true
15830
+ },
15804
15831
  "@types/unzipper": {
15805
15832
  "version": "0.10.0",
15806
15833
  "resolved": "https://registry.npmjs.org/@types/unzipper/-/unzipper-0.10.0.tgz",
@@ -18586,6 +18613,21 @@
18586
18613
  }
18587
18614
  }
18588
18615
  },
18616
+ "firebase-frameworks": {
18617
+ "version": "0.3.0",
18618
+ "resolved": "https://registry.npmjs.org/firebase-frameworks/-/firebase-frameworks-0.3.0.tgz",
18619
+ "integrity": "sha512-Zxtx5WsD8ZZdItIeDjjpM+JgaIWDdwBujmLYLKf2Ou6onyRsd8bNRrnVsqrnq4S3FN9TcNYliXdwMu7AwYdW7Q==",
18620
+ "requires": {
18621
+ "tslib": "^2.3.1"
18622
+ },
18623
+ "dependencies": {
18624
+ "tslib": {
18625
+ "version": "2.3.1",
18626
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
18627
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
18628
+ }
18629
+ }
18630
+ },
18589
18631
  "firebase-functions": {
18590
18632
  "version": "3.18.1",
18591
18633
  "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.18.1.tgz",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "10.4.2",
3
+ "version": "10.7.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -28,6 +28,7 @@
28
28
  "test:emulator": "./scripts/emulator-tests/run.sh",
29
29
  "test:extensions-deploy": "./scripts/extensions-deploy-tests/run.sh",
30
30
  "test:extensions-emulator": "./scripts/extensions-emulator-tests/run.sh",
31
+ "test:ext-dev-emulator": "./scripts/ext-dev-emulators-tests/run.sh",
31
32
  "test:hosting": "./scripts/hosting-tests/run.sh",
32
33
  "test:triggers-end-to-end": "./scripts/triggers-end-to-end-tests/run.sh",
33
34
  "test:storage-deploy": "./scripts/storage-deploy-tests/run.sh",
@@ -106,6 +107,7 @@
106
107
  "exit-code": "^1.0.2",
107
108
  "express": "^4.16.4",
108
109
  "filesize": "^6.1.0",
110
+ "firebase-frameworks": "^0.3.0",
109
111
  "fs-extra": "^5.0.0",
110
112
  "glob": "^7.1.2",
111
113
  "google-auth-library": "^7.11.0",
@@ -187,6 +189,7 @@
187
189
  "@types/tcp-port-used": "^1.0.0",
188
190
  "@types/tmp": "^0.1.0",
189
191
  "@types/triple-beam": "^1.3.0",
192
+ "@types/universal-analytics": "^0.4.5",
190
193
  "@types/unzipper": "^0.10.0",
191
194
  "@types/uuid": "^8.3.1",
192
195
  "@types/ws": "^7.2.3",
@@ -330,6 +330,9 @@
330
330
  {
331
331
  "additionalProperties": false,
332
332
  "properties": {
333
+ "codebase": {
334
+ "type": "string"
335
+ },
333
336
  "ignore": {
334
337
  "items": {
335
338
  "type": "string"
@@ -381,6 +384,9 @@
381
384
  "items": {
382
385
  "additionalProperties": false,
383
386
  "properties": {
387
+ "codebase": {
388
+ "type": "string"
389
+ },
384
390
  "ignore": {
385
391
  "items": {
386
392
  "type": "string"
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ListResponse = exports.ListItem = void 0;
4
- class ListItem {
5
- constructor(name, bucket) {
6
- this.name = name;
7
- this.bucket = bucket;
8
- }
9
- }
10
- exports.ListItem = ListItem;
11
- class ListResponse {
12
- constructor(prefixes, items, nextPageToken) {
13
- this.prefixes = prefixes;
14
- this.items = items;
15
- this.nextPageToken = nextPageToken;
16
- }
17
- }
18
- exports.ListResponse = ListResponse;