@blinkk/root-cms 2.5.1 → 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/app.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getServerVersion
3
- } from "./chunk-KTUENARU.js";
3
+ } from "./chunk-QR62WMN3.js";
4
4
  import {
5
5
  getCollectionSchema,
6
6
  getProjectSchemas
7
- } from "./chunk-RNDSZKAW.js";
7
+ } from "./chunk-MSJGHSR6.js";
8
8
  import "./chunk-MLKGABMK.js";
9
9
 
10
10
  // core/app.tsx
@@ -13,7 +13,7 @@ async function generateTypes() {
13
13
  rootConfig,
14
14
  modulePath
15
15
  );
16
- const schemas = await project.getProjectSchemas();
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
- async function getProjectSchemas() {
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
- async function getCollectionSchema(collectionId) {
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.1",
4
+ version: "2.5.2",
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.1",
169
+ "@blinkk/root": "2.5.2",
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.replaceAll("/", "--")).replace("{locale}", options.locale);
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
- const mode = options.mode;
694
- const modeCollection = mode === "draft" ? "Drafts" : "Published";
695
- slug = slug.replaceAll("/", "--");
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.replaceAll("/", "--");
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
- * Prefer `saveDraftData('Pages/foo', data)`. Only use this if you know what
805
- * you're doing.
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
- const mode = options.mode;
809
- const modeCollection = mode === "draft" ? "Drafts" : "Published";
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
- const mode = options.mode;
819
- const modeCollection = mode === "draft" ? "Drafts" : "Published";
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
- const mode = options.mode;
852
- const modeCollection = mode === "draft" ? "Drafts" : "Published";
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.replaceAll("/", "--");
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).replaceAll("/", "--");
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,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RootCMSClient,
3
3
  getCmsPlugin
4
- } from "./chunk-NUUABQRN.js";
4
+ } from "./chunk-XMR3KFP5.js";
5
5
 
6
6
  // core/versions.ts
7
7
  import path from "path";
package/dist/cli.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  generateTypes
3
- } from "./chunk-RYF3UTHQ.js";
3
+ } from "./chunk-KDXHFMIH.js";
4
4
  import {
5
5
  getCmsPlugin
6
- } from "./chunk-NUUABQRN.js";
6
+ } from "./chunk-XMR3KFP5.js";
7
7
  import "./chunk-MLKGABMK.js";
8
8
 
9
9
  // cli/cli.ts
@@ -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
- * Prefer `saveDraftData('Pages/foo', data)`. Only use this if you know what
595
- * you're doing.
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
  /**
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-ROwBDNeR.js';
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
5
  import './schema-BKfPP_s9.js';
package/dist/client.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  translationsForLocale,
13
13
  unmarshalArray,
14
14
  unmarshalData
15
- } from "./chunk-NUUABQRN.js";
15
+ } from "./chunk-XMR3KFP5.js";
16
16
  import "./chunk-MLKGABMK.js";
17
17
  export {
18
18
  BatchRequest,
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-ROwBDNeR.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-ROwBDNeR.js';
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
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-NUUABQRN.js";
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.replaceAll("/", "--")}`
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.replaceAll("/", "--")}`
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.replaceAll("/", "--");
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
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  runCronJobs
3
- } from "./chunk-RIJF2AHU.js";
4
- import "./chunk-NUUABQRN.js";
3
+ } from "./chunk-YAQCD6SS.js";
4
+ import "./chunk-XMR3KFP5.js";
5
5
  import "./chunk-MLKGABMK.js";
6
6
 
7
7
  // core/functions.ts
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  generateSchemaDts,
3
3
  generateTypes
4
- } from "./chunk-RYF3UTHQ.js";
4
+ } from "./chunk-KDXHFMIH.js";
5
5
  import "./chunk-MLKGABMK.js";
6
6
  export {
7
7
  generateSchemaDts,
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-ROwBDNeR.js';
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
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-KTUENARU.js";
7
+ } from "./chunk-QR62WMN3.js";
8
8
  import {
9
9
  runCronJobs
10
- } from "./chunk-RIJF2AHU.js";
10
+ } from "./chunk-YAQCD6SS.js";
11
11
  import {
12
12
  RootCMSClient,
13
13
  parseDocId,
14
14
  unmarshalData
15
- } from "./chunk-NUUABQRN.js";
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-TQBCE2SG.js").then((generateTypesModule) => {
895
+ import("./generate-types-MHWSSOWV.js").then((generateTypesModule) => {
896
896
  const generateTypes = generateTypesModule.generateTypes;
897
897
  generateTypes();
898
898
  });
package/dist/project.d.ts CHANGED
@@ -16,11 +16,16 @@ declare const SCHEMA_MODULES: Record<string, SchemaModule>;
16
16
  * fileId => schema. This is used by `generate-types.ts` to build the
17
17
  * `root-cms.d.ts` file.
18
18
  */
19
- declare function getProjectSchemas(): Promise<Record<string, Schema>>;
19
+ declare function getProjectSchemas(): Record<string, Schema>;
20
+ /**
21
+ * Resolves SchemaPattern objects in oneOf fields to arrays of Schema objects.
22
+ * This is needed for type generation which expects `field.types` to be an array.
23
+ */
24
+ declare function resolveOneOfPatterns(schemaObj: Schema): Schema;
20
25
  /**
21
26
  * Returns a collection's schema definition as defined in
22
27
  * `/collections/<id>.schema.ts`.
23
28
  */
24
- declare function getCollectionSchema(collectionId: string): Promise<Collection | null>;
29
+ declare function getCollectionSchema(collectionId: string): Collection | null;
25
30
 
26
- export { SCHEMA_MODULES, type SchemaModule, getCollectionSchema, getProjectSchemas };
31
+ export { SCHEMA_MODULES, type SchemaModule, getCollectionSchema, getProjectSchemas, resolveOneOfPatterns };
package/dist/project.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  SCHEMA_MODULES,
3
3
  getCollectionSchema,
4
- getProjectSchemas
5
- } from "./chunk-RNDSZKAW.js";
4
+ getProjectSchemas,
5
+ resolveOneOfPatterns
6
+ } from "./chunk-MSJGHSR6.js";
6
7
  import "./chunk-MLKGABMK.js";
7
8
  export {
8
9
  SCHEMA_MODULES,
9
10
  getCollectionSchema,
10
- getProjectSchemas
11
+ getProjectSchemas,
12
+ resolveOneOfPatterns
11
13
  };