@blinkk/root-cms 2.5.1 → 2.5.3
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 +3 -2
- package/dist/{chunk-RYF3UTHQ.js → chunk-KDXHFMIH.js} +3 -3
- package/dist/{chunk-RNDSZKAW.js → chunk-MSJGHSR6.js} +3 -2
- package/dist/{chunk-KTUENARU.js → chunk-WVOTD7EW.js} +2 -2
- package/dist/{chunk-NUUABQRN.js → chunk-XMR3KFP5.js} +203 -15
- package/dist/{chunk-RIJF2AHU.js → chunk-YAQCD6SS.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{client-ROwBDNeR.d.ts → client-C1pZQL7M.d.ts} +86 -2
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/core.d.ts +2 -2
- package/dist/core.js +5 -4
- package/dist/functions.js +2 -2
- package/dist/{generate-types-TQBCE2SG.js → generate-types-MHWSSOWV.js} +1 -1
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.js +4 -4
- package/dist/project.d.ts +8 -3
- package/dist/project.js +5 -3
- package/dist/ui/ui.css +1 -1
- package/dist/ui/ui.js +142 -142
- package/dist/ui/ui.js.LEGAL.txt +2 -0
- package/package.json +3 -3
package/dist/app.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getServerVersion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WVOTD7EW.js";
|
|
4
4
|
import {
|
|
5
5
|
getCollectionSchema,
|
|
6
6
|
getProjectSchemas
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MSJGHSR6.js";
|
|
8
8
|
import "./chunk-MLKGABMK.js";
|
|
9
9
|
|
|
10
10
|
// core/app.tsx
|
|
@@ -97,6 +97,7 @@ async function renderApp(req, res, options) {
|
|
|
97
97
|
rootConfig: {
|
|
98
98
|
projectId: cmsConfig.id || "default",
|
|
99
99
|
projectName: cmsConfig.name || cmsConfig.id || "",
|
|
100
|
+
minimalBranding: cmsConfig.minimalBranding ?? false,
|
|
100
101
|
domain: rootConfig.domain || "https://example.com",
|
|
101
102
|
base: rootConfig.base || "/",
|
|
102
103
|
gci,
|
|
@@ -13,7 +13,7 @@ async function generateTypes() {
|
|
|
13
13
|
rootConfig,
|
|
14
14
|
modulePath
|
|
15
15
|
);
|
|
16
|
-
const schemas =
|
|
16
|
+
const schemas = project.getProjectSchemas();
|
|
17
17
|
const outputPath = path.resolve(rootDir, "root-cms.d.ts");
|
|
18
18
|
await generateSchemaDts(outputPath, schemas);
|
|
19
19
|
console.log("saved root-cms.d.ts!");
|
|
@@ -227,11 +227,11 @@ function fieldType(field, options) {
|
|
|
227
227
|
if (field.types && Array.isArray(field.types)) {
|
|
228
228
|
const unionTypes = [];
|
|
229
229
|
field.types.forEach((schema) => {
|
|
230
|
-
let typeName;
|
|
230
|
+
let typeName = "";
|
|
231
231
|
if (typeof schema === "string") {
|
|
232
232
|
typeName = schema;
|
|
233
233
|
return;
|
|
234
|
-
} else {
|
|
234
|
+
} else if (schema?.name) {
|
|
235
235
|
typeName = schema.name;
|
|
236
236
|
}
|
|
237
237
|
if (!typeName) {
|
|
@@ -8,7 +8,7 @@ var SCHEMA_MODULES = import.meta.glob(
|
|
|
8
8
|
],
|
|
9
9
|
{ eager: true }
|
|
10
10
|
);
|
|
11
|
-
|
|
11
|
+
function getProjectSchemas() {
|
|
12
12
|
const schemas = {};
|
|
13
13
|
for (const fileId in SCHEMA_MODULES) {
|
|
14
14
|
const schemaModule = SCHEMA_MODULES[fileId];
|
|
@@ -37,7 +37,7 @@ function resolveOneOfPatterns(schemaObj) {
|
|
|
37
37
|
(clone.fields || []).forEach(handleField);
|
|
38
38
|
return clone;
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
function getCollectionSchema(collectionId) {
|
|
41
41
|
if (!testValidCollectionId(collectionId)) {
|
|
42
42
|
throw new Error(`invalid collection id: ${collectionId}`);
|
|
43
43
|
}
|
|
@@ -167,5 +167,6 @@ function convertOneOfTypes(collection) {
|
|
|
167
167
|
export {
|
|
168
168
|
SCHEMA_MODULES,
|
|
169
169
|
getProjectSchemas,
|
|
170
|
+
resolveOneOfPatterns,
|
|
170
171
|
getCollectionSchema
|
|
171
172
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@blinkk/root-cms",
|
|
4
|
-
version: "2.5.
|
|
4
|
+
version: "2.5.3",
|
|
5
5
|
author: "s@blinkk.com",
|
|
6
6
|
license: "MIT",
|
|
7
7
|
engines: {
|
|
@@ -166,7 +166,7 @@ var package_default = {
|
|
|
166
166
|
yjs: "13.6.27"
|
|
167
167
|
},
|
|
168
168
|
peerDependencies: {
|
|
169
|
-
"@blinkk/root": "2.5.
|
|
169
|
+
"@blinkk/root": "2.5.3",
|
|
170
170
|
"firebase-admin": ">=11",
|
|
171
171
|
"firebase-functions": ">=4",
|
|
172
172
|
preact: ">=10",
|
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
Timestamp as Timestamp2
|
|
6
6
|
} from "firebase-admin/firestore";
|
|
7
7
|
|
|
8
|
+
// shared/slug.ts
|
|
9
|
+
function normalizeSlug(slug) {
|
|
10
|
+
return slug.replace(/^[\s/]*/g, "").replace(/[\s/]*$/g, "").replace(/^\/+|\/+$/g, "").replaceAll("/", "--");
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
// core/translations-manager.ts
|
|
9
14
|
import {
|
|
10
15
|
FieldValue,
|
|
@@ -350,7 +355,7 @@ function buildTranslationsLocaleDocDbPath(options) {
|
|
|
350
355
|
return TRANSLATIONS_LOCALE_DOC_DB_PATH_FORMAT.replace(
|
|
351
356
|
"{project}",
|
|
352
357
|
options.project
|
|
353
|
-
).replace("{mode}", options.mode).replace("{id}", options.id
|
|
358
|
+
).replace("{mode}", options.mode).replace("{id}", normalizeSlug(options.id)).replace("{locale}", options.locale);
|
|
354
359
|
}
|
|
355
360
|
|
|
356
361
|
// core/validation.ts
|
|
@@ -675,6 +680,12 @@ var RootCMSClient = class {
|
|
|
675
680
|
this.app = this.cmsPlugin.getFirebaseApp();
|
|
676
681
|
this.db = this.cmsPlugin.getFirestore();
|
|
677
682
|
}
|
|
683
|
+
/**
|
|
684
|
+
* Converts a doc mode to the Firestore collection name.
|
|
685
|
+
*/
|
|
686
|
+
getModeCollection(mode) {
|
|
687
|
+
return mode === "draft" ? "Drafts" : "Published";
|
|
688
|
+
}
|
|
678
689
|
/**
|
|
679
690
|
* Retrieves doc data from Root.js CMS.
|
|
680
691
|
*/
|
|
@@ -690,9 +701,14 @@ var RootCMSClient = class {
|
|
|
690
701
|
* what you are doing.
|
|
691
702
|
*/
|
|
692
703
|
async getRawDoc(collectionId, slug, options) {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
704
|
+
if (!collectionId) {
|
|
705
|
+
throw new Error("collectionId is required");
|
|
706
|
+
}
|
|
707
|
+
if (!slug) {
|
|
708
|
+
throw new Error("slug is required");
|
|
709
|
+
}
|
|
710
|
+
const modeCollection = this.getModeCollection(options.mode);
|
|
711
|
+
slug = normalizeSlug(slug);
|
|
696
712
|
const dbPath = `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}/${slug}`;
|
|
697
713
|
const docRef = this.db.doc(dbPath);
|
|
698
714
|
const doc = await docRef.get();
|
|
@@ -720,7 +736,7 @@ var RootCMSClient = class {
|
|
|
720
736
|
*/
|
|
721
737
|
dbDocPath(collectionId, slug, options) {
|
|
722
738
|
const collectionDocsPath = this.dbCollectionDocsPath(collectionId, options);
|
|
723
|
-
const normalizedSlug = slug
|
|
739
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
724
740
|
return `${collectionDocsPath}/${normalizedSlug}`;
|
|
725
741
|
}
|
|
726
742
|
/**
|
|
@@ -801,12 +817,98 @@ ${errorMessages}`);
|
|
|
801
817
|
});
|
|
802
818
|
}
|
|
803
819
|
/**
|
|
804
|
-
*
|
|
805
|
-
*
|
|
820
|
+
* Sets the raw document data directly in Firestore.
|
|
821
|
+
*
|
|
822
|
+
* CAUTION Prefer using `saveDraftData('Pages/foo', data)` in most cases.
|
|
823
|
+
* Only use this method if you need to manipulate system-level (sys) fields
|
|
824
|
+
* directly or if you're implementing low-level data operations.
|
|
825
|
+
*
|
|
826
|
+
* ## Validation & Normalization
|
|
827
|
+
*
|
|
828
|
+
* This method automatically validates and normalizes `sys` fields to prevent
|
|
829
|
+
* data integrity issues that can cause runtime errors like
|
|
830
|
+
* "e.toMillis is not a function".
|
|
831
|
+
*
|
|
832
|
+
* ### Timestamp Fields (auto-converted)
|
|
833
|
+
* The following fields accept multiple formats and are automatically converted
|
|
834
|
+
* to Firestore Timestamp objects:
|
|
835
|
+
* - `sys.createdAt`
|
|
836
|
+
* - `sys.modifiedAt`
|
|
837
|
+
* - `sys.publishedAt`
|
|
838
|
+
* - `sys.firstPublishedAt`
|
|
839
|
+
*
|
|
840
|
+
* Accepted formats:
|
|
841
|
+
* - Firestore `Timestamp` object (unchanged)
|
|
842
|
+
* - `number` - Interpreted as milliseconds since epoch, converted to Timestamp
|
|
843
|
+
* - `Date` object - Converted to Timestamp
|
|
844
|
+
*
|
|
845
|
+
* ### Required Fields (auto-populated with defaults if missing)
|
|
846
|
+
* - `sys.createdAt` - Defaults to current time if not provided
|
|
847
|
+
* - `sys.modifiedAt` - Defaults to current time if not provided
|
|
848
|
+
* - `sys.createdBy` - Defaults to 'root-cms-client' if not provided
|
|
849
|
+
* - `sys.modifiedBy` - Defaults to 'root-cms-client' if not provided
|
|
850
|
+
* - `sys.locales` - Defaults to ['en'] if not provided
|
|
851
|
+
*
|
|
852
|
+
* ### Optional Fields (validated if present)
|
|
853
|
+
* - `sys.publishedBy` - String identifier
|
|
854
|
+
* - `sys.firstPublishedBy` - String identifier
|
|
855
|
+
* - `sys.publishingLocked` - Object with optional `until` Timestamp
|
|
856
|
+
*
|
|
857
|
+
* ### Document Identity
|
|
858
|
+
* The `id`, `collection`, and `slug` fields are always set to match the
|
|
859
|
+
* provided parameters, overwriting any existing values to prevent data
|
|
860
|
+
* inconsistencies.
|
|
861
|
+
*
|
|
862
|
+
* @param collectionId - The collection ID (e.g., 'Pages')
|
|
863
|
+
* @param slug - The document slug (e.g., 'home')
|
|
864
|
+
* @param data - The complete document data including sys and fields
|
|
865
|
+
* @param options - Options specifying mode ('draft' or 'published')
|
|
866
|
+
*
|
|
867
|
+
* @throws {Error} If sys fields are invalid or missing required fields
|
|
868
|
+
* @throws {Error} If timestamp fields have invalid types
|
|
869
|
+
*
|
|
870
|
+
* @example
|
|
871
|
+
* ```typescript
|
|
872
|
+
* // Minimal example - sys fields use defaults
|
|
873
|
+
* await client.setRawDoc('Pages', 'home', {
|
|
874
|
+
* sys: {}, // All sys fields will be auto-populated with defaults
|
|
875
|
+
* fields: {
|
|
876
|
+
* title: 'Home Page'
|
|
877
|
+
* }
|
|
878
|
+
* }, { mode: 'draft' });
|
|
879
|
+
*
|
|
880
|
+
* // Full example - with number timestamps (auto-converted)
|
|
881
|
+
* await client.setRawDoc('Pages', 'home', {
|
|
882
|
+
* id: 'Pages/home',
|
|
883
|
+
* collection: 'Pages',
|
|
884
|
+
* slug: 'home',
|
|
885
|
+
* sys: {
|
|
886
|
+
* createdAt: Date.now(), // Auto-converted to Timestamp.
|
|
887
|
+
* createdBy: 'user@example.com',
|
|
888
|
+
* modifiedAt: Date.now(), // Auto-converted to Timestamp.
|
|
889
|
+
* modifiedBy: 'user@example.com',
|
|
890
|
+
* locales: ['en', 'es']
|
|
891
|
+
* },
|
|
892
|
+
* fields: {
|
|
893
|
+
* title: 'Home Page'
|
|
894
|
+
* }
|
|
895
|
+
* }, { mode: 'draft' });
|
|
896
|
+
* ```
|
|
806
897
|
*/
|
|
807
898
|
async setRawDoc(collectionId, slug, data, options) {
|
|
808
|
-
|
|
809
|
-
|
|
899
|
+
if (!collectionId) {
|
|
900
|
+
throw new Error("collectionId is required");
|
|
901
|
+
}
|
|
902
|
+
if (!slug) {
|
|
903
|
+
throw new Error("slug is required");
|
|
904
|
+
}
|
|
905
|
+
slug = normalizeSlug(slug);
|
|
906
|
+
const expectedId = `${collectionId}/${slug}`;
|
|
907
|
+
data.id = expectedId;
|
|
908
|
+
data.collection = collectionId;
|
|
909
|
+
data.slug = slug;
|
|
910
|
+
data.sys = validateSysFields(data.sys || {});
|
|
911
|
+
const modeCollection = this.getModeCollection(options.mode);
|
|
810
912
|
const dbPath = `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}/${slug}`;
|
|
811
913
|
const docRef = this.db.doc(dbPath);
|
|
812
914
|
await docRef.set(data);
|
|
@@ -815,8 +917,10 @@ ${errorMessages}`);
|
|
|
815
917
|
* Lists docs from a Root.js CMS collection.
|
|
816
918
|
*/
|
|
817
919
|
async listDocs(collectionId, options) {
|
|
818
|
-
|
|
819
|
-
|
|
920
|
+
if (!collectionId) {
|
|
921
|
+
throw new Error("collectionId is required");
|
|
922
|
+
}
|
|
923
|
+
const modeCollection = this.getModeCollection(options.mode);
|
|
820
924
|
const dbPath = `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
|
|
821
925
|
let query = this.db.collection(dbPath);
|
|
822
926
|
if (options.limit) {
|
|
@@ -848,8 +952,10 @@ ${errorMessages}`);
|
|
|
848
952
|
* Returns the number of docs in a Root.js CMS collection.
|
|
849
953
|
*/
|
|
850
954
|
async getDocsCount(collectionId, options) {
|
|
851
|
-
|
|
852
|
-
|
|
955
|
+
if (!collectionId) {
|
|
956
|
+
throw new Error("collectionId is required");
|
|
957
|
+
}
|
|
958
|
+
const modeCollection = this.getModeCollection(options.mode);
|
|
853
959
|
const dbPath = `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
|
|
854
960
|
let query = this.db.collection(dbPath);
|
|
855
961
|
if (options.query) {
|
|
@@ -1295,7 +1401,7 @@ ${errorMessages}`);
|
|
|
1295
1401
|
if (!(mode === "draft" || mode === "published")) {
|
|
1296
1402
|
throw new Error(`invalid mode: ${mode}`);
|
|
1297
1403
|
}
|
|
1298
|
-
const slug = translationsId
|
|
1404
|
+
const slug = normalizeSlug(translationsId);
|
|
1299
1405
|
const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
|
|
1300
1406
|
return dbPath;
|
|
1301
1407
|
}
|
|
@@ -1639,6 +1745,87 @@ function unmarshalData(data) {
|
|
|
1639
1745
|
}
|
|
1640
1746
|
return result;
|
|
1641
1747
|
}
|
|
1748
|
+
function isDef(value) {
|
|
1749
|
+
return value !== void 0 && value !== null;
|
|
1750
|
+
}
|
|
1751
|
+
function convertToTimestamp(value, fieldName) {
|
|
1752
|
+
if (value && typeof value === "object" && typeof value.toMillis === "function") {
|
|
1753
|
+
return value;
|
|
1754
|
+
}
|
|
1755
|
+
if (typeof value === "number") {
|
|
1756
|
+
return Timestamp2.fromMillis(value);
|
|
1757
|
+
}
|
|
1758
|
+
if (value instanceof Date) {
|
|
1759
|
+
return Timestamp2.fromDate(value);
|
|
1760
|
+
}
|
|
1761
|
+
throw new Error(
|
|
1762
|
+
`Invalid timestamp for ${fieldName}: expected Timestamp, number, or Date, got ${typeof value}`
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
function validateSysFields(sys) {
|
|
1766
|
+
if (!sys || typeof sys !== "object") {
|
|
1767
|
+
throw new Error("sys must be an object");
|
|
1768
|
+
}
|
|
1769
|
+
const result = { ...sys };
|
|
1770
|
+
const now = Timestamp2.now();
|
|
1771
|
+
if (isDef(result.createdAt)) {
|
|
1772
|
+
result.createdAt = convertToTimestamp(result.createdAt, "sys.createdAt");
|
|
1773
|
+
} else {
|
|
1774
|
+
result.createdAt = now;
|
|
1775
|
+
}
|
|
1776
|
+
if (isDef(result.modifiedAt)) {
|
|
1777
|
+
result.modifiedAt = convertToTimestamp(result.modifiedAt, "sys.modifiedAt");
|
|
1778
|
+
} else {
|
|
1779
|
+
result.modifiedAt = now;
|
|
1780
|
+
}
|
|
1781
|
+
const optionalTimestampFields = ["firstPublishedAt", "publishedAt"];
|
|
1782
|
+
for (const field of optionalTimestampFields) {
|
|
1783
|
+
if (isDef(sys[field])) {
|
|
1784
|
+
result[field] = convertToTimestamp(sys[field], `sys.${field}`);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
if (!result.createdBy || typeof result.createdBy !== "string") {
|
|
1788
|
+
result.createdBy = "root-cms-client";
|
|
1789
|
+
}
|
|
1790
|
+
if (!result.modifiedBy || typeof result.modifiedBy !== "string") {
|
|
1791
|
+
result.modifiedBy = "root-cms-client";
|
|
1792
|
+
}
|
|
1793
|
+
const optionalStringFields = ["firstPublishedBy", "publishedBy"];
|
|
1794
|
+
for (const field of optionalStringFields) {
|
|
1795
|
+
if (isDef(sys[field])) {
|
|
1796
|
+
if (typeof sys[field] !== "string") {
|
|
1797
|
+
throw new Error(
|
|
1798
|
+
`Invalid sys.${field}: expected string, got ${typeof sys[field]}`
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
if (isDef(sys.publishingLocked)) {
|
|
1804
|
+
if (typeof sys.publishingLocked !== "object") {
|
|
1805
|
+
throw new Error("Invalid sys.publishingLocked: expected object or null");
|
|
1806
|
+
}
|
|
1807
|
+
if (isDef(sys.publishingLocked.until)) {
|
|
1808
|
+
result.publishingLocked = {
|
|
1809
|
+
...sys.publishingLocked,
|
|
1810
|
+
until: convertToTimestamp(
|
|
1811
|
+
sys.publishingLocked.until,
|
|
1812
|
+
"sys.publishingLocked.until"
|
|
1813
|
+
)
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
if (isDef(result.locales)) {
|
|
1818
|
+
if (!Array.isArray(result.locales)) {
|
|
1819
|
+
throw new Error("Invalid sys.locales: expected array");
|
|
1820
|
+
}
|
|
1821
|
+
if (!result.locales.every((locale) => typeof locale === "string")) {
|
|
1822
|
+
throw new Error("Invalid sys.locales: all items must be strings");
|
|
1823
|
+
}
|
|
1824
|
+
} else {
|
|
1825
|
+
result.locales = ["en"];
|
|
1826
|
+
}
|
|
1827
|
+
return result;
|
|
1828
|
+
}
|
|
1642
1829
|
function normalizeData(data) {
|
|
1643
1830
|
return unmarshalData(data);
|
|
1644
1831
|
}
|
|
@@ -1713,7 +1900,7 @@ function parseDocId(docId) {
|
|
|
1713
1900
|
throw new Error(`invalid doc id: ${docId}`);
|
|
1714
1901
|
}
|
|
1715
1902
|
const collection = docId.slice(0, sepIndex);
|
|
1716
|
-
const slug = docId.slice(sepIndex + 1)
|
|
1903
|
+
const slug = normalizeSlug(docId.slice(sepIndex + 1));
|
|
1717
1904
|
if (!collection || !slug) {
|
|
1718
1905
|
throw new Error(`invalid doc id: ${docId}`);
|
|
1719
1906
|
}
|
|
@@ -1925,6 +2112,7 @@ var BatchResponse = class {
|
|
|
1925
2112
|
};
|
|
1926
2113
|
|
|
1927
2114
|
export {
|
|
2115
|
+
normalizeSlug,
|
|
1928
2116
|
TranslationsManager,
|
|
1929
2117
|
buildTranslationsDbPath,
|
|
1930
2118
|
buildTranslationsLocaleDocDbPath,
|
package/dist/cli.js
CHANGED
|
@@ -128,6 +128,11 @@ type CMSPluginOptions = {
|
|
|
128
128
|
* URL for a custom favicon used by the CMS UI.
|
|
129
129
|
*/
|
|
130
130
|
favicon?: string;
|
|
131
|
+
/**
|
|
132
|
+
* Enables minimal branding mode in the CMS header. This hides the Root CMS
|
|
133
|
+
* logo and displays the project name on the top-right.
|
|
134
|
+
*/
|
|
135
|
+
minimalBranding?: boolean;
|
|
131
136
|
/**
|
|
132
137
|
* Callback when an action occurs.
|
|
133
138
|
*/
|
|
@@ -539,6 +544,10 @@ declare class RootCMSClient {
|
|
|
539
544
|
readonly app: App;
|
|
540
545
|
readonly db: Firestore;
|
|
541
546
|
constructor(rootConfig: RootConfig);
|
|
547
|
+
/**
|
|
548
|
+
* Converts a doc mode to the Firestore collection name.
|
|
549
|
+
*/
|
|
550
|
+
private getModeCollection;
|
|
542
551
|
/**
|
|
543
552
|
* Retrieves doc data from Root.js CMS.
|
|
544
553
|
*/
|
|
@@ -591,8 +600,83 @@ declare class RootCMSClient {
|
|
|
591
600
|
*/
|
|
592
601
|
updateDraftData(docId: string, path: string, fieldValue: any, options?: UpdateDraftOptions): Promise<void>;
|
|
593
602
|
/**
|
|
594
|
-
*
|
|
595
|
-
*
|
|
603
|
+
* Sets the raw document data directly in Firestore.
|
|
604
|
+
*
|
|
605
|
+
* CAUTION Prefer using `saveDraftData('Pages/foo', data)` in most cases.
|
|
606
|
+
* Only use this method if you need to manipulate system-level (sys) fields
|
|
607
|
+
* directly or if you're implementing low-level data operations.
|
|
608
|
+
*
|
|
609
|
+
* ## Validation & Normalization
|
|
610
|
+
*
|
|
611
|
+
* This method automatically validates and normalizes `sys` fields to prevent
|
|
612
|
+
* data integrity issues that can cause runtime errors like
|
|
613
|
+
* "e.toMillis is not a function".
|
|
614
|
+
*
|
|
615
|
+
* ### Timestamp Fields (auto-converted)
|
|
616
|
+
* The following fields accept multiple formats and are automatically converted
|
|
617
|
+
* to Firestore Timestamp objects:
|
|
618
|
+
* - `sys.createdAt`
|
|
619
|
+
* - `sys.modifiedAt`
|
|
620
|
+
* - `sys.publishedAt`
|
|
621
|
+
* - `sys.firstPublishedAt`
|
|
622
|
+
*
|
|
623
|
+
* Accepted formats:
|
|
624
|
+
* - Firestore `Timestamp` object (unchanged)
|
|
625
|
+
* - `number` - Interpreted as milliseconds since epoch, converted to Timestamp
|
|
626
|
+
* - `Date` object - Converted to Timestamp
|
|
627
|
+
*
|
|
628
|
+
* ### Required Fields (auto-populated with defaults if missing)
|
|
629
|
+
* - `sys.createdAt` - Defaults to current time if not provided
|
|
630
|
+
* - `sys.modifiedAt` - Defaults to current time if not provided
|
|
631
|
+
* - `sys.createdBy` - Defaults to 'root-cms-client' if not provided
|
|
632
|
+
* - `sys.modifiedBy` - Defaults to 'root-cms-client' if not provided
|
|
633
|
+
* - `sys.locales` - Defaults to ['en'] if not provided
|
|
634
|
+
*
|
|
635
|
+
* ### Optional Fields (validated if present)
|
|
636
|
+
* - `sys.publishedBy` - String identifier
|
|
637
|
+
* - `sys.firstPublishedBy` - String identifier
|
|
638
|
+
* - `sys.publishingLocked` - Object with optional `until` Timestamp
|
|
639
|
+
*
|
|
640
|
+
* ### Document Identity
|
|
641
|
+
* The `id`, `collection`, and `slug` fields are always set to match the
|
|
642
|
+
* provided parameters, overwriting any existing values to prevent data
|
|
643
|
+
* inconsistencies.
|
|
644
|
+
*
|
|
645
|
+
* @param collectionId - The collection ID (e.g., 'Pages')
|
|
646
|
+
* @param slug - The document slug (e.g., 'home')
|
|
647
|
+
* @param data - The complete document data including sys and fields
|
|
648
|
+
* @param options - Options specifying mode ('draft' or 'published')
|
|
649
|
+
*
|
|
650
|
+
* @throws {Error} If sys fields are invalid or missing required fields
|
|
651
|
+
* @throws {Error} If timestamp fields have invalid types
|
|
652
|
+
*
|
|
653
|
+
* @example
|
|
654
|
+
* ```typescript
|
|
655
|
+
* // Minimal example - sys fields use defaults
|
|
656
|
+
* await client.setRawDoc('Pages', 'home', {
|
|
657
|
+
* sys: {}, // All sys fields will be auto-populated with defaults
|
|
658
|
+
* fields: {
|
|
659
|
+
* title: 'Home Page'
|
|
660
|
+
* }
|
|
661
|
+
* }, { mode: 'draft' });
|
|
662
|
+
*
|
|
663
|
+
* // Full example - with number timestamps (auto-converted)
|
|
664
|
+
* await client.setRawDoc('Pages', 'home', {
|
|
665
|
+
* id: 'Pages/home',
|
|
666
|
+
* collection: 'Pages',
|
|
667
|
+
* slug: 'home',
|
|
668
|
+
* sys: {
|
|
669
|
+
* createdAt: Date.now(), // Auto-converted to Timestamp.
|
|
670
|
+
* createdBy: 'user@example.com',
|
|
671
|
+
* modifiedAt: Date.now(), // Auto-converted to Timestamp.
|
|
672
|
+
* modifiedBy: 'user@example.com',
|
|
673
|
+
* locales: ['en', 'es']
|
|
674
|
+
* },
|
|
675
|
+
* fields: {
|
|
676
|
+
* title: 'Home Page'
|
|
677
|
+
* }
|
|
678
|
+
* }, { mode: 'draft' });
|
|
679
|
+
* ```
|
|
596
680
|
*/
|
|
597
681
|
setRawDoc(collectionId: string, slug: string, data: any, options: SetDocOptions): Promise<void>;
|
|
598
682
|
/**
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '@blinkk/root';
|
|
2
2
|
import 'firebase-admin/app';
|
|
3
3
|
import 'firebase-admin/firestore';
|
|
4
|
-
export { A as Action, q as ArrayObject, C as BatchRequest, B as BatchRequestOptions, x as BatchRequestQuery, y as BatchRequestQueryOptions, E as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, D as DocMode, i as GetCountOptions, G as GetDocOptions, H as HttpMethod, l as ListActionsOptions, h as ListDocsOptions, L as LoadTranslationsOptions, a as LocaleTranslations, k as Release, R as RootCMSClient, f as SaveDraftOptions, S as SetDocOptions, j as Translation, z as TranslationsDoc, T as TranslationsMap, g as UpdateDraftOptions, U as UserRole, n as getCmsPlugin, m as isRichTextData, r as marshalArray, o as marshalData, p as normalizeData, w as parseDocId, t as toArrayObject, v as translationsForLocale, s as unmarshalArray, u as unmarshalData } from './client-
|
|
4
|
+
export { A as Action, q as ArrayObject, C as BatchRequest, B as BatchRequestOptions, x as BatchRequestQuery, y as BatchRequestQueryOptions, E as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, D as DocMode, i as GetCountOptions, G as GetDocOptions, H as HttpMethod, l as ListActionsOptions, h as ListDocsOptions, L as LoadTranslationsOptions, a as LocaleTranslations, k as Release, R as RootCMSClient, f as SaveDraftOptions, S as SetDocOptions, j as Translation, z as TranslationsDoc, T as TranslationsMap, g as UpdateDraftOptions, U as UserRole, n as getCmsPlugin, m as isRichTextData, r as marshalArray, o as marshalData, p as normalizeData, w as parseDocId, t as toArrayObject, v as translationsForLocale, s as unmarshalArray, u as unmarshalData } from './client-C1pZQL7M.js';
|
|
5
5
|
import './schema-BKfPP_s9.js';
|
package/dist/client.js
CHANGED
package/dist/core.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RootCMSClient, D as DocMode, L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslations } from './client-
|
|
2
|
-
export { A as Action, q as ArrayObject, C as BatchRequest, B as BatchRequestOptions, x as BatchRequestQuery, y as BatchRequestQueryOptions, E as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, i as GetCountOptions, G as GetDocOptions, H as HttpMethod, l as ListActionsOptions, h as ListDocsOptions, F as Locale, O as MultiLocaleTranslationsMap, k as Release, f as SaveDraftOptions, S as SetDocOptions, P as SingleLocaleTranslationsMap, I as SourceString, J as TranslatedString, j as Translation, z as TranslationsDoc, K as TranslationsDocMode, N as TranslationsLocaleDocEntry, M as TranslationsLocaleDocHashMap, Q as TranslationsManager, g as UpdateDraftOptions, U as UserRole, V as buildTranslationsDbPath, W as buildTranslationsLocaleDocDbPath, n as getCmsPlugin, m as isRichTextData, r as marshalArray, o as marshalData, p as normalizeData, w as parseDocId, t as toArrayObject, v as translationsForLocale, s as unmarshalArray, u as unmarshalData } from './client-
|
|
1
|
+
import { R as RootCMSClient, D as DocMode, L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslations } from './client-C1pZQL7M.js';
|
|
2
|
+
export { A as Action, q as ArrayObject, C as BatchRequest, B as BatchRequestOptions, x as BatchRequestQuery, y as BatchRequestQueryOptions, E as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, i as GetCountOptions, G as GetDocOptions, H as HttpMethod, l as ListActionsOptions, h as ListDocsOptions, F as Locale, O as MultiLocaleTranslationsMap, k as Release, f as SaveDraftOptions, S as SetDocOptions, P as SingleLocaleTranslationsMap, I as SourceString, J as TranslatedString, j as Translation, z as TranslationsDoc, K as TranslationsDocMode, N as TranslationsLocaleDocEntry, M as TranslationsLocaleDocHashMap, Q as TranslationsManager, g as UpdateDraftOptions, U as UserRole, V as buildTranslationsDbPath, W as buildTranslationsLocaleDocDbPath, n as getCmsPlugin, m as isRichTextData, r as marshalArray, o as marshalData, p as normalizeData, w as parseDocId, t as toArrayObject, v as translationsForLocale, s as unmarshalArray, u as unmarshalData } from './client-C1pZQL7M.js';
|
|
3
3
|
import { Request, RootConfig, Response, RouteParams, GetStaticProps, GetStaticPaths } from '@blinkk/root';
|
|
4
4
|
import { Query } from 'firebase-admin/firestore';
|
|
5
5
|
export { s as schema } from './schema-BKfPP_s9.js';
|
package/dist/core.js
CHANGED
|
@@ -10,12 +10,13 @@ import {
|
|
|
10
10
|
marshalArray,
|
|
11
11
|
marshalData,
|
|
12
12
|
normalizeData,
|
|
13
|
+
normalizeSlug,
|
|
13
14
|
parseDocId,
|
|
14
15
|
toArrayObject,
|
|
15
16
|
translationsForLocale,
|
|
16
17
|
unmarshalArray,
|
|
17
18
|
unmarshalData
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-XMR3KFP5.js";
|
|
19
20
|
import {
|
|
20
21
|
__export
|
|
21
22
|
} from "./chunk-MLKGABMK.js";
|
|
@@ -48,7 +49,7 @@ function createRoute(options) {
|
|
|
48
49
|
const { slug, mode } = routeContext;
|
|
49
50
|
const translationsTags = [
|
|
50
51
|
"common",
|
|
51
|
-
`${options.collection}/${slug
|
|
52
|
+
`${options.collection}/${normalizeSlug(slug)}`
|
|
52
53
|
];
|
|
53
54
|
if (options.translations) {
|
|
54
55
|
const tags = options.translations(routeContext)?.tags || [];
|
|
@@ -102,7 +103,7 @@ function createRoute(options) {
|
|
|
102
103
|
};
|
|
103
104
|
const translationsTags = [
|
|
104
105
|
"common",
|
|
105
|
-
`${options.collection}/${slug
|
|
106
|
+
`${options.collection}/${normalizeSlug(slug)}`
|
|
106
107
|
];
|
|
107
108
|
if (options.translations) {
|
|
108
109
|
const tags = options.translations(routeContext)?.tags || [];
|
|
@@ -311,7 +312,7 @@ async function getDoc(rootConfig, collectionId, slug, options) {
|
|
|
311
312
|
const mode = options.mode;
|
|
312
313
|
const modeCollection = mode === "draft" ? "Drafts" : "Published";
|
|
313
314
|
const db = cmsPlugin.getFirestore();
|
|
314
|
-
slug = slug
|
|
315
|
+
slug = normalizeSlug(slug);
|
|
315
316
|
const dbPath = `Projects/${projectId}/Collections/${collectionId}/${modeCollection}/${slug}`;
|
|
316
317
|
const docRef = db.doc(dbPath);
|
|
317
318
|
const doc = await docRef.get();
|
package/dist/functions.js
CHANGED
package/dist/plugin.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '@blinkk/root';
|
|
2
2
|
import 'firebase-admin/app';
|
|
3
3
|
import 'firebase-admin/firestore';
|
|
4
|
-
export { Z as CMSAIConfig, X as CMSBuiltInSidebarTool, a0 as CMSPlugin, $ as CMSPluginOptions, _ as CMSSidebarTool, Y as CMSUser, a1 as cmsPlugin } from './client-
|
|
4
|
+
export { Z as CMSAIConfig, X as CMSBuiltInSidebarTool, a0 as CMSPlugin, $ as CMSPluginOptions, _ as CMSSidebarTool, Y as CMSUser, a1 as cmsPlugin } from './client-C1pZQL7M.js';
|
|
5
5
|
import './schema-BKfPP_s9.js';
|
package/dist/plugin.js
CHANGED
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
} from "./chunk-T5UK2H24.js";
|
|
5
5
|
import {
|
|
6
6
|
getServerVersion
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WVOTD7EW.js";
|
|
8
8
|
import {
|
|
9
9
|
runCronJobs
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-YAQCD6SS.js";
|
|
11
11
|
import {
|
|
12
12
|
RootCMSClient,
|
|
13
13
|
parseDocId,
|
|
14
14
|
unmarshalData
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XMR3KFP5.js";
|
|
16
16
|
import "./chunk-MLKGABMK.js";
|
|
17
17
|
|
|
18
18
|
// core/plugin.ts
|
|
@@ -892,7 +892,7 @@ function cmsPlugin(options) {
|
|
|
892
892
|
if (process.env.NODE_ENV === "development" && options.watch !== false) {
|
|
893
893
|
plugin.onFileChange = (eventName, filepath) => {
|
|
894
894
|
if (filepath.endsWith(".schema.ts")) {
|
|
895
|
-
import("./generate-types-
|
|
895
|
+
import("./generate-types-MHWSSOWV.js").then((generateTypesModule) => {
|
|
896
896
|
const generateTypes = generateTypesModule.generateTypes;
|
|
897
897
|
generateTypes();
|
|
898
898
|
});
|