@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
@@ -10,6 +10,9 @@ import { createAuthRoutes } from './auth-routes.js';
10
10
  import { createContentRoutes, } from './content-routes.js';
11
11
  import { createEditorRoutes } from './editors-routes.js';
12
12
  import { createNavRoutes } from './nav-routes.js';
13
+ /**
14
+ *
15
+ */
13
16
  export function createCairnAdmin(runtime, deps = {}) {
14
17
  // The runtime already composes the site name and the sender identity, so the magic-link
15
18
  // branding needs no second copy of either unless a site overrides it.
@@ -27,11 +30,13 @@ export function createCairnAdmin(runtime, deps = {}) {
27
30
  const editors = createEditorRoutes();
28
31
  // The nav surface exists only when the site configures a menu; without one its view is a 404.
29
32
  const nav = runtime.navMenu ? createNavRoutes(runtime, { mintToken: deps.mintToken }) : null;
30
- /** Build the event a wrapped content load reads. The catch-all route carries only a rest
33
+ /**
34
+ * Build the event a wrapped content load reads. The catch-all route carries only a rest
31
35
  * param, so `concept` and `id` are synthesized from the parsed view. The override names
32
36
  * each field explicitly rather than spreading: a real RequestEvent's fields can sit behind
33
37
  * getters a bare spread copies poorly, and the structural ContentEvent contract needs only
34
- * these. */
38
+ * these.
39
+ */
35
40
  function contentEvent(event, params) {
36
41
  return {
37
42
  url: event.url,
@@ -42,9 +47,11 @@ export function createCairnAdmin(runtime, deps = {}) {
42
47
  cookies: event.cookies,
43
48
  };
44
49
  }
45
- /** Serve the admin view the pathname names, or a 404 for any shape the parser refuses.
50
+ /**
51
+ * Serve the admin view the pathname names, or a 404 for any shape the parser refuses.
46
52
  * The authed views run the layout load and the view load concurrently; both mint a GitHub
47
- * token, and the installation-token cache coalesces the mints into one signing. */
53
+ * token, and the installation-token cache coalesces the mints into one signing.
54
+ */
48
55
  async function load(event) {
49
56
  const view = parseAdminPath(event.url.pathname, runtime.concepts);
50
57
  if (!view)
@@ -91,11 +98,18 @@ export function createCairnAdmin(runtime, deps = {}) {
91
98
  const [layout, page] = await Promise.all([content.layoutLoad(delegated), content.settingsLoad(delegated)]);
92
99
  return { view: 'settings', layout, page };
93
100
  }
101
+ case 'help': {
102
+ const delegated = contentEvent(event, {});
103
+ const [layout, page] = await Promise.all([content.layoutLoad(delegated), content.helpLoad(delegated)]);
104
+ return { view: 'help', layout, page };
105
+ }
94
106
  }
95
107
  }
96
- /** Wrap a delegate in the parse-and-check every action shares: parse the pathname exactly
108
+ /**
109
+ * Wrap a delegate in the parse-and-check every action shares: parse the pathname exactly
97
110
  * as load does, 404 on a null parse or a view outside the allowed set, then hand the
98
- * narrowed view to the delegate. */
111
+ * narrowed view to the delegate.
112
+ */
99
113
  function viewAction(allowed, delegate) {
100
114
  return async (event) => {
101
115
  const view = parseAdminPath(event.url.pathname, runtime.concepts);
@@ -106,13 +120,15 @@ export function createCairnAdmin(runtime, deps = {}) {
106
120
  };
107
121
  }
108
122
  // The topbar posts publishAll from every authed admin page; login and confirm may not.
109
- const authedViews = ['list', 'edit', 'editors', 'nav', 'media', 'settings'];
123
+ const authedViews = ['list', 'edit', 'editors', 'nav', 'media', 'settings', 'help'];
110
124
  // An editor signs out from wherever they are, so logout accepts any parsed view.
111
- const anyView = ['index', 'login', 'confirm', 'list', 'edit', 'editors', 'nav', 'media', 'settings'];
112
- /** The full admin action vocabulary, one named async function per action, so a site's
125
+ const anyView = ['index', 'login', 'confirm', 'list', 'edit', 'editors', 'nav', 'media', 'settings', 'help'];
126
+ /**
127
+ * The full admin action vocabulary, one named async function per action, so a site's
113
128
  * catch-all route exports `admin.actions` directly. Each wrapper stays thin: parse,
114
129
  * validate the view, synthesize the params the wrapped action reads, delegate. The
115
- * editor actions gate themselves with requireOwner, so no second gate is added here. */
130
+ * editor actions gate themselves with requireOwner, so no second gate is added here.
131
+ */
116
132
  const actions = {
117
133
  request: viewAction(['login'], (event) => auth.requestAction(event)),
118
134
  confirm: viewAction(['confirm'], (event) => auth.confirmAction(event)),
@@ -1,6 +1,9 @@
1
1
  import { fail } from '@sveltejs/kit';
2
+ import { type AdvisoryNotice } from '../content/advisories.js';
2
3
  import { type GithubKeyEnv } from '../github/credentials.js';
3
4
  import { type LinkTarget, type InboundLink } from '../content/manifest.js';
5
+ import { type GettingStarted } from '../content/getting-started.js';
6
+ import { type MarkdownReferenceRow } from '../components/markdown-reference.js';
4
7
  import type { TidyConventions } from '../nav/site-config.js';
5
8
  import type { MediaEntry } from '../media/manifest.js';
6
9
  import type { MediaLibrary, MediaLibraryEntry } from '../media/library-entry.js';
@@ -12,6 +15,7 @@ import type { BulkDeleteSkip } from '../media/bulk-delete-plan.js';
12
15
  import type { CookieJar, EventBase } from './types.js';
13
16
  import type { CairnRuntime, FrontmatterField, ResolvedPreview } from '../content/types.js';
14
17
  import type { Role } from '../auth/types.js';
18
+ export type { AdvisoryNotice, AdvisoryAction } from '../content/advisories.js';
15
19
  /** A sidebar concept entry: just enough to render the nav without shipping validators to the client. */
16
20
  export interface NavConcept {
17
21
  id: string;
@@ -32,13 +36,17 @@ export interface LayoutData {
32
36
  navLabel: string | null;
33
37
  /** The admin theme resolved for SSR: the persisted cookie choice, or the light default. */
34
38
  theme: 'cairn-admin' | 'cairn-admin-dark';
35
- /** The nav group labels the user has collapsed, from the persisted cookie. Read at SSR so a
36
- * collapsed group renders collapsed with no flash. Empty when none are collapsed. */
39
+ /**
40
+ * The nav group labels the user has collapsed, from the persisted cookie. Read at SSR so a
41
+ * collapsed group renders collapsed with no flash. Empty when none are collapsed.
42
+ */
37
43
  collapsedNav: string[];
38
44
  /** The session's CSRF double-submit token, rendered as a hidden field in every admin form. */
39
45
  csrf: string;
40
- /** Every entry with unpublished edits (a `cairn/` ref), for the topbar's publish-all action.
41
- * Null when GitHub is unreachable, so the topbar hides the action rather than lying. */
46
+ /**
47
+ * Every entry with unpublished edits (a `cairn/` ref), for the topbar's publish-all action.
48
+ * Null when GitHub is unreachable, so the topbar hides the action rather than lying.
49
+ */
42
50
  pendingEntries: {
43
51
  concept: string;
44
52
  id: string;
@@ -52,16 +60,20 @@ export interface EntrySummary {
52
60
  draft: boolean;
53
61
  /** Publish state derived from the ref set: live as-is, live with pending edits, or branch-only. */
54
62
  status: 'published' | 'edited' | 'new';
55
- /** The row's one-line summary: the manifest's indexed excerpt for a published row, the branch
56
- * frontmatter/body excerpt for a pending one, and null when neither yields text. */
63
+ /**
64
+ * The row's one-line summary: the manifest's indexed excerpt for a published row, the branch
65
+ * frontmatter/body excerpt for a pending one, and null when neither yields text.
66
+ */
57
67
  summary: string | null;
58
68
  }
59
69
  /** The concept list view's data. */
60
70
  export interface ListData {
61
71
  conceptId: string;
62
72
  label: string;
63
- /** The singular noun for the create affordances ("New post"); from the descriptor, which defaults
64
- * it to `label`. */
73
+ /**
74
+ * The singular noun for the create affordances ("New post"); from the descriptor, which defaults
75
+ * it to `label`.
76
+ */
65
77
  singular: string;
66
78
  /** Posts carry a date in the new-entry form; pages do not (concept routing, spec §7.2). */
67
79
  dated: boolean;
@@ -91,17 +103,21 @@ export interface EditData {
91
103
  slug: string;
92
104
  /** The site's link targets, for the preview resolver and the link picker; from the committed manifest. */
93
105
  linkTargets: LinkTarget[];
94
- /** The minimal media-resolver input the edit page builds its preview `resolveMedia` from, keyed by
95
- * the 16-hex content hash and parallel to `linkTargets`. Empty when media is off or the read fails. */
106
+ /**
107
+ * The minimal media-resolver input the edit page builds its preview `resolveMedia` from, keyed by
108
+ * the 16-hex content hash and parallel to `linkTargets`. Empty when media is off or the read fails.
109
+ */
96
110
  mediaTargets: Record<string, {
97
111
  slug: string;
98
112
  ext: string;
99
113
  contentType: string;
100
114
  }>;
101
- /** The picker's human layer for each stored asset, keyed by the 16-hex content hash and projected
115
+ /**
116
+ * The picker's human layer for each stored asset, keyed by the 16-hex content hash and projected
102
117
  * from the same committed media manifest read that populates `mediaTargets`. The `hash` field
103
118
  * duplicates the key, so the picker can iterate `Object.values`. Empty when media is off or the
104
- * read fails (the same degradation path as `mediaTargets`). */
119
+ * read fails (the same degradation path as `mediaTargets`).
120
+ */
105
121
  mediaLibrary: MediaLibrary;
106
122
  /** The entries that link to this one, for the delete guard. Empty when nothing links here. */
107
123
  inboundLinks: InboundLink[];
@@ -113,107 +129,152 @@ export interface EditData {
113
129
  publishedFlash: boolean;
114
130
  /** True after a discard redirect (`?discarded=1`), for the confirmation strip. */
115
131
  discardedFlash: boolean;
116
- /** The adapter's preview knob resolved for this entry's concept (its `byConcept` override,
132
+ /**
133
+ * The adapter's preview knob resolved for this entry's concept (its `byConcept` override,
117
134
  * when one exists, applied over the top-level values); null when the site sets none, which
118
- * leaves the frame rendering unstyled markup behind a hint. */
135
+ * leaves the frame rendering unstyled markup behind a hint.
136
+ */
119
137
  preview: ResolvedPreview | null;
120
- /** The spellcheck dictionary file for the site's configured dialect (default US English), resolved
138
+ /**
139
+ * The spellcheck dictionary file for the site's configured dialect (default US English), resolved
121
140
  * once at compose. The editor resolves it to a real asset URL on the main thread and hands that URL
122
141
  * to the spellcheck Worker's `init`, the same way `mediaLibrary` is threaded in. Just the filename,
123
- * e.g. "dictionary-en-us.txt". */
142
+ * e.g. "dictionary-en-us.txt".
143
+ */
124
144
  spellcheckDictionary: string;
125
- /** The committed personal-dictionary words for the site (spec 1.6): the durable, shared, reviewable
145
+ /**
146
+ * The committed personal-dictionary words for the site (spec 1.6): the durable, shared, reviewable
126
147
  * layer the editor seeds the spellcheck Worker's personal set from, the way `mediaLibrary` is handed
127
148
  * in. Read from the git-committed `dictionary.txt` at editor load; empty when the file is absent or
128
149
  * unreadable (the editor degrades to dialect-only). The dialect dictionary and the session ignore
129
- * list are the other two layers; only this one is committed. */
150
+ * list are the other two layers; only this one is committed.
151
+ */
130
152
  siteDictionary: string[];
131
- /** The editor-tier tidy facts the review surface needs (spec 2.5): whether tidy is enabled, the model
153
+ /**
154
+ * The editor-tier tidy facts the review surface needs (spec 2.5): whether tidy is enabled, the model
132
155
  * that runs (for the head pill), and the RESOLVED conventions (the only data source for a
133
156
  * normalization's because-line and the local category inference). The API key never appears here, it
134
- * is a Worker secret. `enabled` false hides the Tidy control. */
157
+ * is a Worker secret. `enabled` false hides the Tidy control.
158
+ */
135
159
  tidy: {
136
160
  enabled: boolean;
137
161
  model: string;
138
162
  conventions: TidyConventions;
139
163
  };
164
+ /** Non-blocking editor advisories built server-side; today the cross-branch address collision. */
165
+ advisories: AdvisoryNotice[];
140
166
  }
141
- /** One asset's where-used overlay, kept separate from MediaLibraryEntry so the picker's shared
142
- * projection stays decoupled from the Library-only usage facts. */
167
+ /**
168
+ * One asset's where-used overlay, kept separate from MediaLibraryEntry so the picker's shared
169
+ * projection stays decoupled from the Library-only usage facts.
170
+ */
143
171
  export interface MediaUsageInfo {
144
172
  /** Distinct content entries that reference the asset (count by distinct concept+id). */
145
173
  count: number;
146
174
  /** Every where-used row (published and edit-branch origins), for the detail's grouped list. */
147
175
  entries: UsageEntry[];
148
176
  }
149
- /** The Media Library screen's data: the unioned assets, the per-hash usage overlay, and the
177
+ /**
178
+ * The Media Library screen's data: the unioned assets, the per-hash usage overlay, and the
150
179
  * degraded-load error. The usage overlay is keyed by content hash; an asset with no references
151
- * simply has no key, which the screen renders as "no references found". */
180
+ * simply has no key, which the screen renders as "no references found".
181
+ */
152
182
  export interface MediaLibraryData {
153
183
  assets: MediaLibraryEntry[];
154
184
  /** Per-hash usage overlay, kept separate from MediaLibraryEntry so the popover stays decoupled. */
155
185
  usage: Record<string, MediaUsageInfo>;
156
- /** The degraded-load error: a failed token mint or media read. This slot is the failure of THIS
186
+ /**
187
+ * The degraded-load error: a failed token mint or media read. This slot is the failure of THIS
157
188
  * load, distinct from a prior action's conflict error (see `flashError`), so a read failure and a
158
- * redirected commit conflict never overwrite each other. */
189
+ * redirected commit conflict never overwrite each other.
190
+ */
159
191
  error: string | null;
160
- /** The success flash a redirected action carries: `deleted` from `?deleted=1`, `updated` from
192
+ /**
193
+ * The success flash a redirected action carries: `deleted` from `?deleted=1`, `updated` from
161
194
  * `?updated=1`, `replaced` from `?replaced=1`, `altPropagated` from `?altPropagated=1`,
162
195
  * `bulkDeleted` from `?bulkDeleted=1`, `orphansPurged` from `?orphansPurged=1`, null otherwise.
163
- * The component renders a polite success strip for each. */
196
+ * The component renders a polite success strip for each.
197
+ */
164
198
  flash: 'deleted' | 'updated' | 'replaced' | 'altPropagated' | 'bulkDeleted' | 'orphansPurged' | null;
165
- /** A redirected action's conflict error read from `?error=` (a commit-conflict bounce). Kept in
166
- * its own slot rather than the degraded-load `error` above, so the two never collide. */
199
+ /**
200
+ * A redirected action's conflict error read from `?error=` (a commit-conflict bounce). Kept in
201
+ * its own slot rather than the degraded-load `error` above, so the two never collide.
202
+ */
167
203
  flashError: string | null;
168
204
  }
169
- /** The two-tier tidy settings load (spec 2.8, Task 15). The developer tier is read-only: `enabled`,
205
+ /**
206
+ * The two-tier tidy settings load (spec 2.8, Task 15). The developer tier is read-only: `enabled`,
170
207
  * `keyConfigured`, and `model`/`modelLabel` are deploy-time facts the editor sees but cannot change.
171
208
  * The editor tier is the resolved `conventions` block, written back through the save. The visibility
172
209
  * gate is truthful: `enabled` is true only when `tidy.enabled` is set AND the API key is present, so
173
210
  * the screen renders the convention list only then and the honest gate note otherwise. The key is a
174
211
  * Worker secret, so `keyConfigured` is the presence of `ANTHROPIC_API_KEY` in the load's env, never
175
- * the key itself; nothing here returns or logs the secret. */
212
+ * the key itself; nothing here returns or logs the secret.
213
+ */
176
214
  export interface SettingsData {
177
- /** The truthful gate: tidy is enabled AND the API key is present. The screen renders the editor
215
+ /**
216
+ * The truthful gate: tidy is enabled AND the API key is present. The screen renders the editor
178
217
  * tier only when this is true, and the honest gate note (a labelled region, no disabled controls)
179
- * otherwise. */
218
+ * otherwise.
219
+ */
180
220
  enabled: boolean;
181
- /** Whether `tidy.enabled` is set in the site config, independent of the key. The gate note's
182
- * checklist reads this to show which deploy-time step is still open. */
221
+ /**
222
+ * Whether `tidy.enabled` is set in the site config, independent of the key. The gate note's
223
+ * checklist reads this to show which deploy-time step is still open.
224
+ */
183
225
  tidyEnabled: boolean;
184
226
  /** Whether the API key secret is present in the Worker env. A presence flag, never the key. */
185
227
  keyConfigured: boolean;
186
228
  /** The model id (a developer-tier fact, read-only on the screen). */
187
229
  model: string;
188
- /** A plain-language label for the model id ("Claude Sonnet"), so the read-only fact is not a bare
189
- * jargon token. Falls back to the raw id for an unknown model. */
230
+ /**
231
+ * A plain-language label for the model id ("Claude Sonnet"), so the read-only fact is not a bare
232
+ * jargon token. Falls back to the raw id for an unknown model.
233
+ */
190
234
  modelLabel: string;
191
- /** The resolved editor-tier conventions: every field concrete, the screen's initial control state.
192
- * Present only when the gate is open; the gate state needs no conventions. */
235
+ /**
236
+ * The resolved editor-tier conventions: every field concrete, the screen's initial control state.
237
+ * Present only when the gate is open; the gate state needs no conventions.
238
+ */
193
239
  conventions: TidyConventions;
194
240
  /** The success flash a redirected save carries (`?saved=1`). */
195
241
  saved: boolean;
196
242
  /** A redirected save's validation or conflict error read from `?error=`. */
197
243
  error: string | null;
198
244
  }
199
- /** A refused settings save: a conflict bounce or a malformed conventions payload. Just the one-line
200
- * summary; the save commits nothing on a refusal. */
245
+ /**
246
+ * A refused settings save: a conflict bounce or a malformed conventions payload. Just the one-line
247
+ * summary; the save commits nothing on a refusal.
248
+ */
201
249
  export interface SettingsSaveFailure {
202
250
  error: string;
203
251
  }
252
+ /**
253
+ * The Help home's data: the derived getting-started progress, the full markdown reference (the
254
+ * component curates by group), and the optional support hand-off (rendered only when set).
255
+ */
256
+ export interface HelpData {
257
+ gettingStarted: GettingStarted;
258
+ reference: MarkdownReferenceRow[];
259
+ supportContact?: string;
260
+ }
204
261
  /** The structural event the content routes read; a real SvelteKit RequestEvent satisfies it. */
205
262
  export interface ContentEvent extends EventBase<GithubKeyEnv> {
206
263
  params: Record<string, string>;
207
- /** SvelteKit's cookie jar. The layout load reads the persisted admin theme and issues the CSRF
208
- * token. Optional for non-route callers. */
264
+ /**
265
+ * SvelteKit's cookie jar. The layout load reads the persisted admin theme and issues the CSRF
266
+ * token. Optional for non-route callers.
267
+ */
209
268
  cookies?: CookieJar;
210
269
  }
211
270
  /** Injectable dependencies; tests stub the token mint to avoid signing a real key. */
212
- /** The minimal Anthropic client surface the tidy action uses, typed structurally so the SDK's deep
271
+ /**
272
+ * The minimal Anthropic client surface the tidy action uses, typed structurally so the SDK's deep
213
273
  * generics never reach a public signature and so the integration test can inject a fake whose
214
274
  * `messages.create` it stubs. The real factory builds `new Anthropic({ apiKey })`, which satisfies
215
275
  * this shape. The success path reads only the text blocks, the model, the stop reason, and the usage
216
- * counts. */
276
+ * counts.
277
+ */
217
278
  export interface TidyClient {
218
279
  messages: {
219
280
  create(body: {
@@ -241,25 +302,33 @@ export interface TidyClient {
241
302
  };
242
303
  }
243
304
  export interface ContentRoutesDeps {
244
- /** Mint a GitHub App installation token from the Worker env. Defaults to the real signer.
245
- * A bare string works too; the routes await whatever comes back. */
305
+ /**
306
+ * Mint a GitHub App installation token from the Worker env. Defaults to the real signer.
307
+ * A bare string works too; the routes await whatever comes back.
308
+ */
246
309
  mintToken?: (env: GithubKeyEnv) => string | Promise<string>;
247
- /** Build the Anthropic client for the tidy action from the resolved API key. Defaults to the real
310
+ /**
311
+ * Build the Anthropic client for the tidy action from the resolved API key. Defaults to the real
248
312
  * SDK client. Injected in tests so `messages.create` is stubbed and no network call (or real key)
249
313
  * is ever needed. The factory runs only after the key is read from the env, so a disabled or
250
- * unconfigured site never constructs a client. */
314
+ * unconfigured site never constructs a client.
315
+ */
251
316
  anthropic?: (opts: {
252
317
  apiKey: string;
253
318
  }) => TidyClient;
254
- /** The tidy action's own request deadline in milliseconds, set shorter than the platform limit so a
319
+ /**
320
+ * The tidy action's own request deadline in milliseconds, set shorter than the platform limit so a
255
321
  * slow model call becomes a clean retryable fail(502) rather than a platform timeout. Defaults to
256
- * {@link DEFAULT_TIDY_TIMEOUT_MS}. Overridable in tests to assert the deadline path without waiting. */
322
+ * {@link DEFAULT_TIDY_TIMEOUT_MS}. Overridable in tests to assert the deadline path without waiting.
323
+ */
257
324
  tidyTimeoutMs?: number;
258
325
  }
259
- /** The successful tidy outcome (spec 2.1): the corrected markdown, the model that produced it, and the
326
+ /**
327
+ * The successful tidy outcome (spec 2.1): the corrected markdown, the model that produced it, and the
260
328
  * token usage. The diff is computed on the client (Task 12), so the server returns the plain text and
261
329
  * commits nothing. Admin-internal: consumed by the editor's review surface, not on the package's
262
- * sveltekit subpath, so it carries no reference page. */
330
+ * sveltekit subpath, so it carries no reference page.
331
+ */
263
332
  export interface TidyResult {
264
333
  corrected: string;
265
334
  model: string;
@@ -268,10 +337,12 @@ export interface TidyResult {
268
337
  output_tokens: number;
269
338
  };
270
339
  }
271
- /** A refused tidy: `fail(403)` on a failed CSRF check, `fail(503)` when tidy is disabled or the API
340
+ /**
341
+ * A refused tidy: `fail(403)` on a failed CSRF check, `fail(503)` when tidy is disabled or the API
272
342
  * key is missing, `fail(413)` for an over-long body, `fail(502)` for a deadline overrun, abort, or
273
343
  * model error (all retryable), `fail(422)` for a model refusal, `fail(400)` for a malformed body. Just
274
- * the one-line summary; the action commits nothing, so a refusal can never corrupt the entry. */
344
+ * the one-line summary; the action commits nothing, so a refusal can never corrupt the entry.
345
+ */
275
346
  export interface TidyFailure {
276
347
  error: string;
277
348
  }
@@ -298,9 +369,11 @@ export interface RenameFailure {
298
369
  /** The one-line human summary every content action failure carries. */
299
370
  error: string;
300
371
  }
301
- /** A refused media delete: `fail(404)` for an asset not committed on the default branch, or
372
+ /**
373
+ * A refused media delete: `fail(404)` for an asset not committed on the default branch, or
302
374
  * `fail(409)` when a fresh usage read finds the asset still in use and the typed-slug override
303
- * was not given. `fail(503)` covers media-off or a missing bucket binding. */
375
+ * was not given. `fail(503)` covers media-off or a missing bucket binding.
376
+ */
304
377
  export interface MediaDeleteRefusal {
305
378
  /** The one-line human summary every action failure carries. */
306
379
  error: string;
@@ -311,49 +384,63 @@ export interface MediaDeleteRefusal {
311
384
  /** The distinct-entry count behind the refusal; zero when the asset is uncommitted. */
312
385
  foundIn: number;
313
386
  }
314
- /** A refused media metadata edit: `fail(404)` for an asset not committed on the default branch, or
315
- * `fail(400)` for an invalid slug. */
387
+ /**
388
+ * A refused media metadata edit: `fail(404)` for an asset not committed on the default branch, or
389
+ * `fail(400)` for an invalid slug.
390
+ */
316
391
  export interface MediaUpdateFailure {
317
392
  /** The one-line human summary every action failure carries. */
318
393
  error: string;
319
394
  }
320
- /** A refused media replace: `fail(409)` when a fresh usage read finds the asset still in use and the
395
+ /**
396
+ * A refused media replace: `fail(409)` when a fresh usage read finds the asset still in use and the
321
397
  * typed-slug override was not given, or `fail(503)` when usage cannot be verified (fail closed) or the
322
- * bucket is unbound. Mirrors MediaDeleteRefusal: the asset hash, the where-used rows, and the count. */
398
+ * bucket is unbound. Mirrors MediaDeleteRefusal: the asset hash, the where-used rows, and the count.
399
+ */
323
400
  export interface MediaReplaceFailure {
324
401
  error: string;
325
402
  hash: string;
326
403
  usage: UsageEntry[];
327
404
  foundIn: number;
328
405
  }
329
- /** A refused media alt-propagation: `fail(503)` when usage cannot be verified across main and every
406
+ /**
407
+ * A refused media alt-propagation: `fail(503)` when usage cannot be verified across main and every
330
408
  * open branch (fail closed), or the bucket is unbound. Just the one-line summary; alt fill has no
331
- * typed-slug gate. */
409
+ * typed-slug gate.
410
+ */
332
411
  export interface MediaAltPropagateFailure {
333
412
  error: string;
334
413
  }
335
- /** The personal-dictionary add outcome (spec 1.6): the merged, canonical sorted word list after the
414
+ /**
415
+ * The personal-dictionary add outcome (spec 1.6): the merged, canonical sorted word list after the
336
416
  * add landed. The client reconciles its pending-additions set against this (a word now in the list is
337
417
  * committed and dropped from pending). Admin-internal: exported for the editor host's reconcile, not
338
- * on the package's sveltekit subpath, so it carries no reference page. */
418
+ * on the package's sveltekit subpath, so it carries no reference page.
419
+ */
339
420
  export interface DictionaryAddResult {
340
421
  words: string[];
341
422
  }
342
- /** A refused personal-dictionary add: `fail(403)` on a failed CSRF check, `fail(400)` on a body that
423
+ /**
424
+ * A refused personal-dictionary add: `fail(403)` on a failed CSRF check, `fail(400)` on a body that
343
425
  * carries no valid word. The client keeps its pending additions for the session and re-attempts on
344
- * the next save, so the word is never silently dropped. Just the one-line summary. */
426
+ * the next save, so the word is never silently dropped. Just the one-line summary.
427
+ */
345
428
  export interface DictionaryAddFailure {
346
429
  error: string;
347
430
  }
348
- /** A refused media bulk delete or orphan purge: `fail(503)` for the fail-closed strict-usage refusal
431
+ /**
432
+ * A refused media bulk delete or orphan purge: `fail(503)` for the fail-closed strict-usage refusal
349
433
  * (the whole batch refuses) or media-off / a missing bucket binding. The per-item outcomes ride the
350
- * returned summary, not a fail. */
434
+ * returned summary, not a fail.
435
+ */
351
436
  export interface MediaBulkFailure {
352
437
  error: string;
353
438
  }
354
- /** The bulk-delete outcome the component renders: the deleted hashes, the skipped rows from the
439
+ /**
440
+ * The bulk-delete outcome the component renders: the deleted hashes, the skipped rows from the
355
441
  * partition (with their reason and where-used), and any per-object R2 delete failure. Admin-internal,
356
- * not on the package subpath, so no reference page. */
442
+ * not on the package subpath, so no reference page.
443
+ */
357
444
  export interface MediaBulkDeleteResult {
358
445
  deleted: string[];
359
446
  skipped: BulkDeleteSkip[];
@@ -362,8 +449,10 @@ export interface MediaBulkDeleteResult {
362
449
  error: string;
363
450
  }[];
364
451
  }
365
- /** The orphan-purge outcome: the purged R2 keys, the keys skipped because their hash was claimed by a
366
- * manifest row since the scan, and any per-object delete failure. Admin-internal, no reference page. */
452
+ /**
453
+ * The orphan-purge outcome: the purged R2 keys, the keys skipped because their hash was claimed by a
454
+ * manifest row since the scan, and any per-object delete failure. Admin-internal, no reference page.
455
+ */
367
456
  export interface MediaOrphanPurgeResult {
368
457
  purged: string[];
369
458
  skippedClaimed: string[];
@@ -372,11 +461,13 @@ export interface MediaOrphanPurgeResult {
372
461
  error: string;
373
462
  }[];
374
463
  }
375
- /** One entry the replace preview will rewrite, enriched with its display title and permalink from the
464
+ /**
465
+ * One entry the replace preview will rewrite, enriched with its display title and permalink from the
376
466
  * content manifest (the planner's PlannedEntry carries neither). The screen lists these as the
377
467
  * confirm dialog's where-touched preview, and the apply re-derives its own plan rather than trusting
378
468
  * this. Admin-internal: exported from content-routes for the bundled Media Library component, not
379
- * added to the package's sveltekit subpath, so it carries no reference page. */
469
+ * added to the package's sveltekit subpath, so it carries no reference page.
470
+ */
380
471
  export interface MediaReplacePreviewEntry {
381
472
  /** The concept id, e.g. "posts". */
382
473
  concept: string;
@@ -389,20 +480,24 @@ export interface MediaReplacePreviewEntry {
389
480
  /** The per-reference diff for this entry: one placement per repointed `media:` token. */
390
481
  placements: RepointPlacement[];
391
482
  }
392
- /** The replace preview plan: the affected main entries (enriched), the distinct affected count, and
483
+ /**
484
+ * The replace preview plan: the affected main entries (enriched), the distinct affected count, and
393
485
  * the report-only cross-branch delta (open cairn/* branches that reference the same bytes; an apply
394
- * rewrites main only). Display-only: the apply re-derives a fresh plan and never trusts this. */
486
+ * rewrites main only). Display-only: the apply re-derives a fresh plan and never trusts this.
487
+ */
395
488
  export interface MediaReplacePreviewPlan {
396
489
  affectedCount: number;
397
490
  entries: MediaReplacePreviewEntry[];
398
491
  branchDelta: BranchRef[];
399
492
  }
400
- /** One entry the alt-propagation preview reports, enriched with its display title and permalink from
493
+ /**
494
+ * One entry the alt-propagation preview reports, enriched with its display title and permalink from
401
495
  * the content manifest. Its placements carry every reference of the asset on this entry, each tagged
402
496
  * with the bucket it falls in (a will-fill, a customized alt left as-is, or a decorative hero), so
403
497
  * the screen can show what would change. Admin-internal: exported from content-routes for the bundled
404
498
  * Media Library component, not added to the package's sveltekit subpath, so it carries no reference
405
- * page. */
499
+ * page.
500
+ */
406
501
  export interface MediaAltPreviewEntry {
407
502
  /** The concept id, e.g. "posts". */
408
503
  concept: string;
@@ -415,11 +510,13 @@ export interface MediaAltPreviewEntry {
415
510
  /** The per-reference diff for this entry: one placement per reference of the asset. */
416
511
  placements: AltPlacement[];
417
512
  }
418
- /** The alt-propagation preview plan: every entry that references the asset (enriched), the report-only
513
+ /**
514
+ * The alt-propagation preview plan: every entry that references the asset (enriched), the report-only
419
515
  * cross-branch delta, and the bucket counts aggregated across every placement. Display-only: the
420
516
  * apply re-derives a fresh plan and never trusts this. The preview reports an entry even when its
421
517
  * only placements are reported-but-unchanged (a kept custom alt, a decorative hero), so the screen
422
- * can show every bucket; the apply commits only the entries it actually changes. */
518
+ * can show every bucket; the apply commits only the entries it actually changes.
519
+ */
423
520
  export interface MediaAltPreviewPlan {
424
521
  entries: MediaAltPreviewEntry[];
425
522
  branchDelta: BranchRef[];
@@ -430,24 +527,32 @@ export interface MediaAltPreviewPlan {
430
527
  decorativeSkipped: number;
431
528
  };
432
529
  }
433
- /** What a route's single `form` export presents to a view component: whichever content action
530
+ /**
531
+ * What a route's single `form` export presents to a view component: whichever content action
434
532
  * last failed, merged with every field optional. `error` is always set on a failure; the richer
435
533
  * keys identify which guard refused. The media refusals ride here too, so the Media Library's one
436
534
  * `form` prop carries a `?/mediaDelete`, `?/mediaUpdate`, `?/mediaReplace`, or `?/mediaAltPropagate`
437
- * refusal without a second type. */
535
+ * refusal without a second type.
536
+ */
438
537
  export type ContentFormFailure = Partial<SaveFailure & DeleteRefusal & RenameFailure & MediaDeleteRefusal & MediaUpdateFailure & MediaReplaceFailure & MediaAltPropagateFailure & MediaBulkFailure & TidyFailure>;
439
- /** The successful upload's response (`uploadAction`). The server-owned `record` rides the editor's
538
+ /**
539
+ * The successful upload's response (`uploadAction`). The server-owned `record` rides the editor's
440
540
  * optimistic client state and commits with the entry at Save (the upload itself commits nothing).
441
541
  * `reused` is true when identical bytes were already stored, so the second upload did no second put;
442
- * `mismatch` flags an existing object whose stored content type differs from this sniff. */
542
+ * `mismatch` flags an existing object whose stored content type differs from this sniff.
543
+ */
443
544
  export interface UploadResult {
444
545
  reference: string;
445
546
  record: MediaEntry;
446
547
  reused: boolean;
447
548
  mismatch: boolean;
448
549
  }
550
+ /**
551
+ *
552
+ */
449
553
  export declare function createContentRoutes(runtime: CairnRuntime, deps?: ContentRoutesDeps): {
450
554
  layoutLoad: (event: ContentEvent) => Promise<LayoutData>;
555
+ helpLoad: (event: ContentEvent) => Promise<HelpData>;
451
556
  indexRedirect: () => never;
452
557
  listLoad: (event: ContentEvent) => Promise<ListData>;
453
558
  mediaLibraryLoad: (event: ContentEvent) => Promise<MediaLibraryData>;