firebase-tools 14.22.0 → 14.24.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 (35) hide show
  1. package/README.md +13 -5
  2. package/lib/apiv2.js +12 -2
  3. package/lib/appUtils.js +32 -13
  4. package/lib/appdistribution/client.js +62 -16
  5. package/lib/appdistribution/types.js +1 -12
  6. package/lib/appdistribution/yaml_helper.js +69 -0
  7. package/lib/commands/appdistribution-groups-list.js +3 -5
  8. package/lib/commands/appdistribution-testcases-export.js +32 -0
  9. package/lib/commands/appdistribution-testcases-import.js +34 -0
  10. package/lib/commands/appdistribution-testers-list.js +3 -5
  11. package/lib/commands/dataconnect-sdk-generate.js +3 -2
  12. package/lib/commands/index.js +8 -5
  13. package/lib/commands/init.js +5 -7
  14. package/lib/deploy/functions/services/dataconnect.js +14 -0
  15. package/lib/deploy/functions/services/index.js +11 -0
  16. package/lib/emulator/auth/operations.js +7 -1
  17. package/lib/emulator/downloadableEmulatorInfo.json +33 -25
  18. package/lib/emulator/downloadableEmulators.js +59 -47
  19. package/lib/emulator/functionsEmulatorRuntime.js +8 -0
  20. package/lib/emulator/taskQueue.js +5 -0
  21. package/lib/experiments.js +0 -6
  22. package/lib/firestore/api.js +22 -4
  23. package/lib/functions/events/v2.js +2 -1
  24. package/lib/init/features/dataconnect/sdk.js +18 -0
  25. package/lib/init/features/hosting/github.js +6 -6
  26. package/lib/init/features/hosting/index.js +37 -37
  27. package/lib/management/provisioning/errorHandler.js +54 -0
  28. package/lib/management/provisioning/provision.js +2 -5
  29. package/lib/mcp/tools/crashlytics/events.js +92 -9
  30. package/lib/mcp/tools/functions/index.js +2 -1
  31. package/lib/mcp/tools/functions/list_functions.js +48 -0
  32. package/lib/utils.js +4 -1
  33. package/package.json +2 -2
  34. package/schema/connector-yaml.json +30 -0
  35. package/schema/firebase-config.json +0 -1
@@ -44,38 +44,46 @@
44
44
  }
45
45
  },
46
46
  "pubsub": {
47
- "version": "0.8.14",
48
- "expectedSize": 66786933,
49
- "expectedChecksum": "a9025b3e53fdeafd2969ccb3ba1e1d38",
50
- "expectedChecksumSHA256": "4fbeefd8ecb32b10e5ab522e5d8748e0c2b13891c471c0c327c04632dcc75a8d",
51
- "remoteUrl": "https://storage.googleapis.com/firebase-preview-drop/emulator/pubsub-emulator-0.8.14.zip",
52
- "downloadPathRelativeToCacheDir": "pubsub-emulator-0.8.14.zip",
53
- "binaryPathRelativeToCacheDir": "pubsub-emulator-0.8.14/pubsub-emulator/bin/cloud-pubsub-emulator"
47
+ "version": "0.8.17",
48
+ "expectedSize": 65162324,
49
+ "expectedChecksum": "a88ec6424e49af459b5c8a3657d69c06",
50
+ "expectedChecksumSHA256": "72a49d14ee6cd4c1a0fee4a46f520fe4d7465396a155c61abc0103905047edd3",
51
+ "remoteUrl": "https://storage.googleapis.com/firebase-preview-drop/emulator/pubsub-emulator-0.8.17.zip",
52
+ "downloadPathRelativeToCacheDir": "pubsub-emulator-0.8.17.zip",
53
+ "binaryPathRelativeToCacheDir": "pubsub-emulator-0.8.17/pubsub-emulator/bin/cloud-pubsub-emulator"
54
54
  },
