firebase-tools 15.20.0 → 15.21.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 (44) hide show
  1. package/lib/apphosting/constants.js +2 -1
  2. package/lib/apphosting/localbuilds.js +4 -2
  3. package/lib/archiveDirectory.js +2 -2
  4. package/lib/auth.js +2 -3
  5. package/lib/bin/cli.js +26 -18
  6. package/lib/commands/apptesting.js +11 -2
  7. package/lib/commands/crashlytics-symbols-upload.js +2 -2
  8. package/lib/crashlytics/sourcemap.js +2 -3
  9. package/lib/database/import.js +2 -2
  10. package/lib/dataconnect/build.js +6 -6
  11. package/lib/deploy/apphosting/util.js +9 -1
  12. package/lib/deploy/functions/prepare.js +39 -3
  13. package/lib/deploy/functions/prepareFunctionsUpload.js +1 -2
  14. package/lib/deploy/functions/release/index.js +0 -5
  15. package/lib/emulator/auth/apiSpec.js +307 -33
  16. package/lib/emulator/auth/cloudFunctions.js +2 -2
  17. package/lib/emulator/auth/operations.js +99 -9
  18. package/lib/emulator/auth/state.js +27 -0
  19. package/lib/emulator/downloadableEmulatorInfo.json +24 -24
  20. package/lib/emulator/functionsEmulatorShell.js +4 -4
  21. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  22. package/lib/emulator/pubsubEmulator.js +3 -3
  23. package/lib/emulator/storage/apis/firebase.js +2 -2
  24. package/lib/emulator/storage/cloudFunctions.js +2 -2
  25. package/lib/emulator/storage/metadata.js +1 -2
  26. package/lib/emulator/storage/persistence.js +2 -2
  27. package/lib/emulator/storage/upload.js +3 -3
  28. package/lib/env.js +20 -4
  29. package/lib/experiments.js +1 -2
  30. package/lib/frameworks/angular/index.js +3 -2
  31. package/lib/frameworks/angular/utils.js +100 -2
  32. package/lib/frameworks/astro/index.js +1 -1
  33. package/lib/frameworks/astro/utils.js +1 -1
  34. package/lib/functions/python.js +4 -4
  35. package/lib/hosting/cloudRunProxy.js +8 -0
  36. package/lib/index.js +2 -2
  37. package/lib/init/features/apphosting.js +8 -1
  38. package/lib/init/features/functions/python.js +32 -20
  39. package/lib/localFunction.js +4 -2
  40. package/lib/track.js +2 -2
  41. package/lib/tsconfig.compile.tsbuildinfo +1 -1
  42. package/lib/tsconfig.publish.tsbuildinfo +1 -1
  43. package/lib/utils.js +70 -0
  44. package/package.json +1 -6
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AuthCloudFunction = void 0;
4
- const uuid = require("uuid");
4
+ const crypto_1 = require("crypto");
5
5
  const types_1 = require("../types");
6
6
  const emulatorLogger_1 = require("../emulatorLogger");
7
7
  const registry_1 = require("../registry");
@@ -32,7 +32,7 @@ class AuthCloudFunction {
32
32
  }
