firebase-tools 13.17.0 → 13.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +10 -9
  2. package/lib/commands/dataconnect-services-list.js +4 -3
  3. package/lib/commands/dataconnect-sql-grant.js +37 -0
  4. package/lib/commands/dataconnect-sql-migrate.js +2 -1
  5. package/lib/commands/deploy.js +2 -0
  6. package/lib/commands/ext-info.js +3 -1
  7. package/lib/commands/ext-sdk-install.js +88 -0
  8. package/lib/commands/ext.js +1 -0
  9. package/lib/commands/index.js +3 -0
  10. package/lib/dataconnect/client.js +1 -1
  11. package/lib/dataconnect/dataplaneClient.js +1 -1
  12. package/lib/dataconnect/ensureApis.js +6 -1
  13. package/lib/dataconnect/load.js +3 -1
  14. package/lib/dataconnect/provisionCloudSql.js +34 -21
  15. package/lib/dataconnect/schemaMigration.js +126 -73
  16. package/lib/deploy/dataconnect/deploy.js +16 -13
  17. package/lib/deploy/dataconnect/prepare.js +36 -0
  18. package/lib/deploy/dataconnect/release.js +9 -2
  19. package/lib/deploy/extensions/deploymentSummary.js +3 -2
  20. package/lib/deploy/extensions/planner.js +32 -3
  21. package/lib/deploy/extensions/prepare.js +36 -64
  22. package/lib/deploy/extensions/release.js +11 -10
  23. package/lib/deploy/extensions/tasks.js +32 -21
  24. package/lib/deploy/firestore/prepare.js +10 -0
  25. package/lib/deploy/firestore/release.js +3 -6
  26. package/lib/deploy/functions/checkIam.js +7 -2
  27. package/lib/deploy/functions/ensure.js +10 -2
  28. package/lib/deploy/functions/prepare.js +10 -2
  29. package/lib/deploy/functions/runtimes/node/index.js +1 -1
  30. package/lib/deploy/index.js +9 -5
  31. package/lib/emulator/downloadableEmulators.js +9 -9
  32. package/lib/extensions/extensionsApi.js +3 -2
  33. package/lib/extensions/extensionsHelper.js +3 -3
  34. package/lib/extensions/localHelper.js +31 -0
  35. package/lib/extensions/runtimes/common.js +186 -38
  36. package/lib/extensions/runtimes/node.js +399 -0
  37. package/lib/extensions/types.js +10 -14
  38. package/lib/extensions/warnings.js +5 -2
  39. package/lib/firestore/checkDatabaseType.js +10 -3
  40. package/lib/frameworks/angular/index.js +15 -3
  41. package/lib/frameworks/next/utils.js +1 -1
  42. package/lib/gcp/cloudsql/permissions.js +6 -1
  43. package/lib/gcp/secretManager.js +12 -5
  44. package/lib/init/features/dataconnect/index.js +66 -53
  45. package/lib/init/features/firestore/index.js +20 -1
  46. package/lib/init/features/firestore/indexes.js +4 -4
  47. package/package.json +1 -1
  48. package/schema/connector-yaml.json +43 -17
  49. package/templates/init/dataconnect/connector.yaml +0 -1
  50. package/templates/init/dataconnect/dataconnect-fdccompatiblemode.yaml +12 -0
  51. package/templates/init/dataconnect/dataconnect.yaml +1 -1
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.migrateSchema = exports.diffSchema = void 0;
3
+ exports.grantRoleToUserInSchema = exports.migrateSchema = exports.diffSchema = void 0;
4
4
  const clc = require("colorette");
5
5
  const sql_formatter_1 = require("sql-formatter");
6
6
  const types_1 = require("./types");
7
7
  const client_1 = require("./client");
8
8
  const connect_1 = require("../gcp/cloudsql/connect");
9
9
  const permissions_1 = require("../gcp/cloudsql/permissions");
10
+ const cloudSqlAdminClient = require("../gcp/cloudsql/cloudsqladmin");
11
+ const projectUtils_1 = require("../projectUtils");
10
12
  const prompt_1 = require("../prompt");
11
13
  const logger_1 = require("../logger");
12
14
  const error_1 = require("../error");
@@ -17,15 +19,9 @@ async function diffSchema(schema, schemaValidation) {
17
19
  const { serviceName, instanceName, databaseId } = getIdentifiers(schema);
18
20
  await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, false);
