firebase-tools 13.18.0 → 13.20.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 (74) hide show
  1. package/README.md +10 -9
  2. package/lib/commands/dataconnect-sdk-generate.js +5 -2
  3. package/lib/commands/emulators-start.js +3 -0
  4. package/lib/commands/ext-info.js +3 -1
  5. package/lib/commands/ext-sdk-install.js +88 -0
  6. package/lib/commands/ext.js +1 -0
  7. package/lib/commands/index.js +2 -0
  8. package/lib/commands/init.js +20 -16
  9. package/lib/commands/setup-emulators-dataconnect.js +0 -14
  10. package/lib/dataconnect/ensureApis.js +0 -1
  11. package/lib/dataconnect/fileUtils.js +16 -4
  12. package/lib/dataconnect/freeTrial.js +8 -6
  13. package/lib/dataconnect/provisionCloudSql.js +4 -4
  14. package/lib/dataconnect/types.js +1 -0
  15. package/lib/dataconnect/webhook.js +31 -0
  16. package/lib/deploy/dataconnect/deploy.js +2 -0
  17. package/lib/deploy/dataconnect/prepare.js +2 -0
  18. package/lib/deploy/dataconnect/release.js +10 -5
  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 +15 -56
  22. package/lib/deploy/extensions/release.js +11 -10
  23. package/lib/deploy/extensions/tasks.js +32 -21
  24. package/lib/deploy/functions/prepare.js +8 -0
  25. package/lib/deploy/functions/runtimes/node/index.js +5 -0
  26. package/lib/emulator/commandUtils.js +6 -1
  27. package/lib/emulator/constants.js +1 -1
  28. package/lib/emulator/controller.js +17 -3
  29. package/lib/emulator/dataconnect/pg-gateway/auth/base-auth-flow.js +11 -0
  30. package/lib/emulator/dataconnect/pg-gateway/auth/cert.js +69 -0
  31. package/lib/emulator/dataconnect/pg-gateway/auth/index.js +22 -0
  32. package/lib/emulator/dataconnect/pg-gateway/auth/md5.js +135 -0
  33. package/lib/emulator/dataconnect/pg-gateway/auth/password.js +65 -0
  34. package/lib/emulator/dataconnect/pg-gateway/auth/sasl/sasl-mechanism.js +34 -0
  35. package/lib/emulator/dataconnect/pg-gateway/auth/sasl/scram-sha-256.js +298 -0
  36. package/lib/emulator/dataconnect/pg-gateway/auth/trust.js +2 -0
  37. package/lib/emulator/dataconnect/pg-gateway/backend-error.js +75 -0
  38. package/lib/emulator/dataconnect/pg-gateway/buffer-reader.js +55 -0
  39. package/lib/emulator/dataconnect/pg-gateway/buffer-writer.js +79 -0
  40. package/lib/emulator/dataconnect/pg-gateway/connection.js +419 -0
  41. package/lib/emulator/dataconnect/pg-gateway/connection.types.js +8 -0
  42. package/lib/emulator/dataconnect/pg-gateway/crypto.js +40 -0
  43. package/lib/emulator/dataconnect/pg-gateway/duplex.js +53 -0
  44. package/lib/emulator/dataconnect/pg-gateway/index.js +27 -0
  45. package/lib/emulator/dataconnect/pg-gateway/message-buffer.js +96 -0
  46. package/lib/emulator/dataconnect/pg-gateway/message-codes.js +54 -0
  47. package/lib/emulator/dataconnect/pg-gateway/platforms/node/index.js +13 -0
  48. package/lib/emulator/dataconnect/pg-gateway/polyfills/readable-stream-async-iterator.js +36 -0
  49. package/lib/emulator/dataconnect/pg-gateway/utils.js +40 -0
  50. package/lib/emulator/dataconnect/pgliteServer.js +134 -0
  51. package/lib/emulator/dataconnectEmulator.js +55 -73
  52. package/lib/emulator/dataconnectToolkitController.js +44 -0
  53. package/lib/emulator/downloadableEmulators.js +22 -11
  54. package/lib/emulator/hub.js +2 -1
  55. package/lib/emulator/portUtils.js +9 -11
  56. package/lib/emulator/storage/rules/runtime.js +1 -1
  57. package/lib/experiments.js +1 -0
  58. package/lib/extensions/extensionsApi.js +3 -2
  59. package/lib/extensions/extensionsHelper.js +3 -3
  60. package/lib/extensions/localHelper.js +31 -0
  61. package/lib/extensions/runtimes/common.js +186 -38
  62. package/lib/extensions/runtimes/node.js +399 -0
  63. package/lib/extensions/types.js +10 -14
  64. package/lib/extensions/warnings.js +5 -2
  65. package/lib/init/features/dataconnect/index.js +148 -111
  66. package/lib/init/features/dataconnect/sdk.js +40 -27
  67. package/lib/init/features/emulators.js +2 -14
  68. package/lib/prompt.js +1 -1
  69. package/lib/rc.js +1 -9
  70. package/package.json +3 -1
  71. package/schema/connector-yaml.json +14 -0
  72. package/schema/firebase-config.json +6 -0
  73. package/templates/init/dataconnect/dataconnect-fdccompatiblemode.yaml +1 -1
  74. package/templates/init/dataconnect/queries.gql +1 -2
