firebase-tools 13.3.1 → 13.4.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/api.js +2 -1
- package/lib/apiv2.js +8 -3
- package/lib/commands/apphosting-backends-create.js +3 -3
- package/lib/commands/apphosting-backends-delete.js +3 -39
- package/lib/commands/apphosting-backends-get.js +4 -35
- package/lib/commands/apphosting-backends-list.js +17 -9
- package/lib/commands/apphosting-builds-create.js +4 -4
- package/lib/commands/apphosting-builds-get.js +2 -2
- package/lib/commands/apphosting-rollouts-create.js +3 -3
- package/lib/commands/apphosting-rollouts-list.js +2 -2
- package/lib/commands/firestore-backups-delete.js +44 -0
- package/lib/commands/firestore-backups-get.js +25 -0
- package/lib/commands/firestore-backups-list.js +34 -0
- package/lib/commands/firestore-backups-schedules-create.js +67 -0
- package/lib/commands/firestore-backups-schedules-delete.js +46 -0
- package/lib/commands/firestore-backups-schedules-list.js +28 -0
- package/lib/commands/firestore-backups-schedules-update.js +33 -0
- package/lib/commands/firestore-databases-create.js +4 -2
- package/lib/commands/firestore-databases-delete.js +4 -2
- package/lib/commands/firestore-databases-get.js +3 -1
- package/lib/commands/firestore-databases-list.js +3 -1
- package/lib/commands/firestore-databases-restore.js +42 -0
- package/lib/commands/firestore-databases-update.js +4 -2
- package/lib/commands/firestore-indexes-list.js +5 -3
- package/lib/commands/firestore-locations.js +3 -1
- package/lib/commands/index.js +10 -0
- package/lib/deploy/extensions/v2FunctionHelper.js +2 -1
- package/lib/deploy/functions/backend.js +5 -1
- package/lib/deploy/functions/build.js +9 -6
- package/lib/deploy/functions/ensure.js +2 -2
- package/lib/deploy/functions/prepare.js +5 -9
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +2 -1
- package/lib/emulator/downloadableEmulators.js +3 -3
- package/lib/ensureApiEnabled.js +8 -6
- package/lib/extensions/extensionsHelper.js +2 -2
- package/lib/extensions/secretsUtils.js +2 -1
- package/lib/fetchWebSetup.js +2 -1
- package/lib/firestore/api-sort.js +23 -1
- package/lib/firestore/api-types.js +6 -1
- package/lib/firestore/api.js +18 -115
- package/lib/firestore/backupUtils.js +30 -0
- package/lib/firestore/pretty-print.js +184 -0
- package/lib/frameworks/index.js +6 -2
- package/lib/frameworks/next/constants.js +35 -1
- package/lib/frameworks/next/index.js +25 -3
- package/lib/frameworks/next/utils.js +20 -1
- package/lib/functions/secrets.js +1 -1
- package/lib/gcp/apphosting.js +2 -3
- package/lib/gcp/auth.js +5 -2
- package/lib/gcp/firestore.js +75 -1
- package/lib/gcp/storage.js +1 -1
- package/lib/hosting/api.js +12 -1
- package/lib/init/features/apphosting/index.js +12 -7
- package/lib/init/features/database.js +2 -1
- package/lib/init/features/extensions/index.js +2 -1
- package/lib/init/features/functions/index.js +3 -2
- package/package.json +2 -1
package/lib/firestore/api.js
CHANGED
|
@@ -12,9 +12,11 @@ const prompt_1 = require("../prompt");
|
|
|
12
12
|
const api_1 = require("../api");
|
|
13
13
|
const error_1 = require("../error");
|
|
14
14
|
const apiv2_1 = require("../apiv2");
|
|
15
|
+
const pretty_print_1 = require("./pretty-print");
|
|
15
16
|
class FirestoreApi {
|
|
16
17
|
constructor() {
|
|
17
18
|
this.apiClient = new apiv2_1.Client({ urlPrefix: api_1.firestoreOrigin, apiVersion: "v1" });
|
|
19
|
+
this.printer = new pretty_print_1.PrettyPrint();
|
|
18
20
|
}
|
|
19
21
|
async deploy(options, indexes, fieldOverrides, databaseId = "(default)") {
|
|
20
22
|
const spec = this.upgradeOldSpec({
|
|
@@ -49,7 +51,7 @@ class FirestoreApi {
|
|
|
49
51
|
}
|
|
50
52
|
else if (!options.force) {
|
|
51
53
|
const indexesString = indexesToDelete
|
|
52
|
-
.map((x) => this.prettyIndexString(x, false))
|
|
54
|
+
.map((x) => this.printer.prettyIndexString(x, false))
|
|
53
55
|
.join("\n\t");
|
|
54
56
|
utils.logLabeledBullet("firestore", `The following indexes are defined in your project but are not present in your firestore indexes file:\n\t${indexesString}`);
|
|
55
57
|
}
|
|
@@ -86,7 +88,7 @@ class FirestoreApi {
|
|
|
86
88
|
}
|
|
87
89
|
else if (!options.force) {
|
|
88
90
|
const indexesString = fieldOverridesToDelete
|
|
89
|
-
.map((x) => this.prettyFieldString(x))
|
|
91
|
+
.map((x) => this.printer.prettyFieldString(x))
|
|
90
92
|
.join("\n\t");
|
|
91
93
|
utils.logLabeledBullet("firestore", `The following field overrides are defined in your project but are not present in your firestore indexes file:\n\t${indexesString}`);
|
|
92
94
|
}
|
|
@@ -145,7 +147,7 @@ class FirestoreApi {
|
|
|
145
147
|
return [];
|
|
146
148
|
}
|
|
147
149
|
return fields.filter((field) => {
|
|
148
|
-
return field.name.
|
|
150
|
+
return !field.name.includes("__default__");
|
|
149
151
|
});
|
|
150
152
|
}
|
|
151
153
|
makeIndexSpec(indexes, fields) {
|
|
@@ -184,64 +186,6 @@ class FirestoreApi {
|
|
|
184
186
|
fieldOverrides: sortedFields,
|
|
185
187
|
};
|
|
186
188
|
}
|
|
187
|
-
prettyPrintIndexes(indexes) {
|
|
188
|
-
if (indexes.length === 0) {
|
|
189
|
-
logger_1.logger.info("None");
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
const sortedIndexes = indexes.sort(sort.compareApiIndex);
|
|
193
|
-
sortedIndexes.forEach((index) => {
|
|
194
|
-
logger_1.logger.info(this.prettyIndexString(index));
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
prettyPrintDatabases(databases) {
|
|
198
|
-
if (databases.length === 0) {
|
|
199
|
-
logger_1.logger.info("No databases found.");
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const sortedDatabases = databases.sort(sort.compareApiDatabase);
|
|
203
|
-
const Table = require("cli-table");
|
|
204
|
-
const table = new Table({
|
|
205
|
-
head: ["Database Name"],
|
|
206
|
-
colWidths: [Math.max(...sortedDatabases.map((database) => database.name.length + 5), 20)],
|
|
207
|
-
});
|
|
208
|
-
table.push(...sortedDatabases.map((database) => [this.prettyDatabaseString(database)]));
|
|
209
|
-
logger_1.logger.info(table.toString());
|
|
210
|
-
}
|
|
211
|
-
prettyPrintDatabase(database) {
|
|
212
|
-
const Table = require("cli-table");
|
|
213
|
-
const table = new Table({
|
|
214
|
-
head: ["Field", "Value"],
|
|
215
|
-
colWidths: [25, Math.max(50, 5 + database.name.length)],
|
|
216
|
-
});
|
|
217
|
-
table.push(["Name", clc.yellow(database.name)], ["Create Time", clc.yellow(database.createTime)], ["Last Update Time", clc.yellow(database.updateTime)], ["Type", clc.yellow(database.type)], ["Location", clc.yellow(database.locationId)], ["Delete Protection State", clc.yellow(database.deleteProtectionState)], ["Point In Time Recovery", clc.yellow(database.pointInTimeRecoveryEnablement)], ["Earliest Version Time", clc.yellow(database.earliestVersionTime)], ["Version Retention Period", clc.yellow(database.versionRetentionPeriod)]);
|
|
218
|
-
logger_1.logger.info(table.toString());
|
|
219
|
-
}
|
|
220
|
-
prettyPrintLocations(locations) {
|
|
221
|
-
if (locations.length === 0) {
|
|
222
|
-
logger_1.logger.info("No Locations Available");
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const Table = require("cli-table");
|
|
226
|
-
const table = new Table({
|
|
227
|
-
head: ["Display Name", "LocationId"],
|
|
228
|
-
colWidths: [20, 30],
|
|
229
|
-
});
|
|
230
|
-
table.push(...locations
|
|
231
|
-
.sort(sort.compareLocation)
|
|
232
|
-
.map((location) => [location.displayName, location.locationId]));
|
|
233
|
-
logger_1.logger.info(table.toString());
|
|
234
|
-
}
|
|
235
|
-
printFieldOverrides(fields) {
|
|
236
|
-
if (fields.length === 0) {
|
|
237
|
-
logger_1.logger.info("None");
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const sortedFields = fields.sort(sort.compareApiField);
|
|
241
|
-
sortedFields.forEach((field) => {
|
|
242
|
-
logger_1.logger.info(this.prettyFieldString(field));
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
189
|
validateSpec(spec) {
|
|
246
190
|
validator.assertHas(spec, "indexes");
|
|
247
191
|
spec.indexes.forEach((index) => {
|
|
@@ -391,7 +335,7 @@ class FirestoreApi {
|
|
|
391
335
|
return index.order || index.arrayConfig;
|
|
392
336
|
});
|
|
393
337
|
for (const mode of fieldModes) {
|
|
394
|
-
if (specModes.
|
|
338
|
+
if (!specModes.includes(mode)) {
|
|
395
339
|
return false;
|
|
396
340
|
}
|
|
397
341
|
}
|
|
@@ -507,60 +451,19 @@ class FirestoreApi {
|
|
|
507
451
|
}
|
|
508
452
|
return database;
|
|
509
453
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
result += clc.red(stateMsg);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
const nameInfo = util.parseIndexName(index.name);
|
|
525
|
-
result += clc.cyan(`(${nameInfo.collectionGroupId})`);
|
|
526
|
-
result += " -- ";
|
|
527
|
-
index.fields.forEach((field) => {
|
|
528
|
-
if (field.fieldPath === "__name__") {
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
const orderOrArrayConfig = field.order ? field.order : field.arrayConfig;
|
|
532
|
-
result += `(${field.fieldPath},${orderOrArrayConfig}) `;
|
|
533
|
-
});
|
|
534
|
-
return result;
|
|
535
|
-
}
|
|
536
|
-
prettyDatabaseString(database) {
|
|
537
|
-
return clc.yellow(database.name);
|
|
538
|
-
}
|
|
539
|
-
prettyFieldString(field) {
|
|
540
|
-
let result = "";
|
|
541
|
-
const parsedName = util.parseFieldName(field.name);
|
|
542
|
-
result +=
|
|
543
|
-
"[" +
|
|
544
|
-
clc.cyan(parsedName.collectionGroupId) +
|
|
545
|
-
"." +
|
|
546
|
-
clc.yellow(parsedName.fieldPath) +
|
|
547
|
-
"] --";
|
|
548
|
-
const fieldIndexes = field.indexConfig.indexes || [];
|
|
549
|
-
if (fieldIndexes.length > 0) {
|
|
550
|
-
fieldIndexes.forEach((index) => {
|
|
551
|
-
const firstField = index.fields[0];
|
|
552
|
-
const mode = firstField.order || firstField.arrayConfig;
|
|
553
|
-
result += ` (${mode})`;
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
else {
|
|
557
|
-
result += " (no indexes)";
|
|
558
|
-
}
|
|
559
|
-
const fieldTtl = field.ttlConfig;
|
|
560
|
-
if (fieldTtl) {
|
|
561
|
-
result += ` TTL(${fieldTtl.state})`;
|
|
454
|
+
async restoreDatabase(project, databaseId, backupName) {
|
|
455
|
+
const url = `/projects/${project}/databases:restore`;
|
|
456
|
+
const payload = {
|
|
457
|
+
databaseId,
|
|
458
|
+
backup: backupName,
|
|
459
|
+
};
|
|
460
|
+
const options = { queryParams: { databaseId: databaseId } };
|
|
461
|
+
const res = await this.apiClient.post(url, payload, options);
|
|
462
|
+
const database = res.body.response;
|
|
463
|
+
if (!database) {
|
|
464
|
+
throw new error_1.FirebaseError("Not found");
|
|
562
465
|
}
|
|
563
|
-
return
|
|
466
|
+
return database;
|
|
564
467
|
}
|
|
565
468
|
}
|
|
566
469
|
exports.FirestoreApi = FirestoreApi;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateRetention = exports.Duration = exports.DURATION_REGEX = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
5
|
+
exports.DURATION_REGEX = /^(\d+)([hdmw])$/;
|
|
6
|
+
var Duration;
|
|
7
|
+
(function (Duration) {
|
|
8
|
+
Duration[Duration["MINUTE"] = 60] = "MINUTE";
|
|
9
|
+
Duration[Duration["HOUR"] = 3600] = "HOUR";
|
|
10
|
+
Duration[Duration["DAY"] = 86400] = "DAY";
|
|
11
|
+
Duration[Duration["WEEK"] = 604800] = "WEEK";
|
|
12
|
+
})(Duration = exports.Duration || (exports.Duration = {}));
|
|
13
|
+
const DURATIONS = {
|
|
14
|
+
m: Duration.MINUTE,
|
|
15
|
+
h: Duration.HOUR,
|
|
16
|
+
d: Duration.DAY,
|
|
17
|
+
w: Duration.WEEK,
|
|
18
|
+
};
|
|
19
|
+
function calculateRetention(flag) {
|
|
20
|
+
const match = exports.DURATION_REGEX.exec(flag);
|
|
21
|
+
if (!match) {
|
|
22
|
+
throw new error_1.FirebaseError(`"retention" flag must be a duration string (e.g. 24h, 2w, or 7d)`);
|
|
23
|
+
}
|
|
24
|
+
const d = parseInt(match[1], 10) * DURATIONS[match[2]];
|
|
25
|
+
if (isNaN(d)) {
|
|
26
|
+
throw new error_1.FirebaseError(`Failed to parse provided retention time "${flag}"`);
|
|
27
|
+
}
|
|
28
|
+
return d;
|
|
29
|
+
}
|
|
30
|
+
exports.calculateRetention = calculateRetention;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrettyPrint = void 0;
|
|
4
|
+
const clc = require("colorette");
|
|
5
|
+
const Table = require("cli-table");
|
|
6
|
+
const sort = require("./api-sort");
|
|
7
|
+
const types = require("./api-types");
|
|
8
|
+
const logger_1 = require("../logger");
|
|
9
|
+
const util = require("./util");
|
|
10
|
+
class PrettyPrint {
|
|
11
|
+
prettyPrintIndexes(indexes) {
|
|
12
|
+
if (indexes.length === 0) {
|
|
13
|
+
logger_1.logger.info("None");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const sortedIndexes = indexes.sort(sort.compareApiIndex);
|
|
17
|
+
sortedIndexes.forEach((index) => {
|
|
18
|
+
logger_1.logger.info(this.prettyIndexString(index));
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
prettyPrintDatabases(databases) {
|
|
22
|
+
if (databases.length === 0) {
|
|
23
|
+
logger_1.logger.info("No databases found.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const sortedDatabases = databases.sort(sort.compareApiDatabase);
|
|
27
|
+
const table = new Table({
|
|
28
|
+
head: ["Database Name"],
|
|
29
|
+
colWidths: [Math.max(...sortedDatabases.map((database) => database.name.length + 5), 20)],
|
|
30
|
+
});
|
|
31
|
+
table.push(...sortedDatabases.map((database) => [this.prettyDatabaseString(database)]));
|
|
32
|
+
logger_1.logger.info(table.toString());
|
|
33
|
+
}
|
|
34
|
+
prettyPrintDatabase(database) {
|
|
35
|
+
const table = new Table({
|
|
36
|
+
head: ["Field", "Value"],
|
|
37
|
+
colWidths: [25, Math.max(50, 5 + database.name.length)],
|
|
38
|
+
});
|
|
39
|
+
table.push(["Name", clc.yellow(database.name)], ["Create Time", clc.yellow(database.createTime)], ["Last Update Time", clc.yellow(database.updateTime)], ["Type", clc.yellow(database.type)], ["Location", clc.yellow(database.locationId)], ["Delete Protection State", clc.yellow(database.deleteProtectionState)], ["Point In Time Recovery", clc.yellow(database.pointInTimeRecoveryEnablement)], ["Earliest Version Time", clc.yellow(database.earliestVersionTime)], ["Version Retention Period", clc.yellow(database.versionRetentionPeriod)]);
|
|
40
|
+
logger_1.logger.info(table.toString());
|
|
41
|
+
}
|
|
42
|
+
prettyPrintBackups(backups) {
|
|
43
|
+
if (backups.length === 0) {
|
|
44
|
+
logger_1.logger.info("No backups found.");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const sortedBackups = backups.sort(sort.compareApiBackup);
|
|
48
|
+
const table = new Table({
|
|
49
|
+
head: ["Backup Name", "Database Name", "Snapshot Time", "State"],
|
|
50
|
+
colWidths: [
|
|
51
|
+
Math.max(...sortedBackups.map((backup) => backup.name.length + 5), 20),
|
|
52
|
+
Math.max(...sortedBackups.map((backup) => backup.database.length + 5), 20),
|
|
53
|
+
30,
|
|
54
|
+
10,
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
table.push(...sortedBackups.map((backup) => [
|
|
58
|
+
this.prettyBackupString(backup),
|
|
59
|
+
this.prettyDatabaseString(backup.database || ""),
|
|
60
|
+
backup.snapshotTime,
|
|
61
|
+
backup.state,
|
|
62
|
+
]));
|
|
63
|
+
logger_1.logger.info(table.toString());
|
|
64
|
+
}
|
|
65
|
+
prettyPrintBackupSchedules(backupSchedules, databaseId) {
|
|
66
|
+
if (backupSchedules.length === 0) {
|
|
67
|
+
logger_1.logger.info(`No backup schedules for database ${databaseId} found.`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const sortedBackupSchedules = backupSchedules.sort(sort.compareApiBackupSchedule);
|
|
71
|
+
sortedBackupSchedules.forEach((schedule) => this.prettyPrintBackupSchedule(schedule));
|
|
72
|
+
}
|
|
73
|
+
prettyPrintBackupSchedule(backupSchedule) {
|
|
74
|
+
const table = new Table({
|
|
75
|
+
head: ["Field", "Value"],
|
|
76
|
+
colWidths: [25, Math.max(50, 5 + backupSchedule.name.length)],
|
|
77
|
+
});
|
|
78
|
+
table.push(["Name", clc.yellow(backupSchedule.name)], ["Create Time", clc.yellow(backupSchedule.createTime)], ["Last Update Time", clc.yellow(backupSchedule.updateTime)], ["Retention", clc.yellow(backupSchedule.retention)], ["Recurrence", this.prettyRecurrenceString(backupSchedule)]);
|
|
79
|
+
logger_1.logger.info(table.toString());
|
|
80
|
+
}
|
|
81
|
+
prettyRecurrenceString(backupSchedule) {
|
|
82
|
+
if (backupSchedule.dailyRecurrence) {
|
|
83
|
+
return clc.yellow("DAILY");
|
|
84
|
+
}
|
|
85
|
+
else if (backupSchedule.weeklyRecurrence) {
|
|
86
|
+
return clc.yellow(`WEEKLY (${backupSchedule.weeklyRecurrence.day})`);
|
|
87
|
+
}
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
prettyPrintBackup(backup) {
|
|
91
|
+
const table = new Table({
|
|
92
|
+
head: ["Field", "Value"],
|
|
93
|
+
colWidths: [25, Math.max(50, 5 + backup.name.length, 5 + backup.database.length)],
|
|
94
|
+
});
|
|
95
|
+
table.push(["Name", clc.yellow(backup.name)], ["Database", clc.yellow(backup.database)], ["Database UID", clc.yellow(backup.databaseUid)], ["State", clc.yellow(backup.state)], ["Snapshot Time", clc.yellow(backup.snapshotTime)], ["Expire Time", clc.yellow(backup.expireTime)], ["Stats", clc.yellow(backup.stats)]);
|
|
96
|
+
logger_1.logger.info(table.toString());
|
|
97
|
+
}
|
|
98
|
+
prettyPrintLocations(locations) {
|
|
99
|
+
if (locations.length === 0) {
|
|
100
|
+
logger_1.logger.info("No Locations Available");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const table = new Table({
|
|
104
|
+
head: ["Display Name", "LocationId"],
|
|
105
|
+
colWidths: [20, 30],
|
|
106
|
+
});
|
|
107
|
+
table.push(...locations
|
|
108
|
+
.sort(sort.compareLocation)
|
|
109
|
+
.map((location) => [location.displayName, location.locationId]));
|
|
110
|
+
logger_1.logger.info(table.toString());
|
|
111
|
+
}
|
|
112
|
+
printFieldOverrides(fields) {
|
|
113
|
+
if (fields.length === 0) {
|
|
114
|
+
logger_1.logger.info("None");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const sortedFields = fields.sort(sort.compareApiField);
|
|
118
|
+
sortedFields.forEach((field) => {
|
|
119
|
+
logger_1.logger.info(this.prettyFieldString(field));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
prettyIndexString(index, includeState = true) {
|
|
123
|
+
let result = "";
|
|
124
|
+
if (index.state && includeState) {
|
|
125
|
+
const stateMsg = `[${index.state}] `;
|
|
126
|
+
if (index.state === types.State.READY) {
|
|
127
|
+
result += clc.green(stateMsg);
|
|
128
|
+
}
|
|
129
|
+
else if (index.state === types.State.CREATING) {
|
|
130
|
+
result += clc.yellow(stateMsg);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
result += clc.red(stateMsg);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const nameInfo = util.parseIndexName(index.name);
|
|
137
|
+
result += clc.cyan(`(${nameInfo.collectionGroupId})`);
|
|
138
|
+
result += " -- ";
|
|
139
|
+
index.fields.forEach((field) => {
|
|
140
|
+
if (field.fieldPath === "__name__") {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const orderOrArrayConfig = field.order ? field.order : field.arrayConfig;
|
|
144
|
+
result += `(${field.fieldPath},${orderOrArrayConfig}) `;
|
|
145
|
+
});
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
prettyBackupString(backup) {
|
|
149
|
+
return clc.yellow(backup.name || "");
|
|
150
|
+
}
|
|
151
|
+
prettyBackupScheduleString(backupSchedule) {
|
|
152
|
+
return clc.yellow(backupSchedule.name || "");
|
|
153
|
+
}
|
|
154
|
+
prettyDatabaseString(database) {
|
|
155
|
+
return clc.yellow(typeof database === "string" ? database : database.name);
|
|
156
|
+
}
|
|
157
|
+
prettyFieldString(field) {
|
|
158
|
+
let result = "";
|
|
159
|
+
const parsedName = util.parseFieldName(field.name);
|
|
160
|
+
result +=
|
|
161
|
+
"[" +
|
|
162
|
+
clc.cyan(parsedName.collectionGroupId) +
|
|
163
|
+
"." +
|
|
164
|
+
clc.yellow(parsedName.fieldPath) +
|
|
165
|
+
"] --";
|
|
166
|
+
const fieldIndexes = field.indexConfig.indexes || [];
|
|
167
|
+
if (fieldIndexes.length > 0) {
|
|
168
|
+
fieldIndexes.forEach((index) => {
|
|
169
|
+
const firstField = index.fields[0];
|
|
170
|
+
const mode = firstField.order || firstField.arrayConfig;
|
|
171
|
+
result += ` (${mode})`;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
result += " (no indexes)";
|
|
176
|
+
}
|
|
177
|
+
const fieldTtl = field.ttlConfig;
|
|
178
|
+
if (fieldTtl) {
|
|
179
|
+
result += ` TTL(${fieldTtl.state})`;
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.PrettyPrint = PrettyPrint;
|
package/lib/frameworks/index.js
CHANGED
|
@@ -32,6 +32,7 @@ const projectPath_1 = require("../projectPath");
|
|
|
32
32
|
const logger_1 = require("../logger");
|
|
33
33
|
const frameworks_1 = require("./frameworks");
|
|
34
34
|
Object.defineProperty(exports, "WebFrameworks", { enumerable: true, get: function () { return frameworks_1.WebFrameworks; } });
|
|
35
|
+
const fetchWebSetup_1 = require("../fetchWebSetup");
|
|
35
36
|
async function discover(dir, warn = true) {
|
|
36
37
|
const allFrameworkTypes = [
|
|
37
38
|
...new Set(Object.values(frameworks_1.WebFrameworks).map(({ type }) => type)),
|
|
@@ -149,12 +150,15 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
149
150
|
});
|
|
150
151
|
let firebaseConfig = null;
|
|
151
152
|
if (usesFirebaseJsSdk) {
|
|
152
|
-
const
|
|
153
|
+
const isDemoProject = constants_1.Constants.isDemoProject(project);
|
|
154
|
+
const sites = isDemoProject ? (0, api_1.listDemoSites)(project) : await (0, api_1.listSites)(project);
|
|
153
155
|
const selectedSite = sites.find((it) => it.name && it.name.split("/").pop() === site);
|
|
154
156
|
if (selectedSite) {
|
|
155
157
|
const { appId } = selectedSite;
|
|
156
158
|
if (appId) {
|
|
157
|
-
firebaseConfig =
|
|
159
|
+
firebaseConfig = isDemoProject
|
|
160
|
+
? (0, fetchWebSetup_1.constructDefaultWebSetup)(project)
|
|
161
|
+
: await (0, apps_1.getAppConfig)(appId, apps_1.AppPlatform.WEB);
|
|
158
162
|
firebaseDefaults || (firebaseDefaults = {});
|
|
159
163
|
firebaseDefaults.config = firebaseConfig;
|
|
160
164
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ESBUILD_VERSION = exports.APP_PATHS_MANIFEST = exports.ROUTES_MANIFEST = exports.PRERENDER_MANIFEST = exports.PAGES_MANIFEST = exports.MIDDLEWARE_MANIFEST = exports.IMAGES_MANIFEST = exports.EXPORT_MARKER = exports.APP_PATH_ROUTES_MANIFEST = void 0;
|
|
3
|
+
exports.WEBPACK_LAYERS = exports.ESBUILD_VERSION = exports.SERVER_REFERENCE_MANIFEST = exports.APP_PATHS_MANIFEST = exports.ROUTES_MANIFEST = exports.PRERENDER_MANIFEST = exports.PAGES_MANIFEST = exports.MIDDLEWARE_MANIFEST = exports.IMAGES_MANIFEST = exports.EXPORT_MARKER = exports.APP_PATH_ROUTES_MANIFEST = void 0;
|
|
4
4
|
exports.APP_PATH_ROUTES_MANIFEST = "app-path-routes-manifest.json";
|
|
5
5
|
exports.EXPORT_MARKER = "export-marker.json";
|
|
6
6
|
exports.IMAGES_MANIFEST = "images-manifest.json";
|
|
@@ -9,4 +9,38 @@ exports.PAGES_MANIFEST = "pages-manifest.json";
|
|
|
9
9
|
exports.PRERENDER_MANIFEST = "prerender-manifest.json";
|
|
10
10
|
exports.ROUTES_MANIFEST = "routes-manifest.json";
|
|
11
11
|
exports.APP_PATHS_MANIFEST = "app-paths-manifest.json";
|
|
12
|
+
exports.SERVER_REFERENCE_MANIFEST = "server-reference-manifest.json";
|
|
12
13
|
exports.ESBUILD_VERSION = "0.19.2";
|
|
14
|
+
const WEBPACK_LAYERS_NAMES = {
|
|
15
|
+
shared: "shared",
|
|
16
|
+
reactServerComponents: "rsc",
|
|
17
|
+
serverSideRendering: "ssr",
|
|
18
|
+
actionBrowser: "action-browser",
|
|
19
|
+
api: "api",
|
|
20
|
+
middleware: "middleware",
|
|
21
|
+
edgeAsset: "edge-asset",
|
|
22
|
+
appPagesBrowser: "app-pages-browser",
|
|
23
|
+
appMetadataRoute: "app-metadata-route",
|
|
24
|
+
appRouteHandler: "app-route-handler",
|
|
25
|
+
};
|
|
26
|
+
exports.WEBPACK_LAYERS = Object.assign(Object.assign({}, WEBPACK_LAYERS_NAMES), { GROUP: {
|
|
27
|
+
server: [
|
|
28
|
+
WEBPACK_LAYERS_NAMES.reactServerComponents,
|
|
29
|
+
WEBPACK_LAYERS_NAMES.actionBrowser,
|
|
30
|
+
WEBPACK_LAYERS_NAMES.appMetadataRoute,
|
|
31
|
+
WEBPACK_LAYERS_NAMES.appRouteHandler,
|
|
32
|
+
],
|
|
33
|
+
nonClientServerTarget: [
|
|
34
|
+
WEBPACK_LAYERS_NAMES.middleware,
|
|
35
|
+
WEBPACK_LAYERS_NAMES.api,
|
|
36
|
+
],
|
|
37
|
+
app: [
|
|
38
|
+
WEBPACK_LAYERS_NAMES.reactServerComponents,
|
|
39
|
+
WEBPACK_LAYERS_NAMES.actionBrowser,
|
|
40
|
+
WEBPACK_LAYERS_NAMES.appMetadataRoute,
|
|
41
|
+
WEBPACK_LAYERS_NAMES.appRouteHandler,
|
|
42
|
+
WEBPACK_LAYERS_NAMES.serverSideRendering,
|
|
43
|
+
WEBPACK_LAYERS_NAMES.appPagesBrowser,
|
|
44
|
+
WEBPACK_LAYERS_NAMES.shared,
|
|
45
|
+
],
|
|
46
|
+
} });
|
|
@@ -114,9 +114,10 @@ async function build(dir, target, context) {
|
|
|
114
114
|
source: (0, utils_2.cleanEscapedChars)(source),
|
|
115
115
|
headers,
|
|
116
116
|
}));
|
|
117
|
-
const [appPathsManifest, appPathRoutesManifest] = await Promise.all([
|
|
117
|
+
const [appPathsManifest, appPathRoutesManifest, serverReferenceManifest] = await Promise.all([
|
|
118
118
|
(0, utils_1.readJSON)((0, path_1.join)(dir, distDir, "server", constants_2.APP_PATHS_MANIFEST)).catch(() => undefined),
|
|
119
119
|
(0, utils_1.readJSON)((0, path_1.join)(dir, distDir, constants_2.APP_PATH_ROUTES_MANIFEST)).catch(() => undefined),
|
|
120
|
+
(0, utils_1.readJSON)((0, path_1.join)(dir, distDir, "server", constants_2.SERVER_REFERENCE_MANIFEST)).catch(() => undefined),
|
|
120
121
|
]);
|
|
121
122
|
if (appPathRoutesManifest) {
|
|
122
123
|
const headersFromMetaFiles = await (0, utils_2.getHeadersFromMetaFiles)(dir, distDir, baseUrl, appPathRoutesManifest);
|
|
@@ -131,6 +132,12 @@ async function build(dir, target, context) {
|
|
|
131
132
|
reasonsForBackend.add(`non-static component ${key}`);
|
|
132
133
|
}
|
|
133
134
|
}
|
|
135
|
+
if (serverReferenceManifest) {
|
|
136
|
+
const routesWithServerAction = (0, utils_2.getRoutesWithServerAction)(serverReferenceManifest, appPathRoutesManifest);
|
|
137
|
+
for (const key of routesWithServerAction) {
|
|
138
|
+
reasonsForBackend.add(`route with server action ${key}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
134
141
|
}
|
|
135
142
|
const isEveryRedirectSupported = nextJsRedirects
|
|
136
143
|
.filter((it) => !it.internal)
|
|
@@ -212,12 +219,13 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
|
|
|
212
219
|
await (0, fs_extra_1.copy)(publicPath, (0, path_1.join)(destDir, basePath));
|
|
213
220
|
}
|
|
214
221
|
await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir, "static"), (0, path_1.join)(destDir, basePath, "_next", "static"));
|
|
215
|
-
const [middlewareManifest, prerenderManifest, routesManifest, pagesManifest, appPathRoutesManifest,] = await Promise.all([
|
|
222
|
+
const [middlewareManifest, prerenderManifest, routesManifest, pagesManifest, appPathRoutesManifest, serverReferenceManifest,] = await Promise.all([
|
|
216
223
|
(0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, "server", constants_2.MIDDLEWARE_MANIFEST)),
|
|
217
224
|
(0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, constants_2.PRERENDER_MANIFEST)),
|
|
218
225
|
(0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, constants_2.ROUTES_MANIFEST)),
|
|
219
226
|
(0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, "server", constants_2.PAGES_MANIFEST)),
|
|
220
227
|
(0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, constants_2.APP_PATH_ROUTES_MANIFEST)).catch(() => ({})),
|
|
228
|
+
(0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, "server", constants_2.SERVER_REFERENCE_MANIFEST)).catch(() => ({ node: {}, edge: {}, encryptionKey: "" })),
|
|
221
229
|
]);
|
|
222
230
|
const appPathRoutesEntries = Object.entries(appPathRoutesManifest);
|
|
223
231
|
const middlewareMatcherRegexes = (0, utils_2.getMiddlewareMatcherRegexes)(middlewareManifest);
|
|
@@ -240,10 +248,20 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
|
|
|
240
248
|
...redirectsRegexesNotSupportedByHosting,
|
|
241
249
|
...headersRegexesNotSupportedByHosting,
|
|
242
250
|
];
|
|
251
|
+
const staticRoutesUsingServerActions = (0, utils_2.getRoutesWithServerAction)(serverReferenceManifest, appPathRoutesManifest);
|
|
243
252
|
const pagesManifestLikePrerender = Object.fromEntries(Object.entries(pagesManifest)
|
|
244
253
|
.filter(([, srcRoute]) => srcRoute.endsWith(".html"))
|
|
245
254
|
.map(([path]) => {
|
|
246
|
-
return [
|
|
255
|
+
return [
|
|
256
|
+
path,
|
|
257
|
+
{
|
|
258
|
+
srcRoute: null,
|
|
259
|
+
initialRevalidateSeconds: false,
|
|
260
|
+
dataRoute: "",
|
|
261
|
+
experimentalPPR: false,
|
|
262
|
+
prefetchDataRoute: "",
|
|
263
|
+
},
|
|
264
|
+
];
|
|
247
265
|
}));
|
|
248
266
|
const routesToCopy = Object.assign(Object.assign({}, prerenderManifest.routes), pagesManifestLikePrerender);
|
|
249
267
|
await Promise.all(Object.entries(routesToCopy).map(async ([path, route]) => {
|
|
@@ -256,6 +274,10 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
|
|
|
256
274
|
logger_1.logger.debug(`skipping ${path} due to it matching an unsupported rewrite/redirect/header or middlware`);
|
|
257
275
|
return;
|
|
258
276
|
}
|
|
277
|
+
if (staticRoutesUsingServerActions.some((it) => path === it)) {
|
|
278
|
+
logger_1.logger.debug(`skipping ${path} due to server action`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
259
281
|
const appPathRoute = route.srcRoute && ((_a = appPathRoutesEntries.find(([, it]) => it === route.srcRoute)) === null || _a === void 0 ? void 0 : _a[0]);
|
|
260
282
|
const contentDist = (0, path_1.join)(sourceDir, distDir, "server", appPathRoute ? "app" : "pages");
|
|
261
283
|
const sourceParts = path.split("/").filter((it) => !!it);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasStaticAppNotFoundComponent = exports.getNextVersion = exports.getBuildId = exports.getHeadersFromMetaFiles = exports.getNonStaticServerComponents = exports.getNonStaticRoutes = exports.getMiddlewareMatcherRegexes = exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingNextImageInAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanI18n = exports.cleanCustomRouteI18n = exports.cleanEscapedChars = exports.I18N_SOURCE = void 0;
|
|
3
|
+
exports.getRoutesWithServerAction = exports.hasStaticAppNotFoundComponent = exports.getNextVersion = exports.getBuildId = exports.getHeadersFromMetaFiles = exports.getNonStaticServerComponents = exports.getNonStaticRoutes = exports.getMiddlewareMatcherRegexes = exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingNextImageInAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanI18n = exports.cleanCustomRouteI18n = exports.cleanEscapedChars = exports.I18N_SOURCE = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const fs_extra_1 = require("fs-extra");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -199,3 +199,22 @@ async function hasStaticAppNotFoundComponent(sourceDir, distDir) {
|
|
|
199
199
|
return (0, fs_extra_1.pathExists)((0, path_1.join)(sourceDir, distDir, "server", "app", "_not-found.html"));
|
|
200
200
|
}
|
|
201
201
|
exports.hasStaticAppNotFoundComponent = hasStaticAppNotFoundComponent;
|
|
202
|
+
function getRoutesWithServerAction(serverReferenceManifest, appPathRoutesManifest) {
|
|
203
|
+
const routesWithServerAction = new Set();
|
|
204
|
+
for (const key of Object.keys(serverReferenceManifest)) {
|
|
205
|
+
if (key !== "edge" && key !== "node")
|
|
206
|
+
continue;
|
|
207
|
+
const edgeOrNode = serverReferenceManifest[key];
|
|
208
|
+
for (const actionId of Object.keys(edgeOrNode)) {
|
|
209
|
+
if (!edgeOrNode[actionId].layer)
|
|
210
|
+
continue;
|
|
211
|
+
for (const [route, type] of Object.entries(edgeOrNode[actionId].layer)) {
|
|
212
|
+
if (type === constants_1.WEBPACK_LAYERS.actionBrowser) {
|
|
213
|
+
routesWithServerAction.add(appPathRoutesManifest[route.replace("app", "")]);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return Array.from(routesWithServerAction);
|
|
219
|
+
}
|
|
220
|
+
exports.getRoutesWithServerAction = getRoutesWithServerAction;
|
package/lib/functions/secrets.js
CHANGED
|
@@ -44,7 +44,7 @@ function toUpperSnakeCase(key) {
|
|
|
44
44
|
}
|
|
45
45
|
function ensureApi(options) {
|
|
46
46
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
47
|
-
return ensureApiEnabled.ensure(projectId,
|
|
47
|
+
return ensureApiEnabled.ensure(projectId, api_1.secretManagerOrigin, "secretmanager", true);
|
|
48
48
|
}
|
|
49
49
|
exports.ensureApi = ensureApi;
|
|
50
50
|
async function ensureValidKey(key, options) {
|
package/lib/gcp/apphosting.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getNextRolloutId = exports.ensureApiEnabled = exports.listLocations = exports.updateTraffic = exports.listRollouts = exports.createRollout = exports.createBuild = exports.listBuilds = exports.getBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.client = exports.API_VERSION =
|
|
3
|
+
exports.getNextRolloutId = exports.ensureApiEnabled = exports.listLocations = exports.updateTraffic = exports.listRollouts = exports.createRollout = exports.createBuild = exports.listBuilds = exports.getBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.client = exports.API_VERSION = void 0;
|
|
4
4
|
const proto = require("../gcp/proto");
|
|
5
5
|
const apiv2_1 = require("../apiv2");
|
|
6
6
|
const projectUtils_1 = require("../projectUtils");
|
|
@@ -9,7 +9,6 @@ const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
|
9
9
|
const deploymentTool = require("../deploymentTool");
|
|
10
10
|
const error_1 = require("../error");
|
|
11
11
|
const metaprogramming_1 = require("../metaprogramming");
|
|
12
|
-
exports.API_HOST = new URL(api_1.apphostingOrigin).host;
|
|
13
12
|
exports.API_VERSION = "v1alpha";
|
|
14
13
|
exports.client = new apiv2_1.Client({
|
|
15
14
|
urlPrefix: api_1.apphostingOrigin,
|
|
@@ -126,7 +125,7 @@ async function listLocations(projectId) {
|
|
|
126
125
|
exports.listLocations = listLocations;
|
|
127
126
|
async function ensureApiEnabled(options) {
|
|
128
127
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
129
|
-
return await (0, ensureApiEnabled_1.ensure)(projectId,
|
|
128
|
+
return await (0, ensureApiEnabled_1.ensure)(projectId, api_1.apphostingOrigin, "app hosting", true);
|
|
130
129
|
}
|
|
131
130
|
exports.ensureApiEnabled = ensureApiEnabled;
|
|
132
131
|
async function getNextRolloutId(projectId, location, backendId, counter) {
|
package/lib/gcp/auth.js
CHANGED
|
@@ -5,12 +5,15 @@ const apiv2_1 = require("../apiv2");
|
|
|
5
5
|
const api_1 = require("../api");
|
|
6
6
|
const apiClient = new apiv2_1.Client({ urlPrefix: api_1.identityOrigin, auth: true });
|
|
7
7
|
async function getAuthDomains(project) {
|
|
8
|
-
const res = await apiClient.get(`/admin/v2/projects/${project}/config
|
|
8
|
+
const res = await apiClient.get(`/admin/v2/projects/${project}/config`, { headers: { "x-goog-user-project": project } });
|
|
9
9
|
return res.body.authorizedDomains;
|
|
10
10
|
}
|
|
11
11
|
exports.getAuthDomains = getAuthDomains;
|
|
12
12
|
async function updateAuthDomains(project, authDomains) {
|
|
13
|
-
const res = await apiClient.patch(`/admin/v2/projects/${project}/config`, { authorizedDomains: authDomains }, {
|
|
13
|
+
const res = await apiClient.patch(`/admin/v2/projects/${project}/config`, { authorizedDomains: authDomains }, {
|
|
14
|
+
queryParams: { update_mask: "authorizedDomains" },
|
|
15
|
+
headers: { "x-goog-user-project": project },
|
|
16
|
+
});
|
|
14
17
|
return res.body.authorizedDomains;
|
|
15
18
|
}
|
|
16
19
|
exports.updateAuthDomains = updateAuthDomains;
|