@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/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-tTvlPgCa.d.ts} +5 -0
- package/dist/ui/ui.js +48 -48
- package/package.json +3 -3
package/dist/plugin.js
CHANGED
|
@@ -837,6 +837,35 @@ var RootCMSClient = class {
|
|
|
837
837
|
}
|
|
838
838
|
return null;
|
|
839
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* Firestore path for a collection.
|
|
842
|
+
*/
|
|
843
|
+
dbCollectionDocsPath(collectionId, options) {
|
|
844
|
+
let modeCollection = "";
|
|
845
|
+
if (options.mode === "draft") {
|
|
846
|
+
modeCollection = "Drafts";
|
|
847
|
+
} else if (options.mode === "published") {
|
|
848
|
+
modeCollection = "Published";
|
|
849
|
+
} else {
|
|
850
|
+
throw new Error(`unknown mode: ${options.mode}`);
|
|
851
|
+
}
|
|
852
|
+
return `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Firestore path for a content doc.
|
|
856
|
+
*/
|
|
857
|
+
dbDocPath(collectionId, slug, options) {
|
|
858
|
+
const collectionDocsPath = this.dbCollectionDocsPath(collectionId, options);
|
|
859
|
+
const normalizedSlug = slug.replaceAll("/", "--");
|
|
860
|
+
return `${collectionDocsPath}/${normalizedSlug}`;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Firestore doc ref for a content doc.
|
|
864
|
+
*/
|
|
865
|
+
dbDocRef(collectionId, slug, options) {
|
|
866
|
+
const docPath = this.dbDocPath(collectionId, slug, options);
|
|
867
|
+
return this.db.doc(docPath);
|
|
868
|
+
}
|
|
840
869
|
/**
|
|
841
870
|
* Saves draft data to a doc.
|
|
842
871
|
*
|
|
@@ -1237,6 +1266,25 @@ var RootCMSClient = class {
|
|
|
1237
1266
|
const translationsMap = await this.loadTranslations(options);
|
|
1238
1267
|
return translationsForLocale(translationsMap, locale);
|
|
1239
1268
|
}
|
|
1269
|
+
/**
|
|
1270
|
+
* Firestore path for a translations file.
|
|
1271
|
+
*/
|
|
1272
|
+
dbTranslationsPath(translationsId, options) {
|
|
1273
|
+
const mode = options.mode;
|
|
1274
|
+
if (!(mode === "draft" || mode === "published")) {
|
|
1275
|
+
throw new Error(`invalid mode: ${mode}`);
|
|
1276
|
+
}
|
|
1277
|
+
const slug = translationsId.replaceAll("/", "--");
|
|
1278
|
+
const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
|
|
1279
|
+
return dbPath;
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Firestore doc ref for a translations file.
|
|
1283
|
+
*/
|
|
1284
|
+
dbTranslationsRef(translationsId, options) {
|
|
1285
|
+
const dbPath = this.dbTranslationsPath(translationsId, options);
|
|
1286
|
+
return this.db.doc(dbPath);
|
|
1287
|
+
}
|
|
1240
1288
|
/**
|
|
1241
1289
|
* Returns a data source configuration object.
|
|
1242
1290
|
*/
|
|
@@ -1359,14 +1407,34 @@ var RootCMSClient = class {
|
|
|
1359
1407
|
if (!dataSourceId || dataSourceId.includes("/")) {
|
|
1360
1408
|
throw new Error(`invalid data source id: ${dataSourceId}`);
|
|
1361
1409
|
}
|
|
1362
|
-
const
|
|
1363
|
-
const docRef = this.db.doc(dbPath);
|
|
1410
|
+
const docRef = this.dbDataSourceDataRef(dataSourceId, { mode });
|
|
1364
1411
|
const doc = await docRef.get();
|
|
1365
1412
|
if (doc.exists) {
|
|
1366
1413
|
return doc.data();
|
|
1367
1414
|
}
|
|
1368
1415
|
return null;
|
|
1369
1416
|
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Firestore path for a datasource data.
|
|
1419
|
+
*/
|
|
1420
|
+
dbDataSourceDataPath(dataSourceId, options) {
|
|
1421
|
+
if (!dataSourceId || dataSourceId.includes("/")) {
|
|
1422
|
+
throw new Error(`invalid data source id: ${dataSourceId}`);
|
|
1423
|
+
}
|
|
1424
|
+
const mode = options.mode;
|
|
1425
|
+
if (!(mode === "draft" || mode === "published")) {
|
|
1426
|
+
throw new Error(`invalid mode: ${mode}`);
|
|
1427
|
+
}
|
|
1428
|
+
const dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
|
|
1429
|
+
return dbPath;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Firestore doc ref for a datasource data.
|
|
1433
|
+
*/
|
|
1434
|
+
dbDataSourceDataRef(dataSourceId, options) {
|
|
1435
|
+
const dbPath = this.dbDataSourceDataPath(dataSourceId, options);
|
|
1436
|
+
return this.db.doc(dbPath);
|
|
1437
|
+
}
|
|
1370
1438
|
/**
|
|
1371
1439
|
* Gets the user's role from the project's ACL.
|
|
1372
1440
|
*/
|
|
@@ -1438,6 +1506,13 @@ var RootCMSClient = class {
|
|
|
1438
1506
|
}
|
|
1439
1507
|
}
|
|
1440
1508
|
}
|
|
1509
|
+
/**
|
|
1510
|
+
* Creates a batch request that is capable of fetching one or more docs,
|
|
1511
|
+
* corresponding translations, and dataSources.
|
|
1512
|
+
*/
|
|
1513
|
+
createBatchRequest(options) {
|
|
1514
|
+
return new BatchRequest(this, options);
|
|
1515
|
+
}
|
|
1441
1516
|
};
|
|
1442
1517
|
function isRichTextData(data) {
|
|
1443
1518
|
return Boolean(
|
|
@@ -1572,6 +1647,210 @@ function parseDocId(docId) {
|
|
|
1572
1647
|
}
|
|
1573
1648
|
return { collection, slug };
|
|
1574
1649
|
}
|
|
1650
|
+
var BatchRequest = class {
|
|
1651
|
+
constructor(cmsClient, options) {
|
|
1652
|
+
this.docIds = [];
|
|
1653
|
+
this.dataSourceIds = [];
|
|
1654
|
+
this.queries = [];
|
|
1655
|
+
this.translationsIds = [];
|
|
1656
|
+
this.cmsClient = cmsClient;
|
|
1657
|
+
this.db = cmsClient.db;
|
|
1658
|
+
this.options = options;
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Adds a doc to the batch request.
|
|
1662
|
+
*/
|
|
1663
|
+
addDoc(docId) {
|
|
1664
|
+
this.docIds.push(docId);
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Adds a data source to the batch request.
|
|
1668
|
+
*/
|
|
1669
|
+
addDataSource(dataSourceId) {
|
|
1670
|
+
this.dataSourceIds.push(dataSourceId);
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Adds a collection-based query to the batch request.
|
|
1674
|
+
*/
|
|
1675
|
+
addQuery(queryId, collectionId, queryOptions) {
|
|
1676
|
+
this.queries.push({
|
|
1677
|
+
queryId,
|
|
1678
|
+
collectionId,
|
|
1679
|
+
queryOptions
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Adds a translation file to the request.
|
|
1684
|
+
*/
|
|
1685
|
+
addTranslations(translationsId) {
|
|
1686
|
+
this.translationsIds.push(translationsId);
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Fetches data from the DB.
|
|
1690
|
+
*/
|
|
1691
|
+
async fetch() {
|
|
1692
|
+
const res = new BatchResponse();
|
|
1693
|
+
const promises = [
|
|
1694
|
+
this.fetchDocs(res),
|
|
1695
|
+
this.fetchQueries(res),
|
|
1696
|
+
this.fetchDataSources(res)
|
|
1697
|
+
];
|
|
1698
|
+
if (!this.options.translate && this.translationsIds.length > 0) {
|
|
1699
|
+
promises.push(this.fetchTranslations(res));
|
|
1700
|
+
}
|
|
1701
|
+
await Promise.all(promises);
|
|
1702
|
+
if (this.translationsIds.length > 0) {
|
|
1703
|
+
await this.fetchTranslations(res);
|
|
1704
|
+
}
|
|
1705
|
+
return res;
|
|
1706
|
+
}
|
|
1707
|
+
async fetchDocs(res) {
|
|
1708
|
+
if (this.docIds.length === 0) {
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
const docRefs = this.docIds.map((docId) => {
|
|
1712
|
+
const [collectionId, slug] = docId.split("/");
|
|
1713
|
+
return this.cmsClient.dbDocRef(collectionId, slug, {
|
|
1714
|
+
mode: this.options.mode
|
|
1715
|
+
});
|
|
1716
|
+
});
|
|
1717
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1718
|
+
this.docIds.forEach((docId, i) => {
|
|
1719
|
+
const doc = docs[i];
|
|
1720
|
+
if (!doc.exists) {
|
|
1721
|
+
console.warn(`doc "${docId}" does not exist`);
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
const docData = unmarshalData(doc.data());
|
|
1725
|
+
res.docs[docId] = docData;
|
|
1726
|
+
if (this.options.translate) {
|
|
1727
|
+
this.addTranslations(docId);
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
async fetchQueries(res) {
|
|
1732
|
+
if (this.queries.length === 0) {
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
const mode = this.options.mode;
|
|
1736
|
+
const handleQuery = async (queryItem) => {
|
|
1737
|
+
const docsPath = this.cmsClient.dbCollectionDocsPath(
|
|
1738
|
+
queryItem.collectionId,
|
|
1739
|
+
{ mode }
|
|
1740
|
+
);
|
|
1741
|
+
const queryOptions = queryItem.queryOptions || {};
|
|
1742
|
+
let query = this.db.collection(docsPath);
|
|
1743
|
+
if (queryOptions.limit) {
|
|
1744
|
+
query = query.limit(queryOptions.limit);
|
|
1745
|
+
}
|
|
1746
|
+
if (queryOptions.offset) {
|
|
1747
|
+
query = query.offset(queryOptions.offset);
|
|
1748
|
+
}
|
|
1749
|
+
if (queryOptions.orderBy) {
|
|
1750
|
+
query = query.orderBy(
|
|
1751
|
+
queryOptions.orderBy,
|
|
1752
|
+
queryOptions.orderByDirection
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
if (queryOptions.query) {
|
|
1756
|
+
query = queryOptions.query(query);
|
|
1757
|
+
}
|
|
1758
|
+
const results = await query.get();
|
|
1759
|
+
const docs = [];
|
|
1760
|
+
results.forEach((result) => {
|
|
1761
|
+
const doc = unmarshalData(result.data());
|
|
1762
|
+
docs.push(doc);
|
|
1763
|
+
});
|
|
1764
|
+
res.queries[queryItem.queryId] = docs;
|
|
1765
|
+
};
|
|
1766
|
+
await Promise.all(this.queries.map((queryItem) => handleQuery(queryItem)));
|
|
1767
|
+
}
|
|
1768
|
+
async fetchDataSources(res) {
|
|
1769
|
+
if (this.dataSourceIds.length === 0) {
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
const docRefs = this.dataSourceIds.map((dataSourceId) => {
|
|
1773
|
+
return this.cmsClient.dbDataSourceDataRef(dataSourceId, {
|
|
1774
|
+
mode: this.options.mode
|
|
1775
|
+
});
|
|
1776
|
+
});
|
|
1777
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1778
|
+
this.dataSourceIds.forEach((dataSourceId, i) => {
|
|
1779
|
+
const doc = docs[i];
|
|
1780
|
+
if (!doc.exists) {
|
|
1781
|
+
console.warn(`"data source "${dataSourceId}" does not exist`);
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
res.dataSources[dataSourceId] = doc.data();
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
async fetchTranslations(res) {
|
|
1788
|
+
if (this.translationsIds.length === 0) {
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
const docRefs = this.translationsIds.map((translationsId) => {
|
|
1792
|
+
return this.cmsClient.dbTranslationsRef(translationsId, {
|
|
1793
|
+
mode: this.options.mode
|
|
1794
|
+
});
|
|
1795
|
+
});
|
|
1796
|
+
const docs = await this.db.getAll(...docRefs);
|
|
1797
|
+
this.translationsIds.forEach((translationsId, i) => {
|
|
1798
|
+
const doc = docs[i];
|
|
1799
|
+
if (!doc.exists) {
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
res.translations[translationsId] = doc.data();
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
var BatchResponse = class {
|
|
1807
|
+
constructor() {
|
|
1808
|
+
this.docs = {};
|
|
1809
|
+
this.queries = {};
|
|
1810
|
+
this.dataSources = {};
|
|
1811
|
+
this.translations = {};
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1814
|
+
* Returns a map of translations for a given locale or locale fallbacks.
|
|
1815
|
+
*
|
|
1816
|
+
* The input is either a single locale (e.g. "de") or an array of locales
|
|
1817
|
+
* representing the fallback tree, e.g. ["en-CA", "en-GB", "en"].
|
|
1818
|
+
*
|
|
1819
|
+
* TODO(stevenle): support the locale fallback tree.
|
|
1820
|
+
*
|
|
1821
|
+
* The returned value is a flat map of source string to translated string,
|
|
1822
|
+
* e.g.:
|
|
1823
|
+
* {"<source>": "<translation>"}
|
|
1824
|
+
*/
|
|
1825
|
+
getTranslations(locale) {
|
|
1826
|
+
const translationsMap = this.getTranslationsMap();
|
|
1827
|
+
const translations = translationsForLocale(translationsMap, locale);
|
|
1828
|
+
return translations;
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* Merges the strings from all translations files retrieved in the request.
|
|
1832
|
+
* The returned value is a map of string to translations, e.g.:
|
|
1833
|
+
*
|
|
1834
|
+
* {"<hash>": {"source": "<source>", "<locale>": "<translation>"}}
|
|
1835
|
+
*/
|
|
1836
|
+
getTranslationsMap() {
|
|
1837
|
+
const translationsDocs = Object.values(this.translations).reverse();
|
|
1838
|
+
const translationsMap = {};
|
|
1839
|
+
for (const translationsDoc of translationsDocs) {
|
|
1840
|
+
const strings = translationsDoc.strings || {};
|
|
1841
|
+
for (const hash in strings) {
|
|
1842
|
+
const translations = strings[hash];
|
|
1843
|
+
translationsMap[hash] ??= { source: translations.source };
|
|
1844
|
+
for (const locale in translations) {
|
|
1845
|
+
if (locale !== "source" && translations[locale]) {
|
|
1846
|
+
translationsMap[hash][locale] = translations[locale];
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
return translationsMap;
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1575
1854
|
|
|
1576
1855
|
// core/versions.ts
|
|
1577
1856
|
import path from "node:path";
|
package/dist/project.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ type SelectField = CommonFieldProps & {
|
|
|
50
50
|
label?: string;
|
|
51
51
|
}> | string[];
|
|
52
52
|
translate?: boolean;
|
|
53
|
+
searchable?: boolean;
|
|
53
54
|
};
|
|
54
55
|
declare function select(field: Omit<SelectField, 'type'>): SelectField;
|
|
55
56
|
type MultiSelectField = Omit<SelectField, 'type'> & {
|
|
@@ -68,6 +69,8 @@ type ImageField = CommonFieldProps & {
|
|
|
68
69
|
* Cache-control header to set on the GCS object.
|
|
69
70
|
*/
|
|
70
71
|
cacheControl?: string;
|
|
72
|
+
/** Set to `false` to disable the alt text input. */
|
|
73
|
+
alt?: boolean;
|
|
71
74
|
};
|
|
72
75
|
declare function image(field: Omit<ImageField, 'type'>): ImageField;
|
|
73
76
|
type FileField = CommonFieldProps & {
|
|
@@ -83,6 +86,8 @@ type FileField = CommonFieldProps & {
|
|
|
83
86
|
* Cache-control header to set on the GCS object.
|
|
84
87
|
*/
|
|
85
88
|
cacheControl?: string;
|
|
89
|
+
/** Set to `false` to disable the alt text input. */
|
|
90
|
+
alt?: boolean;
|
|
86
91
|
};
|
|
87
92
|
declare function file(field: Omit<FileField, 'type'>): FileField;
|
|
88
93
|
type ObjectField = CommonFieldProps & {
|