package/README.md CHANGED
@@ -117,15 +117,16 @@ Detailed doc is [here](https://firebase.google.com/docs/cli/auth).
117
117
 
118
118
  ### Extensions Commands
119
119
 
120
- | Command | Description |
121
- | ----------------- | ------------------------------------------------------------------------------------------- |
122
- | **ext** | Display information on how to use ext commands and extensions installed to your project. |
123
- | **ext:configure** | Configure an existing extension instance. |
124
- | **ext:info** | Display information about an extension by name (extensionName@x.y.z for a specific version) |
125
- | **ext:install** | Install an extension. |
126
- | **ext:list** | List all the extensions that are installed in your Firebase project. |
127
- | **ext:uninstall** | Uninstall an extension that is installed in your Firebase project by Instance ID. |
128
- | **ext:update** | Update an existing extension instance to the latest version. |
120
+ | Command | Description |
121
+ | ------------------- | ------------------------------------------------------------------------------------------- |
122
+ | **ext** | Display information on how to use ext commands and extensions installed to your project. |
123
+ | **ext:configure** | Configure an existing extension instance. |
124
+ | **ext:info** | Display information about an extension by name (extensionName@x.y.z for a specific version) |
125
+ | **ext:install** | Install an extension. |
126
+ | **ext:sdk:install** | Install and SDK for an extension so you can define the extension in a functions codebase. |
127
+ | **ext:list** | List all the extensions that are installed in your Firebase project. |
128
+ | **ext:uninstall** | Uninstall an extension that is installed in your Firebase project by Instance ID. |
129
+ | **ext:update** | Update an existing extension instance to the latest version. |
129
130
 
130
131
  ### Cloud Firestore Commands
131
132
 
@@ -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
  }
@@ -110,7 +110,9 @@ exports.command = new command_1.Command("ext:info <extensionName>")
110
110
  else {
111
111
  marked_1.marked.use((0, marked_terminal_1.markedTerminal)());
112
112
  logger_1.logger.info(await (0, marked_1.marked)(lines.join("\n")));
113
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, `to install this extension, type ` +
113
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, `to install this extension, run ` +
114
114
  clc.bold(`firebase ext:install ${extensionName} --project=YOUR_PROJECT`));
115
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, `to install an autogenerated SDK for this extension into your functions codebase, run ` +
116
+ clc.bold(`firebase ext:sdk:install ${extensionName} --project=YOUR_PROJECT`));
115
117
  }
