@407dev/cms-astro 0.1.0 → 0.2.0

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.
Files changed (145) hide show
  1. package/README.md +4 -4
  2. package/dist/{chunk-7E3XJLKX.js → chunk-SGHAANOW.js} +30 -3
  3. package/dist/chunk-SGHAANOW.js.map +1 -0
  4. package/dist/{chunk-QYUVAKMC.js → chunk-YCQMH2T7.js} +51 -10
  5. package/dist/chunk-YCQMH2T7.js.map +1 -0
  6. package/dist/fields/collections.js +1 -1
  7. package/dist/index.d.ts +8 -1
  8. package/dist/index.js +32 -31
  9. package/dist/index.js.map +1 -1
  10. package/dist/middleware/index.js +2 -2
  11. package/package.json +5 -5
  12. package/src/client.ts +0 -1
  13. package/src/fields/attrs.ts +4 -0
  14. package/src/fields/collection.ts +8 -0
  15. package/src/fields/entryScope.test.ts +22 -1
  16. package/src/fields/index.ts +10 -1
  17. package/src/index.test.ts +117 -1
  18. package/src/integration.ts +29 -7
  19. package/src/middleware/preview.test.ts +39 -7
  20. package/src/middleware/preview.ts +18 -4
  21. package/src/preview/bridge-script.test.ts +81 -2
  22. package/src/preview/bridge-script.ts +30 -1
  23. package/dist/chunk-53OQ5RXJ.js +0 -912
  24. package/dist/chunk-53OQ5RXJ.js.map +0 -1
  25. package/dist/chunk-56OMNQLH.js +0 -1013
  26. package/dist/chunk-56OMNQLH.js.map +0 -1
  27. package/dist/chunk-5AOOMQ7K.js +0 -1031
  28. package/dist/chunk-5AOOMQ7K.js.map +0 -1
  29. package/dist/chunk-5XRUCFDC.js +0 -743
  30. package/dist/chunk-5XRUCFDC.js.map +0 -1
  31. package/dist/chunk-62ZHCOLZ.js +0 -25
  32. package/dist/chunk-62ZHCOLZ.js.map +0 -1
  33. package/dist/chunk-6AZLRSYA.js +0 -126
  34. package/dist/chunk-6AZLRSYA.js.map +0 -1
  35. package/dist/chunk-6L3ZTCFB.js +0 -14
  36. package/dist/chunk-6L3ZTCFB.js.map +0 -1
  37. package/dist/chunk-6O7ZNNDT.js +0 -697
  38. package/dist/chunk-6O7ZNNDT.js.map +0 -1
  39. package/dist/chunk-6PQIXTMK.js +0 -697
  40. package/dist/chunk-6PQIXTMK.js.map +0 -1
  41. package/dist/chunk-7AW6M7QW.js +0 -1013
  42. package/dist/chunk-7AW6M7QW.js.map +0 -1
  43. package/dist/chunk-7E3XJLKX.js.map +0 -1
  44. package/dist/chunk-7LM54OTA.js +0 -1031
  45. package/dist/chunk-7LM54OTA.js.map +0 -1
  46. package/dist/chunk-A3OGL4OX.js +0 -706
  47. package/dist/chunk-A3OGL4OX.js.map +0 -1
  48. package/dist/chunk-AO4UAWOV.js +0 -1030
  49. package/dist/chunk-AO4UAWOV.js.map +0 -1
  50. package/dist/chunk-BDFVGXM2.js +0 -697
  51. package/dist/chunk-BDFVGXM2.js.map +0 -1
  52. package/dist/chunk-CXM7NZVX.js +0 -1031
  53. package/dist/chunk-CXM7NZVX.js.map +0 -1
  54. package/dist/chunk-DXJSYGS6.js +0 -743
  55. package/dist/chunk-DXJSYGS6.js.map +0 -1
  56. package/dist/chunk-EFUSAQZM.js +0 -72
  57. package/dist/chunk-EFUSAQZM.js.map +0 -1
  58. package/dist/chunk-F7KDGPBN.js +0 -1013
  59. package/dist/chunk-F7KDGPBN.js.map +0 -1
  60. package/dist/chunk-FBSQT45X.js +0 -126
  61. package/dist/chunk-FBSQT45X.js.map +0 -1
  62. package/dist/chunk-FEPDOMVH.js +0 -697
  63. package/dist/chunk-FEPDOMVH.js.map +0 -1
  64. package/dist/chunk-FQDOL2QW.js +0 -25
  65. package/dist/chunk-FQDOL2QW.js.map +0 -1
  66. package/dist/chunk-GB3LGQJM.js +0 -109
  67. package/dist/chunk-GB3LGQJM.js.map +0 -1
  68. package/dist/chunk-HCNP6R3P.js +0 -736
  69. package/dist/chunk-HCNP6R3P.js.map +0 -1
  70. package/dist/chunk-J6WEJDRI.js +0 -743
  71. package/dist/chunk-J6WEJDRI.js.map +0 -1
  72. package/dist/chunk-JHEAPNJ2.js +0 -117
  73. package/dist/chunk-JHEAPNJ2.js.map +0 -1
  74. package/dist/chunk-JOJDJ6GW.js +0 -25
  75. package/dist/chunk-JOJDJ6GW.js.map +0 -1
  76. package/dist/chunk-KTDV6WYB.js +0 -202
  77. package/dist/chunk-KTDV6WYB.js.map +0 -1
  78. package/dist/chunk-KZWJBKPC.js +0 -734
  79. package/dist/chunk-KZWJBKPC.js.map +0 -1
  80. package/dist/chunk-LEAQBGL6.js +0 -109
  81. package/dist/chunk-LEAQBGL6.js.map +0 -1
  82. package/dist/chunk-LGZJL2Q7.js +0 -697
  83. package/dist/chunk-LGZJL2Q7.js.map +0 -1
  84. package/dist/chunk-LQPBU46R.js +0 -109
  85. package/dist/chunk-LQPBU46R.js.map +0 -1
  86. package/dist/chunk-M55NNUTY.js +0 -1013
  87. package/dist/chunk-M55NNUTY.js.map +0 -1
  88. package/dist/chunk-M6NCYCC3.js +0 -1013
  89. package/dist/chunk-M6NCYCC3.js.map +0 -1
  90. package/dist/chunk-MGN7OZAU.js +0 -109
  91. package/dist/chunk-MGN7OZAU.js.map +0 -1
  92. package/dist/chunk-MGYZOX4K.js +0 -1013
  93. package/dist/chunk-MGYZOX4K.js.map +0 -1
  94. package/dist/chunk-MY4IEKJS.js +0 -1031
  95. package/dist/chunk-MY4IEKJS.js.map +0 -1
  96. package/dist/chunk-NCQRGAB4.js +0 -705
  97. package/dist/chunk-NCQRGAB4.js.map +0 -1
  98. package/dist/chunk-NI4NHXI4.js +0 -697
  99. package/dist/chunk-NI4NHXI4.js.map +0 -1
  100. package/dist/chunk-NPI5N7AU.js +0 -14
  101. package/dist/chunk-NPI5N7AU.js.map +0 -1
  102. package/dist/chunk-QN4CPMJF.js +0 -126
  103. package/dist/chunk-QN4CPMJF.js.map +0 -1
  104. package/dist/chunk-QYUVAKMC.js.map +0 -1
  105. package/dist/chunk-RAAT6PDT.js +0 -25
  106. package/dist/chunk-RAAT6PDT.js.map +0 -1
  107. package/dist/chunk-RDPO5VPS.js +0 -1013
  108. package/dist/chunk-RDPO5VPS.js.map +0 -1
  109. package/dist/chunk-RQHIW2PF.js +0 -25
  110. package/dist/chunk-RQHIW2PF.js.map +0 -1
  111. package/dist/chunk-RREVHA52.js +0 -722
  112. package/dist/chunk-RREVHA52.js.map +0 -1
  113. package/dist/chunk-S7PT4PZN.js +0 -25
  114. package/dist/chunk-S7PT4PZN.js.map +0 -1
  115. package/dist/chunk-SUXV5M32.js +0 -109
  116. package/dist/chunk-SUXV5M32.js.map +0 -1
  117. package/dist/chunk-SZEORUY6.js +0 -696
  118. package/dist/chunk-SZEORUY6.js.map +0 -1
  119. package/dist/chunk-T7NGGWGY.js +0 -25
  120. package/dist/chunk-T7NGGWGY.js.map +0 -1
  121. package/dist/chunk-UEVWP5VE.js +0 -696
  122. package/dist/chunk-UEVWP5VE.js.map +0 -1
  123. package/dist/chunk-UJNKNP7U.js +0 -748
  124. package/dist/chunk-UJNKNP7U.js.map +0 -1
  125. package/dist/chunk-V4XVFWFI.js +0 -1013
  126. package/dist/chunk-V4XVFWFI.js.map +0 -1
  127. package/dist/chunk-VJU2CIKZ.js +0 -729
  128. package/dist/chunk-VJU2CIKZ.js.map +0 -1
  129. package/dist/chunk-VRQUP5L3.js +0 -202
  130. package/dist/chunk-VRQUP5L3.js.map +0 -1
  131. package/dist/chunk-WBJ5E7CL.js +0 -742
  132. package/dist/chunk-WBJ5E7CL.js.map +0 -1
  133. package/dist/chunk-Y3Q65C7R.js +0 -14
  134. package/dist/chunk-Y3Q65C7R.js.map +0 -1
  135. package/dist/chunk-YHEGFPTR.js +0 -1030
  136. package/dist/chunk-YHEGFPTR.js.map +0 -1
  137. package/dist/chunk-ZDLBN46C.js +0 -697
  138. package/dist/chunk-ZDLBN46C.js.map +0 -1
  139. package/dist/preview-BEkLMD6N.d.ts +0 -23
  140. package/dist/preview-DJEA4fj7.d.ts +0 -23
  141. package/dist/preview-DeD1Jn7U.d.ts +0 -23
  142. package/dist/types-15jfCQKb.d.ts +0 -141
  143. package/dist/types-BREdL9Gx.d.ts +0 -140
  144. package/dist/types-C6sUZNa2.d.ts +0 -104
  145. package/dist/types-DpeHpobR.d.ts +0 -104
