firebase-tools 13.19.0 → 13.20.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.
Files changed (57) hide show
  1. package/lib/apiv2.js +8 -1
  2. package/lib/auth.js +14 -2
  3. package/lib/commands/dataconnect-sdk-generate.js +5 -2
  4. package/lib/commands/emulators-start.js +3 -0
  5. package/lib/commands/init.js +20 -16
  6. package/lib/commands/setup-emulators-dataconnect.js +0 -14
  7. package/lib/dataconnect/dataplaneClient.js +12 -9
  8. package/lib/dataconnect/fileUtils.js +16 -4
  9. package/lib/dataconnect/freeTrial.js +8 -6
  10. package/lib/dataconnect/provisionCloudSql.js +4 -4
  11. package/lib/dataconnect/types.js +1 -0
  12. package/lib/dataconnect/webhook.js +31 -0
  13. package/lib/deploy/dataconnect/deploy.js +2 -0
  14. package/lib/deploy/dataconnect/prepare.js +2 -0
  15. package/lib/deploy/dataconnect/release.js +10 -5
  16. package/lib/deploy/functions/runtimes/node/index.js +6 -1
  17. package/lib/emulator/commandUtils.js +6 -1
  18. package/lib/emulator/constants.js +1 -1
  19. package/lib/emulator/controller.js +17 -3
  20. package/lib/emulator/dataconnect/pg-gateway/auth/base-auth-flow.js +11 -0
  21. package/lib/emulator/dataconnect/pg-gateway/auth/cert.js +69 -0
  22. package/lib/emulator/dataconnect/pg-gateway/auth/index.js +22 -0
  23. package/lib/emulator/dataconnect/pg-gateway/auth/md5.js +135 -0
  24. package/lib/emulator/dataconnect/pg-gateway/auth/password.js +65 -0
  25. package/lib/emulator/dataconnect/pg-gateway/auth/sasl/sasl-mechanism.js +34 -0
  26. package/lib/emulator/dataconnect/pg-gateway/auth/sasl/scram-sha-256.js +298 -0
  27. package/lib/emulator/dataconnect/pg-gateway/auth/trust.js +2 -0
  28. package/lib/emulator/dataconnect/pg-gateway/backend-error.js +75 -0
  29. package/lib/emulator/dataconnect/pg-gateway/buffer-reader.js +55 -0
  30. package/lib/emulator/dataconnect/pg-gateway/buffer-writer.js +79 -0
  31. package/lib/emulator/dataconnect/pg-gateway/connection.js +419 -0
  32. package/lib/emulator/dataconnect/pg-gateway/connection.types.js +8 -0
  33. package/lib/emulator/dataconnect/pg-gateway/crypto.js +40 -0
  34. package/lib/emulator/dataconnect/pg-gateway/duplex.js +53 -0
  35. package/lib/emulator/dataconnect/pg-gateway/index.js +27 -0
  36. package/lib/emulator/dataconnect/pg-gateway/message-buffer.js +96 -0
  37. package/lib/emulator/dataconnect/pg-gateway/message-codes.js +54 -0
  38. package/lib/emulator/dataconnect/pg-gateway/platforms/node/index.js +13 -0
  39. package/lib/emulator/dataconnect/pg-gateway/polyfills/readable-stream-async-iterator.js +36 -0
  40. package/lib/emulator/dataconnect/pg-gateway/utils.js +40 -0
  41. package/lib/emulator/dataconnect/pgliteServer.js +134 -0
  42. package/lib/emulator/dataconnectEmulator.js +55 -73
  43. package/lib/emulator/dataconnectToolkitController.js +44 -0
  44. package/lib/emulator/downloadableEmulators.js +22 -11
  45. package/lib/emulator/hub.js +2 -1
  46. package/lib/emulator/portUtils.js +9 -11
  47. package/lib/emulator/storage/rules/runtime.js +1 -1
  48. package/lib/experiments.js +1 -0
  49. package/lib/init/features/dataconnect/index.js +148 -111
  50. package/lib/init/features/dataconnect/sdk.js +40 -27
  51. package/lib/init/features/emulators.js +2 -14
  52. package/lib/prompt.js +1 -1
  53. package/lib/rc.js +1 -9
  54. package/package.json +3 -1
  55. package/schema/connector-yaml.json +14 -0
  56. package/schema/firebase-config.json +6 -0
  57. package/templates/init/dataconnect/queries.gql +1 -2
package/lib/apiv2.js CHANGED
@@ -34,7 +34,9 @@ function setAccessToken(token = "") {
34
34
  }
35
35
  exports.setAccessToken = setAccessToken;
