@blinkk/root-cms 1.4.7 → 1.4.9

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/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 dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
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 dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
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 { N as CMSAIConfig, Q as CMSPlugin, P as CMSPluginOptions, O as CMSSidebarTool, K as CMSUser, V as cmsPlugin } from './client-vS0mO6Nw.js';
4
+ export { X as CMSAIConfig, _ as CMSPlugin, Z as CMSPluginOptions, Y as CMSSidebarTool, W as CMSUser, $ as cmsPlugin } from './client-AE0BYn69.js';