55
55
  "dataconnect": {
56
56
  "darwin": {
57
- "version": "2.15.1",
58
- "expectedSize": 29946720,
59
- "expectedChecksum": "cc8d5dd053cc71adad0f640ac2627018",
60
- "expectedChecksumSHA256": "a3749396507678bc546987ef047a9d0c25145064503a9adc777229f1bc9b8c6f",
61
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-v2.15.1",
62
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.15.1"
57
+ "version": "2.17.0",
58
+ "expectedSize": 29983584,
59
+ "expectedChecksum": "d9a3a5bd575dc24185ad473a440c4738",
60
+ "expectedChecksumSHA256": "da5485e68c7adbf86e3fb2f9ca550e4619f55ae75845009837780fcf16dd05cc",
61
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v2.17.0",
62
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.17.0"
63
+ },
64
+ "darwin_arm64": {
65
+ "version": "2.17.0",
66
+ "expectedSize": 29459746,
67
+ "expectedChecksum": "8362a56419a66507b1aead4630b9033c",
68
+ "expectedChecksumSHA256": "cbb8a3030f69c5aba81d1ef2d64d249f18100915f9738f59b815004b27983dab",
69
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v2.17.0",
70
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.17.0"
63
71
  },
64
72
  "win32": {
65
- "version": "2.15.1",
66
- "expectedSize": 30440960,
67
- "expectedChecksum": "57390c392101a13952ff2aea74b62787",
68
- "expectedChecksumSHA256": "905a9ab2200189dc31f23b5454d21803b0c672442f0ee4bb7db8286d159a86e0",
69
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-v2.15.1",
70
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.15.1.exe"
73
+ "version": "2.17.0",
74
+ "expectedSize": 30477824,
75
+ "expectedChecksum": "7d8434eee4f3d33cc8ec6c99c6056a77",
76
+ "expectedChecksumSHA256": "051c60be0651be4971409da7ab3a15cdfb693400e9293c89010edcb28016d061",
77
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v2.17.0",
78
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.17.0.exe"
71
79
  },
72
80
  "linux": {
73
- "version": "2.15.1",
74
- "expectedSize": 29868216,
75
- "expectedChecksum": "cc6ef676d8c5c3a3f74c0bf037083cf0",
76
- "expectedChecksumSHA256": "1dfe085c467637ebf6a71cc6c8e8bc11fac85202056b960633607627bd647a6d",
77
- "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v2.15.1",
78
- "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.15.1"
81
+ "version": "2.17.0",
82
+ "expectedSize": 29905080,
83
+ "expectedChecksum": "ca7003aaee41e3c1261f9655c5f9dd8a",
84
+ "expectedChecksumSHA256": "79efd09f1bd685cbfa0157b2d08e0f6eb085ed82d83b48fabb7d102db6636c6c",
85
+ "remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v2.17.0",
86
+ "downloadPathRelativeToCacheDir": "dataconnect-emulator-2.17.0"
79
87
  }
80
88
  }
81
89
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isIncomaptibleArchError = exports.start = exports.downloadIfNecessary = exports.stop = exports.getPID = exports.get = exports.getDownloadDetails = exports.requiresJava = exports.handleEmulatorProcessError = exports._getCommand = exports.getLogFileName = exports.DownloadDetails = void 0;
3
+ exports.isIncomaptibleArchError = exports.start = exports.downloadIfNecessary = exports.stop = exports.getPID = exports.get = exports.getDownloadDetails = exports.requiresJava = exports.handleEmulatorProcessError = exports._getCommand = exports.getLogFileName = void 0;
4
4
  const lsofi = require("lsofi");
5
5
  const types_1 = require("./types");
6
6
  const constants_1 = require("./constants");
@@ -20,51 +20,63 @@ const emulatorUpdateDetails = require("./downloadableEmulatorInfo.json");
20
20
  const EMULATOR_INSTANCE_KILL_TIMEOUT = 4000;
21
21
  const CACHE_DIR = process.env.FIREBASE_EMULATORS_PATH || path.join(os.homedir(), ".cache", "firebase", "emulators");
22
22
  const EMULATOR_UPDATE_DETAILS = emulatorUpdateDetails;
