firebase-tools 13.20.1 → 13.21.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/apphosting/githubConnections.js +19 -1
- package/lib/apphosting/index.js +12 -46
- package/lib/apphosting/rollout.js +127 -0
- package/lib/command.js +10 -3
- package/lib/commands/apphosting-rollouts-create.js +13 -13
- package/lib/commands/emulators-start.js +1 -1
- package/lib/config.js +14 -4
- package/lib/dataconnect/fileUtils.js +7 -43
- package/lib/dataconnect/freeTrial.js +44 -10
- package/lib/dataconnect/provisionCloudSql.js +4 -4
- package/lib/dataconnect/types.js +3 -2
- package/lib/dataconnect/webhook.js +2 -1
- package/lib/deploy/dataconnect/prepare.js +5 -0
- package/lib/emulator/apphosting/config.js +45 -0
- package/lib/emulator/apphosting/index.js +9 -11
- package/lib/emulator/apphosting/serve.js +16 -10
- package/lib/emulator/apphosting/utils.js +18 -0
- package/lib/emulator/controller.js +6 -1
- package/lib/emulator/downloadableEmulators.js +12 -12
- package/lib/emulator/eventarcEmulator.js +1 -1
- package/lib/emulator/extensionsEmulator.js +38 -6
- package/lib/emulator/functionsEmulator.js +85 -41
- package/lib/emulator/functionsEmulatorShared.js +2 -1
- package/lib/error.js +24 -1
- package/lib/extensions/emulator/triggerHelper.js +1 -1
- package/lib/extensions/extensionsApi.js +11 -8
- package/lib/extensions/runtimes/common.js +11 -19
- package/lib/extensions/runtimes/node.js +25 -22
- package/lib/extensions/types.js +16 -1
- package/lib/gcp/cloudmonitoring.js +3 -3
- package/lib/gcp/cloudsql/cloudsqladmin.js +32 -20
- package/lib/gcp/devConnect.js +38 -1
- package/lib/init/features/dataconnect/index.js +69 -85
- package/lib/init/features/dataconnect/sdk.js +69 -86
- package/lib/init/spawn.js +2 -1
- package/package.json +1 -1
|
@@ -24,6 +24,11 @@ const CONNECTOR_YAML_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconn
|
|
|
24
24
|
const SCHEMA_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/schema.gql");
|
|
25
25
|
const QUERIES_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/queries.gql");
|
|
26
26
|
const MUTATIONS_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/mutations.gql");
|
|
27
|
+
const emptyConnector = {
|
|
28
|
+
id: "default",
|
|
29
|
+
path: "./connector",
|
|
30
|
+
files: [],
|
|
31
|
+
};
|
|
27
32
|
const defaultConnector = {
|
|
28
33
|
id: "default",
|
|
29
34
|
path: "./connector",
|
|
@@ -38,29 +43,27 @@ const defaultConnector = {
|
|
|
38
43
|
},
|
|
39
44
|
],
|
|
40
45
|
};
|
|
46
|
+
const defaultSchema = { path: "schema.gql", content: SCHEMA_TEMPLATE };
|
|
41
47
|
async function doSetup(setup, config) {
|
|
42
|
-
const
|
|
48
|
+
const isBillingEnabled = setup.projectId ? await (0, cloudbilling_1.checkBillingEnabled)(setup.projectId) : false;
|
|
49
|
+
if (setup.projectId) {
|
|
50
|
+
isBillingEnabled ? await (0, ensureApis_1.ensureApis)(setup.projectId) : await (0, ensureApis_1.ensureSparkApis)(setup.projectId);
|
|
51
|
+
}
|
|
52
|
+
const info = await askQuestions(setup, isBillingEnabled);
|
|
43
53
|
await actuate(setup, config, info);
|
|
44
54
|
const cwdPlatformGuess = await (0, fileUtils_1.getPlatformFromFolder)(process.cwd());
|
|
45
|
-
if (cwdPlatformGuess !== types_1.Platform.
|
|
55
|
+
if (cwdPlatformGuess !== types_1.Platform.NONE) {
|
|
46
56
|
await sdk.doSetup(setup, config);
|
|
47
57
|
}
|
|
48
58
|
else {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
+
(0, utils_1.logBullet)(`If you'd like to add the generated SDK to your app your, run ${clc.bold("firebase init dataconnect:sdk")}`);
|
|
60
|
+
}
|
|
61
|
+
if (setup.projectId && !isBillingEnabled) {
|
|
62
|
+
(0, utils_1.logBullet)((0, freeTrial_1.upgradeInstructions)(setup.projectId));
|
|
59
63
|
}
|
|
60
|
-
logger_1.logger.info("");
|
|
61
64
|
}
|
|
62
65
|
exports.doSetup = doSetup;
|
|
63
|
-
async function askQuestions(setup) {
|
|
66
|
+
async function askQuestions(setup, isBillingEnabled) {
|
|
64
67
|
let info = {
|
|
65
68
|
serviceId: "",
|
|
66
69
|
locationId: "",
|
|
@@ -69,14 +72,10 @@ async function askQuestions(setup) {
|
|
|
69
72
|
cloudSqlDatabase: "",
|
|
70
73
|
isNewDatabase: false,
|
|
71
74
|
connectors: [defaultConnector],
|
|
72
|
-
schemaGql: [],
|
|
75
|
+
schemaGql: [defaultSchema],
|
|
73
76
|
shouldProvisionCSQL: false,
|
|
74
77
|
};
|
|
75
|
-
|
|
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);
|
|
78
|
+
info = await promptForExistingServices(setup, info, isBillingEnabled);
|
|
80
79
|
const requiredConfigUnset = info.serviceId === "" ||
|
|
81
80
|
info.cloudSqlInstanceId === "" ||
|
|
82
81
|
info.locationId === "" ||
|
|
@@ -84,13 +83,12 @@ async function askQuestions(setup) {
|
|
|
84
83
|
const shouldConfigureBackend = isBillingEnabled && requiredConfigUnset
|
|
85
84
|
? await (0, prompt_1.confirm)({
|
|
86
85
|
message: `Would you like to configure your backend resources now?`,
|
|
87
|
-
default:
|
|
86
|
+
default: true,
|
|
88
87
|
})
|
|
89
88
|
: false;
|
|
90
89
|
if (shouldConfigureBackend) {
|
|
91
90
|
info = await promptForService(info);
|
|
92
|
-
info = await
|
|
93
|
-
info = await promptForDatabase(info);
|
|
91
|
+
info = await promptForCloudSQL(setup, info);
|
|
94
92
|
info.shouldProvisionCSQL = !!(setup.projectId &&
|
|
95
93
|
(info.isNewInstance || info.isNewDatabase) &&
|
|
96
94
|
isBillingEnabled &&
|
|
@@ -100,14 +98,10 @@ async function askQuestions(setup) {
|
|
|
100
98
|
})));
|
|
101
99
|
}
|
|
102
100
|
else {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
info.
|
|
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`;
|
|
101
|
+
info.serviceId = info.serviceId || (0, path_1.basename)(process.cwd());
|
|
102
|
+
info.cloudSqlInstanceId = info.cloudSqlInstanceId || `${info.serviceId || "app"}-fdc`;
|
|
103
|
+
info.locationId = info.locationId || `us-central1`;
|
|
104
|
+
info.cloudSqlDatabase = info.cloudSqlDatabase || `fdcdb`;
|
|
111
105
|
}
|
|
112
106
|
return info;
|
|
113
107
|
}
|
|
@@ -130,16 +124,12 @@ async function writeFiles(config, info) {
|
|
|
130
124
|
const dir = config.get("dataconnect.source") || "dataconnect";
|
|
131
125
|
const subbedDataconnectYaml = subDataconnectYamlValues(Object.assign(Object.assign({}, info), { connectorDirs: info.connectors.map((c) => c.path) }));
|
|
132
126
|
config.set("dataconnect", { source: dir });
|
|
133
|
-
await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml);
|
|
127
|
+
await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml, false, true);
|
|
134
128
|
if (info.schemaGql.length) {
|
|
135
|
-
(0, utils_1.logSuccess)("The service you chose already has GQL files deployed. We'll use those instead of the default templates.");
|
|
136
129
|
for (const f of info.schemaGql) {
|
|
137
130
|
await config.askWriteProjectFile((0, path_1.join)(dir, "schema", f.path), f.content);
|
|
138
131
|
}
|
|
139
132
|
}
|
|
140
|
-
else {
|
|
141
|
-
await config.askWriteProjectFile((0, path_1.join)(dir, "schema", "schema.gql"), SCHEMA_TEMPLATE);
|
|
142
|
-
}
|
|
143
133
|
for (const c of info.connectors) {
|
|
144
134
|
await writeConnectorFiles(config, c);
|
|
145
135
|
}
|
|
@@ -178,8 +168,8 @@ function subConnectorYamlValues(replacementValues) {
|
|
|
178
168
|
}
|
|
179
169
|
return replaced;
|
|
180
170
|
}
|
|
181
|
-
async function
|
|
182
|
-
var _a, _b, _c;
|
|
171
|
+
async function promptForExistingServices(setup, info, isBillingEnabled) {
|
|
172
|
+
var _a, _b, _c, _d;
|
|
183
173
|
if (!setup.projectId || !isBillingEnabled) {
|
|
184
174
|
return info;
|
|
185
175
|
}
|
|
@@ -208,16 +198,18 @@ async function checkExistingInstances(setup, info, isBillingEnabled) {
|
|
|
208
198
|
const serviceName = (0, names_1.parseServiceName)(choice.service.name);
|
|
209
199
|
info.serviceId = serviceName.serviceId;
|
|
210
200
|
info.locationId = serviceName.location;
|
|
201
|
+
info.schemaGql = [];
|
|
202
|
+
info.connectors = [emptyConnector];
|
|
211
203
|
if (choice.schema) {
|
|
212
204
|
const primaryDatasource = choice.schema.datasources.find((d) => d.postgresql);
|
|
213
205
|
if ((_a = primaryDatasource === null || primaryDatasource === void 0 ? void 0 : primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) {
|
|
214
206
|
const instanceName = (0, names_1.parseCloudSQLInstanceName)(primaryDatasource.postgresql.cloudSql.instance);
|
|
215
207
|
info.cloudSqlInstanceId = instanceName.instanceId;
|
|
216
208
|
}
|
|
217
|
-
if (choice.schema.source.files) {
|
|
209
|
+
if ((_b = choice.schema.source.files) === null || _b === void 0 ? void 0 : _b.length) {
|
|
218
210
|
info.schemaGql = choice.schema.source.files;
|
|
219
211
|
}
|
|
220
|
-
info.cloudSqlDatabase = (
|
|
212
|
+
info.cloudSqlDatabase = (_d = (_c = primaryDatasource === null || primaryDatasource === void 0 ? void 0 : primaryDatasource.postgresql) === null || _c === void 0 ? void 0 : _c.database) !== null && _d !== void 0 ? _d : "";
|
|
221
213
|
const connectors = await (0, client_1.listConnectors)(choice.service.name, [
|
|
222
214
|
"connectors.name",
|
|
223
215
|
"connectors.source.files",
|
|
@@ -234,20 +226,24 @@ async function checkExistingInstances(setup, info, isBillingEnabled) {
|
|
|
234
226
|
}
|
|
235
227
|
}
|
|
236
228
|
}
|
|
237
|
-
else {
|
|
238
|
-
info = await promptForService(info);
|
|
239
|
-
}
|
|
240
229
|
}
|
|
241
|
-
|
|
230
|
+
return info;
|
|
231
|
+
}
|
|
232
|
+
async function promptForCloudSQL(setup, info) {
|
|
233
|
+
if (info.cloudSqlInstanceId === "" && setup.projectId) {
|
|
242
234
|
const instances = await cloudsql.listInstances(setup.projectId);
|
|
243
235
|
let choices = instances.map((i) => {
|
|
244
|
-
|
|
236
|
+
var _a;
|
|
237
|
+
let display = `${i.name} (${i.region})`;
|
|
238
|
+
if (((_a = i.settings.userLabels) === null || _a === void 0 ? void 0 : _a["firebase-data-connect"]) === "ft") {
|
|
239
|
+
display += " (no cost trial)";
|
|
240
|
+
}
|
|
241
|
+
return { name: display, value: i.name, location: i.region };
|
|
245
242
|
});
|
|
246
243
|
choices = choices.filter((c) => info.locationId === "" || info.locationId === c.location);
|
|
247
244
|
if (choices.length) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
choices.push({ name: "Create a new instance", value: "", location: "" });
|
|
245
|
+
if (!(await (0, freeTrial_1.checkFreeTrialInstanceUsed)(setup.projectId))) {
|
|
246
|
+
choices.push({ name: "Create a new free trial instance", value: "", location: "" });
|
|
251
247
|
}
|
|
252
248
|
info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
|
|
253
249
|
message: `Which CloudSQL instance would you like to use?`,
|
|
@@ -257,12 +253,25 @@ async function checkExistingInstances(setup, info, isBillingEnabled) {
|
|
|
257
253
|
if (info.cloudSqlInstanceId !== "") {
|
|
258
254
|
info.locationId = choices.find((c) => c.value === info.cloudSqlInstanceId).location;
|
|
259
255
|
}
|
|
260
|
-
else {
|
|
261
|
-
info = await promptForCloudSQLInstance(setup, info);
|
|
262
|
-
}
|
|
263
256
|
}
|
|
264
257
|
}
|
|
265
|
-
if (info.
|
|
258
|
+
if (info.cloudSqlInstanceId === "") {
|
|
259
|
+
info.isNewInstance = true;
|
|
260
|
+
info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
|
|
261
|
+
message: `What ID would you like to use for your new CloudSQL instance?`,
|
|
262
|
+
type: "input",
|
|
263
|
+
default: `${info.serviceId || "app"}-fdc`,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (info.locationId === "") {
|
|
267
|
+
const choices = await locationChoices(setup);
|
|
268
|
+
info.locationId = await (0, prompt_1.promptOnce)({
|
|
269
|
+
message: "What location would like to use?",
|
|
270
|
+
type: "list",
|
|
271
|
+
choices,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
if (info.cloudSqlDatabase === "" && setup.projectId) {
|
|
266
275
|
try {
|
|
267
276
|
const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId);
|
|
268
277
|
const choices = dbs.map((d) => {
|
|
@@ -275,15 +284,20 @@ async function checkExistingInstances(setup, info, isBillingEnabled) {
|
|
|
275
284
|
type: "list",
|
|
276
285
|
choices,
|
|
277
286
|
});
|
|
278
|
-
if (info.cloudSqlDatabase === "") {
|
|
279
|
-
info = await promptForDatabase(info);
|
|
280
|
-
}
|
|
281
287
|
}
|
|
282
288
|
}
|
|
283
289
|
catch (err) {
|
|
284
290
|
logger_1.logger.debug(`[dataconnect] Cannot list databases during init: ${err}`);
|
|
285
291
|
}
|
|
286
292
|
}
|
|
293
|
+
if (info.cloudSqlDatabase === "") {
|
|
294
|
+
info.isNewDatabase = true;
|
|
295
|
+
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
|
|
296
|
+
message: `What ID would you like to use for your new database in ${info.cloudSqlInstanceId}?`,
|
|
297
|
+
type: "input",
|
|
298
|
+
default: `fdcdb`,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
287
301
|
return info;
|
|
288
302
|
}
|
|
289
303
|
async function promptForService(info) {
|
|
@@ -296,25 +310,6 @@ async function promptForService(info) {
|
|
|
296
310
|
}
|
|
297
311
|
return info;
|
|
298
312
|
}
|
|
299
|
-
async function promptForCloudSQLInstance(setup, info) {
|
|
300
|
-
if (info.cloudSqlInstanceId === "") {
|
|
301
|
-
info.isNewInstance = true;
|
|
302
|
-
info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
|
|
303
|
-
message: `What ID would you like to use for your new CloudSQL instance?`,
|
|
304
|
-
type: "input",
|
|
305
|
-
default: `${info.serviceId || "app"}-fdc`,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
if (info.locationId === "") {
|
|
309
|
-
const choices = await locationChoices(setup);
|
|
310
|
-
info.locationId = await (0, prompt_1.promptOnce)({
|
|
311
|
-
message: "What location would like to use?",
|
|
312
|
-
type: "list",
|
|
313
|
-
choices,
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
return info;
|
|
317
|
-
}
|
|
318
313
|
async function locationChoices(setup) {
|
|
319
314
|
if (setup.projectId) {
|
|
320
315
|
const locations = await (0, client_1.listLocations)(setup.projectId);
|
|
@@ -335,14 +330,3 @@ async function locationChoices(setup) {
|
|
|
335
330
|
];
|
|
336
331
|
}
|
|
337
332
|
}
|
|
338
|
-
async function promptForDatabase(info) {
|
|
339
|
-
if (info.cloudSqlDatabase === "") {
|
|
340
|
-
info.isNewDatabase = true;
|
|
341
|
-
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
|
|
342
|
-
message: `What ID would you like to use for your new database in ${info.cloudSqlInstanceId}?`,
|
|
343
|
-
type: "input",
|
|
344
|
-
default: `fdcdb`,
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
return info;
|
|
348
|
-
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.actuate = exports.doSetup = exports.FDC_APP_FOLDER = void 0;
|
|
3
|
+
exports.actuate = exports.generateSdkYaml = exports.doSetup = exports.FDC_APP_FOLDER = void 0;
|
|
4
4
|
const yaml = require("yaml");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const clc = require("colorette");
|
|
7
7
|
const path = require("path");
|
|
8
|
+
const fsutils_1 = require("../../../fsutils");
|
|
8
9
|
const prompt_1 = require("../../../prompt");
|
|
9
10
|
const fileUtils_1 = require("../../../dataconnect/fileUtils");
|
|
10
11
|
const load_1 = require("../../../dataconnect/load");
|
|
@@ -16,12 +17,12 @@ const utils_1 = require("../../../utils");
|
|
|
16
17
|
exports.FDC_APP_FOLDER = "_FDC_APP_FOLDER";
|
|
17
18
|
async function doSetup(setup, config) {
|
|
18
19
|
const sdkInfo = await askQuestions(setup, config);
|
|
19
|
-
await actuate(sdkInfo
|
|
20
|
-
(0, utils_1.logSuccess)(`If you'd like to
|
|
20
|
+
await actuate(sdkInfo);
|
|
21
|
+
(0, utils_1.logSuccess)(`If you'd like to add more generated SDKs to your app your later, run ${clc.bold("firebase init dataconnect:sdk")} again`);
|
|
21
22
|
}
|
|
22
23
|
exports.doSetup = doSetup;
|
|
23
24
|
async function askQuestions(setup, config) {
|
|
24
|
-
var _a
|
|
25
|
+
var _a;
|
|
25
26
|
const serviceCfgs = (0, fileUtils_1.readFirebaseJson)(config);
|
|
26
27
|
const serviceInfos = await Promise.all(serviceCfgs.map((c) => (0, load_1.load)(setup.projectId || "", config, c.source)));
|
|
27
28
|
const connectorChoices = serviceInfos
|
|
@@ -37,121 +38,103 @@ async function askQuestions(setup, config) {
|
|
|
37
38
|
if (!connectorChoices.length) {
|
|
38
39
|
throw new error_1.FirebaseError(`Your config has no connectors to set up SDKs for. Run ${clc.bold("firebase init dataconnect")} to set up a service and connectors.`);
|
|
39
40
|
}
|
|
40
|
-
let targetPlatform = types_1.Platform.UNDETERMINED;
|
|
41
41
|
let appDir = process.env[exports.FDC_APP_FOLDER] || process.cwd();
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
(0,
|
|
45
|
-
|
|
42
|
+
let targetPlatform = await (0, fileUtils_1.getPlatformFromFolder)(appDir);
|
|
43
|
+
if (targetPlatform === types_1.Platform.NONE && !((_a = process.env[exports.FDC_APP_FOLDER]) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
44
|
+
appDir = await (0, prompt_1.promptForDirectory)({
|
|
45
|
+
config,
|
|
46
|
+
message: "Where is your app directory? Leave blank to set up a generated SDK in your current directory.",
|
|
47
|
+
});
|
|
48
|
+
targetPlatform = await (0, fileUtils_1.getPlatformFromFolder)(appDir);
|
|
46
49
|
}
|
|
47
|
-
|
|
48
|
-
(
|
|
49
|
-
|
|
50
|
-
(_a = process.env[exports.FDC_APP_FOLDER]) !== null && _a !== void 0 ? _a : (await (0, prompt_1.promptForDirectory)({
|
|
51
|
-
config,
|
|
52
|
-
message: "Where is your app directory? Leave blank to set up a generated SDK in your current directory.",
|
|
53
|
-
}));
|
|
54
|
-
const platformGuess = await (0, fileUtils_1.getPlatformFromFolder)(appDir);
|
|
55
|
-
if (platformGuess !== types_1.Platform.UNDETERMINED) {
|
|
56
|
-
(0, utils_1.logSuccess)(`Detected ${platformGuess} app in directory ${appDir}`);
|
|
57
|
-
targetPlatform = platformGuess;
|
|
50
|
+
if (targetPlatform === types_1.Platform.NONE || targetPlatform === types_1.Platform.MULTIPLE) {
|
|
51
|
+
if (targetPlatform === types_1.Platform.NONE) {
|
|
52
|
+
(0, utils_1.logBullet)(`Couldn't automatically detect app your in directory ${appDir}.`);
|
|
58
53
|
}
|
|
59
54
|
else {
|
|
60
|
-
(0, utils_1.
|
|
61
|
-
const platforms = [
|
|
62
|
-
{ name: "iOS (Swift)", value: types_1.Platform.IOS },
|
|
63
|
-
{ name: "Web (JavaScript)", value: types_1.Platform.WEB },
|
|
64
|
-
{ name: "Android (Kotlin)", value: types_1.Platform.ANDROID },
|
|
65
|
-
];
|
|
66
|
-
targetPlatform = await (0, prompt_1.promptOnce)({
|
|
67
|
-
message: "Which platform do you want to set up a generated SDK for?",
|
|
68
|
-
type: "list",
|
|
69
|
-
choices: platforms,
|
|
70
|
-
});
|
|
55
|
+
(0, utils_1.logSuccess)(`Detected multiple app platforms in directory ${appDir}`);
|
|
71
56
|
}
|
|
57
|
+
const platforms = [
|
|
58
|
+
{ name: "iOS (Swift)", value: types_1.Platform.IOS },
|
|
59
|
+
{ name: "Web (JavaScript)", value: types_1.Platform.WEB },
|
|
60
|
+
{ name: "Android (Kotlin)", value: types_1.Platform.ANDROID },
|
|
61
|
+
{ name: "Flutter (Dart)", value: types_1.Platform.FLUTTER },
|
|
62
|
+
];
|
|
63
|
+
targetPlatform = await (0, prompt_1.promptOnce)({
|
|
64
|
+
message: "Which platform do you want to set up a generated SDK for?",
|
|
65
|
+
type: "list",
|
|
66
|
+
choices: platforms,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
(0, utils_1.logSuccess)(`Detected ${targetPlatform} app in directory ${appDir}`);
|
|
72
71
|
}
|
|
73
72
|
const connectorInfo = await (0, prompt_1.promptOnce)({
|
|
74
73
|
message: "Which connector do you want set up a generated SDK for?",
|
|
75
74
|
type: "list",
|
|
76
75
|
choices: connectorChoices,
|
|
77
76
|
});
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
const connectorYaml = JSON.parse(JSON.stringify(connectorInfo.connectorYaml));
|
|
78
|
+
const newConnectorYaml = generateSdkYaml(targetPlatform, connectorYaml, connectorInfo.directory, appDir);
|
|
79
|
+
const connectorYamlContents = yaml.stringify(newConnectorYaml);
|
|
80
|
+
connectorInfo.connectorYaml = newConnectorYaml;
|
|
81
|
+
const displayIOSWarning = targetPlatform === types_1.Platform.IOS;
|
|
82
|
+
return { connectorYamlContents, connectorInfo, displayIOSWarning };
|
|
83
|
+
}
|
|
84
|
+
function generateSdkYaml(targetPlatform, connectorYaml, connectorDir, appDir) {
|
|
85
|
+
if (!connectorYaml.generate) {
|
|
86
|
+
connectorYaml.generate = {};
|
|
81
87
|
}
|
|
82
|
-
let displayIOSWarning = false;
|
|
83
88
|
if (targetPlatform === types_1.Platform.IOS) {
|
|
84
|
-
const
|
|
85
|
-
path.relative(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
displayIOSWarning = true;
|
|
89
|
+
const swiftSdk = {
|
|
90
|
+
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/swift`)),
|
|
91
|
+
package: (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(connectorYaml.connectorId)) + "Connector",
|
|
92
|
+
};
|
|
93
|
+
connectorYaml.generate.swiftSdk = swiftSdk;
|
|
90
94
|
}
|
|
91
95
|
if (targetPlatform === types_1.Platform.WEB) {
|
|
92
|
-
const
|
|
93
|
-
path.relative(connectorInfo.directory, path.join(appDir, `generated/javascript/${newConnectorYaml.connectorId}`));
|
|
94
|
-
const pkg = (_g = (_f = newConnectorYaml.generate.javascriptSdk) === null || _f === void 0 ? void 0 : _f.package) !== null && _g !== void 0 ? _g : `@firebasegen/${connectorInfo.connectorYaml.connectorId}`;
|
|
96
|
+
const pkg = `${connectorYaml.connectorId}-connector`;
|
|
95
97
|
const javascriptSdk = {
|
|
96
|
-
outputDir,
|
|
97
|
-
package: pkg
|
|
98
|
+
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/js/${pkg}`)),
|
|
99
|
+
package: `@firebasegen/${pkg}`,
|
|
100
|
+
packageJsonDir: path.relative(connectorDir, appDir),
|
|
98
101
|
};
|
|
99
|
-
|
|
100
|
-
(await (0, prompt_1.confirm)({
|
|
101
|
-
message: "Would you like to add a dependency on the generated SDK to your package.json?",
|
|
102
|
-
}))) {
|
|
103
|
-
javascriptSdk.packageJsonDir = path.relative(connectorInfo.directory, appDir);
|
|
104
|
-
}
|
|
105
|
-
newConnectorYaml.generate.javascriptSdk = javascriptSdk;
|
|
102
|
+
connectorYaml.generate.javascriptSdk = javascriptSdk;
|
|
106
103
|
}
|
|
107
|
-
if (targetPlatform === types_1.Platform.
|
|
108
|
-
const
|
|
109
|
-
path.relative(connectorInfo.directory, path.join(appDir, `generated/dart/${newConnectorYaml.connectorId}`));
|
|
110
|
-
const pkg = (_k = (_j = newConnectorYaml.generate.dartSdk) === null || _j === void 0 ? void 0 : _j.package) !== null && _k !== void 0 ? _k : newConnectorYaml.connectorId;
|
|
104
|
+
if (targetPlatform === types_1.Platform.FLUTTER) {
|
|
105
|
+
const pkg = `${(0, lodash_1.snakeCase)(connectorYaml.connectorId)}_connector`;
|
|
111
106
|
const dartSdk = {
|
|
112
|
-
outputDir,
|
|
107
|
+
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/dart/${pkg}`)),
|
|
113
108
|
package: pkg,
|
|
114
109
|
};
|
|
115
|
-
|
|
110
|
+
connectorYaml.generate.dartSdk = dartSdk;
|
|
116
111
|
}
|
|
117
112
|
if (targetPlatform === types_1.Platform.ANDROID) {
|
|
118
|
-
|
|
113
|
+
const kotlinSdk = {
|
|
114
|
+
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/kotlin`)),
|
|
115
|
+
package: `connectors.${(0, lodash_1.snakeCase)(connectorYaml.connectorId)}`,
|
|
116
|
+
};
|
|
119
117
|
for (const candidateSubdir of ["app/src/main/java", "app/src/main/kotlin"]) {
|
|
120
118
|
const candidateDir = path.join(appDir, candidateSubdir);
|
|
121
|
-
if (
|
|
122
|
-
|
|
119
|
+
if ((0, fsutils_1.dirExistsSync)(candidateDir)) {
|
|
120
|
+
kotlinSdk.outputDir = path.relative(connectorDir, candidateDir);
|
|
123
121
|
}
|
|
124
122
|
}
|
|
125
|
-
|
|
126
|
-
path.relative(connectorInfo.directory, baseDir);
|
|
127
|
-
const pkg = (_o = (_m = newConnectorYaml.generate.kotlinSdk) === null || _m === void 0 ? void 0 : _m.package) !== null && _o !== void 0 ? _o : `connectors.${(0, lodash_1.snakeCase)(connectorInfo.connectorYaml.connectorId)}`;
|
|
128
|
-
const kotlinSdk = {
|
|
129
|
-
outputDir,
|
|
130
|
-
package: pkg,
|
|
131
|
-
};
|
|
132
|
-
newConnectorYaml.generate.kotlinSdk = kotlinSdk;
|
|
123
|
+
connectorYaml.generate.kotlinSdk = kotlinSdk;
|
|
133
124
|
}
|
|
134
|
-
|
|
135
|
-
(await (0, prompt_1.confirm)({
|
|
136
|
-
message: "Would you like to generate SDK code now?",
|
|
137
|
-
default: true,
|
|
138
|
-
})));
|
|
139
|
-
const connectorYamlContents = yaml.stringify(newConnectorYaml);
|
|
140
|
-
connectorInfo.connectorYaml = newConnectorYaml;
|
|
141
|
-
return { connectorYamlContents, connectorInfo, shouldGenerate, displayIOSWarning };
|
|
125
|
+
return connectorYaml;
|
|
142
126
|
}
|
|
143
|
-
|
|
127
|
+
exports.generateSdkYaml = generateSdkYaml;
|
|
128
|
+
async function actuate(sdkInfo) {
|
|
144
129
|
var _a;
|
|
145
130
|
const connectorYamlPath = `${sdkInfo.connectorInfo.directory}/connector.yaml`;
|
|
146
131
|
fs.writeFileSync(connectorYamlPath, sdkInfo.connectorYamlContents, "utf8");
|
|
147
132
|
(0, utils_1.logBullet)(`Wrote new config to ${connectorYamlPath}`);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
(0, utils_1.logBullet)(`Generated SDK code for ${sdkInfo.connectorInfo.connectorYaml.connectorId}`);
|
|
154
|
-
}
|
|
133
|
+
await dataconnectEmulator_1.DataConnectEmulator.generate({
|
|
134
|
+
configDir: sdkInfo.connectorInfo.directory,
|
|
135
|
+
connectorId: sdkInfo.connectorInfo.connectorYaml.connectorId,
|
|
136
|
+
});
|
|
137
|
+
(0, utils_1.logBullet)(`Generated SDK code for ${sdkInfo.connectorInfo.connectorYaml.connectorId}`);
|
|
155
138
|
if (((_a = sdkInfo.connectorInfo.connectorYaml.generate) === null || _a === void 0 ? void 0 : _a.swiftSdk) && sdkInfo.displayIOSWarning) {
|
|
156
139
|
(0, utils_1.logBullet)(clc.bold("Please follow the instructions here to add your generated sdk to your XCode project:\n\thttps://firebase.google.com/docs/data-connect/gp/ios-sdk#set-client"));
|
|
157
140
|
}
|
package/lib/init/spawn.js
CHANGED
|
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.wrapSpawn = void 0;
|
|
4
4
|
const spawn = require("cross-spawn");
|
|
5
5
|
const logger_1 = require("../logger");
|
|
6
|
-
function wrapSpawn(cmd, args, projectDir) {
|
|
6
|
+
function wrapSpawn(cmd, args, projectDir, environmentVariables) {
|
|
7
7
|
return new Promise((resolve, reject) => {
|
|
8
8
|
const installer = spawn(cmd, args, {
|
|
9
9
|
cwd: projectDir,
|
|
10
10
|
stdio: "inherit",
|
|
11
|
+
env: Object.assign(Object.assign({}, process.env), environmentVariables),
|
|
11
12
|
});
|
|
12
13
|
installer.on("error", (err) => {
|
|
13
14
|
logger_1.logger.debug(err.stack);
|