19
21
  let diffs = [];
20
- let validationMode = "STRICT";
21
- if (experiments.isEnabled("fdccompatiblemode")) {
22
- if (!schemaValidation) {
23
- validationMode = "COMPATIBLE";
24
- }
25
- else {
26
- validationMode = schemaValidation;
27
- }
28
- }
22
+ let validationMode = experiments.isEnabled("fdccompatiblemode")
23
+ ? schemaValidation !== null && schemaValidation !== void 0 ? schemaValidation : "COMPATIBLE"
24
+ : "STRICT";
29
25
  setSchemaValidationMode(schema, validationMode);
30
26
  try {
31
27
  if (!schemaValidation && experiments.isEnabled("fdccompatiblemode")) {
@@ -56,33 +52,31 @@ async function diffSchema(schema, schemaValidation) {
56
52
  diffs = incompatible.diffs;
57
53
  }
58
54
  }
59
- if (experiments.isEnabled("fdccompatiblemode")) {
60
- if (!schemaValidation) {
61
- validationMode = "STRICT";
62
- setSchemaValidationMode(schema, validationMode);
63
- try {
64
- (0, utils_1.logLabeledBullet)("dataconnect", `generating schema changes, including optional changes...`);
65
- await (0, client_1.upsertSchema)(schema, true);
66
- (0, utils_1.logLabeledSuccess)("dataconnect", `no additional optional changes`);
55
+ if (experiments.isEnabled("fdccompatiblemode") && !schemaValidation) {
56
+ validationMode = "STRICT";
57
+ setSchemaValidationMode(schema, validationMode);
58
+ try {
59
+ (0, utils_1.logLabeledBullet)("dataconnect", `generating schema changes, including optional changes...`);
60
+ await (0, client_1.upsertSchema)(schema, true);
61
+ (0, utils_1.logLabeledSuccess)("dataconnect", `no additional optional changes`);
62
+ }
63
+ catch (err) {
64
+ if ((err === null || err === void 0 ? void 0 : err.status) !== 400) {
65
+ throw err;
67
66
  }
68
- catch (err) {
69
- if ((err === null || err === void 0 ? void 0 : err.status) !== 400) {
70
- throw err;
71
- }
72
- const incompatible = errors.getIncompatibleSchemaError(err);
73
- if (incompatible) {
74
- if (!diffsEqual(diffs, incompatible.diffs)) {
75
- if (diffs.length === 0) {
76
- displaySchemaChanges(incompatible, "STRICT_AFTER_COMPATIBLE", instanceName, databaseId);
77
- }
78
- else {
79
- displaySchemaChanges(incompatible, validationMode, instanceName, databaseId);
80
- }
81
- diffs = incompatible.diffs;
67
+ const incompatible = errors.getIncompatibleSchemaError(err);
68
+ if (incompatible) {
69
+ if (!diffsEqual(diffs, incompatible.diffs)) {
70
+ if (diffs.length === 0) {
71
+ displaySchemaChanges(incompatible, "STRICT_AFTER_COMPATIBLE", instanceName, databaseId);
82
72
  }
83
73
  else {
84
- (0, utils_1.logLabeledSuccess)("dataconnect", `no additional optional changes`);
74
+ displaySchemaChanges(incompatible, validationMode, instanceName, databaseId);
85
75
  }
76
+ diffs = incompatible.diffs;
77
+ }
78
+ else {
79
+ (0, utils_1.logLabeledSuccess)("dataconnect", `no additional optional changes`);
86
80
  }
87
81
  }
88
82
  }
@@ -91,10 +85,13 @@ async function diffSchema(schema, schemaValidation) {
91
85
  }
92
86
  exports.diffSchema = diffSchema;
93
87
  async function migrateSchema(args) {
94
- const { options, schema, validateOnly } = args;
88
+ const { options, schema, validateOnly, schemaValidation } = args;
95
89
  const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema);
96
90
  await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, true);
97
- const validationMode = experiments.isEnabled("fdccompatiblemode") ? "COMPATIBLE" : "STRICT";
91
+ let diffs = [];
92
+ let validationMode = experiments.isEnabled("fdccompatiblemode")
93
+ ? schemaValidation !== null && schemaValidation !== void 0 ? schemaValidation : "COMPATIBLE"
94
+ : "STRICT";
98
95
  setSchemaValidationMode(schema, validationMode);
99
96
  try {
100
97
  await (0, client_1.upsertSchema)(schema, validateOnly);
@@ -111,7 +108,6 @@ async function migrateSchema(args) {
111
108
  }
112
109
  const migrationMode = await promptForSchemaMigration(options, instanceName, databaseId, incompatible, validateOnly, validationMode);
113
110
  const shouldDeleteInvalidConnectors = await promptForInvalidConnectorError(options, serviceName, invalidConnectors, validateOnly);
114
- let diffs = [];
115
111
  if (incompatible) {
116
112
  diffs = await handleIncompatibleSchemaError({
117
113
  options,
@@ -127,11 +123,54 @@ async function migrateSchema(args) {
127
123
  if (!validateOnly) {
128
124
  await (0, client_1.upsertSchema)(schema, validateOnly);
129
125
  }
130
- return diffs;
131
126
  }
132
- return [];
127
+ if (experiments.isEnabled("fdccompatiblemode") && !schemaValidation) {
128
+ validationMode = "STRICT";
129
+ setSchemaValidationMode(schema, validationMode);
130
+ try {
131
+ await (0, client_1.upsertSchema)(schema, validateOnly);
132
+ }
133
+ catch (err) {
134
+ if (err.status !== 400) {
135
+ throw err;
136
+ }
137
+ const incompatible = errors.getIncompatibleSchemaError(err);
138
+ const invalidConnectors = errors.getInvalidConnectors(err);
139
+ if (!incompatible && !invalidConnectors.length) {
140
+ throw err;
141
+ }
142
+ const migrationMode = await promptForSchemaMigration(options, instanceName, databaseId, incompatible, validateOnly, "STRICT_AFTER_COMPATIBLE");
143
+ if (incompatible) {
144
+ const maybeDiffs = await handleIncompatibleSchemaError({
145
+ options,
146
+ databaseId,
147
+ instanceId,
148
+ incompatibleSchemaError: incompatible,
149
+ choice: migrationMode,
150
+ });
151
+ diffs = diffs.concat(maybeDiffs);
152
+ }
153
+ }
154
+ }
155
+ return diffs;
133
156
  }
134
157
  exports.migrateSchema = migrateSchema;
158
+ async function grantRoleToUserInSchema(options, schema) {
159
+ const role = options.role;
160
+ const email = options.email;
161
+ const { instanceId, databaseId } = getIdentifiers(schema);
162
+ const projectId = (0, projectUtils_1.needProjectId)(options);
163
+ const { user, mode } = (0, connect_1.toDatabaseUser)(email);
164
+ const fdcSqlRole = permissions_1.fdcSqlRoleMap[role](databaseId);
165
+ const userIsCSQLAdmin = await (0, permissions_1.iamUserIsCSQLAdmin)(options);
166
+ if (!userIsCSQLAdmin) {
167
+ throw new error_1.FirebaseError(`Only users with 'roles/cloudsql.admin' can grant SQL roles. If you do not have this role, ask your database administrator to run this command or manually grant ${fdcSqlRole} to ${user}`);
168
+ }
169
+ await (0, connect_1.setupIAMUsers)(instanceId, databaseId, options);
170
+ await cloudSqlAdminClient.createUser(projectId, instanceId, mode, user);
171
+ await (0, connect_1.executeSqlCmdsAsSuperUser)(options, instanceId, databaseId, [`GRANT "${fdcSqlRole}" TO "${user}"`], false);
172
+ }
173
+ exports.grantRoleToUserInSchema = grantRoleToUserInSchema;
135
174
  function diffsEqual(x, y) {
136
175
  if (x.length !== y.length) {
137
176
  return false;
@@ -146,17 +185,21 @@ function diffsEqual(x, y) {
146
185
  return true;
147
186
  }
148
187
  function setSchemaValidationMode(schema, schemaValidation) {
149
- if (experiments.isEnabled("fdccompatiblemode") && schema.primaryDatasource.postgresql) {
150
- schema.primaryDatasource.postgresql.schemaValidation = schemaValidation;
188
+ if (experiments.isEnabled("fdccompatiblemode")) {
189
+ const postgresDatasource = schema.datasources.find((d) => d.postgresql);
190
+ if (postgresDatasource === null || postgresDatasource === void 0 ? void 0 : postgresDatasource.postgresql) {
191
+ postgresDatasource.postgresql.schemaValidation = schemaValidation;
192
+ }
151
193
  }
152
194
  }
153
195
  function getIdentifiers(schema) {
154
196
  var _a, _b;
155
- const databaseId = (_a = schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.database;
197
+ const postgresDatasource = schema.datasources.find((d) => d.postgresql);
198
+ const databaseId = (_a = postgresDatasource === null || postgresDatasource === void 0 ? void 0 : postgresDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.database;
156
199
  if (!databaseId) {
157
- throw new error_1.FirebaseError("Schema is missing primaryDatasource.postgresql?.database, cannot migrate");
200
+ throw new error_1.FirebaseError("Service does not have a postgres datasource, cannot migrate");
158
201
  }
159
- const instanceName = (_b = schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance;
202
+ const instanceName = (_b = postgresDatasource === null || postgresDatasource === void 0 ? void 0 : postgresDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance;
160
203
  if (!instanceName) {
161
204
  throw new error_1.FirebaseError("tried to migrate schema but instance name was not provided in dataconnect.yaml");
162
205
  }
@@ -218,28 +261,38 @@ async function handleIncompatibleSchemaError(args) {
218
261
  }
219
262
  return [];
220
263
  }
221
- async function promptForSchemaMigration(options, instanceName, databaseId, err, validateOnly, schemaValidation) {
264
+ async function promptForSchemaMigration(options, instanceName, databaseId, err, validateOnly, validationMode) {
222
265
  if (!err) {
223
266
  return "none";
224
267
  }
225
- displaySchemaChanges(err, schemaValidation, instanceName, databaseId);
268
+ if (validationMode === "STRICT_AFTER_COMPATIBLE" && (options.nonInteractive || options.force)) {
269
+ return "none";
270
+ }
271
+ displaySchemaChanges(err, validationMode, instanceName, databaseId);
226
272
  if (!options.nonInteractive) {
227
273
  if (validateOnly && options.force) {
228
274
  return "all";
229
275
  }
230
- const choices = err.destructive
231
- ? [
232
- { name: "Execute all changes (including destructive changes)", value: "all" },
233
- { name: "Abort changes", value: "none" },
234
- ]
235
- : [
236
- { name: "Execute changes", value: "all" },
237
- { name: "Abort changes", value: "none" },
238
- ];
276
+ const message = validationMode === "STRICT_AFTER_COMPATIBLE"
277
+ ? `Would you like to execute these optional changes against ${databaseId} in your CloudSQL instance ${instanceName}?`
278
+ : `Would you like to execute these changes against ${databaseId} in your CloudSQL instance ${instanceName}?`;
279
+ let executeChangePrompt = "Execute changes";
280
+ if (validationMode === "STRICT_AFTER_COMPATIBLE") {
281
+ executeChangePrompt = "Execute optional changes";
282
+ }
283
+ if (err.destructive) {
284
+ executeChangePrompt = executeChangePrompt + " (including destructive changes)";
285
+ }
286
+ const choices = [
287
+ { name: executeChangePrompt, value: "all" },
288
+ { name: "Abort changes", value: "none" },
289
+ ];
290
+ const defaultValue = validationMode === "STRICT_AFTER_COMPATIBLE" ? "none" : "all";
239
291
  return await (0, prompt_1.promptOnce)({
240
- message: `Would you like to execute these changes against ${databaseId}?`,
292
+ message: message,
241
293
  type: "list",
242
294
  choices,
295
+ default: defaultValue,
243
296
  });
244
297
  }
245
298
  if (!validateOnly) {
@@ -261,10 +314,7 @@ async function promptForInvalidConnectorError(options, serviceName, invalidConne
261
314
  }
262
315
  displayInvalidConnectors(invalidConnectors);
263
316
  if (validateOnly) {
264
- if (options.force) {
265
- return false;
266
- }
267
- throw new error_1.FirebaseError(`Command aborted. If you'd like to migrate it anyway, you may override with --force.`);
317
+ return false;
268
318
  }
269
319
  if (options.force) {
270
320
  return true;
@@ -297,17 +347,20 @@ async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, datab
297
347
  source: {
298
348
  files: [],
299
349
  },
300
- primaryDatasource: {
301
- postgresql: {
302
- database: databaseId,
303
- cloudSql: {
304
- instance: instanceId,
350
+ datasources: [
351
+ {
352
+ postgresql: {
353
+ database: databaseId,
354
+ cloudSql: {
355
+ instance: instanceId,
356
+ },
305
357
  },
306
358
  },
307
- },
359
+ ],
308
360
  };
309
361
  }
310
- const postgresql = currentSchema.primaryDatasource.postgresql;
362
+ const postgresDatasource = currentSchema.datasources.find((d) => d.postgresql);
363
+ const postgresql = postgresDatasource === null || postgresDatasource === void 0 ? void 0 : postgresDatasource.postgresql;
311
364
  if ((postgresql === null || postgresql === void 0 ? void 0 : postgresql.cloudSql.instance) !== instanceId) {
312
365
  (0, utils_1.logLabeledWarning)("dataconnect", `Switching connected Cloud SQL instance\nFrom ${postgresql === null || postgresql === void 0 ? void 0 : postgresql.cloudSql.instance}\nTo ${instanceId}`);
313
366
  }
@@ -328,22 +381,22 @@ async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, datab
328
381
  logger_1.logger.debug(err);
329
382
  }
330
383
  }
331
- function displaySchemaChanges(error, schemaValidation, instanceName, databaseId) {
384
+ function displaySchemaChanges(error, validationMode, instanceName, databaseId) {
332
385
  switch (error.violationType) {
333
386
  case "INCOMPATIBLE_SCHEMA":
334
387
  {
335
388
  let message;
336
- if (schemaValidation === "COMPATIBLE") {
389
+ if (validationMode === "COMPATIBLE") {
337
390
  message =
338
- "Your new application schema is incompatible with the schema of your PostgreSQL database " +
391
+ "Your PostgreSQL database " +
339
392
  databaseId +
340
393
  " in your CloudSQL instance " +
341
394
  instanceName +
342
- ". " +
395
+ " must be migrated in order to be compatible with your application schema. " +
343
396
  "The following SQL statements will migrate your database schema to be compatible with your new Data Connect schema.\n" +
344
397
  error.diffs.map(toString).join("\n");
345
398
  }
346
- else if (schemaValidation === "STRICT_AFTER_COMPATIBLE") {
399
+ else if (validationMode === "STRICT_AFTER_COMPATIBLE") {
347
400
  message =
348
401
  "Your new application schema is compatible with the schema of your PostgreSQL database " +
349
402
  databaseId +
@@ -355,11 +408,11 @@ function displaySchemaChanges(error, schemaValidation, instanceName, databaseId)
355
408
  }
356
409
  else {
357
410
  message =
358
- "Your new application schema does not match the schema of your PostgreSQL database " +
411
+ "Your PostgreSQL database " +
359
412
  databaseId +
360
413
  " in your CloudSQL instance " +
361
414
  instanceName +
362
- ". " +
415
+ " must be migrated in order to match your application schema. " +
363
416
  "The following SQL statements will migrate your database schema to match your new Data Connect schema.\n" +
364
417
  error.diffs.map(toString).join("\n");
365
418
  }
@@ -44,20 +44,23 @@ async function default_1(context, options) {
44
44
  })
45
45
  .map(async (s) => {
46
46
  var _a, _b;
47
- const instanceId = (_a = s.schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance.split("/").pop();
48
- const databaseId = (_b = s.schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.database;
49
- if (!instanceId || !databaseId) {
50
- return Promise.resolve();
47
+ const postgresDatasource = s.schema.datasources.find((d) => d.postgresql);
48
+ if (postgresDatasource) {
49
+ const instanceId = (_a = postgresDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance.split("/").pop();
50
+ const databaseId = (_b = postgresDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.database;
51
+ if (!instanceId || !databaseId) {
52
+ return Promise.resolve();
53
+ }
54
+ const enableGoogleMlIntegration = (0, types_1.requiresVector)(s.deploymentMetadata);
55
+ return (0, provisionCloudSql_1.provisionCloudSql)({
56
+ projectId,
57
+ locationId: (0, names_1.parseServiceName)(s.serviceName).location,
58
+ instanceId,
59
+ databaseId,
60
+ enableGoogleMlIntegration,
61
+ waitForCreation: true,
62
+ });
51
63
  }
52
- const enableGoogleMlIntegration = (0, types_1.requiresVector)(s.deploymentMetadata);
53
- return (0, provisionCloudSql_1.provisionCloudSql)({
54
- projectId,
55
- locationId: (0, names_1.parseServiceName)(s.serviceName).location,
56
- instanceId,
57
- databaseId,
58
- enableGoogleMlIntegration,
59
- waitForCreation: true,
60
- });
61
64
  }));
62
65
  return;
63
66
  }
@@ -11,8 +11,13 @@ const build_1 = require("../../dataconnect/build");
11
11
  const ensureApis_1 = require("../../dataconnect/ensureApis");
12
12
  const requireTosAcceptance_1 = require("../../requireTosAcceptance");
13
13
  const firedata_1 = require("../../gcp/firedata");
14
+ const provisionCloudSql_1 = require("../../dataconnect/provisionCloudSql");
15
+ const names_1 = require("../../dataconnect/names");
14
16
  const error_1 = require("../../error");
17
+ const types_1 = require("../../dataconnect/types");
18
+ const schemaMigration_1 = require("../../dataconnect/schemaMigration");
15
19
  async function default_1(context, options) {
20
+ var _a;
16
21
  const projectId = (0, projectUtils_1.needProjectId)(options);
17
22
  await (0, ensureApis_1.ensureApis)(projectId);
18
23
  await (0, requireTosAcceptance_1.requireTosAcceptance)(firedata_1.DATA_CONNECT_TOS_ID)(options);
@@ -41,6 +46,37 @@ async function default_1(context, options) {
41
46
  filters,
42
47
  };
43
48
  utils.logLabeledBullet("dataconnect", `Successfully prepared schema and connectors`);
49
+ if (options.dryRun) {
50
+ for (const si of serviceInfos) {
51
+ await (0, schemaMigration_1.diffSchema)(si.schema, (_a = si.dataConnectYaml.schema.datasource.postgresql) === null || _a === void 0 ? void 0 : _a.schemaValidation);
52
+ }
53
+ utils.logLabeledBullet("dataconnect", "Checking for CloudSQL resources...");
54
+ await Promise.all(serviceInfos
55
+ .filter((si) => {
56
+ return !filters || (filters === null || filters === void 0 ? void 0 : filters.some((f) => si.dataConnectYaml.serviceId === f.serviceId));
57
+ })
58
+ .map(async (s) => {
59
+ var _a, _b;
60
+ const postgresDatasource = s.schema.datasources.find((d) => d.postgresql);
61
+ if (postgresDatasource) {
62
+ const instanceId = (_a = postgresDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance.split("/").pop();
63
+ const databaseId = (_b = postgresDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.database;
64
+ if (!instanceId || !databaseId) {
65
+ return Promise.resolve();
66
+ }
67
+ const enableGoogleMlIntegration = (0, types_1.requiresVector)(s.deploymentMetadata);
68
+ return (0, provisionCloudSql_1.provisionCloudSql)({
69
+ projectId,
70
+ locationId: (0, names_1.parseServiceName)(s.serviceName).location,
71
+ instanceId,
72
+ databaseId,
73
+ enableGoogleMlIntegration,
74
+ waitForCreation: true,
75
+ dryRun: options.dryRun,
76
+ });
77
+ }
78
+ }));
79
+ }
44
80
  logger_1.logger.debug(JSON.stringify(context.dataconnect, null, 2));
45
81
  return;
46
82
  }
@@ -14,14 +14,21 @@ async function default_1(context, options) {
14
14
  return f.serviceId === si.dataConnectYaml.serviceId && (f.schemaOnly || f.fullService);
15
15
  }));
16
16
  })
17
- .map((s) => s.schema);
17
+ .map((s) => {
18
+ var _a;
19
+ return ({
20
+ schema: s.schema,
21
+ validationMode: (_a = s.dataConnectYaml.schema.datasource.postgresql) === null || _a === void 0 ? void 0 : _a.schemaValidation,
22
+ });
23
+ });
18
24
  if (wantSchemas.length) {
19
25
  utils.logLabeledBullet("dataconnect", "Releasing Data Connect schemas...");
20
26
  for (const s of wantSchemas) {
21
27
  await (0, schemaMigration_1.migrateSchema)({
22
28
  options,
23
- schema: s,
29
+ schema: s.schema,
24
30
  validateOnly: false,
31
+ schemaValidation: s.validationMode,
25
32
  });
26
33
  }
27
34
  utils.logLabeledBullet("dataconnect", "Schemas released.");
@@ -47,10 +47,11 @@ function configuresSummary(toConfigure) {
47
47
  : "";
48
48
  }
49
49
  exports.configuresSummary = configuresSummary;
50
- function deletesSummary(toDelete) {
50
+ function deletesSummary(toDelete, isDynamic) {
51
51
  const instancesToDelete = toDelete.map((s) => `\t${(0, exports.humanReadable)(s)}`).join("\n");
52
+ const definedLocation = isDynamic ? "your local source code" : "'firebase.json'";
52
53
  return toDelete.length
53
- ? `The following extension instances are not listed in 'firebase.json':\n${instancesToDelete}\n`
54
+ ? `The following extension instances are found in your project but do not exist in ${definedLocation}:\n${instancesToDelete}\n`
54
55
  : "";
55
56
  }
56
57
  exports.deletesSummary = deletesSummary;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveVersion = exports.want = exports.wantDynamic = exports.have = exports.getExtensionSpec = exports.getExtension = exports.getExtensionVersion = void 0;
3
+ exports.resolveVersion = exports.want = exports.wantDynamic = exports.have = exports.haveDynamic = exports.getExtensionSpec = exports.getExtension = exports.getExtensionVersion = void 0;
4
4
  const semver = require("semver");
5
5
  const extensionsApi = require("../../extensions/extensionsApi");
6
6
  const refs = require("../../extensions/refs");
@@ -49,9 +49,33 @@ async function getExtensionSpec(i) {
49
49
  return i.extensionSpec;
50
50
  }
51
51
  exports.getExtensionSpec = getExtensionSpec;
52
+ async function haveDynamic(projectId) {
53
+ return (await extensionsApi.listInstances(projectId))
54
+ .filter((i) => { var _a; return ((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"; })
55
+ .map((i) => {
56
+ var _a;
57
+ const dep = {
58
+ instanceId: i.name.split("/").pop(),
59
+ params: i.config.params,
60
+ systemParams: (_a = i.config.systemParams) !== null && _a !== void 0 ? _a : {},
61
+ allowedEventTypes: i.config.allowedEventTypes,
62
+ eventarcChannel: i.config.eventarcChannel,
63
+ etag: i.etag,
64
+ labels: i.labels,
65
+ };
66
+ if (i.config.extensionRef) {
67
+ const ref = refs.parse(i.config.extensionRef);
68
+ dep.ref = ref;
69
+ dep.ref.version = i.config.extensionVersion;
70
+ }
71
+ return dep;
72
+ });
73
+ }
74
+ exports.haveDynamic = haveDynamic;
52
75
  async function have(projectId) {
53
- const instances = await extensionsApi.listInstances(projectId);
54
- return instances.map((i) => {
76
+ return (await extensionsApi.listInstances(projectId))
77
+ .filter((i) => { var _a; return !(((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"); })
78
+ .map((i) => {
55
79
  var _a;
56
80
  const dep = {
57
81
  instanceId: i.name.split("/").pop(),
@@ -61,6 +85,9 @@ async function have(projectId) {
61
85
  eventarcChannel: i.config.eventarcChannel,
62
86
  etag: i.etag,
63
87
  };
88
+ if (i.labels) {
89
+ dep.labels = i.labels;
90
+ }
64
91
  if (i.config.extensionRef) {
65
92
  const ref = refs.parse(i.config.extensionRef);
66
93
  dep.ref = ref;
@@ -97,6 +124,7 @@ async function wantDynamic(args) {
97
124
  systemParams,
98
125
  allowedEventTypes,
99
126
  eventarcChannel,
127
+ labels: ext.labels,
100
128
  });
101
129
  }
102
130
  else if (ext.ref) {
@@ -107,6 +135,7 @@ async function wantDynamic(args) {
107
135
  systemParams,
108
136
  allowedEventTypes,
109
137
  eventarcChannel,
138
+ labels: ext.labels,
110
139
  });
111
140
  }
112
141
  }