package/README.md CHANGED
@@ -6,13 +6,13 @@
6
6
 
7
7
  ## Surface
8
8
 
9
- - Declarative field helpers & scopes: [src/fields/index.ts](src/fields/index.ts) (`f`, `f.text`, `f.img`, `f.video`, `f.richText`, `f.number`, `f.toggle`, `f.select`, `f.videoList`, `f.geoArea`, `f.addressList`, `f.scope`, `f.entryScope`, `f.group`, `defineCollection`, `collectionPaths`)
9
+ - Declarative field helpers & scopes: [src/fields/index.ts](src/fields/index.ts) (`f`, `f.text`, `f.img`, `f.video`, `f.richText`, `f.number`, `f.toggle`, `f.select`, `f.videoList`, `f.geoArea`, `f.addressList`, `f.scope`, `f.entryScope`, `f.collectionAttrs`, `cmsCollectionAttr`, `f.group`, `defineCollection`, `collectionPaths`)
10
10
  - Collection factories (`@407dev/cms-astro/collections`): [src/fields/collections.ts](src/fields/collections.ts) (`defineEmailCampaignCollection`, `defineSmsCampaignCollection`)
11
11
  - Dynamic dual-callable helper generator derived from `@407dev/field-types`: [src/fields/helpers.ts](src/fields/helpers.ts)
12
12
  - Scope & key prefixing: [src/fields/scope.ts](src/fields/scope.ts)
13
13
  - Entry scoping: [src/fields/entryScope.ts](src/fields/entryScope.ts) (`f.entryScope`)
14
14
  - Group definition & accessor binding: [src/fields/group.ts](src/fields/group.ts)
15
- - Collection handle & routing: [src/fields/collection.ts](src/fields/collection.ts)
15
+ - Collection handle & routing: [src/fields/collection.ts](src/fields/collection.ts) (`collectionAttrs`)
16
16
  - ProseMirror RichText renderer: [src/RichText.astro](src/RichText.astro) & [src/richtext/render.ts](src/richtext/render.ts)
17
17
  - Preview bridge script generator: [src/preview/bridge-script.ts](src/preview/bridge-script.ts)
18
18
  - Dev toolbar app & UI: [src/toolbar/app.ts](src/toolbar/app.ts) & [src/toolbar/widgets.ts](src/toolbar/widgets.ts)
@@ -32,9 +32,9 @@
32
32
 
33
33
  - **Usage is the Schema**: Reading `f.text('home.hero.heading')` or `<f.text k="home.hero.heading" />` simultaneously marks the DOM editable region and defines the manifest entry for static extraction.
34
34
  - **Dual-Callable Helpers**: Helpers work synchronously as functions (`f.text('key', { defaultValue: '...' })`) returning typed primitives or as Astro JSX components (`<f.text k="key" />`) emitting DOM marker attributes (`data-cms-field`, `data-cms-entry-field`).
35
- - **Entry Scoping**: `f.entryScope('blog', entry.slug)` creates bound helpers that emit `data-cms-entry-field` for visual click-to-edit inside collection templates.
35
+ - **Entry Scoping & Collection Listings**: `f.entryScope('blog', entry.slug)` creates bound helpers emitting `data-cms-entry-field` and provides `.attrs()` emitting `data-cms-collection` + `data-cms-entry`. `f.collectionAttrs('blog')` emits `data-cms-collection` on listing containers for visual canvas collection editing.
36
36
  - **Group Multiplication**: `f.group` defines reusable multi-field shapes instantiated at different prefixes (`Hero('home.hero')`, `Hero('about.hero')`), passing bound helpers to prop-drilled components.
37
- - **Preview Bridge Injection**: In preview requests (`/_preview/*?preview_token=...`) and Astro dev mode, the bridge IIFE is injected before `</body>` to handle handshake, capabilities (`capabilities: ['comments']`), click capturing, comment mode click suppression, anchor chain derivation, live `anchor-rects` streaming, outlines, and DOM patching.
37
+ - **Preview Bridge Injection**: In preview requests (`/_preview/*?preview_token=...`) and Astro dev mode, the bridge IIFE is injected before `</body>` to handle handshake, capabilities (`capabilities: ['comments', 'collection-click']`), click capturing (field -> group -> entry -> collection priority), collection outlines with dashed borders and label chips, comment mode click suppression, anchor chain derivation, live `anchor-rects` streaming, outlines, and DOM patching.
38
38
  - **Dev-Server Middleware API**: In dev mode (`command === 'dev'`), Vite middleware mounts `/_cms/dev/*` for status, bundle, and draft field writes without polluting production bundles.
39
39
  - **Single Bundle Fetch**: Published bundle is fetched once per build and hydrated across all static pages synchronously via store singleton and `.cms/bundle.json`.
40
40
  - **Zero-Config Integration**: `cmsAstro()` accepts no arguments, automatically falling back to environment variables `CMS_SITE_ID` and `CMS_CONTENT_URL` populated by `cms link` (preview secrets are never stored on site hosts; preview tokens are verified directly by content-worker).
@@ -24,6 +24,29 @@ function markBundleReady(bundle) {
24
24
  function isBundleReady() {
25
25
  return isReady || getActiveBundle() !== null;
26
26
  }
27
+
28
+ // src/fields/attrs.ts
29
+ function cmsFieldAttr(key) {
30
+ return { "data-cms-field": key };
31
+ }
32
+ function cmsGroupAttr(groupName, prefix) {
33
+ return { "data-cms-group": `${groupName}:${prefix}` };
34
+ }
35
+ function cmsEntryAttr(collectionKey, slug) {
36
+ if (slug) {
37
+ return {
38
+ "data-cms-collection": collectionKey,
39
+ "data-cms-entry": slug
40
+ };
41
+ }
42
+ return { "data-cms-collection": collectionKey };
43
+ }
44
+ function cmsCollectionAttr(collectionKey) {
45
+ return cmsEntryAttr(collectionKey);
46
+ }
47
+ function cmsEntryFieldAttr(path) {
48
+ return { "data-cms-entry-field": path };
49
+ }
27
50
  function defineCollection(options) {
28
51
  const jsonSchema = zodToJsonSchema(options.schema);
29
52
  return {
@@ -67,7 +90,11 @@ async function collectionPaths(handleOrKey) {
67
90
  }
68
91
  }));
69
92
  }
93
+ function collectionAttrs(handleOrKey) {
94
+ const collectionKey = typeof handleOrKey === "string" ? handleOrKey : handleOrKey.key;
95
+ return cmsCollectionAttr(collectionKey);
96
+ }
70
97
 
71
- export { bundleReady, collectionPaths, defineCollection, getEntries, getEntry, isBundleReady, markBundleReady };
72
- //# sourceMappingURL=chunk-7E3XJLKX.js.map
73
- //# sourceMappingURL=chunk-7E3XJLKX.js.map
98
+ export { bundleReady, cmsCollectionAttr, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionAttrs, collectionPaths, defineCollection, getEntries, getEntry, isBundleReady, markBundleReady };
99
+ //# sourceMappingURL=chunk-SGHAANOW.js.map
100
+ //# sourceMappingURL=chunk-SGHAANOW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/bundle.ts","../src/fields/attrs.ts","../src/fields/collection.ts"],"names":[],"mappings":"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","file":"chunk-SGHAANOW.js","sourcesContent":["import type { ContentBundle } from '../types';\nimport { getActiveBundle, setBuildBundle } from './store';\n\nlet resolveBundleReady: ((bundle: ContentBundle) => void) | null = null;\nlet isReady = false;\n\nexport const bundleReady = new Promise<ContentBundle>((resolve) => {\n const active = getActiveBundle();\n if (active) {\n isReady = true;\n resolve(active);\n } else {\n resolveBundleReady = resolve;\n }\n});\n\nexport function markBundleReady(bundle: ContentBundle): void {\n setBuildBundle(bundle);\n isReady = true;\n if (resolveBundleReady) {\n resolveBundleReady(bundle);\n resolveBundleReady = null;\n }\n}\n\nexport function isBundleReady(): boolean {\n return isReady || getActiveBundle() !== null;\n}\n","export function cmsFieldAttr(key: string): { 'data-cms-field': string } {\n return { 'data-cms-field': key };\n}\n\nexport function cmsGroupAttr(groupName: string, prefix: string): { 'data-cms-group': string } {\n return { 'data-cms-group': `${groupName}:${prefix}` };\n}\n\nexport function cmsEntryAttr(\n collectionKey: string,\n slug?: string,\n): { 'data-cms-collection': string; 'data-cms-entry'?: string } {\n if (slug) {\n return {\n 'data-cms-collection': collectionKey,\n 'data-cms-entry': slug,\n };\n }\n return { 'data-cms-collection': collectionKey };\n}\n\nexport function cmsCollectionAttr(collectionKey: string): { 'data-cms-collection': string } {\n return cmsEntryAttr(collectionKey) as { 'data-cms-collection': string };\n}\n\nexport function cmsEntryFieldAttr(path: string): { 'data-cms-entry-field': string } {\n return { 'data-cms-entry-field': path };\n}\n","import { type z, zodToJsonSchema } from '@407dev/blocks';\nimport { bundleReady } from '../runtime/bundle';\nimport { getActiveBundle, isDraftMode } from '../runtime/store';\nimport { cmsCollectionAttr } from './attrs';\nimport type {\n CollectionEntry,\n CollectionHandle,\n CollectionStaticPath,\n DefineCollectionOptions,\n InferEntryContent,\n} from './types';\n\nexport function defineCollection<TSchema extends z.ZodTypeAny>(\n options: DefineCollectionOptions<TSchema>,\n): CollectionHandle<TSchema> {\n const jsonSchema = zodToJsonSchema(options.schema);\n\n return {\n key: options.key,\n schema: options.schema,\n route: options.route,\n presentation: options.presentation,\n titleField: options.titleField,\n listColumns: options.listColumns,\n bodyField: options.bodyField,\n orderable: options.orderable,\n seed: options.seed,\n jsonSchema: jsonSchema as Record<string, unknown>,\n schemaVersion: 1,\n };\n}\n\nexport function getEntries<T extends CollectionHandle<z.ZodTypeAny> | string>(\n handleOrKey: T,\n): Array<CollectionEntry<InferEntryContent<T>>> {\n const collectionKey = typeof handleOrKey === 'string' ? handleOrKey : handleOrKey.key;\n const bundle = getActiveBundle();\n const rawEntries = bundle?.entries?.[collectionKey] || [];\n const draft = isDraftMode();\n\n const filtered = draft ? rawEntries : rawEntries.filter((e) => e.status === 'published');\n\n return filtered as unknown as Array<CollectionEntry<InferEntryContent<T>>>;\n}\n\nexport function getEntry<T extends CollectionHandle<z.ZodTypeAny> | string>(\n handleOrKey: T,\n slug: string,\n): CollectionEntry<InferEntryContent<T>> | null {\n const entries = getEntries(handleOrKey);\n const found = entries.find((e) => e.slug === slug);\n return (found || null) as CollectionEntry<InferEntryContent<T>> | null;\n}\n\nexport async function collectionPaths<T extends CollectionHandle<z.ZodTypeAny> | string>(\n handleOrKey: T,\n): Promise<Array<CollectionStaticPath<InferEntryContent<T>>>> {\n const bundle = getActiveBundle() || (await bundleReady);\n const collectionKey = typeof handleOrKey === 'string' ? handleOrKey : handleOrKey.key;\n const rawEntries = bundle?.entries?.[collectionKey] || [];\n\n // Build static paths only for published entries\n const publishedEntries = rawEntries.filter((e) => e.status === 'published');\n\n return publishedEntries.map((entry) => ({\n params: {\n slug: entry.slug,\n },\n props: {\n entry: entry as CollectionEntry<InferEntryContent<T>>,\n },\n }));\n}\n\nexport function collectionAttrs<T extends CollectionHandle<z.ZodTypeAny> | string>(\n handleOrKey: T,\n): { 'data-cms-collection': string } {\n const collectionKey = typeof handleOrKey === 'string' ? handleOrKey : handleOrKey.key;\n return cmsCollectionAttr(collectionKey);\n}\n"]}
@@ -5,7 +5,7 @@ import { resolveEditorOrigins } from './chunk-XJPVYMZM.js';
5
5
 