116
118
  });
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const clc = require("colorette");
5
+ const semver = require("semver");
6
+ const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
7
+ const command_1 = require("../command");
8
+ const extensionsApi = require("../extensions/extensionsApi");
9
+ const extensionsHelper_1 = require("../extensions/extensionsHelper");
10
+ const localHelper_1 = require("../extensions/localHelper");
11
+ const requirePermissions_1 = require("../requirePermissions");
12
+ const common_1 = require("../extensions/runtimes/common");
13
+ const error_1 = require("../error");
14
+ const displayExtensionInfo_1 = require("../extensions/displayExtensionInfo");
15
+ const refs = require("../extensions/refs");
16
+ const logger_1 = require("../logger");
17
+ const prompt_1 = require("../prompt");
18
+ const utils = require("../utils");
19
+ exports.command = new command_1.Command("ext:sdk:install <extensionName>")
20
+ .description("get an SDK for this extension. The SDK will be put in the 'generated' directory")
21
+ .option(`--codebase <codebase>`, `specifies a codebase to install the SDK into`)
22
+ .option(`--force`, `will overwrite existing sdk files if true`)
23
+ .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
24
+ .action(async (extensionName, options) => {
25
+ const runtime = await (0, common_1.getCodebaseRuntime)(options);
26
+ if (!runtime.startsWith("nodejs")) {
27
+ throw new error_1.FirebaseError(`Extension SDK generation is currently only supported for NodeJs. We detected the target source to be: ${runtime}`);
28
+ }
29
+ let spec;
30
+ let extensionRef;
31
+ let localPath;
32
+ if ((0, localHelper_1.isLocalExtension)(extensionName)) {
33
+ spec = await (0, localHelper_1.getLocalExtensionSpec)(extensionName);
34
+ spec.systemParams = [];
35
+ localPath = extensionName;
36
+ await (0, displayExtensionInfo_1.displayExtensionVersionInfo)({ spec });
37
+ }
38
+ else {
39
+ await (0, requirePermissions_1.requirePermissions)(options, ["firebaseextensions.sources.get"]);
40
+ await (0, extensionsHelper_1.ensureExtensionsApiEnabled)(options);
41
+ const hasPublisherId = extensionName.split("/").length >= 2;
42
+ if (hasPublisherId) {
43
+ const nameAndVersion = extensionName.split("/")[1];
44
+ if (nameAndVersion.split("@").length < 2) {
45
+ extensionName = extensionName + "@latest";
46
+ }
47
+ }
48
+ else {
49
+ const [name, version] = extensionName.split("@");
50
+ extensionName = `firebase/${name}@${version || "latest"}`;
51
+ }
52
+ const ref = refs.parse(extensionName);
53
+ const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
54
+ const version = await extensionsApi.getExtensionVersion(extensionName);
55
+ spec = version.spec;
56
+ extensionRef = version.ref;
57
+ await (0, displayExtensionInfo_1.displayExtensionVersionInfo)({
58
+ spec,
59
+ extensionVersion: version,
60
+ latestApprovedVersion: extension.latestApprovedVersion,
61
+ latestVersion: extension.latestVersion,
62
+ });
63
+ if (version.state === "DEPRECATED") {
64
+ throw new error_1.FirebaseError(`Extension version ${clc.bold(extensionName)} is deprecated and cannot be installed. To install an SDK for the ` +
65
+ `latest non-deprecated version, omit the version in the extension ref.`);
66
+ }
67
+ logger_1.logger.info();
68
+ if ((extension.latestApprovedVersion &&
69
+ semver.gt(extension.latestApprovedVersion, version.spec.version)) ||
70
+ (!extension.latestApprovedVersion &&
71
+ extension.latestVersion &&
72
+ semver.gt(extension.latestVersion, version.spec.version))) {
73
+ const latest = extension.latestApprovedVersion || extension.latestVersion;
74
+ logger_1.logger.info(`You are about to install an SDK for extension version ${clc.bold(version.spec.version)} which is older than the latest ${extension.latestApprovedVersion ? "accepted version" : "version"} ${clc.bold(latest)}.`);
75
+ }
76
+ }
77
+ if (!(await (0, prompt_1.confirm)({
78
+ nonInteractive: options.nonInteractive,
79
+ force: options.force,
80
+ default: true,
81
+ }))) {
82
+ return;
83
+ }
84
+ const codeSample = await (0, common_1.writeSDK)(extensionRef, localPath, spec, options);
85
+ logger_1.logger.info();
86
+ utils.logSuccess("Extension SDK installed successfully");
87
+ logger_1.logger.info(codeSample);
88
+ });
@@ -23,6 +23,7 @@ exports.command = new command_1.Command("ext")
23
23
  "ext:configure",
24
24
  "ext:update",
25
25
  "ext:uninstall",
26
+ "ext:sdk:install",
26
27
  ];
27
28
  for (const commandName of commandNames) {
28
29
  const command = firebaseTools.getCommand(commandName);
@@ -83,6 +83,8 @@ function load(client) {
83
83
  client.ext.list = loadCommand("ext-list");
84
84
  client.ext.uninstall = loadCommand("ext-uninstall");
85
85
  client.ext.update = loadCommand("ext-update");
86
+ client.ext.sdk = {};
87
+ client.ext.sdk.install = loadCommand("ext-sdk-install");
86
88
  client.ext.dev = {};
87
89
  client.ext.dev.init = loadCommand("ext-dev-init");
88
90
  client.ext.dev.list = loadCommand("ext-dev-list");
@@ -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
  });
@@ -12,7 +12,6 @@ async function ensureApis(projectId) {
12
12
  exports.ensureApis = ensureApis;
13
13
  async function ensureSparkApis(projectId) {
14
14
  const prefix = "dataconnect";
15
- await (0, ensureApiEnabled_1.ensure)(projectId, api.dataconnectOrigin(), prefix);
16
15
  await (0, ensureApiEnabled_1.ensure)(projectId, api.cloudSQLAdminOrigin(), prefix);
17
16
  }
18
17
  exports.ensureSparkApis = ensureSparkApis;
@@ -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;
@@ -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
  }