23
- const emulatorUiDetails = experiments.isEnabled("emulatoruisnapshot")
24
- ? EMULATOR_UPDATE_DETAILS.ui.snapshot
25
- : EMULATOR_UPDATE_DETAILS.ui.main;
26
- const dataconnectDetails = process.platform === "darwin"
27
- ? EMULATOR_UPDATE_DETAILS.dataconnect.darwin
28
- : process.platform === "win32"
29
- ? EMULATOR_UPDATE_DETAILS.dataconnect.win32
30
- : EMULATOR_UPDATE_DETAILS.dataconnect.linux;
31
- exports.DownloadDetails = {
32
- database: {
33
- downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.database.downloadPathRelativeToCacheDir),
34
- version: EMULATOR_UPDATE_DETAILS.database.version,
35
- opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.database), { cacheDir: CACHE_DIR, namePrefix: "firebase-database-emulator" }),
36
- },
37
- firestore: {
38
- downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.firestore.downloadPathRelativeToCacheDir),
39
- version: EMULATOR_UPDATE_DETAILS.firestore.version,
40
- opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.firestore), { cacheDir: CACHE_DIR, namePrefix: "cloud-firestore-emulator" }),
41
- },
42
- storage: {
43
- downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.storage.downloadPathRelativeToCacheDir),
44
- version: EMULATOR_UPDATE_DETAILS.storage.version,
45
- opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.storage), { cacheDir: CACHE_DIR, namePrefix: "cloud-storage-rules-emulator" }),
46
- },
47
- ui: {
48
- version: emulatorUiDetails.version,
49
- downloadPath: path.join(CACHE_DIR, emulatorUiDetails.downloadPathRelativeToCacheDir),
50
- unzipDir: path.join(CACHE_DIR, `ui-v${emulatorUiDetails.version}`),
51
- binaryPath: path.join(CACHE_DIR, emulatorUiDetails.binaryPathRelativeToCacheDir),
52
- opts: Object.assign(Object.assign({}, emulatorUiDetails), { cacheDir: CACHE_DIR, skipCache: experiments.isEnabled("emulatoruisnapshot"), skipChecksumAndSize: experiments.isEnabled("emulatoruisnapshot"), namePrefix: "ui" }),
53
- },
54
- pubsub: {
55
- downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.pubsub.downloadPathRelativeToCacheDir),
56
- version: EMULATOR_UPDATE_DETAILS.pubsub.version,
57
- unzipDir: path.join(CACHE_DIR, `pubsub-emulator-${EMULATOR_UPDATE_DETAILS.pubsub.version}`),
58
- binaryPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.pubsub.binaryPathRelativeToCacheDir),
59
- opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.pubsub), { cacheDir: CACHE_DIR, namePrefix: "pubsub-emulator" }),
60
- },
61
- dataconnect: {
62
- downloadPath: path.join(CACHE_DIR, dataconnectDetails.downloadPathRelativeToCacheDir),
63
- version: dataconnectDetails.version,
64
- binaryPath: path.join(CACHE_DIR, dataconnectDetails.downloadPathRelativeToCacheDir),
65
- opts: Object.assign(Object.assign({}, dataconnectDetails), { cacheDir: CACHE_DIR, skipChecksumAndSize: false, namePrefix: "dataconnect-emulator", auth: false }),
66
- },
67
- };
23
+ function generateDownloadDetails(emulator) {
24
+ const emulatorUiDetails = experiments.isEnabled("emulatoruisnapshot")
25
+ ? EMULATOR_UPDATE_DETAILS.ui.snapshot
26
+ : EMULATOR_UPDATE_DETAILS.ui.main;
27
+ const dataconnectDetails = process.platform === "darwin"
28
+ ? process.arch === "arm64"
29
+ ? EMULATOR_UPDATE_DETAILS.dataconnect.darwin_arm64
30
+ : EMULATOR_UPDATE_DETAILS.dataconnect.darwin
31
+ : process.platform === "win32"
32
+ ? EMULATOR_UPDATE_DETAILS.dataconnect.win32
33
+ : EMULATOR_UPDATE_DETAILS.dataconnect.linux;
34
+ switch (emulator) {
35
+ case "database":
36
+ return {
37
+ downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.database.downloadPathRelativeToCacheDir),
38
+ version: EMULATOR_UPDATE_DETAILS.database.version,
39
+ opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.database), { cacheDir: CACHE_DIR, namePrefix: "firebase-database-emulator" }),
40
+ };
41
+ case "firestore":
42
+ return {
43
+ downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.firestore.downloadPathRelativeToCacheDir),
44
+ version: EMULATOR_UPDATE_DETAILS.firestore.version,
45
+ opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.firestore), { cacheDir: CACHE_DIR, namePrefix: "cloud-firestore-emulator" }),
46
+ };
47
+ case "storage":
48
+ return {
49
+ downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.storage.downloadPathRelativeToCacheDir),
50
+ version: EMULATOR_UPDATE_DETAILS.storage.version,
51
+ opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.storage), { cacheDir: CACHE_DIR, namePrefix: "cloud-storage-rules-emulator" }),
52
+ };
53
+ case "ui":
54
+ return {
55
+ version: emulatorUiDetails.version,
56
+ downloadPath: path.join(CACHE_DIR, emulatorUiDetails.downloadPathRelativeToCacheDir),
57
+ unzipDir: path.join(CACHE_DIR, `ui-v${emulatorUiDetails.version}`),
58
+ binaryPath: path.join(CACHE_DIR, emulatorUiDetails.binaryPathRelativeToCacheDir),
59
+ opts: Object.assign(Object.assign({}, emulatorUiDetails), { cacheDir: CACHE_DIR, skipCache: experiments.isEnabled("emulatoruisnapshot"), skipChecksumAndSize: experiments.isEnabled("emulatoruisnapshot"), namePrefix: "ui" }),
60
+ };
61
+ case "pubsub":
62
+ return {
63
+ downloadPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.pubsub.downloadPathRelativeToCacheDir),
64
+ version: EMULATOR_UPDATE_DETAILS.pubsub.version,
65
+ unzipDir: path.join(CACHE_DIR, `pubsub-emulator-${EMULATOR_UPDATE_DETAILS.pubsub.version}`),
66
+ binaryPath: path.join(CACHE_DIR, EMULATOR_UPDATE_DETAILS.pubsub.binaryPathRelativeToCacheDir),
67
+ opts: Object.assign(Object.assign({}, EMULATOR_UPDATE_DETAILS.pubsub), { cacheDir: CACHE_DIR, namePrefix: "pubsub-emulator" }),
68
+ };
69
+ case "dataconnect":
70
+ return {
71
+ downloadPath: path.join(CACHE_DIR, dataconnectDetails.downloadPathRelativeToCacheDir),
72
+ version: dataconnectDetails.version,
73
+ binaryPath: path.join(CACHE_DIR, dataconnectDetails.downloadPathRelativeToCacheDir),
74
+ opts: Object.assign(Object.assign({}, dataconnectDetails), { cacheDir: CACHE_DIR, skipChecksumAndSize: false, namePrefix: "dataconnect-emulator", auth: false }),
75
+ };
76
+ default:
77
+ throw new Error(`Invalid downloadable emulator: ${emulator}`);
78
+ }
79
+ }
68
80
  const EmulatorDetails = {
69
81
  database: {
70
82
  name: types_1.Emulators.DATABASE,
@@ -318,7 +330,7 @@ async function _runBinary(emulator, command, extraEnv) {
318
330
  });
319
331
  }
320
332
  function getDownloadDetails(emulator) {
321
- const details = exports.DownloadDetails[emulator];
333
+ const details = generateDownloadDetails(emulator);
322
334
  const pathOverride = process.env[`${emulator.toUpperCase()}_EMULATOR_BINARY_PATH`];
323
335
  if (pathOverride) {
324
336
  const logger = emulatorLogger_1.EmulatorLogger.forEmulator(emulator);
@@ -240,6 +240,10 @@ function initializeNetworkFiltering() {
240
240
  }
241
241
  async function initializeFirebaseFunctionsStubs() {
242
242
  const firebaseFunctionsResolution = await assertResolveDeveloperNodeModule("firebase-functions");
243
+ if ((0, functionsEmulatorUtils_1.compareVersionStrings)(firebaseFunctionsResolution.version, "7.0.0") >= 0) {
244
+ logDebug("Detected firebase-functions v7+, skipping legacy stubs.");
245
+ return;
246
+ }
243
247
  const firebaseFunctionsRoot = (0, functionsEmulatorShared_1.findModuleRoot)("firebase-functions", firebaseFunctionsResolution.resolution);
244
248
  const httpsProviderResolution = path.join(firebaseFunctionsRoot, "lib/providers/https");
245
249
  const httpsProviderV1Resolution = path.join(firebaseFunctionsRoot, "lib/v1/providers/https");
@@ -451,6 +455,10 @@ function warnAboutStorageProd() {
451
455
  }
452
456
  async function initializeFunctionsConfigHelper() {
453
457
  const functionsResolution = await assertResolveDeveloperNodeModule("firebase-functions");
458
+ if ((0, functionsEmulatorUtils_1.compareVersionStrings)(functionsResolution.version, "7.0.0") >= 0) {
459
+ logDebug("Detected firebase-functions v7+, skipping config helper.");
460
+ return;
461
+ }
454
462
  const localFunctionsModule = require(functionsResolution.resolution);
455
463
  logDebug("Checked functions.config()", {
456
464
  config: localFunctionsModule.config(),
@@ -4,6 +4,7 @@ exports.TaskQueue = exports.TaskStatus = exports.Queue = void 0;
4
4
  const abort_controller_1 = require("abort-controller");
5
5
  const emulatorLogger_1 = require("./emulatorLogger");
6
6
  const types_1 = require("./types");
7
+ const error_1 = require("../error");
7
8
  const node_fetch_1 = require("node-fetch");
8
9
  class Node {
9
10
  constructor(data) {
@@ -198,6 +199,10 @@ class TaskQueue {
198
199
  }
199
200
  const controller = new abort_controller_1.default();
200
201
  const signal = controller.signal;
202
+ signal.reason = "";
203
+ signal.throwIfAborted = () => {
204
+ throw new error_1.FirebaseError("Aborted");
205
+ };
201
206
  const request = (0, node_fetch_1.default)(emulatedTask.task.httpRequest.url, {
202
207
  method: "POST",
203
208
  headers: headers,
@@ -118,12 +118,6 @@ exports.ALL_EXPERIMENTS = experiments({
118
118
  shortDescription: "Adds experimental App Testing feature",
119
119
  public: true,
120
120
  },
121
- ailogic: {
122
- shortDescription: "Enable Firebase AI Logic feature for existing apps",
123
- fullDescription: "Enables the AI Logic initialization feature that provisions AI Logic for existing Firebase apps.",
124
- public: true,
125
- default: false,
126
- },
127
121
  });
128
122
  function isValidExperiment(name) {
129
123
  return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
@@ -22,16 +22,34 @@ class FirestoreApi {
22
22
  this.printer = new pretty_print_1.PrettyPrint();
23
23
  }
24
24
  static processIndex(index) {
25
- var _a, _b, _c;
26
- const fields = index.fields;
25
+ var _a;
26
+ let fields = index.fields;
27
+ const suffixOrder = FirestoreApi.lastIndexFieldOrder(fields);
28
+ const nameSuffix = { fieldPath: "__name__", order: suffixOrder };
27
29
  const lastField = (_a = index.fields) === null || _a === void 0 ? void 0 : _a[index.fields.length - 1];
30
+ if (lastField.vectorConfig) {
31
+ const vectorField = lastField;
32
+ fields = fields.slice(0, -1);
33
+ if (fields.length === 0 || (fields === null || fields === void 0 ? void 0 : fields[fields.length - 1].fieldPath) !== "__name__") {
34
+ fields.push(nameSuffix);
35
+ }
36
+ fields.push(vectorField);
37
+ return Object.assign(Object.assign({}, index), { fields });
38
+ }
28
39
  if ((lastField === null || lastField === void 0 ? void 0 : lastField.fieldPath) !== "__name__") {
29
- const defaultDirection = (_c = (_b = index.fields) === null || _b === void 0 ? void 0 : _b[index.fields.length - 1]) === null || _c === void 0 ? void 0 : _c.order;
30
- const nameSuffix = { fieldPath: "__name__", order: defaultDirection };
31
40
  fields.push(nameSuffix);
32
41
  }
33
42
  return Object.assign(Object.assign({}, index), { fields });
34
43
  }
44
+ static lastIndexFieldOrder(fields) {
45
+ let lastIndexFieldOrder = types.Order.ASCENDING;
46
+ for (const field of fields) {
47
+ if (field.order) {
48
+ lastIndexFieldOrder = field.order;
49
+ }
50
+ }
51
+ return lastIndexFieldOrder;
52
+ }
35
53
  async deploy(options, indexes, fieldOverrides, databaseId = "(default)") {
36
54
  var _a;
37
55
  const spec = this.upgradeOldSpec({
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONVERTABLE_EVENTS = exports.FIREALERTS_EVENT = exports.FIRESTORE_EVENTS = exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
3
+ exports.CONVERTABLE_EVENTS = exports.DATACONNECT_EVENT = exports.FIREALERTS_EVENT = exports.FIRESTORE_EVENTS = exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
4
4
  exports.PUBSUB_PUBLISH_EVENT = "google.cloud.pubsub.topic.v1.messagePublished";
5
5
  exports.STORAGE_EVENTS = [
6
6
  "google.cloud.storage.object.v1.finalized",
@@ -28,6 +28,7 @@ exports.FIRESTORE_EVENTS = [
28
28
  "google.cloud.firestore.document.v1.deleted.withAuthContext",
29
29
  ];
30
30
  exports.FIREALERTS_EVENT = "google.firebase.firebasealerts.alerts.v1.published";
31
+ exports.DATACONNECT_EVENT = "google.firebase.dataconnect.connector.v1.mutationExecuted";
31
32
  exports.CONVERTABLE_EVENTS = {
32
33
  "google.cloud.firestore.document.v1.created": "google.cloud.firestore.document.v1.created.withAuthContext",
33
34
  "google.cloud.firestore.document.v1.updated": "google.cloud.firestore.document.v1.updated.withAuthContext",
@@ -145,9 +145,13 @@ function initAppCounters(info) {
145
145
  num_android_apps: 0,
146
146
  num_ios_apps: 0,
147
147
  num_flutter_apps: 0,
148
+ num_admin_node_apps: 0,
148
149
  };
149
150
  for (const app of (_a = info.apps) !== null && _a !== void 0 ? _a : []) {
150
151
  switch (app.platform) {
152
+ case appUtils_1.Platform.ADMIN_NODE:
153
+ counts.num_admin_node_apps++;
154
+ break;
151
155
  case appUtils_1.Platform.WEB:
152
156
  counts.num_web_apps++;
153
157
  break;
@@ -246,6 +250,20 @@ function addSdkGenerateToConnectorYaml(connectorInfo, connectorYaml, app) {
246
250
  }
247
251
  const generate = connectorYaml.generate;
248
252
  switch (app.platform) {
253
+ case appUtils_1.Platform.ADMIN_NODE: {
254
+ const adminNodeSdk = {
255
+ outputDir: path.relative(connectorDir, path.join(appDir, `src/dataconnect-admin-generated`)),
256
+ package: `@dataconnect/admin-generated`,
257
+ packageJsonDir: path.relative(connectorDir, appDir),
258
+ };
259
+ if (!(0, lodash_1.isArray)(generate === null || generate === void 0 ? void 0 : generate.adminNodeSdk)) {
260
+ generate.adminNodeSdk = generate.adminNodeSdk ? [generate.adminNodeSdk] : [];
261
+ }
262
+ if (!generate.adminNodeSdk.some((s) => s.outputDir === adminNodeSdk.outputDir)) {
263
+ generate.adminNodeSdk.push(adminNodeSdk);
264
+ }
265
+ break;
266
+ }
249
267
  case appUtils_1.Platform.WEB: {
250
268
  const javascriptSdk = {
251
269
  outputDir: path.relative(connectorDir, path.join(appDir, `src/dataconnect-generated`)),
@@ -29,11 +29,11 @@ const HOSTING_GITHUB_ACTION_NAME = "FirebaseExtended/action-hosting-deploy@v0";
29
29
  const SERVICE_ACCOUNT_MAX_KEY_NUMBER = 10;
30
30
  const githubApiClient = new apiv2_1.Client({ urlPrefix: (0, api_1.githubApiOrigin)(), auth: false });
31
31
  async function initGitHub(setup) {
32
- var _a, _b, _c, _d, _e;
32
+ var _a, _b, _c, _d, _e, _f, _g;
33
33
  if (!setup.projectId) {
34
34
  return (0, utils_1.reject)("Could not determine Project ID, can't set up GitHub workflow.", { exit: 1 });
35
35
  }
36
- if (!setup.config.hosting) {
36
+ if (!setup.config.hosting && !((_a = setup.featureInfo) === null || _a === void 0 ? void 0 : _a.hosting)) {
37
37
  return (0, utils_1.reject)(`Didn't find a Hosting config in firebase.json. Run ${(0, colorette_1.bold)("firebase init hosting")} instead.`);
38
38
  }
39
39
  logger_1.logger.info();
@@ -67,10 +67,10 @@ async function initGitHub(setup) {
67
67
  (0, utils_1.logSuccess)(`Uploaded service account JSON to GitHub as secret ${(0, colorette_1.bold)(githubSecretName)}.`);
68
68
  (0, utils_1.logBullet)(`You can manage your secrets at https://github.com/${repo}/settings/secrets.`);
69
69
  logger_1.logger.info();
70
- if (!Array.isArray(setup.config.hosting) && setup.config.hosting.predeploy) {
70
+ if (!Array.isArray(setup.config.hosting) && ((_b = setup.config.hosting) === null || _b === void 0 ? void 0 : _b.predeploy)) {
71
71
  (0, utils_1.logBullet)(`You have a predeploy script configured in firebase.json.`);
72
72
  }
73
- const { script } = await promptForBuildScript((_a = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _a === void 0 ? void 0 : _a.useWebFrameworks);
73
+ const { script } = await promptForBuildScript((_c = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _c === void 0 ? void 0 : _c.useWebFrameworks);
74
74
  const ymlDeployDoc = loadYMLDeploy();
75
75
  let shouldWriteYMLHostingFile = true;
76
76
  let shouldWriteYMLDeployFile = false;
@@ -81,7 +81,7 @@ async function initGitHub(setup) {
81
81
  shouldWriteYMLHostingFile = overwrite;
82
82
  }
83
83
  if (shouldWriteYMLHostingFile) {
84
- writeChannelActionYMLFile(YML_FULL_PATH_PULL_REQUEST, githubSecretName, setup.projectId, script, (_b = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _b === void 0 ? void 0 : _b.useWebFrameworks, (_c = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _c === void 0 ? void 0 : _c.source);
84
+ writeChannelActionYMLFile(YML_FULL_PATH_PULL_REQUEST, githubSecretName, setup.projectId, script, (_d = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _d === void 0 ? void 0 : _d.useWebFrameworks, (_e = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _e === void 0 ? void 0 : _e.source);
85
85
  logger_1.logger.info();
86
86
  (0, utils_1.logSuccess)(`Created workflow file ${(0, colorette_1.bold)(YML_FULL_PATH_PULL_REQUEST)}`);
87
87
  }
@@ -101,7 +101,7 @@ async function initGitHub(setup) {
101
101
  shouldWriteYMLDeployFile = true;
102
102
  }
103
103
  if (shouldWriteYMLDeployFile) {
104
- writeDeployToProdActionYMLFile(YML_FULL_PATH_MERGE, branch, githubSecretName, setup.projectId, script, (_d = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _d === void 0 ? void 0 : _d.useWebFrameworks, (_e = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _e === void 0 ? void 0 : _e.source);
104
+ writeDeployToProdActionYMLFile(YML_FULL_PATH_MERGE, branch, githubSecretName, setup.projectId, script, (_f = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _f === void 0 ? void 0 : _f.useWebFrameworks, (_g = setup === null || setup === void 0 ? void 0 : setup.hosting) === null || _g === void 0 ? void 0 : _g.source);
105
105
  logger_1.logger.info();
106
106
  (0, utils_1.logSuccess)(`Created workflow file ${(0, colorette_1.bold)(YML_FULL_PATH_MERGE)}`);
107
107
  }
@@ -48,10 +48,10 @@ async function askQuestions(setup, config, options) {
48
48
  setup.featureInfo.hosting.newSiteId = await (0, interactive_1.pickHostingSiteName)("", createOptions);
49
49
  }
50
50
  }
51
+ let discoveredFramework = experiments.isEnabled("webframeworks")
52
+ ? await (0, frameworks_1.discover)(config.projectDir, false)
53
+ : undefined;
51
54
  if (experiments.isEnabled("webframeworks")) {
52
- let discoveredFramework = experiments.isEnabled("webframeworks")
53
- ? await (0, frameworks_1.discover)(config.projectDir, false)
54
- : undefined;
55
55
  if (discoveredFramework &&
56
56
  (await (0, prompt_1.confirm)({
57
57
  message: `Detected an existing ${frameworks_1.WebFrameworks[discoveredFramework.framework].name} codebase in the current directory, do you want to use this?`,
@@ -65,43 +65,43 @@ async function askQuestions(setup, config, options) {
65
65
  else {
66
66
  setup.featureInfo.hosting.useWebFrameworks = await (0, prompt_1.confirm)(`Do you want to use a web framework? (${clc.bold("experimental")})`);
67
67
  }
68
- if (setup.featureInfo.hosting.useWebFrameworks) {
69
- (_a = (_g = setup.featureInfo.hosting).source) !== null && _a !== void 0 ? _a : (_g.source = await (0, prompt_1.input)({
70
- message: "What folder would you like to use for your web application's root directory?",
71
- default: "hosting",
68
+ }
69
+ if (setup.featureInfo.hosting.useWebFrameworks) {
70
+ (_a = (_g = setup.featureInfo.hosting).source) !== null && _a !== void 0 ? _a : (_g.source = await (0, prompt_1.input)({
71
+ message: "What folder would you like to use for your web application's root directory?",
72
+ default: "hosting",
73
+ }));
74
+ discoveredFramework = await (0, frameworks_1.discover)((0, path_1.join)(config.projectDir, setup.featureInfo.hosting.source));
75
+ if (discoveredFramework) {
76
+ const name = frameworks_1.WebFrameworks[discoveredFramework.framework].name;
77
+ (_b = (_h = setup.featureInfo.hosting).useDiscoveredFramework) !== null && _b !== void 0 ? _b : (_h.useDiscoveredFramework = await (0, prompt_1.confirm)({
78
+ message: `Detected an existing ${name} codebase in ${setup.featureInfo.hosting.source}, should we use this?`,
79
+ default: true,
72
80
  }));
73
- discoveredFramework = await (0, frameworks_1.discover)((0, path_1.join)(config.projectDir, setup.featureInfo.hosting.source));
74
- if (discoveredFramework) {
75
- const name = frameworks_1.WebFrameworks[discoveredFramework.framework].name;
76
- (_b = (_h = setup.featureInfo.hosting).useDiscoveredFramework) !== null && _b !== void 0 ? _b : (_h.useDiscoveredFramework = await (0, prompt_1.confirm)({
77
- message: `Detected an existing ${name} codebase in ${setup.featureInfo.hosting.source}, should we use this?`,
78
- default: true,
79
- }));
80
- if (setup.featureInfo.hosting.useDiscoveredFramework)
81
- setup.featureInfo.hosting.webFramework = discoveredFramework.framework;
82
- }
83
- const choices = [];
84
- for (const value in frameworks_1.WebFrameworks) {
85
- if (frameworks_1.WebFrameworks[value]) {
86
- const { name, init } = frameworks_1.WebFrameworks[value];
87
- if (init)
88
- choices.push({ name, value });
89
- }
81
+ if (setup.featureInfo.hosting.useDiscoveredFramework)
82
+ setup.featureInfo.hosting.webFramework = discoveredFramework.framework;
83
+ }
84
+ const choices = [];
85
+ for (const value in frameworks_1.WebFrameworks) {
86
+ if (frameworks_1.WebFrameworks[value]) {
87
+ const { name, init } = frameworks_1.WebFrameworks[value];
88
+ if (init)
89
+ choices.push({ name, value });
90
90
  }
91
- const defaultChoice = (_c = choices.find(({ value }) => value === (discoveredFramework === null || discoveredFramework === void 0 ? void 0 : discoveredFramework.framework))) === null || _c === void 0 ? void 0 : _c.value;
92
- (_d = (_j = setup.featureInfo.hosting).webFramework) !== null && _d !== void 0 ? _d : (_j.webFramework = await (0, prompt_1.select)({
93
- message: "Please choose the framework:",
94
- default: defaultChoice,
95
- choices,
96
- }));
97
- setup.featureInfo.hosting.region =
98
- setup.featureInfo.hosting.region ||
99
- (await (0, prompt_1.select)({
100
- message: "In which region would you like to host server-side content, if applicable?",
101
- default: constants_1.DEFAULT_REGION,
102
- choices: constants_1.ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
103
- }));
104
91
  }
92
+ const defaultChoice = (_c = choices.find(({ value }) => value === (discoveredFramework === null || discoveredFramework === void 0 ? void 0 : discoveredFramework.framework))) === null || _c === void 0 ? void 0 : _c.value;
93
+ (_d = (_j = setup.featureInfo.hosting).webFramework) !== null && _d !== void 0 ? _d : (_j.webFramework = await (0, prompt_1.select)({
94
+ message: "Please choose the framework:",
95
+ default: defaultChoice,
96
+ choices,
97
+ }));
98
+ setup.featureInfo.hosting.region =
99
+ setup.featureInfo.hosting.region ||
100
+ (await (0, prompt_1.select)({
101
+ message: "In which region would you like to host server-side content, if applicable?",
102
+ default: constants_1.DEFAULT_REGION,
103
+ choices: constants_1.ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
104
+ }));
105
105
  }
106
106
  else {
107
107
  logger_1.logger.info();
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enhanceProvisioningError = void 0;
4
+ const error_1 = require("../../error");
5
+ function isErrorInfo(detail) {
6
+ return detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo";
7
+ }
8
+ function isHelpLinks(detail) {
9
+ return detail["@type"] === "type.googleapis.com/google.rpc.Help";
10
+ }
11
+ function extractErrorDetails(err) {
12
+ var _a;
13
+ if (!(err instanceof Error)) {
14
+ return "";
15
+ }
16
+ if (err instanceof error_1.FirebaseError && err.context) {
17
+ const context = err.context;
18
+ const errorBody = (_a = context.body) === null || _a === void 0 ? void 0 : _a.error;
19
+ if ((errorBody === null || errorBody === void 0 ? void 0 : errorBody.details) && Array.isArray(errorBody.details)) {
20
+ const parts = [];
21
+ for (const detail of errorBody.details) {
22
+ if (isErrorInfo(detail)) {
23
+ parts.push(`Error details:`);
24
+ parts.push(` Reason: ${detail.reason}`);
25
+ parts.push(` Domain: ${detail.domain}`);
26
+ if (detail.metadata) {
27
+ parts.push(` Additional Info: ${JSON.stringify(detail.metadata)}`);
28
+ }
29
+ }
30
+ else if (isHelpLinks(detail)) {
31
+ parts.push(`\nFor help resolving this issue:`);
32
+ for (const link of detail.links) {
33
+ parts.push(` - ${link.description}`);
34
+ parts.push(` ${link.url}`);
35
+ }
36
+ }
37
+ }
38
+ return parts.length > 0 ? `\n\n${parts.join("\n")}` : "";
39
+ }
40
+ }
41
+ return "";
42
+ }
43
+ function enhanceProvisioningError(err, contextMessage) {
44
+ const originalError = (0, error_1.getError)(err);
45
+ const errorDetails = extractErrorDetails(err);
46
+ const fullMessage = errorDetails
47
+ ? `${contextMessage}: ${originalError.message}${errorDetails}`
48
+ : `${contextMessage}: ${originalError.message}`;
49
+ return new error_1.FirebaseError(fullMessage, {
50
+ exit: 2,
51
+ original: originalError,
52
+ });
53
+ }
54
+ exports.enhanceProvisioningError = enhanceProvisioningError;
@@ -7,6 +7,7 @@ const error_1 = require("../../error");
7
7
  const logger_1 = require("../../logger");
8
8
  const operation_poller_1 = require("../../operation-poller");
9
9
  const apps_1 = require("../apps");
10
+ const errorHandler_1 = require("./errorHandler");
10
11
  const apiClient = new apiv2_1.Client({
11
12
  urlPrefix: (0, api_1.firebaseApiOrigin)(),
12
13
  apiVersion: "v1alpha",
@@ -100,11 +101,7 @@ async function provisionFirebaseApp(options) {
100
101
  return result;
101
102
  }
102
103
  catch (err) {
103
- const errorMessage = err instanceof Error ? err.message : String(err);
104
- throw new error_1.FirebaseError(`Failed to provision Firebase app: ${errorMessage}`, {
105
- exit: 2,
106
- original: err instanceof Error ? err : new Error(String(err)),
107
- });
104
+ throw (0, errorHandler_1.enhanceProvisioningError)(err, "Failed to provision Firebase app");
108
105
  }
109
106
  }
110
107
  exports.provisionFirebaseApp = provisionFirebaseApp;