firebase-tools 13.8.1 → 13.8.3

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 (36) hide show
  1. package/lib/apphosting/app.js +9 -7
  2. package/lib/apphosting/githubConnections.js +6 -8
  3. package/lib/apphosting/index.js +20 -19
  4. package/lib/apphosting/repo.js +2 -2
  5. package/lib/commands/apphosting-backends-create.js +3 -3
  6. package/lib/commands/{dataconnect-list.js → dataconnect-services-list.js} +23 -6
  7. package/lib/commands/dataconnect-sql-migrate.js +3 -3
  8. package/lib/commands/index.js +2 -1
  9. package/lib/commands/init.js +3 -3
  10. package/lib/dataconnect/client.js +2 -2
  11. package/lib/dataconnect/errors.js +31 -0
  12. package/lib/dataconnect/fileUtils.js +10 -7
  13. package/lib/dataconnect/freeTrial.js +1 -1
  14. package/lib/dataconnect/graphqlError.js +2 -2
  15. package/lib/dataconnect/provisionCloudSql.js +4 -3
  16. package/lib/dataconnect/schemaMigration.js +119 -46
  17. package/lib/deploy/dataconnect/deploy.js +4 -14
  18. package/lib/deploy/dataconnect/prepare.js +3 -0
  19. package/lib/emulator/dataconnectEmulator.js +2 -1
  20. package/lib/emulator/downloadableEmulators.js +9 -9
  21. package/lib/experiments.js +5 -0
  22. package/lib/gcp/cloudsql/cloudsqladmin.js +39 -19
  23. package/lib/gcp/firedata.js +3 -2
  24. package/lib/init/features/dataconnect/index.js +39 -33
  25. package/lib/init/features/emulators.js +9 -10
  26. package/lib/init/features/functions/index.js +4 -0
  27. package/lib/init/features/functions/npm-dependencies.js +12 -23
  28. package/lib/init/features/genkit.js +54 -0
  29. package/lib/init/features/index.js +3 -1
  30. package/lib/init/index.js +1 -0
  31. package/lib/init/spawn.js +23 -0
  32. package/lib/requireTosAcceptance.js +1 -0
  33. package/package.json +1 -1
  34. package/templates/init/dataconnect/mutations.gql +29 -3
  35. package/templates/init/dataconnect/queries.gql +49 -4
  36. package/templates/init/dataconnect/schema.gql +23 -10
@@ -11,66 +11,104 @@ const logger_1 = require("../logger");
11
11
  const error_1 = require("../error");
12
12
  const projectUtils_1 = require("../projectUtils");
13
13
  const utils_1 = require("../utils");
