@glw907/cairn-cms 0.62.2 → 0.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/CHANGELOG.md +216 -0
  2. package/dist/ambient.d.ts +2 -0
  3. package/dist/auth/types.d.ts +7 -0
  4. package/dist/components/CairnAdmin.svelte.d.ts +2 -7
  5. package/dist/components/ComponentForm.svelte +44 -27
  6. package/dist/components/ComponentInsertDialog.svelte +22 -11
  7. package/dist/components/ComponentInsertDialog.svelte.d.ts +2 -6
  8. package/dist/components/ConceptList.svelte +25 -4
  9. package/dist/components/EditPage.svelte +29 -107
  10. package/dist/components/EditPage.svelte.d.ts +2 -7
  11. package/dist/components/EntryPicker.svelte +117 -0
  12. package/dist/components/EntryPicker.svelte.d.ts +35 -0
  13. package/dist/components/FieldInput.svelte +218 -0
  14. package/dist/components/FieldInput.svelte.d.ts +51 -0
  15. package/dist/components/IconPicker.svelte +2 -2
  16. package/dist/components/IconPicker.svelte.d.ts +2 -0
  17. package/dist/components/LinkPicker.svelte +8 -75
  18. package/dist/components/LinkPicker.svelte.d.ts +4 -5
  19. package/dist/components/MediaHeroField.svelte +8 -5
  20. package/dist/components/MediaHeroField.svelte.d.ts +4 -0
  21. package/dist/components/ObjectGroupField.svelte +54 -0
  22. package/dist/components/ObjectGroupField.svelte.d.ts +47 -0
  23. package/dist/components/ReferenceField.svelte +94 -0
  24. package/dist/components/ReferenceField.svelte.d.ts +27 -0
  25. package/dist/components/RepeatableField.svelte +221 -0
  26. package/dist/components/RepeatableField.svelte.d.ts +53 -0
  27. package/dist/components/cairn-admin.css +179 -2
  28. package/dist/components/preview-doc.js +5 -1
  29. package/dist/components/tidy-validate.js +1 -1
  30. package/dist/content/adapter.js +18 -0
  31. package/dist/content/advisories.d.ts +2 -2
  32. package/dist/content/advisories.js +3 -5
  33. package/dist/content/compose.d.ts +7 -6
  34. package/dist/content/compose.js +26 -20
  35. package/dist/content/concepts.d.ts +21 -15
  36. package/dist/content/concepts.js +55 -32
  37. package/dist/content/field-rules.d.ts +15 -0
  38. package/dist/content/field-rules.js +38 -0
  39. package/dist/content/fields.d.ts +169 -0
  40. package/dist/content/fields.js +41 -0
  41. package/dist/content/fieldset.d.ts +107 -0
  42. package/dist/content/fieldset.js +386 -0
  43. package/dist/content/frontmatter-region.d.ts +38 -0
  44. package/dist/content/frontmatter-region.js +75 -0
  45. package/dist/content/frontmatter.d.ts +35 -2
  46. package/dist/content/frontmatter.js +232 -11
  47. package/dist/content/manifest.d.ts +34 -0
  48. package/dist/content/manifest.js +80 -4
  49. package/dist/content/media-refs.d.ts +2 -2
  50. package/dist/content/media-rewrite.js +1 -69
  51. package/dist/content/reference-index.d.ts +56 -0
  52. package/dist/content/reference-index.js +95 -0
  53. package/dist/content/references.d.ts +40 -0
  54. package/dist/content/references.js +0 -0
  55. package/dist/content/standard-schema.d.ts +30 -0
  56. package/dist/content/standard-schema.js +4 -0
  57. package/dist/content/types.d.ts +127 -178
  58. package/dist/delivery/data.d.ts +2 -2
  59. package/dist/delivery/data.js +1 -1
  60. package/dist/delivery/public-routes.d.ts +10 -5
  61. package/dist/delivery/public-routes.js +25 -2
  62. package/dist/delivery/site-descriptors.d.ts +5 -1
  63. package/dist/delivery/site-descriptors.js +8 -3
  64. package/dist/delivery/site-indexes.d.ts +2 -2
  65. package/dist/delivery/site-resolver.d.ts +25 -0
  66. package/dist/delivery/site-resolver.js +49 -0
  67. package/dist/doctor/checks-local.js +6 -11
  68. package/dist/github/backend.d.ts +83 -0
  69. package/dist/github/backend.js +76 -0
  70. package/dist/github/credentials.d.ts +11 -5
  71. package/dist/github/credentials.js +3 -3
  72. package/dist/github/repo.d.ts +8 -19
  73. package/dist/github/repo.js +69 -80
  74. package/dist/github/types.d.ts +1 -1
  75. package/dist/github/types.js +4 -4
  76. package/dist/index.d.ts +18 -10
  77. package/dist/index.js +9 -5
  78. package/dist/islands/index.d.ts +12 -0
  79. package/dist/islands/index.js +83 -0
  80. package/dist/islands/types.d.ts +7 -0
  81. package/dist/islands/types.js +1 -0
  82. package/dist/log/events.d.ts +1 -1
  83. package/dist/media/index.d.ts +1 -1
  84. package/dist/media/index.js +1 -1
  85. package/dist/media/manifest.d.ts +11 -0
  86. package/dist/media/manifest.js +13 -0
  87. package/dist/media/rewrite-plan.d.ts +2 -3
  88. package/dist/media/rewrite-plan.js +2 -3
  89. package/dist/media/usage.d.ts +2 -2
  90. package/dist/media/usage.js +3 -5
  91. package/dist/nav/site-config.d.ts +0 -6
  92. package/dist/nav/site-config.js +6 -4
  93. package/dist/render/component-grammar.js +11 -11
  94. package/dist/render/component-reference.js +5 -3
  95. package/dist/render/component-validate.d.ts +4 -1
  96. package/dist/render/component-validate.js +10 -35
  97. package/dist/render/highlight.d.ts +9 -0
  98. package/dist/render/highlight.js +206 -0
  99. package/dist/render/pipeline.d.ts +0 -6
  100. package/dist/render/pipeline.js +13 -2
  101. package/dist/render/registry.d.ts +44 -36
  102. package/dist/render/registry.js +47 -6
  103. package/dist/render/rehype-dispatch.d.ts +6 -10
  104. package/dist/render/rehype-dispatch.js +38 -17
  105. package/dist/render/remark-directives.js +4 -5
  106. package/dist/render/sanitize-schema.d.ts +10 -0
  107. package/dist/render/sanitize-schema.js +30 -1
  108. package/dist/sveltekit/cairn-admin.d.ts +5 -5
  109. package/dist/sveltekit/cairn-admin.js +3 -4
  110. package/dist/sveltekit/content-routes.d.ts +10 -8
  111. package/dist/sveltekit/content-routes.js +269 -181
  112. package/dist/sveltekit/guard.js +10 -0
  113. package/dist/sveltekit/health.d.ts +7 -3
  114. package/dist/sveltekit/health.js +9 -3
  115. package/dist/sveltekit/index.d.ts +1 -1
  116. package/dist/sveltekit/nav-routes.d.ts +6 -5
  117. package/dist/sveltekit/nav-routes.js +22 -20
  118. package/dist/sveltekit/types.d.ts +2 -0
  119. package/dist/vite/index.d.ts +3 -3
  120. package/dist/vite/index.js +17 -8
  121. package/package.json +17 -2
  122. package/src/lib/ambient.ts +7 -0
  123. package/src/lib/auth/types.ts +7 -0
  124. package/src/lib/components/CairnAdmin.svelte +2 -6
  125. package/src/lib/components/ComponentForm.svelte +48 -27
  126. package/src/lib/components/ComponentInsertDialog.svelte +26 -14
  127. package/src/lib/components/ConceptList.svelte +41 -4
  128. package/src/lib/components/EditPage.svelte +43 -119
  129. package/src/lib/components/EntryPicker.svelte +154 -0
  130. package/src/lib/components/FieldInput.svelte +262 -0
  131. package/src/lib/components/IconPicker.svelte +4 -2
  132. package/src/lib/components/LinkPicker.svelte +10 -81
  133. package/src/lib/components/MediaHeroField.svelte +12 -5
  134. package/src/lib/components/ObjectGroupField.svelte +97 -0
  135. package/src/lib/components/ReferenceField.svelte +126 -0
  136. package/src/lib/components/RepeatableField.svelte +310 -0
  137. package/src/lib/components/preview-doc.ts +5 -1
  138. package/src/lib/components/tidy-validate.ts +1 -1
  139. package/src/lib/content/adapter.ts +21 -0
  140. package/src/lib/content/advisories.ts +4 -7
  141. package/src/lib/content/compose.ts +30 -23
  142. package/src/lib/content/concepts.ts +68 -40
  143. package/src/lib/content/field-rules.ts +39 -0
  144. package/src/lib/content/fields.ts +178 -0
  145. package/src/lib/content/fieldset.ts +470 -0
  146. package/src/lib/content/frontmatter-region.ts +90 -0
  147. package/src/lib/content/frontmatter.ts +231 -15
  148. package/src/lib/content/manifest.ts +101 -4
  149. package/src/lib/content/media-refs.ts +2 -2
  150. package/src/lib/content/media-rewrite.ts +7 -80
  151. package/src/lib/content/reference-index.ts +159 -0
  152. package/src/lib/content/references.ts +0 -0
  153. package/src/lib/content/standard-schema.ts +25 -0
  154. package/src/lib/content/types.ts +128 -195
  155. package/src/lib/delivery/data.ts +2 -2
  156. package/src/lib/delivery/public-routes.ts +36 -4
  157. package/src/lib/delivery/site-descriptors.ts +8 -3
  158. package/src/lib/delivery/site-indexes.ts +2 -2
  159. package/src/lib/delivery/site-resolver.ts +64 -0
  160. package/src/lib/doctor/checks-local.ts +6 -14
  161. package/src/lib/github/backend.ts +161 -0
  162. package/src/lib/github/credentials.ts +10 -7
  163. package/src/lib/github/repo.ts +79 -83
  164. package/src/lib/github/types.ts +5 -5
  165. package/src/lib/index.ts +40 -18
  166. package/src/lib/islands/index.ts +84 -0
  167. package/src/lib/islands/types.ts +11 -0
  168. package/src/lib/log/events.ts +1 -0
  169. package/src/lib/media/index.ts +1 -0
  170. package/src/lib/media/manifest.ts +14 -0
  171. package/src/lib/media/rewrite-plan.ts +4 -6
  172. package/src/lib/media/usage.ts +4 -7
  173. package/src/lib/nav/site-config.ts +8 -9
  174. package/src/lib/render/component-grammar.ts +10 -10
  175. package/src/lib/render/component-reference.ts +4 -3
  176. package/src/lib/render/component-validate.ts +10 -35
  177. package/src/lib/render/highlight.ts +259 -0
  178. package/src/lib/render/pipeline.ts +13 -8
  179. package/src/lib/render/registry.ts +88 -42
  180. package/src/lib/render/rehype-dispatch.ts +47 -16
  181. package/src/lib/render/remark-directives.ts +4 -5
  182. package/src/lib/render/sanitize-schema.ts +32 -1
  183. package/src/lib/sveltekit/cairn-admin.ts +8 -9
  184. package/src/lib/sveltekit/content-routes.ts +330 -221
  185. package/src/lib/sveltekit/guard.ts +15 -0
  186. package/src/lib/sveltekit/health.ts +13 -6
  187. package/src/lib/sveltekit/index.ts +2 -2
  188. package/src/lib/sveltekit/nav-routes.ts +33 -29
  189. package/src/lib/sveltekit/types.ts +5 -1
  190. package/src/lib/vite/index.ts +20 -11
  191. package/dist/content/schema.d.ts +0 -87
  192. package/dist/content/schema.js +0 -89
  193. package/dist/content/validate.d.ts +0 -17
  194. package/dist/content/validate.js +0 -93
  195. package/src/lib/content/schema.ts +0 -167
  196. package/src/lib/content/validate.ts +0 -90
@@ -1,5 +1,6 @@
1
1
  import { defaultSchema } from 'hast-util-sanitize';
2
2
  import { visit } from 'unist-util-visit';
3
+ import { toString } from 'hast-util-to-string';
3
4
  import { dataAttrProp } from './registry.js';
4
5
  // The fixed directive markers the stamp writes and the dispatch reads. They are inert data
5
6
  // attributes, never a script vector, and must survive the floor so the dispatch still runs.
@@ -16,7 +17,7 @@ const FIXED_MARKERS = ['dataPrimitive', 'dataSlot', 'dataRole', 'dataRise'];
16
17
  * allowlist but not weaken the core strip.
17
18
  */
18
19
  export function buildSanitizeSchema(registry, extend) {
19
- const attrMarkers = registry.defs.flatMap((d) => (d.attributes ?? []).map((a) => dataAttrProp(a.key)));
20
+ const attrMarkers = registry.defs.flatMap((d) => Object.keys(d.attributes ?? {}).map((key) => dataAttrProp(key)));
20
21
  const markers = [...FIXED_MARKERS, ...attrMarkers];
21
22
  const attributes = defaultSchema.attributes ?? {};
22
23
  // defaultSchema's `a` entry carries a className tuple (`['className', 'data-footnote-backref']`)
@@ -58,6 +59,34 @@ export function rehypeAnchorRel(rel) {
58
59
  });
59
60
  };
60
61
  }
62
+ /**
63
+ * Give every GFM task-list checkbox an accessible name from its item text. remark-gfm emits a real
64
+ * `<input type="checkbox" disabled>` with no label, which axe's `label` rule flags as a critical
65
+ * violation even though the control is read-only; the visible label is the surrounding `<li>` text,
66
+ * not associated programmatically. This sets `aria-label` on each task-list checkbox to its item's
67
+ * text so the name travels with the control, keeping the engine's real disabled input (the bar's
68
+ * non-color cue) while clearing the violation on every site. It must run after the sanitize floor,
69
+ * which does not allow `aria-label`, so the attribute is added once the floor has run.
70
+ */
71
+ export function rehypeTaskListA11y() {
72
+ return (tree) => {
73
+ visit(tree, 'element', (node) => {
74
+ const className = node.properties?.className;
75
+ const isTaskItem = node.tagName === 'li' && Array.isArray(className) && className.includes('task-list-item');
76
+ if (!isTaskItem)
77
+ return;
78
+ const checkbox = node.children.find((child) => child.type === 'element' &&
79
+ child.tagName === 'input' &&
80
+ child.properties?.type === 'checkbox');
81
+ if (!checkbox)
82
+ return;
83
+ const label = toString(node).trim();
84
+ // Only when there is text to name it; an empty item leaves the box unnamed rather than blank.
85
+ if (label)
86
+ (checkbox.properties ??= {})['ariaLabel'] = label;
87
+ });
88
+ };
89
+ }
61
90
  // URL-bearing hast properties the post-dispatch guard scheme-checks. hast camelCases attribute
62
91
  // names through property-information (srcset -> srcSet, xlink:href -> xLinkHref with a capital L,
63
92
  // formaction -> formAction). data is the <object data> URL attribute; data-* attributes camelCase
@@ -2,7 +2,7 @@ import { type ContentRoutesDeps, type LayoutData, type ListData, type EditData,
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';
5
- import type { GithubKeyEnv } from '../github/credentials.js';
5
+ import type { BackendEnv } from '../github/credentials.js';
6
6
  import type { CairnRuntime } from '../content/types.js';
7
7
  import type { CookieJar, EventBase } from './types.js';
8
8
  /**
@@ -10,19 +10,19 @@ import type { CookieJar, EventBase } from './types.js';
10
10
  * (ContentEvent minus params, which the dispatcher synthesizes, plus RequestContext's cookies
11
11
  * and setHeaders). A real SvelteKit RequestEvent satisfies it.
12
12
  */
13
- export interface AdminEvent extends EventBase<GithubKeyEnv & AuthEnv> {
13
+ export interface AdminEvent extends EventBase<BackendEnv & AuthEnv> {
14
14
  cookies: CookieJar;
15
15
  setHeaders(headers: Record<string, string>): void;
16
16
  }
17
17
  /**
18
18
  * Injectable dependencies. Branding defaults from the runtime's siteName and sender, so a
19
- * site overrides it only to change the magic-link email identity; `send` and `mintToken`
20
- * are the same seams the underlying factories take.
19
+ * site overrides it only to change the magic-link email identity; `send` is the same seam the
20
+ * underlying auth factory takes. The content backend rides `event.locals.backend` (the dev double)
21
+ * or the adapter's provider, so it is not a dep here.
21
22
  */
22
23
  export interface CairnAdminDeps {
23
24
  branding?: AuthBranding;
24
25
  send?: SendMagicLink;
25
- mintToken?: ContentRoutesDeps['mintToken'];
26
26
  /**
27
27
  * Build the Anthropic client for the tidy action. Forwarded to the content routes; a site that
28
28
  * enables tidy injects a stub here to avoid a real network call. Defaults to the real SDK client.
@@ -23,13 +23,12 @@ export function createCairnAdmin(runtime, deps = {}) {
23
23
  };
24
24
  const auth = createAuthRoutes({ branding, send: deps.send });
25
25
  const content = createContentRoutes(runtime, {
26
- mintToken: deps.mintToken,
27
26
  anthropic: deps.anthropic,
28
27
  tidyTimeoutMs: deps.tidyTimeoutMs,
29
28
  });
30
29
  const editors = createEditorRoutes();
31
30
  // The nav surface exists only when the site configures a menu; without one its view is a 404.
32
- const nav = runtime.navMenu ? createNavRoutes(runtime, { mintToken: deps.mintToken }) : null;
31
+ const nav = runtime.navMenu ? createNavRoutes(runtime) : null;
33
32
  /**
34
33
  * Build the event a wrapped content load reads. The catch-all route carries only a rest
35
34
  * param, so `concept` and `id` are synthesized from the parsed view. The override names
@@ -49,8 +48,8 @@ export function createCairnAdmin(runtime, deps = {}) {
49
48
  }
50
49
  /**
51
50
  * Serve the admin view the pathname names, or a 404 for any shape the parser refuses.
52
- * The authed views run the layout load and the view load concurrently; both mint a GitHub
53
- * token, and the installation-token cache coalesces the mints into one signing.
51
+ * The authed views run the layout load and the view load concurrently; both resolve the same
52
+ * backend, and the installation-token cache coalesces their lazy mints into one signing.
54
53
  */
55
54
  async function load(event) {
56
55
  const view = parseAdminPath(event.url.pathname, runtime.concepts);
@@ -1,6 +1,7 @@
1
1
  import { fail } from '@sveltejs/kit';
2
2
  import { type AdvisoryNotice } from '../content/advisories.js';
3
- import { type GithubKeyEnv } from '../github/credentials.js';
3
+ import type { BackendEnv } from '../github/credentials.js';
4
+ import type { Backend } from '../github/backend.js';
4
5
  import { type LinkTarget, type InboundLink } from '../content/manifest.js';
5
6
  import { type GettingStarted } from '../content/getting-started.js';
6
7
  import { type MarkdownReferenceRow } from '../components/markdown-reference.js';
@@ -13,7 +14,7 @@ import type { RepointPlacement, AltPlacement } from '../content/media-rewrite.js
13
14
  import type { BranchRef } from '../media/rewrite-plan.js';
14
15
  import type { BulkDeleteSkip } from '../media/bulk-delete-plan.js';
15
16
  import type { CookieJar, EventBase } from './types.js';
16
- import type { CairnRuntime, FrontmatterField, ResolvedPreview } from '../content/types.js';
17
+ import type { CairnRuntime, NamedField, ResolvedPreview } from '../content/types.js';
17
18
  import type { Role } from '../auth/types.js';
18
19
  export type { AdvisoryNotice, AdvisoryAction } from '../content/advisories.js';
19
20
  /** A sidebar concept entry: just enough to render the nav without shipping validators to the client. */
@@ -90,7 +91,7 @@ export interface EditData {
90
91
  conceptId: string;
91
92
  id: string;
92
93
  label: string;
93
- fields: FrontmatterField[];
94
+ fields: NamedField[];
94
95
  frontmatter: Record<string, unknown>;
95
96
  body: string;
96
97
  title: string;
@@ -259,7 +260,7 @@ export interface HelpData {
259
260
  supportContact?: string;
260
261
  }
261
262
  /** The structural event the content routes read; a real SvelteKit RequestEvent satisfies it. */
262
- export interface ContentEvent extends EventBase<GithubKeyEnv> {
263
+ export interface ContentEvent extends EventBase<BackendEnv> {
263
264
  params: Record<string, string>;
264
265
  /**
265
266
  * SvelteKit's cookie jar. The layout load reads the persisted admin theme and issues the CSRF
@@ -303,10 +304,12 @@ export interface TidyClient {
303
304
  }
304
305
  export interface ContentRoutesDeps {
305
306
  /**
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.
307
+ * Override the resolved content backend. A test injects a live `Backend` (a `makeGithubBackend`
308
+ * over a fetch double, or an in-memory fake) so the read and commit paths run with no real token
309
+ * mint. When set it replaces the per-handler `locals.backend ?? runtime.backend.connect(env)`
310
+ * resolve; a production caller leaves it unset and the dev double rides `event.locals.backend`.
308
311
  */
309
- mintToken?: (env: GithubKeyEnv) => string | Promise<string>;
312
+ backend?: Backend;
310
313
  /**
311
314
  * Build the Anthropic client for the tidy action from the resolved API key. Defaults to the real
312
315
  * SDK client. Injected in tests so `messages.create` is stubbed and no network call (or real key)
@@ -579,5 +582,4 @@ export declare function createContentRoutes(runtime: CairnRuntime, deps?: Conten
579
582
  mediaAltApply: (event: ContentEvent) => Promise<ReturnType<typeof fail> | never>;
580
583
  addDictionaryWord: (event: ContentEvent) => Promise<ReturnType<typeof fail> | DictionaryAddResult>;
581
584
  tidyAction: (event: ContentEvent) => Promise<ReturnType<typeof fail> | TidyResult>;
582
- mintToken: (env: GithubKeyEnv) => string | Promise<string>;
583
585
  };