6
6
  // package.json
7
7
  var package_default = {
8
- version: "0.1.0"};
8
+ version: "0.2.0"};
9
9
 
10
10
  // src/version.ts
11
11
  var CMS_ASTRO_VERSION = package_default.version;
@@ -33,8 +33,7 @@ function createCmsClient(config) {
33
33
  headers["x-preview-token"] = options.previewToken;
34
34
  }
35
35
  const res = await fetchFn(url, {
36
- headers,
37
- cache: "no-store"
36
+ headers
38
37
  });
39
38
  if (!res.ok) {
40
39
  const error = new Error(
@@ -211,6 +210,13 @@ function buildBridgeScript(options = {}) {
211
210
  'html[data-cms-edit-mode] [data-cms-group]:hover {',
212
211
  ' outline: 2px solid ${chromeTokens.success} !important;',
213
212
  ' outline-offset: 3px !important;',
213
+ '}',
214
+ 'html[data-cms-edit-mode] [data-cms-collection] {',
215
+ ' cursor: pointer !important;',
216
+ '}',
217
+ 'html[data-cms-edit-mode] [data-cms-collection]:hover {',
218
+ ' outline: 2px dashed ${chromeTokens.warning} !important;',
219
+ ' outline-offset: 4px !important;',
214
220
  '}'
215
221
  ].filter(Boolean).join('\\n');
216
222
 
@@ -703,6 +709,28 @@ function buildBridgeScript(options = {}) {
703
709
  rect: gRect
704
710
  });
705
711
  }
712
+ return;
713
+ }
714
+
715
+ var collectionEl = target.closest('[data-cms-collection]');
716
+ if (collectionEl) {
717
+ e.preventDefault();
718
+ e.stopPropagation();
719
+
720
+ var collKey = collectionEl.getAttribute('data-cms-collection') || '';
721
+ var entryEl = target.closest('[data-cms-entry]');
722
+ var slug = collectionEl.getAttribute('data-cms-entry') || (entryEl ? entryEl.getAttribute('data-cms-entry') : null) || undefined;
723
+ var cRect = getElementRect(collectionEl);
724
+
725
+ postToEditor({
726
+ source: 'cms-preview',
727
+ v: PROTOCOL_VERSION,
728
+ type: 'collection-click',
729
+ collection: collKey,
730
+ slug: slug,
731
+ rect: cRect
732
+ });
733
+ return;
706
734
  }
707
735
  }, true);
708
736
 
@@ -722,7 +750,7 @@ function buildBridgeScript(options = {}) {
722
750
  v: PROTOCOL_VERSION,
723
751
  type: 'ready',
724
752
  protocolVersion: PROTOCOL_VERSION,
725
- capabilities: ['comments']
753
+ capabilities: ['comments', 'collection-click']
726
754
  });
727
755
 
728
756
  scanRenderedFields();
@@ -927,9 +955,20 @@ function createPreviewMiddleware(options = {}) {
927
955
  let draftBundle;
928
956
  try {
929
957
  draftBundle = await client.getBundle({ previewToken });
930
- } catch (_err) {
931
- return new Response("Preview token is not valid for this site", {
932
- status: 404,
958
+ } catch (err) {
959
+ const status = err?.status;
960
+ if (status === 401 || status === 403 || status === 404) {
961
+ return new Response("Preview token is not valid for this site", {
962
+ status: 404,
963
+ headers: {
964
+ "Cache-Control": "private, no-store",
965
+ "X-Robots-Tag": "noindex, nofollow"
966
+ }
967
+ });
968
+ }
969
+ console.error(err);
970
+ return new Response("Failed to load preview content", {
971
+ status: 502,
933
972
  headers: {
934
973
  "Cache-Control": "private, no-store",
935
974
  "X-Robots-Tag": "noindex, nofollow"
@@ -976,7 +1015,9 @@ function createPreviewMiddleware(options = {}) {
976
1015
  const isHtml = typeof contentType === "string" && contentType.includes("text/html") || !contentType && !isStaticAsset;
977
1016
  if (isHtml) {
978
1017
  const html = await response.text();
979
- const bridgeScript = buildBridgeScript({ editorOrigins: options.editorOrigins });
1018
+ const bridgeScript = buildBridgeScript({
1019
+ editorOrigins: options.editorOrigins
1020
+ });
980
1021
  const scriptTag = `<script>${bridgeScript}</script>`;
981
1022
  const modifiedHtml = html.includes("</body>") ? html.replace("</body>", `${scriptTag}</body>`) : `${html}${scriptTag}`;
982
1023
  const newHeaders = new Headers(response.headers);
@@ -1009,5 +1050,5 @@ function createPreviewMiddleware(options = {}) {
1009
1050
  }
1010
1051
 
1011
1052
  export { buildBridgeScript, createCmsClient, createPreviewMiddleware, getClient, initCmsClient, setClient };
1012
- //# sourceMappingURL=chunk-QYUVAKMC.js.map
1013
- //# sourceMappingURL=chunk-QYUVAKMC.js.map
1053
+ //# sourceMappingURL=chunk-YCQMH2T7.js.map
1054
+ //# sourceMappingURL=chunk-YCQMH2T7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../package.json","../src/version.ts","../src/client.ts","../src/preview/bridge-script.ts","../src/middleware/preview.ts"],"names":["globalWithCms"],"mappings":"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A;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AA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","file":"chunk-YCQMH2T7.js","sourcesContent":["{\n \"name\": \"@407dev/cms-astro\",\n \"version\": \"0.2.0\",\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/407dev/cms.git\",\n \"directory\": \"packages/astro\"\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"source\": \"./src/index.ts\",\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n },\n \"./collections\": {\n \"source\": \"./src/fields/collections.ts\",\n \"types\": \"./dist/fields/collections.d.ts\",\n \"import\": \"./dist/fields/collections.js\"\n },\n \"./CmsImage.astro\": \"./src/CmsImage.astro\",\n \"./CmsVideo.astro\": \"./src/CmsVideo.astro\",\n \"./CmsHead.astro\": \"./src/CmsHead.astro\",\n \"./RichText.astro\": \"./src/RichText.astro\",\n \"./middleware\": {\n \"source\": \"./src/middleware/index.ts\",\n \"types\": \"./dist/middleware/index.d.ts\",\n \"import\": \"./dist/middleware/index.js\",\n \"default\": \"./dist/middleware/index.js\"\n },\n \"./toolbar\": {\n \"source\": \"./src/toolbar/app.ts\",\n \"types\": \"./dist/toolbar/app.d.ts\",\n \"import\": \"./dist/toolbar/app.js\",\n \"default\": \"./dist/toolbar/app.js\"\n },\n \"./dev\": {\n \"source\": \"./src/dev/index.ts\",\n \"types\": \"./dist/dev/index.d.ts\",\n \"import\": \"./dist/dev/index.js\",\n \"default\": \"./dist/dev/index.js\"\n }\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"lint\": \"biome check src\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"dependencies\": {\n \"@407dev/blocks\": \"workspace:*\",\n \"@407dev/field-types\": \"workspace:*\",\n \"zod\": \"^4.4.3\"\n },\n \"peerDependencies\": {\n \"@407dev/cli\": \"workspace:*\",\n \"astro\": \"^5.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@407dev/cli\": {\n \"optional\": true\n },\n \"astro\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@407dev/api-client\": \"workspace:*\",\n \"@407dev/cli\": \"workspace:*\",\n \"@407dev/config\": \"workspace:*\",\n \"@407dev/design-tokens\": \"workspace:*\",\n \"astro\": \"^5.3.0\",\n \"expect-type\": \"^0.20.0\",\n \"tsup\": \"^8.4.0\",\n \"typescript\": \"^5.7.3\",\n \"vite\": \"^6.1.0\",\n \"vitest\": \"3.0.7\"\n }\n}\n","import pkg from '../package.json';\n\nexport const CMS_ASTRO_VERSION: string = pkg.version;\n","import { DEFAULT_DEV_CONTENT_URL } from '@407dev/config';\nimport type {\n CmsClient,\n CmsClientConfig,\n CmsSiteConfig,\n ContentBundle,\n GetBundleOptions,\n} from './types';\nimport { CMS_ASTRO_VERSION } from './version.js';\n\nexport function createCmsClient(config: CmsClientConfig): CmsClient {\n const siteId = config.siteId;\n const contentUrl = config.contentUrl.replace(/\\/+$/, '');\n const fetchFn = config.fetch || fetch;\n\n // In-memory cache for published bundle to ensure build determinism\n let cachedPublishedBundle: ContentBundle | null = null;\n\n const client: CmsClient = {\n siteId,\n contentUrl,\n previewSecret: config.previewSecret,\n\n async getBundle(options?: GetBundleOptions): Promise<ContentBundle> {\n const isDraft = Boolean(options?.previewToken);\n\n if (!isDraft && cachedPublishedBundle) {\n return cachedPublishedBundle;\n }\n\n const url = isDraft\n ? `${contentUrl}/draft/${siteId}/bundle`\n : `${contentUrl}/content/${siteId}/bundle`;\n\n const headers: Record<string, string> = {\n 'x-cms-sdk': `cms-astro@${CMS_ASTRO_VERSION}`,\n };\n if (options?.previewToken) {\n headers['x-preview-token'] = options.previewToken;\n }\n\n const res = await fetchFn(url, {\n headers,\n });\n if (!res.ok) {\n const error = new Error(\n `CMS Client: Failed to fetch bundle from ${url} (status ${res.status}): ${res.statusText}`,\n );\n (error as unknown as { status?: number }).status = res.status;\n throw error;\n }\n\n const bundle = (await res.json()) as ContentBundle;\n\n if (!isDraft) {\n cachedPublishedBundle = bundle;\n }\n\n return bundle;\n },\n\n async getFields(options?: GetBundleOptions): Promise<ContentBundle['fields']> {\n const bundle = await this.getBundle(options);\n return bundle.fields || {};\n },\n\n async getField<T = unknown>(key: string, options?: GetBundleOptions): Promise<T | null> {\n const fields = await this.getFields(options);\n return (fields[key] as T) ?? null;\n },\n\n async getCollections(options?: GetBundleOptions): Promise<ContentBundle['collections']> {\n const bundle = await this.getBundle(options);\n return bundle.collections || {};\n },\n\n async getEntries(\n collectionKey: string,\n options?: GetBundleOptions,\n ): Promise<ContentBundle['entries'][string]> {\n const bundle = await this.getBundle(options);\n return bundle.entries?.[collectionKey] || [];\n },\n\n async getEntry(\n collectionKey: string,\n slug: string,\n options?: GetBundleOptions,\n ): Promise<ContentBundle['entries'][string][number] | null> {\n const entries = await this.getEntries(collectionKey, options);\n return entries.find((e) => e.slug === slug) || null;\n },\n\n async getRoutes(options?: GetBundleOptions): Promise<ContentBundle['routes']> {\n const bundle = await this.getBundle(options);\n return bundle.routes || [];\n },\n\n async getSiteConfig(options?: GetBundleOptions): Promise<CmsSiteConfig> {\n const bundle = await this.getBundle(options);\n return {\n site_id: bundle.site_id,\n redirects: bundle.redirects || [],\n robots: bundle.settings?.robots || {},\n default_seo: bundle.settings?.default_seo || {},\n sitemap: bundle.settings?.sitemap || {},\n not_found_path: bundle.settings?.not_found_path || null,\n };\n },\n\n clearCache(): void {\n cachedPublishedBundle = null;\n },\n };\n\n return client;\n}\n\nconst globalWithCms = globalThis as typeof globalThis & {\n __CMS_CLIENT__?: CmsClient | null;\n};\n\nlet globalClient: CmsClient | null =\n (typeof globalThis !== 'undefined' && globalWithCms.__CMS_CLIENT__) || null;\n\nexport function initCmsClient(options: {\n siteId?: string;\n contentUrl?: string;\n previewSecret?: string;\n client?: CmsClient;\n}): CmsClient {\n if (options.client) {\n globalClient = options.client;\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = options.client;\n }\n return globalClient;\n }\n\n globalClient = createCmsClient({\n siteId: options.siteId || process.env.CMS_SITE_ID || '',\n contentUrl: options.contentUrl || process.env.CMS_CONTENT_URL || DEFAULT_DEV_CONTENT_URL,\n previewSecret: options.previewSecret || process.env.CMS_PREVIEW_SECRET,\n });\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = globalClient;\n }\n\n return globalClient;\n}\n\nexport function getClient(): CmsClient | null {\n return (\n globalClient || (typeof globalThis !== 'undefined' && globalWithCms.__CMS_CLIENT__) || null\n );\n}\n\nexport function setClient(client: CmsClient | null): void {\n globalClient = client;\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = client;\n }\n}\n","import { chromeTokens } from '@407dev/design-tokens/tokens';\nimport { resolveEditorOrigins } from './origins';\n\nexport const BRIDGE_PROTOCOL_VERSION = 1;\n\nexport interface BridgeScriptOptions {\n editorOrigins?: string[];\n}\n\nexport function buildBridgeScript(options: BridgeScriptOptions = {}): string {\n const allowedOrigins = resolveEditorOrigins(options.editorOrigins);\n const allowedOriginsJson = JSON.stringify(allowedOrigins);\n\n return `(function() {\n if (typeof window === 'undefined') return;\n if (window.__CMS_BRIDGE_INITIALIZED__) return;\n window.__CMS_BRIDGE_INITIALIZED__ = true;\n\n var PROTOCOL_VERSION = ${BRIDGE_PROTOCOL_VERSION};\n var allowedOrigins = ${allowedOriginsJson};\n var connectedOrigin = null;\n var connectedSource = null;\n var activeKey = null;\n var watchedAnchors = [];\n var rafScheduled = false;\n var isPatchingDom = false;\n var debounceRescanTimer = null;\n\n function normalizeOrigin(raw) {\n if (!raw || typeof raw !== 'string') return null;\n var trimmed = raw.trim();\n if (!trimmed) return null;\n try {\n var withScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\\\/\\\\//.test(trimmed) ? trimmed : 'https://' + trimmed;\n var url = new URL(withScheme);\n if (!url.protocol || !url.host) return null;\n return (url.protocol + '//' + url.host).toLowerCase();\n } catch (e) {\n return null;\n }\n }\n\n var normalizedAllowed = allowedOrigins.map(normalizeOrigin).filter(Boolean);\n\n function isOriginAllowed(origin) {\n var norm = normalizeOrigin(origin);\n if (!norm) return false;\n return normalizedAllowed.indexOf(norm) !== -1;\n }\n\n function postToEditor(msg) {\n if (!connectedSource || !connectedOrigin) return;\n try {\n connectedSource.postMessage(msg, connectedOrigin);\n } catch (err) {\n // Failed to post\n }\n }\n\n // Inject Bridge Styles\n var isEmbedded = false;\n try {\n isEmbedded = window.self !== window.top || window.parent !== window;\n } catch (_e) {\n isEmbedded = true;\n }\n\n var toolbarTag = 'astro-' + 'dev-toolbar';\n\n function ensureBridgeStyles() {\n if (typeof document === 'undefined' || !document || typeof document.getElementById !== 'function') return;\n if (document.getElementById('cms-bridge-styles')) return;\n var style = document.createElement('style');\n style.id = 'cms-bridge-styles';\n style.textContent = [\n isEmbedded ? toolbarTag + ' { display: none !important; }' : '',\n 'html[data-cms-comment-mode],',\n 'html[data-cms-comment-mode] * {',\n ' cursor: crosshair !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-field],',\n 'html[data-cms-edit-mode] [data-cms-entry-field] {',\n ' cursor: pointer !important;',\n ' outline: 1px dashed rgba(99, 102, 241, 0.5) !important;',\n ' outline-offset: 2px !important;',\n ' transition: outline 0.15s ease-in-out !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-field]:hover,',\n 'html[data-cms-edit-mode] [data-cms-entry-field]:hover {',\n ' outline: 2px solid ${chromeTokens.primary} !important;',\n ' outline-offset: 2px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-group] {',\n ' outline: 1px dashed rgba(16, 185, 129, 0.4) !important;',\n ' outline-offset: 3px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-group]:hover {',\n ' outline: 2px solid ${chromeTokens.success} !important;',\n ' outline-offset: 3px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-collection] {',\n ' cursor: pointer !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-collection]:hover {',\n ' outline: 2px dashed ${chromeTokens.warning} !important;',\n ' outline-offset: 4px !important;',\n '}'\n ].filter(Boolean).join('\\\\n');\n\n var target = document.head || document.documentElement;\n if (target) {\n target.appendChild(style);\n }\n }\n\n function hideDevToolbar() {\n if (!isEmbedded) return;\n ensureBridgeStyles();\n if (typeof document === 'undefined' || !document || typeof document.querySelector !== 'function') return;\n try {\n var tb = document.querySelector(toolbarTag);\n if (tb && tb instanceof HTMLElement) {\n tb.style.setProperty('display', 'none', 'important');\n }\n } catch (_e) {}\n }\n\n ensureBridgeStyles();\n hideDevToolbar();\n\n function inferFieldKind(el) {\n if (!el) return 'unknown';\n var tag = el.tagName ? el.tagName.toLowerCase() : '';\n if (tag === 'img') return 'image';\n if (tag === 'video') return 'video';\n var explicitKind = el.getAttribute('data-cms-kind');\n if (explicitKind) return explicitKind;\n if (el.classList.contains('rich-body') || el.classList.contains('cms-richtext') || el.getAttribute('data-cms-richtext') === 'true') {\n return 'richtext';\n }\n return 'text';\n }\n\n function getElementRect(el) {\n var r = el.getBoundingClientRect();\n return {\n top: r.top,\n left: r.left,\n width: r.width,\n height: r.height\n };\n }\n\n function parseGroupAttr(raw) {\n if (!raw) return undefined;\n var idx = raw.indexOf(':');\n if (idx === -1) return { group: raw, scope: '' };\n return {\n group: raw.slice(0, idx),\n scope: raw.slice(idx + 1)\n };\n }\n\n function scanRenderedFields() {\n var fieldEls = document.querySelectorAll('[data-cms-field], [data-cms-entry-field]');\n var fieldMap = {};\n\n for (var i = 0; i < fieldEls.length; i++) {\n var el = fieldEls[i];\n var key = el.getAttribute('data-cms-field') || el.getAttribute('data-cms-entry-field') || '';\n if (!key) continue;\n\n var isEntry = el.hasAttribute('data-cms-entry-field');\n var groupEl = el.closest('[data-cms-group]');\n var collectionEl = el.closest('[data-cms-collection]');\n var groupName = undefined;\n if (groupEl) {\n var g = parseGroupAttr(groupEl.getAttribute('data-cms-group'));\n if (g) groupName = g.group;\n }\n\n var entryRef = undefined;\n if (isEntry || collectionEl) {\n entryRef = {\n collection: collectionEl ? collectionEl.getAttribute('data-cms-collection') || '' : '',\n slug: collectionEl ? collectionEl.getAttribute('data-cms-entry') || '' : '',\n path: isEntry ? key : key\n };\n }\n\n var uniqueId = (isEntry && entryRef ? entryRef.collection + ':' + entryRef.slug + ':' : '') + key;\n\n if (!fieldMap[uniqueId]) {\n fieldMap[uniqueId] = {\n key: key,\n kind: inferFieldKind(el),\n group: groupName,\n entryRef: entryRef,\n instances: 1\n };\n } else {\n fieldMap[uniqueId].instances++;\n }\n }\n\n var fields = [];\n for (var k in fieldMap) {\n if (Object.prototype.hasOwnProperty.call(fieldMap, k)) {\n fields.push(fieldMap[k]);\n }\n }\n\n window.__CMS_FIELDS__ = fields;\n window.__CMS_RESCAN__ = scanRenderedFields;\n\n try {\n document.dispatchEvent(new CustomEvent('cms:fields-updated', { detail: fields }));\n } catch (_e) {}\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'rendered-fields',\n fields: fields\n });\n }\n\n function debouncedRescan() {\n if (isPatchingDom) return;\n if (debounceRescanTimer) clearTimeout(debounceRescanTimer);\n debounceRescanTimer = setTimeout(function() {\n scanRenderedFields();\n scheduleRectsUpdate();\n }, 150);\n }\n\n var currentObserver = null;\n function setupMutationObserver() {\n if (typeof MutationObserver === 'undefined' || !document.body) return;\n if (currentObserver) {\n try {\n currentObserver.disconnect();\n } catch (_e) {}\n }\n currentObserver = new MutationObserver(function(mutations) {\n if (isPatchingDom) return;\n hideDevToolbar();\n debouncedRescan();\n });\n currentObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributeFilter: ['data-cms-field', 'data-cms-entry-field', 'data-cms-group', 'data-cms-collection', 'data-cms-entry']\n });\n }\n\n function buildStableSelector(target) {\n if (!target || !target.tagName) return '';\n if (target === document.documentElement) return 'html';\n if (target === document.body) return 'body';\n\n var parts = [];\n var curr = target;\n var maxLevels = 8;\n\n while (curr && curr !== document.documentElement && parts.length < maxLevels) {\n if (curr === document.body) {\n parts.unshift('body');\n break;\n }\n var id = curr.getAttribute('id');\n if (id && id.trim()) {\n var escapedId = (typeof CSS !== 'undefined' && CSS.escape) ? CSS.escape(id.trim()) : id.trim();\n parts.unshift('#' + escapedId);\n break;\n }\n var tag = curr.tagName ? curr.tagName.toLowerCase() : '';\n if (!tag) break;\n var count = 1;\n var sib = curr.previousElementSibling;\n while (sib) {\n if (sib.tagName && sib.tagName.toLowerCase() === tag) {\n count++;\n }\n sib = sib.previousElementSibling;\n }\n parts.unshift(tag + ':nth-of-type(' + count + ')');\n curr = curr.parentElement;\n }\n\n return parts.join(' > ');\n }\n\n function buildElementLabel(el) {\n if (!el || !el.tagName) return 'element';\n\n var ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n var id = el.getAttribute('id');\n if (id && id.trim()) {\n return '#' + id.trim();\n }\n\n var tag = el.tagName.toLowerCase();\n\n if (tag === 'nav') return 'Navigation';\n if (tag === 'header') return 'Header';\n if (tag === 'footer') return 'Footer';\n if (tag === 'aside') return 'Sidebar';\n if (tag === 'form') return 'Form';\n\n if (tag === 'img') {\n var alt = el.getAttribute('alt');\n if (alt && alt.trim()) return alt.trim();\n return 'img';\n }\n\n if (tag === 'a' || tag === 'button') {\n var text = (el.textContent || '').trim().replace(/\\\\s+/g, ' ');\n if (text) {\n return text.length > 40 ? text.slice(0, 37) + '...' : text;\n }\n return tag;\n }\n\n return tag || 'element';\n }\n\n function buildCandidateEntry(targetEl, clientX, clientY) {\n if (!targetEl || !targetEl.tagName) return null;\n var selector = buildStableSelector(targetEl);\n if (!selector) return null;\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(targetEl));\n var hitRect = targetEl.getBoundingClientRect();\n var offsetX = typeof clientX === 'number' ? Math.round(clientX - hitRect.left) : 0;\n var offsetY = typeof clientY === 'number' ? Math.round(clientY - hitRect.top) : 0;\n return {\n selector: selector,\n instance: instance,\n kind: 'element',\n label: buildElementLabel(targetEl),\n offsetX: offsetX,\n offsetY: offsetY,\n rect: getElementRect(targetEl)\n };\n }\n\n function buildAnchorChain(el, clientX, clientY) {\n var chain = [];\n var curr = el;\n while (curr && curr !== document.documentElement && curr !== document.body) {\n var hit = curr.closest('[data-cms-field], [data-cms-entry-field], [data-cms-group], [data-cms-collection][data-cms-entry]');\n if (!hit) break;\n\n var selector = '';\n var kind = 'unknown';\n var label = '';\n\n if (hit.hasAttribute('data-cms-field')) {\n var fieldKey = hit.getAttribute('data-cms-field') || '';\n selector = '[data-cms-field=\"' + fieldKey + '\"]';\n kind = inferFieldKind(hit);\n label = fieldKey;\n } else if (hit.hasAttribute('data-cms-entry-field')) {\n var entryFieldKey = hit.getAttribute('data-cms-entry-field') || '';\n selector = '[data-cms-entry-field=\"' + entryFieldKey + '\"]';\n kind = inferFieldKind(hit);\n label = entryFieldKey;\n } else if (hit.hasAttribute('data-cms-group')) {\n var groupAttr = hit.getAttribute('data-cms-group') || '';\n selector = '[data-cms-group=\"' + groupAttr + '\"]';\n kind = 'group';\n var parsed = parseGroupAttr(groupAttr);\n label = parsed ? parsed.group : groupAttr;\n } else if (hit.hasAttribute('data-cms-collection') && hit.hasAttribute('data-cms-entry')) {\n var col = hit.getAttribute('data-cms-collection') || '';\n var ent = hit.getAttribute('data-cms-entry') || '';\n selector = '[data-cms-collection=\"' + col + '\"][data-cms-entry=\"' + ent + '\"]';\n kind = 'entry';\n label = col + '/' + ent;\n }\n\n if (selector) {\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(hit));\n var hitRect = hit.getBoundingClientRect();\n var offsetX = typeof clientX === 'number' ? Math.round(clientX - hitRect.left) : 0;\n var offsetY = typeof clientY === 'number' ? Math.round(clientY - hitRect.top) : 0;\n chain.push({\n selector: selector,\n instance: instance,\n kind: kind,\n label: label,\n offsetX: offsetX,\n offsetY: offsetY,\n rect: getElementRect(hit)\n });\n }\n\n curr = hit.parentElement;\n }\n\n if (chain.length > 0) {\n return chain;\n }\n\n if (!el || !el.tagName) return chain;\n\n var interactiveEl = el.closest ? el.closest('a, button') : null;\n var selfEl = interactiveEl || (el.closest ? el.closest('a, button, nav, header, footer, aside, main, section, article, form, img, svg, [role]') : null) || el;\n var landmarkEl = selfEl.closest ? selfEl.closest('nav, header, footer, aside, main, section, article, form, [role=\"navigation\"], [role=\"banner\"], [role=\"contentinfo\"]') : null;\n\n var selfEntry = buildCandidateEntry(selfEl, clientX, clientY);\n if (selfEntry) {\n chain.push(selfEntry);\n }\n\n if (landmarkEl && landmarkEl !== selfEl) {\n var landmarkEntry = buildCandidateEntry(landmarkEl, clientX, clientY);\n if (landmarkEntry) {\n chain.push(landmarkEntry);\n }\n }\n\n return chain;\n }\n\n function resolveAnchorEl(anchor) {\n if (!anchor || !anchor.selector) return null;\n try {\n var els = document.querySelectorAll(anchor.selector);\n if (!els || els.length === 0) return null;\n var inst = typeof anchor.instance === 'number' ? anchor.instance : 0;\n if (inst >= 0 && inst < els.length) return els[inst];\n return els[0];\n } catch (_e) {\n return null;\n }\n }\n\n function scheduleRectsUpdate() {\n if (rafScheduled) return;\n rafScheduled = true;\n requestAnimationFrame(function() {\n rafScheduled = false;\n var rects = {};\n if (activeKey) {\n var el = document.querySelector('[data-cms-field=\"' + activeKey + '\"], [data-cms-entry-field=\"' + activeKey + '\"]');\n if (el) {\n rects[activeKey] = getElementRect(el);\n }\n }\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'rects-update',\n rects: rects,\n scrollY: window.scrollY || window.pageYOffset || 0\n });\n\n if (watchedAnchors && watchedAnchors.length > 0) {\n var anchorRects = {};\n for (var a = 0; a < watchedAnchors.length; a++) {\n var wAnchor = watchedAnchors[a];\n var resolvedEl = resolveAnchorEl(wAnchor);\n if (resolvedEl) {\n anchorRects[wAnchor.id] = getElementRect(resolvedEl);\n } else {\n anchorRects[wAnchor.id] = null;\n }\n }\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'anchor-rects',\n rects: anchorRects\n });\n }\n });\n }\n\n // Click handler\n document.addEventListener('click', function(e) {\n if (document.documentElement.hasAttribute('data-cms-comment-mode')) {\n e.preventDefault();\n e.stopPropagation();\n var target = e.target;\n if (!target || !(target instanceof Element)) return;\n\n var docWidth = Math.max(\n document.documentElement.scrollWidth || 0,\n document.body ? document.body.scrollWidth : 0,\n window.innerWidth || 0\n );\n var docHeight = Math.max(\n document.documentElement.scrollHeight || 0,\n document.body ? document.body.scrollHeight : 0,\n window.innerHeight || 0\n );\n var pageX = e.pageX !== undefined ? e.pageX : (e.clientX + (window.scrollX || window.pageXOffset || 0));\n var pageY = e.pageY !== undefined ? e.pageY : (e.clientY + (window.scrollY || window.pageYOffset || 0));\n var pageXPct = docWidth > 0 ? Math.round((pageX / docWidth) * 10000) / 100 : 0;\n var pageYPct = docHeight > 0 ? Math.round((pageY / docHeight) * 10000) / 100 : 0;\n\n var chain = buildAnchorChain(target, e.clientX, e.clientY);\n var clickRect = chain.length > 0 ? chain[0].rect : {\n top: e.clientY,\n left: e.clientX,\n width: 0,\n height: 0\n };\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'comment-click',\n chain: chain,\n point: { pageXPct: pageXPct, pageYPct: pageYPct },\n rect: clickRect\n });\n return;\n }\n\n if (!document.documentElement.hasAttribute('data-cms-edit-mode')) return;\n var target = e.target;\n if (!target || !(target instanceof Element)) return;\n\n var fieldEl = target.closest('[data-cms-field], [data-cms-entry-field]');\n var groupEl = target.closest('[data-cms-group]');\n\n if (fieldEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var isEntry = fieldEl.hasAttribute('data-cms-entry-field');\n var key = fieldEl.getAttribute('data-cms-field') || fieldEl.getAttribute('data-cms-entry-field') || '';\n var kind = inferFieldKind(fieldEl);\n var rect = getElementRect(fieldEl);\n activeKey = key;\n\n var selector = isEntry ? '[data-cms-entry-field=\"' + key + '\"]' : '[data-cms-field=\"' + key + '\"]';\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(fieldEl));\n\n var collectionEl = fieldEl.closest('[data-cms-collection]');\n var entryRef = (isEntry || collectionEl) ? {\n collection: collectionEl ? collectionEl.getAttribute('data-cms-collection') || '' : '',\n slug: collectionEl ? collectionEl.getAttribute('data-cms-entry') || '' : '',\n path: isEntry ? key : key\n } : undefined;\n\n var groupPath = groupEl ? parseGroupAttr(groupEl.getAttribute('data-cms-group')) : undefined;\n\n try {\n document.dispatchEvent(new CustomEvent('cms:field-selected', {\n detail: {\n key: key,\n kind: kind,\n entryRef: entryRef,\n groupPath: groupPath\n }\n }));\n } catch (_e) {}\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'field-click',\n key: key,\n kind: kind,\n rect: rect,\n instance: instance,\n entryRef: entryRef,\n groupPath: groupPath\n });\n return;\n }\n\n if (groupEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var g = parseGroupAttr(groupEl.getAttribute('data-cms-group'));\n if (g) {\n var gRect = getElementRect(groupEl);\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'group-click',\n group: g.group,\n scope: g.scope,\n rect: gRect\n });\n }\n return;\n }\n\n var collectionEl = target.closest('[data-cms-collection]');\n if (collectionEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var collKey = collectionEl.getAttribute('data-cms-collection') || '';\n var entryEl = target.closest('[data-cms-entry]');\n var slug = collectionEl.getAttribute('data-cms-entry') || (entryEl ? entryEl.getAttribute('data-cms-entry') : null) || undefined;\n var cRect = getElementRect(collectionEl);\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'collection-click',\n collection: collKey,\n slug: slug,\n rect: cRect\n });\n return;\n }\n }, true);\n\n // Message handler\n window.addEventListener('message', function(e) {\n var data = e.data;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'cms-editor') return;\n\n if (data.type === 'hello') {\n if (!isOriginAllowed(e.origin)) return;\n connectedOrigin = e.origin;\n connectedSource = e.source;\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'ready',\n protocolVersion: PROTOCOL_VERSION,\n capabilities: ['comments', 'collection-click']\n });\n\n scanRenderedFields();\n return;\n }\n\n if (!connectedOrigin || e.origin !== connectedOrigin) return;\n\n if (data.type === 'highlight-mode') {\n if (data.on) {\n document.documentElement.setAttribute('data-cms-edit-mode', 'true');\n } else {\n document.documentElement.removeAttribute('data-cms-edit-mode');\n }\n return;\n }\n\n if (data.type === 'comment-mode') {\n if (data.on) {\n document.documentElement.setAttribute('data-cms-comment-mode', 'true');\n } else {\n document.documentElement.removeAttribute('data-cms-comment-mode');\n }\n return;\n }\n\n if (data.type === 'watch-anchors') {\n watchedAnchors = Array.isArray(data.anchors) ? data.anchors : [];\n scheduleRectsUpdate();\n return;\n }\n\n if (data.type === 'scroll-to-anchor') {\n var sId = data.id;\n var targetItem = null;\n for (var si = 0; si < watchedAnchors.length; si++) {\n if (watchedAnchors[si].id === sId) {\n targetItem = watchedAnchors[si];\n break;\n }\n }\n if (targetItem) {\n var elToScroll = resolveAnchorEl(targetItem);\n if (elToScroll) {\n elToScroll.scrollIntoView({ behavior: 'smooth', block: 'center' });\n scheduleRectsUpdate();\n }\n }\n return;\n }\n\n if (data.type === 'patch') {\n isPatchingDom = true;\n var patchKey = data.key;\n var patchKind = data.kind;\n var patchVal = data.value;\n var patchEntry = data.entryRef;\n\n var patchSelector;\n var fPath = patchEntry && patchEntry.path ? patchEntry.path : patchKey;\n if (patchEntry && (patchEntry.collection || patchEntry.slug)) {\n var colAttr = patchEntry.collection ? '[data-cms-collection=\"' + patchEntry.collection + '\"]' : '';\n var entryAttr = patchEntry.slug ? '[data-cms-entry=\"' + patchEntry.slug + '\"]' : '';\n var scopeSel = colAttr + entryAttr;\n patchSelector = scopeSel + ' [data-cms-entry-field=\"' + fPath + '\"], ' +\n scopeSel + '[data-cms-entry-field=\"' + fPath + '\"]';\n } else if (patchEntry) {\n patchSelector = '[data-cms-entry-field=\"' + fPath + '\"]';\n } else {\n patchSelector = '[data-cms-field=\"' + patchKey + '\"]';\n }\n\n var matchingEls = document.querySelectorAll(patchSelector);\n for (var j = 0; j < matchingEls.length; j++) {\n var mEl = matchingEls[j];\n var isStructured = patchKind === 'geo.area' || patchKind === 'geoArea' ||\n patchKind === 'address' || patchKind === 'address.list' ||\n patchKind === 'media.videoList' || patchKind === 'videoList' ||\n mEl.getAttribute('data-cms-kind') === 'geo.area' ||\n mEl.getAttribute('data-cms-kind') === 'address.list' ||\n mEl.getAttribute('data-cms-kind') === 'media.videoList';\n\n if (patchKind === 'image' || mEl.tagName.toLowerCase() === 'img') {\n if (patchVal && typeof patchVal === 'object') {\n if (patchVal.url) mEl.setAttribute('src', patchVal.url);\n if (patchVal.alt !== undefined) mEl.setAttribute('alt', patchVal.alt);\n } else if (typeof patchVal === 'string') {\n mEl.setAttribute('src', patchVal);\n }\n } else if (patchKind === 'video' || mEl.tagName.toLowerCase() === 'video') {\n if (patchVal && typeof patchVal === 'object') {\n if (patchVal.url) mEl.setAttribute('src', patchVal.url);\n if (patchVal.poster !== undefined) mEl.setAttribute('poster', patchVal.poster);\n } else if (typeof patchVal === 'string') {\n mEl.setAttribute('src', patchVal);\n }\n if (typeof mEl.load === 'function') mEl.load();\n } else if (isStructured || (patchVal && typeof patchVal === 'object')) {\n // Structured non-image field values (e.g. videoList, geoArea, address) cannot be rendered\n // via simple textContent replacement without producing [object Object].\n // Skip the text write and leave server-rendered markup intact; structured fields refresh via reload.\n } else {\n mEl.textContent = patchVal !== null && patchVal !== undefined ? String(patchVal) : '';\n }\n }\n\n isPatchingDom = false;\n scanRenderedFields();\n scheduleRectsUpdate();\n return;\n }\n\n if (data.type === 'scroll-to') {\n var scrollKey = data.key;\n var scrollInstance = typeof data.instance === 'number' ? data.instance : 0;\n var scrollEls = document.querySelectorAll('[data-cms-field=\"' + scrollKey + '\"], [data-cms-entry-field=\"' + scrollKey + '\"]');\n if (scrollEls.length > scrollInstance) {\n scrollEls[scrollInstance].scrollIntoView({ behavior: 'smooth', block: 'center' });\n activeKey = scrollKey;\n scheduleRectsUpdate();\n }\n return;\n }\n\n if (data.type === 'reload') {\n window.location.reload();\n return;\n }\n });\n\n function handlePageTransition() {\n hideDevToolbar();\n scanRenderedFields();\n setupMutationObserver();\n }\n\n window.addEventListener('scroll', scheduleRectsUpdate, { passive: true });\n window.addEventListener('resize', scheduleRectsUpdate, { passive: true });\n\n document.addEventListener('astro:page-load', handlePageTransition);\n document.addEventListener('astro:after-swap', handlePageTransition);\n window.addEventListener('popstate', handlePageTransition);\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', function() {\n handlePageTransition();\n });\n } else {\n handlePageTransition();\n }\n})();`;\n}\n","import { createCmsClient, getClient } from '../client';\nimport { buildBridgeScript } from '../preview/bridge-script';\nimport { isDraftMode, runWithDraftBundle, setActiveDraftBundle } from '../runtime/store';\nimport type { CmsClient, ContentBundle } from '../types';\n\nexport interface PreviewMiddlewareOptions {\n client?: CmsClient;\n siteId?: string;\n contentUrl?: string;\n /** @deprecated Site hosts no longer verify preview tokens. Ignored outside astro dev. */\n previewSecret?: string;\n editorOrigins?: string[];\n}\n\ninterface PreviewContextLocals {\n __cms_is_draft?: boolean;\n __cms_draft_bundle?: ContentBundle;\n [key: string]: unknown;\n}\n\nexport interface PreviewMiddlewareContext {\n request: Request;\n url?: URL;\n locals?: PreviewContextLocals;\n rewrite?: (path: string) => Promise<Response> | undefined;\n}\n\nexport function createPreviewMiddleware(options: PreviewMiddlewareOptions = {}) {\n let client = options.client;\n\n return async (\n context: PreviewMiddlewareContext,\n next: () => Promise<Response>,\n ): Promise<Response> => {\n const globalWithCms = globalThis as typeof globalThis & {\n __CMS_IS_REWRITING__?: boolean;\n };\n\n // If already running within an active draft bundle context or internal rewrite, pass through\n if (\n (typeof globalThis !== 'undefined' && globalWithCms.__CMS_IS_REWRITING__) ||\n isDraftMode() ||\n context.locals?.__cms_is_draft\n ) {\n return next();\n }\n\n const rawUrl = context.url;\n const url =\n rawUrl && typeof rawUrl.href === 'string'\n ? new URL(rawUrl.href)\n : rawUrl && typeof (rawUrl as unknown as { pathname?: string }).pathname === 'string'\n ? rawUrl\n : new URL(context.request?.url || '/', 'http://localhost');\n const pathname = url.pathname || '/';\n const isPreviewRoute = pathname === '/_preview' || pathname.startsWith('/_preview/');\n\n const previewToken =\n (rawUrl?.searchParams?.get ? rawUrl.searchParams.get('preview_token') : null) ||\n (url?.searchParams?.get ? url.searchParams.get('preview_token') : null) ||\n (context.request?.headers?.get ? context.request.headers.get('x-preview-token') : null);\n\n if (!isPreviewRoute && !previewToken) {\n return next();\n }\n\n if (!client) {\n client = getClient() || undefined;\n }\n\n if (!client) {\n const metaEnv = (import.meta as unknown as { env?: Record<string, string | undefined> }).env;\n const siteId =\n options.siteId ||\n (typeof process !== 'undefined' && process.env?.CMS_SITE_ID) ||\n (typeof import.meta !== 'undefined' && metaEnv?.CMS_SITE_ID) ||\n '';\n const contentUrl =\n options.contentUrl ||\n (typeof process !== 'undefined' && process.env?.CMS_CONTENT_URL) ||\n (typeof import.meta !== 'undefined' && metaEnv?.CMS_CONTENT_URL) ||\n '';\n if (siteId && contentUrl) {\n client = createCmsClient({\n siteId,\n contentUrl,\n });\n }\n }\n\n if (!previewToken) {\n return new Response('Preview token is missing', {\n status: 400,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n if (!client) {\n return new Response('CMS client is missing or not configured', {\n status: 500,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n let draftBundle: ContentBundle;\n try {\n draftBundle = await client.getBundle({ previewToken });\n } catch (err) {\n const status = (err as { status?: number })?.status;\n if (status === 401 || status === 403 || status === 404) {\n return new Response('Preview token is not valid for this site', {\n status: 404,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n console.error(err);\n return new Response('Failed to load preview content', {\n status: 502,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n // Run downstream request within the draft bundle context\n if (context.locals) {\n context.locals.__cms_is_draft = true;\n context.locals.__cms_draft_bundle = draftBundle;\n }\n\n let finalResponse: Response;\n setActiveDraftBundle(draftBundle);\n try {\n finalResponse = await runWithDraftBundle(draftBundle, async () => {\n let response: Response;\n if (isPreviewRoute) {\n const basePath = pathname.replace(/^\\/_preview/, '') || '/';\n if (typeof context.rewrite === 'function') {\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_IS_REWRITING__ = true;\n }\n try {\n const rewritten = await context.rewrite(basePath);\n if (rewritten) {\n response = rewritten as Response;\n } else {\n response = await next();\n }\n } finally {\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_IS_REWRITING__ = false;\n }\n }\n } else {\n response = await next();\n }\n } else {\n response = await next();\n }\n\n const contentType = response?.headers?.get ? response.headers.get('content-type') : '';\n const isStaticAsset = Boolean(\n pathname.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|webp|woff|woff2|ttf|json|map)$/i),\n );\n const isHtml =\n (typeof contentType === 'string' && contentType.includes('text/html')) ||\n (!contentType && !isStaticAsset);\n\n if (isHtml) {\n const html = await response.text();\n const bridgeScript = buildBridgeScript({\n editorOrigins: options.editorOrigins,\n });\n const scriptTag = `<script>${bridgeScript}</script>`;\n const modifiedHtml = html.includes('</body>')\n ? html.replace('</body>', `${scriptTag}</body>`)\n : `${html}${scriptTag}`;\n\n const newHeaders = new Headers(response.headers);\n if (!newHeaders.has('content-type')) {\n newHeaders.set('content-type', 'text/html; charset=utf-8');\n }\n newHeaders.delete('content-length');\n newHeaders.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');\n newHeaders.set('X-Robots-Tag', 'noindex, nofollow');\n\n return new Response(modifiedHtml, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n });\n }\n\n const nonHtmlHeaders = new Headers(response.headers);\n nonHtmlHeaders.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');\n nonHtmlHeaders.set('X-Robots-Tag', 'noindex, nofollow');\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: nonHtmlHeaders,\n });\n });\n } finally {\n setActiveDraftBundle(null);\n }\n\n return finalResponse;\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { defineCollection } from '../chunk-7E3XJLKX.js';
1
+ import { defineCollection } from '../chunk-SGHAANOW.js';
2
2
  import '../chunk-DMLOBKYE.js';
3
3
  import { z } from '@407dev/blocks';
4
4
 
package/dist/index.d.ts CHANGED
@@ -21,6 +21,9 @@ declare function defineCollection<TSchema extends z.ZodTypeAny>(options: DefineC
21
21
  declare function getEntries<T extends CollectionHandle<z.ZodTypeAny> | string>(handleOrKey: T): Array<CollectionEntry<InferEntryContent<T>>>;
22
22
  declare function getEntry<T extends CollectionHandle<z.ZodTypeAny> | string>(handleOrKey: T, slug: string): CollectionEntry<InferEntryContent<T>> | null;
23
23
  declare function collectionPaths<T extends CollectionHandle<z.ZodTypeAny> | string>(handleOrKey: T): Promise<Array<CollectionStaticPath<InferEntryContent<T>>>>;
24
+ declare function collectionAttrs<T extends CollectionHandle<z.ZodTypeAny> | string>(handleOrKey: T): {
25
+ 'data-cms-collection': string;
26
+ };
24
27
 
25
28
  declare function createEntryDualCallableHelper<TValue = unknown, TDefault = TValue>(typeId: string, publicName: string, collectionKey: string, slug: string, defaultPath?: string): DualCallableHelper<TValue, TDefault>;
26
29
  type EntryScopeAccessor = {
@@ -57,6 +60,9 @@ declare function cmsEntryAttr(collectionKey: string, slug?: string): {
57
60
  'data-cms-collection': string;
58
61
  'data-cms-entry'?: string;
59
62
  };
63
+ declare function cmsCollectionAttr(collectionKey: string): {
64
+ 'data-cms-collection': string;
65
+ };
60
66
  declare function cmsEntryFieldAttr(path: string): {
61
67
  'data-cms-entry-field': string;
62
68
  };
@@ -69,6 +75,7 @@ type CmsF = FieldHelpersMap & {
69
75
  entry: typeof getEntry;
70
76
  defineCollection: typeof defineCollection;
71
77
  collectionPaths: typeof collectionPaths;
78
+ collectionAttrs: typeof collectionAttrs;
72
79
  };
73
80
  declare const f: CmsF;
74
81
 
@@ -232,4 +239,4 @@ interface SitemapRouteItem {
232
239
  */
233
240
  declare function renderSitemapXml(routes: SitemapRouteItem[], options: RenderSitemapOptions): string;
234
241
 
235
- export { type BuildHeadTagsOptions, CmsAstroOptions, CmsClient, CmsClientConfig, type CmsF, CmsRedirect, CmsSiteConfig, CollectionEntry, CollectionHandle, CollectionStaticPath, ContentBundle, DEFAULT_EDITOR_ORIGINS, DefineCollectionOptions, DualCallableHelper, type EntryScopeAccessor, FieldHelpersMap, FieldScope, type GetPreviewDataOptions, GroupDefinition, type HeadRouteInput, type HeadTag, type ImageTransformOptions, InferEntryContent, KNOWN_NODES, type LinkMarkAttrs, type PreviewBundleResult, type RenderRobotsOptions, type RenderSitemapOptions, type RichTextNodeShape, type RichTextRenderOptions, RouteSeo, type SitemapRouteItem, VerifyTokenResult, buildCdnImageUrl, buildHeadTags, buildSrcSet, bundleReady, clearMissingFieldWarnings, cms, cmsAstro, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionPaths, createCmsClient, createEntryDualCallableHelper, createEntryScope, createScope, defineCollection, defineGroup, entryScope, escapeHtml, f, getActiveBundle, getBuildBundle, getClient, getEntries, getEntry, getLinkMarkAttrs, getMissingFieldWarnings, getPreviewData, initCmsClient, isBundleReady, isCdnTransformableUrl, isDraftMode, markBundleReady, parseRichTextDoc, recordMissingField, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml, resolveEditorOrigins, runWithDraftBundle, setActiveDraftBundle, setBuildBundle, setClient, signPreviewToken, updateBundleFieldValue, verifyPreviewToken };
242
+ export { type BuildHeadTagsOptions, CmsAstroOptions, CmsClient, CmsClientConfig, type CmsF, CmsRedirect, CmsSiteConfig, CollectionEntry, CollectionHandle, CollectionStaticPath, ContentBundle, DEFAULT_EDITOR_ORIGINS, DefineCollectionOptions, DualCallableHelper, type EntryScopeAccessor, FieldHelpersMap, FieldScope, type GetPreviewDataOptions, GroupDefinition, type HeadRouteInput, type HeadTag, type ImageTransformOptions, InferEntryContent, KNOWN_NODES, type LinkMarkAttrs, type PreviewBundleResult, type RenderRobotsOptions, type RenderSitemapOptions, type RichTextNodeShape, type RichTextRenderOptions, RouteSeo, type SitemapRouteItem, VerifyTokenResult, buildCdnImageUrl, buildHeadTags, buildSrcSet, bundleReady, clearMissingFieldWarnings, cms, cmsAstro, cmsCollectionAttr, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionAttrs, collectionPaths, createCmsClient, createEntryDualCallableHelper, createEntryScope, createScope, defineCollection, defineGroup, entryScope, escapeHtml, f, getActiveBundle, getBuildBundle, getClient, getEntries, getEntry, getLinkMarkAttrs, getMissingFieldWarnings, getPreviewData, initCmsClient, isBundleReady, isCdnTransformableUrl, isDraftMode, markBundleReady, parseRichTextDoc, recordMissingField, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml, resolveEditorOrigins, runWithDraftBundle, setActiveDraftBundle, setBuildBundle, setClient, signPreviewToken, updateBundleFieldValue, verifyPreviewToken };
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { mintDevPreviewToken } from './chunk-7LMUFCWX.js';
2
2
  export { signPreviewToken, verifyPreviewToken } from './chunk-7LMUFCWX.js';
3
- import { collectionPaths, defineCollection, getEntry, getEntries, markBundleReady } from './chunk-7E3XJLKX.js';
4
- export { bundleReady, collectionPaths, defineCollection, getEntries, getEntry, isBundleReady, markBundleReady } from './chunk-7E3XJLKX.js';
5
- import { initCmsClient, buildBridgeScript, getClient } from './chunk-QYUVAKMC.js';
6
- export { createCmsClient, createPreviewMiddleware, getClient, initCmsClient, setClient } from './chunk-QYUVAKMC.js';
3
+ import { collectionAttrs, collectionPaths, defineCollection, getEntry, getEntries, markBundleReady, cmsEntryAttr, cmsGroupAttr } from './chunk-SGHAANOW.js';
4
+ export { bundleReady, cmsCollectionAttr, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionAttrs, collectionPaths, defineCollection, getEntries, getEntry, isBundleReady, markBundleReady } from './chunk-SGHAANOW.js';
5
+ import { initCmsClient, buildBridgeScript, getClient } from './chunk-YCQMH2T7.js';
6
+ export { createCmsClient, createPreviewMiddleware, getClient, initCmsClient, setClient } from './chunk-YCQMH2T7.js';
7
7
  import './chunk-B4YYLS7Y.js';
8
8
  import { getActiveBundle, recordMissingField, getMissingFieldWarnings, clearMissingFieldWarnings } from './chunk-DMLOBKYE.js';
9
9
  export { clearMissingFieldWarnings, getActiveBundle, getBuildBundle, getMissingFieldWarnings, isDraftMode, recordMissingField, runWithDraftBundle, setActiveDraftBundle, setBuildBundle, updateBundleFieldValue } from './chunk-DMLOBKYE.js';
@@ -185,26 +185,6 @@ function renderRichTextHtml(doc, options = {}) {
185
185
  }
186
186
  return renderNode(root);
187
187
  }
188
-
189
- // src/fields/attrs.ts
190
- function cmsFieldAttr(key) {
191
- return { "data-cms-field": key };
192
- }
193
- function cmsGroupAttr(groupName, prefix) {
194
- return { "data-cms-group": `${groupName}:${prefix}` };
195
- }
196
- function cmsEntryAttr(collectionKey, slug) {
197
- if (slug) {
198
- return {
199
- "data-cms-collection": collectionKey,
200
- "data-cms-entry": slug
201
- };
202
- }
203
- return { "data-cms-collection": collectionKey };
204
- }
205
- function cmsEntryFieldAttr(path2) {
206
- return { "data-cms-entry-field": path2 };
207
- }
208
188
  var DEFAULT_TAGS = {
209
189
  text: "span",
210
190
  number: "span",
@@ -574,7 +554,8 @@ var f = {
574
554
  entries: getEntries,
575
555
  entry: getEntry,
576
556
  defineCollection,
577
- collectionPaths
557
+ collectionPaths,
558
+ collectionAttrs
578
559
  };
579
560
 
580
561
  // src/head.ts
@@ -792,22 +773,42 @@ function cmsAstro(options = {}) {
792
773
  }
793
774
  const activeClient = getClient();
794
775
  if (activeClient) {
776
+ let bundle;
795
777
  try {
796
778
  const devPreviewToken = command === "dev" ? await mintDevPreviewToken(activeClient.siteId, effectivePreviewSecret) : null;
797
- const bundle = await activeClient.getBundle(
779
+ bundle = await activeClient.getBundle(
798
780
  devPreviewToken ? { previewToken: devPreviewToken } : void 0
799
781
  );
782
+ } catch (err) {
783
+ if (command === "build") {
784
+ const status = err?.status;
785
+ if (status === 404) {
786
+ logger.warn(
787
+ "CMS bundle not found (no published version yet); building without it."
788
+ );
789
+ } else if (status !== void 0) {
790
+ throw err;
791
+ } else {
792
+ const url = `${activeClient.contentUrl.replace(/\/+$/, "")}/content/${activeClient.siteId}/bundle`;
793
+ const message = err instanceof Error ? err.message : String(err);
794
+ throw new Error(
795
+ `Failed to fetch CMS bundle from ${url} (unreachable): ${message}`,
796
+ {
797
+ cause: err
798
+ }
799
+ );
800
+ }
801
+ }
802
+ }
803
+ if (bundle) {
800
804
  markBundleReady(bundle);
801
805
  const cmsDir = path.resolve(process.cwd(), ".cms");
802
- if (!fs.existsSync(cmsDir)) {
803
- fs.mkdirSync(cmsDir, { recursive: true });
804
- }
806
+ fs.mkdirSync(cmsDir, { recursive: true });
805
807
  fs.writeFileSync(
806
808
  path.join(cmsDir, "bundle.json"),
807
809
  JSON.stringify(bundle, null, 2),
808
810
  "utf-8"
809
811
  );
810
- } catch {
811
812
  }
812
813
  }
813
814
  },
@@ -951,6 +952,6 @@ ${urlEntries.join("\n")}
951
952
  `;
952
953
  }
953
954
 
954
- export { KNOWN_NODES, buildCdnImageUrl, buildHeadTags, buildSrcSet, cms, cmsAstro, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, createEntryDualCallableHelper, createEntryScope, createScope, defineGroup, entryScope, escapeHtml, f, getLinkMarkAttrs, getPreviewData, isCdnTransformableUrl, parseRichTextDoc, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml };
955
+ export { KNOWN_NODES, buildCdnImageUrl, buildHeadTags, buildSrcSet, cms, cmsAstro, createEntryDualCallableHelper, createEntryScope, createScope, defineGroup, entryScope, escapeHtml, f, getLinkMarkAttrs, getPreviewData, isCdnTransformableUrl, parseRichTextDoc, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml };
955
956
  //# sourceMappingURL=index.js.map
956
957
  //# sourceMappingURL=index.js.map