@blinkk/root-cms 1.4.7 → 1.4.8
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/dist/app.js +2 -2
- package/dist/{client-vS0mO6Nw.d.ts → client-AE0BYn69.d.ts} +145 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +283 -2
- package/dist/core.d.ts +3 -3
- package/dist/core.js +283 -2
- package/dist/functions.js +281 -2
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.js +281 -2
- package/dist/project.d.ts +1 -1
- package/dist/{schema-hlZc-G1f.d.ts → schema-NuZy-PDV.d.ts} +4 -0
- package/dist/ui/ui.js +3 -3
- package/package.json +3 -3
package/dist/core.js
CHANGED
|
@@ -396,6 +396,35 @@ var RootCMSClient = class {
|
|
|
396
396
|
}
|
|
397
397
|
return null;
|
|
398
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Firestore path for a collection.
|
|
401
|
+
*/
|
|
402
|
+
dbCollectionDocsPath(collectionId, options) {
|
|
403
|
+
let modeCollection = "";
|
|
404
|
+
if (options.mode === "draft") {
|
|
405
|
+
modeCollection = "Drafts";
|
|
406
|
+
} else if (options.mode === "published") {
|
|
407
|
+
modeCollection = "Published";
|
|
408
|
+
} else {
|
|
409
|
+
throw new Error(`unknown mode: ${options.mode}`);
|
|
410
|
+
}
|
|
411
|
+
return `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Firestore path for a content doc.
|
|
415
|
+
*/
|
|
416
|
+
dbDocPath(collectionId, slug, options) {
|
|
417
|
+
const collectionDocsPath = this.dbCollectionDocsPath(collectionId, options);
|
|
418
|
+
const normalizedSlug = slug.replaceAll("/", "--");
|
|
419
|
+
return `${collectionDocsPath}/${normalizedSlug}`;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Firestore doc ref for a content doc.
|
|
423
|
+
*/
|
|
424
|
+
dbDocRef(collectionId, slug, options) {
|
|
425
|
+
const docPath = this.dbDocPath(collectionId, slug, options);
|
|
426
|
+
return this.db.doc(docPath);
|
|
427
|
+
}
|
|
399
428
|
/**
|
|
400
429
|
* Saves draft data to a doc.
|
|
401
430
|
*
|
|
@@ -796,6 +825,25 @@ var RootCMSClient = class {
|
|
|
796
825
|
const translationsMap = await this.loadTranslations(options);
|
|
797
826
|
return translationsForLocale(translationsMap, locale);
|
|
798
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* Firestore path for a translations file.
|
|
830
|
+
*/
|
|
831
|
+
dbTranslationsPath(translationsId, options) {
|
|
832
|
+
const mode = options.mode;
|
|
833
|
+
if (!(mode === "draft" || mode === "published")) {
|
|
834
|
+
throw new Error(`invalid mode: ${mode}`);
|
|
835
|
+
}
|
|
836
|
+
const slug = translationsId.replaceAll("/", "--");
|
|
837
|
+
const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
|
|
838
|
+
return dbPath;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Firestore doc ref for a translations file.
|
|
842
|
+
*/
|
|
843
|
+
dbTranslationsRef(translationsId, options) {
|
|
844
|
+
const dbPath = this.dbTranslationsPath(translationsId, options);
|
|
845
|
+
return this.db.doc(dbPath);
|
|
846
|
+
}
|
|
799
847
|
/**
|
|
800
848
|
* Returns a data source configuration object.
|
|
801
849
|
*/
|
|
@@ -918,14 +966,34 @@ var RootCMSClient = class {
|
|
|
918
966
|
if (!dataSourceId || dataSourceId.includes("/")) {
|
|
919
967
|
throw new Error(`invalid data source id: ${dataSourceId}`);
|
|
920
968
|
}
|
|
921
|
-
const
|
|
922
|
-
const docRef = this.db.doc(dbPath);
|
|
969
|
+
const docRef = this.dbDataSourceDataRef(dataSourceId, { mode });
|
|
923
970
|
const doc = await docRef.get();
|
|
924
971
|
if (doc.exists) {
|
|
925
972
|
return doc.data();
|
|
926
973
|
}
|
|
927
974
|
return null;
|
|
928
975
|
}
|
|
976
|
+
/**
|
|
977
|
+
* Firestore path for a datasource data.
|
|
978
|
+
*/
|
|
979
|
+
dbDataSourceDataPath(dataSourceId, options) {
|
|
980
|
+
if (!dataSourceId || dataSourceId.includes("/")) {
|
|
981
|
+
throw new Error(`invalid data source id: ${dataSourceId}`);
|
|
982
|
+
}
|
|
983
|
+
const mode = options.mode;
|
|
984
|
+
if (!(mode === "draft" || mode === "published")) {
|
|
985
|
+
throw new Error(`invalid mode: ${mode}`);
|
|
986
|
+
}
|
|
987
|
+
const dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
|
|
988
|
+
return dbPath;
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Firestore doc ref for a datasource data.
|
|
992
|
+
*/
|
|
993
|
+
dbDataSourceDataRef(dataSourceId, options) {
|
|
994
|
+
const dbPath = this.dbDataSourceDataPath(dataSourceId, options);
|
|
995
|
+
return this.db.doc(dbPath);
|
|
996
|
+
}
|
|
929
997
|
/**
|
|
930
998
|
* Gets the user's role from the project's ACL.
|
|
931
999
|
*/
|
|
@@ -997,6 +1065,13 @@ var RootCMSClient = class {
|
|
|
997
1065
|
}
|
|
998
1066
|
}
|
|
999
1067
|
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Creates a batch request that is capable of fetching one or more docs,
|
|
1070
|
+
* corresponding translations, and dataSources.
|
|
1071
|
+
*/
|
|
1072
|
+
createBatchRequest(options) {
|
|
1073
|
+
return new BatchRequest(this, options);
|
|
1074
|
+
}
|
|
1000
1075
|
};
|
|
1001
1076
|
function isRichTextData(data) {
|
|
1002
1077
|
return Boolean(
|
|
@@ -1142,6 +1217,210 @@ function parseDocId(docId) {
|
|
|
1142
1217
|
}
|
|
1143
1218
|
return { collection: collection2, slug };
|
|
1144
1219
|
}
|
|
1220
|
+
var BatchRequest = class {
|
|
1221
|
+
constructor(cmsClient, options) {
|
|
1222
|
+
this.docIds = [];
|
|
1223
|
+
this.dataSourceIds = [];
|
|
1224
|
+
this.queries = [];
|
|
1225
|
+
this.translationsIds = [];
|
|
1226
|
+
this.cmsClient = cmsClient;
|
|
1227
|
+
this.db = cmsClient.db;
|
|
1228
|
+
this.options = options;
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Adds a doc to the batch request.
|
|
1232
|
+
*/
|
|
1233
|
+
addDoc(docId) {
|
|
1234
|
+
this.docIds.push(docId);
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Adds a data source to the batch request.
|
|
1238
|
+
*/
|
|
1239
|
+
addDataSource(dataSourceId) {
|
|
1240
|
+
this.dataSourceIds.push(dataSourceId);
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Adds a collection-based query to the batch request.
|
|
1244
|
+
*/
|
|
1245
|
+
addQuery(queryId, collectionId, queryOptions) {
|
|
1246
|
+
this.queries.push({
|
|
1247
|
+
queryId,
|
|
1248
|
+
collectionId,
|
|
1249
|
+
queryOptions
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Adds a translation file to the request.
|
|
1254
|
+
*/
|
|
1255
|
+
addTranslations(translationsId) {
|
|
1256
|
+
this.translationsIds.push(translationsId);
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Fetches data from the DB.
|
|
1260
|
+
*/
|
|
1261
|
+
async fetch() {
|
|
1262
|
+
const res = new BatchResponse();
|
|
1263
|
+
const promises = [
|
|
1264
|
+
this.fetchDocs(res),
|
|
1265
|
+
this.fetchQueries(res),
|
|
1266
|
+
this.fetchDataSources(res)
|
|
1267
|
+
];
|
|
1268
|
+
if (!this.options.translate && this.translationsIds.length > 0) {
|
|
1269
|
+
promises.push(this.fetchTranslations(res));
|
|
1270
|
+
}
|
|
1271
|
+
await Promise.all(promises);
|
|
1272
|
+
if (this.translationsIds.length > 0) {
|
|
1273
|
+
await this.fetchTranslations(res);
|
|
1274
|
+
}
|
|
1275
|
+
return res;
|
|
1276
|
+
}
|
|
1277
|
+
async fetchDocs(res) {
|
|
1278
|
+
if (this.docIds.length === 0) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
const docRefs = this.docIds.map((docId) => {
|
|
1282
|
+
const [collectionId, slug] = docId.split("/");
|
|
1283
|
+
return this.cmsClient.dbDocRef(collectionId, slug, {
|
|
1284
|
+
mode: this.options.mode
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1288
|
+
this.docIds.forEach((docId, i) => {
|
|
1289
|
+
const doc = docs[i];
|
|
1290
|
+
if (!doc.exists) {
|
|
1291
|
+
console.warn(`doc "${docId}" does not exist`);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
const docData = unmarshalData(doc.data());
|
|
1295
|
+
res.docs[docId] = docData;
|
|
1296
|
+
if (this.options.translate) {
|
|
1297
|
+
this.addTranslations(docId);
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
async fetchQueries(res) {
|
|
1302
|
+
if (this.queries.length === 0) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
const mode = this.options.mode;
|
|
1306
|
+
const handleQuery = async (queryItem) => {
|
|
1307
|
+
const docsPath = this.cmsClient.dbCollectionDocsPath(
|
|
1308
|
+
queryItem.collectionId,
|
|
1309
|
+
{ mode }
|
|
1310
|
+
);
|
|
1311
|
+
const queryOptions = queryItem.queryOptions || {};
|
|
1312
|
+
let query = this.db.collection(docsPath);
|
|
1313
|
+
if (queryOptions.limit) {
|
|
1314
|
+
query = query.limit(queryOptions.limit);
|
|
1315
|
+
}
|
|
1316
|
+
if (queryOptions.offset) {
|
|
1317
|
+
query = query.offset(queryOptions.offset);
|
|
1318
|
+
}
|
|
1319
|
+
if (queryOptions.orderBy) {
|
|
1320
|
+
query = query.orderBy(
|
|
1321
|
+
queryOptions.orderBy,
|
|
1322
|
+
queryOptions.orderByDirection
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
if (queryOptions.query) {
|
|
1326
|
+
query = queryOptions.query(query);
|
|
1327
|
+
}
|
|
1328
|
+
const results = await query.get();
|
|
1329
|
+
const docs = [];
|
|
1330
|
+
results.forEach((result) => {
|
|
1331
|
+
const doc = unmarshalData(result.data());
|
|
1332
|
+
docs.push(doc);
|
|
1333
|
+
});
|
|
1334
|
+
res.queries[queryItem.queryId] = docs;
|
|
1335
|
+
};
|
|
1336
|
+
await Promise.all(this.queries.map((queryItem) => handleQuery(queryItem)));
|
|
1337
|
+
}
|
|
1338
|
+
async fetchDataSources(res) {
|
|
1339
|
+
if (this.dataSourceIds.length === 0) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const docRefs = this.dataSourceIds.map((dataSourceId) => {
|
|
1343
|
+
return this.cmsClient.dbDataSourceDataRef(dataSourceId, {
|
|
1344
|
+
mode: this.options.mode
|
|
1345
|
+
});
|
|
1346
|
+
});
|
|
1347
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1348
|
+
this.dataSourceIds.forEach((dataSourceId, i) => {
|
|
1349
|
+
const doc = docs[i];
|
|
1350
|
+
if (!doc.exists) {
|
|
1351
|
+
console.warn(`"data source "${dataSourceId}" does not exist`);
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
res.dataSources[dataSourceId] = doc.data();
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
async fetchTranslations(res) {
|
|
1358
|
+
if (this.translationsIds.length === 0) {
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
const docRefs = this.translationsIds.map((translationsId) => {
|
|
1362
|
+
return this.cmsClient.dbTranslationsRef(translationsId, {
|
|
1363
|
+
mode: this.options.mode
|
|
1364
|
+
});
|
|
1365
|
+
});
|
|
1366
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1367
|
+
this.translationsIds.forEach((translationsId, i) => {
|
|
1368
|
+
const doc = docs[i];
|
|
1369
|
+
if (!doc.exists) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
res.translations[translationsId] = doc.data();
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
var BatchResponse = class {
|
|
1377
|
+
constructor() {
|
|
1378
|
+
this.docs = {};
|
|
1379
|
+
this.queries = {};
|
|
1380
|
+
this.dataSources = {};
|
|
1381
|
+
this.translations = {};
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Returns a map of translations for a given locale or locale fallbacks.
|
|
1385
|
+
*
|
|
1386
|
+
* The input is either a single locale (e.g. "de") or an array of locales
|
|
1387
|
+
* representing the fallback tree, e.g. ["en-CA", "en-GB", "en"].
|
|
1388
|
+
*
|
|
1389
|
+
* TODO(stevenle): support the locale fallback tree.
|
|
1390
|
+
*
|
|
1391
|
+
* The returned value is a flat map of source string to translated string,
|
|
1392
|
+
* e.g.:
|
|
1393
|
+
* {"<source>": "<translation>"}
|
|
1394
|
+
*/
|
|
1395
|
+
getTranslations(locale) {
|
|
1396
|
+
const translationsMap = this.getTranslationsMap();
|
|
1397
|
+
const translations = translationsForLocale(translationsMap, locale);
|
|
1398
|
+
return translations;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Merges the strings from all translations files retrieved in the request.
|
|
1402
|
+
* The returned value is a map of string to translations, e.g.:
|
|
1403
|
+
*
|
|
1404
|
+
* {"<hash>": {"source": "<source>", "<locale>": "<translation>"}}
|
|
1405
|
+
*/
|
|
1406
|
+
getTranslationsMap() {
|
|
1407
|
+
const translationsDocs = Object.values(this.translations).reverse();
|
|
1408
|
+
const translationsMap = {};
|
|
1409
|
+
for (const translationsDoc of translationsDocs) {
|
|
1410
|
+
const strings = translationsDoc.strings || {};
|
|
1411
|
+
for (const hash in strings) {
|
|
1412
|
+
const translations = strings[hash];
|
|
1413
|
+
translationsMap[hash] ??= { source: translations.source };
|
|
1414
|
+
for (const locale in translations) {
|
|
1415
|
+
if (locale !== "source" && translations[locale]) {
|
|
1416
|
+
translationsMap[hash][locale] = translations[locale];
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return translationsMap;
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1145
1424
|
|
|
1146
1425
|
// core/runtime.ts
|
|
1147
1426
|
import { FieldValue as FieldValue3 } from "firebase-admin/firestore";
|
|
@@ -1387,6 +1666,8 @@ function defineCollection(collection2) {
|
|
|
1387
1666
|
}
|
|
1388
1667
|
var collection = defineCollection;
|
|
1389
1668
|
export {
|
|
1669
|
+
BatchRequest,
|
|
1670
|
+
BatchResponse,
|
|
1390
1671
|
RootCMSClient,
|
|
1391
1672
|
TranslationsManager,
|
|
1392
1673
|
buildTranslationsDbPath,
|
package/dist/functions.js
CHANGED
|
@@ -395,6 +395,35 @@ var RootCMSClient = class {
|
|
|
395
395
|
}
|
|
396
396
|
return null;
|
|
397
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* Firestore path for a collection.
|
|
400
|
+
*/
|
|
401
|
+
dbCollectionDocsPath(collectionId, options) {
|
|
402
|
+
let modeCollection = "";
|
|
403
|
+
if (options.mode === "draft") {
|
|
404
|
+
modeCollection = "Drafts";
|
|
405
|
+
} else if (options.mode === "published") {
|
|
406
|
+
modeCollection = "Published";
|
|
407
|
+
} else {
|
|
408
|
+
throw new Error(`unknown mode: ${options.mode}`);
|
|
409
|
+
}
|
|
410
|
+
return `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Firestore path for a content doc.
|
|
414
|
+
*/
|
|
415
|
+
dbDocPath(collectionId, slug, options) {
|
|
416
|
+
const collectionDocsPath = this.dbCollectionDocsPath(collectionId, options);
|
|
417
|
+
const normalizedSlug = slug.replaceAll("/", "--");
|
|
418
|
+
return `${collectionDocsPath}/${normalizedSlug}`;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Firestore doc ref for a content doc.
|
|
422
|
+
*/
|
|
423
|
+
dbDocRef(collectionId, slug, options) {
|
|
424
|
+
const docPath = this.dbDocPath(collectionId, slug, options);
|
|
425
|
+
return this.db.doc(docPath);
|
|
426
|
+
}
|
|
398
427
|
/**
|
|
399
428
|
* Saves draft data to a doc.
|
|
400
429
|
*
|
|
@@ -795,6 +824,25 @@ var RootCMSClient = class {
|
|
|
795
824
|
const translationsMap = await this.loadTranslations(options);
|
|
796
825
|
return translationsForLocale(translationsMap, locale);
|
|
797
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Firestore path for a translations file.
|
|
829
|
+
*/
|
|
830
|
+
dbTranslationsPath(translationsId, options) {
|
|
831
|
+
const mode = options.mode;
|
|
832
|
+
if (!(mode === "draft" || mode === "published")) {
|
|
833
|
+
throw new Error(`invalid mode: ${mode}`);
|
|
834
|
+
}
|
|
835
|
+
const slug = translationsId.replaceAll("/", "--");
|
|
836
|
+
const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
|
|
837
|
+
return dbPath;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Firestore doc ref for a translations file.
|
|
841
|
+
*/
|
|
842
|
+
dbTranslationsRef(translationsId, options) {
|
|
843
|
+
const dbPath = this.dbTranslationsPath(translationsId, options);
|
|
844
|
+
return this.db.doc(dbPath);
|
|
845
|
+
}
|
|
798
846
|
/**
|
|
799
847
|
* Returns a data source configuration object.
|
|
800
848
|
*/
|
|
@@ -917,14 +965,34 @@ var RootCMSClient = class {
|
|
|
917
965
|
if (!dataSourceId || dataSourceId.includes("/")) {
|
|
918
966
|
throw new Error(`invalid data source id: ${dataSourceId}`);
|
|
919
967
|
}
|
|
920
|
-
const
|
|
921
|
-
const docRef = this.db.doc(dbPath);
|
|
968
|
+
const docRef = this.dbDataSourceDataRef(dataSourceId, { mode });
|
|
922
969
|
const doc = await docRef.get();
|
|
923
970
|
if (doc.exists) {
|
|
924
971
|
return doc.data();
|
|
925
972
|
}
|
|
926
973
|
return null;
|
|
927
974
|
}
|
|
975
|
+
/**
|
|
976
|
+
* Firestore path for a datasource data.
|
|
977
|
+
*/
|
|
978
|
+
dbDataSourceDataPath(dataSourceId, options) {
|
|
979
|
+
if (!dataSourceId || dataSourceId.includes("/")) {
|
|
980
|
+
throw new Error(`invalid data source id: ${dataSourceId}`);
|
|
981
|
+
}
|
|
982
|
+
const mode = options.mode;
|
|
983
|
+
if (!(mode === "draft" || mode === "published")) {
|
|
984
|
+
throw new Error(`invalid mode: ${mode}`);
|
|
985
|
+
}
|
|
986
|
+
const dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
|
|
987
|
+
return dbPath;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Firestore doc ref for a datasource data.
|
|
991
|
+
*/
|
|
992
|
+
dbDataSourceDataRef(dataSourceId, options) {
|
|
993
|
+
const dbPath = this.dbDataSourceDataPath(dataSourceId, options);
|
|
994
|
+
return this.db.doc(dbPath);
|
|
995
|
+
}
|
|
928
996
|
/**
|
|
929
997
|
* Gets the user's role from the project's ACL.
|
|
930
998
|
*/
|
|
@@ -996,6 +1064,13 @@ var RootCMSClient = class {
|
|
|
996
1064
|
}
|
|
997
1065
|
}
|
|
998
1066
|
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Creates a batch request that is capable of fetching one or more docs,
|
|
1069
|
+
* corresponding translations, and dataSources.
|
|
1070
|
+
*/
|
|
1071
|
+
createBatchRequest(options) {
|
|
1072
|
+
return new BatchRequest(this, options);
|
|
1073
|
+
}
|
|
999
1074
|
};
|
|
1000
1075
|
function isRichTextData(data) {
|
|
1001
1076
|
return Boolean(
|
|
@@ -1130,6 +1205,210 @@ function parseDocId(docId) {
|
|
|
1130
1205
|
}
|
|
1131
1206
|
return { collection, slug };
|
|
1132
1207
|
}
|
|
1208
|
+
var BatchRequest = class {
|
|
1209
|
+
constructor(cmsClient, options) {
|
|
1210
|
+
this.docIds = [];
|
|
1211
|
+
this.dataSourceIds = [];
|
|
1212
|
+
this.queries = [];
|
|
1213
|
+
this.translationsIds = [];
|
|
1214
|
+
this.cmsClient = cmsClient;
|
|
1215
|
+
this.db = cmsClient.db;
|
|
1216
|
+
this.options = options;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Adds a doc to the batch request.
|
|
1220
|
+
*/
|
|
1221
|
+
addDoc(docId) {
|
|
1222
|
+
this.docIds.push(docId);
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Adds a data source to the batch request.
|
|
1226
|
+
*/
|
|
1227
|
+
addDataSource(dataSourceId) {
|
|
1228
|
+
this.dataSourceIds.push(dataSourceId);
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Adds a collection-based query to the batch request.
|
|
1232
|
+
*/
|
|
1233
|
+
addQuery(queryId, collectionId, queryOptions) {
|
|
1234
|
+
this.queries.push({
|
|
1235
|
+
queryId,
|
|
1236
|
+
collectionId,
|
|
1237
|
+
queryOptions
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Adds a translation file to the request.
|
|
1242
|
+
*/
|
|
1243
|
+
addTranslations(translationsId) {
|
|
1244
|
+
this.translationsIds.push(translationsId);
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Fetches data from the DB.
|
|
1248
|
+
*/
|
|
1249
|
+
async fetch() {
|
|
1250
|
+
const res = new BatchResponse();
|
|
1251
|
+
const promises = [
|
|
1252
|
+
this.fetchDocs(res),
|
|
1253
|
+
this.fetchQueries(res),
|
|
1254
|
+
this.fetchDataSources(res)
|
|
1255
|
+
];
|
|
1256
|
+
if (!this.options.translate && this.translationsIds.length > 0) {
|
|
1257
|
+
promises.push(this.fetchTranslations(res));
|
|
1258
|
+
}
|
|
1259
|
+
await Promise.all(promises);
|
|
1260
|
+
if (this.translationsIds.length > 0) {
|
|
1261
|
+
await this.fetchTranslations(res);
|
|
1262
|
+
}
|
|
1263
|
+
return res;
|
|
1264
|
+
}
|
|
1265
|
+
async fetchDocs(res) {
|
|
1266
|
+
if (this.docIds.length === 0) {
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
const docRefs = this.docIds.map((docId) => {
|
|
1270
|
+
const [collectionId, slug] = docId.split("/");
|
|
1271
|
+
return this.cmsClient.dbDocRef(collectionId, slug, {
|
|
1272
|
+
mode: this.options.mode
|
|
1273
|
+
});
|
|
1274
|
+
});
|
|
1275
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1276
|
+
this.docIds.forEach((docId, i) => {
|
|
1277
|
+
const doc = docs[i];
|
|
1278
|
+
if (!doc.exists) {
|
|
1279
|
+
console.warn(`doc "${docId}" does not exist`);
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
const docData = unmarshalData(doc.data());
|
|
1283
|
+
res.docs[docId] = docData;
|
|
1284
|
+
if (this.options.translate) {
|
|
1285
|
+
this.addTranslations(docId);
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
async fetchQueries(res) {
|
|
1290
|
+
if (this.queries.length === 0) {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
const mode = this.options.mode;
|
|
1294
|
+
const handleQuery = async (queryItem) => {
|
|
1295
|
+
const docsPath = this.cmsClient.dbCollectionDocsPath(
|
|
1296
|
+
queryItem.collectionId,
|
|
1297
|
+
{ mode }
|
|
1298
|
+
);
|
|
1299
|
+
const queryOptions = queryItem.queryOptions || {};
|
|
1300
|
+
let query = this.db.collection(docsPath);
|
|
1301
|
+
if (queryOptions.limit) {
|
|
1302
|
+
query = query.limit(queryOptions.limit);
|
|
1303
|
+
}
|
|
1304
|
+
if (queryOptions.offset) {
|
|
1305
|
+
query = query.offset(queryOptions.offset);
|
|
1306
|
+
}
|
|
1307
|
+
if (queryOptions.orderBy) {
|
|
1308
|
+
query = query.orderBy(
|
|
1309
|
+
queryOptions.orderBy,
|
|
1310
|
+
queryOptions.orderByDirection
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
if (queryOptions.query) {
|
|
1314
|
+
query = queryOptions.query(query);
|
|
1315
|
+
}
|
|
1316
|
+
const results = await query.get();
|
|
1317
|
+
const docs = [];
|
|
1318
|
+
results.forEach((result) => {
|
|
1319
|
+
const doc = unmarshalData(result.data());
|
|
1320
|
+
docs.push(doc);
|
|
1321
|
+
});
|
|
1322
|
+
res.queries[queryItem.queryId] = docs;
|
|
1323
|
+
};
|
|
1324
|
+
await Promise.all(this.queries.map((queryItem) => handleQuery(queryItem)));
|
|
1325
|
+
}
|
|
1326
|
+
async fetchDataSources(res) {
|
|
1327
|
+
if (this.dataSourceIds.length === 0) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
const docRefs = this.dataSourceIds.map((dataSourceId) => {
|
|
1331
|
+
return this.cmsClient.dbDataSourceDataRef(dataSourceId, {
|
|
1332
|
+
mode: this.options.mode
|
|
1333
|
+
});
|
|
1334
|
+
});
|
|
1335
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1336
|
+
this.dataSourceIds.forEach((dataSourceId, i) => {
|
|
1337
|
+
const doc = docs[i];
|
|
1338
|
+
if (!doc.exists) {
|
|
1339
|
+
console.warn(`"data source "${dataSourceId}" does not exist`);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
res.dataSources[dataSourceId] = doc.data();
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
async fetchTranslations(res) {
|
|
1346
|
+
if (this.translationsIds.length === 0) {
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
const docRefs = this.translationsIds.map((translationsId) => {
|
|
1350
|
+
return this.cmsClient.dbTranslationsRef(translationsId, {
|
|
1351
|
+
mode: this.options.mode
|
|
1352
|
+
});
|
|
1353
|
+
});
|
|
1354
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1355
|
+
this.translationsIds.forEach((translationsId, i) => {
|
|
1356
|
+
const doc = docs[i];
|
|
1357
|
+
if (!doc.exists) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
res.translations[translationsId] = doc.data();
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
};
|
|
1364
|
+
var BatchResponse = class {
|
|
1365
|
+
constructor() {
|
|
1366
|
+
this.docs = {};
|
|
1367
|
+
this.queries = {};
|
|
1368
|
+
this.dataSources = {};
|
|
1369
|
+
this.translations = {};
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Returns a map of translations for a given locale or locale fallbacks.
|
|
1373
|
+
*
|
|
1374
|
+
* The input is either a single locale (e.g. "de") or an array of locales
|
|
1375
|
+
* representing the fallback tree, e.g. ["en-CA", "en-GB", "en"].
|
|
1376
|
+
*
|
|
1377
|
+
* TODO(stevenle): support the locale fallback tree.
|
|
1378
|
+
*
|
|
1379
|
+
* The returned value is a flat map of source string to translated string,
|
|
1380
|
+
* e.g.:
|
|
1381
|
+
* {"<source>": "<translation>"}
|
|
1382
|
+
*/
|
|
1383
|
+
getTranslations(locale) {
|
|
1384
|
+
const translationsMap = this.getTranslationsMap();
|
|
1385
|
+
const translations = translationsForLocale(translationsMap, locale);
|
|
1386
|
+
return translations;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Merges the strings from all translations files retrieved in the request.
|
|
1390
|
+
* The returned value is a map of string to translations, e.g.:
|
|
1391
|
+
*
|
|
1392
|
+
* {"<hash>": {"source": "<source>", "<locale>": "<translation>"}}
|
|
1393
|
+
*/
|
|
1394
|
+
getTranslationsMap() {
|
|
1395
|
+
const translationsDocs = Object.values(this.translations).reverse();
|
|
1396
|
+
const translationsMap = {};
|
|
1397
|
+
for (const translationsDoc of translationsDocs) {
|
|
1398
|
+
const strings = translationsDoc.strings || {};
|
|
1399
|
+
for (const hash in strings) {
|
|
1400
|
+
const translations = strings[hash];
|
|
1401
|
+
translationsMap[hash] ??= { source: translations.source };
|
|
1402
|
+
for (const locale in translations) {
|
|
1403
|
+
if (locale !== "source" && translations[locale]) {
|
|
1404
|
+
translationsMap[hash][locale] = translations[locale];
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
return translationsMap;
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1133
1412
|
|
|
1134
1413
|
// core/versions.ts
|
|
1135
1414
|
import path from "node:path";
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import '@blinkk/root';
|
|
2
2
|
import 'firebase-admin/app';
|
|
3
3
|
import 'firebase-admin/firestore';
|
|
4
|
-
export {
|
|
4
|
+
export { X as CMSAIConfig, _ as CMSPlugin, Z as CMSPluginOptions, Y as CMSSidebarTool, W as CMSUser, $ as cmsPlugin } from './client-AE0BYn69.js';
|