33
33
  createEventRequestBody(action, userInfoPayload) {
34
34
  return {
35
- eventId: uuid.v4(),
35
+ eventId: (0, crypto_1.randomUUID)(),
36
36
  eventType: `providers/firebase.auth/eventTypes/user.${action}`,
37
37
  resource: {
38
38
  name: `projects/${this.projectId}`,
@@ -41,6 +41,14 @@ exports.authOperations = {
41
41
  start: mfaSignInStart,
42
42
  finalize: mfaSignInFinalize,
43
43
  },
44
+ passkeyEnrollment: {
45
+ start: passkeyEnrollmentStart,
46
+ finalize: passkeyEnrollmentFinalize,
47
+ },
48
+ passkeySignIn: {
49
+ start: passkeySignInStart,
50
+ finalize: passkeySignInFinalize,
51
+ },
44
52
  },
45
53
  projects: {
46
54
  createSessionCookie,
@@ -914,6 +922,10 @@ function setAccountInfoImpl(state, reqBody, { privileged = false, emulatorUrl =
914
922
  if (reqBody.deleteProvider?.includes(state_1.PROVIDER_PHONE)) {
915
923
  updates.phoneNumber = undefined;
916
924
  }
925
+ if (reqBody.deletePasskey) {
926
+ const deletePasskey = reqBody.deletePasskey;
927
+ updates.passkeyInfo = (user.passkeyInfo || []).filter((pk) => pk.credentialId && !deletePasskey.includes(pk.credentialId));
928
+ }
917
929
  }
918
930
  if (reqBody.linkProviderUserInfo) {
919
931
  (0, errors_1.assert)(reqBody.linkProviderUserInfo.providerId, "MISSING_PROVIDER_ID");
@@ -1574,16 +1586,90 @@ async function mfaSignInFinalize(state, reqBody) {
1574
1586
  refreshToken,
1575
1587
  };
1576
1588
  }
1589
+ function passkeyEnrollmentStart(state, reqBody) {
1590
+ (0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
1591
+ (0, errors_1.assert)(reqBody.idToken, "MISSING_ID_TOKEN");
1592
+ const { user } = parseIdToken(state, reqBody.idToken);
1593
+ return {
1594
+ credentialCreationOptions: {
1595
+ rp: { name: "localhost", id: "localhost" },
1596
+ user: {
1597
+ id: Buffer.from(user.localId).toString("base64"),
1598
+ name: user.email || "user@example.com",
1599
+ displayName: user.displayName || "User",
1600
+ },
1601
+ challenge: Buffer.from(newRandomId(32)).toString("base64"),
1602
+ pubKeyCredParams: [
1603
+ { type: "public-key", alg: -7 },
1604
+ { type: "public-key", alg: -257 },
1605
+ ],
1606
+ timeout: 60000,
1607
+ attestation: "none",
1608
+ },
1609
+ };
1610
+ }
1611
+ function passkeyEnrollmentFinalize(state, reqBody) {
1612
+ (0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
1613
+ (0, errors_1.assert)(reqBody.idToken, "MISSING_ID_TOKEN");
1614
+ (0, errors_1.assert)(reqBody.authenticatorRegistrationResponse, "MISSING_AUTHENTICATOR_RESPONSE");
1615
+ let { user } = parseIdToken(state, reqBody.idToken);
1616
+ const credentialId = reqBody.authenticatorRegistrationResponse.id;
1617
+ (0, errors_1.assert)(credentialId, "INVALID_CREDENTIAL_ID");
1618
+ const isDuplicate = !!state.getUserByPasskeyCredentialId(credentialId);
1619
+ (0, errors_1.assert)(!isDuplicate, "CREDENTIAL_ALREADY_IN_USE");
1620
+ const newPasskey = {
1621
+ credentialId,
1622
+ name: reqBody.name || reqBody.displayName || "Unnamed Passkey",
1623
+ };
1624
+ const existing = user.passkeyInfo || [];
1625
+ user = state.updateUserByLocalId(user.localId, {
1626
+ passkeyInfo: [...existing, newPasskey],
1627
+ });
1628
+ const { idToken, refreshToken } = issueTokens(state, user, "passkey");
1629
+ return {
1630
+ localId: user.localId,
1631
+ idToken,
1632
+ refreshToken,
1633
+ };
1634
+ }
1635
+ function passkeySignInStart(state) {
1636
+ (0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
1637
+ return {
1638
+ credentialRequestOptions: {
1639
+ challenge: Buffer.from(newRandomId(32)).toString("base64"),
1640
+ rpId: "localhost",
1641
+ userVerification: "required",
1642
+ },
1643
+ };
1644
+ }
1645
+ function passkeySignInFinalize(state, reqBody) {
1646
+ (0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
1647
+ (0, errors_1.assert)(reqBody.authenticatorAuthenticationResponse, "MISSING_AUTHENTICATOR_RESPONSE");
1648
+ const credentialId = reqBody.authenticatorAuthenticationResponse.id;
1649
+ (0, errors_1.assert)(credentialId, "INVALID_CREDENTIAL_ID");
1650
+ let matchedUser = state.getUserByPasskeyCredentialId(credentialId);
1651
+ (0, errors_1.assert)(matchedUser, "PASSKEY_CREDENTIAL_NOT_FOUND");
1652
+ (0, errors_1.assert)(!matchedUser.disabled, "USER_DISABLED");
1653
+ matchedUser = state.updateUserByLocalId(matchedUser.localId, {
1654
+ lastLoginAt: Date.now().toString(),
1655
+ });
1656
+ const { idToken, refreshToken } = issueTokens(state, matchedUser, "passkey");
1657
+ return {
1658
+ idToken,
1659
+ refreshToken,
1660
+ };
1661
+ }
1577
1662
  function getConfig(state) {
1578
1663
  (0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Can only get top-level configurations on agent projects.))");
1579
1664
  return state.config;
1580
1665
  }
1581
1666
  function updateConfig(state, reqBody, ctx) {
1582
1667
  (0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Can only update top-level configurations on agent projects.))");
1583
- for (const event in reqBody.blockingFunctions?.triggers) {
1584
- if (Object.prototype.hasOwnProperty.call(reqBody.blockingFunctions.triggers, event)) {
1668
+ const triggers = reqBody.blockingFunctions?.triggers ?? {};
1669
+ for (const event in triggers) {
1670
+ if (Object.prototype.hasOwnProperty.call(triggers, event)) {
1585
1671
  (0, errors_1.assert)(Object.values(state_1.BlockingFunctionEvents).includes(event), "INVALID_BLOCKING_FUNCTION : ((Event type is invalid.))");
1586
- (0, errors_1.assert)((0, utils_1.parseAbsoluteUri)(reqBody.blockingFunctions.triggers[event].functionUri), "INVALID_BLOCKING_FUNCTION : ((Expected an absolute URI with valid scheme and host.))");
1672
+ (0, errors_1.assert)((0, utils_1.parseAbsoluteUri)(triggers[event].functionUri), "INVALID_BLOCKING_FUNCTION : ((Expected an absolute URI with valid scheme and host.))");
1587
1673
  }
1588
1674
  }
1589
1675
  return state.updateConfig(reqBody, ctx.params.query.updateMask);
@@ -1870,13 +1956,13 @@ function fakeFetchUserInfoFromIdp(providerId, claims, samlResponse) {
1870
1956
  });
1871
1957
  break;
1872
1958
  }
1873
- case providerId.match(/^saml\./)?.input:
1959
+ case /^saml\./.exec(providerId)?.input:
1874
1960
  const nameId = samlResponse?.assertion?.subject?.nameId;
1875
1961
  response.email = nameId && (0, utils_1.isValidEmailAddress)(nameId) ? nameId : response.email;
1876
1962
  response.emailVerified = true;
1877
1963
  response.rawUserInfo = JSON.stringify(samlResponse?.assertion?.attributeStatements);
1878
1964
  break;
1879
- case providerId.match(/^oidc\./)?.input:
1965
+ case /^oidc\./.exec(providerId)?.input:
1880
1966
  default:
1881
1967
  response.rawUserInfo = JSON.stringify(claims);
1882
1968
  break;
@@ -2271,11 +2357,15 @@ function generateBlockingFunctionJwt(state, event, url, timeoutMs, user, options
2271
2357
  });
2272
2358
  return jwtStr;
2273
2359
  }
2360
+ function assertBlockingFunctionsJwtPayload(payload) {
2361
+ (0, errors_1.assert)(payload !== null && typeof payload === "object", "((Invalid blocking function jwt.))");
2362
+ const p = payload;
2363
+ (0, errors_1.assert)(typeof p.iss === "string", "((Invalid blocking function jwt, missing `iss` claim.))");
2364
+ (0, errors_1.assert)(typeof p.aud === "string", "((Invalid blocking function jwt, missing `aud` claim.))");
2365
+ (0, errors_1.assert)(p.user_record !== undefined, "((Invalid blocking function jwt, missing `user_record` claim.))");
2366
+ }
2274
2367
  function parseBlockingFunctionJwt(jwt) {
2275
2368
  const decoded = (0, jsonwebtoken_1.decode)(jwt, { json: true });
2276
- (0, errors_1.assert)(decoded, "((Invalid blocking function jwt.))");
2277
- (0, errors_1.assert)(decoded.iss, "((Invalid blocking function jwt, missing `iss` claim.))");
2278
- (0, errors_1.assert)(decoded.aud, "((Invalid blocking function jwt, missing `aud` claim.))");
2279
- (0, errors_1.assert)(decoded.user_record, "((Invalid blocking function jwt, missing `user_record` claim.))");
2369
+ assertBlockingFunctionsJwtPayload(decoded);
2280
2370
  return decoded;
2281
2371
  }
@@ -21,6 +21,7 @@ class ProjectState {
21
21
  this.localIdForPhoneNumber = new Map();
22
22
  this.localIdsForProviderEmail = new Map();
23
23
  this.userIdForProviderRawId = new Map();
24
+ this.localIdForPasskeyCredentialId = new Map();
24
25
  this.oobs = new Map();
25
26
  this.verificationCodes = new Map();
26
27
  this.temporaryProofs = new Map();
@@ -83,9 +84,22 @@ class ProjectState {
83
84
  }
84
85
  const oldEmail = user.email;
85
86
  const oldPhoneNumber = user.phoneNumber;
87
+ const oldPasskeyInfo = user.passkeyInfo;
86
88
  for (const field of Object.keys(fields)) {
87
89
  (0, utils_1.mirrorFieldTo)(user, field, fields);
88
90
  }
91
+ if (fields.passkeyInfo) {
92
+ for (const pk of oldPasskeyInfo ?? []) {
93
+ if (pk.credentialId) {
94
+ this.localIdForPasskeyCredentialId.delete(pk.credentialId);
95
+ }
96
+ }
97
+ for (const pk of fields.passkeyInfo) {
98
+ if (pk.credentialId) {
99
+ this.localIdForPasskeyCredentialId.set(pk.credentialId, user.localId);
100
+ }
101
+ }
102
+ }
89
103
  if (oldEmail && oldEmail !== user.email) {
90
104
  this.localIdForEmail.delete(oldEmail);
91
105
  }
@@ -267,6 +281,13 @@ class ProjectState {
267
281
  getUserByLocalId(localId) {
268
282
  return this.users.get(localId);
269
283
  }
284
+ getUserByPasskeyCredentialId(credentialId) {
285
+ const localId = this.localIdForPasskeyCredentialId.get(credentialId);
286
+ if (!localId) {
287
+ return undefined;
288
+ }
289
+ return this.getUserByLocalIdAssertingExists(localId);
290
+ }
270
291
  createRefreshTokenFor(userInfo, provider, { extraClaims = {}, secondFactor, } = {}) {
271
292
  const localId = userInfo.localId;
272
293
  const refreshTokenRecord = {
@@ -343,6 +364,7 @@ class ProjectState {
343
364
  this.localIdForPhoneNumber.clear();
344
365
  this.localIdsForProviderEmail.clear();
345
366
  this.userIdForProviderRawId.clear();
367
+ this.localIdForPasskeyCredentialId.clear();
346
368
  }
347
369
  getUserCount() {
348
370
  return this.users.size;
@@ -400,6 +422,11 @@ class ProjectState {
400
422
  this.removeProviderEmailForUser(info.email, user.localId);
401
423
  }
402
424
  }
425
+ for (const pk of user.passkeyInfo ?? []) {
426
+ if (pk.credentialId) {
427
+ this.localIdForPasskeyCredentialId.delete(pk.credentialId);
428
+ }
429
+ }
403
430
  }
404
431
  }
405
432
  exports.ProjectState = ProjectState;
@@ -54,36 +54,36 @@
54
54
  },
55
55
  "dataconnect": {
56
56
  "darwin": {
57
- "version": "3.4.10",
58
- "expectedSize": 32439760,
59
- "expectedChecksum": "c3609b01993c1f66d340eda59fa31467",
60
- "expectedChecksumSHA256": "257419922a81b4856b1ce7c1ac0684b4690a380072fe132d1960070f7d00941a",
61
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v3.4.10",
62
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.10"
57
+ "version": "3.4.11",
58
+ "expectedSize": 32444112,
59
+ "expectedChecksum": "b7d6dfb69ff26d5952ad93bbb6b071c9",
60
+ "expectedChecksumSHA256": "66ef23bd048e7cb93dd7574ab92fbbdc66c82e7b72e38625d7a9f1f8b724532a",
61
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v3.4.11",
62
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.11"
63
63
  },
64
64
  "darwin_arm64": {
65
- "version": "3.4.10",
66
- "expectedSize": 30571186,
67
- "expectedChecksum": "fd17de6fb356a5e0c1c67ae7f4adfa08",
68
- "expectedChecksumSHA256": "9c6da9eea98ee85b16b6e0c5075d1c757aaa252526470fbe63cfb915e3585361",
69
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v3.4.10",
70
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.10"
65
+ "version": "3.4.11",
66
+ "expectedSize": 30587970,
67
+ "expectedChecksum": "ab0a05b2441ebdda9e04dc8d4dfd3118",
68
+ "expectedChecksumSHA256": "f22fa6b588644f112def735591f43f05b8864e5c2c2f2aff4a4e00c435f9f101",
69
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v3.4.11",
70
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.11"
71
71
  },
72
72
  "win32": {
73
- "version": "3.4.10",
74
- "expectedSize": 32479744,
75
- "expectedChecksum": "3ed78e5d74da96e89f385a64fa6151fc",
76
- "expectedChecksumSHA256": "bc4bb887b5adbba5b916fa41a091f544aac70f35d5209c483fac90f89abb2c93",
77
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v3.4.10",
78
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.10.exe"
73
+ "version": "3.4.11",
74
+ "expectedSize": 32483840,
75
+ "expectedChecksum": "211210d49b7595e229a2552f56c1d9d3",
76
+ "expectedChecksumSHA256": "dd88350a2f4fd77ccdc8dcf4b465edc6be08609d7c79a195a57febd9b31db6cd",
77
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v3.4.11",
78
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.11.exe"
79
79
  },
80
80
  "linux": {
81
- "version": "3.4.10",
82
- "expectedSize": 31592632,
83
- "expectedChecksum": "a003103017717ddc4ea9967d5820ea51",
84
- "expectedChecksumSHA256": "50b22fdaf7bf1c30b5f331ef07a7f19c51309ca9c9897be426e86254e02b514c",
85
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v3.4.10",
86
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.10"
81
+ "version": "3.4.11",
82
+ "expectedSize": 31600824,
83
+ "expectedChecksum": "73385ff19e1324724d01ad1577552fdd",
84
+ "expectedChecksumSHA256": "28870bff742c78221e7be4940d993189c56fc26f50fc2cc17afcf062c84dc439",
85
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v3.4.11",
86
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.11"
87
87
  }
88
88
  }
89
89
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FunctionsEmulatorShell = void 0;
4
- const uuid = require("uuid");
4
+ const crypto_1 = require("crypto");
5
5
  const utils = require("../utils");
6
6
  const functionsEmulator_1 = require("./functionsEmulator");
7
7
  const logger_1 = require("../logger");
@@ -26,7 +26,7 @@ class FunctionsEmulatorShell {
26
26
  resource = resource.name;
27
27
  }
28
28
  return {
29
- eventId: uuid.v4(),
29
+ eventId: (0, crypto_1.randomUUID)(),
30
30
  timestamp: new Date().toISOString(),
31
31
  eventType: eventTrigger.eventType,
32
32
  resource: resource,
@@ -39,7 +39,7 @@ class FunctionsEmulatorShell {
39
39
  const ce = {
40
40
  specversion: "1.0",
41
41
  datacontenttype: "application/json",
42
- id: uuid.v4(),
42
+ id: (0, crypto_1.randomUUID)(),
43
43
  type: eventTrigger.eventType,
44
44
  time: new Date().toISOString(),
45
45
  source: "",
@@ -50,7 +50,7 @@ class FunctionsEmulatorShell {
50
50
  }
51
51
  else if (eventTrigger.eventType.startsWith("google.cloud.pubsub")) {
52
52
  ce.source = eventTrigger.eventFilters.topic;
53
- data = { ...data, messageId: uuid.v4() };
53
+ data = { ...data, messageId: (0, crypto_1.randomUUID)() };
54
54
  }
55
55
  else if (eventTrigger.eventType.startsWith("google.cloud.firestore")) {
56
56
  ce.source = `projects/_/databases/(default)`;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RuntimeWorkerPool = exports.RuntimeWorker = exports.RuntimeWorkerState = void 0;
4
4
  const http = require("http");
5
- const uuid = require("uuid");
5
+ const crypto_1 = require("crypto");
6
6
  const types_1 = require("./types");
7
7
  const events_1 = require("events");
8
8
  const emulatorLogger_1 = require("./emulatorLogger");
@@ -26,7 +26,7 @@ class RuntimeWorker {
26
26
  this.stateEvents = new events_1.EventEmitter();
27
27
  this.logListeners = [];
28
28
  this._state = RuntimeWorkerState.CREATED;
29
- this.id = uuid.v4();
29
+ this.id = (0, crypto_1.randomUUID)();
30
30
  this.triggerKey = triggerId || FREE_WORKER_KEY;
31
31
  this.runtime = runtime;
32
32
  const childProc = this.runtime.process;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PubsubEmulator = void 0;
4
- const uuid = require("uuid");
4
+ const crypto_1 = require("crypto");
5
5
  const pubsub_1 = require("@google-cloud/pubsub");
6
6
  const downloadableEmulators = require("./downloadableEmulators");
7
7
  const emulatorLogger_1 = require("./emulatorLogger");
@@ -117,7 +117,7 @@ class PubsubEmulator {
117
117
  createLegacyEventRequestBody(topic, message) {
118
118
  return {
119
119
  context: {
120
- eventId: uuid.v4(),
120
+ eventId: (0, crypto_1.randomUUID)(),
121
121
  resource: {
122
122
  service: "pubsub.googleapis.com",
123
123
  name: `projects/${this.args.projectId}/topics/${topic}`,
@@ -147,7 +147,7 @@ class PubsubEmulator {
147
147
  };
148
148
  return {
149
149
  specversion: "1.0",
150
- id: uuid.v4(),
150
+ id: (0, crypto_1.randomUUID)(),
151
151
  time: truncatedPublishTime,
152
152
  type: "google.cloud.pubsub.topic.v1.messagePublished",
153
153
  source: `//pubsub.googleapis.com/projects/${this.args.projectId}/topics/${topic}`,
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createFirebaseEndpoints = createFirebaseEndpoints;
4
4
  const emulatorLogger_1 = require("../../emulatorLogger");
5
5
  const types_1 = require("../../types");
6
- const uuid = require("uuid");
6
+ const crypto_1 = require("crypto");
7
7
  const metadata_1 = require("../metadata");
8
8
  const express_1 = require("express");
9
9
  const shared_1 = require("./shared");
@@ -157,7 +157,7 @@ function createFirebaseEndpoints(emulator) {
157
157
  if (!upload.metadata?.metadata?.firebaseStorageDownloadTokens) {
158
158
  const customMetadata = {
159
159
  ...(upload.metadata?.metadata || {}),
160
- firebaseStorageDownloadTokens: uuid.v4(),
160
+ firebaseStorageDownloadTokens: (0, crypto_1.randomUUID)(),
161
161
  };
162
162
  upload.metadata = { ...(upload.metadata || {}), metadata: customMetadata };
163
163
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StorageCloudFunctions = void 0;
4
- const uuid = require("uuid");
4
+ const crypto_1 = require("crypto");
5
5
  const registry_1 = require("../registry");
6
6
  const types_1 = require("../types");
7
7
  const emulatorLogger_1 = require("../emulatorLogger");
@@ -77,7 +77,7 @@ class StorageCloudFunctions {
77
77
  }
78
78
  return {
79
79
  specversion: "1.0",
80
- id: uuid.v4(),
80
+ id: (0, crypto_1.randomUUID)(),
81
81
  type: `google.cloud.storage.object.v1.${ceAction}`,
82
82
  source: `//storage.googleapis.com/projects/_/buckets/${objectMetadataPayload.bucket}/objects/${objectMetadataPayload.name}`,
83
83
  time,
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CloudStorageObjectMetadata = exports.CloudStorageObjectAccessControlMetadata = exports.CloudStorageBucketMetadata = exports.OutgoingFirebaseMetadata = exports.StoredFileMetadata = void 0;
4
4
  exports.toSerializedDate = toSerializedDate;
5
- const uuid = require("uuid");
6
5
  const crypto = require("crypto");
7
6
  const registry_1 = require("../registry");
8
7
  const types_1 = require("../types");
@@ -185,7 +184,7 @@ class StoredFileMetadata {
185
184
  }
186
185
  }
187
186
  addDownloadToken(shouldTrigger = true) {
188
- this.downloadTokens = [...(this.downloadTokens || []), uuid.v4()];
187
+ this.downloadTokens = [...(this.downloadTokens || []), crypto.randomUUID()];
189
188
  this.update({}, shouldTrigger);
190
189
  }
191
190
  deleteDownloadToken(token) {
@@ -6,7 +6,7 @@ const promises_1 = require("node:fs/promises");
6
6
  const fs = require("fs");
7
7
  const fse = require("fs-extra");
8
8
  const path = require("path");
9
- const uuid = require("uuid");
9
+ const crypto_1 = require("crypto");
10
10
  class Persistence {
11
11
  constructor(dirPath) {
12
12
  this._diskPathMap = new Map();
@@ -78,7 +78,7 @@ class Persistence {
78
78
  fse.copyFileSync(sourcePath, this.getDiskPath(newName));
79
79
  }
80
80
  generateNewDiskName() {
81
- return uuid.v4();
81
+ return (0, crypto_1.randomUUID)();
82
82
  }
83
83
  }
84
84
  exports.Persistence = Persistence;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UploadService = exports.NotCancellableError = exports.UploadPreviouslyFinalizedError = exports.UploadNotActiveError = exports.UploadStatus = exports.UploadType = void 0;
4
- const uuid_1 = require("uuid");
4
+ const crypto_1 = require("crypto");
5
5
  const errors_1 = require("./errors");
6
6
  var UploadType;
7
7
  (function (UploadType) {
@@ -58,7 +58,7 @@ class UploadService {
58
58
  return upload;
59
59
  }
60
60
  startOneShotUpload(request) {
61
- const id = (0, uuid_1.v4)();
61
+ const id = (0, crypto_1.randomUUID)();
62
62
  const upload = {
63
63
  id,
64
64
  bucketId: request.bucketId,
@@ -74,7 +74,7 @@ class UploadService {
74
74
  return upload;
75
75
  }
76
76
  startResumableUpload(request) {
77
- const id = (0, uuid_1.v4)();
77
+ const id = (0, crypto_1.randomUUID)();
78
78
  const upload = {
79
79
  id: id,
80
80
  bucketId: request.bucketId,
package/lib/env.js CHANGED
@@ -22,23 +22,39 @@ function setFirebaseMcp(value) {
22
22
  isFirebaseMcpFlag = value;
23
23
  }
24
24
  function detectAIAgent() {
25
+ if (process.env.AI_AGENT) {
26
+ return process.env.AI_AGENT.trim();
27
+ }
25
28
  if (process.env.ANTIGRAVITY_AGENT)
26
29
  return "antigravity";
27
- if (process.env.CLAUDECODE)
30
+ if (process.env.CLAUDECODE || process.env.CLAUDE_CODE)
28
31
  return "claude_code";
29
32
  if (process.env.CLINE_ACTIVE)
30
33
  return "cline";
31
- if (process.env.CODEX_SANDBOX)
34
+ if (process.env.CODEX_SANDBOX || process.env.CODEX_CI || process.env.CODEX_THREAD_ID) {
32
35
  return "codex_cli";
33
- if (process.env.CURSOR_AGENT)
36
+ }
37
+ if (process.env.CURSOR_AGENT ||
38
+ process.env.CURSOR_TRACE_ID ||
39
+ process.env.CURSOR_EXTENSION_HOST_ROLE === "agent-exec") {
34
40
  return "cursor";
41
+ }
35
42
  if (process.env.GEMINI_CLI)
36
43
  return "gemini_cli";
37
- if (process.env.OPENCODE)
44
+ if (process.env.OPENCODE || process.env.OPENCODE_CLIENT)
38
45
  return "open_code";
39
46
  if (process.env.ANDROID_STUDIO_AGENT)
40
47
  return "android_studio_agent";
41
48
  if (process.env.KIRO_AGENT_PATH)
42
49
  return "kiro";
50
+ if (process.env.COPILOT_MODEL ||
51
+ process.env.COPILOT_ALLOW_ALL ||
52
+ process.env.COPILOT_GITHUB_TOKEN) {
53
+ return "github_copilot";
54
+ }
55
+ if (process.env.REPL_ID)
56
+ return "replit";
57
+ if (process.env.AUGMENT_AGENT)
58
+ return "augment";
43
59
  return "unknown";
44
60
  }
@@ -9,7 +9,6 @@ exports.enableExperimentsFromCliEnvVariable = enableExperimentsFromCliEnvVariabl
9
9
  exports.assertEnabled = assertEnabled;
10
10
  exports.flushToDisk = flushToDisk;
11
11
  const colorette_1 = require("colorette");
12
- const leven = require("leven");
13
12
  const path_1 = require("path");
14
13
  const configstore_1 = require("./configstore");
15
14
  const error_1 = require("./error");
@@ -195,7 +194,7 @@ function experimentNameAutocorrect(malformed) {
195
194
  if (isValidExperiment(malformed)) {
196
195
  throw new error_1.FirebaseError("Assertion failed: experimentNameAutocorrect given actual experiment name", { exit: 2 });
197
196
  }
198
- return Object.keys(exports.ALL_EXPERIMENTS).filter((name) => leven(name, malformed) < malformed.length * 0.4);
197
+ return Object.keys(exports.ALL_EXPERIMENTS).filter((name) => (0, utils_1.stringDistance)(name, malformed) < malformed.length * 0.4);
199
198
  }
200
199
  let localPreferencesCache = undefined;
201
200
  function localPreferences() {
@@ -45,8 +45,9 @@ function init(setup, config) {
45
45
  return Promise.resolve();
46
46
  }
47
47
  async function build(dir, configuration) {
48
- const { targets, serveOptimizedImages, locales, baseHref: baseUrl, ssr, } = await (0, utils_2.getBuildConfig)(dir, configuration);
48
+ const { targets, serveOptimizedImages, locales, baseHref: baseUrl, ssr, buildTargetOptions, } = await (0, utils_2.getBuildConfig)(dir, configuration);
49
49
  await (0, utils_1.warnIfCustomBuildScript)(dir, exports.name, DEFAULT_BUILD_SCRIPT);
50
+ await (0, utils_2.maybeWarnAngular22SsrSecurity)(dir, { ssr, buildTargetOptions });
50
51
  for (const target of targets) {
51
52
  const cli = (0, utils_1.getNodeModuleBin)("ng", dir);
52
53
  const result = (0, cross_spawn_1.sync)(cli, ["run", target], {
@@ -145,7 +146,7 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir, configuration) {
145
146
  if (bundleDependencies) {
146
147
  const dependencies = {};
147
148
  for (const externalDependency of externalDependencies) {
148
- const packageVersion = (0, utils_1.findDependency)(externalDependency)?.version;
149
+ const packageVersion = (0, utils_1.findDependency)(externalDependency, { cwd: sourceDir })?.version;
149
150
  if (packageVersion) {
150
151
  dependencies[externalDependency] = packageVersion;
151
152
  }