@glw907/cairn-cms 0.26.0 → 0.33.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 (234) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/dist/auth/crypto.d.ts +0 -1
  3. package/dist/auth/store.d.ts +0 -1
  4. package/dist/auth/types.d.ts +0 -1
  5. package/dist/components/AdminLayout.svelte +372 -44
  6. package/dist/components/AdminLayout.svelte.d.ts +5 -5
  7. package/dist/components/CairnLogo.svelte +28 -0
  8. package/dist/components/CairnLogo.svelte.d.ts +15 -0
  9. package/dist/components/ComponentForm.svelte +1 -1
  10. package/dist/components/ComponentForm.svelte.d.ts +0 -1
  11. package/dist/components/ComponentInsertDialog.svelte.d.ts +0 -1
  12. package/dist/components/ConceptList.svelte +240 -45
  13. package/dist/components/ConceptList.svelte.d.ts +12 -3
  14. package/dist/components/ConfirmPage.svelte +20 -3
  15. package/dist/components/ConfirmPage.svelte.d.ts +0 -1
  16. package/dist/components/DeleteDialog.svelte.d.ts +0 -1
  17. package/dist/components/EditPage.svelte +12 -7
  18. package/dist/components/EditPage.svelte.d.ts +0 -1
  19. package/dist/components/EditorToolbar.svelte.d.ts +0 -1
  20. package/dist/components/IconPicker.svelte.d.ts +0 -1
  21. package/dist/components/LinkPicker.svelte.d.ts +0 -1
  22. package/dist/components/LoginPage.svelte +27 -5
  23. package/dist/components/LoginPage.svelte.d.ts +0 -1
  24. package/dist/components/ManageEditors.svelte +8 -5
  25. package/dist/components/ManageEditors.svelte.d.ts +0 -1
  26. package/dist/components/MarkdownEditor.svelte.d.ts +0 -1
  27. package/dist/components/NavTree.svelte +2 -2
  28. package/dist/components/NavTree.svelte.d.ts +0 -1
  29. package/dist/components/RenameDialog.svelte.d.ts +0 -1
  30. package/dist/components/admin-icons.d.ts +13 -0
  31. package/dist/components/admin-icons.js +15 -0
  32. package/dist/components/cairn-admin.css +5516 -37
  33. package/dist/components/cairn-favicon.d.ts +2 -0
  34. package/dist/components/cairn-favicon.js +7 -0
  35. package/dist/components/chrome-guard.d.ts +9 -0
  36. package/dist/components/chrome-guard.js +55 -0
  37. package/dist/components/fonts/BricolageGrotesque-OFL.txt +93 -0
  38. package/dist/components/fonts/Figtree-OFL.txt +93 -0
  39. package/dist/components/fonts/bricolage-grotesque.woff2 +0 -0
  40. package/dist/components/fonts/figtree.woff2 +0 -0
  41. package/dist/components/index.d.ts +0 -1
  42. package/dist/components/link-completion.d.ts +0 -1
  43. package/dist/components/markdown-format.d.ts +0 -1
  44. package/dist/content/adapter.d.ts +0 -1
  45. package/dist/content/compose.d.ts +1 -2
  46. package/dist/content/compose.js +2 -3
  47. package/dist/content/concepts.d.ts +7 -1
  48. package/dist/content/concepts.js +49 -1
  49. package/dist/content/frontmatter.d.ts +0 -1
  50. package/dist/content/identity.d.ts +23 -0
  51. package/dist/content/identity.js +43 -0
  52. package/dist/content/ids.d.ts +0 -1
  53. package/dist/content/links.d.ts +0 -1
  54. package/dist/content/manifest.d.ts +3 -2
  55. package/dist/content/manifest.js +6 -26
  56. package/dist/content/permalink.d.ts +0 -1
  57. package/dist/content/schema.d.ts +0 -1
  58. package/dist/content/types.d.ts +0 -1
  59. package/dist/content/validate.d.ts +0 -1
  60. package/dist/delivery/CairnHead.svelte.d.ts +0 -1
  61. package/dist/delivery/content-index.d.ts +0 -1
  62. package/dist/delivery/content-index.js +8 -25
  63. package/dist/delivery/data.d.ts +0 -1
  64. package/dist/delivery/excerpt.d.ts +0 -1
  65. package/dist/delivery/feeds.d.ts +0 -1
  66. package/dist/delivery/head.d.ts +0 -1
  67. package/dist/delivery/index.d.ts +0 -1
  68. package/dist/delivery/json-ld.d.ts +0 -1
  69. package/dist/delivery/manifest.d.ts +0 -1
  70. package/dist/delivery/paginate.d.ts +0 -1
  71. package/dist/delivery/responses.d.ts +0 -1
  72. package/dist/delivery/robots.d.ts +0 -1
  73. package/dist/delivery/seo-fields.d.ts +0 -1
  74. package/dist/delivery/seo.d.ts +0 -1
  75. package/dist/delivery/site-descriptors.d.ts +0 -1
  76. package/dist/delivery/site-descriptors.js +5 -6
  77. package/dist/delivery/site-index.d.ts +0 -1
  78. package/dist/delivery/site-indexes.d.ts +0 -1
  79. package/dist/delivery/sitemap.d.ts +0 -1
  80. package/dist/email.d.ts +0 -1
  81. package/dist/env.d.ts +0 -1
  82. package/dist/github/credentials.d.ts +0 -1
  83. package/dist/github/repo.d.ts +0 -1
  84. package/dist/github/signing.d.ts +0 -1
  85. package/dist/github/types.d.ts +0 -1
  86. package/dist/index.d.ts +0 -29
  87. package/dist/index.js +4 -23
  88. package/dist/nav/site-config.d.ts +0 -1
  89. package/dist/render/authoring.d.ts +3 -0
  90. package/dist/render/authoring.js +5 -0
  91. package/dist/render/component-grammar.d.ts +0 -1
  92. package/dist/render/component-insert.d.ts +0 -1
  93. package/dist/render/component-reference.d.ts +0 -1
  94. package/dist/render/component-validate.d.ts +0 -1
  95. package/dist/render/glyph.d.ts +0 -1
  96. package/dist/render/index.d.ts +0 -1
  97. package/dist/render/pipeline.d.ts +0 -1
  98. package/dist/render/pipeline.js +5 -1
  99. package/dist/render/registry.d.ts +2 -1
  100. package/dist/render/registry.js +15 -0
  101. package/dist/render/rehype-dispatch.d.ts +9 -7
  102. package/dist/render/rehype-dispatch.js +12 -6
  103. package/dist/render/remark-directives.d.ts +0 -1
  104. package/dist/render/remark-directives.js +1 -1
  105. package/dist/render/resolve-links.d.ts +0 -1
  106. package/dist/render/sanitize-schema.d.ts +14 -1
  107. package/dist/render/sanitize-schema.js +96 -0
  108. package/dist/sveltekit/auth-routes.d.ts +0 -1
  109. package/dist/sveltekit/content-routes.d.ts +12 -2
  110. package/dist/sveltekit/content-routes.js +37 -13
  111. package/dist/sveltekit/editors-routes.d.ts +0 -1
  112. package/dist/sveltekit/guard.d.ts +0 -1
  113. package/dist/sveltekit/health.d.ts +0 -1
  114. package/dist/sveltekit/index.d.ts +1 -3
  115. package/dist/sveltekit/index.js +0 -1
  116. package/dist/sveltekit/nav-routes.d.ts +0 -1
  117. package/dist/sveltekit/public-routes.d.ts +0 -1
  118. package/dist/sveltekit/types.d.ts +0 -1
  119. package/dist/vite/bin.d.ts +0 -1
  120. package/dist/vite/index.d.ts +0 -1
  121. package/package.json +16 -2
  122. package/src/lib/components/AdminLayout.svelte +372 -44
  123. package/src/lib/components/CairnLogo.svelte +28 -0
  124. package/src/lib/components/ComponentForm.svelte +1 -1
  125. package/src/lib/components/ConceptList.svelte +240 -45
  126. package/src/lib/components/ConfirmPage.svelte +20 -3
  127. package/src/lib/components/EditPage.svelte +12 -7
  128. package/src/lib/components/LoginPage.svelte +27 -5
  129. package/src/lib/components/ManageEditors.svelte +8 -5
  130. package/src/lib/components/NavTree.svelte +2 -2
  131. package/src/lib/components/admin-icons.ts +15 -0
  132. package/src/lib/components/cairn-admin.css +162 -7
  133. package/src/lib/components/cairn-favicon.ts +9 -0
  134. package/src/lib/components/chrome-guard.ts +62 -0
  135. package/src/lib/components/fonts/BricolageGrotesque-OFL.txt +93 -0
  136. package/src/lib/components/fonts/Figtree-OFL.txt +93 -0
  137. package/src/lib/components/fonts/bricolage-grotesque.woff2 +0 -0
  138. package/src/lib/components/fonts/figtree.woff2 +0 -0
  139. package/src/lib/content/compose.ts +3 -3
  140. package/src/lib/content/concepts.ts +61 -1
  141. package/src/lib/content/identity.ts +60 -0
  142. package/src/lib/content/manifest.ts +6 -27
  143. package/src/lib/delivery/content-index.ts +8 -27
  144. package/src/lib/delivery/site-descriptors.ts +5 -6
  145. package/src/lib/index.ts +4 -57
  146. package/src/lib/render/authoring.ts +7 -0
  147. package/src/lib/render/pipeline.ts +4 -1
  148. package/src/lib/render/registry.ts +20 -0
  149. package/src/lib/render/rehype-dispatch.ts +13 -6
  150. package/src/lib/render/remark-directives.ts +1 -1
  151. package/src/lib/render/sanitize-schema.ts +97 -0
  152. package/src/lib/sveltekit/content-routes.ts +51 -14
  153. package/src/lib/sveltekit/index.ts +2 -8
  154. package/dist/auth/crypto.d.ts.map +0 -1
  155. package/dist/auth/store.d.ts.map +0 -1
  156. package/dist/auth/types.d.ts.map +0 -1
  157. package/dist/components/AdminLayout.svelte.d.ts.map +0 -1
  158. package/dist/components/ComponentForm.svelte.d.ts.map +0 -1
  159. package/dist/components/ComponentInsertDialog.svelte.d.ts.map +0 -1
  160. package/dist/components/ConceptList.svelte.d.ts.map +0 -1
  161. package/dist/components/ConfirmPage.svelte.d.ts.map +0 -1
  162. package/dist/components/DeleteDialog.svelte.d.ts.map +0 -1
  163. package/dist/components/EditPage.svelte.d.ts.map +0 -1
  164. package/dist/components/EditorToolbar.svelte.d.ts.map +0 -1
  165. package/dist/components/IconPicker.svelte.d.ts.map +0 -1
  166. package/dist/components/LinkPicker.svelte.d.ts.map +0 -1
  167. package/dist/components/LoginPage.svelte.d.ts.map +0 -1
  168. package/dist/components/ManageEditors.svelte.d.ts.map +0 -1
  169. package/dist/components/MarkdownEditor.svelte.d.ts.map +0 -1
  170. package/dist/components/NavTree.svelte.d.ts.map +0 -1
  171. package/dist/components/RenameDialog.svelte.d.ts.map +0 -1
  172. package/dist/components/index.d.ts.map +0 -1
  173. package/dist/components/link-completion.d.ts.map +0 -1
  174. package/dist/components/markdown-format.d.ts.map +0 -1
  175. package/dist/content/adapter.d.ts.map +0 -1
  176. package/dist/content/compose.d.ts.map +0 -1
  177. package/dist/content/concepts.d.ts.map +0 -1
  178. package/dist/content/frontmatter.d.ts.map +0 -1
  179. package/dist/content/ids.d.ts.map +0 -1
  180. package/dist/content/links.d.ts.map +0 -1
  181. package/dist/content/manifest.d.ts.map +0 -1
  182. package/dist/content/permalink.d.ts.map +0 -1
  183. package/dist/content/schema.d.ts.map +0 -1
  184. package/dist/content/types.d.ts.map +0 -1
  185. package/dist/content/validate.d.ts.map +0 -1
  186. package/dist/delivery/CairnHead.svelte.d.ts.map +0 -1
  187. package/dist/delivery/content-index.d.ts.map +0 -1
  188. package/dist/delivery/data.d.ts.map +0 -1
  189. package/dist/delivery/excerpt.d.ts.map +0 -1
  190. package/dist/delivery/feeds.d.ts.map +0 -1
  191. package/dist/delivery/head.d.ts.map +0 -1
  192. package/dist/delivery/index.d.ts.map +0 -1
  193. package/dist/delivery/json-ld.d.ts.map +0 -1
  194. package/dist/delivery/manifest.d.ts.map +0 -1
  195. package/dist/delivery/paginate.d.ts.map +0 -1
  196. package/dist/delivery/responses.d.ts.map +0 -1
  197. package/dist/delivery/robots.d.ts.map +0 -1
  198. package/dist/delivery/seo-fields.d.ts.map +0 -1
  199. package/dist/delivery/seo.d.ts.map +0 -1
  200. package/dist/delivery/site-descriptors.d.ts.map +0 -1
  201. package/dist/delivery/site-index.d.ts.map +0 -1
  202. package/dist/delivery/site-indexes.d.ts.map +0 -1
  203. package/dist/delivery/sitemap.d.ts.map +0 -1
  204. package/dist/email.d.ts.map +0 -1
  205. package/dist/env.d.ts.map +0 -1
  206. package/dist/github/credentials.d.ts.map +0 -1
  207. package/dist/github/repo.d.ts.map +0 -1
  208. package/dist/github/signing.d.ts.map +0 -1
  209. package/dist/github/types.d.ts.map +0 -1
  210. package/dist/index.d.ts.map +0 -1
  211. package/dist/nav/site-config.d.ts.map +0 -1
  212. package/dist/render/component-grammar.d.ts.map +0 -1
  213. package/dist/render/component-insert.d.ts.map +0 -1
  214. package/dist/render/component-reference.d.ts.map +0 -1
  215. package/dist/render/component-validate.d.ts.map +0 -1
  216. package/dist/render/glyph.d.ts.map +0 -1
  217. package/dist/render/index.d.ts.map +0 -1
  218. package/dist/render/pipeline.d.ts.map +0 -1
  219. package/dist/render/registry.d.ts.map +0 -1
  220. package/dist/render/rehype-dispatch.d.ts.map +0 -1
  221. package/dist/render/remark-directives.d.ts.map +0 -1
  222. package/dist/render/resolve-links.d.ts.map +0 -1
  223. package/dist/render/sanitize-schema.d.ts.map +0 -1
  224. package/dist/sveltekit/auth-routes.d.ts.map +0 -1
  225. package/dist/sveltekit/content-routes.d.ts.map +0 -1
  226. package/dist/sveltekit/editors-routes.d.ts.map +0 -1
  227. package/dist/sveltekit/guard.d.ts.map +0 -1
  228. package/dist/sveltekit/health.d.ts.map +0 -1
  229. package/dist/sveltekit/index.d.ts.map +0 -1
  230. package/dist/sveltekit/nav-routes.d.ts.map +0 -1
  231. package/dist/sveltekit/public-routes.d.ts.map +0 -1
  232. package/dist/sveltekit/types.d.ts.map +0 -1
  233. package/dist/vite/bin.d.ts.map +0 -1
  234. package/dist/vite/index.d.ts.map +0 -1
@@ -3,9 +3,8 @@
3
3
  // code reads the content graph without an N+1 GitHub crawl. The build regenerates and verifies
4
4
  // it; the save path patches one entry and commits it with the content in one commit. Each entry
5
5
  // carries its identity and its outbound cairn: edges, so the manifest is the link graph.
6
- import { idFromFilename, slugFromId } from './ids.js';
7
6
  import { parseMarkdown } from './frontmatter.js';
8
- import { permalink } from './permalink.js';
7
+ import { entryIdentity, asString } from './identity.js';
9
8
  import { extractCairnLinks, type CairnRef, type LinkResolve } from './links.js';
10
9
  import type { ConceptDescriptor } from './types.js';
11
10
 
@@ -36,38 +35,18 @@ export interface LinkTarget {
36
35
  draft: boolean;
37
36
  }
38
37
 
39
- function basename(path: string): string {
40
- const slash = path.lastIndexOf('/');
41
- return slash >= 0 ? path.slice(slash + 1) : path;
42
- }
43
-
44
- /** Mirror content-index's frontmatter coercion: a present non-empty string, else undefined. */
45
- function asString(value: unknown): string | undefined {
46
- return typeof value === 'string' && value.trim() ? value : undefined;
47
- }
48
-
49
- /** Mirror content-index's date coercion: an unquoted YAML date is a JS Date, a string is sliced. */
50
- function asDate(value: unknown): string | undefined {
51
- if (value instanceof Date) return Number.isNaN(value.getTime()) ? undefined : value.toISOString().slice(0, 10);
52
- if (typeof value === 'string') return value.match(/^\d{4}-\d{2}-\d{2}/)?.[0];
53
- return undefined;
54
- }
55
-
56
- /** Build one manifest entry from a content file. Drafts are included and flagged. */
38
+ /** Build one manifest entry from a content file. Drafts are included and flagged. The id, date, and
39
+ * permalink come from entryIdentity, the same source content-index uses, so a cairn: link resolves to
40
+ * one URL whether the admin preview reads the manifest or the public build reads the content index. */
57
41
  export function manifestEntryFromFile(descriptor: ConceptDescriptor, file: { path: string; raw: string }): ManifestEntry {
58
- const id = idFromFilename(basename(file.path));
59
- // Use the same slug rule content-index uses, so the manifest's permalink for an entry always
60
- // equals content-index's permalink for it. A cairn link must resolve to one URL whether the
61
- // admin preview reads the manifest or the public build reads the content index.
62
- const slug = slugFromId(id, descriptor.routing.dated ? descriptor.datePrefix : null);
63
42
  const { frontmatter, body } = parseMarkdown(file.raw);
64
- const date = asDate(frontmatter.date);
43
+ const { id, date, permalink } = entryIdentity(descriptor, file.path, frontmatter);
65
44
  return {
66
45
  id,
67
46
  concept: descriptor.id,
68
47
  title: asString(frontmatter.title) ?? id,
69
48
  date,
70
- permalink: permalink(descriptor, { id, slug, date }),
49
+ permalink,
71
50
  draft: frontmatter.draft === true,
72
51
  links: extractCairnLinks(body),
73
52
  };
@@ -3,8 +3,7 @@
3
3
  // returns cheap plain-data summaries plus an on-demand detail lookup. It is concept-generic:
4
4
  // every operation reads the descriptor and its routing rule, never a hardcoded concept id.
5
5
  import { parseMarkdown } from '../content/frontmatter.js';
6
- import { idFromFilename, slugFromId } from '../content/ids.js';
7
- import { permalink } from '../content/permalink.js';
6
+ import { entryId, entryIdentity, asDate, asString, asTags } from '../content/identity.js';
8
7
  import { deriveExcerpt, wordCount } from './excerpt.js';
9
8
  import type { ConceptDescriptor } from '../content/types.js';
10
9
 
@@ -70,25 +69,6 @@ export function fromGlob(record: Record<string, string>): RawFile[] {
70
69
  return Object.entries(record).map(([path, raw]) => ({ path, raw }));
71
70
  }
72
71
 
73
- function basename(path: string): string {
74
- const slash = path.lastIndexOf('/');
75
- return slash >= 0 ? path.slice(slash + 1) : path;
76
- }
77
-
78
- function asString(value: unknown): string | undefined {
79
- return typeof value === 'string' && value.trim() ? value : undefined;
80
- }
81
-
82
- function asDate(value: unknown): string | undefined {
83
- if (value instanceof Date) return Number.isNaN(value.getTime()) ? undefined : value.toISOString().slice(0, 10);
84
- if (typeof value === 'string') return value.match(/^\d{4}-\d{2}-\d{2}/)?.[0];
85
- return undefined;
86
- }
87
-
88
- function asTags(value: unknown): string[] {
89
- return Array.isArray(value) ? value.map(String) : [];
90
- }
91
-
92
72
  /** Build a concept's index from its raw files and normalized descriptor. */
93
73
  export function createContentIndex<F = Record<string, unknown>>(
94
74
  files: RawFile[],
@@ -97,18 +77,19 @@ export function createContentIndex<F = Record<string, unknown>>(
97
77
  const problems: ContentProblem[] = [];
98
78
  const entries: ContentEntry<F>[] = [];
99
79
  for (const file of files) {
100
- const id = idFromFilename(basename(file.path));
101
- const slug = slugFromId(id, descriptor.routing.dated ? descriptor.datePrefix : null);
102
80
  const { frontmatter: raw, body } = parseMarkdown(file.raw);
103
- const date = asDate(raw.date);
81
+ const id = entryId(file.path);
104
82
  const draft = raw.draft === true;
105
- // Validate once at build. A failure is recorded for the site gate and excluded from the typed
106
- // read, so every readable entry's frontmatter is the validator's normalized output, never raw.
83
+ // Validate before resolving the permalink. A date-token permalink throws on an entry with no
84
+ // valid date; the validate gate records that as a content problem rather than aborting the whole
85
+ // index build, so one bad entry degrades to a skip, not a crash. A failure is also excluded from
86
+ // the typed read, so every readable entry's frontmatter is the validator's normalized output.
107
87
  const result = descriptor.validate(raw, body);
108
88
  if (!result.ok) {
109
89
  problems.push({ id, draft, errors: result.errors });
110
90
  continue;
111
91
  }
92
+ const { slug, date, permalink } = entryIdentity(descriptor, file.path, raw);
112
93
  const summaryFieldValues: Record<string, unknown> = {};
113
94
  for (const key of descriptor.summaryFields) {
114
95
  if (key in result.data) summaryFieldValues[key] = result.data[key];
@@ -117,7 +98,7 @@ export function createContentIndex<F = Record<string, unknown>>(
117
98
  concept: descriptor.id,
118
99
  id,
119
100
  slug,
120
- permalink: permalink(descriptor, { id, slug, date }),
101
+ permalink,
121
102
  title: asString(raw.title) ?? id,
122
103
  date,
123
104
  updated: asDate(raw.updated),
@@ -1,12 +1,11 @@
1
- // cairn-cms: the one-call descriptor helper. A delivery site needs the same per-concept
2
- // descriptors the admin runtime uses; this wraps the two calls that derive them so the
3
- // pairing is not tribal knowledge. The YAML URL policy stays the single source of truth.
4
- import { normalizeConcepts } from '../content/concepts.js';
5
- import { urlPolicyFrom } from '../nav/site-config.js';
1
+ // cairn-cms: the one-call descriptor helper. A delivery site needs the same per-concept descriptors
2
+ // the admin runtime uses; this delegates to the shared resolveConcepts so the pairing is one path, not
3
+ // tribal knowledge. The YAML URL policy stays the single source of truth.
4
+ import { resolveConcepts } from '../content/concepts.js';
6
5
  import type { CairnAdapter, ConceptDescriptor } from '../content/types.js';
7
6
  import type { SiteConfig } from '../nav/site-config.js';
8
7
 
9
8
  /** Per-concept descriptors for a site, from its adapter content and its parsed site config. */
10
9
  export function siteDescriptors(adapter: CairnAdapter, siteConfig: SiteConfig): ConceptDescriptor[] {
11
- return normalizeConcepts(adapter.content, urlPolicyFrom(siteConfig));
10
+ return resolveConcepts(adapter.content, siteConfig);
12
11
  }
package/src/lib/index.ts CHANGED
@@ -88,34 +88,16 @@ export type { ReferenceOptions } from './render/component-reference.js';
88
88
  export { glyph } from './render/glyph.js';
89
89
  export type { IconSet } from './render/glyph.js';
90
90
  export { remarkDirectiveStamp } from './render/remark-directives.js';
91
- export {
92
- rehypeDispatch,
93
- isElement,
94
- strProp,
95
- iconSpan,
96
- cardShell,
97
- headRow,
98
- markFirstList,
99
- } from './render/rehype-dispatch.js';
100
- export type { MakeIcon } from './render/rehype-dispatch.js';
91
+ // The component-authoring helpers (iconSpan, cardShell, headRow, isElement, strAttr) live on the
92
+ // @glw907/cairn-cms/render subpath, not the root barrel. rehypeDispatch is deliberately not public:
93
+ // createRenderer is the one public render pipeline, so the safe plugin ordering is the only public
94
+ // path. See docs/superpowers/specs/2026-06-05-cairn-render-authoring-surface-design.md.
101
95
  export { createRenderer } from './render/pipeline.js';
102
96
  export type { RendererOptions } from './render/pipeline.js';
103
97
 
104
98
  // GitHub read-and-commit backend (Plan 03).
105
99
  export type { RepoRef, RepoFile, CommitAuthor, AppCredentials } from './github/types.js';
106
100
  export { CommitConflictError } from './github/types.js';
107
- export { appJwt, installationToken, signingSelfTest } from './github/signing.js';
108
- export {
109
- treeUrl,
110
- markdownFilesIn,
111
- listMarkdown,
112
- contentsUrl,
113
- readRaw,
114
- fileSha,
115
- commitFile,
116
- } from './github/repo.js';
117
- export { appCredentials } from './github/credentials.js';
118
- export type { GithubKeyEnv } from './github/credentials.js';
119
101
 
120
102
  // Nav tree and site-config helpers (Plan 06).
121
103
  export {
@@ -129,38 +111,3 @@ export {
129
111
  SiteConfigError,
130
112
  } from './nav/site-config.js';
131
113
  export type { NavNode, SiteConfig } from './nav/site-config.js';
132
-
133
- // Public content delivery (public-delivery design): the query index, syndication, and
134
- // discovery surface that sites read. Pure builders plus the one permalink resolver; the
135
- // SvelteKit loaders live under the /sveltekit subpath.
136
- export { permalink } from './content/permalink.js';
137
- export { createContentIndex, fromGlob } from './delivery/content-index.js';
138
- export type {
139
- RawFile,
140
- ContentSummary,
141
- ContentEntry,
142
- ContentIndex,
143
- ContentProblem,
144
- } from './delivery/content-index.js';
145
- export { createSiteIndex } from './delivery/site-index.js';
146
- export type { SiteIndex, ConceptIndex } from './delivery/site-index.js';
147
- export { createSiteIndexes } from './delivery/site-indexes.js';
148
- export type { SiteIndexes, SiteGlobs } from './delivery/site-indexes.js';
149
- export { deriveExcerpt, wordCount } from './delivery/excerpt.js';
150
- export { buildRssFeed, buildJsonFeed } from './delivery/feeds.js';
151
- export type { FeedChannel, FeedItem } from './delivery/feeds.js';
152
- export { buildSitemap } from './delivery/sitemap.js';
153
- export type { SitemapUrl } from './delivery/sitemap.js';
154
- export { buildRobots } from './delivery/robots.js';
155
- export { buildSeoMeta } from './delivery/seo.js';
156
- export type { SeoInput, SeoMeta } from './delivery/seo.js';
157
- export { readSeoFields, resolveImageUrl } from './delivery/seo-fields.js';
158
- export type { SeoFields } from './delivery/seo-fields.js';
159
- export { paginate } from './delivery/paginate.js';
160
- export type { Page } from './delivery/paginate.js';
161
- // Root superset of the delivery route surface: a wrong guess from root for a route loader or a
162
- // response helper now resolves. The CairnHead component stays out of root so the root barrel stays
163
- // node-importable for the unit suite; it resolves from @glw907/cairn-cms/delivery/head.
164
- export { rssResponse, jsonFeedResponse, sitemapResponse, robotsResponse } from './delivery/responses.js';
165
- export { createPublicRoutes } from './sveltekit/public-routes.js';
166
- export type { PublicRoutesDeps, ListData, TagData, TagIndexData, EntryData } from './sveltekit/public-routes.js';
@@ -0,0 +1,7 @@
1
+ // cairn-cms: the component-authoring toolkit (@glw907/cairn-cms/render). A site authoring components
2
+ // through build(ctx) reaches for these hast builders and the string-attribute reader. Curated on
3
+ // purpose: the internal hast helpers (strProp, markFirstList, dataAttrProp) stay internal, and
4
+ // rehypeDispatch is deliberately omitted (createRenderer is the one public render pipeline).
5
+ export { iconSpan, cardShell, headRow, isElement, strAttr } from './rehype-dispatch.js';
6
+ export type { MakeIcon } from './rehype-dispatch.js';
7
+ export type { ComponentContext } from './registry.js';
@@ -9,7 +9,7 @@ import rehypeStringify from 'rehype-stringify';
9
9
  import rehypeSanitize from 'rehype-sanitize';
10
10
  import type { Schema } from 'hast-util-sanitize';
11
11
  import { VFile } from 'vfile';
12
- import { buildSanitizeSchema, rehypeAnchorRel } from './sanitize-schema.js';
12
+ import { buildSanitizeSchema, rehypeAnchorRel, rehypeSinkGuard } from './sanitize-schema.js';
13
13
  import { remarkDirectiveStamp } from './remark-directives.js';
14
14
  import { remarkResolveCairnLinks, CAIRN_RESOLVE } from './resolve-links.js';
15
15
  import { rehypeDispatch } from './rehype-dispatch.js';
@@ -58,6 +58,9 @@ export function createRenderer(
58
58
  rehypeSlug,
59
59
  ];
60
60
  if (rel !== false) rehypePlugins.push([rehypeAnchorRel, rel]);
61
+ // The sink guard runs last, over the fully-built tree, so it neutralizes a sink a component
62
+ // build() emitted after the floor. Gated by the same switch as the floor.
63
+ if (!options.unsafeDisableSanitize) rehypePlugins.push(rehypeSinkGuard);
61
64
  const processor = unified()
62
65
  .use(remarkParse)
63
66
  .use(remarkGfm)
@@ -82,6 +82,8 @@ export interface ComponentRegistry {
82
82
  names: string[];
83
83
  get(name: string): ComponentDef | undefined;
84
84
  defaultIcon(name: string, role?: string): string | undefined;
85
+ /** The component's first `type:'icon'` attribute, or undefined when it declares none. */
86
+ iconField(name: string): AttributeField | undefined;
85
87
  }
86
88
 
87
89
  /** The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
@@ -91,17 +93,35 @@ export function dataAttrProp(key: string): string {
91
93
  return `dataAttr${key.charAt(0).toUpperCase()}${key.slice(1)}`;
92
94
  }
93
95
 
96
+ /** A component's first `type:'icon'` attribute, or undefined when it declares none. Both the
97
+ * construction-time guard and the registry's `iconField` derive the icon field from this one
98
+ * predicate rather than spelling the `type === 'icon'` find twice. */
99
+ function findIconField(def: ComponentDef): AttributeField | undefined {
100
+ return def.attributes?.find((field) => field.type === 'icon');
101
+ }
102
+
94
103
  /**
95
104
  * Build a registry from a site's component definitions. The single source the render
96
105
  * pipeline (directive stamp plus rehype dispatch) and the editor palette both read.
97
106
  */
98
107
  export function defineRegistry({ components }: { components: ComponentDef[] }): ComponentRegistry {
108
+ for (const c of components) {
109
+ if (c.defaultIconByRole && Object.keys(c.defaultIconByRole).length > 0 && !findIconField(c)) {
110
+ throw new Error(
111
+ `cairn: component "${c.name}" sets defaultIconByRole but declares no type:'icon' attribute, so the default icon can never render`,
112
+ );
113
+ }
114
+ }
99
115
  const byName = new Map(components.map((c) => [c.name, c]));
100
116
  return {
101
117
  defs: components,
102
118
  names: components.map((c) => c.name),
103
119
  get: (name) => byName.get(name),
104
120
  defaultIcon: (name, role) => (role ? byName.get(name)?.defaultIconByRole?.[role] : undefined),
121
+ iconField: (name) => {
122
+ const def = byName.get(name);
123
+ return def ? findIconField(def) : undefined;
124
+ },
105
125
  };
106
126
  }
107
127
 
@@ -6,6 +6,13 @@ export function isElement(node: ElementContent | undefined): node is Element {
6
6
  return !!node && node.type === 'element';
7
7
  }
8
8
 
9
+ /** Read a declared string attribute off the component context, returning undefined for a boolean or
10
+ * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats. */
11
+ export function strAttr(ctx: ComponentContext, key: string): string | undefined {
12
+ const value = ctx.attributes[key];
13
+ return typeof value === 'string' ? value : undefined;
14
+ }
15
+
9
16
  // hast Properties values are PropertyValue (string | number | boolean | array | null).
10
17
  // Directive markers (dataPrimitive/dataRole/dataAttr<Key>) are always stamped as strings;
11
18
  // this reads them back with that guarantee instead of casting at each call site.
@@ -28,14 +35,14 @@ export function cardShell(classes: string[], body: ElementContent[]): Element {
28
35
  return h('section', { className: classes }, [h('div', { className: ['card-body'] }, body)]);
29
36
  }
30
37
 
31
- /** Card head row: `<div class="ec-head">[icon]<h2 class="card-title">{title}</h2></div>`.
32
- * Pass the title's inline children and an optional pre-built icon element, the way `cardShell`
33
- * takes already-built body content. This factors the icon-plus-heading head that a titled
34
- * component build would otherwise rebuild by hand (the shape the removed `splitHead` produced). */
35
- export function headRow(title: ElementContent[], icon?: Element): Element {
38
+ /** Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
39
+ * Pass the title's inline children, an optional pre-built icon element, and an optional heading
40
+ * level (default 2). This factors the icon-plus-heading head that a titled component build would
41
+ * otherwise rebuild by hand (the shape the removed `splitHead` produced). */
42
+ export function headRow(title: ElementContent[], icon?: Element, level: number = 2): Element {
36
43
  const children: ElementContent[] = [];
37
44
  if (icon) children.push(icon);
38
- children.push(h('h2', { className: ['card-title'] }, title));
45
+ children.push(h(`h${level}`, { className: ['card-title'] }, title));
39
46
  return h('div', { className: ['ec-head'] }, children);
40
47
  }
41
48
 
@@ -59,7 +59,7 @@ export function remarkDirectiveStamp(registry: ComponentRegistry) {
59
59
  const def = registry.get(node.name);
60
60
  const attrs = node.attributes ?? {};
61
61
  const role = attrs.role || undefined;
62
- const iconField = def?.attributes?.find((field) => field.type === 'icon');
62
+ const iconField = registry.iconField(node.name);
63
63
  const iconKey = iconField?.key ?? 'icon';
64
64
  let icon = attrs[iconKey] || undefined;
65
65
  if (!icon && role) icon = registry.defaultIcon(node.name, role);
@@ -65,3 +65,100 @@ export function rehypeAnchorRel(rel: string) {
65
65
  });
66
66
  };
67
67
  }
68
+
69
+ // URL-bearing hast properties the post-dispatch guard scheme-checks. hast camelCases attribute
70
+ // names through property-information (srcset -> srcSet, xlink:href -> xLinkHref with a capital L,
71
+ // formaction -> formAction). data is the <object data> URL attribute; data-* attributes camelCase
72
+ // to dataFoo and are not matched here.
73
+ const URL_PROPS = new Set([
74
+ 'href',
75
+ 'src',
76
+ 'srcSet',
77
+ 'xLinkHref',
78
+ 'poster',
79
+ 'formAction',
80
+ 'action',
81
+ 'data',
82
+ 'background',
83
+ ]);
84
+
85
+ // The safe URL schemes: the union of every protocol list in defaultSchema, plus cairn. The
86
+ // floor admits these and strips the rest, so deriving from the same source keeps the floor and
87
+ // this guard from drifting on what a safe scheme is. javascript:/data:/vbscript: are never in
88
+ // defaultSchema, so they are never safe.
89
+ const SAFE_SCHEMES: Set<string> = (() => {
90
+ const protocols = defaultSchema.protocols ?? {};
91
+ const schemes = new Set<string>(['cairn']);
92
+ for (const list of Object.values(protocols)) {
93
+ for (const scheme of list ?? []) schemes.add(String(scheme).toLowerCase());
94
+ }
95
+ return schemes;
96
+ })();
97
+
98
+ // Read a URL value's scheme for the safety check, defeating the whitespace and control-character
99
+ // tricks a browser ignores inside a scheme (java\tscript:, a leading space). A value with no
100
+ // scheme (relative, anchor, query) returns undefined and is always safe.
101
+ function urlScheme(value: string): string | undefined {
102
+ const cleaned = value.replace(/[\x00-\x20]+/g, '');
103
+ const match = /^([a-z][a-z0-9+.-]*):/i.exec(cleaned);
104
+ return match ? match[1].toLowerCase() : undefined;
105
+ }
106
+
107
+ function isSafeUrl(value: string): boolean {
108
+ const scheme = urlScheme(value);
109
+ return scheme === undefined || SAFE_SCHEMES.has(scheme);
110
+ }
111
+
112
+ // srcset is "url descriptor, url descriptor, …". hast may store it as a string or, because
113
+ // property-information marks it comma-separated, as a string array. One unsafe candidate makes
114
+ // the whole attribute unsafe.
115
+ function isSafeSrcset(value: unknown): boolean {
116
+ const candidates = Array.isArray(value)
117
+ ? value.map(String)
118
+ : typeof value === 'string'
119
+ ? value.split(',')
120
+ : [];
121
+ return candidates.every((candidate) => {
122
+ const url = candidate.trim().split(/\s+/)[0];
123
+ return url === '' || isSafeUrl(url);
124
+ });
125
+ }
126
+
127
+ // Decide whether one URL-bearing property value is safe to keep. srcset has its own
128
+ // multi-candidate grammar. A non-string value carries no scheme to abuse, so the floor's own
129
+ // handling stands and the guard leaves it alone.
130
+ function isSafeUrlProp(key: string, value: unknown): boolean {
131
+ if (key === 'srcSet') return isSafeSrcset(value);
132
+ if (typeof value !== 'string') return true;
133
+ return isSafeUrl(value);
134
+ }
135
+
136
+ /**
137
+ * Post-dispatch safety floor over the fully-built tree. The pre-dispatch rehype-sanitize floor
138
+ * cleans author content, but a component build() runs after it and can route a raw author
139
+ * attribute value into a sink. This guard runs last and neutralizes those sinks on every element
140
+ * no matter which plugin or which build() produced it: an unsafe URL scheme in a URL-bearing
141
+ * attribute, an inline on* event handler, or an inline style (stripped wholesale, matching the
142
+ * floor and cairn's class-driven styling). It is gated by the same unsafeDisableSanitize switch as
143
+ * the floor.
144
+ *
145
+ * The guard's boundary is the URL scheme check plus the on* and style strip. It does not remove a
146
+ * build()-emitted raw script, style, or iframe srcdoc element node. A build() that emits those is
147
+ * running site-developer code, and author markdown is cleaned by the pre-dispatch floor.
148
+ */
149
+ export function rehypeSinkGuard() {
150
+ return (tree: Root) => {
151
+ visit(tree, 'element', (node: Element) => {
152
+ const props = node.properties;
153
+ if (!props) return;
154
+ for (const key of Object.keys(props)) {
155
+ if (/^on/i.test(key) || key === 'style') {
156
+ delete props[key];
157
+ continue;
158
+ }
159
+ if (!URL_PROPS.has(key)) continue;
160
+ if (!isSafeUrlProp(key, props[key])) delete props[key];
161
+ }
162
+ });
163
+ };
164
+ }
@@ -22,15 +22,20 @@ export interface NavConcept {
22
22
  label: string;
23
23
  }
24
24
 
25
- /** The admin layout's data: site identity, the signed-in user, the nav, and the active path. */
25
+ /** The admin layout's data: site identity, the signed-in user, the nav, the active path, and theme. */
26
26
  export interface LayoutData {
27
27
  siteName: string;
28
- user: { displayName: string; role: Role };
28
+ user: { displayName: string; email: string; role: Role };
29
29
  concepts: NavConcept[];
30
30
  pathname: string;
31
31
  canManageEditors: boolean;
32
32
  /** The nav menu's label when the site configures one; gates the Navigation nav entry. Null otherwise. */
33
33
  navLabel: string | null;
34
+ /** The admin theme resolved for SSR: the persisted cookie choice, or the light default. */
35
+ theme: 'cairn-admin' | 'cairn-admin-dark';
36
+ /** The nav group labels the user has collapsed, from the persisted cookie. Read at SSR so a
37
+ * collapsed group renders collapsed with no flash. Empty when none are collapsed. */
38
+ collapsedNav: string[];
34
39
  }
35
40
 
36
41
  /** One row in a concept's list view. */
@@ -83,6 +88,8 @@ export interface ContentEvent {
83
88
  request: Request;
84
89
  locals: { editor?: Editor | null };
85
90
  platform?: { env?: GithubKeyEnv };
91
+ /** SvelteKit's cookie jar; the layout load reads the persisted admin theme. Optional for non-route callers. */
92
+ cookies?: { get(name: string): string | undefined };
86
93
  }
87
94
 
88
95
  /** Injectable dependencies; tests stub the token mint to avoid signing a real key. */
@@ -109,16 +116,24 @@ export function createContentRoutes(runtime: CairnRuntime, deps: ContentRoutesDe
109
116
  const mintToken =
110
117
  deps.mintToken ?? ((env: GithubKeyEnv) => cachedInstallationToken(appCredentials(runtime.backend, env)));
111
118
 
112
- /** Layout load for every admin page: the nav, the user, and the active path. */
119
+ /** Layout load for every admin page: the nav, the user, the active path, and the resolved theme. */
113
120
  function layoutLoad(event: ContentEvent): LayoutData {
114
121
  const editor = sessionOf(event);
122
+ const cookieTheme = event.cookies?.get('cairn-admin-theme');
123
+ const theme = cookieTheme === 'cairn-admin-dark' ? 'cairn-admin-dark' : 'cairn-admin';
124
+ const cookieCollapsed = event.cookies?.get('cairn-admin-nav-collapsed');
125
+ const collapsedNav = cookieCollapsed
126
+ ? cookieCollapsed.split(',').map((part) => decodeURIComponent(part)).filter(Boolean)
127
+ : [];
115
128
  return {
116
129
  siteName: runtime.siteName,
117
- user: { displayName: editor.displayName, role: editor.role },
130
+ user: { displayName: editor.displayName, email: editor.email, role: editor.role },
118
131
  concepts: runtime.concepts.map((c) => ({ id: c.id, label: c.label })),
119
132
  pathname: event.url.pathname,
120
133
  canManageEditors: editor.role === 'owner',
121
134
  navLabel: runtime.navMenu?.label ?? null,
135
+ theme,
136
+ collapsedNav,
122
137
  };
123
138
  }
124
139
 
@@ -338,14 +353,17 @@ export function createContentRoutes(runtime: CairnRuntime, deps: ContentRoutesDe
338
353
  throw redirect(303, `/admin/${concept.id}/${id}?${savedQuery}`);
339
354
  }
340
355
 
341
- /** Delete an entry. Block-until-clean: refuse while inbound links exist (naming them), else commit
342
- * the file removal and the manifest patch in one commit. The inbound recheck here is the
343
- * authoritative gate, closing the load-to-delete race. */
344
- async function deleteAction(event: ContentEvent): Promise<ReturnType<typeof fail> | never> {
345
- const editor = sessionOf(event);
346
- const concept = conceptOf(runtime, event.params);
347
- const id = event.params.id ?? '';
348
- if (!isValidId(id)) throw error(400, 'Invalid entry id');
356
+ /** The shared delete core. Block-until-clean: refuse while inbound links exist (naming them), else
357
+ * commit the file removal and the manifest patch in one commit. The inbound recheck here is the
358
+ * authoritative gate, closing the load-to-delete race. Both the editor delete (id from params) and
359
+ * the list delete (id from the form body) call this with an already-validated id, so the guard is
360
+ * enforced once. */
361
+ async function deleteEntry(
362
+ event: ContentEvent,
363
+ concept: ConceptDescriptor,
364
+ id: string,
365
+ editor: Editor,
366
+ ): Promise<ReturnType<typeof fail> | never> {
349
367
  const path = `${concept.dir}/${filenameFromId(id)}`;
350
368
  const token = await mintToken(event.platform?.env ?? {});
351
369
 
@@ -355,7 +373,7 @@ export function createContentRoutes(runtime: CairnRuntime, deps: ContentRoutesDe
355
373
  const manifest = manifestRaw === null ? emptyManifest() : parseManifest(manifestRaw);
356
374
  const inbound = inboundLinks(manifest, concept.id, id);
357
375
  if (inbound.length) {
358
- return fail(409, { inboundLinks: inbound });
376
+ return fail(409, { inboundLinks: inbound, id });
359
377
  }
360
378
 
361
379
  const nextManifest = serializeManifest(removeEntry(manifest, concept.id, id));
@@ -379,6 +397,25 @@ export function createContentRoutes(runtime: CairnRuntime, deps: ContentRoutesDe
379
397
  throw redirect(303, `/admin/${concept.id}`);
380
398
  }
381
399
 
400
+ /** Delete an entry from its editor. The id comes from the route param. */
401
+ async function deleteAction(event: ContentEvent): Promise<ReturnType<typeof fail> | never> {
402
+ const editor = sessionOf(event);
403
+ const concept = conceptOf(runtime, event.params);
404
+ const id = event.params.id ?? '';
405
+ if (!isValidId(id)) throw error(400, 'Invalid entry id');
406
+ return deleteEntry(event, concept, id, editor);
407
+ }
408
+
409
+ /** Delete an entry from the concept list. The id comes from the form body. */
410
+ async function listDeleteAction(event: ContentEvent): Promise<ReturnType<typeof fail> | never> {
411
+ const editor = sessionOf(event);
412
+ const concept = conceptOf(runtime, event.params);
413
+ const form = await event.request.formData();
414
+ const id = String(form.get('id') ?? '');
415
+ if (!isValidId(id)) throw error(400, 'Invalid entry id');
416
+ return deleteEntry(event, concept, id, editor);
417
+ }
418
+
382
419
  /** Rename an entry: change its slug, move the file, and rewrite every inbound cairn token in one
383
420
  * atomic commit, so no internal link breaks. The collision check and the inbound recompute here
384
421
  * are the authoritative gate. The same last-writer-wins manifest race as save and delete applies,
@@ -466,5 +503,5 @@ export function createContentRoutes(runtime: CairnRuntime, deps: ContentRoutesDe
466
503
  throw redirect(303, `/admin/${concept.id}/${newId}?renamed=1`);
467
504
  }
468
505
 
469
- return { layoutLoad, indexRedirect, listLoad, createAction, editLoad, saveAction, deleteAction, renameAction, mintToken };
506
+ return { layoutLoad, indexRedirect, listLoad, createAction, editLoad, saveAction, deleteAction, listDeleteAction, renameAction, mintToken };
470
507
  }
@@ -17,11 +17,5 @@ export { createNavRoutes } from './nav-routes.js';
17
17
  export type { NavLoadData, NavPageOption, NavRoutesDeps } from './nav-routes.js';
18
18
  export { healthLoad, type HealthData } from './health.js';
19
19
  export type { RequestContext, CookieJar, HandleInput } from './types.js';
20
- export { createPublicRoutes } from './public-routes.js';
21
- export type {
22
- PublicRoutesDeps,
23
- ListData as PublicListData,
24
- TagData,
25
- TagIndexData,
26
- EntryData,
27
- } from './public-routes.js';
20
+ // Re-exported here, not from root, so the public ContentRoutesDeps consumer can name it.
21
+ export type { GithubKeyEnv } from '../github/credentials.js';
@@ -1 +0,0 @@
1
- {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/lib/auth/crypto.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAEzD;AAED,yCAAyC;AACzC,eAAO,MAAM,YAAY,QAAiB,CAAC;AAE3C,6BAA6B;AAC7B,eAAO,MAAM,cAAc,QAA2B,CAAC;AAEvD,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,QAAY,CAAC;AAU1C,kDAAkD;AAClD,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,4CAA4C;AAC5C,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,oEAAoE;AACpE,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/lib/auth/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQ/C,yCAAyC;AACzC,wBAAsB,UAAU,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMtF;AAED,2EAA2E;AAC3E,wBAAsB,UAAU,CAC9B,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,yGAAyG;AACzG,wBAAsB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnG;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMzG;AAED,4BAA4B;AAC5B,wBAAsB,aAAa,CACjC,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUpG;AAED,iCAAiC;AACjC,wBAAsB,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7E;AAED,2CAA2C;AAC3C,wBAAsB,WAAW,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKnE;AAED,sCAAsC;AACtC,wBAAsB,YAAY,CAChC,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM/E;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAe1F;AAED,iFAAiF;AACjF,wBAAsB,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU1F"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEtC,0FAA0F;AAC1F,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,4FAA4F;AAC5F,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,qGAAqG;IACrG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,OAAO,EAAE;YACZ,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;SACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACnB,CAAC;CACH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"AdminLayout.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/AdminLayout.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,mBAAmB,CAAC;AAGzB,UAAU,KAAK;IACb,4FAA4F;IAC5F,IAAI,EAAE,UAAU,CAAC;IACjB,qBAAqB;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAyEH;;;;;GAKG;AACH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ComponentForm.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ComponentForm.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIhD,UAAU,KAAK;IACb,GAAG,EAAE,YAAY,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B;IAC5B,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAyJH;;;;;GAKG;AACH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ComponentInsertDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ComponentInsertDialog.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIhD,UAAU,KAAK;IACb,qCAAqC;IACrC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,4CAA4C;IAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAkFH;;;;;GAKG;AACH,QAAA,MAAM,qBAAqB,2CAAwC,CAAC;AACpE,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACtE,eAAe,qBAAqB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ConceptList.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ConceptList.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAG7D,UAAU,KAAK;IACb,qFAAqF;IACrF,IAAI,EAAE,QAAQ,CAAC;CAChB;AA2EH;;;GAGG;AACH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ConfirmPage.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ConfirmPage.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,mBAAmB,CAAC;AAGzB,UAAU,KAAK;IACb,0FAA0F;IAC1F,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACjE;AA8BH;;;GAGG;AACH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeleteDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/DeleteDialog.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGxD,UAAU,KAAK;IACb,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAqEH;;;;;GAKG;AACH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"EditPage.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/EditPage.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIrD,UAAU,KAAK;IACb,gEAAgE;IAChE,IAAI,EAAE,QAAQ,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,qIAAqI;IACrI,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,WAAW,CAAA;KAAE,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvG,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;oFACgF;IAChF,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,wBAAwB,EAAE,WAAW,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9I;AAyQH;;;;GAIG;AACH,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"EditorToolbar.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/EditorToolbar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGrD,UAAU,KAAK;IACb,oEAAoE;IACpE,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACpC;AAiDH;;;;;GAKG;AACH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}