firebase-tools 13.19.0 → 13.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/apiv2.js +8 -1
- package/lib/auth.js +14 -2
- 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/dataplaneClient.js +12 -9
- 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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataConnectToolkitController = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
5
|
+
const portUtils = require("./portUtils");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const dataconnectEmulator_1 = require("./dataconnectEmulator");
|
|
8
|
+
const name = "Data Connect Toolkit";
|
|
9
|
+
class DataConnectToolkitController {
|
|
10
|
+
static async start(args) {
|
|
11
|
+
if (this.isRunning || this.instance) {
|
|
12
|
+
throw new error_1.FirebaseError(`${name} is already running!`, {});
|
|
13
|
+
}
|
|
14
|
+
this.instance = new dataconnectEmulator_1.DataConnectEmulator(args);
|
|
15
|
+
this.isRunning = true;
|
|
16
|
+
await this.instance.start();
|
|
17
|
+
const info = this.instance.getInfo();
|
|
18
|
+
await portUtils.waitForPortUsed(info.port, (0, utils_1.connectableHostname)(info.host), info.timeout);
|
|
19
|
+
}
|
|
20
|
+
static async stop() {
|
|
21
|
+
if (!this.isRunning) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
await this.instance.stop();
|
|
26
|
+
this.isRunning = false;
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
throw new error_1.FirebaseError(`Data Connect Toolkit failed to stop with error: ${e}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
static getInfo() {
|
|
33
|
+
return this.instance.getInfo();
|
|
34
|
+
}
|
|
35
|
+
static getUrl() {
|
|
36
|
+
const info = this.instance.getInfo();
|
|
37
|
+
if (info.host.includes(":")) {
|
|
38
|
+
return `http://[${info.host}]:${info.port}`;
|
|
39
|
+
}
|
|
40
|
+
return `http://${info.host}:${info.port}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.DataConnectToolkitController = DataConnectToolkitController;
|
|
44
|
+
DataConnectToolkitController.isRunning = false;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.start = exports.downloadIfNecessary = exports.stop = exports.getPID = exports.get = exports.getDownloadDetails = exports.requiresJava = exports.handleEmulatorProcessError = exports._getCommand = exports.getLogFileName = exports.DownloadDetails = void 0;
|
|
4
|
+
const lsofi = require("lsofi");
|
|
4
5
|
const types_1 = require("./types");
|
|
5
6
|
const constants_1 = require("./constants");
|
|
6
7
|
const error_1 = require("../error");
|
|
@@ -14,6 +15,7 @@ const os = require("os");
|
|
|
14
15
|
const registry_1 = require("./registry");
|
|
15
16
|
const download_1 = require("../emulator/download");
|
|
16
17
|
const experiments = require("../experiments");
|
|
18
|
+
const process = require("process");
|
|
17
19
|
const EMULATOR_INSTANCE_KILL_TIMEOUT = 4000;
|
|
18
20
|
const CACHE_DIR = process.env.FIREBASE_EMULATORS_PATH || path.join(os.homedir(), ".cache", "firebase", "emulators");
|
|
19
21
|
const EMULATOR_UPDATE_DETAILS = {
|
|
@@ -46,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
46
48
|
},
|
|
47
49
|
dataconnect: process.platform === "darwin"
|
|
48
50
|
? {
|
|
49
|
-
version: "1.3
|
|
50
|
-
expectedSize:
|
|
51
|
-
expectedChecksum: "
|
|
51
|
+
version: "1.4.3",
|
|
52
|
+
expectedSize: 25125632,
|
|
53
|
+
expectedChecksum: "1edc7180b101b1b3653429ecb8312d2d",
|
|
52
54
|
}
|
|
53
55
|
: process.platform === "win32"
|
|
54
56
|
? {
|
|
55
|
-
version: "1.3
|
|
56
|
-
expectedSize:
|
|
57
|
-
expectedChecksum: "
|
|
57
|
+
version: "1.4.3",
|
|
58
|
+
expectedSize: 25548800,
|
|
59
|
+
expectedChecksum: "16b31831577778e8842c8715f35b4faa",
|
|
58
60
|
}
|
|
59
61
|
: {
|
|
60
|
-
version: "1.3
|
|
61
|
-
expectedSize:
|
|
62
|
-
expectedChecksum: "
|
|
62
|
+
version: "1.4.3",
|
|
63
|
+
expectedSize: 25034904,
|
|
64
|
+
expectedChecksum: "c959f7bd2ed3221c509cb7ad22956de3",
|
|
63
65
|
},
|
|
64
66
|
};
|
|
65
67
|
exports.DownloadDetails = {
|
|
@@ -295,6 +297,7 @@ function _getCommand(emulator, args) {
|
|
|
295
297
|
optionalArgs: baseCmd.optionalArgs,
|
|
296
298
|
joinArgs: baseCmd.joinArgs,
|
|
297
299
|
shell: baseCmd.shell,
|
|
300
|
+
port: args.port,
|
|
298
301
|
};
|
|
299
302
|
}
|
|
300
303
|
exports._getCommand = _getCommand;
|
|
@@ -308,11 +311,15 @@ async function _fatal(emulator, errorMsg) {
|
|
|
308
311
|
process.exit(1);
|
|
309
312
|
}
|
|
310
313
|
}
|
|
311
|
-
async function handleEmulatorProcessError(emulator, err) {
|
|
314
|
+
async function handleEmulatorProcessError(emulator, err, port) {
|
|
312
315
|
const description = constants_1.Constants.description(emulator);
|
|
313
316
|
if (err.path === "java" && err.code === "ENOENT") {
|
|
314
317
|
await _fatal(emulator, `${description} has exited because java is not installed, you can install it from https://openjdk.java.net/install/`);
|
|
315
318
|
}
|
|
319
|
+
else if (err.code === "EADDRINUSE") {
|
|
320
|
+
const ps = port ? await lsofi(port) : false;
|
|
321
|
+
await _fatal(emulator, `${description} has exited because its configured port is already in use${ps ? ` by process number ${ps}` : ""}. Are you running another copy of the emulator suite?`);
|
|
322
|
+
}
|
|
316
323
|
else {
|
|
317
324
|
await _fatal(emulator, `${description} has exited: ${err}`);
|
|
318
325
|
}
|
|
@@ -366,9 +373,13 @@ async function _runBinary(emulator, command, extraEnv) {
|
|
|
366
373
|
if (data.toString().includes("java.lang.UnsupportedClassVersionError")) {
|
|
367
374
|
logger.logLabeled("WARN", emulator.name, "Unsupported java version, make sure java --version reports 1.8 or higher.");
|
|
368
375
|
}
|
|
376
|
+
if (data.toString().includes("address already in use")) {
|
|
377
|
+
const message = `${description} has exited because its configured port ${command.port} is already in use. Are you running another copy of the emulator suite?`;
|
|
378
|
+
logger.logLabeled("ERROR", emulator.name, message);
|
|
379
|
+
}
|
|
369
380
|
});
|
|
370
381
|
emulator.instance.on("error", (err) => {
|
|
371
|
-
handleEmulatorProcessError(emulator.name, err);
|
|
382
|
+
void handleEmulatorProcessError(emulator.name, err, command.port);
|
|
372
383
|
});
|
|
373
384
|
emulator.instance.once("exit", async (code, signal) => {
|
|
374
385
|
if (signal) {
|
package/lib/emulator/hub.js
CHANGED
|
@@ -10,6 +10,7 @@ const types_1 = require("./types");
|
|
|
10
10
|
const hubExport_1 = require("./hubExport");
|
|
11
11
|
const registry_1 = require("./registry");
|
|
12
12
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
13
|
+
const utils_1 = require("../utils");
|
|
13
14
|
const pkg = require("../../package.json");
|
|
14
15
|
class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
15
16
|
static readLocatorFile(projectId) {
|
|
@@ -19,7 +20,7 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
19
20
|
}
|
|
20
21
|
const data = fs.readFileSync(locatorPath, "utf8").toString();
|
|
21
22
|
const locator = JSON.parse(data);
|
|
22
|
-
if (locator.version !== this.CLI_VERSION) {
|
|
23
|
+
if (!utils_1.isVSCodeExtension && locator.version !== this.CLI_VERSION) {
|
|
23
24
|
logger_1.logger.debug(`Found locator with mismatched version, ignoring: ${JSON.stringify(locator)}`);
|
|
24
25
|
return undefined;
|
|
25
26
|
}
|
|
@@ -11,7 +11,6 @@ const types_1 = require("./types");
|
|
|
11
11
|
const constants_1 = require("./constants");
|
|
12
12
|
const emulatorLogger_1 = require("./emulatorLogger");
|
|
13
13
|
const node_child_process_1 = require("node:child_process");
|
|
14
|
-
const dataconnectEmulator_1 = require("./dataconnectEmulator");
|
|
15
14
|
const RESTRICTED_PORTS = new Set([
|
|
16
15
|
1,
|
|
17
16
|
7,
|
|
@@ -147,6 +146,7 @@ const EMULATOR_CAN_LISTEN_ON_PRIMARY_ONLY = {
|
|
|
147
146
|
firestore: true,
|
|
148
147
|
"firestore.websocket": true,
|
|
149
148
|
pubsub: true,
|
|
149
|
+
"dataconnect.postgres": true,
|
|
150
150
|
dataconnect: false,
|
|
151
151
|
hub: false,
|
|
152
152
|
ui: false,
|
|
@@ -185,7 +185,11 @@ async function resolveHostAndAssignPorts(listenConfig) {
|
|
|
185
185
|
lookupForHost.set(host, lookup);
|
|
186
186
|
}
|
|
187
187
|
const findAddrs = lookup.then(async (addrs) => {
|
|
188
|
-
const emuLogger = emulatorLogger_1.EmulatorLogger.forEmulator(name === "firestore.websocket"
|
|
188
|
+
const emuLogger = emulatorLogger_1.EmulatorLogger.forEmulator(name === "firestore.websocket"
|
|
189
|
+
? types_1.Emulators.FIRESTORE
|
|
190
|
+
: name === "dataconnect.postgres"
|
|
191
|
+
? types_1.Emulators.DATACONNECT
|
|
192
|
+
: name);
|
|
189
193
|
if (addrs.some((addr) => addr.address === dns_1.IPV6_UNSPECIFIED.address)) {
|
|
190
194
|
if (!addrs.some((addr) => addr.address === dns_1.IPV4_UNSPECIFIED.address)) {
|
|
191
195
|
emuLogger.logLabeled("DEBUG", name, `testing listening on IPv4 wildcard in addition to IPv6. To listen on IPv6 only, use "::0" instead.`);
|
|
@@ -222,14 +226,6 @@ async function resolveHostAndAssignPorts(listenConfig) {
|
|
|
222
226
|
available.push(listen);
|
|
223
227
|
}
|
|
224
228
|
else {
|
|
225
|
-
if (/^dataconnect/i.exec(name)) {
|
|
226
|
-
const alreadyRunning = await (0, dataconnectEmulator_1.checkIfDataConnectEmulatorRunningOnAddress)(listen);
|
|
227
|
-
if (alreadyRunning) {
|
|
228
|
-
emuLogger.logLabeled("DEBUG", "dataconnect", `Detected already running emulator on ${listen.address}:${listen.port}. Will attempt to reuse it.`);
|
|
229
|
-
}
|
|
230
|
-
available.push(listen);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
229
|
if (!portFixed) {
|
|
234
230
|
if (i > 0) {
|
|
235
231
|
emuLogger.logLabeled("DEBUG", name, `Port ${p} taken on secondary address ${addr.address}, will keep searching to find a better port.`);
|
|
@@ -281,7 +277,9 @@ exports.resolveHostAndAssignPorts = resolveHostAndAssignPorts;
|
|
|
281
277
|
function portDescription(name) {
|
|
282
278
|
return name === "firestore.websocket"
|
|
283
279
|
? `websocket server for ${types_1.Emulators.FIRESTORE}`
|
|
284
|
-
:
|
|
280
|
+
: name === "dataconnect.postgres"
|
|
281
|
+
? `postgres server for ${types_1.Emulators.DATACONNECT}`
|
|
282
|
+
: constants_1.Constants.description(name);
|
|
285
283
|
}
|
|
286
284
|
function warnPartiallyAvailablePort(emuLogger, port, available, unavailable) {
|
|
287
285
|
emuLogger.logLabeled("WARN", `Port ${port} is available on ` +
|
|
@@ -109,7 +109,7 @@ class StorageRulesRuntime {
|
|
|
109
109
|
};
|
|
110
110
|
});
|
|
111
111
|
this._childprocess.on("error", (err) => {
|
|
112
|
-
(0, downloadableEmulators_1.handleEmulatorProcessError)(types_2.Emulators.STORAGE, err);
|
|
112
|
+
void (0, downloadableEmulators_1.handleEmulatorProcessError)(types_2.Emulators.STORAGE, err);
|
|
113
113
|
});
|
|
114
114
|
(_a = this._childprocess.stderr) === null || _a === void 0 ? void 0 : _a.on("data", (buf) => {
|
|
115
115
|
const error = buf.toString();
|
package/lib/experiments.js
CHANGED
|
@@ -109,6 +109,7 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
109
109
|
fdccompatiblemode: {
|
|
110
110
|
shortDescription: "Enable Data Connect schema migrations in Compatible Mode",
|
|
111
111
|
fullDescription: "Enable Data Connect schema migrations in Compatible Mode",
|
|
112
|
+
default: true,
|
|
112
113
|
public: false,
|
|
113
114
|
},
|
|
114
115
|
});
|
|
@@ -10,12 +10,14 @@ const cloudsql = require("../../../gcp/cloudsql/cloudsqladmin");
|
|
|
10
10
|
const ensureApis_1 = require("../../../dataconnect/ensureApis");
|
|
11
11
|
const experiments = require("../../../experiments");
|
|
12
12
|
const client_1 = require("../../../dataconnect/client");
|
|
13
|
-
const
|
|
13
|
+
const types_1 = require("../../../dataconnect/types");
|
|
14
14
|
const names_1 = require("../../../dataconnect/names");
|
|
15
15
|
const logger_1 = require("../../../logger");
|
|
16
16
|
const templates_1 = require("../../../templates");
|
|
17
17
|
const utils_1 = require("../../../utils");
|
|
18
18
|
const cloudbilling_1 = require("../../../gcp/cloudbilling");
|
|
19
|
+
const sdk = require("./sdk");
|
|
20
|
+
const fileUtils_1 = require("../../../dataconnect/fileUtils");
|
|
19
21
|
const DATACONNECT_YAML_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/dataconnect.yaml");
|
|
20
22
|
const DATACONNECT_YAML_COMPAT_EXPERIMENT_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/dataconnect-fdccompatiblemode.yaml");
|
|
21
23
|
const CONNECTOR_YAML_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/connector.yaml");
|
|
@@ -37,14 +39,28 @@ const defaultConnector = {
|
|
|
37
39
|
],
|
|
38
40
|
};
|
|
39
41
|
async function doSetup(setup, config) {
|
|
40
|
-
const info = await askQuestions(setup
|
|
42
|
+
const info = await askQuestions(setup);
|
|
41
43
|
await actuate(setup, config, info);
|
|
44
|
+
const cwdPlatformGuess = await (0, fileUtils_1.getPlatformFromFolder)(process.cwd());
|
|
45
|
+
if (cwdPlatformGuess !== types_1.Platform.UNDETERMINED) {
|
|
46
|
+
await sdk.doSetup(setup, config);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const promptForSDKGeneration = await (0, prompt_1.confirm)({
|
|
50
|
+
message: `Would you like to configure generated SDKs now?`,
|
|
51
|
+
default: false,
|
|
52
|
+
});
|
|
53
|
+
if (promptForSDKGeneration) {
|
|
54
|
+
await sdk.doSetup(setup, config);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
(0, utils_1.logBullet)(`If you'd like to generate an SDK for your new connector later, run ${clc.bold("firebase init dataconnect:sdk")}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
42
60
|
logger_1.logger.info("");
|
|
43
|
-
(0, utils_1.logSuccess)(`If you'd like to generate an SDK for your new connector, run ${clc.bold("firebase init dataconnect:sdk")}`);
|
|
44
61
|
}
|
|
45
62
|
exports.doSetup = doSetup;
|
|
46
|
-
async function askQuestions(setup
|
|
47
|
-
var _a, _b, _c;
|
|
63
|
+
async function askQuestions(setup) {
|
|
48
64
|
let info = {
|
|
49
65
|
serviceId: "",
|
|
50
66
|
locationId: "",
|
|
@@ -57,28 +73,42 @@ async function askQuestions(setup, config) {
|
|
|
57
73
|
shouldProvisionCSQL: false,
|
|
58
74
|
};
|
|
59
75
|
const isBillingEnabled = setup.projectId ? await (0, cloudbilling_1.checkBillingEnabled)(setup.projectId) : false;
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
if (setup.projectId) {
|
|
77
|
+
isBillingEnabled ? await (0, ensureApis_1.ensureApis)(setup.projectId) : await (0, ensureApis_1.ensureSparkApis)(setup.projectId);
|
|
78
|
+
}
|
|
79
|
+
info = await checkExistingInstances(setup, info, isBillingEnabled);
|
|
80
|
+
const requiredConfigUnset = info.serviceId === "" ||
|
|
81
|
+
info.cloudSqlInstanceId === "" ||
|
|
82
|
+
info.locationId === "" ||
|
|
83
|
+
info.cloudSqlDatabase === "";
|
|
84
|
+
const shouldConfigureBackend = isBillingEnabled && requiredConfigUnset
|
|
85
|
+
? await (0, prompt_1.confirm)({
|
|
86
|
+
message: `Would you like to configure your backend resources now?`,
|
|
87
|
+
default: false,
|
|
88
|
+
})
|
|
89
|
+
: false;
|
|
90
|
+
if (shouldConfigureBackend) {
|
|
91
|
+
info = await promptForService(info);
|
|
62
92
|
info = await promptForCloudSQLInstance(setup, info);
|
|
93
|
+
info = await promptForDatabase(info);
|
|
94
|
+
info.shouldProvisionCSQL = !!(setup.projectId &&
|
|
95
|
+
(info.isNewInstance || info.isNewDatabase) &&
|
|
96
|
+
isBillingEnabled &&
|
|
97
|
+
(await (0, prompt_1.confirm)({
|
|
98
|
+
message: `Would you like to provision your Cloud SQL instance and database now?${info.isNewInstance ? " This will take several minutes." : ""}.`,
|
|
99
|
+
default: true,
|
|
100
|
+
})));
|
|
63
101
|
}
|
|
64
|
-
|
|
65
|
-
|
|
102
|
+
else {
|
|
103
|
+
if (requiredConfigUnset) {
|
|
104
|
+
(0, utils_1.logBullet)(`Setting placeholder values in dataconnect.yaml. You can edit these before you deploy to specify different IDs or regions.`);
|
|
105
|
+
}
|
|
106
|
+
info.serviceId = info.serviceId !== "" ? info.serviceId : (0, path_1.basename)(process.cwd());
|
|
107
|
+
info.cloudSqlInstanceId =
|
|
108
|
+
info.cloudSqlInstanceId !== "" ? info.cloudSqlInstanceId : `${info.serviceId || "app"}-fdc`;
|
|
109
|
+
info.locationId = info.locationId !== "" ? info.locationId : `us-central1`;
|
|
110
|
+
info.cloudSqlDatabase = info.cloudSqlDatabase !== "" ? info.cloudSqlDatabase : `fdcdb`;
|
|
66
111
|
}
|
|
67
|
-
const defaultConnectionString = (_c = (_b = (_a = setup.rcfile.dataconnectEmulatorConfig) === null || _a === void 0 ? void 0 : _a.postgres) === null || _b === void 0 ? void 0 : _b.localConnectionString) !== null && _c !== void 0 ? _c : emulators_1.DEFAULT_POSTGRES_CONNECTION;
|
|
68
|
-
const localConnectionString = await (0, prompt_1.promptOnce)({
|
|
69
|
-
type: "input",
|
|
70
|
-
name: "localConnectionString",
|
|
71
|
-
message: `What is the connection string of the local Postgres instance you would like to use with the Data Connect emulator?`,
|
|
72
|
-
default: defaultConnectionString,
|
|
73
|
-
});
|
|
74
|
-
setup.rcfile.dataconnectEmulatorConfig = { postgres: { localConnectionString } };
|
|
75
|
-
info.shouldProvisionCSQL = !!(setup.projectId &&
|
|
76
|
-
(info.isNewInstance || info.isNewDatabase) &&
|
|
77
|
-
isBillingEnabled &&
|
|
78
|
-
(await (0, prompt_1.confirm)({
|
|
79
|
-
message: `Would you like to provision your Cloud SQL instance and database now?${info.isNewInstance ? " This will take several minutes." : ""}.`,
|
|
80
|
-
default: true,
|
|
81
|
-
})));
|
|
82
112
|
return info;
|
|
83
113
|
}
|
|
84
114
|
async function actuate(setup, config, info) {
|
|
@@ -89,6 +119,7 @@ async function actuate(setup, config, info) {
|
|
|
89
119
|
locationId: info.locationId,
|
|
90
120
|
instanceId: info.cloudSqlInstanceId,
|
|
91
121
|
databaseId: info.cloudSqlDatabase,
|
|
122
|
+
configYamlPath: (0, path_1.join)(config.get("dataconnect.source"), "dataconnect.yaml"),
|
|
92
123
|
enableGoogleMlIntegration: false,
|
|
93
124
|
waitForCreation: false,
|
|
94
125
|
});
|
|
@@ -97,7 +128,6 @@ async function actuate(setup, config, info) {
|
|
|
97
128
|
exports.actuate = actuate;
|
|
98
129
|
async function writeFiles(config, info) {
|
|
99
130
|
const dir = config.get("dataconnect.source") || "dataconnect";
|
|
100
|
-
console.log(dir);
|
|
101
131
|
const subbedDataconnectYaml = subDataconnectYamlValues(Object.assign(Object.assign({}, info), { connectorDirs: info.connectors.map((c) => c.path) }));
|
|
102
132
|
config.set("dataconnect", { source: dir });
|
|
103
133
|
await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml);
|
|
@@ -148,79 +178,67 @@ function subConnectorYamlValues(replacementValues) {
|
|
|
148
178
|
}
|
|
149
179
|
return replaced;
|
|
150
180
|
}
|
|
151
|
-
async function
|
|
181
|
+
async function checkExistingInstances(setup, info, isBillingEnabled) {
|
|
152
182
|
var _a, _b, _c;
|
|
153
|
-
if (setup.projectId) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
}
|
|
183
|
+
if (!setup.projectId || !isBillingEnabled) {
|
|
184
|
+
return info;
|
|
185
|
+
}
|
|
186
|
+
const existingServices = await (0, client_1.listAllServices)(setup.projectId);
|
|
187
|
+
const existingServicesAndSchemas = await Promise.all(existingServices.map(async (s) => {
|
|
188
|
+
return {
|
|
189
|
+
service: s,
|
|
190
|
+
schema: await (0, client_1.getSchema)(s.name),
|
|
191
|
+
};
|
|
192
|
+
}));
|
|
193
|
+
if (existingServicesAndSchemas.length) {
|
|
194
|
+
const choices = existingServicesAndSchemas.map((s) => {
|
|
195
|
+
const serviceName = (0, names_1.parseServiceName)(s.service.name);
|
|
196
|
+
return {
|
|
197
|
+
name: `${serviceName.location}/${serviceName.serviceId}`,
|
|
198
|
+
value: s,
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
choices.push({ name: "Create a new service", value: undefined });
|
|
202
|
+
const choice = await (0, prompt_1.promptOnce)({
|
|
203
|
+
message: "Your project already has existing services. Which would you like to set up local files for?",
|
|
204
|
+
type: "list",
|
|
205
|
+
choices,
|
|
206
|
+
});
|
|
207
|
+
if (choice) {
|
|
208
|
+
const serviceName = (0, names_1.parseServiceName)(choice.service.name);
|
|
209
|
+
info.serviceId = serviceName.serviceId;
|
|
210
|
+
info.locationId = serviceName.location;
|
|
211
|
+
if (choice.schema) {
|
|
212
|
+
const primaryDatasource = choice.schema.datasources.find((d) => d.postgresql);
|
|
213
|
+
if ((_a = primaryDatasource === null || primaryDatasource === void 0 ? void 0 : primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) {
|
|
214
|
+
const instanceName = (0, names_1.parseCloudSQLInstanceName)(primaryDatasource.postgresql.cloudSql.instance);
|
|
215
|
+
info.cloudSqlInstanceId = instanceName.instanceId;
|
|
216
|
+
}
|
|
217
|
+
if (choice.schema.source.files) {
|
|
218
|
+
info.schemaGql = choice.schema.source.files;
|
|
219
|
+
}
|
|
220
|
+
info.cloudSqlDatabase = (_c = (_b = primaryDatasource === null || primaryDatasource === void 0 ? void 0 : primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.database) !== null && _c !== void 0 ? _c : "";
|
|
221
|
+
const connectors = await (0, client_1.listConnectors)(choice.service.name, [
|
|
222
|
+
"connectors.name",
|
|
223
|
+
"connectors.source.files",
|
|
224
|
+
]);
|
|
225
|
+
if (connectors.length) {
|
|
226
|
+
info.connectors = connectors.map((c) => {
|
|
227
|
+
const id = c.name.split("/").pop();
|
|
228
|
+
return {
|
|
229
|
+
id,
|
|
230
|
+
path: connectors.length === 1 ? "./connector" : `./${id}`,
|
|
231
|
+
files: c.source.files || [],
|
|
232
|
+
};
|
|
233
|
+
});
|
|
206
234
|
}
|
|
207
235
|
}
|
|
208
236
|
}
|
|
209
237
|
else {
|
|
210
|
-
await (
|
|
238
|
+
info = await promptForService(info);
|
|
211
239
|
}
|
|
212
240
|
}
|
|
213
|
-
if (info.
|
|
214
|
-
info.serviceId = await (0, prompt_1.promptOnce)({
|
|
215
|
-
message: "What ID would you like to use for this service?",
|
|
216
|
-
type: "input",
|
|
217
|
-
default: "app",
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
return info;
|
|
221
|
-
}
|
|
222
|
-
async function promptForCloudSQLInstance(setup, info) {
|
|
223
|
-
if (setup.projectId) {
|
|
241
|
+
if (info.cloudSqlInstanceId === "") {
|
|
224
242
|
const instances = await cloudsql.listInstances(setup.projectId);
|
|
225
243
|
let choices = instances.map((i) => {
|
|
226
244
|
return { name: i.name, value: i.name, location: i.region };
|
|
@@ -239,8 +257,46 @@ async function promptForCloudSQLInstance(setup, info) {
|
|
|
239
257
|
if (info.cloudSqlInstanceId !== "") {
|
|
240
258
|
info.locationId = choices.find((c) => c.value === info.cloudSqlInstanceId).location;
|
|
241
259
|
}
|
|
260
|
+
else {
|
|
261
|
+
info = await promptForCloudSQLInstance(setup, info);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (info.cloudSqlDatabase === "" && info.cloudSqlInstanceId !== "") {
|
|
266
|
+
try {
|
|
267
|
+
const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId);
|
|
268
|
+
const choices = dbs.map((d) => {
|
|
269
|
+
return { name: d.name, value: d.name };
|
|
270
|
+
});
|
|
271
|
+
choices.push({ name: "Create a new database", value: "" });
|
|
272
|
+
if (dbs.length) {
|
|
273
|
+
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
|
|
274
|
+
message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`,
|
|
275
|
+
type: "list",
|
|
276
|
+
choices,
|
|
277
|
+
});
|
|
278
|
+
if (info.cloudSqlDatabase === "") {
|
|
279
|
+
info = await promptForDatabase(info);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
242
282
|
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
logger_1.logger.debug(`[dataconnect] Cannot list databases during init: ${err}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return info;
|
|
288
|
+
}
|
|
289
|
+
async function promptForService(info) {
|
|
290
|
+
if (info.serviceId === "") {
|
|
291
|
+
info.serviceId = await (0, prompt_1.promptOnce)({
|
|
292
|
+
message: "What ID would you like to use for this service?",
|
|
293
|
+
type: "input",
|
|
294
|
+
default: (0, path_1.basename)(process.cwd()),
|
|
295
|
+
});
|
|
243
296
|
}
|
|
297
|
+
return info;
|
|
298
|
+
}
|
|
299
|
+
async function promptForCloudSQLInstance(setup, info) {
|
|
244
300
|
if (info.cloudSqlInstanceId === "") {
|
|
245
301
|
info.isNewInstance = true;
|
|
246
302
|
info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
|
|
@@ -279,26 +335,7 @@ async function locationChoices(setup) {
|
|
|
279
335
|
];
|
|
280
336
|
}
|
|
281
337
|
}
|
|
282
|
-
async function promptForDatabase(
|
|
283
|
-
if (!info.isNewInstance && setup.projectId) {
|
|
284
|
-
try {
|
|
285
|
-
const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId);
|
|
286
|
-
const choices = dbs.map((d) => {
|
|
287
|
-
return { name: d.name, value: d.name };
|
|
288
|
-
});
|
|
289
|
-
choices.push({ name: "Create a new database", value: "" });
|
|
290
|
-
if (dbs.length) {
|
|
291
|
-
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
|
|
292
|
-
message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`,
|
|
293
|
-
type: "list",
|
|
294
|
-
choices,
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
catch (err) {
|
|
299
|
-
logger_1.logger.debug(`[dataconnect] Cannot list databases during init: ${err}`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
338
|
+
async function promptForDatabase(info) {
|
|
302
339
|
if (info.cloudSqlDatabase === "") {
|
|
303
340
|
info.isNewDatabase = true;
|
|
304
341
|
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
|