firebase-tools 13.19.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/lib/commands/dataconnect-sdk-generate.js +5 -2
- package/lib/commands/emulators-start.js +3 -0
- package/lib/commands/init.js +20 -16
- package/lib/commands/setup-emulators-dataconnect.js +0 -14
- 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/functions/runtimes/node/index.js +6 -1
- 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/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/queries.gql +1 -2
|
@@ -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/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
|
});
|
|
@@ -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;
|
|
@@ -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 = "
|
|
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
|
}
|
|
@@ -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 = ((
|
|
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: (
|
|
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;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
3
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
4
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
5
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
6
|
+
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
7
|
+
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
8
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
9
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
10
|
+
function fulfill(value) { resume("next", value); }
|
|
11
|
+
function reject(value) { resume("throw", value); }
|
|
12
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.CertAuthFlow = void 0;
|
|
16
|
+
const backend_error_1 = require("../backend-error");
|
|
17
|
+
const base_auth_flow_1 = require("./base-auth-flow");
|
|
18
|
+
const connection_1 = require("../connection");
|
|
19
|
+
class CertAuthFlow extends base_auth_flow_1.BaseAuthFlow {
|
|
20
|
+
constructor(params) {
|
|
21
|
+
var _a;
|
|
22
|
+
super(params);
|
|
23
|
+
this.completed = false;
|
|
24
|
+
this.auth = Object.assign(Object.assign({}, params.auth), { validateCredentials: (_a = params.auth.validateCredentials) !== null && _a !== void 0 ? _a : (async ({ username, certificate }) => {
|
|
25
|
+
return certificate.subject.CN === username;
|
|
26
|
+
}) });
|
|
27
|
+
this.username = params.username;
|
|
28
|
+
}
|
|
29
|
+
handleClientMessage(message) {
|
|
30
|
+
return __asyncGenerator(this, arguments, function* handleClientMessage_1() {
|
|
31
|
+
if (false) {
|
|
32
|
+
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
33
|
+
severity: 'FATAL',
|
|
34
|
+
code: '08000',
|
|
35
|
+
message: `ssl connection required when auth mode is 'certificate'`,
|
|
36
|
+
}));
|
|
37
|
+
yield yield __await(connection_1.closeSignal);
|
|
38
|
+
return yield __await(void 0);
|
|
39
|
+
}
|
|
40
|
+
if (false) {
|
|
41
|
+
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
42
|
+
severity: 'FATAL',
|
|
43
|
+
code: '08000',
|
|
44
|
+
message: 'client certificate is invalid',
|
|
45
|
+
}));
|
|
46
|
+
yield yield __await(connection_1.closeSignal);
|
|
47
|
+
return yield __await(void 0);
|
|
48
|
+
}
|
|
49
|
+
const isValid = false;
|
|
50
|
+
if (!isValid) {
|
|
51
|
+
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
52
|
+
severity: 'FATAL',
|
|
53
|
+
code: '08000',
|
|
54
|
+
message: 'client certificate is invalid',
|
|
55
|
+
}));
|
|
56
|
+
yield yield __await(connection_1.closeSignal);
|
|
57
|
+
return yield __await(void 0);
|
|
58
|
+
}
|
|
59
|
+
this.completed = true;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
createInitialAuthMessage() {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
get isCompleted() {
|
|
66
|
+
return this.completed;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.CertAuthFlow = CertAuthFlow;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAuthFlow = void 0;
|
|
4
|
+
const cert_1 = require("./cert");
|
|
5
|
+
const md5_1 = require("./md5");
|
|
6
|
+
const password_1 = require("./password");
|
|
7
|
+
const scram_sha_256_1 = require("./sasl/scram-sha-256");
|
|
8
|
+
function createAuthFlow(options) {
|
|
9
|
+
switch (options.auth.method) {
|
|
10
|
+
case 'password':
|
|
11
|
+
return new password_1.PasswordAuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
12
|
+
case 'md5':
|
|
13
|
+
return new md5_1.Md5AuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
14
|
+
case 'scram-sha-256':
|
|
15
|
+
return new scram_sha_256_1.ScramSha256AuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
16
|
+
case 'cert':
|
|
17
|
+
return new cert_1.CertAuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Unsupported auth method: ${options.auth.method}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.createAuthFlow = createAuthFlow;
|