firebase-tools 11.16.1 → 11.17.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.
@@ -1126,7 +1126,8 @@ async function signInWithIdp(state, reqBody) {
1126
1126
  oauthExpiresIn: coercePrimitiveToString(response.oauthExpireIn),
1127
1127
  };
1128
1128
  if (response.isNewUser) {
1129
- let updates = Object.assign(Object.assign({}, accountUpdates.fields), { lastLoginAt: Date.now().toString(), providerUserInfo: [providerUserInfo], tenantId: state instanceof state_1.TenantProjectState ? state.tenantId : undefined });
1129
+ const timestamp = new Date();
1130
+ let updates = Object.assign(Object.assign({}, accountUpdates.fields), { createdAt: timestamp.getTime().toString(), lastLoginAt: timestamp.getTime().toString(), providerUserInfo: [providerUserInfo], tenantId: state instanceof state_1.TenantProjectState ? state.tenantId : undefined });
1130
1131
  const localId = state.generateLocalId();
1131
1132
  const userBeforeCreate = Object.assign({ localId }, updates);
1132
1133
  const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_CREATE, userBeforeCreate, {
@@ -1187,7 +1188,8 @@ async function signInWithIdp(state, reqBody) {
1187
1188
  async function signInWithPassword(state, reqBody) {
1188
1189
  (0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
1189
1190
  (0, errors_1.assert)(state.allowPasswordSignup, "PASSWORD_LOGIN_DISABLED");
1190
- (0, errors_1.assert)(reqBody.email, "MISSING_EMAIL");
1191
+ (0, errors_1.assert)(reqBody.email !== undefined, "MISSING_EMAIL");
1192
+ (0, errors_1.assert)((0, utils_1.isValidEmailAddress)(reqBody.email), "INVALID_EMAIL");
1191
1193
  (0, errors_1.assert)(reqBody.password, "MISSING_PASSWORD");
1192
1194
  if (reqBody.captchaResponse || reqBody.captchaChallenge) {
1193
1195
  throw new errors_1.NotImplementedError("captcha unimplemented");
@@ -97,14 +97,24 @@ async function createApp(defaultProjectId, singleProjectMode = index_1.SinglePro
97
97
  registerLegacyRoutes(app);
98
98
  (0, handlers_1.registerHandlers)(app, (apiKey, tenantId) => getProjectStateById(getProjectIdByApiKey(apiKey), tenantId));
99
99
  const apiKeyAuthenticator = (ctx, info) => {
100
- if (info.in !== "query") {
101
- throw new Error('apiKey must be defined as in: "query" in API spec.');
102
- }
103
100
  if (!info.name) {
104
- throw new Error("apiKey param name is undefined in API spec.");
101
+ throw new Error("apiKey param/header name is undefined in API spec.");
102
+ }
103
+ let key;
104
+ const req = ctx.req;
105
+ switch (info.in) {
106
+ case "header":
107
+ key = req.get(info.name);
108
+ break;
109
+ case "query": {
110
+ const q = req.query[info.name];
111
+ key = typeof q === "string" ? q : undefined;
112
+ break;
113
+ }
114
+ default:
115
+ throw new Error('apiKey must be defined as in: "query" or "header" in API spec.');
105
116
  }
106
- const key = ctx.req.query[info.name];
107
- if (typeof key === "string" && key.length > 0) {
117
+ if (key) {
108
118
  return { type: "success", user: getProjectIdByApiKey(key) };
109
119
  }
110
120
  else {
@@ -138,7 +148,8 @@ async function createApp(defaultProjectId, singleProjectMode = index_1.SinglePro
138
148
  const apis = await exegesisExpress.middleware(specForRouter(), {
139
149
  controllers: { auth: toExegesisController(operations_1.authOperations, getProjectStateById) },
140
150
  authenticators: {
141
- apiKey: apiKeyAuthenticator,
151
+ apiKeyQuery: apiKeyAuthenticator,
152
+ apiKeyHeader: apiKeyAuthenticator,
142
153
  Oauth2: oauth2Authenticator,
143
154
  },
144
155
  autoHandleHttpErrors(err) {
@@ -206,7 +217,7 @@ async function createApp(defaultProjectId, singleProjectMode = index_1.SinglePro
206
217
  postController(ctx) {
207
218
  if (ctx.res.statusCode === 401) {
208
219
  const requirements = ctx.api.operationObject.security;
209
- if (requirements === null || requirements === void 0 ? void 0 : requirements.some((req) => req.apiKey)) {
220
+ if (requirements === null || requirements === void 0 ? void 0 : requirements.some((req) => req.apiKeyQuery || req.apiKeyHeader)) {
210
221
  throw new errors_2.PermissionDeniedError("The request is missing a valid API key.");
211
222
  }
212
223
  else {
@@ -8,6 +8,7 @@ const utils_1 = require("../utils");
8
8
  const emulatorLogger_1 = require("./emulatorLogger");
9
9
  const registry_1 = require("./registry");
10
10
  const error_1 = require("../error");
11
+ const eventarcEmulatorUtils_1 = require("./eventarcEmulatorUtils");
11
12
  class EventarcEmulator {
12
13
  constructor(args) {
13
14
  this.args = args;
@@ -89,7 +90,7 @@ class EventarcEmulator {
89
90
  .request({
90
91
  method: "POST",
91
92
  path: `/functions/projects/${trigger.projectId}/triggers/${trigger.triggerName}`,
92
- body: JSON.stringify(event),
93
+ body: JSON.stringify((0, eventarcEmulatorUtils_1.cloudEventFromProtoToJson)(event)),
93
94
  responseType: "stream",
94
95
  resolveOnHTTPError: true,
95
96
  })
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cloudEventFromProtoToJson = void 0;
4
+ const error_1 = require("../error");
5
+ const BUILT_IN_ATTRS = ["time", "datacontenttype", "subject"];
6
+ function cloudEventFromProtoToJson(ce) {
7
+ if (ce["id"] === undefined) {
8
+ throw new error_1.FirebaseError("CloudEvent 'id' is required.");
9
+ }
10
+ if (ce["type"] === undefined) {
11
+ throw new error_1.FirebaseError("CloudEvent 'type' is required.");
12
+ }
13
+ if (ce["specVersion"] === undefined) {
14
+ throw new error_1.FirebaseError("CloudEvent 'specVersion' is required.");
15
+ }
16
+ if (ce["source"] === undefined) {
17
+ throw new error_1.FirebaseError("CloudEvent 'source' is required.");
18
+ }
19
+ const out = {
20
+ id: ce["id"],
21
+ type: ce["type"],
22
+ specversion: ce["specVersion"],
23
+ source: ce["source"],
24
+ subject: getOptionalAttribute(ce, "subject", "ceString"),
25
+ time: getRequiredAttribute(ce, "time", "ceTimestamp"),
26
+ data: getData(ce),
27
+ datacontenttype: getRequiredAttribute(ce, "datacontenttype", "ceString"),
28
+ };
29
+ for (const attr in ce["attributes"]) {
30
+ if (BUILT_IN_ATTRS.includes(attr)) {
31
+ continue;
32
+ }
33
+ out[attr] = getRequiredAttribute(ce, attr, "ceString");
34
+ }
35
+ return out;
36
+ }
37
+ exports.cloudEventFromProtoToJson = cloudEventFromProtoToJson;
38
+ function getOptionalAttribute(ce, attr, type) {
39
+ return ce["attributes"][attr][type];
40
+ }
41
+ function getRequiredAttribute(ce, attr, type) {
42
+ const val = ce["attributes"][attr][type];
43
+ if (val === undefined) {
44
+ throw new error_1.FirebaseError("CloudEvent must contain " + attr + " attribute");
45
+ }
46
+ return val;
47
+ }
48
+ function getData(ce) {
49
+ const contentType = getRequiredAttribute(ce, "datacontenttype", "ceString");
50
+ switch (contentType) {
51
+ case "application/json":
52
+ return JSON.parse(ce["textData"]);
53
+ case "text/plain":
54
+ return ce["textData"];
55
+ case undefined:
56
+ return undefined;
57
+ default:
58
+ throw new error_1.FirebaseError("Unsupported content type: " + contentType);
59
+ }
60
+ }
@@ -334,7 +334,7 @@ class FunctionsEmulator {
334
334
  added = await this.addFirestoreTrigger(this.args.projectId, key, definition.eventTrigger);
335
335
  break;
336
336
  case constants_1.Constants.SERVICE_REALTIME_DATABASE:
337
- added = await this.addRealtimeDatabaseTrigger(this.args.projectId, key, definition.eventTrigger, signature, definition.region);
337
+ added = await this.addRealtimeDatabaseTrigger(this.args.projectId, definition.id, key, definition.eventTrigger, signature, definition.region);
338
338
  break;
339
339
  case constants_1.Constants.SERVICE_PUBSUB:
340
340
  added = await this.addPubsubTrigger(definition.name, key, definition.eventTrigger, signature, definition.schedule);
@@ -438,7 +438,7 @@ class FunctionsEmulator {
438
438
  }
439
439
  return { bundle, apiPath, instance };
440
440
  }
441
- getV2DatabaseApiAttributes(projectId, key, eventTrigger, region) {
441
+ getV2DatabaseApiAttributes(projectId, id, key, eventTrigger, region) {
442
442
  var _a, _b, _c;
443
443
  const instance = ((_a = eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.instance) || ((_b = eventTrigger.eventFilterPathPatterns) === null || _b === void 0 ? void 0 : _b.instance);
444
444
  if (!instance) {
@@ -448,6 +448,9 @@ class FunctionsEmulator {
448
448
  if (!ref) {
449
449
  throw new error_1.FirebaseError("A database reference must be supplied.");
450
450
  }
451
+ if (region !== "us-central1") {
452
+ this.logger.logLabeled("WARN", `functions[${id}]`, `function region is defined outside the database region, will not trigger.`);
453
+ }
451
454
  const bundle = JSON.stringify({
452
455
  name: `projects/${projectId}/locations/${region}/triggers/${key}`,
453
456
  path: ref,
@@ -458,12 +461,12 @@ class FunctionsEmulator {
458
461
  const apiPath = "/.settings/functionTriggers.json";
459
462
  return { bundle, apiPath, instance };
460
463
  }
461
- async addRealtimeDatabaseTrigger(projectId, key, eventTrigger, signature, region) {
464
+ async addRealtimeDatabaseTrigger(projectId, id, key, eventTrigger, signature, region) {
462
465
  if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.DATABASE)) {
463
466
  return false;
464
467
  }
465
468
  const { bundle, apiPath, instance } = signature === "cloudevent"
466
- ? this.getV2DatabaseApiAttributes(projectId, key, eventTrigger, region)
469
+ ? this.getV2DatabaseApiAttributes(projectId, id, key, eventTrigger, region)
467
470
  : this.getV1DatabaseApiAttributes(projectId, key, eventTrigger);
468
471
  logger_1.logger.debug(`addRealtimeDatabaseTrigger[${instance}]`, JSON.stringify(bundle));
469
472
  const client = registry_1.EmulatorRegistry.client(types_1.Emulators.DATABASE);
@@ -881,6 +884,10 @@ class FunctionsEmulator {
881
884
  return;
882
885
  }
883
886
  const record = this.getTriggerRecordByKey(triggerId);
887
+ if (!record.enabled) {
888
+ res.status(204).send("Background triggers are currently disabled.");
889
+ return;
890
+ }
884
891
  const trigger = record.def;
885
892
  logger_1.logger.debug(`Accepted request ${method} ${req.url} --> ${triggerId}`);
886
893
  const reqBody = req.rawBody;
@@ -558,12 +558,15 @@ async function diagnoseAndFixProject(options) {
558
558
  }
559
559
  }
560
560
  exports.diagnoseAndFixProject = diagnoseAndFixProject;
561
- async function canonicalizeRefInput(extensionName) {
562
- if (extensionName.split("/").length < 2) {
563
- const [extensionID, version] = extensionName.split("@");
564
- extensionName = `firebase/${extensionID}@${version || "latest"}`;
561
+ async function canonicalizeRefInput(refInput) {
562
+ let inferredRef = refInput;
563
+ if (refInput.split("/").length < 2) {
564
+ inferredRef = `firebase/${inferredRef}`;
565
565
  }
566
- const ref = refs.parse(extensionName);
566
+ if (refInput.split("@").length < 2) {
567
+ inferredRef = `${inferredRef}@latest`;
568
+ }
569
+ const ref = refs.parse(inferredRef);
567
570
  ref.version = await (0, planner_1.resolveVersion)(ref);
568
571
  return refs.toExtensionVersionRef(ref);
569
572
  }
package/lib/utils.js CHANGED
@@ -363,7 +363,7 @@ function datetimeString(d) {
363
363
  }
364
364
  exports.datetimeString = datetimeString;
365
365
  function isCloudEnvironment() {
366
- return !!process.env.CODESPACES;
366
+ return !!process.env.CODESPACES || !!process.env.GOOGLE_CLOUD_WORKSTATIONS;
367
367
  }
368
368
  exports.isCloudEnvironment = isCloudEnvironment;
369
369
  function isRunningInWSL() {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "11.16.1",
3
+ "version": "11.17.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "firebase-tools",
9
- "version": "11.16.1",
9
+ "version": "11.17.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@google-cloud/pubsub": "^3.0.1",
@@ -167,24 +167,6 @@
167
167
  "node": ">=12.0.0"
168
168
  }
169
169
  },
170
- "node_modules/@google-cloud/pubsub/node_modules/@grpc/proto-loader": {
171
- "version": "0.6.12",
172
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.12.tgz",
173
- "integrity": "sha512-filTVbETFnxb9CyRX98zN18ilChTuf/C5scZ2xyaOTp0EHGq0/ufX8rjqXUcSb1Gpv7eZq4M2jDvbh9BogKnrg==",
174
- "dependencies": {
175
- "@types/long": "^4.0.1",
176
- "lodash.camelcase": "^4.3.0",
177
- "long": "^4.0.0",
178
- "protobufjs": "^6.10.0",
179
- "yargs": "^16.2.0"
180
- },
181
- "bin": {
182
- "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
183
- },
184
- "engines": {
185
- "node": ">=6"
186
- }
187
- },
188
170
  "node_modules/@google-cloud/pubsub/node_modules/debug": {
189
171
  "version": "4.3.4",
190
172
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -343,15 +325,15 @@
343
325
  "node": "^8.13.0 || >=10.10.0"
344
326
  }
345
327
  },
346
- "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": {
347
- "version": "0.6.9",
348
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.9.tgz",
349
- "integrity": "sha512-UlcCS8VbsU9d3XTXGiEVFonN7hXk+oMXZtoHHG2oSA1/GcDP1q6OUgs20PzHDGizzyi8ufGSUDlk3O2NyY7leg==",
328
+ "node_modules/@grpc/proto-loader": {
329
+ "version": "0.6.13",
330
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz",
331
+ "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==",
350
332
  "dependencies": {
351
333
  "@types/long": "^4.0.1",
352
334
  "lodash.camelcase": "^4.3.0",
353
335
  "long": "^4.0.0",
354
- "protobufjs": "^6.10.0",
336
+ "protobufjs": "^6.11.3",
355
337
  "yargs": "^16.2.0"
356
338
  },
357
339
  "bin": {
@@ -3024,14 +3006,6 @@
3024
3006
  "node": ">=10"
3025
3007
  }
3026
3008
  },
3027
- "node_modules/google-p12-pem/node_modules/node-forge": {
3028
- "version": "1.3.1",
3029
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
3030
- "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
3031
- "engines": {
3032
- "node": ">= 6.13.0"
3033
- }
3034
- },
3035
3009
  "node_modules/got": {
3036
3010
  "version": "9.6.0",
3037
3011
  "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
@@ -3210,9 +3184,9 @@
3210
3184
  }
3211
3185
  },
3212
3186
  "node_modules/https-proxy-agent": {
3213
- "version": "5.0.0",
3214
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
3215
- "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
3187
+ "version": "5.0.1",
3188
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
3189
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
3216
3190
  "dependencies": {
3217
3191
  "agent-base": "6",
3218
3192
  "debug": "4"
@@ -4539,6 +4513,14 @@
4539
4513
  }
4540
4514
  }
4541
4515
  },
4516
+ "node_modules/node-forge": {
4517
+ "version": "1.3.1",
4518
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
4519
+ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
4520
+ "engines": {
4521
+ "node": ">= 6.13.0"
4522
+ }
4523
+ },
4542
4524
  "node_modules/node-gyp": {
4543
4525
  "version": "9.1.0",
4544
4526
  "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.1.0.tgz",
@@ -7006,18 +6988,6 @@
7006
6988
  "extend": "^3.0.2"
7007
6989
  }
7008
6990
  },
7009
- "@grpc/proto-loader": {
7010
- "version": "0.6.12",
7011
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.12.tgz",
7012
- "integrity": "sha512-filTVbETFnxb9CyRX98zN18ilChTuf/C5scZ2xyaOTp0EHGq0/ufX8rjqXUcSb1Gpv7eZq4M2jDvbh9BogKnrg==",
7013
- "requires": {
7014
- "@types/long": "^4.0.1",
7015
- "lodash.camelcase": "^4.3.0",
7016
- "long": "^4.0.0",
7017
- "protobufjs": "^6.10.0",
7018
- "yargs": "^16.2.0"
7019
- }
7020
- },
7021
6991
  "debug": {
7022
6992
  "version": "4.3.4",
7023
6993
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -7138,20 +7108,18 @@
7138
7108
  "requires": {
7139
7109
  "@grpc/proto-loader": "^0.6.4",
7140
7110
  "@types/node": ">=12.12.47"
7141
- },
7142
- "dependencies": {
7143
- "@grpc/proto-loader": {
7144
- "version": "0.6.9",
7145
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.9.tgz",
7146
- "integrity": "sha512-UlcCS8VbsU9d3XTXGiEVFonN7hXk+oMXZtoHHG2oSA1/GcDP1q6OUgs20PzHDGizzyi8ufGSUDlk3O2NyY7leg==",
7147
- "requires": {
7148
- "@types/long": "^4.0.1",
7149
- "lodash.camelcase": "^4.3.0",
7150
- "long": "^4.0.0",
7151
- "protobufjs": "^6.10.0",
7152
- "yargs": "^16.2.0"
7153
- }
7154
- }
7111
+ }
7112
+ },
7113
+ "@grpc/proto-loader": {
7114
+ "version": "0.6.13",
7115
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz",
7116
+ "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==",
7117
+ "requires": {
7118
+ "@types/long": "^4.0.1",
7119
+ "lodash.camelcase": "^4.3.0",
7120
+ "long": "^4.0.0",
7121
+ "protobufjs": "^6.11.3",
7122
+ "yargs": "^16.2.0"
7155
7123
  }
7156
7124
  },
7157
7125
  "@jsdevtools/ono": {
@@ -9246,13 +9214,6 @@
9246
9214
  "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==",
9247
9215
  "requires": {
9248
9216
  "node-forge": "^1.0.0"
9249
- },
9250
- "dependencies": {
9251
- "node-forge": {
9252
- "version": "1.3.1",
9253
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
9254
- "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
9255
- }
9256
9217
  }
9257
9218
  },
9258
9219
  "got": {
@@ -9402,9 +9363,9 @@
9402
9363
  }
9403
9364
  },
9404
9365
  "https-proxy-agent": {
9405
- "version": "5.0.0",
9406
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
9407
- "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
9366
+ "version": "5.0.1",
9367
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
9368
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
9408
9369
  "requires": {
9409
9370
  "agent-base": "6",
9410
9371
  "debug": "4"
@@ -10434,6 +10395,11 @@
10434
10395
  "whatwg-url": "^5.0.0"
10435
10396
  }
10436
10397
  },
10398
+ "node-forge": {
10399
+ "version": "1.3.1",
10400
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
10401
+ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
10402
+ },
10437
10403
  "node-gyp": {
10438
10404
  "version": "9.1.0",
10439
10405
  "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.1.0.tgz",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "11.16.1",
3
+ "version": "11.17.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {