firebase-tools 13.10.2 → 13.11.1

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.
@@ -17,7 +17,7 @@ exports.command = new command_1.Command("dataconnect:services:list")
17
17
  "dataconnect.connectors.list",
18
18
  ])
19
19
  .action(async (options) => {
20
- var _a, _b, _c, _d, _e, _f;
20
+ var _a, _b, _c, _d, _e, _f, _g;
21
21
  const projectId = (0, projectUtils_1.needProjectId)(options);
22
22
  await (0, ensureApis_1.ensureApis)(projectId);
23
23
  const services = await client.listAllServices(projectId);
@@ -34,28 +34,22 @@ exports.command = new command_1.Command("dataconnect:services:list")
34
34
  });
35
35
  const jsonOutput = { services: [] };
36
36
  for (const service of services) {
37
- let schema = {
37
+ const schema = (_a = (await client.getSchema(service.name))) !== null && _a !== void 0 ? _a : {
38
38
  name: "",
39
39
  primaryDatasource: {},
40
40
  source: { files: [] },
41
41
  };
42
- try {
43
- schema = await client.getSchema(service.name);
44
- }
45
- catch (err) {
46
- logger_1.logger.debug(`Error fetching schema: ${err}`);
47
- }
48
42
  const connectors = await client.listConnectors(service.name);
49
43
  const serviceName = names.parseServiceName(service.name);
50
- const instanceName = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) !== null && _b !== void 0 ? _b : "";
44
+ const instanceName = (_c = (_b = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance) !== null && _c !== void 0 ? _c : "";
51
45
  const instanceId = instanceName.split("/").pop();
52
- const dbId = (_d = (_c = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _c === void 0 ? void 0 : _c.database) !== null && _d !== void 0 ? _d : "";
46
+ const dbId = (_e = (_d = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _d === void 0 ? void 0 : _d.database) !== null && _e !== void 0 ? _e : "";
53
47
  const dbName = `CloudSQL Instance: ${instanceId}\nDatabase:${dbId}`;
54
48
  table.push([
55
49
  serviceName.serviceId,
56
50
  serviceName.location,
57
51
  dbName,
58
- (_e = schema === null || schema === void 0 ? void 0 : schema.updateTime) !== null && _e !== void 0 ? _e : "",
52
+ (_f = schema === null || schema === void 0 ? void 0 : schema.updateTime) !== null && _f !== void 0 ? _f : "",
59
53
  "",
60
54
  "",
61
55
  ]);
@@ -71,7 +65,7 @@ exports.command = new command_1.Command("dataconnect:services:list")
71
65
  table.push(["", "", "", "", connectorName.connectorId, conn.updateTime]);
72
66
  serviceJson.connectors.push({
73
67
  connectorId: connectorName.connectorId,
74
- connectorLastUpdated: (_f = conn.updateTime) !== null && _f !== void 0 ? _f : "",
68
+ connectorLastUpdated: (_g = conn.updateTime) !== null && _g !== void 0 ? _g : "",
75
69
  });
76
70
  }
77
71
  jsonOutput.services.push(serviceJson);
@@ -12,10 +12,11 @@ const rimraf = require("rimraf");
12
12
  const utils = require("../utils");
13
13
  const JAR_CACHE_DIR = process.env.FIREBASE_CRASHLYTICS_BUILDTOOLS_PATH ||
14
14
  path.join(os.homedir(), ".cache", "firebase", "crashlytics", "buildtools");
15
- const JAR_VERSION = "2.9.2";
15
+ const JAR_VERSION = "3.0.0";
16
16
  const JAR_URL = `https://dl.google.com/android/maven2/com/google/firebase/firebase-crashlytics-buildtools/${JAR_VERSION}/firebase-crashlytics-buildtools-${JAR_VERSION}.jar`;
17
17
  async function fetchBuildtoolsJar() {
18
18
  if (process.env.CRASHLYTICS_LOCAL_JAR) {
19
+ logger_1.logger.debug(`Using local Crashlytics Jar override at ${process.env.CRASHLYTICS_LOCAL_JAR}`);
19
20
  return process.env.CRASHLYTICS_LOCAL_JAR;
20
21
  }
21
22
  const jarPath = path.join(JAR_CACHE_DIR, `crashlytics-buildtools-${JAR_VERSION}.jar`);
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.upsertConnector = exports.listConnectors = exports.deleteConnector = exports.getConnector = exports.upsertSchema = exports.getSchema = exports.deleteService = exports.createService = exports.listServices = exports.listAllServices = exports.listLocations = void 0;
3
+ exports.upsertConnector = exports.listConnectors = exports.deleteConnector = exports.getConnector = exports.upsertSchema = exports.getSchema = exports.deleteService = exports.createService = exports.listAllServices = exports.listLocations = void 0;
4
4
  const api_1 = require("../api");
5
5
  const apiv2_1 = require("../apiv2");
6
6
  const operationPoller = require("../operation-poller");
7
7
  const types = require("./types");
8
- const logger_1 = require("../logger");
9
8
  const DATACONNECT_API_VERSION = "v1alpha";
10
9
  const dataconnectClient = () => new apiv2_1.Client({
11
10
  urlPrefix: (0, api_1.dataconnectOrigin)(),
@@ -19,26 +18,11 @@ async function listLocations(projectId) {
19
18
  }
20
19
  exports.listLocations = listLocations;
21
20
  async function listAllServices(projectId) {
22
- const locations = await listLocations(projectId);
23
- let services = [];
24
- await Promise.all(locations.map(async (l) => {
25
- try {
26
- const locationServices = await listServices(projectId, l);
27
- services = services.concat(locationServices);
28
- }
29
- catch (err) {
30
- logger_1.logger.debug(`Unable to listServices in ${l}: ${err}`);
31
- }
32
- }));
33
- return services;
34
- }
35
- exports.listAllServices = listAllServices;
36
- async function listServices(projectId, locationId) {
37
21
  var _a;
38
- const res = await dataconnectClient().get(`/projects/${projectId}/locations/${locationId}/services`);
22
+ const res = await dataconnectClient().get(`/projects/${projectId}/locations/-/services`);
39
23
  return (_a = res.body.services) !== null && _a !== void 0 ? _a : [];
40
24
  }
41
- exports.listServices = listServices;
25
+ exports.listAllServices = listAllServices;
42
26
  async function createService(projectId, locationId, serviceId) {
43
27
  const op = await dataconnectClient().post(`/projects/${projectId}/locations/${locationId}/services`, {
44
28
  name: `projects/${projectId}/locations/${locationId}/services/${serviceId}`,
@@ -66,8 +50,16 @@ async function deleteService(projectId, locationId, serviceId) {
66
50
  }
67
51
  exports.deleteService = deleteService;
68
52
  async function getSchema(serviceName) {
69
- const res = await dataconnectClient().get(`${serviceName}/schemas/${types.SCHEMA_ID}`);
70
- return res.body;
53
+ try {
54
+ const res = await dataconnectClient().get(`${serviceName}/schemas/${types.SCHEMA_ID}`);
55
+ return res.body;
56
+ }
57
+ catch (err) {
58
+ if (err.status !== 404) {
59
+ throw err;
60
+ }
61
+ return undefined;
62
+ }
71
63
  }
72
64
  exports.getSchema = getSchema;
73
65
  async function upsertSchema(schema, validateOnly = false) {
@@ -2,11 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prettify = void 0;
4
4
  function prettify(err) {
5
- var _a;
5
+ var _a, _b, _c, _d;
6
6
  const message = err.message;
7
- let header = (_a = err.extensions.file) !== null && _a !== void 0 ? _a : "";
8
- if (err.locations) {
9
- header += `:${err.locations[0].line}`;
7
+ let header = (_b = (_a = err.extensions) === null || _a === void 0 ? void 0 : _a.file) !== null && _b !== void 0 ? _b : "";
8
+ if (err.locations && err.locations.length) {
9
+ const line = (_d = (_c = err.locations[0]) === null || _c === void 0 ? void 0 : _c.line) !== null && _d !== void 0 ? _d : "";
10
+ if (line) {
11
+ header += `:${line}`;
12
+ }
10
13
  }
11
14
  return header.length ? `${header}: ${message}` : message;
12
15
  }
@@ -9,8 +9,8 @@ const GOOGLE_ML_INTEGRATION_ROLE = "roles/aiplatform.user";
9
9
  const freeTrial_1 = require("./freeTrial");
10
10
  const error_1 = require("../error");
11
11
  async function provisionCloudSql(args) {
12
- let connectionName;
13
- const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, silent } = args;
12
+ let connectionName = "";
13
+ const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, waitForCreation, silent, } = args;
14
14
  try {
15
15
  const existingInstance = await cloudSqlAdminClient.getInstance(projectId, instanceId);
16
16
  silent || utils.logLabeledBullet("dataconnect", `Found existing instance ${instanceId}.`);
@@ -35,11 +35,17 @@ async function provisionCloudSql(args) {
35
35
  throw new error_1.FirebaseError("Free trial unavailable.");
36
36
  }
37
37
  silent ||
38
- utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found, creating it. This instance is provided under the terms of the Data Connect free trial ${(0, freeTrial_1.freeTrialTermsLink)()}`);
39
- silent || utils.logLabeledBullet("dataconnect", `This may take while...`);
40
- const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration), "Creating your instance...");
41
- silent || utils.logLabeledBullet("dataconnect", "Instance created");
42
- connectionName = (newInstance === null || newInstance === void 0 ? void 0 : newInstance.connectionName) || "";
38
+ utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found, creating it.` +
39
+ `\nThis instance is provided under the terms of the Data Connect free trial ${(0, freeTrial_1.freeTrialTermsLink)()}` +
40
+ `\nMonitor the progress at ${cloudSqlAdminClient.instanceConsoleLink(projectId, instanceId)}`);
41
+ const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance...");
42
+ if (newInstance) {
43
+ silent || utils.logLabeledBullet("dataconnect", "Instance created");
44
+ connectionName = (newInstance === null || newInstance === void 0 ? void 0 : newInstance.connectionName) || "";
45
+ }
46
+ else {
47
+ silent || utils.logLabeledBullet("dataconnect", "Instance creation process started");
48
+ }
43
49
  }
44
50
  try {
45
51
  await cloudSqlAdminClient.getDatabase(projectId, instanceId, databaseId);
@@ -205,14 +205,8 @@ function displayInvalidConnectors(invalidConnectors) {
205
205
  (0, utils_1.logLabeledWarning)("dataconnect", `This is a ${clc.red("breaking")} change and may break existing apps.`);
206
206
  }
207
207
  async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, databaseId, linkIfNotConnected) {
208
- let currentSchema;
209
- try {
210
- currentSchema = await (0, client_1.getSchema)(serviceName);
211
- }
212
- catch (err) {
213
- if (err.status !== 404) {
214
- throw err;
215
- }
208
+ let currentSchema = await (0, client_1.getSchema)(serviceName);
209
+ if (!currentSchema) {
216
210
  if (!linkIfNotConnected) {
217
211
  (0, utils_1.logLabeledWarning)("dataconnect", `Not yet linked to the Cloud SQL instance.`);
218
212
  return;
@@ -56,6 +56,7 @@ async function default_1(context, options) {
56
56
  instanceId,
57
57
  databaseId,
58
58
  enableGoogleMlIntegration,
59
+ waitForCreation: true,
59
60
  });
60
61
  }));
61
62
  return;
@@ -290,7 +290,7 @@ async function loadCodebases(config, options, firebaseConfig, runtimeConfig, fil
290
290
  const firebaseJsonRuntime = codebaseConfig.runtime;
291
291
  if (firebaseJsonRuntime && !supported.isRuntime(firebaseJsonRuntime)) {
292
292
  throw new error_1.FirebaseError(`Functions codebase ${codebase} has invalid runtime ` +
293
- `${firebaseJsonRuntime} specified in firebase.json. Valid values are: ` +
293
+ `${firebaseJsonRuntime} specified in firebase.json. Valid values are: \n` +
294
294
  Object.keys(supported.RUNTIMES)
295
295
  .map((s) => `- ${s}`)
296
296
  .join("\n"));
@@ -53,6 +53,12 @@ exports.RUNTIMES = runtimes({
53
53
  deprecationDate: "2026-04-30",
54
54
  decommissionDate: "2026-10-31",
55
55
  },
56
+ nodejs22: {
57
+ friendly: "Node.js 22",
58
+ status: "beta",
59
+ deprecationDate: "2027-04-30",
60
+ decommissionDate: "2027-10-31",
61
+ },
56
62
  python310: {
57
63
  friendly: "Python 3.10",
58
64
  status: "GA",
@@ -539,6 +539,9 @@ async function startAll(options, showUI = true, runningTestScript = false) {
539
539
  rc: options.rc,
540
540
  });
541
541
  await startEmulator(dataConnectEmulator);
542
+ if (!utils.isVSCodeExtension()) {
543
+ await dataConnectEmulator.connectToPostgres();
544
+ }
542
545
  }
543
546
  if (listenForEmulator.storage) {
544
547
  const storageAddr = legacyGetFirstAddr(types_1.Emulators.STORAGE);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DataConnectEmulator = void 0;
3
+ exports.DataConnectEmulatorClient = exports.DataConnectEmulator = void 0;
4
4
  const childProcess = require("child_process");
5
5
  const api_1 = require("../api");
6
6
  const constants_1 = require("./constants");
@@ -10,23 +10,35 @@ const error_1 = require("../error");
10
10
  const emulatorLogger_1 = require("./emulatorLogger");
11
11
  const types_2 = require("../dataconnect/types");
12
12
  const portUtils_1 = require("./portUtils");
13
+ const registry_1 = require("./registry");
13
14
  class DataConnectEmulator {
14
15
  constructor(args) {
15
16
  this.args = args;
16
17
  this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT);
18
+ this.emulatorClient = new DataConnectEmulatorClient();
17
19
  }
18
20
  async start() {
19
- this.logger.log("DEBUG", `Using Postgres connection string: ${this.getLocalConectionString()}`);
20
- const info = await DataConnectEmulator.build({ configDir: this.args.configDir });
21
- if ((0, types_2.requiresVector)(info.metadata)) {
22
- if (constants_1.Constants.isDemoProject(this.args.projectId)) {
23
- this.logger.logLabeled("WARN", "Data Connect", "Detected a 'demo-' project, but vector embeddings require a real project. Operations that use vector_embed will fail.");
24
- }
25
- else {
26
- this.logger.logLabeled("WARN", "Data Connect", "Operations that use vector_embed will make calls to production Vertex AI");
21
+ try {
22
+ const info = await DataConnectEmulator.build({ configDir: this.args.configDir });
23
+ if ((0, types_2.requiresVector)(info.metadata)) {
24
+ if (constants_1.Constants.isDemoProject(this.args.projectId)) {
25
+ this.logger.logLabeled("WARN", "Data Connect", "Detected a 'demo-' project, but vector embeddings require a real project. Operations that use vector_embed will fail.");
26
+ }
27
+ else {
28
+ this.logger.logLabeled("WARN", "Data Connect", "Operations that use vector_embed will make calls to production Vertex AI");
29
+ }
27
30
  }
28
31
  }
29
- return (0, downloadableEmulators_1.start)(types_1.Emulators.DATACONNECT, Object.assign(Object.assign({}, this.args), { listen: (0, portUtils_1.listenSpecsToString)(this.args.listen), config_dir: this.args.configDir, local_connection_string: this.getLocalConectionString(), project_id: this.args.projectId, service_location: this.args.locationId }));
32
+ catch (err) {
33
+ this.logger.log("DEBUG", `'fdc build' failed with error: ${err.message}`);
34
+ }
35
+ return (0, downloadableEmulators_1.start)(types_1.Emulators.DATACONNECT, {
36
+ auto_download: this.args.auto_download,
37
+ listen: (0, portUtils_1.listenSpecsToString)(this.args.listen),
38
+ config_dir: this.args.configDir,
39
+ project_id: this.args.projectId,
40
+ service_location: this.args.locationId,
41
+ });
30
42
  }
31
43
  connect() {
32
44
  return Promise.resolve();
@@ -73,8 +85,11 @@ class DataConnectEmulator {
73
85
  original: res.error,
74
86
  });
75
87
  }
88
+ if (res.status !== 0) {
89
+ throw new error_1.FirebaseError(`Unable to build your Data Connect schema and connectors (exit code ${res.status}): ${res.stderr}`);
90
+ }
76
91
  if (res.stderr) {
77
- throw new error_1.FirebaseError(`Unable to build your Data Connect schema and connectors: ${res.stderr}`);
92
+ emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).log("DEBUG", res.stderr);
78
93
  }
79
94
  try {
80
95
  return JSON.parse(res.stdout);
@@ -90,5 +105,35 @@ class DataConnectEmulator {
90
105
  }
91
106
  return (_b = (_a = this.args.rc.getDataconnect()) === null || _a === void 0 ? void 0 : _a.postgres) === null || _b === void 0 ? void 0 : _b.localConnectionString;
92
107
  }
108
+ async connectToPostgres(localConnectionString, database, serviceId) {
109
+ const connectionString = localConnectionString !== null && localConnectionString !== void 0 ? localConnectionString : this.getLocalConectionString();
110
+ if (!connectionString) {
111
+ this.logger.log("DEBUG", "No Postgres connection string found, not connecting to Postgres");
112
+ return false;
113
+ }
114
+ await this.emulatorClient.configureEmulator({ connectionString, database, serviceId });
115
+ return true;
116
+ }
93
117
  }
94
118
  exports.DataConnectEmulator = DataConnectEmulator;
119
+ class DataConnectEmulatorClient {
120
+ constructor() {
121
+ this.client = undefined;
122
+ }
123
+ async configureEmulator(body) {
124
+ if (!this.client) {
125
+ this.client = registry_1.EmulatorRegistry.client(types_1.Emulators.DATACONNECT);
126
+ }
127
+ try {
128
+ const res = await this.client.post("emulator/configure", body);
129
+ return res;
130
+ }
131
+ catch (err) {
132
+ if (err.status === 500) {
133
+ throw new error_1.FirebaseError(`Data Connect emulator: ${err.context.body.message}`);
134
+ }
135
+ throw err;
136
+ }
137
+ }
138
+ }
139
+ exports.DataConnectEmulatorClient = DataConnectEmulatorClient;
@@ -13,6 +13,10 @@ const downloadUtils = require("../downloadUtils");
13
13
  tmp.setGracefulCleanup();
14
14
  async function downloadEmulator(name) {
15
15
  const emulator = downloadableEmulators.getDownloadDetails(name);
16
+ if (emulator.localOnly) {
17
+ emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("WARN", name, `Env variable override detected, skipping download. Using ${emulator} emulator at ${emulator.binaryPath}`);
18
+ return;
19
+ }
16
20
  emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("BULLET", name, `downloading ${path.basename(emulator.downloadPath)}...`);
17
21
  fs.ensureDirSync(emulator.opts.cacheDir);
18
22
  const tmpfile = await downloadUtils.downloadToTmp(emulator.opts.remoteUrl, !!emulator.opts.auth);
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
24
24
  },
25
25
  firestore: {
26
- version: "1.19.6",
27
- expectedSize: 66349770,
28
- expectedChecksum: "2eaabbe3cdb4867df585b7ec5505bad7",
26
+ version: "1.19.7",
27
+ expectedSize: 66438992,
28
+ expectedChecksum: "aec233bea95c5cfab03881574ec16d6c",
29
29
  },
30
30
  storage: {
31
31
  version: "1.1.3",
@@ -40,26 +40,26 @@ const EMULATOR_UPDATE_DETAILS = {
40
40
  expectedChecksum: "a7f4398a00e5ca22abdcd78dc3877d00",
41
41
  },
42
42
  pubsub: {
43
- version: "0.8.2",
44
- expectedSize: 65611398,
45
- expectedChecksum: "70bb840321423e6ae621a3ae2f314903",
43
+ version: "0.8.14",
44
+ expectedSize: 66786933,
45
+ expectedChecksum: "a9025b3e53fdeafd2969ccb3ba1e1d38",
46
46
  },
47
47
  dataconnect: process.platform === "darwin"
48
48
  ? {
49
- version: "1.1.19",
50
- expectedSize: 25836864,
51
- expectedChecksum: "b31ba00789b82a30f0dee1c03b8f74ce",
49
+ version: "1.2.0",
50
+ expectedSize: 23954240,
51
+ expectedChecksum: "0f250761959519bb5a28fed76ceab2cb",
52
52
  }
53
53
  : process.platform === "win32"
54
54
  ? {
55
- version: "1.1.19",
56
- expectedSize: 23629824,
57
- expectedChecksum: "bcbd7705b36cee72ff0587749d67bfc3",
55
+ version: "1.2.0",
56
+ expectedSize: 24360960,
57
+ expectedChecksum: "168ce32c742e1d26037c52bdbb7d871c",
58
58
  }
59
59
  : {
60
- version: "1.1.19",
61
- expectedSize: 23247120,
62
- expectedChecksum: "56d6cb2ad85474d3a67999e35d2916a1",
60
+ version: "1.2.0",
61
+ expectedSize: 23970052,
62
+ expectedChecksum: "2ca17e4009a9ebae0f7c983bafff2ee6",
63
63
  },
64
64
  };
65
65
  exports.DownloadDetails = {
@@ -243,12 +243,15 @@ const Commands = {
243
243
  optionalArgs: [
244
244
  "listen",
245
245
  "config_dir",
246
- "local_connection_string",
247
246
  "project_id",
248
247
  "service_location",
248
+ "disable_sdk_generation",
249
+ "resolvers_emulator",
250
+ "vertex_location",
251
+ "rpc_retry_count",
249
252
  ],
250
253
  joinArgs: true,
251
- shell: true,
254
+ shell: false,
252
255
  },
253
256
  };
254
257
  function getExecPath(name) {
@@ -380,7 +383,17 @@ async function _runBinary(emulator, command, extraEnv) {
380
383
  });
381
384
  }
382
385
  function getDownloadDetails(emulator) {
383
- return exports.DownloadDetails[emulator];
386
+ const details = exports.DownloadDetails[emulator];
387
+ const pathOverride = process.env[`${emulator.toUpperCase()}_EMULATOR_BINARY_PATH`];
388
+ if (pathOverride) {
389
+ const logger = emulatorLogger_1.EmulatorLogger.forEmulator(emulator);
390
+ logger.logLabeled("WARN", emulator, `Env variable override detected. Using ${emulator} emulator at ${pathOverride}`);
391
+ details.downloadPath = pathOverride;
392
+ details.binaryPath = pathOverride;
393
+ details.localOnly = true;
394
+ fs.chmodSync(pathOverride, 0o755);
395
+ }
396
+ return details;
384
397
  }
385
398
  exports.getDownloadDetails = getDownloadDetails;
386
399
  function get(emulator) {
@@ -424,7 +437,7 @@ async function downloadIfNecessary(targetName) {
424
437
  }
425
438
  exports.downloadIfNecessary = downloadIfNecessary;
426
439
  async function start(targetName, args, extraEnv = {}) {
427
- const downloadDetails = exports.DownloadDetails[targetName];
440
+ const downloadDetails = getDownloadDetails(targetName);
428
441
  const emulator = get(targetName);
429
442
  const hasEmulator = fs.existsSync(getExecPath(targetName));
430
443
  const logger = emulatorLogger_1.EmulatorLogger.forEmulator(targetName);
@@ -74,7 +74,7 @@ class StorageRulesRuntime {
74
74
  if (this.alive) {
75
75
  return;
76
76
  }
77
- const downloadDetails = downloadableEmulators_1.DownloadDetails[types_2.Emulators.STORAGE];
77
+ const downloadDetails = (0, downloadableEmulators_1.getDownloadDetails)(types_2.Emulators.STORAGE);
78
78
  const hasEmulator = fs.existsSync(downloadDetails.downloadPath);
79
79
  if (!hasEmulator) {
80
80
  if (autoDownload) {
@@ -310,6 +310,8 @@ async function getContext(dir, targetOrConfiguration) {
310
310
  continue;
311
311
  if (target === buildTarget && builder === "@angular-devkit/build-angular:application")
312
312
  continue;
313
+ if (target === buildTarget && builder === "@angular-devkit/build-angular:browser")
314
+ continue;
313
315
  if (target === browserTarget && builder === "@angular-devkit/build-angular:browser-esbuild")
314
316
  continue;
315
317
  if (target === browserTarget && builder === "@angular-devkit/build-angular:browser")
@@ -364,10 +366,13 @@ async function getBrowserConfig(sourceDir, configuration) {
364
366
  if (!buildOrBrowserTarget) {
365
367
  throw new assert_1.AssertionError({ message: "expected build or browser target defined" });
366
368
  }
367
- const { locales, defaultLocale } = await localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject);
368
- const targetOptions = await architectHost.getOptionsForTarget(buildOrBrowserTarget);
369
+ const [{ locales, defaultLocale }, targetOptions, builderName] = await Promise.all([
370
+ localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject),
371
+ architectHost.getOptionsForTarget(buildOrBrowserTarget),
372
+ architectHost.getBuilderNameForTarget(buildOrBrowserTarget),
373
+ ]);
369
374
  (0, utils_2.assertIsString)(targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.outputPath);
370
- const outputPath = (0, path_1.join)(targetOptions.outputPath, buildTarget ? "browser" : "");
375
+ const outputPath = (0, path_1.join)(targetOptions.outputPath, buildTarget && builderName === "@angular-devkit/build-angular:application" ? "browser" : "");
371
376
  return { locales, baseHref, outputPath, defaultLocale };
372
377
  }
373
378
  exports.getBrowserConfig = getBrowserConfig;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.listUsers = exports.deleteUser = exports.getUser = exports.createUser = exports.createDatabase = exports.getDatabase = exports.listDatabases = exports.updateInstanceForDataConnect = exports.createInstance = exports.getInstance = exports.listInstances = void 0;
3
+ exports.listUsers = exports.deleteUser = exports.getUser = exports.createUser = exports.createDatabase = exports.getDatabase = exports.listDatabases = exports.updateInstanceForDataConnect = exports.createInstance = exports.instanceConsoleLink = exports.getInstance = exports.listInstances = void 0;
4
4
  const apiv2_1 = require("../../apiv2");
5
5
  const api_1 = require("../../api");
6
6
  const operationPoller = require("../../operation-poller");
7
+ const error_1 = require("../../error");
7
8
  const API_VERSION = "v1";
8
9
  const client = new apiv2_1.Client({
9
10
  urlPrefix: (0, api_1.cloudSQLAdminOrigin)(),
@@ -18,10 +19,17 @@ async function listInstances(projectId) {
18
19
  exports.listInstances = listInstances;
19
20
  async function getInstance(projectId, instanceId) {
20
21
  const res = await client.get(`projects/${projectId}/instances/${instanceId}`);
22
+ if (res.body.state === "FAILED") {
23
+ throw new error_1.FirebaseError(`Cloud SQL instance ${instanceId} is in a failed state.\nGo to ${instanceConsoleLink(projectId, instanceId)} to repair or delete it.`);
24
+ }
21
25
  return res.body;
22
26
  }
23
27
  exports.getInstance = getInstance;
24
- async function createInstance(projectId, location, instanceId, enableGoogleMlIntegration) {
28
+ function instanceConsoleLink(projectId, instanceId) {
29
+ return `https://console.cloud.google.com/sql/instances/${instanceId}/overview?project=${projectId}`;
30
+ }
31
+ exports.instanceConsoleLink = instanceConsoleLink;
32
+ async function createInstance(projectId, location, instanceId, enableGoogleMlIntegration, waitForCreation) {
25
33
  const databaseFlags = [{ name: "cloudsql.iam_authentication", value: "on" }];
26
34
  if (enableGoogleMlIntegration) {
27
35
  databaseFlags.push({ name: "cloudsql.enable_google_ml_integration", value: "on" });
@@ -47,6 +55,9 @@ async function createInstance(projectId, location, instanceId, enableGoogleMlInt
47
55
  },
48
56
  },
49
57
  });
58
+ if (!waitForCreation) {
59
+ return;
60
+ }
50
61
  const opName = `projects/${projectId}/operations/${op.body.name}`;
51
62
  const pollRes = await operationPoller.pollOperation({
52
63
  apiOrigin: (0, api_1.cloudSQLAdminOrigin)(),
@@ -10,6 +10,8 @@ const cloudsql = require("../../../gcp/cloudsql/cloudsqladmin");
10
10
  const ensureApis_1 = require("../../../dataconnect/ensureApis");
11
11
  const client_1 = require("../../../dataconnect/client");
12
12
  const emulators_1 = require("../emulators");
13
+ const names_1 = require("../../../dataconnect/names");
14
+ const logger_1 = require("../../../logger");
13
15
  const TEMPLATE_ROOT = (0, path_1.resolve)(__dirname, "../../../../templates/init/dataconnect/");
14
16
  const DATACONNECT_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "dataconnect.yaml"), "utf8");
15
17
  const CONNECTOR_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "connector.yaml"), "utf8");
@@ -18,97 +20,21 @@ const QUERIES_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT,
18
20
  const MUTATIONS_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "mutations.gql"), "utf8");
19
21
  async function doSetup(setup, config) {
20
22
  var _a, _b, _c;
21
- if (setup.projectId) {
22
- await (0, ensureApis_1.ensureApis)(setup.projectId);
23
- }
24
- const serviceId = await (0, prompt_1.promptOnce)({
25
- message: "What ID would you like to use for this service?",
26
- type: "input",
27
- default: "dataconnect",
28
- });
29
- const connectorId = await (0, prompt_1.promptOnce)({
30
- message: "What ID would you like to use for your connector?",
31
- type: "input",
32
- default: "my-connector",
33
- });
34
- let cloudSqlInstanceId = "";
35
- let newInstance = false;
36
- let locationId = "";
37
- if (setup.projectId) {
38
- const instances = await cloudsql.listInstances(setup.projectId);
39
- const choices = instances.map((i) => {
40
- return { name: i.name, value: i.name, location: i.region };
41
- });
42
- const freeTrialInstanceId = await (0, freeTrial_1.checkForFreeTrialInstance)(setup.projectId);
43
- if (!freeTrialInstanceId) {
44
- choices.push({ name: "Create a new instance", value: "", location: "" });
45
- }
46
- if (instances.length) {
47
- cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
48
- message: `Which CloudSQL instance would you like to use?`,
49
- type: "list",
50
- choices,
51
- });
52
- }
53
- locationId = choices.find((c) => c.value === cloudSqlInstanceId).location;
54
- }
55
- if (cloudSqlInstanceId === "") {
56
- let locationOptions = [
57
- { name: "us-central1", value: "us-central1" },
58
- { name: "europe-north1", value: "europe-north1" },
59
- { name: "europe-central2", value: "europe-central2" },
60
- { name: "europe-west1", value: "europe-west1" },
61
- { name: "southamerica-west1", value: "southamerica-west1" },
62
- { name: "us-east4", value: "us-east4" },
63
- { name: "us-west1", value: "us-west1" },
64
- { name: "asia-southeast1", value: "asia-southeast1" },
65
- ];
66
- if (setup.projectId) {
67
- const locations = await (0, client_1.listLocations)(setup.projectId);
68
- locationOptions = locations.map((l) => {
69
- return { name: l, value: l };
70
- });
71
- }
72
- newInstance = true;
73
- cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
74
- message: `What ID would you like to use for your new CloudSQL instance?`,
75
- type: "input",
76
- default: `dataconnect-test`,
77
- });
78
- locationId = await (0, prompt_1.promptOnce)({
79
- message: "What location would you use for this instance?",
80
- type: "list",
81
- choices: locationOptions,
82
- });
83
- }
84
- const dir = config.get("dataconnect.source") || "dataconnect";
85
- if (!config.has("dataconnect")) {
86
- config.set("dataconnect.source", dir);
87
- config.set("dataconnect.location", locationId);
88
- }
89
- let cloudSqlDatabase = "";
90
- let newDB = false;
91
- if (!newInstance && setup.projectId) {
92
- const dbs = await cloudsql.listDatabases(setup.projectId, cloudSqlInstanceId);
93
- const choices = dbs.map((d) => {
94
- return { name: d.name, value: d.name };
95
- });
96
- choices.push({ name: "Create a new database", value: "" });
97
- if (dbs.length) {
98
- cloudSqlDatabase = await (0, prompt_1.promptOnce)({
99
- message: `Which database in ${cloudSqlInstanceId} would you like to use?`,
100
- type: "list",
101
- choices,
102
- });
103
- }
23
+ let info = {
24
+ serviceId: "",
25
+ locationId: "",
26
+ cloudSqlInstanceId: "",
27
+ isNewInstance: false,
28
+ cloudSqlDatabase: "",
29
+ isNewDatabase: false,
30
+ connectorId: "default-connector",
31
+ };
32
+ info = await promptForService(setup, info);
33
+ if (info.cloudSqlInstanceId === "") {
34
+ info = await promptForCloudSQLInstance(setup, info);
104
35
  }
105
- if (cloudSqlDatabase === "") {
106
- newDB = true;
107
- cloudSqlDatabase = await (0, prompt_1.promptOnce)({
108
- message: `What ID would you like to use for your new database in ${cloudSqlInstanceId}?`,
109
- type: "input",
110
- default: `dataconnect`,
111
- });
36
+ if (info.cloudSqlDatabase === "") {
37
+ info = await promptForDatabase(setup, config, info);
112
38
  }
113
39
  const defaultConnectionString = (_c = (_b = (_a = setup.rcfile.dataconnectEmulatorConfig) === null || _a === void 0 ? void 0 : _a.postgres) === null || _b === void 0 ? void 0 : _b.localConnectionString) !== null && _c !== void 0 ? _c : emulators_1.DEFAULT_POSTGRES_CONNECTION;
114
40
  const localConnectionString = await (0, prompt_1.promptOnce)({
@@ -118,35 +44,27 @@ async function doSetup(setup, config) {
118
44
  default: defaultConnectionString,
119
45
  });
120
46
  setup.rcfile.dataconnectEmulatorConfig = { postgres: { localConnectionString } };
121
- const subbedDataconnectYaml = subValues(DATACONNECT_YAML_TEMPLATE, {
122
- serviceId,
123
- cloudSqlInstanceId,
124
- cloudSqlDatabase,
125
- connectorId,
126
- });
127
- const subbedConnectorYaml = subValues(CONNECTOR_YAML_TEMPLATE, {
128
- serviceId,
129
- cloudSqlInstanceId,
130
- cloudSqlDatabase,
131
- connectorId,
132
- });
47
+ const dir = config.get("dataconnect.source") || "dataconnect";
48
+ const subbedDataconnectYaml = subValues(DATACONNECT_YAML_TEMPLATE, info);
49
+ const subbedConnectorYaml = subValues(CONNECTOR_YAML_TEMPLATE, info);
133
50
  await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml);
134
- await config.askWriteProjectFile((0, path_1.join)(dir, "connector", "connector.yaml"), subbedConnectorYaml);
135
51
  await config.askWriteProjectFile((0, path_1.join)(dir, "schema", "schema.gql"), SCHEMA_TEMPLATE);
136
- await config.askWriteProjectFile((0, path_1.join)(dir, "connector", "queries.gql"), QUERIES_TEMPLATE);
137
- await config.askWriteProjectFile((0, path_1.join)(dir, "connector", "mutations.gql"), MUTATIONS_TEMPLATE);
52
+ await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "connector.yaml"), subbedConnectorYaml);
53
+ await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "queries.gql"), QUERIES_TEMPLATE);
54
+ await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "mutations.gql"), MUTATIONS_TEMPLATE);
138
55
  if (setup.projectId &&
139
- (newInstance || newDB) &&
56
+ (info.isNewInstance || info.isNewDatabase) &&
140
57
  (await (0, prompt_1.confirm)({
141
58
  message: "Would you like to provision your CloudSQL instance and database now? This will take a few minutes.",
142
59
  default: true,
143
60
  }))) {
144
61
  await (0, provisionCloudSql_1.provisionCloudSql)({
145
62
  projectId: setup.projectId,
146
- locationId,
147
- instanceId: cloudSqlInstanceId,
148
- databaseId: cloudSqlDatabase,
63
+ locationId: info.locationId,
64
+ instanceId: info.cloudSqlInstanceId,
65
+ databaseId: info.cloudSqlDatabase,
149
66
  enableGoogleMlIntegration: false,
67
+ waitForCreation: false,
150
68
  });
151
69
  }
152
70
  }
@@ -164,3 +82,146 @@ function subValues(template, replacementValues) {
164
82
  }
165
83
  return replaced;
166
84
  }
85
+ async function promptForService(setup, info) {
86
+ var _a, _b, _c, _d;
87
+ if (setup.projectId) {
88
+ await (0, ensureApis_1.ensureApis)(setup.projectId);
89
+ const existingServices = await (0, client_1.listAllServices)(setup.projectId);
90
+ const existingServicesAndSchemas = await Promise.all(existingServices.map(async (s) => {
91
+ return {
92
+ service: s,
93
+ schema: await (0, client_1.getSchema)(s.name),
94
+ };
95
+ }));
96
+ const existingFreshServicesAndSchemas = existingServicesAndSchemas.filter((s) => {
97
+ var _a, _b;
98
+ return !((_b = (_a = s.schema) === null || _a === void 0 ? void 0 : _a.source.files) === null || _b === void 0 ? void 0 : _b.length);
99
+ });
100
+ if (existingFreshServicesAndSchemas.length) {
101
+ const choices = existingFreshServicesAndSchemas.map((s) => {
102
+ const serviceName = (0, names_1.parseServiceName)(s.service.name);
103
+ return {
104
+ name: `${serviceName.location}/${serviceName.serviceId}`,
105
+ value: s,
106
+ };
107
+ });
108
+ choices.push({ name: "Create a new service", value: undefined });
109
+ const choice = await (0, prompt_1.promptOnce)({
110
+ message: "Your project already has existing services. Which would you like to set up local files for?",
111
+ type: "list",
112
+ choices,
113
+ });
114
+ if (choice) {
115
+ const serviceName = (0, names_1.parseServiceName)(choice.service.name);
116
+ info.serviceId = serviceName.serviceId;
117
+ info.locationId = serviceName.location;
118
+ if (choice.schema) {
119
+ info.cloudSqlInstanceId =
120
+ (_b = (_a = choice.schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) !== null && _b !== void 0 ? _b : "";
121
+ info.cloudSqlDatabase = (_d = (_c = choice.schema.primaryDatasource.postgresql) === null || _c === void 0 ? void 0 : _c.database) !== null && _d !== void 0 ? _d : "";
122
+ }
123
+ }
124
+ }
125
+ }
126
+ if (info.serviceId === "") {
127
+ info.serviceId = await (0, prompt_1.promptOnce)({
128
+ message: "What ID would you like to use for this service?",
129
+ type: "input",
130
+ default: "my-service",
131
+ });
132
+ }
133
+ return info;
134
+ }
135
+ async function promptForCloudSQLInstance(setup, info) {
136
+ if (setup.projectId) {
137
+ const instances = await cloudsql.listInstances(setup.projectId);
138
+ let choices = instances.map((i) => {
139
+ return { name: i.name, value: i.name, location: i.region };
140
+ });
141
+ choices = choices.filter((c) => info.locationId === "" || info.locationId === c.location);
142
+ if (choices.length) {
143
+ const freeTrialInstanceId = await (0, freeTrial_1.checkForFreeTrialInstance)(setup.projectId);
144
+ if (!freeTrialInstanceId) {
145
+ choices.push({ name: "Create a new instance", value: "", location: "" });
146
+ }
147
+ info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
148
+ message: `Which CloudSQL instance would you like to use?`,
149
+ type: "list",
150
+ choices,
151
+ });
152
+ info.locationId = choices.find((c) => c.value === info.cloudSqlInstanceId).location;
153
+ }
154
+ }
155
+ if (info.cloudSqlInstanceId === "") {
156
+ info.isNewInstance = true;
157
+ info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
158
+ message: `What ID would you like to use for your new CloudSQL instance?`,
159
+ type: "input",
160
+ default: `fdc-sql`,
161
+ });
162
+ }
163
+ if (info.locationId === "") {
164
+ const choices = await locationChoices(setup);
165
+ info.locationId = await (0, prompt_1.promptOnce)({
166
+ message: "What location would like to use?",
167
+ type: "list",
168
+ choices,
169
+ });
170
+ }
171
+ return info;
172
+ }
173
+ async function locationChoices(setup) {
174
+ if (setup.projectId) {
175
+ const locations = await (0, client_1.listLocations)(setup.projectId);
176
+ return locations.map((l) => {
177
+ return { name: l, value: l };
178
+ });
179
+ }
180
+ else {
181
+ return [
182
+ { name: "us-central1", value: "us-central1" },
183
+ { name: "europe-north1", value: "europe-north1" },
184
+ { name: "europe-central2", value: "europe-central2" },
185
+ { name: "europe-west1", value: "europe-west1" },
186
+ { name: "southamerica-west1", value: "southamerica-west1" },
187
+ { name: "us-east4", value: "us-east4" },
188
+ { name: "us-west1", value: "us-west1" },
189
+ { name: "asia-southeast1", value: "asia-southeast1" },
190
+ ];
191
+ }
192
+ }
193
+ async function promptForDatabase(setup, config, info) {
194
+ const dir = config.get("dataconnect.source") || "dataconnect";
195
+ if (!config.has("dataconnect")) {
196
+ config.set("dataconnect.source", dir);
197
+ config.set("dataconnect.location", info.locationId);
198
+ }
199
+ if (!info.isNewInstance && setup.projectId) {
200
+ try {
201
+ const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId);
202
+ const choices = dbs.map((d) => {
203
+ return { name: d.name, value: d.name };
204
+ });
205
+ choices.push({ name: "Create a new database", value: "" });
206
+ if (dbs.length) {
207
+ info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
208
+ message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`,
209
+ type: "list",
210
+ choices,
211
+ });
212
+ }
213
+ }
214
+ catch (err) {
215
+ logger_1.logger.debug(`[dataconnect] Cannot list databases during init: ${err}`);
216
+ }
217
+ }
218
+ if (info.cloudSqlDatabase === "") {
219
+ info.isNewDatabase = true;
220
+ info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
221
+ message: `What ID would you like to use for your new database in ${info.cloudSqlInstanceId}?`,
222
+ type: "input",
223
+ default: `fdcdb`,
224
+ });
225
+ }
226
+ return info;
227
+ }
package/lib/rc.js CHANGED
@@ -157,9 +157,7 @@ class RC {
157
157
  return (_a = this.data.dataconnectEmulatorConfig) !== null && _a !== void 0 ? _a : {};
158
158
  }
159
159
  setDataconnect(localConnectionString) {
160
- if (!this.data.dataconnectEmulatorConfig) {
161
- this.data.dataconnectEmulatorConfig = { postgres: { localConnectionString } };
162
- }
160
+ this.data.dataconnectEmulatorConfig = { postgres: { localConnectionString } };
163
161
  }
164
162
  save() {
165
163
  if (this.path) {
package/lib/track.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.track = exports.cliSession = exports.emulatorSession = exports.trackEmulator = exports.trackGA4 = exports.usageEnabled = exports.GA4_PROPERTIES = void 0;
3
+ exports.track = exports.cliSession = exports.vscodeSession = exports.emulatorSession = exports.trackVSCode = exports.trackEmulator = exports.trackGA4 = exports.usageEnabled = exports.GA4_PROPERTIES = void 0;
4
4
  const node_fetch_1 = require("node-fetch");
5
5
  const ua = require("universal-analytics");
6
6
  const uuid_1 = require("uuid");
@@ -19,6 +19,11 @@ exports.GA4_PROPERTIES = {
19
19
  apiSecret: process.env.FIREBASE_EMULATOR_GA4_API_SECRET || "2V_zBYc4TdeoppzDaIu0zw",
20
20
  clientIdKey: "emulator-analytics-clientId",
21
21
  },
22
+ vscode: {
23
+ measurementId: process.env.FIREBASE_VSCODE_GA4_MEASUREMENT_ID || "G-FYJ489XM2T",
24
+ apiSecret: process.env.FIREBASE_VSCODE_GA4_API_SECRET || "XAEWKHe7RM-ygCK44N52Ww",
25
+ clientIdKey: "vscode-analytics-clientId",
26
+ },
22
27
  };
23
28
  function usageEnabled() {
24
29
  return !!process.env.IS_FIREBASE_CLI && !!configstore_1.configstore.get("usage");
@@ -69,6 +74,24 @@ async function trackEmulator(eventName, params) {
69
74
  });
70
75
  }
71
76
  exports.trackEmulator = trackEmulator;
77
+ async function trackVSCode(eventName, params) {
78
+ const session = vscodeSession();
79
+ if (!session) {
80
+ return;
81
+ }
82
+ session.debugMode = process.env.VSCODE_DEBUG_MODE === "true";
83
+ const oldTotalEngagementSeconds = session.totalEngagementSeconds;
84
+ session.totalEngagementSeconds = process.uptime();
85
+ const duration = session.totalEngagementSeconds - oldTotalEngagementSeconds;
86
+ return _ga4Track({
87
+ session,
88
+ apiSecret: exports.GA4_PROPERTIES.vscode.apiSecret,
89
+ eventName,
90
+ params,
91
+ duration,
92
+ });
93
+ }
94
+ exports.trackVSCode = trackVSCode;
72
95
  async function _ga4Track(args) {
73
96
  const { session, apiSecret, eventName, params, duration } = args;
74
97
  session.commandName = (params === null || params === void 0 ? void 0 : params.command_name) || session.commandName;
@@ -119,13 +142,17 @@ function emulatorSession() {
119
142
  return session("emulator");
120
143
  }
121
144
  exports.emulatorSession = emulatorSession;
145
+ function vscodeSession() {
146
+ return session("vscode");
147
+ }
148
+ exports.vscodeSession = vscodeSession;
122
149
  function cliSession() {
123
150
  return session("cli");
124
151
  }
125
152
  exports.cliSession = cliSession;
126
153
  function session(propertyName) {
127
154
  const validateOnly = !!process.env.FIREBASE_CLI_MP_VALIDATE;
128
- if (!usageEnabled()) {
155
+ if (!usageEnabled() && propertyName !== "vscode") {
129
156
  if (validateOnly) {
130
157
  logger_1.logger.warn("Google Analytics is DISABLED. To enable, (re)login and opt in to collection.");
131
158
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.10.2",
3
+ "version": "13.11.1",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -726,6 +726,7 @@
726
726
  "nodejs16",
727
727
  "nodejs18",
728
728
  "nodejs20",
729
+ "nodejs22",
729
730
  "nodejs6",
730
731
  "nodejs8",
731
732
  "python310",
@@ -787,6 +788,7 @@
787
788
  "nodejs16",
788
789
  "nodejs18",
789
790
  "nodejs20",
791
+ "nodejs22",
790
792
  "nodejs6",
791
793
  "nodejs8",
792
794
  "python310",
@@ -7,4 +7,4 @@ schema:
7
7
  database: "__cloudSqlDatabase__"
8
8
  cloudSql:
9
9
  instanceId: "__cloudSqlInstanceId__"
10
- connectorDirs: ["./connector"]
10
+ connectorDirs: ["./__connectorId__"]
@@ -10,7 +10,7 @@
10
10
  # }
11
11
  # mutation CreateEmail($content: String, $subject: String, $fromUid: String) @auth(level: PUBLIC) {
12
12
  # email_insert(data: {
13
- # text: $content,
13
+ # text: $content, # The request variable name doesn't have to match the field name.
14
14
  # subject: $subject,
15
15
  # fromUid: $fromUid,
16
16
  ## Server values let your service populate data for you
@@ -13,12 +13,12 @@
13
13
  ## where allows you to filter lists
14
14
  ## Here, we use it to filter to only emails where this user is one of the recipients.
15
15
  # emails(where: {
16
- # users_via_Recipient: {
16
+ # users_via_Recipient: {
17
17
  # exist: { uid: { eq: $uid }
18
18
  # }}
19
19
  # }) {
20
- # id subject sent
21
- # content: text
20
+ # id subject sent
21
+ # content: text # Select the `text` field but alias it as `content` in the response.
22
22
  # sender: from { name email: address uid }
23
23
 
24
24
  ## <field>_on_<foreign_key_field> makes it easy to grab info from another table
@@ -38,11 +38,11 @@
38
38
  # query ListSent(
39
39
  # $uid: String
40
40
  # ) @auth(level: PUBLIC) {
41
- # emails(where: {
41
+ # emails(where: {
42
42
  # fromUid: { eq: $uid }
43
43
  # }) {
44
- # id subject sent
45
- # content: text
44
+ # id subject sent
45
+ # content: text
46
46
  # sender: from { name email: address uid }
47
47
  # to: recipients_on_email {
48
48
  # user { name email: address uid }