@blinkk/root-cms 2.4.10 → 2.5.2
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/ai-OZY3JXDH.js +19 -0
- package/dist/app.js +2 -2
- package/dist/{chunk-RYF3UTHQ.js → chunk-KDXHFMIH.js} +3 -3
- package/dist/chunk-MSJGHSR6.js +172 -0
- package/dist/{chunk-Y65VGJLE.js → chunk-QR62WMN3.js} +2 -2
- package/dist/{chunk-ZOEPOKGE.js → chunk-T5UK2H24.js} +131 -6
- package/dist/{chunk-62EVNFXB.js → chunk-XMR3KFP5.js} +264 -15
- package/dist/{chunk-SI44FG3H.js → chunk-YAQCD6SS.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{client-PhodvL2Q.d.ts → client-BZ03biQh.d.ts} +89 -3
- package/dist/client.d.ts +2 -2
- package/dist/client.js +1 -1
- package/dist/core.d.ts +3 -3
- package/dist/core.js +14 -4
- package/dist/functions.js +2 -2
- package/dist/{generate-types-TQBCE2SG.js → generate-types-MHWSSOWV.js} +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.js +84 -6
- package/dist/project.d.ts +9 -4
- package/dist/project.js +5 -3
- package/dist/{schema-Bux4PrV2.d.ts → schema-BKfPP_s9.d.ts} +78 -2
- package/dist/ui/ui.css +1 -1
- package/dist/ui/ui.js +153 -153
- package/dist/ui/ui.js.LEGAL.txt +16 -12
- package/package.json +3 -3
- package/dist/ai-DRQJXU4N.js +0 -13
- package/dist/chunk-377TGNX2.js +0 -82
|
@@ -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) {
|
|
@@ -964,6 +1070,67 @@ ${errorMessages}`);
|
|
|
964
1070
|
console.log(`published ${publishedDocs.length} docs!`);
|
|
965
1071
|
return publishedDocs;
|
|
966
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Batch unpublishes a set of docs by id.
|
|
1075
|
+
*/
|
|
1076
|
+
async unpublishDocs(docIds, options) {
|
|
1077
|
+
const projectCollectionsPath = `Projects/${this.projectId}/Collections`;
|
|
1078
|
+
const unpublishedBy = options?.unpublishedBy || "root-cms-client";
|
|
1079
|
+
const docRefs = docIds.map((docId) => {
|
|
1080
|
+
const [collection, slug] = docId.split("/");
|
|
1081
|
+
if (!collection || !slug) {
|
|
1082
|
+
throw new Error(`invalid doc id: ${docId}`);
|
|
1083
|
+
}
|
|
1084
|
+
const docRef = this.db.doc(
|
|
1085
|
+
`${projectCollectionsPath}/${collection}/Drafts/${slug}`
|
|
1086
|
+
);
|
|
1087
|
+
return docRef;
|
|
1088
|
+
});
|
|
1089
|
+
const docSnapshots = await this.db.getAll(...docRefs);
|
|
1090
|
+
const docs = docSnapshots.map((snapshot) => snapshot.data()).filter((d) => !!d);
|
|
1091
|
+
if (docs.length === 0) {
|
|
1092
|
+
console.log("no docs to unpublish");
|
|
1093
|
+
return [];
|
|
1094
|
+
}
|
|
1095
|
+
let batchCount = 0;
|
|
1096
|
+
const batch = options?.batch || this.db.batch();
|
|
1097
|
+
const unpublishedDocs = [];
|
|
1098
|
+
for (const doc of docs) {
|
|
1099
|
+
const { id, collection, slug } = doc;
|
|
1100
|
+
const draftRef = this.db.doc(
|
|
1101
|
+
`${projectCollectionsPath}/${collection}/Drafts/${slug}`
|
|
1102
|
+
);
|
|
1103
|
+
const scheduledRef = this.db.doc(
|
|
1104
|
+
`${projectCollectionsPath}/${collection}/Scheduled/${slug}`
|
|
1105
|
+
);
|
|
1106
|
+
const publishedRef = this.db.doc(
|
|
1107
|
+
`${projectCollectionsPath}/${collection}/Published/${slug}`
|
|
1108
|
+
);
|
|
1109
|
+
batch.update(draftRef, {
|
|
1110
|
+
"sys.modifiedAt": FieldValue2.serverTimestamp(),
|
|
1111
|
+
"sys.modifiedBy": unpublishedBy,
|
|
1112
|
+
"sys.publishedAt": FieldValue2.delete(),
|
|
1113
|
+
"sys.publishedBy": FieldValue2.delete(),
|
|
1114
|
+
"sys.firstPublishedAt": FieldValue2.delete(),
|
|
1115
|
+
"sys.firstPublishedBy": FieldValue2.delete()
|
|
1116
|
+
});
|
|
1117
|
+
batchCount += 1;
|
|
1118
|
+
batch.delete(scheduledRef);
|
|
1119
|
+
batchCount += 1;
|
|
1120
|
+
batch.delete(publishedRef);
|
|
1121
|
+
batchCount += 1;
|
|
1122
|
+
unpublishedDocs.push(doc);
|
|
1123
|
+
if (batchCount >= 400) {
|
|
1124
|
+
await batch.commit();
|
|
1125
|
+
batchCount = 0;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
if (batchCount > 0) {
|
|
1129
|
+
await batch.commit();
|
|
1130
|
+
}
|
|
1131
|
+
console.log(`unpublished ${unpublishedDocs.length} docs!`);
|
|
1132
|
+
return unpublishedDocs;
|
|
1133
|
+
}
|
|
967
1134
|
/**
|
|
968
1135
|
* Publishes scheduled docs.
|
|
969
1136
|
*/
|
|
@@ -1234,7 +1401,7 @@ ${errorMessages}`);
|
|
|
1234
1401
|
if (!(mode === "draft" || mode === "published")) {
|
|
1235
1402
|
throw new Error(`invalid mode: ${mode}`);
|
|
1236
1403
|
}
|
|
1237
|
-
const slug = translationsId
|
|
1404
|
+
const slug = normalizeSlug(translationsId);
|
|
1238
1405
|
const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
|
|
1239
1406
|
return dbPath;
|
|
1240
1407
|
}
|
|
@@ -1578,6 +1745,87 @@ function unmarshalData(data) {
|
|
|
1578
1745
|
}
|
|
1579
1746
|
return result;
|
|
1580
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
|
+
}
|
|
1581
1829
|
function normalizeData(data) {
|
|
1582
1830
|
return unmarshalData(data);
|
|
1583
1831
|
}
|
|
@@ -1652,7 +1900,7 @@ function parseDocId(docId) {
|
|
|
1652
1900
|
throw new Error(`invalid doc id: ${docId}`);
|
|
1653
1901
|
}
|
|
1654
1902
|
const collection = docId.slice(0, sepIndex);
|
|
1655
|
-
const slug = docId.slice(sepIndex + 1)
|
|
1903
|
+
const slug = normalizeSlug(docId.slice(sepIndex + 1));
|
|
1656
1904
|
if (!collection || !slug) {
|
|
1657
1905
|
throw new Error(`invalid doc id: ${docId}`);
|
|
1658
1906
|
}
|
|
@@ -1864,6 +2112,7 @@ var BatchResponse = class {
|
|
|
1864
2112
|
};
|
|
1865
2113
|
|
|
1866
2114
|
export {
|
|
2115
|
+
normalizeSlug,
|
|
1867
2116
|
TranslationsManager,
|
|
1868
2117
|
buildTranslationsDbPath,
|
|
1869
2118
|
buildTranslationsLocaleDocDbPath,
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Plugin, Request, RootConfig } from '@blinkk/root';
|
|
2
2
|
import { App } from 'firebase-admin/app';
|
|
3
3
|
import { Firestore, WriteBatch, Timestamp, Query } from 'firebase-admin/firestore';
|
|
4
|
-
import { C as Collection } from './schema-
|
|
4
|
+
import { C as Collection } from './schema-BKfPP_s9.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Supported Root AI models. Defaults to 'gemini-3-flash-preview'.
|
|
@@ -539,6 +539,10 @@ declare class RootCMSClient {
|
|
|
539
539
|
readonly app: App;
|
|
540
540
|
readonly db: Firestore;
|
|
541
541
|
constructor(rootConfig: RootConfig);
|
|
542
|
+
/**
|
|
543
|
+
* Converts a doc mode to the Firestore collection name.
|
|
544
|
+
*/
|
|
545
|
+
private getModeCollection;
|
|
542
546
|
/**
|
|
543
547
|
* Retrieves doc data from Root.js CMS.
|
|
544
548
|
*/
|
|
@@ -591,8 +595,83 @@ declare class RootCMSClient {
|
|
|
591
595
|
*/
|
|
592
596
|
updateDraftData(docId: string, path: string, fieldValue: any, options?: UpdateDraftOptions): Promise<void>;
|
|
593
597
|
/**
|
|
594
|
-
*
|
|
595
|
-
*
|
|
598
|
+
* Sets the raw document data directly in Firestore.
|
|
599
|
+
*
|
|
600
|
+
* CAUTION Prefer using `saveDraftData('Pages/foo', data)` in most cases.
|
|
601
|
+
* Only use this method if you need to manipulate system-level (sys) fields
|
|
602
|
+
* directly or if you're implementing low-level data operations.
|
|
603
|
+
*
|
|
604
|
+
* ## Validation & Normalization
|
|
605
|
+
*
|
|
606
|
+
* This method automatically validates and normalizes `sys` fields to prevent
|
|
607
|
+
* data integrity issues that can cause runtime errors like
|
|
608
|
+
* "e.toMillis is not a function".
|
|
609
|
+
*
|
|
610
|
+
* ### Timestamp Fields (auto-converted)
|
|
611
|
+
* The following fields accept multiple formats and are automatically converted
|
|
612
|
+
* to Firestore Timestamp objects:
|
|
613
|
+
* - `sys.createdAt`
|
|
614
|
+
* - `sys.modifiedAt`
|
|
615
|
+
* - `sys.publishedAt`
|
|
616
|
+
* - `sys.firstPublishedAt`
|
|
617
|
+
*
|
|
618
|
+
* Accepted formats:
|
|
619
|
+
* - Firestore `Timestamp` object (unchanged)
|
|
620
|
+
* - `number` - Interpreted as milliseconds since epoch, converted to Timestamp
|
|
621
|
+
* - `Date` object - Converted to Timestamp
|
|
622
|
+
*
|
|
623
|
+
* ### Required Fields (auto-populated with defaults if missing)
|
|
624
|
+
* - `sys.createdAt` - Defaults to current time if not provided
|
|
625
|
+
* - `sys.modifiedAt` - Defaults to current time if not provided
|
|
626
|
+
* - `sys.createdBy` - Defaults to 'root-cms-client' if not provided
|
|
627
|
+
* - `sys.modifiedBy` - Defaults to 'root-cms-client' if not provided
|
|
628
|
+
* - `sys.locales` - Defaults to ['en'] if not provided
|
|
629
|
+
*
|
|
630
|
+
* ### Optional Fields (validated if present)
|
|
631
|
+
* - `sys.publishedBy` - String identifier
|
|
632
|
+
* - `sys.firstPublishedBy` - String identifier
|
|
633
|
+
* - `sys.publishingLocked` - Object with optional `until` Timestamp
|
|
634
|
+
*
|
|
635
|
+
* ### Document Identity
|
|
636
|
+
* The `id`, `collection`, and `slug` fields are always set to match the
|
|
637
|
+
* provided parameters, overwriting any existing values to prevent data
|
|
638
|
+
* inconsistencies.
|
|
639
|
+
*
|
|
640
|
+
* @param collectionId - The collection ID (e.g., 'Pages')
|
|
641
|
+
* @param slug - The document slug (e.g., 'home')
|
|
642
|
+
* @param data - The complete document data including sys and fields
|
|
643
|
+
* @param options - Options specifying mode ('draft' or 'published')
|
|
644
|
+
*
|
|
645
|
+
* @throws {Error} If sys fields are invalid or missing required fields
|
|
646
|
+
* @throws {Error} If timestamp fields have invalid types
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```typescript
|
|
650
|
+
* // Minimal example - sys fields use defaults
|
|
651
|
+
* await client.setRawDoc('Pages', 'home', {
|
|
652
|
+
* sys: {}, // All sys fields will be auto-populated with defaults
|
|
653
|
+
* fields: {
|
|
654
|
+
* title: 'Home Page'
|
|
655
|
+
* }
|
|
656
|
+
* }, { mode: 'draft' });
|
|
657
|
+
*
|
|
658
|
+
* // Full example - with number timestamps (auto-converted)
|
|
659
|
+
* await client.setRawDoc('Pages', 'home', {
|
|
660
|
+
* id: 'Pages/home',
|
|
661
|
+
* collection: 'Pages',
|
|
662
|
+
* slug: 'home',
|
|
663
|
+
* sys: {
|
|
664
|
+
* createdAt: Date.now(), // Auto-converted to Timestamp.
|
|
665
|
+
* createdBy: 'user@example.com',
|
|
666
|
+
* modifiedAt: Date.now(), // Auto-converted to Timestamp.
|
|
667
|
+
* modifiedBy: 'user@example.com',
|
|
668
|
+
* locales: ['en', 'es']
|
|
669
|
+
* },
|
|
670
|
+
* fields: {
|
|
671
|
+
* title: 'Home Page'
|
|
672
|
+
* }
|
|
673
|
+
* }, { mode: 'draft' });
|
|
674
|
+
* ```
|
|
596
675
|
*/
|
|
597
676
|
setRawDoc(collectionId: string, slug: string, data: any, options: SetDocOptions): Promise<void>;
|
|
598
677
|
/**
|
|
@@ -613,6 +692,13 @@ declare class RootCMSClient {
|
|
|
613
692
|
batch?: WriteBatch;
|
|
614
693
|
releaseId?: string;
|
|
615
694
|
}): Promise<any[]>;
|
|
695
|
+
/**
|
|
696
|
+
* Batch unpublishes a set of docs by id.
|
|
697
|
+
*/
|
|
698
|
+
unpublishDocs(docIds: string[], options?: {
|
|
699
|
+
unpublishedBy?: string;
|
|
700
|
+
batch?: WriteBatch;
|
|
701
|
+
}): Promise<any[]>;
|
|
616
702
|
/**
|
|
617
703
|
* Publishes scheduled docs.
|
|
618
704
|
*/
|
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-
|
|
5
|
-
import './schema-
|
|
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-BZ03biQh.js';
|
|
5
|
+
import './schema-BKfPP_s9.js';
|
package/dist/client.js
CHANGED
package/dist/core.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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-BZ03biQh.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-BZ03biQh.js';
|
|
3
3
|
import { Request, RootConfig, Response, RouteParams, GetStaticProps, GetStaticPaths } from '@blinkk/root';
|
|
4
4
|
import { Query } from 'firebase-admin/firestore';
|
|
5
|
-
export { s as schema } from './schema-
|
|
5
|
+
export { s as schema } from './schema-BKfPP_s9.js';
|
|
6
6
|
import 'firebase-admin/app';
|
|
7
7
|
|
|
8
8
|
/**
|
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();
|
|
@@ -484,6 +485,7 @@ __export(schema_exports, {
|
|
|
484
485
|
defineCollection: () => defineCollection,
|
|
485
486
|
defineSchema: () => defineSchema,
|
|
486
487
|
file: () => file,
|
|
488
|
+
glob: () => glob,
|
|
487
489
|
image: () => image,
|
|
488
490
|
multiselect: () => multiselect,
|
|
489
491
|
number: () => number,
|
|
@@ -565,6 +567,14 @@ function defineCollection(collection2) {
|
|
|
565
567
|
return collection2;
|
|
566
568
|
}
|
|
567
569
|
var collection = defineCollection;
|
|
570
|
+
function glob(pattern, options) {
|
|
571
|
+
return {
|
|
572
|
+
_schemaPattern: true,
|
|
573
|
+
pattern,
|
|
574
|
+
exclude: options?.exclude,
|
|
575
|
+
omitFields: options?.omitFields
|
|
576
|
+
};
|
|
577
|
+
}
|
|
568
578
|
export {
|
|
569
579
|
BatchRequest,
|
|
570
580
|
BatchResponse,
|
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-
|
|
5
|
-
import './schema-
|
|
4
|
+
export { Z as CMSAIConfig, X as CMSBuiltInSidebarTool, a0 as CMSPlugin, $ as CMSPluginOptions, _ as CMSSidebarTool, Y as CMSUser, a1 as cmsPlugin } from './client-BZ03biQh.js';
|
|
5
|
+
import './schema-BKfPP_s9.js';
|