firebase-tools 13.11.0 → 13.11.2

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.
@@ -20,6 +20,17 @@ exports.command = new command_1.Command("dataconnect:sdk:generate")
20
20
  configDir = path.resolve(path.join(cwd), configDir);
21
21
  }
22
22
  const serviceInfo = await (0, load_1.load)(projectId, service.location, configDir);
23
+ const hasGeneratables = serviceInfo.connectorInfo.some((c) => {
24
+ var _a, _b, _c;
25
+ return (((_a = c.connectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) ||
26
+ ((_b = c.connectorYaml.generate) === null || _b === void 0 ? void 0 : _b.kotlinSdk) ||
27
+ ((_c = c.connectorYaml.generate) === null || _c === void 0 ? void 0 : _c.swiftSdk));
28
+ });
29
+ if (!hasGeneratables) {
30
+ logger_1.logger.warn("No generated SDKs have been declared in connector.yaml files.");
31
+ logger_1.logger.warn("See https://firebase.google.com/docs/data-connect/quickstart#configure-sdk-outputs for examples of how to configure generated SDKs.");
32
+ return;
33
+ }
23
34
  for (const conn of serviceInfo.connectorInfo) {
24
35
  const output = await dataconnectEmulator_1.DataConnectEmulator.generate({
25
36
  configDir,
@@ -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}`,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseConnectorName = exports.parseServiceName = void 0;
3
+ exports.parseCloudSQLInstanceName = exports.parseConnectorName = exports.parseServiceName = void 0;
4
4
  const error_1 = require("../error");
5
5
  const serviceNameRegex = /projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/services\/(?<serviceId>[^\/]+)/;
6
6
  function parseServiceName(serviceName) {
@@ -46,3 +46,24 @@ function parseConnectorName(connectorName) {
46
46
  };
47
47
  }
48
48
  exports.parseConnectorName = parseConnectorName;
49
+ const cloudSQLInstanceNameRegex = /projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/instances\/(?<instanceId>[^\/]+)/;
50
+ function parseCloudSQLInstanceName(cloudSQLInstanceName) {
51
+ var _a, _b, _c;
52
+ const res = cloudSQLInstanceNameRegex.exec(cloudSQLInstanceName);
53
+ const projectId = (_a = res === null || res === void 0 ? void 0 : res.groups) === null || _a === void 0 ? void 0 : _a.projectId;
54
+ const location = (_b = res === null || res === void 0 ? void 0 : res.groups) === null || _b === void 0 ? void 0 : _b.location;
55
+ const instanceId = (_c = res === null || res === void 0 ? void 0 : res.groups) === null || _c === void 0 ? void 0 : _c.instanceId;
56
+ if (!projectId || !location || !instanceId) {
57
+ throw new error_1.FirebaseError(`${cloudSQLInstanceName} is not a valid cloudSQL instance name`);
58
+ }
59
+ const toString = () => {
60
+ return `projects/${projectId}/locations/${location}/services/${instanceId}`;
61
+ };
62
+ return {
63
+ projectId,
64
+ location,
65
+ instanceId,
66
+ toString,
67
+ };
68
+ }
69
+ exports.parseCloudSQLInstanceName = parseCloudSQLInstanceName;
@@ -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);
@@ -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;
@@ -540,7 +540,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
540
540
  });
541
541
  await startEmulator(dataConnectEmulator);
542
542
  if (!utils.isVSCodeExtension()) {
543
- dataConnectEmulator.connectToPostgres();
543
+ await dataConnectEmulator.connectToPostgres();
544
544
  }
545
545
  }
546
546
  if (listenForEmulator.storage) {
@@ -118,11 +118,22 @@ class DataConnectEmulator {
118
118
  exports.DataConnectEmulator = DataConnectEmulator;
119
119
  class DataConnectEmulatorClient {
120
120
  constructor() {
121
- this.client = registry_1.EmulatorRegistry.client(types_1.Emulators.DATACONNECT);
121
+ this.client = undefined;
122
122
  }
123
123
  async configureEmulator(body) {
124
- const res = await this.client.post("emulator/configure", body);
125
- return res;
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
+ }
126
137
  }
127
138
  }
128
139
  exports.DataConnectEmulatorClient = DataConnectEmulatorClient;
@@ -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)(),
@@ -11,6 +11,7 @@ const ensureApis_1 = require("../../../dataconnect/ensureApis");
11
11
  const client_1 = require("../../../dataconnect/client");
12
12
  const emulators_1 = require("../emulators");
13
13
  const names_1 = require("../../../dataconnect/names");
14
+ const logger_1 = require("../../../logger");
14
15
  const TEMPLATE_ROOT = (0, path_1.resolve)(__dirname, "../../../../templates/init/dataconnect/");
15
16
  const DATACONNECT_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "dataconnect.yaml"), "utf8");
16
17
  const CONNECTOR_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "connector.yaml"), "utf8");
@@ -46,6 +47,10 @@ async function doSetup(setup, config) {
46
47
  const dir = config.get("dataconnect.source") || "dataconnect";
47
48
  const subbedDataconnectYaml = subValues(DATACONNECT_YAML_TEMPLATE, info);
48
49
  const subbedConnectorYaml = subValues(CONNECTOR_YAML_TEMPLATE, info);
50
+ if (!config.has("dataconnect")) {
51
+ config.set("dataconnect.source", dir);
52
+ config.set("dataconnect.location", info.locationId);
53
+ }
49
54
  await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml);
50
55
  await config.askWriteProjectFile((0, path_1.join)(dir, "schema", "schema.gql"), SCHEMA_TEMPLATE);
51
56
  await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "connector.yaml"), subbedConnectorYaml);
@@ -63,6 +68,7 @@ async function doSetup(setup, config) {
63
68
  instanceId: info.cloudSqlInstanceId,
64
69
  databaseId: info.cloudSqlDatabase,
65
70
  enableGoogleMlIntegration: false,
71
+ waitForCreation: false,
66
72
  });
67
73
  }
68
74
  }
@@ -114,8 +120,10 @@ async function promptForService(setup, info) {
114
120
  info.serviceId = serviceName.serviceId;
115
121
  info.locationId = serviceName.location;
116
122
  if (choice.schema) {
117
- info.cloudSqlInstanceId =
118
- (_b = (_a = choice.schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) !== null && _b !== void 0 ? _b : "";
123
+ if ((_a = choice.schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) {
124
+ const instanceName = (0, names_1.parseCloudSQLInstanceName)((_b = choice.schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance);
125
+ info.cloudSqlInstanceId = instanceName.instanceId;
126
+ }
119
127
  info.cloudSqlDatabase = (_d = (_c = choice.schema.primaryDatasource.postgresql) === null || _c === void 0 ? void 0 : _c.database) !== null && _d !== void 0 ? _d : "";
120
128
  }
121
129
  }
@@ -147,7 +155,9 @@ async function promptForCloudSQLInstance(setup, info) {
147
155
  type: "list",
148
156
  choices,
149
157
  });
150
- info.locationId = choices.find((c) => c.value === info.cloudSqlInstanceId).location;
158
+ if (info.cloudSqlInstanceId !== "") {
159
+ info.locationId = choices.find((c) => c.value === info.cloudSqlInstanceId).location;
160
+ }
151
161
  }
152
162
  }
153
163
  if (info.cloudSqlInstanceId === "") {
@@ -189,23 +199,23 @@ async function locationChoices(setup) {
189
199
  }
190
200
  }
191
201
  async function promptForDatabase(setup, config, info) {
192
- const dir = config.get("dataconnect.source") || "dataconnect";
193
- if (!config.has("dataconnect")) {
194
- config.set("dataconnect.source", dir);
195
- config.set("dataconnect.location", info.locationId);
196
- }
197
202
  if (!info.isNewInstance && setup.projectId) {
198
- const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId);
199
- const choices = dbs.map((d) => {
200
- return { name: d.name, value: d.name };
201
- });
202
- choices.push({ name: "Create a new database", value: "" });
203
- if (dbs.length) {
204
- info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
205
- message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`,
206
- type: "list",
207
- choices,
203
+ try {
204
+ const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId);
205
+ const choices = dbs.map((d) => {
206
+ return { name: d.name, value: d.name };
208
207
  });
208
+ choices.push({ name: "Create a new database", value: "" });
209
+ if (dbs.length) {
210
+ info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
211
+ message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`,
212
+ type: "list",
213
+ choices,
214
+ });
215
+ }
216
+ }
217
+ catch (err) {
218
+ logger_1.logger.debug(`[dataconnect] Cannot list databases during init: ${err}`);
209
219
  }
210
220
  }
211
221
  if (info.cloudSqlDatabase === "") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.11.0",
3
+ "version": "13.11.2",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {