@glw907/cairn-cms 0.60.0 → 0.62.1

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 (281) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/dist/components/AdminLayout.svelte +152 -229
  3. package/dist/components/CairnAdmin.svelte +13 -42
  4. package/dist/components/CairnLogo.svelte +1 -6
  5. package/dist/components/CairnMediaLibrary.svelte +821 -1210
  6. package/dist/components/CairnTidySettings.svelte +194 -261
  7. package/dist/components/CairnTidySettings.svelte.d.ts +1 -1
  8. package/dist/components/ComponentForm.svelte +110 -185
  9. package/dist/components/ComponentInsertDialog.svelte +163 -283
  10. package/dist/components/ConceptList.svelte +111 -191
  11. package/dist/components/ConfirmPage.svelte +5 -12
  12. package/dist/components/CsrfField.svelte +5 -11
  13. package/dist/components/DeleteDialog.svelte +15 -42
  14. package/dist/components/EditPage.svelte +781 -1205
  15. package/dist/components/EditorToolbar.svelte +108 -170
  16. package/dist/components/HelpHome.svelte +824 -0
  17. package/dist/components/HelpHome.svelte.d.ts +22 -0
  18. package/dist/components/IconPicker.svelte +23 -53
  19. package/dist/components/LinkPicker.svelte +34 -58
  20. package/dist/components/LoginPage.svelte +14 -27
  21. package/dist/components/ManageEditors.svelte +3 -15
  22. package/dist/components/MarkdownEditor.svelte +689 -957
  23. package/dist/components/MarkdownHelpDialog.svelte +12 -27
  24. package/dist/components/MediaCaptureCard.svelte +18 -57
  25. package/dist/components/MediaFigureControl.svelte +32 -71
  26. package/dist/components/MediaHeroField.svelte +210 -329
  27. package/dist/components/MediaInsertPopover.svelte +156 -283
  28. package/dist/components/MediaPicker.svelte +67 -131
  29. package/dist/components/NavTree.svelte +46 -78
  30. package/dist/components/RenameDialog.svelte +16 -43
  31. package/dist/components/ShortcutsDialog.svelte +9 -13
  32. package/dist/components/ShortcutsGrid.svelte +1 -2
  33. package/dist/components/TidyReview.svelte +140 -248
  34. package/dist/components/WebLinkDialog.svelte +19 -40
  35. package/dist/components/cairn-admin.css +4 -0
  36. package/dist/components/client-ingest.d.ts +16 -8
  37. package/dist/components/client-ingest.js +12 -6
  38. package/dist/components/editor-media.js +16 -8
  39. package/dist/components/editor-placeholder.d.ts +4 -2
  40. package/dist/components/editor-tidy.d.ts +24 -12
  41. package/dist/components/editor-tidy.js +8 -4
  42. package/dist/components/index.d.ts +1 -0
  43. package/dist/components/index.js +1 -0
  44. package/dist/components/link-completion.d.ts +12 -6
  45. package/dist/components/link-completion.js +12 -6
  46. package/dist/components/markdown-directives.d.ts +9 -6
  47. package/dist/components/markdown-directives.js +9 -6
  48. package/dist/components/markdown-format.d.ts +7 -2
  49. package/dist/components/markdown-format.js +59 -28
  50. package/dist/components/markdown-reference.d.ts +8 -0
  51. package/dist/components/markdown-reference.js +22 -0
  52. package/dist/components/media-upload-outcome.d.ts +12 -6
  53. package/dist/components/objective-errors.d.ts +8 -4
  54. package/dist/components/objective-errors.js +8 -4
  55. package/dist/components/preview-doc.d.ts +4 -2
  56. package/dist/components/preview-doc.js +4 -2
  57. package/dist/components/spellcheck.d.ts +57 -29
  58. package/dist/components/spellcheck.js +50 -20
  59. package/dist/components/tidy-categorize.d.ts +20 -10
  60. package/dist/components/tidy-categorize.js +16 -8
  61. package/dist/components/tidy-validate.d.ts +12 -6
  62. package/dist/components/tidy-validate.js +20 -10
  63. package/dist/components/topbar-context.d.ts +4 -2
  64. package/dist/content/advisories.d.ts +51 -0
  65. package/dist/content/advisories.js +79 -0
  66. package/dist/content/compose.d.ts +4 -2
  67. package/dist/content/compose.js +1 -0
  68. package/dist/content/excerpt.js +4 -2
  69. package/dist/content/getting-started.d.ts +18 -0
  70. package/dist/content/getting-started.js +12 -0
  71. package/dist/content/links.d.ts +16 -8
  72. package/dist/content/links.js +12 -6
  73. package/dist/content/manifest.d.ts +36 -18
  74. package/dist/content/manifest.js +32 -16
  75. package/dist/content/media-refs.d.ts +4 -2
  76. package/dist/content/media-refs.js +4 -2
  77. package/dist/content/media-rewrite.d.ts +8 -4
  78. package/dist/content/media-rewrite.js +76 -38
  79. package/dist/content/schema.d.ts +20 -10
  80. package/dist/content/site-dictionary.d.ts +4 -2
  81. package/dist/content/site-dictionary.js +8 -4
  82. package/dist/content/types.d.ts +97 -42
  83. package/dist/delivery/CairnHead.svelte +8 -11
  84. package/dist/delivery/content-index.d.ts +16 -8
  85. package/dist/delivery/feeds.js +4 -2
  86. package/dist/delivery/json-ld.d.ts +3 -0
  87. package/dist/delivery/json-ld.js +3 -0
  88. package/dist/delivery/manifest.d.ts +4 -2
  89. package/dist/delivery/manifest.js +4 -2
  90. package/dist/delivery/public-routes.d.ts +12 -6
  91. package/dist/delivery/public-routes.js +4 -2
  92. package/dist/delivery/seo-fields.d.ts +12 -6
  93. package/dist/delivery/seo-fields.js +8 -4
  94. package/dist/delivery/site-indexes.d.ts +4 -2
  95. package/dist/delivery/site-resolver.d.ts +4 -2
  96. package/dist/delivery/site-resolver.js +4 -2
  97. package/dist/doctor/cloudflare-api.d.ts +6 -0
  98. package/dist/doctor/cloudflare-api.js +6 -0
  99. package/dist/doctor/index.d.ts +12 -6
  100. package/dist/doctor/report.d.ts +3 -0
  101. package/dist/doctor/report.js +3 -0
  102. package/dist/doctor/run.d.ts +3 -0
  103. package/dist/doctor/run.js +3 -0
  104. package/dist/doctor/types.d.ts +10 -2
  105. package/dist/doctor/types.js +6 -0
  106. package/dist/doctor/wrangler-config.d.ts +7 -2
  107. package/dist/doctor/wrangler-config.js +3 -0
  108. package/dist/email.d.ts +4 -2
  109. package/dist/env.d.ts +0 -3
  110. package/dist/env.js +0 -3
  111. package/dist/github/branches.d.ts +4 -2
  112. package/dist/github/branches.js +4 -2
  113. package/dist/github/signing.d.ts +1 -1
  114. package/dist/github/signing.js +2 -2
  115. package/dist/log/events.d.ts +1 -1
  116. package/dist/media/bulk-delete-plan.d.ts +8 -4
  117. package/dist/media/config.d.ts +12 -6
  118. package/dist/media/config.js +16 -8
  119. package/dist/media/delivery-bucket.d.ts +4 -2
  120. package/dist/media/library-entry.d.ts +4 -2
  121. package/dist/media/library-entry.js +4 -2
  122. package/dist/media/manifest.d.ts +29 -15
  123. package/dist/media/manifest.js +29 -16
  124. package/dist/media/naming.d.ts +12 -6
  125. package/dist/media/naming.js +24 -12
  126. package/dist/media/orphan-scan.d.ts +4 -2
  127. package/dist/media/reconcile.d.ts +21 -11
  128. package/dist/media/reconcile.js +12 -6
  129. package/dist/media/reference.d.ts +8 -4
  130. package/dist/media/reference.js +12 -6
  131. package/dist/media/rewrite-plan.d.ts +12 -6
  132. package/dist/media/sniff.d.ts +4 -2
  133. package/dist/media/sniff.js +28 -14
  134. package/dist/media/store.d.ts +16 -8
  135. package/dist/media/store.js +4 -2
  136. package/dist/media/transform-url.d.ts +12 -6
  137. package/dist/media/transform-url.js +8 -4
  138. package/dist/media/usage.d.ts +8 -4
  139. package/dist/nav/site-config.d.ts +16 -8
  140. package/dist/render/component-grammar.d.ts +23 -10
  141. package/dist/render/component-grammar.js +19 -8
  142. package/dist/render/component-insert.d.ts +8 -4
  143. package/dist/render/component-insert.js +4 -2
  144. package/dist/render/component-reference.d.ts +4 -2
  145. package/dist/render/component-reference.js +4 -2
  146. package/dist/render/component-validate.d.ts +3 -0
  147. package/dist/render/component-validate.js +3 -0
  148. package/dist/render/glyph.d.ts +4 -2
  149. package/dist/render/glyph.js +4 -2
  150. package/dist/render/pipeline.d.ts +20 -10
  151. package/dist/render/pipeline.js +4 -2
  152. package/dist/render/registry.d.ts +40 -20
  153. package/dist/render/registry.js +16 -8
  154. package/dist/render/rehype-dispatch.d.ts +22 -8
  155. package/dist/render/rehype-dispatch.js +22 -8
  156. package/dist/render/remark-directives.d.ts +3 -0
  157. package/dist/render/remark-directives.js +3 -0
  158. package/dist/render/remark-figure.d.ts +4 -2
  159. package/dist/render/remark-figure.js +4 -2
  160. package/dist/render/resolve-links.d.ts +4 -2
  161. package/dist/render/resolve-links.js +4 -2
  162. package/dist/render/resolve-media.d.ts +16 -8
  163. package/dist/render/resolve-media.js +12 -6
  164. package/dist/sveltekit/admin-dispatch.d.ts +2 -0
  165. package/dist/sveltekit/admin-dispatch.js +9 -3
  166. package/dist/sveltekit/auth-routes.d.ts +3 -0
  167. package/dist/sveltekit/auth-routes.js +3 -0
  168. package/dist/sveltekit/cairn-admin.d.ts +16 -5
  169. package/dist/sveltekit/cairn-admin.js +26 -10
  170. package/dist/sveltekit/content-routes.d.ts +191 -86
  171. package/dist/sveltekit/content-routes.js +295 -107
  172. package/dist/sveltekit/editors-routes.d.ts +3 -0
  173. package/dist/sveltekit/editors-routes.js +3 -0
  174. package/dist/sveltekit/guard.d.ts +4 -2
  175. package/dist/sveltekit/guard.js +4 -2
  176. package/dist/sveltekit/https-required-page.d.ts +1 -1
  177. package/dist/sveltekit/https-required-page.js +1 -1
  178. package/dist/sveltekit/index.d.ts +1 -1
  179. package/dist/sveltekit/media-route.d.ts +1 -2
  180. package/dist/sveltekit/media-route.js +13 -8
  181. package/dist/sveltekit/nav-routes.d.ts +7 -2
  182. package/dist/sveltekit/nav-routes.js +3 -0
  183. package/dist/sveltekit/types.d.ts +4 -2
  184. package/dist/vite/index.d.ts +32 -16
  185. package/dist/vite/index.js +52 -26
  186. package/dist/vite/resolve-root.d.ts +8 -4
  187. package/dist/vite/resolve-root.js +4 -2
  188. package/package.json +8 -2
  189. package/src/lib/components/AdminLayout.svelte +22 -0
  190. package/src/lib/components/CairnAdmin.svelte +3 -0
  191. package/src/lib/components/CairnTidySettings.svelte +2 -2
  192. package/src/lib/components/ComponentForm.svelte +0 -1
  193. package/src/lib/components/EditPage.svelte +133 -41
  194. package/src/lib/components/HelpHome.svelte +850 -0
  195. package/src/lib/components/MarkdownHelpDialog.svelte +4 -15
  196. package/src/lib/components/client-ingest.ts +20 -10
  197. package/src/lib/components/editor-media.ts +20 -10
  198. package/src/lib/components/editor-placeholder.ts +12 -6
  199. package/src/lib/components/editor-tidy.ts +28 -14
  200. package/src/lib/components/index.ts +1 -0
  201. package/src/lib/components/link-completion.ts +12 -6
  202. package/src/lib/components/markdown-directives.ts +13 -8
  203. package/src/lib/components/markdown-format.ts +63 -30
  204. package/src/lib/components/markdown-reference.ts +30 -0
  205. package/src/lib/components/media-upload-outcome.ts +12 -6
  206. package/src/lib/components/objective-errors.ts +16 -8
  207. package/src/lib/components/preview-doc.ts +4 -2
  208. package/src/lib/components/spellcheck.ts +92 -40
  209. package/src/lib/components/tidy-categorize.ts +28 -14
  210. package/src/lib/components/tidy-validate.ts +28 -14
  211. package/src/lib/components/topbar-context.ts +4 -2
  212. package/src/lib/content/advisories.ts +141 -0
  213. package/src/lib/content/compose.ts +5 -2
  214. package/src/lib/content/excerpt.ts +4 -2
  215. package/src/lib/content/getting-started.ts +31 -0
  216. package/src/lib/content/links.ts +16 -8
  217. package/src/lib/content/manifest.ts +36 -18
  218. package/src/lib/content/media-refs.ts +4 -2
  219. package/src/lib/content/media-rewrite.ts +100 -50
  220. package/src/lib/content/schema.ts +20 -10
  221. package/src/lib/content/site-dictionary.ts +8 -4
  222. package/src/lib/content/types.ts +97 -42
  223. package/src/lib/delivery/content-index.ts +16 -8
  224. package/src/lib/delivery/feeds.ts +4 -2
  225. package/src/lib/delivery/json-ld.ts +3 -0
  226. package/src/lib/delivery/manifest.ts +4 -2
  227. package/src/lib/delivery/public-routes.ts +16 -8
  228. package/src/lib/delivery/seo-fields.ts +12 -6
  229. package/src/lib/delivery/site-indexes.ts +4 -2
  230. package/src/lib/delivery/site-resolver.ts +4 -2
  231. package/src/lib/doctor/cloudflare-api.ts +6 -0
  232. package/src/lib/doctor/index.ts +12 -6
  233. package/src/lib/doctor/report.ts +3 -0
  234. package/src/lib/doctor/run.ts +3 -0
  235. package/src/lib/doctor/types.ts +10 -2
  236. package/src/lib/doctor/wrangler-config.ts +7 -2
  237. package/src/lib/email.ts +4 -2
  238. package/src/lib/env.ts +0 -3
  239. package/src/lib/github/branches.ts +4 -2
  240. package/src/lib/github/signing.ts +2 -2
  241. package/src/lib/log/events.ts +1 -0
  242. package/src/lib/media/bulk-delete-plan.ts +8 -4
  243. package/src/lib/media/config.ts +24 -12
  244. package/src/lib/media/delivery-bucket.ts +4 -2
  245. package/src/lib/media/library-entry.ts +4 -2
  246. package/src/lib/media/manifest.ts +33 -18
  247. package/src/lib/media/naming.ts +24 -12
  248. package/src/lib/media/orphan-scan.ts +4 -2
  249. package/src/lib/media/reconcile.ts +21 -11
  250. package/src/lib/media/reference.ts +12 -6
  251. package/src/lib/media/rewrite-plan.ts +12 -6
  252. package/src/lib/media/sniff.ts +28 -14
  253. package/src/lib/media/store.ts +16 -8
  254. package/src/lib/media/transform-url.ts +12 -6
  255. package/src/lib/media/usage.ts +8 -4
  256. package/src/lib/nav/site-config.ts +16 -8
  257. package/src/lib/render/component-grammar.ts +23 -10
  258. package/src/lib/render/component-insert.ts +8 -4
  259. package/src/lib/render/component-reference.ts +4 -2
  260. package/src/lib/render/component-validate.ts +3 -0
  261. package/src/lib/render/glyph.ts +4 -2
  262. package/src/lib/render/pipeline.ts +20 -10
  263. package/src/lib/render/registry.ts +44 -22
  264. package/src/lib/render/rehype-dispatch.ts +22 -8
  265. package/src/lib/render/remark-directives.ts +3 -0
  266. package/src/lib/render/remark-figure.ts +4 -2
  267. package/src/lib/render/resolve-links.ts +4 -2
  268. package/src/lib/render/resolve-media.ts +16 -8
  269. package/src/lib/sveltekit/admin-dispatch.ts +10 -4
  270. package/src/lib/sveltekit/auth-routes.ts +3 -0
  271. package/src/lib/sveltekit/cairn-admin.ts +37 -15
  272. package/src/lib/sveltekit/content-routes.ts +492 -197
  273. package/src/lib/sveltekit/editors-routes.ts +3 -0
  274. package/src/lib/sveltekit/guard.ts +4 -2
  275. package/src/lib/sveltekit/https-required-page.ts +1 -1
  276. package/src/lib/sveltekit/index.ts +3 -0
  277. package/src/lib/sveltekit/media-route.ts +13 -8
  278. package/src/lib/sveltekit/nav-routes.ts +7 -2
  279. package/src/lib/sveltekit/types.ts +4 -2
  280. package/src/lib/vite/index.ts +60 -30
  281. package/src/lib/vite/resolve-root.ts +8 -4
@@ -20,14 +20,18 @@ export interface AttributeField {
20
20
  source: string;
21
21
  message: string;
22
22
  };
23
- /** A pure, browser-safe cross-field validator. Returns an error string, or null when valid.
23
+ /**
24
+ * A pure, browser-safe cross-field validator. Returns an error string, or null when valid.
24
25
  * Receives the field's value and the full {@link ComponentValues} so a rule can read sibling
25
- * fields. The picker wraps the call in try/catch so an author's throw never crashes the form. */
26
+ * fields. The picker wraps the call in try/catch so an author's throw never crashes the form.
27
+ */
26
28
  validate?: (value: string | boolean, all: ComponentValues) => string | null;
27
29
  }
28
30
  export type SlotKind = 'markdown' | 'inline' | 'repeatable';
29
- /** One named content region of a component. The slots named `title` and `body` are special: `title`
30
- * serializes to the directive `[label]` and `body` to the unmarked content (see the canonical grammar). */
31
+ /**
32
+ * One named content region of a component. The slots named `title` and `body` are special: `title`
33
+ * serializes to the directive `[label]` and `body` to the unmarked content (see the canonical grammar).
34
+ */
31
35
  export interface SlotDef {
32
36
  name: string;
33
37
  label: string;
@@ -36,14 +40,18 @@ export interface SlotDef {
36
40
  help?: string;
37
41
  /** For `kind: 'repeatable'`: the fields composing each list item (v1 uses the first field). */
38
42
  itemFields?: AttributeField[];
39
- /** For `kind: 'repeatable'`: derives a row's label from its item values and zero-based index.
40
- * When it returns nothing, the picker falls back to `${label} ${index + 1}`. */
43
+ /**
44
+ * For `kind: 'repeatable'`: derives a row's label from its item values and zero-based index.
45
+ * When it returns nothing, the picker falls back to `${label} ${index + 1}`.
46
+ */
41
47
  itemLabel?: (item: Record<string, string | boolean>, index: number) => string;
42
48
  }
43
- /** The structured input a component's `build` receives. The engine stamps the component's
49
+ /**
50
+ * The structured input a component's `build` receives. The engine stamps the component's
44
51
  * attributes and partitions its slots from the rendered hast, so `build` arranges hast and
45
52
  * never walks the tree. `slot(name)` returns a slot's rendered children (title, body, or any
46
- * named slot); `items(name)` returns a repeatable slot's items, one child list per item. */
53
+ * named slot); `items(name)` returns a repeatable slot's items, one child list per item.
54
+ */
47
55
  export interface ComponentContext {
48
56
  /** Declared attribute values, keyed by attribute key. Booleans are real booleans. */
49
57
  attributes: Record<string, string | boolean>;
@@ -64,9 +72,11 @@ export interface ComponentDef {
64
72
  description: string;
65
73
  /** Markdown scaffold inserted at the cursor by the editor palette. */
66
74
  insertTemplate?: string;
67
- /** Build the final hast element from the component context (attributes plus partitioned
75
+ /**
76
+ * Build the final hast element from the component context (attributes plus partitioned
68
77
  * slots). The engine stamps the entrance-stagger ordinal (`data-rise`) on the top-level
69
- * result, so a build fn stays free of any motion concern. */
78
+ * result, so a build fn stays free of any motion concern.
79
+ */
70
80
  build: (ctx: ComponentContext) => Element;
71
81
  /** Optional role-to-default-icon, e.g. `{ caution: 'warning' }`. */
72
82
  defaultIconByRole?: Record<string, string>;
@@ -82,8 +92,10 @@ export interface ComponentDef {
82
92
  group?: string;
83
93
  /** Omit from the top-level picker (for a nested or round-trip-only component). */
84
94
  hidden?: boolean;
85
- /** A structured sample the picker seeds the form with and renders through the same path a real
86
- * insert takes. Declaring `preview` is what opts the component into the two-pane configure layout. */
95
+ /**
96
+ * A structured sample the picker seeds the form with and renders through the same path a real
97
+ * insert takes. Declaring `preview` is what opts the component into the two-pane configure layout.
98
+ */
87
99
  preview?: {
88
100
  attributes?: Record<string, string | boolean>;
89
101
  slots?: Record<string, string | string[]>;
@@ -97,9 +109,11 @@ export interface ComponentRegistry {
97
109
  /** The component's first `type:'icon'` attribute, or undefined when it declares none. */
98
110
  iconField(name: string): AttributeField | undefined;
99
111
  }
100
- /** The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
112
+ /**
113
+ * The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
101
114
  * becomes `dataAttrTone`. The directive stamp writes it and the rehype dispatch reads it, so both
102
- * sides derive the name from this one helper rather than spelling the capitalize twice. */
115
+ * sides derive the name from this one helper rather than spelling the capitalize twice.
116
+ */
103
117
  export declare function dataAttrProp(key: string): string;
104
118
  /**
105
119
  * Build a registry from a site's component definitions. The single source the render
@@ -108,16 +122,22 @@ export declare function dataAttrProp(key: string): string;
108
122
  export declare function defineRegistry({ components }: {
109
123
  components: ComponentDef[];
110
124
  }): ComponentRegistry;
111
- /** Guided-form values for one component: attribute values keyed by attribute key, slot values keyed
112
- * by slot name (a string, or a string list for a repeatable slot). */
125
+ /**
126
+ * Guided-form values for one component: attribute values keyed by attribute key, slot values keyed
127
+ * by slot name (a string, or a string list for a repeatable slot).
128
+ */
113
129
  export interface ComponentValues {
114
130
  attributes: Record<string, string | boolean>;
115
131
  slots: Record<string, string | string[]>;
116
132
  }
117
- /** Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
118
- * and empty slot values ([] for repeatable, '' otherwise). */
133
+ /**
134
+ * Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
135
+ * and empty slot values ([] for repeatable, '' otherwise).
136
+ */
119
137
  export declare function emptyValues(def: ComponentDef): ComponentValues;
120
- /** Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
138
+ /**
139
+ * Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
121
140
  * with `def.preview.attributes` and `def.preview.slots` overlaid (a shallow merge per side). When
122
- * the def declares no `preview`, returns exactly the {@link emptyValues} output. */
141
+ * the def declares no `preview`, returns exactly the {@link emptyValues} output.
142
+ */
123
143
  export declare function previewValues(def: ComponentDef): ComponentValues;
@@ -1,12 +1,16 @@
1
- /** The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
1
+ /**
2
+ * The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
2
3
  * becomes `dataAttrTone`. The directive stamp writes it and the rehype dispatch reads it, so both
3
- * sides derive the name from this one helper rather than spelling the capitalize twice. */
4
+ * sides derive the name from this one helper rather than spelling the capitalize twice.
5
+ */
4
6
  export function dataAttrProp(key) {
5
7
  return `dataAttr${key.charAt(0).toUpperCase()}${key.slice(1)}`;
6
8
  }
7
- /** A component's first `type:'icon'` attribute, or undefined when it declares none. Both the
9
+ /**
10
+ * A component's first `type:'icon'` attribute, or undefined when it declares none. Both the
8
11
  * construction-time guard and the registry's `iconField` derive the icon field from this one
9
- * predicate rather than spelling the `type === 'icon'` find twice. */
12
+ * predicate rather than spelling the `type === 'icon'` find twice.
13
+ */
10
14
  function findIconField(def) {
11
15
  return def.attributes?.find((field) => field.type === 'icon');
12
16
  }
@@ -35,8 +39,10 @@ export function defineRegistry({ components }) {
35
39
  },
36
40
  };
37
41
  }
38
- /** Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
39
- * and empty slot values ([] for repeatable, '' otherwise). */
42
+ /**
43
+ * Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
44
+ * and empty slot values ([] for repeatable, '' otherwise).
45
+ */
40
46
  export function emptyValues(def) {
41
47
  const attributes = {};
42
48
  for (const field of def.attributes ?? []) {
@@ -48,9 +54,11 @@ export function emptyValues(def) {
48
54
  }
49
55
  return { attributes, slots };
50
56
  }
51
- /** Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
57
+ /**
58
+ * Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
52
59
  * with `def.preview.attributes` and `def.preview.slots` overlaid (a shallow merge per side). When
53
- * the def declares no `preview`, returns exactly the {@link emptyValues} output. */
60
+ * the def declares no `preview`, returns exactly the {@link emptyValues} output.
61
+ */
54
62
  export function previewValues(def) {
55
63
  const base = emptyValues(def);
56
64
  if (!def.preview)
@@ -1,9 +1,17 @@
1
1
  import type { Root, Element, ElementContent } from 'hast';
2
2
  import { type ComponentContext, type ComponentRegistry } from './registry.js';
3
+ /**
4
+ *
5
+ */
3
6
  export declare function isElement(node: ElementContent | undefined): node is Element;
4
- /** Read a declared string attribute off the component context, returning undefined for a boolean or
5
- * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats. */
7
+ /**
8
+ * Read a declared string attribute off the component context, returning undefined for a boolean or
9
+ * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats.
10
+ */
6
11
  export declare function strAttr(ctx: ComponentContext, key: string): string | undefined;
12
+ /**
13
+ *
14
+ */
7
15
  export declare function strProp(node: Element, name: string): string | undefined;
8
16
  /** Wrap a pre-built glyph in an ec-icon span; secondary role adds the modifier. */
9
17
  export declare function iconSpan(glyphEl: Element, role?: string): Element;
@@ -11,18 +19,24 @@ export declare function iconSpan(glyphEl: Element, role?: string): Element;
11
19
  export type MakeIcon = (name: string, role?: string) => Element;
12
20
  /** Section wrapper: `<section class=…><div class="card-body">…</div></section>`. */
13
21
  export declare function cardShell(classes: string[], body: ElementContent[]): Element;
14
- /** Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
22
+ /**
23
+ * Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
15
24
  * Pass the title's inline children, an optional pre-built icon element, and an optional heading
16
25
  * level (default 2). This factors the icon-plus-heading head that a titled component build would
17
- * otherwise rebuild by hand (the shape the removed `splitHead` produced). */
26
+ * otherwise rebuild by hand (the shape the removed `splitHead` produced).
27
+ */
18
28
  export declare function headRow(title: ElementContent[], icon?: Element, level?: number): Element;
19
- /** Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
20
- * text nodes so the bare list serializes without newlines. Returns that <ul>. */
29
+ /**
30
+ * Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
31
+ * text nodes so the bare list serializes without newlines. Returns that <ul>.
32
+ */
21
33
  export declare function markFirstList(children: ElementContent[]): Element | undefined;
22
- /** Rehype transformer: dispatch each stamped element through its registry `build`
34
+ /**
35
+ * Rehype transformer: dispatch each stamped element through its registry `build`
23
36
  * fn. When `stagger` is on, each top-level primitive gets a `data-rise` attribute
24
37
  * carrying its document-order index (0, 1, 2, …); the site's CSS maps that ordinal
25
38
  * to an entrance delay. The index is inert, so a consumer's sanitize floor can keep
26
39
  * `data-rise` while dropping `style`. Nested primitives never get it. Non-primitive
27
- * content (lede, intro paragraphs, the page-toc nav) passes through untouched. */
40
+ * content (lede, intro paragraphs, the page-toc nav) passes through untouched.
41
+ */
28
42
  export declare function rehypeDispatch(registry: ComponentRegistry, stagger?: boolean): (tree: Root) => void;
@@ -1,10 +1,15 @@
1
1
  import { h } from 'hastscript';
2
2
  import { dataAttrProp } from './registry.js';
3
+ /**
4
+ *
5
+ */
3
6
  export function isElement(node) {
4
7
  return !!node && node.type === 'element';
5
8
  }
6
- /** Read a declared string attribute off the component context, returning undefined for a boolean or
7
- * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats. */
9
+ /**
10
+ * Read a declared string attribute off the component context, returning undefined for a boolean or
11
+ * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats.
12
+ */
8
13
  export function strAttr(ctx, key) {
9
14
  const value = ctx.attributes[key];
10
15
  return typeof value === 'string' ? value : undefined;
@@ -12,6 +17,9 @@ export function strAttr(ctx, key) {
12
17
  // hast Properties values are PropertyValue (string | number | boolean | array | null).
13
18
  // Directive markers (dataPrimitive/dataRole/dataAttr<Key>) are always stamped as strings;
14
19
  // this reads them back with that guarantee instead of casting at each call site.
20
+ /**
21
+ *
22
+ */
15
23
  export function strProp(node, name) {
16
24
  const value = node.properties?.[name];
17
25
  return typeof value === 'string' ? value : undefined;
@@ -25,10 +33,12 @@ export function iconSpan(glyphEl, role) {
25
33
  export function cardShell(classes, body) {
26
34
  return h('section', { className: classes }, [h('div', { className: ['card-body'] }, body)]);
27
35
  }
28
- /** Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
36
+ /**
37
+ * Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
29
38
  * Pass the title's inline children, an optional pre-built icon element, and an optional heading
30
39
  * level (default 2). This factors the icon-plus-heading head that a titled component build would
31
- * otherwise rebuild by hand (the shape the removed `splitHead` produced). */
40
+ * otherwise rebuild by hand (the shape the removed `splitHead` produced).
41
+ */
32
42
  export function headRow(title, icon, level = 2) {
33
43
  const children = [];
34
44
  if (icon)
@@ -36,8 +46,10 @@ export function headRow(title, icon, level = 2) {
36
46
  children.push(h(`h${level}`, { className: ['card-title'] }, title));
37
47
  return h('div', { className: ['ec-head'] }, children);
38
48
  }
39
- /** Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
40
- * text nodes so the bare list serializes without newlines. Returns that <ul>. */
49
+ /**
50
+ * Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
51
+ * text nodes so the bare list serializes without newlines. Returns that <ul>.
52
+ */
41
53
  export function markFirstList(children) {
42
54
  const ul = children.find((c) => isElement(c) && c.tagName === 'ul');
43
55
  if (ul) {
@@ -133,12 +145,14 @@ function transformNode(node, registry) {
133
145
  };
134
146
  return def.build(ctx);
135
147
  }
136
- /** Rehype transformer: dispatch each stamped element through its registry `build`
148
+ /**
149
+ * Rehype transformer: dispatch each stamped element through its registry `build`
137
150
  * fn. When `stagger` is on, each top-level primitive gets a `data-rise` attribute
138
151
  * carrying its document-order index (0, 1, 2, …); the site's CSS maps that ordinal
139
152
  * to an entrance delay. The index is inert, so a consumer's sanitize floor can keep
140
153
  * `data-rise` while dropping `style`. Nested primitives never get it. Non-primitive
141
- * content (lede, intro paragraphs, the page-toc nav) passes through untouched. */
154
+ * content (lede, intro paragraphs, the page-toc nav) passes through untouched.
155
+ */
142
156
  export function rehypeDispatch(registry, stagger) {
143
157
  return (tree) => {
144
158
  let idx = 0;
@@ -1,3 +1,6 @@
1
1
  import type { Root } from 'mdast';
2
2
  import { type ComponentRegistry } from './registry.js';
3
+ /**
4
+ *
5
+ */
3
6
  export declare function remarkDirectiveStamp(registry: ComponentRegistry): (tree: Root) => void;
@@ -51,6 +51,9 @@ function restoreLiteral(node) {
51
51
  // component name, icon, and role. No structure is built here; the rehype
52
52
  // dispatcher rewrites the marked elements once their children are hast.
53
53
  // Text and leaf directives are restored to literal text (accidental prose colons).
54
+ /**
55
+ *
56
+ */
54
57
  export function remarkDirectiveStamp(registry) {
55
58
  const known = new Set(registry.names);
56
59
  return (tree) => {
@@ -1,4 +1,6 @@
1
1
  import type { Root } from 'mdast';
2
- /** Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
3
- * is left to remarkDirectiveStamp, which already skips unregistered names. */
2
+ /**
3
+ * Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
4
+ * is left to remarkDirectiveStamp, which already skips unregistered names.
5
+ */
4
6
  export declare function remarkFigure(): (tree: Root) => void;
@@ -42,8 +42,10 @@ function trimLeadingNewline(children) {
42
42
  }
43
43
  return children;
44
44
  }
45
- /** Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
46
- * is left to remarkDirectiveStamp, which already skips unregistered names. */
45
+ /**
46
+ * Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
47
+ * is left to remarkDirectiveStamp, which already skips unregistered names.
48
+ */
47
49
  export function remarkFigure() {
48
50
  return (tree) => {
49
51
  visit(tree, 'containerDirective', (node) => {
@@ -1,7 +1,9 @@
1
1
  import type { VFile } from 'vfile';
2
2
  /** The VFile data key the renderer sets the per-call resolver under. */
3
3
  export declare const CAIRN_RESOLVE = "cairnResolve";
4
- /** Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
4
+ /**
5
+ * Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
5
6
  * pass through. A missing target is marked with the cairn-broken-link class (the resolver returns
6
- * undefined) or, when the resolver throws, the error propagates and fails the build. */
7
+ * undefined) or, when the resolver throws, the error propagates and fails the build.
8
+ */
7
9
  export declare function remarkResolveCairnLinks(): (tree: unknown, file: VFile) => void;
@@ -7,9 +7,11 @@ import { visit } from 'unist-util-visit';
7
7
  import { parseCairnToken } from '../content/links.js';
8
8
  /** The VFile data key the renderer sets the per-call resolver under. */
9
9
  export const CAIRN_RESOLVE = 'cairnResolve';
10
- /** Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
10
+ /**
11
+ * Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
11
12
  * pass through. A missing target is marked with the cairn-broken-link class (the resolver returns
12
- * undefined) or, when the resolver throws, the error propagates and fails the build. */
13
+ * undefined) or, when the resolver throws, the error propagates and fails the build.
14
+ */
13
15
  export function remarkResolveCairnLinks() {
14
16
  return (tree, file) => {
15
17
  const resolve = file.data[CAIRN_RESOLVE];
@@ -4,31 +4,39 @@ import { type MediaManifest } from '../media/manifest.js';
4
4
  import type { ResolvedAssetConfig } from '../media/config.js';
5
5
  /** The VFile data key the renderer sets the per-call media resolver under. */
6
6
  export declare const MEDIA_RESOLVE = "mediaResolve";
7
- /** Resolve a media reference to its delivery URL. `undefined` is a preview miss (the plugin marks
7
+ /**
8
+ * Resolve a media reference to its delivery URL. `undefined` is a preview miss (the plugin marks
8
9
  * the image broken); a resolver that throws is the build backstop (the error propagates out of
9
- * render and fails the build), exactly like LinkResolve. */
10
+ * render and fails the build), exactly like LinkResolve.
11
+ */
10
12
  export type MediaResolve = (ref: MediaRef) => string | undefined;
11
- /** Build the per-call media resolver, closing over the manifest and the resolved config. The
13
+ /**
14
+ * Build the per-call media resolver, closing over the manifest and the resolved config. The
12
15
  * returned resolver looks a ref's content hash up in the manifest and builds the canonical delivery
13
16
  * path from the manifest entry's slug and ext, not the token's, so a rename never breaks the
14
17
  * reference. With a preset and zone transformations on it returns the variant URL; without a preset,
15
18
  * or when transformations are off, it returns the bare full-size path so a fresh zone with Image
16
19
  * Transformations disabled serves correct thumbnails rather than dead /cdn-cgi/image URLs. It returns
17
- * undefined when media is off or no entry carries the hash (the preview-miss backstop). */
20
+ * undefined when media is off or no entry carries the hash (the preview-miss backstop).
21
+ */
18
22
  export declare function makeMediaResolver(manifest: MediaManifest, resolved: ResolvedAssetConfig, opts?: {
19
23
  preset?: string;
20
24
  }): MediaResolve;
21
- /** A resolver backed by the lean `mediaTargets` projection, for the admin preview. It mirrors
25
+ /**
26
+ * A resolver backed by the lean `mediaTargets` projection, for the admin preview. It mirrors
22
27
  * manifestLinkResolver: a hash present in the projection builds the slug delivery path
23
28
  * (`/media/<slug>.<hash>.<ext>`); a miss returns undefined, so the render step marks the image
24
29
  * broken rather than throwing. Pure over the projection, with no manifest and no config, so the
25
- * edit page reaches it with the data it actually has. */
30
+ * edit page reaches it with the data it actually has.
31
+ */
26
32
  export declare function manifestMediaResolver(targets: Record<string, {
27
33
  slug: string;
28
34
  ext: string;
29
35
  contentType: string;
30
36
  }>): MediaResolve;
31
- /** Resolve media: image nodes against the VFile's resolver. A non-media src and a malformed token
37
+ /**
38
+ * Resolve media: image nodes against the VFile's resolver. A non-media src and a malformed token
32
39
  * pass through. A missing target is marked with the cairn-broken-media class (the resolver returns
33
- * undefined) or, when the resolver throws, the error propagates and fails the build. */
40
+ * undefined) or, when the resolver throws, the error propagates and fails the build.
41
+ */
34
42
  export declare function remarkResolveMedia(): (tree: unknown, file: VFile) => void;
@@ -11,13 +11,15 @@ import { presetUrl } from '../media/transform-url.js';
11
11
  import { log } from '../log/index.js';
12
12
  /** The VFile data key the renderer sets the per-call media resolver under. */
13
13
  export const MEDIA_RESOLVE = 'mediaResolve';
14
- /** Build the per-call media resolver, closing over the manifest and the resolved config. The
14
+ /**
15
+ * Build the per-call media resolver, closing over the manifest and the resolved config. The
15
16
  * returned resolver looks a ref's content hash up in the manifest and builds the canonical delivery
16
17
  * path from the manifest entry's slug and ext, not the token's, so a rename never breaks the
17
18
  * reference. With a preset and zone transformations on it returns the variant URL; without a preset,
18
19
  * or when transformations are off, it returns the bare full-size path so a fresh zone with Image
19
20
  * Transformations disabled serves correct thumbnails rather than dead /cdn-cgi/image URLs. It returns
20
- * undefined when media is off or no entry carries the hash (the preview-miss backstop). */
21
+ * undefined when media is off or no entry carries the hash (the preview-miss backstop).
22
+ */
21
23
  export function makeMediaResolver(manifest, resolved, opts) {
22
24
  return (ref) => {
23
25
  if (!resolved.enabled)
@@ -36,11 +38,13 @@ export function makeMediaResolver(manifest, resolved, opts) {
36
38
  return path;
37
39
  };
38
40
  }
39
- /** A resolver backed by the lean `mediaTargets` projection, for the admin preview. It mirrors
41
+ /**
42
+ * A resolver backed by the lean `mediaTargets` projection, for the admin preview. It mirrors
40
43
  * manifestLinkResolver: a hash present in the projection builds the slug delivery path
41
44
  * (`/media/<slug>.<hash>.<ext>`); a miss returns undefined, so the render step marks the image
42
45
  * broken rather than throwing. Pure over the projection, with no manifest and no config, so the
43
- * edit page reaches it with the data it actually has. */
46
+ * edit page reaches it with the data it actually has.
47
+ */
44
48
  export function manifestMediaResolver(targets) {
45
49
  return (ref) => {
46
50
  const entry = targets[ref.hash];
@@ -49,9 +53,11 @@ export function manifestMediaResolver(targets) {
49
53
  return publicPath(entry.slug, ref.hash, entry.ext, 'slug');
50
54
  };
51
55
  }
52
- /** Resolve media: image nodes against the VFile's resolver. A non-media src and a malformed token
56
+ /**
57
+ * Resolve media: image nodes against the VFile's resolver. A non-media src and a malformed token
53
58
  * pass through. A missing target is marked with the cairn-broken-media class (the resolver returns
54
- * undefined) or, when the resolver throws, the error propagates and fails the build. */
59
+ * undefined) or, when the resolver throws, the error propagates and fails the build.
60
+ */
55
61
  export function remarkResolveMedia() {
56
62
  return (tree, file) => {
57
63
  const resolve = file.data[MEDIA_RESOLVE];
@@ -21,6 +21,8 @@ export type AdminView = {
21
21
  view: 'media';
22
22
  } | {
23
23
  view: 'settings';
24
+ } | {
25
+ view: 'help';
24
26
  };
25
27
  /**
26
28
  * Parse a raw `URL.pathname` (the caller passes `event.url.pathname`, never a SvelteKit rest
@@ -3,10 +3,12 @@ import { isValidId } from '../content/ids.js';
3
3
  /**
4
4
  * Fixed first segments that never resolve as concepts. The engine only allows posts and pages
5
5
  * today, so no collision is possible, but the parser does not depend on that: a reserved
6
- * segment wins before concept lookup. `settings`, `nav`, and `media` are decided as views below,
7
- * so they are not in this no-view set.
6
+ * segment wins before concept lookup. `nav` and `media` are decided as views below, so they are
7
+ * not in this no-view set. `settings` and `help` are decided as views below AND kept here, so a
8
+ * deeper path (or a future concept claiming the segment) can never reach the two-segment edit
9
+ * branch through them.
8
10
  */
9
- const RESERVED_SEGMENTS = new Set(['login', 'auth', 'editors', 'nav', 'settings']);
11
+ const RESERVED_SEGMENTS = new Set(['login', 'auth', 'editors', 'nav', 'settings', 'help']);
10
12
  /**
11
13
  * Parse a raw `URL.pathname` (the caller passes `event.url.pathname`, never a SvelteKit rest
12
14
  * param) into the admin view it names. A single trailing slash is tolerated everywhere; empty
@@ -51,6 +53,10 @@ export function parseAdminPath(pathname, concepts) {
51
53
  // (the two-segment branch never matches settings), which is the correct shape.
52
54
  if (head === 'settings')
53
55
  return { view: 'settings' };
56
+ // help is its own view (the Help home, editor-help Pass 2), decided here like settings. It is
57
+ // also in the reserved set so /admin/help/<anything> 404s and no concept can claim the segment.
58
+ if (head === 'help')
59
+ return { view: 'help' };
54
60
  if (RESERVED_SEGMENTS.has(head))
55
61
  return null;
56
62
  const concept = findConcept(concepts, head);
@@ -19,6 +19,9 @@ export type RequestResult = {
19
19
  status: 'throttled';
20
20
  sent: false;
21
21
  };
22
+ /**
23
+ *
24
+ */
22
25
  export declare function createAuthRoutes(config: AuthRoutesConfig): {
23
26
  loginLoad: (event: RequestContext) => {
24
27
  siteName: string;
@@ -19,6 +19,9 @@ function scrubSendError(err) {
19
19
  .replace(/([?&]token=)[^&\s"'<]+/g, '$1[redacted]')
20
20
  .slice(0, 300);
21
21
  }
22
+ /**
23
+ *
24
+ */
22
25
  export function createAuthRoutes(config) {
23
26
  const send = config.send ?? cloudflareSend;
24
27
  /**
@@ -1,4 +1,4 @@
1
- import { type ContentRoutesDeps, type LayoutData, type ListData, type EditData, type MediaLibraryData, type SettingsData } from './content-routes.js';
1
+ import { type ContentRoutesDeps, type LayoutData, type ListData, type EditData, type MediaLibraryData, type SettingsData, type HelpData } from './content-routes.js';
2
2
  import { type NavLoadData } from './nav-routes.js';
3
3
  import type { AuthBranding, SendMagicLink } from '../email.js';
4
4
  import type { AuthEnv, Editor } from '../auth/types.js';
@@ -14,15 +14,19 @@ export interface AdminEvent extends EventBase<GithubKeyEnv & AuthEnv> {
14
14
  cookies: CookieJar;
15
15
  setHeaders(headers: Record<string, string>): void;
16
16
  }
17
- /** Injectable dependencies. Branding defaults from the runtime's siteName and sender, so a
17
+ /**
18
+ * Injectable dependencies. Branding defaults from the runtime's siteName and sender, so a
18
19
  * site overrides it only to change the magic-link email identity; `send` and `mintToken`
19
- * are the same seams the underlying factories take. */
20
+ * are the same seams the underlying factories take.
21
+ */
20
22
  export interface CairnAdminDeps {
21
23
  branding?: AuthBranding;
22
24
  send?: SendMagicLink;
23
25
  mintToken?: ContentRoutesDeps['mintToken'];
24
- /** Build the Anthropic client for the tidy action. Forwarded to the content routes; a site that
25
- * enables tidy injects a stub here to avoid a real network call. Defaults to the real SDK client. */
26
+ /**
27
+ * Build the Anthropic client for the tidy action. Forwarded to the content routes; a site that
28
+ * enables tidy injects a stub here to avoid a real network call. Defaults to the real SDK client.
29
+ */
26
30
  anthropic?: ContentRoutesDeps['anthropic'];
27
31
  /** The tidy action's own request deadline in milliseconds. Forwarded to the content routes. */
28
32
  tidyTimeoutMs?: ContentRoutesDeps['tidyTimeoutMs'];
@@ -74,7 +78,14 @@ export type AdminData = {
74
78
  view: 'settings';
75
79
  layout: LayoutData;
76
80
  page: SettingsData;
81
+ } | {
82
+ view: 'help';
83
+ layout: LayoutData;
84
+ page: HelpData;
77
85
  };
86
+ /**
87
+ *
88
+ */
78
89
  export declare function createCairnAdmin(runtime: CairnRuntime, deps?: CairnAdminDeps): {
79
90
  load: (event: AdminEvent) => Promise<AdminData>;
80
91
  actions: {