36
36
  async function getAccessToken() {
37
- if (accessToken) {
37
+ const valid = auth.haveValidTokens(refreshToken, []);
38
+ const usingADC = !auth.loggedIn();
39
+ if (accessToken && (valid || usingADC)) {
38
40
  return accessToken;
39
41
  }
40
42
  const data = await auth.getAccessToken(refreshToken, []);
@@ -295,6 +297,11 @@ class Client {
295
297
  }
296
298
  this.logResponse(res, body, options);
297
299
  if (res.status >= 400) {
300
+ if (res.status === 401 && this.opts.auth) {
301
+ logger_1.logger.debug("Got a 401 Unauthenticated error for a call that required authentication. Refreshing tokens.");
302
+ setAccessToken();
303
+ setAccessToken(await getAccessToken());
304
+ }
298
305
  if ((_a = options.retryCodes) === null || _a === void 0 ? void 0 : _a.includes(res.status)) {
299
306
  const err = (0, responseToError_1.responseToError)({ statusCode: res.status }, body) || undefined;
300
307
  if (operation.retry(err)) {
package/lib/auth.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addAdditionalAccount = exports.logout = exports.getAccessToken = exports.findAccountByEmail = exports.loginGithub = exports.loginGoogle = exports.setGlobalDefaultAccount = exports.setProjectAccount = exports.loginAdditionalAccount = exports.selectAccount = exports.setRefreshToken = exports.setActiveAccount = exports.getAllAccounts = exports.getAdditionalAccounts = exports.getProjectDefaultAccount = exports.getGlobalDefaultAccount = void 0;
3
+ exports.addAdditionalAccount = exports.logout = exports.getAccessToken = exports.haveValidTokens = exports.loggedIn = exports.findAccountByEmail = exports.loginGithub = exports.loginGoogle = exports.setGlobalDefaultAccount = exports.setProjectAccount = exports.loginAdditionalAccount = exports.selectAccount = exports.setRefreshToken = exports.setActiveAccount = exports.getAllAccounts = exports.getAdditionalAccounts = exports.getProjectDefaultAccount = exports.getGlobalDefaultAccount = void 0;
4
4
  const clc = require("colorette");
5
5
  const FormData = require("form-data");
6
6
  const http = require("http");
@@ -394,6 +394,10 @@ function findAccountByEmail(email) {
394
394
  return getAllAccounts().find((a) => a.user.email === email);
395
395
  }
396
396
  exports.findAccountByEmail = findAccountByEmail;
397
+ function loggedIn() {
398
+ return !!lastAccessToken;
399
+ }
400
+ exports.loggedIn = loggedIn;
397
401
  function haveValidTokens(refreshToken, authScopes) {
398
402
  var _a;
399
403
  if (!(lastAccessToken === null || lastAccessToken === void 0 ? void 0 : lastAccessToken.access_token)) {
@@ -407,8 +411,16 @@ function haveValidTokens(refreshToken, authScopes) {
407
411
  const newScopesJSON = JSON.stringify(authScopes.sort());
408
412
  const hasSameScopes = oldScopesJSON === newScopesJSON;
409
413
  const isExpired = ((lastAccessToken === null || lastAccessToken === void 0 ? void 0 : lastAccessToken.expires_at) || 0) < Date.now() + FIFTEEN_MINUTES_IN_MS;
410
- return hasTokens && hasSameScopes && !isExpired;
414
+ const valid = hasTokens && hasSameScopes && !isExpired;
415
+ if (hasTokens) {
416
+ logger_1.logger.debug(`Checked if tokens are valid: ${valid}, expires at: ${lastAccessToken === null || lastAccessToken === void 0 ? void 0 : lastAccessToken.expires_at}`);
417
+ }
418
+ else {
419
+ logger_1.logger.debug("No OAuth tokens found");
420
+ }
421
+ return valid;
411
422
  }
423
+ exports.haveValidTokens = haveValidTokens;
412
424
  function deleteAccount(account) {
413
425
  const defaultAccount = getGlobalDefaultAccount();
414
426
  if (account.user.email === (defaultAccount === null || defaultAccount === void 0 ? void 0 : defaultAccount.user.email)) {
@@ -10,6 +10,7 @@ const fileUtils_1 = require("../dataconnect/fileUtils");
10
10
  const logger_1 = require("../logger");
11
11
  exports.command = new command_1.Command("dataconnect:sdk:generate")
12
12
  .description("generates typed SDKs for your Data Connect connectors")
13
+ .option("--watch", "watch for changes to your connector GQL files and regenerate your SDKs when updates occur")
13
14
  .action(async (options) => {
14
15
  const projectId = (0, projectUtils_1.needProjectId)(options);
15
16
  const services = (0, fileUtils_1.readFirebaseJson)(options.config);
@@ -17,10 +18,11 @@ exports.command = new command_1.Command("dataconnect:sdk:generate")
17
18
  const configDir = service.source;
18
19
  const serviceInfo = await (0, load_1.load)(projectId, options.config, configDir);
19
20
  const hasGeneratables = serviceInfo.connectorInfo.some((c) => {
20
- var _a, _b, _c;
21
+ var _a, _b, _c, _d;
21
22
  return (((_a = c.connectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) ||
22
23
  ((_b = c.connectorYaml.generate) === null || _b === void 0 ? void 0 : _b.kotlinSdk) ||
23
- ((_c = c.connectorYaml.generate) === null || _c === void 0 ? void 0 : _c.swiftSdk));
24
+ ((_c = c.connectorYaml.generate) === null || _c === void 0 ? void 0 : _c.swiftSdk) ||
25
+ ((_d = c.connectorYaml.generate) === null || _d === void 0 ? void 0 : _d.dartSdk));
24
26
  });
25
27
  if (!hasGeneratables) {
26
28
  logger_1.logger.warn("No generated SDKs have been declared in connector.yaml files.");
@@ -32,6 +34,7 @@ exports.command = new command_1.Command("dataconnect:sdk:generate")
32
34
  const output = await dataconnectEmulator_1.DataConnectEmulator.generate({
33
35
  configDir,
34
36
  connectorId: conn.connectorYaml.connectorId,
37
+ watch: options.watch,
35
38
  });
36
39
  logger_1.logger.info(output);
37
40
  logger_1.logger.info(`Generated SDKs for ${conn.connectorYaml.connectorId}`);
@@ -10,6 +10,7 @@ const types_1 = require("../emulator/types");
10
10
  const clc = require("colorette");
11
11
  const constants_1 = require("../emulator/constants");
12
12
  const utils_1 = require("../utils");
13
+ const webhook_1 = require("../dataconnect/webhook");
13
14
  const Table = require("cli-table");
14
15
  function stylizeLink(url) {
15
16
  return clc.underline(clc.bold(url));
@@ -31,8 +32,10 @@ exports.command = new command_1.Command("emulators:start")
31
32
  let deprecationNotices;
32
33
  try {
33
34
  ({ deprecationNotices } = await controller.startAll(options));
35
+ await (0, webhook_1.sendVSCodeMessage)({ message: webhook_1.VSCODE_MESSAGE.EMULATORS_STARTED });
34
36
  }
35
37
  catch (e) {
38
+ await (0, webhook_1.sendVSCodeMessage)({ message: webhook_1.VSCODE_MESSAGE.EMULATORS_START_ERRORED });
36
39
  await controller.cleanShutdown();
37
40
  throw e;
38
41
  }
@@ -21,10 +21,10 @@ const GITIGNORE_TEMPLATE = (0, templates_1.readTemplateSync)("_gitignore");
21
21
  function isOutside(from, to) {
22
22
  return !!/^\.\./.exec(path.relative(from, to));
23
23
  }
24
- const choices = [
24
+ let choices = [
25
25
  {
26
- value: "database",
27
- name: "Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance",
26
+ value: "dataconnect",
27
+ name: "Data Connect: Set up a Firebase Data Connect service",
28
28
  checked: false,
29
29
  },
30
30
  {
@@ -42,12 +42,6 @@ const choices = [
42
42
  name: "Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys",
43
43
  checked: false,
44
44
  },
45
- {
46
- value: "hosting:github",
47
- name: "Hosting: Set up GitHub Action deploys",
48
- checked: false,
49
- hidden: true,
50
- },
51
45
  {
52
46
  value: "storage",
53
47
  name: "Storage: Configure a security rules file for Cloud Storage",
@@ -69,10 +63,16 @@ const choices = [
69
63
  checked: false,
70
64
  },
71
65
  {
72
- value: "dataconnect",
73
- name: "Data Connect: Set up a Firebase Data Connect service",
66
+ value: "database",
67
+ name: "Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance",
74
68
  checked: false,
75
69
  },
70
+ {
71
+ value: "hosting:github",
72
+ name: "Hosting: Set up GitHub Action deploys",
73
+ checked: false,
74
+ hidden: true,
75
+ },
76
76
  {
77
77
  value: "dataconnect:sdk",
78
78
  name: "Data Connect: Set up a generated SDK for your Firebase Data Connect service",
@@ -81,11 +81,15 @@ const choices = [
81
81
  },
82
82
  ];
83
83
  if ((0, experiments_1.isEnabled)("genkit")) {
84
- choices.push({
85
- value: "genkit",
86
- name: "Genkit: Setup a new Genkit project with Firebase",
87
- checked: false,
88
- });
84
+ choices = [
85
+ ...choices.slice(0, 2),
86
+ {
87
+ value: "genkit",
88
+ name: "Genkit: Setup a new Genkit project with Firebase",
89
+ checked: false,
90
+ },
91
+ ...choices.slice(2),
92
+ ];
89
93
  }
90
94
  const featureNames = choices.map((choice) => choice.value);
91
95
  const DESCRIPTION = `Interactively configure the current directory as a Firebase project or initialize new features in an already configured Firebase project directory.
@@ -3,30 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.command = void 0;
4
4
  const command_1 = require("../command");
5
5
  const types_1 = require("../emulator/types");
6
- const emulators_1 = require("../init/features/emulators");
7
- const prompt_1 = require("../prompt");
8
6
  const logger_1 = require("../logger");
9
7
  const downloadableEmulators_1 = require("../emulator/downloadableEmulators");
10
8
  const NAME = types_1.Emulators.DATACONNECT;
11
9
  exports.command = new command_1.Command(`setup:emulators:${NAME}`)
12
10
  .description(`downloads the ${NAME} emulator`)
13
11
  .action(async (options) => {
14
- var _a, _b;
15
12
  await (0, downloadableEmulators_1.downloadIfNecessary)(NAME);
16
13
  if (!options.config) {
17
14
  logger_1.logger.info("Not currently in a Firebase project directory. Run this command from a project directory to configure the Data Connect emulator.");
18
15
  return;
19
16
  }
20
- if (!options.nonInteractive) {
21
- const dataconnectEmulatorConfig = options.rc.getDataconnect();
22
- const defaultConnectionString = (_b = (_a = dataconnectEmulatorConfig === null || dataconnectEmulatorConfig === void 0 ? void 0 : dataconnectEmulatorConfig.postgres) === null || _a === void 0 ? void 0 : _a.localConnectionString) !== null && _b !== void 0 ? _b : emulators_1.DEFAULT_POSTGRES_CONNECTION;
23
- const localConnectionString = await (0, prompt_1.promptOnce)({
24
- type: "input",
25
- name: "localConnectionString",
26
- message: `What is the connection string of the local Postgres instance you would like to use with the Data Connect emulator?`,
27
- default: defaultConnectionString,
28
- });
29
- options.rc.setDataconnect(localConnectionString);
30
- }
31
17
  logger_1.logger.info("Setup complete!");
32
18
  });
@@ -1,16 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.executeGraphQL = void 0;
3
+ exports.executeGraphQL = exports.dataconnectDataplaneClient = exports.DATACONNECT_API_VERSION = void 0;
4
4
  const api_1 = require("../api");
5
5
  const apiv2_1 = require("../apiv2");
6
- const DATACONNECT_API_VERSION = "v1beta";
7
- const dataconnectDataplaneClient = () => new apiv2_1.Client({
8
- urlPrefix: (0, api_1.dataconnectOrigin)(),
9
- apiVersion: DATACONNECT_API_VERSION,
10
- auth: true,
11
- });
12
- async function executeGraphQL(servicePath, body) {
13
- const res = await dataconnectDataplaneClient().post(`${servicePath}:executeGraphql`, body, { resolveOnHTTPError: true });
6
+ exports.DATACONNECT_API_VERSION = "v1beta";
7
+ function dataconnectDataplaneClient() {
8
+ return new apiv2_1.Client({
9
+ urlPrefix: (0, api_1.dataconnectOrigin)(),
10
+ apiVersion: exports.DATACONNECT_API_VERSION,
11
+ auth: true,
12
+ });
13
+ }
14
+ exports.dataconnectDataplaneClient = dataconnectDataplaneClient;
15
+ async function executeGraphQL(client, servicePath, body) {
16
+ const res = await client.post(`${servicePath}:executeGraphql`, body, { resolveOnHTTPError: true });
14
17
  return res;
15
18
  }
16
19
  exports.executeGraphQL = executeGraphQL;
@@ -8,7 +8,7 @@ const types_1 = require("./types");
8
8
  const utils_1 = require("../utils");
9
9
  const load_1 = require("./load");
10
10
  function readFirebaseJson(config) {
11
- if (!config.has("dataconnect")) {
11
+ if (!(config === null || config === void 0 ? void 0 : config.has("dataconnect"))) {
12
12
  return [];
13
13
  }
14
14
  const validator = (cfg) => {
@@ -96,28 +96,34 @@ exports.pickService = pickService;
96
96
  const WEB_INDICATORS = ["package.json", "package-lock.json", "node_modules"];
97
97
  const IOS_INDICATORS = ["info.plist", "podfile", "package.swift"];
98
98
  const ANDROID_INDICATORS = ["androidmanifest.xml", "build.gradle", "build.gradle.kts"];
99
+ const DART_INDICATORS = ["pubspec.yaml", "pubspec.lock"];
99
100
  const IOS_POSTFIX_INDICATORS = [".xcworkspace", ".xcodeproj"];
100
101
  async function getPlatformFromFolder(dirPath) {
101
102
  const fileNames = await fs.readdir(dirPath);
102
103
  let hasWeb = false;
103
104
  let hasAndroid = false;
104
105
  let hasIOS = false;
106
+ let hasDart = false;
105
107
  for (const fileName of fileNames) {
106
108
  const cleanedFileName = fileName.toLowerCase();
107
109
  hasWeb || (hasWeb = WEB_INDICATORS.some((indicator) => indicator === cleanedFileName));
108
110
  hasAndroid || (hasAndroid = ANDROID_INDICATORS.some((indicator) => indicator === cleanedFileName));
109
111
  hasIOS || (hasIOS = IOS_INDICATORS.some((indicator) => indicator === cleanedFileName) ||
110
112
  IOS_POSTFIX_INDICATORS.some((indicator) => cleanedFileName.endsWith(indicator)));
113
+ hasDart || (hasDart = DART_INDICATORS.some((indicator) => indicator === cleanedFileName));
111
114
  }
112
- if (hasWeb && !hasAndroid && !hasIOS) {
115
+ if (hasWeb && !hasAndroid && !hasIOS && !hasDart) {
113
116
  return types_1.Platform.WEB;
114
117
  }
115
- else if (hasAndroid && !hasWeb && !hasIOS) {
118
+ else if (hasAndroid && !hasWeb && !hasIOS && !hasDart) {
116
119
  return types_1.Platform.ANDROID;
117
120
  }
118
- else if (hasIOS && !hasWeb && !hasAndroid) {
121
+ else if (hasIOS && !hasWeb && !hasAndroid && !hasDart) {
119
122
  return types_1.Platform.IOS;
120
123
  }
124
+ else if (hasDart && !hasWeb && !hasIOS && !hasAndroid) {
125
+ return types_1.Platform.DART;
126
+ }
121
127
  return types_1.Platform.UNDETERMINED;
122
128
  }
123
129
  exports.getPlatformFromFolder = getPlatformFromFolder;
@@ -151,6 +157,12 @@ function generateSdkYaml(platform, connectorYaml, connectorYamlFolder, appFolder
151
157
  package: `connectors.${connectorYaml.connectorId}`,
152
158
  };
153
159
  }
160
+ if (platform === types_1.Platform.DART) {
161
+ connectorYaml.generate.dartSdk = {
162
+ outputDir,
163
+ package: connectorYaml.connectorId,
164
+ };
165
+ }
154
166
  return connectorYaml;
155
167
  }
156
168
  exports.generateSdkYaml = generateSdkYaml;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.printFreeTrialUnavailable = exports.checkForFreeTrialInstance = exports.freeTrialTermsLink = void 0;
4
4
  const cloudsqladmin_1 = require("../gcp/cloudsql/cloudsqladmin");
5
5
  const utils = require("../utils");
6
+ const clc = require("colorette");
6
7
  function freeTrialTermsLink() {
7
8
  return "https://firebase.google.com/pricing";
8
9
  }
@@ -13,11 +14,12 @@ async function checkForFreeTrialInstance(projectId) {
13
14
  return (_a = instances.find((i) => { var _a; return ((_a = i.settings.userLabels) === null || _a === void 0 ? void 0 : _a["firebase-data-connect"]) === "ft"; })) === null || _a === void 0 ? void 0 : _a.name;
14
15
  }
15
16
  exports.checkForFreeTrialInstance = checkForFreeTrialInstance;
16
- function printFreeTrialUnavailable(projectId, instanceId) {
17
- const message = `Project '${projectId}' already has a CloudSQL instance '${instanceId}' on the Firebase Data Connect free trial. ` +
18
- "The free trial only includes one CloudSQL instance. " +
19
- `Consider using a separate database on ${instanceId}, or creating a new CloudSQL instance at ` +
20
- "https://console.cloud.google.com/sql/instances";
21
- utils.logLabeledError("dataconnect", message);
17
+ function printFreeTrialUnavailable(projectId, instanceId, configYamlPath) {
18
+ utils.logLabeledError("dataconnect", `Project '${projectId} already has a CloudSQL instance '${instanceId}' on the Firebase Data Connect no-cost trial.`);
19
+ const reuseHint = `To use a different database in the same instance, ${clc.bold(`change the ${clc.blue("instanceId")} to "${instanceId}"`)} in ` +
20
+ `${clc.green(configYamlPath)}. (Also, update the ${clc.blue("database")} field (i.e. DB name in the instance) ` +
21
+ `and ${clc.blue("location")} as needed.)`;
22
+ utils.logLabeledBullet("dataconnect", reuseHint);
23
+ utils.logLabeledBullet("dataconnect", `Or you may create a new (paid) CloudSQL instance at https://console.cloud.google.com/sql/instances`);
22
24
  }
23
25
  exports.printFreeTrialUnavailable = printFreeTrialUnavailable;
@@ -11,7 +11,7 @@ const freeTrial_1 = require("./freeTrial");
11
11
  const error_1 = require("../error");
12
12
  async function provisionCloudSql(args) {
13
13
  let connectionName = "";
14
- const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, waitForCreation, silent, dryRun, } = args;
14
+ const { projectId, locationId, instanceId, databaseId, configYamlPath, enableGoogleMlIntegration, waitForCreation, silent, dryRun, } = args;
15
15
  try {
16
16
  const existingInstance = await cloudSqlAdminClient.getInstance(projectId, instanceId);
17
17
  silent || utils.logLabeledBullet("dataconnect", `Found existing instance ${instanceId}.`);
@@ -35,14 +35,14 @@ async function provisionCloudSql(args) {
35
35
  }
36
36
  const freeTrialInstanceId = await (0, freeTrial_1.checkForFreeTrialInstance)(projectId);
37
37
  if (freeTrialInstanceId) {
38
- (0, freeTrial_1.printFreeTrialUnavailable)(projectId, freeTrialInstanceId);
39
- throw new error_1.FirebaseError("Free trial unavailable.");
38
+ (0, freeTrial_1.printFreeTrialUnavailable)(projectId, freeTrialInstanceId, configYamlPath);
39
+ throw new error_1.FirebaseError("Cannot create another no-cost trial Cloud SQL instance.");
40
40
  }
41
41
  const cta = dryRun ? "It will be created on your next deploy" : "Creating it now.";
42
42
  silent ||
43
43
  utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found.` +
44
44
  cta +
45
- `\nThis instance is provided under the terms of the Data Connect free trial ${(0, freeTrial_1.freeTrialTermsLink)()}` +
45
+ `\nThis instance is provided under the terms of the Data Connect no-cost trial ${(0, freeTrial_1.freeTrialTermsLink)()}` +
46
46
  `\nMonitor the progress at ${cloudSqlAdminClient.instanceConsoleLink(projectId, instanceId)}`);
47
47
  if (!dryRun) {
48
48
  const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance...");
@@ -12,6 +12,7 @@ var Platform;
12
12
  Platform["ANDROID"] = "ANDROID";
13
13
  Platform["WEB"] = "WEB";
14
14
  Platform["IOS"] = "IOS";
15
+ Platform["DART"] = "DART";
15
16
  Platform["UNDETERMINED"] = "UNDETERMINED";
16
17
  })(Platform = exports.Platform || (exports.Platform = {}));
17
18
  function toDatasource(projectId, locationId, ds) {
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendVSCodeMessage = exports.port = exports.DEFAULT_PORT = exports.VSCODE_MESSAGE = void 0;
4
+ const node_fetch_1 = require("node-fetch");
5
+ const logger_1 = require("../logger");
6
+ var VSCODE_MESSAGE;
7
+ (function (VSCODE_MESSAGE) {
8
+ VSCODE_MESSAGE["EMULATORS_STARTED"] = "EMULATORS_STARTED";
9
+ VSCODE_MESSAGE["EMULATORS_START_ERRORED"] = "EMULATORS_START_ERRORED";
10
+ VSCODE_MESSAGE["EMULATORS_SHUTDOWN"] = "EMULATORS_SHUTDOWN";
11
+ })(VSCODE_MESSAGE = exports.VSCODE_MESSAGE || (exports.VSCODE_MESSAGE = {}));
12
+ exports.DEFAULT_PORT = "40001";
13
+ exports.port = process.env.VSCODE_WEBHOOK_PORT || exports.DEFAULT_PORT;
14
+ async function sendVSCodeMessage(body) {
15
+ const jsonBody = JSON.stringify(body);
16
+ try {
17
+ return await (0, node_fetch_1.default)(`http://localhost:${exports.port}/vscode/notify`, {
18
+ method: "POST",
19
+ headers: {
20
+ Accept: "application/json",
21
+ "Content-Type": "application/json",
22
+ "x-mantle-admin": "all",
23
+ },
24
+ body: jsonBody,
25
+ });
26
+ }
27
+ catch (e) {
28
+ logger_1.logger.debug(`Could not find VSCode notification endpoint: ${e}`);
29
+ }
30
+ }
31
+ exports.sendVSCodeMessage = sendVSCodeMessage;
@@ -8,6 +8,7 @@ const provisionCloudSql_1 = require("../../dataconnect/provisionCloudSql");
8
8
  const names_1 = require("../../dataconnect/names");
9
9
  const api_1 = require("../../api");
10
10
  const ensureApiEnabled = require("../../ensureApiEnabled");
11
+ const node_path_1 = require("node:path");
11
12
  async function default_1(context, options) {
12
13
  const projectId = (0, projectUtils_1.needProjectId)(options);
13
14
  const serviceInfos = context.dataconnect.serviceInfos;
@@ -57,6 +58,7 @@ async function default_1(context, options) {
57
58
  locationId: (0, names_1.parseServiceName)(s.serviceName).location,
58
59
  instanceId,
59
60
  databaseId,
61
+ configYamlPath: (0, node_path_1.join)(s.sourceDirectory, "dataconnect.yaml"),
60
62
  enableGoogleMlIntegration,
61
63
  waitForCreation: true,
62
64
  });
@@ -16,6 +16,7 @@ const names_1 = require("../../dataconnect/names");
16
16
  const error_1 = require("../../error");
17
17
  const types_1 = require("../../dataconnect/types");
18
18
  const schemaMigration_1 = require("../../dataconnect/schemaMigration");
19
+ const node_path_1 = require("node:path");
19
20
  async function default_1(context, options) {
20
21
  var _a;
21
22
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -70,6 +71,7 @@ async function default_1(context, options) {
70
71
  locationId: (0, names_1.parseServiceName)(s.serviceName).location,
71
72
  instanceId,
72
73
  databaseId,
74
+ configYamlPath: (0, node_path_1.join)(s.sourceDirectory, "dataconnect.yaml"),
73
75
  enableGoogleMlIntegration,
74
76
  waitForCreation: true,
75
77
  dryRun: options.dryRun,
@@ -4,7 +4,9 @@ const utils = require("../../utils");
4
4
  const client_1 = require("../../dataconnect/client");
5
5
  const prompts_1 = require("../../dataconnect/prompts");
6
6
  const schemaMigration_1 = require("../../dataconnect/schemaMigration");
7
+ const projectUtils_1 = require("../../projectUtils");
7
8
  async function default_1(context, options) {
9
+ const project = (0, projectUtils_1.needProjectId)(options);
8
10
  const serviceInfos = context.dataconnect.serviceInfos;
9
11
  const filters = context.dataconnect.filters;
10
12
  const wantSchemas = serviceInfos
@@ -22,7 +24,7 @@ async function default_1(context, options) {
22
24
  });
23
25
  });
24
26
  if (wantSchemas.length) {
25
- utils.logLabeledBullet("dataconnect", "Releasing Data Connect schemas...");
27
+ utils.logLabeledBullet("dataconnect", "Deploying Data Connect schemas...");
26
28
  for (const s of wantSchemas) {
27
29
  await (0, schemaMigration_1.migrateSchema)({
28
30
  options,
@@ -31,7 +33,7 @@ async function default_1(context, options) {
31
33
  schemaValidation: s.validationMode,
32
34
  });
33
35
  }
34
- utils.logLabeledBullet("dataconnect", "Schemas released.");
36
+ utils.logLabeledBullet("dataconnect", "Schemas deployed.");
35
37
  }
36
38
  let wantConnectors = [];
37
39
  wantConnectors = wantConnectors.concat(...serviceInfos.map((si) => si.connectorInfo
@@ -48,7 +50,7 @@ async function default_1(context, options) {
48
50
  ? []
49
51
  : haveConnectors.filter((h) => !wantConnectors.some((w) => w.name === h.name));
50
52
  if (wantConnectors.length) {
51
- utils.logLabeledBullet("dataconnect", "Releasing connectors...");
53
+ utils.logLabeledBullet("dataconnect", "Deploying connectors...");
52
54
  await Promise.all(wantConnectors.map(async (c) => {
53
55
  await (0, client_1.upsertConnector)(c);
54
56
  utils.logLabeledSuccess("dataconnect", `Deployed connector ${c.name}`);
@@ -56,9 +58,12 @@ async function default_1(context, options) {
56
58
  for (const c of connectorsToDelete) {
57
59
  await (0, prompts_1.promptDeleteConnector)(options, c.name);
58
60
  }
59
- utils.logLabeledBullet("dataconnect", "Connectors released.");
61
+ utils.logLabeledBullet("dataconnect", "Connectors deployed.");
60
62
  }
61
- utils.logLabeledSuccess("dataconnect", "Deploy complete!");
63
+ else {
64
+ utils.logLabeledBullet("dataconnect", "No connectors to deploy.");
65
+ }
66
+ utils.logLabeledSuccess("dataconnect", `Deployment complete! View your deployed schema and connectors at ${utils.consoleUrl(project, "/dataconnect")}`);
62
67
  return;
63
68
  }
64
69
  exports.default = default_1;
@@ -18,7 +18,8 @@ const validate = require("./validate");
18
18
  const versioning = require("./versioning");
19
19
  const parseTriggers = require("./parseTriggers");
20
20
  const fsutils_1 = require("../../../../fsutils");
21
- const MIN_FUNCTIONS_SDK_VERSION = "5.1.0";
21
+ const MIN_FUNCTIONS_SDK_VERSION = "3.20.0";
22
+ const MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES = "5.1.0";
22
23
  async function tryCreateDelegate(context) {
23
24
  const packageJsonPath = path.join(context.sourceDir, "package.json");
24
25
  if (!(await (0, util_1.promisify)(fs.exists)(packageJsonPath))) {
@@ -156,6 +157,10 @@ class Delegate {
156
157
  `Please update firebase-functions SDK to >=${MIN_FUNCTIONS_SDK_VERSION}`);
157
158
  return parseTriggers.discoverBuild(this.projectId, this.sourceDir, this.runtime, config, env);
158
159
  }
160
+ if (semver.lt(this.sdkVersion, MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES)) {
161
+ (0, utils_1.logLabeledBullet)("functions", `You are using a version of firebase-functions SDK (${this.sdkVersion}) that does not have support for the newest Firebase Extensions features. ` +
162
+ `Please update firebase-functions SDK to >=${MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES} to use them correctly`);
163
+ }
159
164
  let discovered = await discovery.detectFromYaml(this.sourceDir, this.projectId, this.runtime);
160
165
  if (!discovered) {
161
166
  const basePort = 8000 + (0, utils_1.randomInt)(0, 1000);
@@ -20,6 +20,7 @@ const fsutils = require("../fsutils");
20
20
  const Table = require("cli-table");
21
21
  const track_1 = require("../track");
22
22
  const env_1 = require("./env");
23
+ const webhook_1 = require("../dataconnect/webhook");
23
24
  exports.FLAG_ONLY = "--only <emulators>";
24
25
  exports.DESC_ONLY = "only specific emulators. " +
25
26
  "This is a comma separated list of emulator names. " +
@@ -291,13 +292,17 @@ async function emulatorExec(script, options) {
291
292
  extraEnv[constants_1.Constants.FIREBASE_GA_SESSION] = JSON.stringify(session);
292
293
  }
293
294
  let exitCode = 0;
294
- let deprecationNotices;
295
+ let deprecationNotices = [];
295
296
  try {
296
297
  const showUI = !!options.ui;
297
298
  ({ deprecationNotices } = await controller.startAll(options, showUI, true));
299
+ await (0, webhook_1.sendVSCodeMessage)({ message: webhook_1.VSCODE_MESSAGE.EMULATORS_STARTED });
298
300
  exitCode = await runScript(script, extraEnv);
299
301
  await controller.onExit(options);
300
302
  }
303
+ catch (_a) {
304
+ await (0, webhook_1.sendVSCodeMessage)({ message: webhook_1.VSCODE_MESSAGE.EMULATORS_START_ERRORED });
305
+ }
301
306
  finally {
302
307
  await controller.cleanShutdown();
303
308
  }
@@ -32,7 +32,7 @@ exports.FIND_AVAILBLE_PORT_BY_DEFAULT = {
32
32
  storage: false,
33
33
  extensions: false,
34
34
  eventarc: true,
35
- dataconnect: true,
35
+ dataconnect: false,
36
36
  tasks: true,
37
37
  };
38
38
  exports.EMULATOR_DESCRIPTION = {
@@ -46,6 +46,7 @@ const storage_1 = require("./storage");
46
46
  const fileUtils_1 = require("../dataconnect/fileUtils");
47
47
  const tasksEmulator_1 = require("./tasksEmulator");
48
48
  const apphosting_1 = require("./apphosting");
49
+ const webhook_1 = require("../dataconnect/webhook");
49
50
  const START_LOGGING_EMULATOR = utils.envOverride("START_LOGGING_EMULATOR", "false", (val) => val === "true");
50
51
  async function exportOnExit(options) {
51
52
  const exportOnExitDir = options.exportOnExit;
@@ -69,6 +70,7 @@ exports.onExit = onExit;
69
70
  async function cleanShutdown() {
70
71
  emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HUB).logLabeled("BULLET", "emulators", "Shutting down emulators.");
71
72
  await registry_1.EmulatorRegistry.stopAll();
73
+ await (0, webhook_1.sendVSCodeMessage)({ message: webhook_1.VSCODE_MESSAGE.EMULATORS_SHUTDOWN });
72
74
  }
73
75
  exports.cleanShutdown = cleanShutdown;
74
76
  function filterEmulatorTargets(options) {
@@ -161,7 +163,7 @@ function findExportMetadata(importPath) {
161
163
  }
162
164
  }
163
165
  async function startAll(options, showUI = true, runningTestScript = false) {
164
- var _a, _b, _c, _d, _e, _f, _g, _h;
166
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
165
167
  const targets = filterEmulatorTargets(options);
166
168
  options.targets = targets;
167
169
  const singleProjectModeEnabled = ((_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a.singleProjectMode) === undefined ||
@@ -249,6 +251,14 @@ async function startAll(options, showUI = true, runningTestScript = false) {
249
251
  portFixed: !!wsPortConfig,
250
252
  };
251
253
  }
254
+ if (emulator === types_1.Emulators.DATACONNECT) {
255
+ const pglitePortConfig = (_f = (_e = options.config.src.emulators) === null || _e === void 0 ? void 0 : _e.dataconnect) === null || _f === void 0 ? void 0 : _f.postgresPort;
256
+ listenConfig["dataconnect.postgres"] = {
257
+ host: config.host,
258
+ port: pglitePortConfig || 5432,
259
+ portFixed: !!pglitePortConfig,
260
+ };
261
+ }
252
262
  }
253
263
  }
254
264
  let listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(listenConfig);
@@ -315,7 +325,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
315
325
  utils.assertIsStringOrUndefined(options.extDevDir);
316
326
  for (const cfg of functionsCfg) {
317
327
  const functionsDir = path.join(projectDir, cfg.source);
318
- const runtime = ((_e = options.extDevRuntime) !== null && _e !== void 0 ? _e : cfg.runtime);
328
+ const runtime = ((_g = options.extDevRuntime) !== null && _g !== void 0 ? _g : cfg.runtime);
319
329
  if (runtime && !(0, supported_1.isRuntime)(runtime)) {
320
330
  throw new error_1.FirebaseError(`Cannot load functions from ${functionsDir} because it has invalid runtime ${runtime}`);
321
331
  }
@@ -335,7 +345,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
335
345
  }
336
346
  if (emulatableBackends.length) {
337
347
  if (!listenForEmulator.functions || !listenForEmulator.eventarc || !listenForEmulator.tasks) {
338
- listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(Object.assign(Object.assign({}, listenForEmulator), { functions: (_f = listenForEmulator.functions) !== null && _f !== void 0 ? _f : getListenConfig(options, types_1.Emulators.FUNCTIONS), eventarc: (_g = listenForEmulator.eventarc) !== null && _g !== void 0 ? _g : getListenConfig(options, types_1.Emulators.EVENTARC), tasks: (_h = listenForEmulator.eventarc) !== null && _h !== void 0 ? _h : getListenConfig(options, types_1.Emulators.TASKS) }));
348
+ listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(Object.assign(Object.assign({}, listenForEmulator), { functions: (_h = listenForEmulator.functions) !== null && _h !== void 0 ? _h : getListenConfig(options, types_1.Emulators.FUNCTIONS), eventarc: (_j = listenForEmulator.eventarc) !== null && _j !== void 0 ? _j : getListenConfig(options, types_1.Emulators.EVENTARC), tasks: (_k = listenForEmulator.eventarc) !== null && _k !== void 0 ? _k : getListenConfig(options, types_1.Emulators.TASKS) }));
339
349
  hubLogger.log("DEBUG", "late-assigned ports for functions and eventarc emulators", {
340
350
  user: listenForEmulator,
341
351
  });
@@ -544,6 +554,10 @@ async function startAll(options, showUI = true, runningTestScript = false) {
544
554
  configDir,
545
555
  rc: options.rc,
546
556
  config: options.config,
557
+ autoconnectToPostgres: true,
558
+ postgresListen: listenForEmulator["dataconnect.postgres"],
559
+ enable_output_generated_sdk: true,
560
+ enable_output_schema_extensions: true,
547
561
  });
548
562
  await startEmulator(dataConnectEmulator);
549
563
  }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseAuthFlow = void 0;
4
+ class BaseAuthFlow {
5
+ constructor(params) {
6
+ this.reader = params.reader;
7
+ this.writer = params.writer;
8
+ this.connectionState = params.connectionState;
9
+ }
10
+ }
11
+ exports.BaseAuthFlow = BaseAuthFlow;