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.
- package/README.md +10 -9
- package/lib/commands/dataconnect-sdk-generate.js +5 -2
- package/lib/commands/emulators-start.js +3 -0
- package/lib/commands/ext-info.js +3 -1
- package/lib/commands/ext-sdk-install.js +88 -0
- package/lib/commands/ext.js +1 -0
- package/lib/commands/index.js +2 -0
- package/lib/commands/init.js +20 -16
- package/lib/commands/setup-emulators-dataconnect.js +0 -14
- package/lib/dataconnect/ensureApis.js +0 -1
- package/lib/dataconnect/fileUtils.js +16 -4
- package/lib/dataconnect/freeTrial.js +8 -6
- package/lib/dataconnect/provisionCloudSql.js +4 -4
- package/lib/dataconnect/types.js +1 -0
- package/lib/dataconnect/webhook.js +31 -0
- package/lib/deploy/dataconnect/deploy.js +2 -0
- package/lib/deploy/dataconnect/prepare.js +2 -0
- package/lib/deploy/dataconnect/release.js +10 -5
- package/lib/deploy/extensions/deploymentSummary.js +3 -2
- package/lib/deploy/extensions/planner.js +32 -3
- package/lib/deploy/extensions/prepare.js +15 -56
- package/lib/deploy/extensions/release.js +11 -10
- package/lib/deploy/extensions/tasks.js +32 -21
- package/lib/deploy/functions/prepare.js +8 -0
- package/lib/deploy/functions/runtimes/node/index.js +5 -0
- package/lib/emulator/commandUtils.js +6 -1
- package/lib/emulator/constants.js +1 -1
- package/lib/emulator/controller.js +17 -3
- package/lib/emulator/dataconnect/pg-gateway/auth/base-auth-flow.js +11 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/cert.js +69 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/index.js +22 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/md5.js +135 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/password.js +65 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/sasl/sasl-mechanism.js +34 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/sasl/scram-sha-256.js +298 -0
- package/lib/emulator/dataconnect/pg-gateway/auth/trust.js +2 -0
- package/lib/emulator/dataconnect/pg-gateway/backend-error.js +75 -0
- package/lib/emulator/dataconnect/pg-gateway/buffer-reader.js +55 -0
- package/lib/emulator/dataconnect/pg-gateway/buffer-writer.js +79 -0
- package/lib/emulator/dataconnect/pg-gateway/connection.js +419 -0
- package/lib/emulator/dataconnect/pg-gateway/connection.types.js +8 -0
- package/lib/emulator/dataconnect/pg-gateway/crypto.js +40 -0
- package/lib/emulator/dataconnect/pg-gateway/duplex.js +53 -0
- package/lib/emulator/dataconnect/pg-gateway/index.js +27 -0
- package/lib/emulator/dataconnect/pg-gateway/message-buffer.js +96 -0
- package/lib/emulator/dataconnect/pg-gateway/message-codes.js +54 -0
- package/lib/emulator/dataconnect/pg-gateway/platforms/node/index.js +13 -0
- package/lib/emulator/dataconnect/pg-gateway/polyfills/readable-stream-async-iterator.js +36 -0
- package/lib/emulator/dataconnect/pg-gateway/utils.js +40 -0
- package/lib/emulator/dataconnect/pgliteServer.js +134 -0
- package/lib/emulator/dataconnectEmulator.js +55 -73
- package/lib/emulator/dataconnectToolkitController.js +44 -0
- package/lib/emulator/downloadableEmulators.js +22 -11
- package/lib/emulator/hub.js +2 -1
- package/lib/emulator/portUtils.js +9 -11
- package/lib/emulator/storage/rules/runtime.js +1 -1
- package/lib/experiments.js +1 -0
- package/lib/extensions/extensionsApi.js +3 -2
- package/lib/extensions/extensionsHelper.js +3 -3
- package/lib/extensions/localHelper.js +31 -0
- package/lib/extensions/runtimes/common.js +186 -38
- package/lib/extensions/runtimes/node.js +399 -0
- package/lib/extensions/types.js +10 -14
- package/lib/extensions/warnings.js +5 -2
- package/lib/init/features/dataconnect/index.js +148 -111
- package/lib/init/features/dataconnect/sdk.js +40 -27
- package/lib/init/features/emulators.js +2 -14
- package/lib/prompt.js +1 -1
- package/lib/rc.js +1 -9
- package/package.json +3 -1
- package/schema/connector-yaml.json +14 -0
- package/schema/firebase-config.json +6 -0
- package/templates/init/dataconnect/dataconnect-fdccompatiblemode.yaml +1 -1
- 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
|
|
121
|
-
|
|
|
122
|
-
| **ext**
|
|
123
|
-
| **ext:configure**
|
|
124
|
-
| **ext:info**
|
|
125
|
-
| **ext:install**
|
|
126
|
-
| **ext:
|
|
127
|
-
| **ext:
|
|
128
|
-
| **ext:
|
|
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
|
}
|
package/lib/commands/ext-info.js
CHANGED
|
@@ -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,
|
|
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
|
+
});
|
package/lib/commands/ext.js
CHANGED
package/lib/commands/index.js
CHANGED
|
@@ -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");
|
package/lib/commands/init.js
CHANGED
|
@@ -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
|
-
|
|
24
|
+
let choices = [
|
|
25
25
|
{
|
|
26
|
-
value: "
|
|
27
|
-
name: "
|
|
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: "
|
|
73
|
-
name: "
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
utils.
|
|
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("
|
|
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
|
|
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...");
|
package/lib/dataconnect/types.js
CHANGED
|
@@ -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", "
|
|
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
|
|
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", "
|
|
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
|
|
61
|
+
utils.logLabeledBullet("dataconnect", "Connectors deployed.");
|
|
60
62
|
}
|
|
61
|
-
|
|
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
|
|
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
|
-
|
|
54
|
-
|
|
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
|
}
|