14
- const IMCOMPATIBLE_SCHEMA_ERROR_TYPESTRING = "type.googleapis.com/google.firebase.dataconnect.v1main.IncompatibleSqlSchemaError";
14
+ const errors = require("./errors");
15
15
  async function diffSchema(schema) {
16
- var _a, _b;
17
- const dbName = (_a = schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.database;
18
- const instanceName = (_b = schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance;
19
- if (!instanceName || !dbName) {
20
- throw new error_1.FirebaseError(`tried to diff schema but ${instanceName} was undefined`);
21
- }
16
+ const { serviceName, instanceName, databaseId } = getIdentifiers(schema);
17
+ await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId);
22
18
  try {
23
- const serviceName = schema.name.replace(`/schemas/${types_1.SCHEMA_ID}`, "");
24
- await ensureServiceIsConnectedToCloudSql(serviceName);
25
19
  await (0, client_1.upsertSchema)(schema, true);
26
20
  }
27
21
  catch (err) {
28
- const incompatible = getIncompatibleSchemaError(err);
22
+ const invalidConnectors = errors.getInvalidConnectors(err);
23
+ if (invalidConnectors.length) {
24
+ displayInvalidConnectors(invalidConnectors);
25
+ }
26
+ const incompatible = errors.getIncompatibleSchemaError(err);
29
27
  if (incompatible) {
30
28
  displaySchemaChanges(incompatible);
31
29
  return incompatible.diffs;
32
30
  }
33
- throw err;
34
31
  }
35
- logger_1.logger.debug(`Schema was up to date for ${instanceName}:${dbName}`);
32
+ (0, utils_1.logLabeledSuccess)("dataconnect", `Database schema is up to date.`);
36
33
  return [];
37
34
  }
38
35
  exports.diffSchema = diffSchema;
39
36
  async function migrateSchema(args) {
40
- var _a, _b;
41
- const { schema, validateOnly } = args;
42
- const databaseId = (_a = schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.database;
43
- if (!databaseId) {
44
- throw new error_1.FirebaseError("Schema is missing primaryDatasource.postgresql?.database, cannot migrate");
45
- }
46
- const instanceId = (_b = schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance.split("/").pop();
47
- if (!instanceId) {
48
- throw new error_1.FirebaseError(`tried to migrate schema but ${instanceId} was undefined`);
49
- }
37
+ const { options, schema, allowNonInteractiveMigration, validateOnly } = args;
38
+ const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema);
39
+ await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId);
50
40
  try {
51
- const serviceName = schema.name.replace(`/schemas/${types_1.SCHEMA_ID}`, "");
52
- await ensureServiceIsConnectedToCloudSql(serviceName);
53
41
  await (0, client_1.upsertSchema)(schema, validateOnly);
54
42
  logger_1.logger.debug(`Database schema was up to date for ${instanceId}:${databaseId}`);
55
- return [];
56
43
  }
57
44
  catch (err) {
58
- const incompatible = getIncompatibleSchemaError(err);
59
- if (!incompatible) {
45
+ const incompatible = errors.getIncompatibleSchemaError(err);
46
+ const invalidConnectors = errors.getInvalidConnectors(err);
47
+ if (!incompatible && !invalidConnectors.length) {
60
48
  throw err;
61
49
  }
62
- const diffs = await handleIncompatibleSchemaError(Object.assign(Object.assign({}, args), { incompatibleSchemaError: incompatible, instanceId,
63
- databaseId }));
50
+ const shouldDeleteInvalidConnectors = await promptForInvalidConnectorError(options, invalidConnectors, validateOnly);
51
+ if (!shouldDeleteInvalidConnectors && invalidConnectors.length) {
52
+ const cmd = suggestedCommand(serviceName, invalidConnectors);
53
+ throw new error_1.FirebaseError(`Command aborted. Try deploying compatible connectors first with ${clc.bold(cmd)}`);
54
+ }
55
+ const migrationMode = incompatible
56
+ ? await promptForSchemaMigration(options, databaseId, incompatible, allowNonInteractiveMigration)
57
+ : "none";
58
+ if (migrationMode === "none" && incompatible) {
59
+ throw new error_1.FirebaseError("Command aborted.");
60
+ }
61
+ let diffs = [];
62
+ if (incompatible) {
63
+ diffs = await handleIncompatibleSchemaError({
64
+ options,
65
+ databaseId,
66
+ instanceId,
67
+ incompatibleSchemaError: incompatible,
68
+ choice: migrationMode,
69
+ });
70
+ }
71
+ if (invalidConnectors.length) {
72
+ await deleteInvalidConnectors(invalidConnectors);
73
+ }
64
74
  await (0, client_1.upsertSchema)(schema, validateOnly);
65
75
  return diffs;
66
76
  }
77
+ return [];
67
78
  }
68
79
  exports.migrateSchema = migrateSchema;
80
+ function getIdentifiers(schema) {
81
+ var _a, _b;
82
+ const databaseId = (_a = schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.database;
83
+ if (!databaseId) {
84
+ throw new error_1.FirebaseError("Schema is missing primaryDatasource.postgresql?.database, cannot migrate");
85
+ }
86
+ const instanceName = (_b = schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance;
87
+ if (!instanceName) {
88
+ throw new error_1.FirebaseError("tried to migrate schema but instance name was not provided in dataconnect.yaml");
89
+ }
90
+ const instanceId = instanceName.split("/").pop();
91
+ const serviceName = schema.name.replace(`/schemas/${types_1.SCHEMA_ID}`, "");
92
+ return {
93
+ databaseId,
94
+ instanceId,
95
+ instanceName,
96
+ serviceName,
97
+ };
98
+ }
99
+ function suggestedCommand(serviceName, invalidConnectorNames) {
100
+ const serviceId = serviceName.split("/")[5];
101
+ const connectorIds = invalidConnectorNames.map((i) => i.split("/")[7]);
102
+ const onlys = connectorIds.map((c) => `dataconnect:${serviceId}:${c}`).join(",");
103
+ return `firebase deploy --only ${onlys}`;
104
+ }
69
105
  async function handleIncompatibleSchemaError(args) {
70
- const { incompatibleSchemaError, options, instanceId, databaseId, allowNonInteractiveMigration } = args;
106
+ const { incompatibleSchemaError, options, instanceId, databaseId, choice } = args;
107
+ if (incompatibleSchemaError.destructive && choice === "safe") {
108
+ throw new error_1.FirebaseError("This schema migration includes potentially destructive changes. If you'd like to execute it anyway, rerun this command with --force");
109
+ }
71
110
  const projectId = (0, projectUtils_1.needProjectId)(options);
72
111
  const iamUser = await (0, connect_1.setupIAMUser)(instanceId, databaseId, options);
73
- const choice = await promptForSchemaMigration(options, databaseId, incompatibleSchemaError, allowNonInteractiveMigration);
74
112
  const commandsToExecute = incompatibleSchemaError.diffs
75
113
  .filter((d) => {
76
114
  switch (choice) {
@@ -104,7 +142,6 @@ async function promptForSchemaMigration(options, databaseName, err, allowNonInte
104
142
  const choices = err.destructive
105
143
  ? [
106
144
  { name: "Execute all changes (including destructive changes)", value: "all" },
107
- { name: "Execute only safe changes", value: "safe" },
108
145
  { name: "Abort changes", value: "none" },
109
146
  ]
110
147
  : [
@@ -132,23 +169,69 @@ async function promptForSchemaMigration(options, databaseName, err, allowNonInte
132
169
  return "none";
133
170
  }
134
171
  }
135
- async function ensureServiceIsConnectedToCloudSql(serviceName) {
172
+ async function promptForInvalidConnectorError(options, invalidConnectors, validateOnly) {
173
+ if (!invalidConnectors.length) {
174
+ return false;
175
+ }
176
+ displayInvalidConnectors(invalidConnectors);
177
+ if (validateOnly) {
178
+ return false;
179
+ }
180
+ else if (options.force ||
181
+ (!options.nonInteractive &&
182
+ (await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Would you like to delete and recreate these connectors?" }))))) {
183
+ return true;
184
+ }
185
+ return false;
186
+ }
187
+ async function deleteInvalidConnectors(invalidConnectors) {
188
+ return Promise.all(invalidConnectors.map(client_1.deleteConnector));
189
+ }
190
+ function displayInvalidConnectors(invalidConnectors) {
191
+ const connectorIds = invalidConnectors.map((i) => i.split("/").pop()).join(", ");
192
+ (0, utils_1.logLabeledWarning)("dataconnect", `The schema you are deploying is incompatible with the following existing connectors: ${connectorIds}.`);
193
+ (0, utils_1.logLabeledWarning)("dataconnect", `This is a ${clc.red("breaking")} change and will cause a brief downtime.`);
194
+ }
195
+ async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, databaseId) {
136
196
  let currentSchema;
137
197
  try {
138
198
  currentSchema = await (0, client_1.getSchema)(serviceName);
139
199
  }
140
200
  catch (err) {
141
201
  if (err.status === 404) {
142
- return;
202
+ currentSchema = {
203
+ name: `${serviceName}/schemas/${types_1.SCHEMA_ID}`,
204
+ source: {
205
+ files: [],
206
+ },
207
+ primaryDatasource: {
208
+ postgresql: {
209
+ database: databaseId,
210
+ cloudSql: {
211
+ instance: instanceId,
212
+ },
213
+ },
214
+ },
215
+ };
216
+ }
217
+ else {
218
+ throw err;
143
219
  }
144
- throw err;
145
220
  }
146
221
  if (!currentSchema.primaryDatasource.postgresql ||
147
222
  currentSchema.primaryDatasource.postgresql.schemaValidation === "STRICT") {
148
223
  return;
149
224
  }
150
225
  currentSchema.primaryDatasource.postgresql.schemaValidation = "STRICT";
151
- await (0, client_1.upsertSchema)(currentSchema, false);
226
+ try {
227
+ await (0, client_1.upsertSchema)(currentSchema, false);
228
+ }
229
+ catch (err) {
230
+ if (err.status >= 500) {
231
+ throw err;
232
+ }
233
+ logger_1.logger.debug(err);
234
+ }
152
235
  }
153
236
  function displaySchemaChanges(error) {
154
237
  const message = "Your new schema is incompatible with the schema of your CloudSQL database. " +
@@ -159,13 +242,3 @@ function displaySchemaChanges(error) {
159
242
  function toString(diff) {
160
243
  return `\/** ${diff.destructive ? clc.red("Destructive: ") : ""}${diff.description}*\/\n${(0, sql_formatter_1.format)(diff.sql, { language: "postgresql" })}`;
161
244
  }
162
- function getIncompatibleSchemaError(err) {
163
- var _a;
164
- const original = ((_a = err.context) === null || _a === void 0 ? void 0 : _a.body.error) || err.orignal;
165
- if (!original) {
166
- throw err;
167
- }
168
- const details = original.details;
169
- const incompatibles = details.filter((d) => d["@type"] === IMCOMPATIBLE_SCHEMA_ERROR_TYPESTRING);
170
- return incompatibles[0];
171
- }
@@ -6,7 +6,6 @@ const types_1 = require("../../dataconnect/types");
6
6
  const projectUtils_1 = require("../../projectUtils");
7
7
  const provisionCloudSql_1 = require("../../dataconnect/provisionCloudSql");
8
8
  const names_1 = require("../../dataconnect/names");
9
- const prompt_1 = require("../../prompt");
10
9
  const api_1 = require("../../api");
11
10
  const ensureApiEnabled = require("../../ensureApiEnabled");
12
11
  async function default_1(context, options) {
@@ -33,19 +32,10 @@ async function default_1(context, options) {
33
32
  utils.logLabeledSuccess("dataconnect", `Created service ${s.serviceName}`);
34
33
  }));
35
34
  if (servicesToDelete.length) {
36
- if (await (0, prompt_1.confirm)({
37
- force: options.force,
38
- nonInteractive: options.nonInteractive,
39
- message: `The following services exist on ${projectId} but are not listed in your 'firebase.json'\n${servicesToDelete
40
- .map((s) => s.name)
41
- .join("\n")}\nWould you like to delete these services?`,
42
- })) {
43
- await Promise.all(servicesToDelete.map(async (s) => {
44
- const { projectId, locationId, serviceId } = splitName(s.name);
45
- await client.deleteService(projectId, locationId, serviceId);
46
- utils.logLabeledSuccess("dataconnect", `Deleted service ${s.name}`);
47
- }));
48
- }
35
+ const warning = `The following services exist on ${projectId} but are not listed in your 'firebase.json'\n${servicesToDelete
36
+ .map((s) => s.name)
37
+ .join("\n")}\nConsider deleting these via the Firebase console if they are no longer needed.`;
38
+ utils.logLabeledWarning("dataconnect", warning);
49
39
  }
50
40
  utils.logLabeledBullet("dataconnect", "Checking for CloudSQL resources...");
51
41
  await Promise.all(serviceInfos
@@ -9,9 +9,12 @@ const projectUtils_1 = require("../../projectUtils");
9
9
  const filters_1 = require("../../dataconnect/filters");
10
10
  const build_1 = require("../../dataconnect/build");
11
11
  const ensureApis_1 = require("../../dataconnect/ensureApis");
12
+ const requireTosAcceptance_1 = require("../../requireTosAcceptance");
13
+ const firedata_1 = require("../../gcp/firedata");
12
14
  async function default_1(context, options) {
13
15
  const projectId = (0, projectUtils_1.needProjectId)(options);
14
16
  await (0, ensureApis_1.ensureApis)(projectId);
17
+ await (0, requireTosAcceptance_1.requireTosAcceptance)(firedata_1.DATA_CONNECT_TOS_ID)(options);
15
18
  const serviceCfgs = (0, fileUtils_1.readFirebaseJson)(options.config);
16
19
  utils.logLabeledBullet("dataconnect", `Preparing to deploy`);
17
20
  const filters = (0, filters_1.getResourceFilters)(options);
@@ -9,6 +9,7 @@ const types_1 = require("./types");
9
9
  const error_1 = require("../error");
10
10
  const emulatorLogger_1 = require("./emulatorLogger");
11
11
  const types_2 = require("../dataconnect/types");
12
+ const grpcDefaultPort = 9510;
12
13
  class DataConnectEmulator {
13
14
  constructor(args) {
14
15
  this.args = args;
@@ -26,7 +27,7 @@ class DataConnectEmulator {
26
27
  this.logger.logLabeled("WARN", "Data Connect", "Operations that use vector_embed will make calls to production Vertex AI");
27
28
  }
28
29
  }
29
- return (0, downloadableEmulators_1.start)(types_1.Emulators.DATACONNECT, Object.assign(Object.assign({}, this.args), { http_port: port, grpc_port: port + 1, config_dir: this.args.configDir, local_connection_string: this.getLocalConectionString(), project_id: this.args.projectId, service_location: this.args.locationId }));
30
+ return (0, downloadableEmulators_1.start)(types_1.Emulators.DATACONNECT, Object.assign(Object.assign({}, this.args), { http_port: port, grpc_port: grpcDefaultPort, config_dir: this.args.configDir, local_connection_string: this.getLocalConectionString(), project_id: this.args.projectId, service_location: this.args.locationId }));
30
31
  }
31
32
  connect() {
32
33
  return Promise.resolve();
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
24
24
  },
25
25
  firestore: {
26
- version: "1.19.5",
27
- expectedSize: 66204670,
28
- expectedChecksum: "6d9fb826605701668af722f25048ad95",
26
+ version: "1.19.6",
27
+ expectedSize: 66349770,
28
+ expectedChecksum: "2eaabbe3cdb4867df585b7ec5505bad7",
29
29
  },
30
30
  storage: {
31
31
  version: "1.1.3",
@@ -46,14 +46,14 @@ const EMULATOR_UPDATE_DETAILS = {
46
46
  },
47
47
  dataconnect: process.platform === "darwin"
48
48
  ? {
49
- version: "1.1.15",
50
- expectedSize: 25600896,
51
- expectedChecksum: "36dcf9be7273b9ba6052faf0b3c0347f",
49
+ version: "1.1.17",
50
+ expectedSize: 25602224,
51
+ expectedChecksum: "1f9e3dd040a0ac4d1cb4d9dde4a3c0b0",
52
52
  }
53
53
  : {
54
- version: "1.1.15",
55
- expectedSize: 23036688,
56
- expectedChecksum: "e42203947bf984993f295976ee3ba2be",
54
+ version: "1.1.17",
55
+ expectedSize: 23036912,
56
+ expectedChecksum: "a0ec0517108f842ed06fea14fe7c7e56",
57
57
  },
58
58
  };
59
59
  exports.DownloadDetails = {
@@ -96,6 +96,11 @@ exports.ALL_EXPERIMENTS = experiments({
96
96
  fullDescription: "Enable Data Connect related features.",
97
97
  public: false,
98
98
  },
99
+ genkit: {
100
+ shortDescription: "Enable Genkit related features.",
101
+ fullDescription: "Enable Genkit related features.",
102
+ public: false,
103
+ },
99
104
  });
100
105
  function isValidExperiment(name) {
101
106
  return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
@@ -113,27 +113,47 @@ async function createDatabase(projectId, instanceId, databaseId) {
113
113
  }
114
114
  exports.createDatabase = createDatabase;
115
115
  async function createUser(projectId, instanceId, type, username, password) {
116
- const op = await client.post(`projects/${projectId}/instances/${instanceId}/users`, {
117
- name: username,
118
- instance: instanceId,
119
- project: projectId,
120
- password: password,
121
- sqlserverUserDetails: {
122
- disabled: false,
123
- serverRoles: ["cloudsqlsuperuser"],
124
- },
125
- type,
126
- });
127
- const opName = `projects/${projectId}/operations/${op.body.name}`;
128
- const pollRes = await operationPoller.pollOperation({
129
- apiOrigin: (0, api_1.cloudSQLAdminOrigin)(),
130
- apiVersion: API_VERSION,
131
- operationResourceName: opName,
132
- doneFn: (op) => op.status === "DONE",
133
- });
134
- return pollRes;
116
+ const maxRetries = 3;
117
+ let retries = 0;
118
+ while (true) {
119
+ try {
120
+ const op = await client.post(`projects/${projectId}/instances/${instanceId}/users`, {
121
+ name: username,
122
+ instance: instanceId,
123
+ project: projectId,
124
+ password: password,
125
+ sqlserverUserDetails: {
126
+ disabled: false,
127
+ serverRoles: ["cloudsqlsuperuser"],
128
+ },
129
+ type,
130
+ });
131
+ const opName = `projects/${projectId}/operations/${op.body.name}`;
132
+ const pollRes = await operationPoller.pollOperation({
133
+ apiOrigin: (0, api_1.cloudSQLAdminOrigin)(),
134
+ apiVersion: API_VERSION,
135
+ operationResourceName: opName,
136
+ doneFn: (op) => op.status === "DONE",
137
+ });
138
+ return pollRes;
139
+ }
140
+ catch (err) {
141
+ if (builtinRoleNotReady(err.message) && retries < maxRetries) {
142
+ retries++;
143
+ await new Promise((resolve) => {
144
+ setTimeout(resolve, 1000 * retries);
145
+ });
146
+ }
147
+ else {
148
+ throw err;
149
+ }
150
+ }
151
+ }
135
152
  }
136
153
  exports.createUser = createUser;
154
+ function builtinRoleNotReady(message) {
155
+ return message.includes("cloudsqliamuser");
156
+ }
137
157
  async function getUser(projectId, instanceId, username) {
138
158
  const res = await client.get(`projects/${projectId}/instances/${instanceId}/users/${username}`);
139
159
  return res.body;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isProductTosAccepted = exports.getAcceptanceStatus = exports.getTosStatus = exports.APP_CHECK_TOS_ID = exports.APPHOSTING_TOS_ID = void 0;
3
+ exports.isProductTosAccepted = exports.getAcceptanceStatus = exports.getTosStatus = exports.DATA_CONNECT_TOS_ID = exports.APP_CHECK_TOS_ID = exports.APPHOSTING_TOS_ID = void 0;
4
4
  const apiv2_1 = require("../apiv2");
5
5
  const api_1 = require("../api");
6
6
  const error_1 = require("../error");
7
7
  const client = new apiv2_1.Client({ urlPrefix: (0, api_1.firedataOrigin)(), auth: true, apiVersion: "v1" });
8
8
  exports.APPHOSTING_TOS_ID = "APP_HOSTING_TOS";
9
9
  exports.APP_CHECK_TOS_ID = "APP_CHECK";
10
+ exports.DATA_CONNECT_TOS_ID = "FIREBASE_DATA_CONNECT";
10
11
  async function getTosStatus() {
11
12
  const res = await client.get("accessmanagement/tos:getStatus");
12
13
  return res.body;
@@ -15,7 +16,7 @@ exports.getTosStatus = getTosStatus;
15
16
  function getAcceptanceStatus(response, tosId) {
16
17
  const perServiceStatus = response.perServiceStatus.find((tosStatus) => tosStatus.tosId === tosId);
17
18
  if (perServiceStatus === undefined) {
18
- throw new error_1.FirebaseError(`Missing terms of service status for product: ${tosId}`);
19
+ throw new error_1.FirebaseError(`Missing terms of service status for product: ${tosId}`);
19
20
  }
20
21
  return perServiceStatus.serviceStatus.status;
21
22
  }
@@ -5,9 +5,11 @@ const path_1 = require("path");
5
5
  const prompt_1 = require("../../../prompt");
6
6
  const fs_1 = require("fs");
7
7
  const provisionCloudSql_1 = require("../../../dataconnect/provisionCloudSql");
8
+ const freeTrial_1 = require("../../../dataconnect/freeTrial");
8
9
  const cloudsql = require("../../../gcp/cloudsql/cloudsqladmin");
9
10
  const ensureApis_1 = require("../../../dataconnect/ensureApis");
10
11
  const client_1 = require("../../../dataconnect/client");
12
+ const emulators_1 = require("../emulators");
11
13
  const TEMPLATE_ROOT = (0, path_1.resolve)(__dirname, "../../../../templates/init/dataconnect/");
12
14
  const DATACONNECT_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "dataconnect.yaml"), "utf8");
13
15
  const CONNECTOR_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "connector.yaml"), "utf8");
@@ -24,61 +26,65 @@ async function doSetup(setup, config) {
24
26
  type: "input",
25
27
  default: "dataconnect",
26
28
  });
27
- let locationOptions = [
28
- { name: "us-central1", value: "us-central1" },
29
- { name: "europe-north1", value: "europe-north1" },
30
- { name: "europe-central2", value: "europe-central2" },
31
- { name: "europe-west1", value: "europe-west1" },
32
- { name: "southamerica-west1", value: "southamerica-west1" },
33
- { name: "us-east4", value: "us-east4" },
34
- { name: "us-west1", value: "us-west1" },
35
- { name: "asia-southeast1", value: "asia-southeast1" },
36
- ];
37
- if (setup.projectId) {
38
- const locations = await (0, client_1.listLocations)(setup.projectId);
39
- locationOptions = locations.map((l) => {
40
- return { name: l, value: l };
41
- });
42
- }
43
- const locationId = await (0, prompt_1.promptOnce)({
44
- message: "What location would you like to deploy this service into?",
45
- type: "list",
46
- choices: locationOptions,
47
- });
48
29
  const connectorId = await (0, prompt_1.promptOnce)({
49
30
  message: "What ID would you like to use for your connector?",
50
31
  type: "input",
51
32
  default: "my-connector",
52
33
  });
53
- const dir = config.get("dataconnect.source") || "dataconnect";
54
- if (!config.has("dataconnect")) {
55
- config.set("dataconnect.source", dir);
56
- config.set("dataconnect.location", locationId);
57
- }
58
34
  let cloudSqlInstanceId = "";
59
35
  let newInstance = false;
36
+ let locationId = "";
60
37
  if (setup.projectId) {
61
38
  const instances = await cloudsql.listInstances(setup.projectId);
62
- const instancesInLocation = instances.filter((i) => i.region === locationId);
63
- const choices = instancesInLocation.map((i) => {
64
- return { name: i.name, value: i.name };
39
+ const choices = instances.map((i) => {
40
+ return { name: i.name, value: i.name, location: i.region };
65
41
  });
66
- choices.push({ name: "Create a new instance", value: "" });
67
- if (instancesInLocation.length) {
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) {
68
47
  cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
69
- message: `Which CloudSSQL in ${locationId} would you like to use?`,
48
+ message: `Which CloudSSQL instance would you like to use?`,
70
49
  type: "list",
71
50
  choices,
72
51
  });
73
52
  }
53
+ locationId = choices.find((c) => c.value === cloudSqlInstanceId).location;
74
54
  }
75
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
+ }
76
72
  newInstance = true;
77
73
  cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
78
74
  message: `What ID would you like to use for your new CloudSQL instance?`,
79
75
  type: "input",
80
76
  default: `dataconnect-test`,
81
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);
82
88
  }
83
89
  let cloudSqlDatabase = "";
84
90
  let newDB = false;
@@ -104,7 +110,7 @@ async function doSetup(setup, config) {
104
110
  default: `dataconnect`,
105
111
  });
106
112
  }
107
- 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 : "postgresql://localhost:5432?sslmode=disable";
113
+ 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;
108
114
  const localConnectionString = await (0, prompt_1.promptOnce)({
109
115
  type: "input",
110
116
  name: "localConnectionString",
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.doSetup = void 0;
3
+ exports.doSetup = exports.DEFAULT_POSTGRES_CONNECTION = void 0;
4
4
  const clc = require("colorette");
5
5
  const _ = require("lodash");
6
6
  const utils = require("../../utils");
@@ -8,6 +8,7 @@ const prompt_1 = require("../../prompt");
8
8
  const types_1 = require("../../emulator/types");
9
9
  const constants_1 = require("../../emulator/constants");
10
10
  const downloadableEmulators_1 = require("../../emulator/downloadableEmulators");
11
+ exports.DEFAULT_POSTGRES_CONNECTION = "postgresql://localhost:5432?sslmode=disable";
11
12
  async function doSetup(setup, config) {
12
13
  var _a, _b, _c;
13
14
  const choices = types_1.ALL_SERVICE_EMULATORS.map((e) => {
@@ -78,15 +79,13 @@ async function doSetup(setup, config) {
78
79
  }
79
80
  }
80
81
  if (selections.emulators.includes(types_1.Emulators.DATACONNECT)) {
81
- 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 : "postgresql://localhost:5432";
82
- const localConnectionString = await (0, prompt_1.prompt)(setup.config.emulators[types_1.Emulators.DATACONNECT], [
83
- {
84
- type: "input",
85
- name: "localConnectionString",
86
- message: `What is the connection string of the local Postgres instance you would like to use with the Data Connect emulator?`,
87
- default: defaultConnectionString,
88
- },
89
- ]);
82
+ 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 : exports.DEFAULT_POSTGRES_CONNECTION;
83
+ const localConnectionString = await (0, prompt_1.promptOnce)({
84
+ type: "input",
85
+ name: "localConnectionString",
86
+ message: `What is the connection string of the local Postgres instance you would like to use with the Data Connect emulator?`,
87
+ default: defaultConnectionString,
88
+ });
90
89
  setup.rcfile.dataconnectEmulatorConfig = { postgres: { localConnectionString } };
91
90
  }
92
91
  await (0, prompt_1.prompt)(selections, [
@@ -130,6 +130,9 @@ async function overwriteCodebase(setup, config) {
130
130
  return languageSetup(setup, config);
131
131
  }
132
132
  async function languageSetup(setup, config) {
133
+ if (setup.languageOverride) {
134
+ return require("./" + setup.languageOverride).setup(setup, config);
135
+ }
133
136
  const choices = [
134
137
  {
135
138
  name: "JavaScript",
@@ -174,5 +177,6 @@ async function languageSetup(setup, config) {
174
177
  cbconfig.ignore = ["venv", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"];
175
178
  break;
176
179
  }
180
+ setup.functions.languageChoice = language;
177
181
  return require("./" + language).setup(setup, config);
178
182
  }