firebase-tools 13.28.0 → 13.29.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/dataconnect/fileUtils.js +3 -0
- package/lib/dataconnect/schemaMigration.js +2 -1
- package/lib/deploy/functions/backend.js +1 -3
- package/lib/deploy/functions/build.js +3 -1
- package/lib/deploy/functions/release/planner.js +4 -4
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +4 -0
- package/lib/deploy/functions/runtimes/supported/types.js +1 -1
- package/lib/emulator/controller.js +15 -0
- package/lib/emulator/dataconnect/pgliteServer.js +36 -12
- package/lib/emulator/dataconnectEmulator.js +8 -1
- package/lib/emulator/downloadableEmulators.js +9 -10
- package/lib/error.js +3 -1
- package/lib/functions/events/v2.js +7 -3
- package/lib/gcp/cloudfunctionsv2.js +6 -0
- package/lib/init/features/dataconnect/index.js +4 -0
- package/lib/management/projects.js +23 -1
- package/package.json +1 -1
- package/templates/init/functions/javascript/package.lint.json +1 -1
- package/templates/init/functions/javascript/package.nolint.json +1 -1
- package/templates/init/functions/typescript/package.lint.json +1 -1
- package/templates/init/functions/typescript/package.nolint.json +1 -1
- package/templates/init/functions/typescript/tsconfig.json +3 -1
|
@@ -53,6 +53,9 @@ function validateConnectorYaml(unvalidated) {
|
|
|
53
53
|
return unvalidated;
|
|
54
54
|
}
|
|
55
55
|
async function readGQLFiles(sourceDir) {
|
|
56
|
+
if (!fs.existsSync(sourceDir)) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
56
59
|
const files = await fs.readdir(sourceDir);
|
|
57
60
|
return files
|
|
58
61
|
.filter((f) => f.endsWith(".gql") || f.endsWith(".graphql"))
|
|
@@ -345,6 +345,7 @@ async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, datab
|
|
|
345
345
|
{
|
|
346
346
|
postgresql: {
|
|
347
347
|
database: databaseId,
|
|
348
|
+
schemaValidation: "NONE",
|
|
348
349
|
cloudSql: {
|
|
349
350
|
instance: instanceId,
|
|
350
351
|
},
|
|
@@ -361,7 +362,7 @@ async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, datab
|
|
|
361
362
|
if ((postgresql === null || postgresql === void 0 ? void 0 : postgresql.database) !== databaseId) {
|
|
362
363
|
(0, utils_1.logLabeledWarning)("dataconnect", `Switching connected Postgres database from ${postgresql === null || postgresql === void 0 ? void 0 : postgresql.database} to ${databaseId}`);
|
|
363
364
|
}
|
|
364
|
-
if (!postgresql || postgresql.schemaValidation
|
|
365
|
+
if (!postgresql || postgresql.schemaValidation !== "NONE") {
|
|
365
366
|
return;
|
|
366
367
|
}
|
|
367
368
|
postgresql.schemaValidation = "STRICT";
|
|
@@ -25,9 +25,7 @@ function endpointTriggerType(endpoint) {
|
|
|
25
25
|
else if (isBlockingTriggered(endpoint)) {
|
|
26
26
|
return endpoint.blockingTrigger.eventType;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
throw new Error("Unexpected trigger type for endpoint " + JSON.stringify(endpoint));
|
|
30
|
-
}
|
|
28
|
+
(0, functional_1.assertExhaustive)(endpoint);
|
|
31
29
|
}
|
|
32
30
|
exports.endpointTriggerType = endpointTriggerType;
|
|
33
31
|
exports.AllVpcEgressSettings = ["PRIVATE_RANGES_ONLY", "ALL_TRAFFIC"];
|
|
@@ -259,7 +259,9 @@ function discoverTrigger(endpoint, region, r) {
|
|
|
259
259
|
return { httpsTrigger };
|
|
260
260
|
}
|
|
261
261
|
else if (isCallableTriggered(endpoint)) {
|
|
262
|
-
|
|
262
|
+
const trigger = { callableTrigger: {} };
|
|
263
|
+
proto.copyIfPresent(trigger.callableTrigger, endpoint.callableTrigger, "genkitAction");
|
|
264
|
+
return trigger;
|
|
263
265
|
}
|
|
264
266
|
else if (isBlockingTriggered(endpoint)) {
|
|
265
267
|
return { blockingTrigger: endpoint.blockingTrigger };
|
|
@@ -7,7 +7,6 @@ const error_1 = require("../../../error");
|
|
|
7
7
|
const utils = require("../../../utils");
|
|
8
8
|
const backend = require("../backend");
|
|
9
9
|
const v2events = require("../../../functions/events/v2");
|
|
10
|
-
const v2_1 = require("../../../functions/events/v2");
|
|
11
10
|
function calculateChangesets(want, have, keyFn, deleteAll) {
|
|
12
11
|
const toCreate = utils.groupBy(Object.keys(want)
|
|
13
12
|
.filter((id) => !have[id])
|
|
@@ -167,9 +166,9 @@ function upgradedScheduleFromV1ToV2(want, have) {
|
|
|
167
166
|
exports.upgradedScheduleFromV1ToV2 = upgradedScheduleFromV1ToV2;
|
|
168
167
|
function checkForUnsafeUpdate(want, have) {
|
|
169
168
|
return (backend.isEventTriggered(want) &&
|
|
170
|
-
v2_1.FIRESTORE_EVENT_WITH_AUTH_CONTEXT_REGEX.test(want.eventTrigger.eventType) &&
|
|
171
169
|
backend.isEventTriggered(have) &&
|
|
172
|
-
|
|
170
|
+
want.eventTrigger.eventType ===
|
|
171
|
+
v2events.CONVERTABLE_EVENTS[have.eventTrigger.eventType]);
|
|
173
172
|
}
|
|
174
173
|
exports.checkForUnsafeUpdate = checkForUnsafeUpdate;
|
|
175
174
|
function checkForIllegalUpdate(want, have) {
|
|
@@ -196,7 +195,8 @@ function checkForIllegalUpdate(want, have) {
|
|
|
196
195
|
};
|
|
197
196
|
const wantType = triggerType(want);
|
|
198
197
|
const haveType = triggerType(have);
|
|
199
|
-
|
|
198
|
+
const upgradingHttpsFunction = backend.isHttpsTriggered(have) && backend.isCallableTriggered(want);
|
|
199
|
+
if (wantType !== haveType && !upgradingHttpsFunction) {
|
|
200
200
|
throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_1.getFunctionLabel)(want)}] Changing from ${haveType} function to ${wantType} function is not allowed. Please delete your function and create a new one instead.`);
|
|
201
201
|
}
|
|
202
202
|
if (want.platform === "gcfv1" && have.platform === "gcfv2") {
|
|
@@ -134,6 +134,9 @@ function assertBuildEndpoint(ep, id) {
|
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
else if (build.isCallableTriggered(ep)) {
|
|
137
|
+
(0, parsing_1.assertKeyTypes)(prefix + ".callableTrigger", ep.callableTrigger, {
|
|
138
|
+
genkitAction: "string?",
|
|
139
|
+
});
|
|
137
140
|
}
|
|
138
141
|
else if (build.isScheduleTriggered(ep)) {
|
|
139
142
|
(0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger", ep.scheduleTrigger, {
|
|
@@ -216,6 +219,7 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
|
|
|
216
219
|
}
|
|
217
220
|
else if (build.isCallableTriggered(ep)) {
|
|
218
221
|
triggered = { callableTrigger: {} };
|
|
222
|
+
(0, proto_1.copyIfPresent)(triggered.callableTrigger, ep.callableTrigger, "genkitAction");
|
|
219
223
|
}
|
|
220
224
|
else if (build.isScheduleTriggered(ep)) {
|
|
221
225
|
const st = {
|
|
@@ -572,11 +572,26 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
572
572
|
postgresListen: listenForEmulator["dataconnect.postgres"],
|
|
573
573
|
enable_output_generated_sdk: true,
|
|
574
574
|
enable_output_schema_extensions: true,
|
|
575
|
+
debug: options.debug,
|
|
575
576
|
};
|
|
576
577
|
if (exportMetadata.dataconnect) {
|
|
577
578
|
utils.assertIsString(options.import);
|
|
578
579
|
const importDirAbsPath = path.resolve(options.import);
|
|
579
580
|
const exportMetadataFilePath = path.resolve(importDirAbsPath, exportMetadata.dataconnect.path);
|
|
581
|
+
const dataDirectory = options.config.get("emulators.dataconnect.dataDir");
|
|
582
|
+
if (exportMetadataFilePath && dataDirectory) {
|
|
583
|
+
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).logLabeled("WARN", "dataconnect", "'firebase.json#emulators.dataconnect.dataDir' is set and `--import` flag was passed. " +
|
|
584
|
+
"This will overwrite any data saved from previous runs.");
|
|
585
|
+
if (!options.nonInteractive &&
|
|
586
|
+
!(await (0, prompt_1.promptOnce)({
|
|
587
|
+
type: "confirm",
|
|
588
|
+
message: `Do you wish to continue and overwrite data in ${dataDirectory}?`,
|
|
589
|
+
default: false,
|
|
590
|
+
}))) {
|
|
591
|
+
await cleanShutdown();
|
|
592
|
+
return { deprecationNotices: [] };
|
|
593
|
+
}
|
|
594
|
+
}
|
|
580
595
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).logLabeled("BULLET", "dataconnect", `Importing data from ${exportMetadataFilePath}`);
|
|
581
596
|
args.importPath = exportMetadataFilePath;
|
|
582
597
|
void (0, track_1.trackEmulator)("emulator_import", {
|
|
@@ -27,15 +27,17 @@ const fs = require("fs");
|
|
|
27
27
|
const index_1 = require("./pg-gateway/index");
|
|
28
28
|
const node_1 = require("./pg-gateway/platforms/node");
|
|
29
29
|
const logger_1 = require("../../logger");
|
|
30
|
+
const error_1 = require("../../error");
|
|
30
31
|
exports.TRUNCATE_TABLES_SQL = `
|
|
31
32
|
DO $do$
|
|
33
|
+
DECLARE _clear text;
|
|
32
34
|
BEGIN
|
|
33
|
-
|
|
34
|
-
(SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
|
|
35
|
+
SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
|
|
35
36
|
FROM pg_class
|
|
36
37
|
WHERE relkind = 'r'
|
|
37
38
|
AND relnamespace = 'public'::regnamespace
|
|
38
|
-
|
|
39
|
+
INTO _clear;
|
|
40
|
+
EXECUTE COALESCE(_clear, 'select now()');
|
|
39
41
|
END
|
|
40
42
|
$do$;`;
|
|
41
43
|
class PostgresServer {
|
|
@@ -62,6 +64,7 @@ class PostgresServer {
|
|
|
62
64
|
server.emit("error", err);
|
|
63
65
|
});
|
|
64
66
|
});
|
|
67
|
+
this.server = server;
|
|
65
68
|
const listeningPromise = new Promise((resolve) => {
|
|
66
69
|
server.listen(port, host, () => {
|
|
67
70
|
resolve();
|
|
@@ -75,9 +78,7 @@ class PostgresServer {
|
|
|
75
78
|
const vector = (await dynamicImport("@electric-sql/pglite/vector")).vector;
|
|
76
79
|
const uuidOssp = (await dynamicImport("@electric-sql/pglite/contrib/uuid_ossp")).uuid_ossp;
|
|
77
80
|
const pgliteArgs = {
|
|
78
|
-
|
|
79
|
-
database: this.database,
|
|
80
|
-
debug: 0,
|
|
81
|
+
debug: this.debug,
|
|
81
82
|
extensions: {
|
|
82
83
|
vector,
|
|
83
84
|
uuidOssp,
|
|
@@ -90,7 +91,7 @@ class PostgresServer {
|
|
|
90
91
|
const file = new File([rf], this.importPath);
|
|
91
92
|
pgliteArgs.loadDataDir = file;
|
|
92
93
|
}
|
|
93
|
-
this.db = await
|
|
94
|
+
this.db = await this.forceCreateDB(pgliteArgs);
|
|
94
95
|
await this.db.waitReady;
|
|
95
96
|
}
|
|
96
97
|
return this.db;
|
|
@@ -105,12 +106,35 @@ class PostgresServer {
|
|
|
105
106
|
const arrayBuff = await dump.arrayBuffer();
|
|
106
107
|
fs.writeFileSync(exportPath, new Uint8Array(arrayBuff));
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
+
async forceCreateDB(pgliteArgs) {
|
|
110
|
+
try {
|
|
111
|
+
const db = await pglite_1.PGlite.create(pgliteArgs);
|
|
112
|
+
return db;
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (pgliteArgs.dataDir && (0, error_1.hasMessage)(err) && /Database already exists/.test(err.message)) {
|
|
116
|
+
fs.rmSync(pgliteArgs.dataDir, { force: true, recursive: true });
|
|
117
|
+
const db = await pglite_1.PGlite.create(pgliteArgs);
|
|
118
|
+
return db;
|
|
119
|
+
}
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async stop() {
|
|
124
|
+
if (this.db) {
|
|
125
|
+
await this.db.close();
|
|
126
|
+
}
|
|
127
|
+
if (this.server) {
|
|
128
|
+
this.server.close();
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
constructor(args) {
|
|
109
133
|
this.db = undefined;
|
|
110
|
-
this.
|
|
111
|
-
this.
|
|
112
|
-
this.
|
|
113
|
-
this.
|
|
134
|
+
this.server = undefined;
|
|
135
|
+
this.dataDirectory = args.dataDirectory;
|
|
136
|
+
this.importPath = args.importPath;
|
|
137
|
+
this.debug = args.debug ? 5 : 0;
|
|
114
138
|
}
|
|
115
139
|
}
|
|
116
140
|
exports.PostgresServer = PostgresServer;
|
|
@@ -69,7 +69,11 @@ class DataConnectEmulator {
|
|
|
69
69
|
const postgresDumpPath = this.args.importPath
|
|
70
70
|
? path.join(this.args.importPath, "postgres.tar.gz")
|
|
71
71
|
: undefined;
|
|
72
|
-
this.postgresServer = new pgliteServer_1.PostgresServer(
|
|
72
|
+
this.postgresServer = new pgliteServer_1.PostgresServer({
|
|
73
|
+
dataDirectory,
|
|
74
|
+
importPath: postgresDumpPath,
|
|
75
|
+
debug: this.args.debug,
|
|
76
|
+
});
|
|
73
77
|
const server = await this.postgresServer.createPGServer(pgHost, pgPort);
|
|
74
78
|
const connectableHost = (0, utils_1.connectableHostname)(pgHost);
|
|
75
79
|
connStr = `postgres://${connectableHost}:${pgPort}/${dbId}?sslmode=disable`;
|
|
@@ -101,6 +105,9 @@ class DataConnectEmulator {
|
|
|
101
105
|
this.logger.logLabeled("INFO", "dataconnect", "Skipping cleanup of Data Connect emulator, as it was not started by this process.");
|
|
102
106
|
return;
|
|
103
107
|
}
|
|
108
|
+
if (this.postgresServer) {
|
|
109
|
+
await this.postgresServer.stop();
|
|
110
|
+
}
|
|
104
111
|
return (0, downloadableEmulators_1.stop)(types_1.Emulators.DATACONNECT);
|
|
105
112
|
}
|
|
106
113
|
getInfo() {
|
|
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
48
48
|
},
|
|
49
49
|
dataconnect: process.platform === "darwin"
|
|
50
50
|
? {
|
|
51
|
-
version: "1.7.
|
|
52
|
-
expectedSize:
|
|
53
|
-
expectedChecksum: "
|
|
51
|
+
version: "1.7.5",
|
|
52
|
+
expectedSize: 25281280,
|
|
53
|
+
expectedChecksum: "85d0de96b5c08b553fd8506a2bc381bb",
|
|
54
54
|
}
|
|
55
55
|
: process.platform === "win32"
|
|
56
56
|
? {
|
|
57
|
-
version: "1.7.
|
|
58
|
-
expectedSize:
|
|
59
|
-
expectedChecksum: "
|
|
57
|
+
version: "1.7.5",
|
|
58
|
+
expectedSize: 25711616,
|
|
59
|
+
expectedChecksum: "c99d67fa8e74d41760b96122b055b8e2",
|
|
60
60
|
}
|
|
61
61
|
: {
|
|
62
|
-
version: "1.7.
|
|
62
|
+
version: "1.7.5",
|
|
63
63
|
expectedSize: 25190552,
|
|
64
|
-
expectedChecksum: "
|
|
64
|
+
expectedChecksum: "61d966b781e6f2887f8b38ec271b54e2",
|
|
65
65
|
},
|
|
66
66
|
};
|
|
67
67
|
exports.DownloadDetails = {
|
|
@@ -475,8 +475,7 @@ async function start(targetName, args, extraEnv = {}) {
|
|
|
475
475
|
exports.start = start;
|
|
476
476
|
function isIncomaptibleArchError(err) {
|
|
477
477
|
var _a;
|
|
478
|
-
|
|
479
|
-
return (hasMessage(err) &&
|
|
478
|
+
return ((0, error_1.hasMessage)(err) &&
|
|
480
479
|
/Unknown system error/.test((_a = err.message) !== null && _a !== void 0 ? _a : "") &&
|
|
481
480
|
process.platform === "darwin");
|
|
482
481
|
}
|
package/lib/error.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isBillingError = exports.getError = exports.getErrStatus = exports.isObject = exports.getErrStack = exports.getErrMsg = exports.FirebaseError = void 0;
|
|
3
|
+
exports.hasMessage = exports.isBillingError = exports.getError = exports.getErrStatus = exports.isObject = exports.getErrStack = exports.getErrMsg = exports.FirebaseError = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const DEFAULT_CHILDREN = [];
|
|
6
6
|
const DEFAULT_EXIT = 1;
|
|
@@ -65,3 +65,5 @@ function isBillingError(e) {
|
|
|
65
65
|
}));
|
|
66
66
|
}
|
|
67
67
|
exports.isBillingError = isBillingError;
|
|
68
|
+
const hasMessage = (e) => !!(e === null || e === void 0 ? void 0 : e.message);
|
|
69
|
+
exports.hasMessage = hasMessage;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CONVERTABLE_EVENTS = exports.FIREALERTS_EVENT = exports.FIRESTORE_EVENTS = exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
|
|
4
4
|
exports.PUBSUB_PUBLISH_EVENT = "google.cloud.pubsub.topic.v1.messagePublished";
|
|
5
5
|
exports.STORAGE_EVENTS = [
|
|
6
6
|
"google.cloud.storage.object.v1.finalized",
|
|
@@ -28,5 +28,9 @@ exports.FIRESTORE_EVENTS = [
|
|
|
28
28
|
"google.cloud.firestore.document.v1.deleted.withAuthContext",
|
|
29
29
|
];
|
|
30
30
|
exports.FIREALERTS_EVENT = "google.firebase.firebasealerts.alerts.v1.published";
|
|
31
|
-
exports.
|
|
32
|
-
|
|
31
|
+
exports.CONVERTABLE_EVENTS = {
|
|
32
|
+
"google.cloud.firestore.document.v1.created": "google.cloud.firestore.document.v1.created.withAuthContext",
|
|
33
|
+
"google.cloud.firestore.document.v1.updated": "google.cloud.firestore.document.v1.updated.withAuthContext",
|
|
34
|
+
"google.cloud.firestore.document.v1.deleted": "google.cloud.firestore.document.v1.deleted.withAuthContext",
|
|
35
|
+
"google.cloud.firestore.document.v1.written": "google.cloud.firestore.document.v1.written.withAuthContext",
|
|
36
|
+
};
|
|
@@ -259,6 +259,9 @@ function functionFromEndpoint(endpoint) {
|
|
|
259
259
|
}
|
|
260
260
|
else if (backend.isCallableTriggered(endpoint)) {
|
|
261
261
|
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callable": "true" });
|
|
262
|
+
if (endpoint.callableTrigger.genkitAction) {
|
|
263
|
+
gcfFunction.labels["genkit-action"] = endpoint.callableTrigger.genkitAction;
|
|
264
|
+
}
|
|
262
265
|
}
|
|
263
266
|
else if (backend.isBlockingTriggered(endpoint)) {
|
|
264
267
|
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [constants_1.BLOCKING_LABEL]: constants_1.BLOCKING_EVENT_TO_LABEL_KEY[endpoint.blockingTrigger.eventType] });
|
|
@@ -294,6 +297,9 @@ function endpointFromFunction(gcfFunction) {
|
|
|
294
297
|
trigger = {
|
|
295
298
|
callableTrigger: {},
|
|
296
299
|
};
|
|
300
|
+
if (gcfFunction.labels["genkit-action"]) {
|
|
301
|
+
trigger.callableTrigger.genkitAction = gcfFunction.labels["genkit-action"];
|
|
302
|
+
}
|
|
297
303
|
}
|
|
298
304
|
else if ((_d = gcfFunction.labels) === null || _d === void 0 ? void 0 : _d[constants_1.BLOCKING_LABEL]) {
|
|
299
305
|
trigger = {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.actuate = exports.doSetup = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const clc = require("colorette");
|
|
6
|
+
const fs = require("fs-extra");
|
|
6
7
|
const prompt_1 = require("../../../prompt");
|
|
7
8
|
const provisionCloudSql_1 = require("../../../dataconnect/provisionCloudSql");
|
|
8
9
|
const freeTrial_1 = require("../../../dataconnect/freeTrial");
|
|
@@ -137,6 +138,9 @@ async function writeFiles(config, info) {
|
|
|
137
138
|
await config.askWriteProjectFile((0, path_1.join)(dir, "schema", f.path), f.content);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
141
|
+
else {
|
|
142
|
+
fs.ensureFileSync((0, path_1.join)(dir, "schema", "schema.gql"));
|
|
143
|
+
}
|
|
140
144
|
for (const c of info.connectors) {
|
|
141
145
|
await writeConnectorFiles(config, c);
|
|
142
146
|
}
|
|
@@ -26,12 +26,34 @@ exports.PROJECTS_CREATE_QUESTIONS = [
|
|
|
26
26
|
default: "",
|
|
27
27
|
message: "Please specify a unique project id " +
|
|
28
28
|
`(${clc.yellow("warning")}: cannot be modified afterward) [6-30 characters]:\n`,
|
|
29
|
+
validate: (projectId) => {
|
|
30
|
+
if (projectId.length < 6) {
|
|
31
|
+
return "Project ID must be at least 6 characters long";
|
|
32
|
+
}
|
|
33
|
+
else if (projectId.length > 30) {
|
|
34
|
+
return "Project ID cannot be longer than 30 characters";
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
29
40
|
},
|
|
30
41
|
{
|
|
31
42
|
type: "input",
|
|
32
43
|
name: "displayName",
|
|
33
|
-
default:
|
|
44
|
+
default: (answers) => answers.projectId,
|
|
34
45
|
message: "What would you like to call your project? (defaults to your project ID)",
|
|
46
|
+
validate: (displayName) => {
|
|
47
|
+
if (displayName.length < 4) {
|
|
48
|
+
return "Project name must be at least 4 characters long";
|
|
49
|
+
}
|
|
50
|
+
else if (displayName.length > 30) {
|
|
51
|
+
return "Project name cannot be longer than 30 characters";
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
35
57
|
},
|
|
36
58
|
];
|
|
37
59
|
const firebaseAPIClient = new apiv2_1.Client({
|
package/package.json
CHANGED