@glw907/cairn-cms 0.24.0 → 0.26.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 (42) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +50 -37
  3. package/dist/content/compose.d.ts +15 -4
  4. package/dist/content/compose.d.ts.map +1 -1
  5. package/dist/content/compose.js +9 -4
  6. package/dist/content/manifest.d.ts +20 -3
  7. package/dist/content/manifest.d.ts.map +1 -1
  8. package/dist/content/manifest.js +49 -6
  9. package/dist/content/validate.d.ts +4 -1
  10. package/dist/content/validate.d.ts.map +1 -1
  11. package/dist/content/validate.js +4 -1
  12. package/dist/delivery/content-index.d.ts +4 -0
  13. package/dist/delivery/content-index.d.ts.map +1 -1
  14. package/dist/delivery/data.d.ts +24 -0
  15. package/dist/delivery/data.d.ts.map +1 -0
  16. package/dist/delivery/data.js +18 -0
  17. package/dist/delivery/index.d.ts +1 -23
  18. package/dist/delivery/index.d.ts.map +1 -1
  19. package/dist/delivery/index.js +5 -20
  20. package/dist/index.d.ts +3 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +1 -1
  23. package/dist/render/pipeline.d.ts +2 -2
  24. package/dist/render/pipeline.d.ts.map +1 -1
  25. package/dist/render/pipeline.js +2 -1
  26. package/dist/vite/bin.d.ts +3 -0
  27. package/dist/vite/bin.d.ts.map +1 -0
  28. package/dist/vite/bin.js +9 -0
  29. package/dist/vite/index.d.ts +33 -0
  30. package/dist/vite/index.d.ts.map +1 -0
  31. package/dist/vite/index.js +178 -0
  32. package/package.json +21 -4
  33. package/src/lib/content/compose.ts +18 -9
  34. package/src/lib/content/manifest.ts +63 -7
  35. package/src/lib/content/validate.ts +4 -1
  36. package/src/lib/delivery/content-index.ts +4 -0
  37. package/src/lib/delivery/data.ts +26 -0
  38. package/src/lib/delivery/index.ts +5 -28
  39. package/src/lib/index.ts +3 -1
  40. package/src/lib/render/pipeline.ts +5 -2
  41. package/src/lib/vite/bin.ts +10 -0
  42. package/src/lib/vite/index.ts +213 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are recorded here, most recent first.
4
+
5
+ ## 0.26.0
6
+
7
+ ### Added
8
+ - A `cairnManifest()` Vite plugin (`@glw907/cairn-cms/vite`) verifies the committed content manifest on
9
+ every build and fails the build with a diff naming what drifted. The check runs outside the prerender
10
+ lifecycle, so `handleHttpError` cannot mask it. Consumers must: add `cairnManifest({ configModule,
11
+ content, manifestPath })` to the Vite config.
12
+ - A `cairn-manifest` bin regenerates the committed manifest from a Vite context. Consumers must: set the
13
+ regenerate script to `"cairn:manifest": "cairn-manifest"` and delete the hand-written
14
+ `scripts/build-manifest.mjs`.
15
+ - A node-safe `@glw907/cairn-cms/delivery/data` entry exposes the pure delivery projections with no
16
+ `@sveltejs/kit` in the graph. Consumers must: move any plain-Node import of a delivery data helper
17
+ (such as `buildSiteManifest`) from `@glw907/cairn-cms/delivery` to `@glw907/cairn-cms/delivery/data`.
18
+
19
+ ### Changed
20
+ - `verifyManifest` now throws an error that names the added, removed, and changed entries. Consumers
21
+ must: nothing. The message is strictly more informative.
22
+
23
+ ## 0.25.0
24
+
25
+ ### Changed (breaking)
26
+ - `composeRuntime` now takes a single object, `composeRuntime({ adapter, siteConfig, extensions? })`,
27
+ and derives the per-concept URL policy from `siteConfig`. The loose third `urlPolicy` argument is
28
+ gone, and a missing `siteConfig` throws. Consumers must: pass the parsed site config to every
29
+ `composeRuntime` call and drop any hand-passed URL policy.
30
+
31
+ ### Changed
32
+ - `createRenderer()` now defaults its registry to the empty registry, so a plain-prose site calls
33
+ `createRenderer()` with no argument. Consumers must: nothing; passing a built registry is unchanged.
34
+
35
+ ### Docs
36
+ - A render sanitize-floor reference (`docs/render-sanitize-floor.md`) states what the floor keeps,
37
+ strips, and rewrites, including the `target="_blank"` rel policy.
38
+ - An upgrade guide (`docs/upgrading.md`) collects the `0.x` renames with a consumer action each.
39
+
40
+ ## 0.24.0
41
+
42
+ ### Added
43
+ - `headRow(title, icon?)` builds the icon-plus-heading component head, exported beside `cardShell` and
44
+ `iconSpan`.
45
+ - A `createRenderer` `anchorRel` option sets the `rel` value forced on `target="_blank"` anchors
46
+ (default `'noopener noreferrer'`), or disables the injection when set to `false`.
47
+
48
+ ### Changed
49
+ - A component's `defaultIconByRole` default now reaches the build through the declared `type: 'icon'`
50
+ attribute (`ctx.attributes`), so a role default no longer needs a hardcoded fallback in the build. A
51
+ component using `defaultIconByRole` must declare a `type: 'icon'` attribute.
52
+ - The engine drops an unclaimed directive `[label]` when a component has no `title` slot, so a stray
53
+ `[]` no longer renders an empty paragraph.
54
+
55
+ ### Removed
56
+ - The internal `data-icon` marker, which no build read. The resolved icon now travels on the declared
57
+ attribute path.
58
+
59
+ ## 0.23.0
60
+
61
+ ### Changed (breaking)
62
+ - A `date` field now validates a real `YYYY-MM-DD` calendar date. A site adopting this version whose
63
+ committed content holds a malformed or impossible date will see it fail validation, which is the loud
64
+ failure this restores.
65
+ - A `tags` field now enforces its declared `options` as a closed vocabulary. A committed value outside
66
+ the list fails validation. Use a `freetags` field for free-form tags.
67
+ - `normalizeConcepts` now throws when a `summaryFields` key names no declared field, so a typo fails at
68
+ config load instead of silently producing an empty list card.
69
+
70
+ ### Changed
71
+ - `AttributeField.options` is now `readonly string[]`, so a site can share one frozen `as const`
72
+ vocabulary across components. Read-only by use, so no call site changes.
73
+
74
+ ## 0.22.0
75
+
76
+ ### Added
77
+ - `ContentSummary.concept` and `EntryData.concept`: the read model carries its resolved concept id, so a
78
+ list or page branches per concept without re-deriving it from `entry.date`.
79
+ - A `summaryFields` knob on a concept config surfaces named frontmatter keys on `ContentSummary.fields`,
80
+ so a list card reads an authored field with no per-entry detail read.
81
+ - The package root re-exports the delivery route loaders (`createPublicRoutes`) and the response helpers
82
+ (`rssResponse`, `jsonFeedResponse`, `sitemapResponse`, `robotsResponse`).
83
+
84
+ ### Changed (breaking)
85
+ - `CairnHead` moved off the `@glw907/cairn-cms/delivery` barrel to its own `@glw907/cairn-cms/delivery/head`
86
+ entry, so a node-environment data import from `/delivery` stays component-free. Update the import:
87
+ `import { CairnHead } from '@glw907/cairn-cms/delivery/head'`.
package/README.md CHANGED
@@ -1,32 +1,33 @@
1
1
  # cairn-cms
2
2
 
3
3
  An embedded, **magic-link**, GitHub-committing CMS for SvelteKit + Cloudflare sites.
4
- Non-technical authors log in by email (no GitHub account, no password), edit **raw
5
- markdown** in a [Carta](https://github.com/BearToCode/carta) editor, and save. Each save
6
- commits to `main` via a **GitHub App** (committer = `cairn-cms[bot]`, author = the editor)
7
- and auto-deploys.
4
+ Non-technical authors log in by email (no GitHub account, no password), edit **raw markdown**
5
+ in a client-only CodeMirror editor with a live preview, and save. Each save commits to `main`
6
+ via a **GitHub App** (committer = `cairn-cms[bot]`, author = the editor) and auto-deploys.
8
7
 
9
- It is **design-agnostic**: each consumer site supplies an adapter (collections, slug
10
- convention, frontmatter schema, and its own `renderPreview(md)`), so the same engine drives
11
- sites with completely different markdown pipelines (e.g. [ecnordic.ski](https://ecnordic.ski)
12
- (remark→rehype directive pipeline) and [907.life](https://907.life) (plain `remark-html`)).
8
+ It is **design-agnostic**. Each consumer site supplies an adapter (the content contract through
9
+ `defineAdapter`/`defineFields`, the slug and permalink rules, and its render configuration), so the
10
+ same engine drives sites with completely different markdown pipelines. Two run in production today:
11
+ [ecnordic.ski](https://ecnordic.ski) (a remark-to-rehype directive pipeline) and
12
+ [907.life](https://907.life) (the engine's own `createRenderer`). Content is a fixed set of
13
+ first-class concepts (Posts and Pages), not open-ended collections.
13
14
 
14
15
  ## Status
15
16
 
16
- **`0.4.x`: auth on [better-auth](https://better-auth.com); API not yet frozen.** The core was
17
- built *inside ecnordic.ski first* (the richer proving ground) with the cairn-core ↔ site-adapter
18
- seams designed in from day one, then extracted into this package and validated on a second design
19
- (907.life). Editor auth runs on **better-auth (Cloudflare D1 + magic-link)** behind a scanner-safe
20
- **POST-confirm** flow, with two-tier `owner`/`editor` roles; the GitHub-App commit signer stays
21
- bespoke. The GitHub commit path, Carta preview, the adapter contract, and the shared admin shell
22
- (`/sveltekit` server logic + `/components` Svelte UI + `/auth`) all run on both sites. Pin a caret
23
- range and expect 0.x churn.
24
-
25
- > **Breaking in `0.4.0`** (from `0.3.x`): editor auth moved off the hand-rolled magic-link/KV/
26
- > signed-cookie stack onto better-auth. Each site now needs a **D1 binding** (`AUTH_DB`) +
27
- > committed migrations, an `AUTH_SECRET`, a `/api/auth/[...all]` catch-all + `/admin/auth/confirm`
28
- > shims, and the new `better-auth` + `drizzle-orm` peer deps. Magic links are now POST-confirm
29
- > (a confirm page, not a GET link).
17
+ cairn-cms runs two production sites today, [ecnordic.ski](https://ecnordic.ski) and
18
+ [907.life](https://907.life). It is `0.x` and breaks between minor versions. The author is
19
+ still working through the core-feature roadmap, and the project stays closely held until that
20
+ core lands. See the [ROADMAP](./ROADMAP.md) for what is planned and the
21
+ [CHANGELOG](./CHANGELOG.md) for what changed.
22
+
23
+ Editor auth is self-owned: an atomic single-use magic-link token, a POST-confirm flow, opaque
24
+ D1-backed session rows, and two-tier `owner`/`editor` roles. There is no better-auth, Drizzle,
25
+ or ORM. Pin a caret range and read the CHANGELOG before bumping; every breaking entry carries a
26
+ "Consumers must" line.
27
+
28
+ A contributor who feels inspired is welcome to open an issue or a discussion to start a
29
+ conversation. There is no formal contribution process yet, so this is not an open call for
30
+ pull requests.
30
31
 
31
32
  ## Install
32
33
 
@@ -34,23 +35,35 @@ range and expect 0.x churn.
34
35
  npm install @glw907/cairn-cms
35
36
  ```
36
37
 
37
- Peers: `svelte@^5`, `@sveltejs/kit@^2`, and `carta-md@^4.11` (the editor component). Each site
38
- implements a `CairnAdapter` (see `docs/PLAN.md`) and mounts thin `/admin` route shims around
39
- `@glw907/cairn-cms/sveltekit` (server logic) and `@glw907/cairn-cms/components` (the admin UI).
38
+ Peer dependencies: `svelte@^5` and `@sveltejs/kit@^2`. A consumer site implements a `CairnAdapter`
39
+ and mounts thin `/admin` route shims around the package subpaths:
40
40
 
41
- ## How it's developed
41
+ - `@glw907/cairn-cms`: the core engine and adapter contract.
42
+ - `@glw907/cairn-cms/sveltekit`: the server load and action logic.
43
+ - `@glw907/cairn-cms/components`: the admin Svelte UI.
44
+ - `@glw907/cairn-cms/delivery` and `/delivery/data`: the public read model (indexes, feeds,
45
+ sitemap, SEO head). The `/delivery/data` barrel is node-safe, with no `@sveltejs/kit` in its graph.
46
+ - `@glw907/cairn-cms/vite`: the `cairnManifest()` Vite plugin, paired with the `cairn-manifest` bin,
47
+ that builds and verifies the committed content manifest at build time.
42
48
 
43
- This repo lives in a dev meta-workspace alongside its consumer sites:
49
+ Each site binds a Cloudflare D1 database as `AUTH_DB` (the editor allowlist, sessions, and single-use
50
+ magic tokens) and a `[[send_email]]` binding named `EMAIL`. The worked reference for every shape is
51
+ `examples/showcase`.
44
52
 
45
- ```
46
- ~/Projects/cairn/ # npm workspace root (not a git repo)
47
- cairn-cms/ this repo
48
- ecnordic-ski/ ← consumer (first proving ground)
49
- 907-life/ ← consumer (second design, validates the abstraction)
50
- ```
53
+ ## Documentation
54
+
55
+ The [`docs/`](./docs/README.md) tree is organized in four arms: a tutorial that builds a first
56
+ site end to end, how-to guides for each setup task, a reference for every package export, and
57
+ explanation pages for the architecture and design rules. Start at the
58
+ [documentation index](./docs/README.md). The [security policy](./SECURITY.md) covers reporting
59
+ and the security posture.
60
+
61
+ ## How it's developed
51
62
 
52
- npm workspaces symlink `cairn-cms` into each site's `node_modules` for zero-publish local
53
- dev. In CI, each site pins a published version so deploys stay reproducible.
63
+ This is a standalone repo. Consumer sites install the published package from the npm registry by
64
+ version range. The library's own development proves changes against `examples/showcase`, a
65
+ self-contained SvelteKit site that consumes the package through the relative `file:../..` path, so a
66
+ change is exercised end to end before it publishes.
54
67
 
55
- See **`docs/PLAN.md`** for the full architecture, locked decisions, phased passes, and
56
- risk register.
68
+ The historical rebuild plan and the early architecture writeups live under `docs/internal/`.
69
+ They are kept for history and are not current.
@@ -1,7 +1,18 @@
1
- import type { CairnAdapter, CairnExtension, CairnRuntime, ConceptUrlPolicy } from './types.js';
1
+ import type { CairnAdapter, CairnExtension, CairnRuntime } from './types.js';
2
+ import { type SiteConfig } from '../nav/site-config.js';
3
+ /** The input to {@link composeRuntime}. `siteConfig` is required so the per-concept URL policy is
4
+ * always derived from one source and can never be silently dropped. `extensions` fold in after the
5
+ * adapter's concepts. */
6
+ export interface ComposeInput {
7
+ adapter: CairnAdapter;
8
+ siteConfig: SiteConfig;
9
+ extensions?: CairnExtension[];
10
+ }
2
11
  /**
3
- * Fold an adapter and any extensions into the composed runtime (seam 2). Extension concepts
4
- * merge after the adapter's. The asset slot (seam 4) passes through untouched.
12
+ * Fold an adapter and any extensions into the composed runtime (seam 2). The per-concept URL policy
13
+ * is derived from the site config, the same source the delivery path uses, so the runtime and
14
+ * delivery permalinks cannot diverge. Extension concepts merge after the adapter's. The asset slot
15
+ * (seam 4) passes through untouched.
5
16
  */
6
- export declare function composeRuntime(adapter: CairnAdapter, extensions?: CairnExtension[], urlPolicy?: Record<string, ConceptUrlPolicy | undefined>): CairnRuntime;
17
+ export declare function composeRuntime({ adapter, siteConfig, extensions }: ComposeInput): CairnRuntime;
7
18
  //# sourceMappingURL=compose.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/lib/content/compose.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAc,YAAY,EAAE,cAAc,EAAE,YAAY,EAAiB,gBAAgB,EAAgB,MAAM,YAAY,CAAC;AAGxI;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,UAAU,GAAE,cAAc,EAAO,EACjC,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAM,GAC3D,YAAY,CAyBd"}
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/lib/content/compose.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAc,YAAY,EAAE,cAAc,EAAE,YAAY,EAA+B,MAAM,YAAY,CAAC;AAEtH,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;0BAE0B;AAC1B,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,UAAe,EAAE,EAAE,YAAY,GAAG,YAAY,CA0BnG"}
@@ -1,9 +1,14 @@
1
1
  import { normalizeConcepts } from './concepts.js';
2
+ import { urlPolicyFrom } from '../nav/site-config.js';
2
3
  /**
3
- * Fold an adapter and any extensions into the composed runtime (seam 2). Extension concepts
4
- * merge after the adapter's. The asset slot (seam 4) passes through untouched.
4
+ * Fold an adapter and any extensions into the composed runtime (seam 2). The per-concept URL policy
5
+ * is derived from the site config, the same source the delivery path uses, so the runtime and
6
+ * delivery permalinks cannot diverge. Extension concepts merge after the adapter's. The asset slot
7
+ * (seam 4) passes through untouched.
5
8
  */
6
- export function composeRuntime(adapter, extensions = [], urlPolicy = {}) {
9
+ export function composeRuntime({ adapter, siteConfig, extensions = [] }) {
10
+ if (!siteConfig)
11
+ throw new Error('composeRuntime needs a site config to derive the URL policy');
7
12
  const content = { ...adapter.content };
8
13
  const adminPanels = [];
9
14
  const fieldTypes = [];
@@ -19,7 +24,7 @@ export function composeRuntime(adapter, extensions = [], urlPolicy = {}) {
19
24
  }
20
25
  return {
21
26
  siteName: adapter.siteName,
22
- concepts: normalizeConcepts(content, urlPolicy),
27
+ concepts: normalizeConcepts(content, urlPolicyFrom(siteConfig)),
23
28
  backend: adapter.backend,
24
29
  sender: adapter.sender,
25
30
  render: adapter.render,
@@ -39,9 +39,26 @@ export declare function serializeManifest(manifest: Manifest): string;
39
39
  * error. The build regenerates the manifest, so a real file is always canonical; this guards a
40
40
  * hand-edited or truncated one. */
41
41
  export declare function parseManifest(raw: string): Manifest;
42
- /** Throw if the committed manifest drifts from what the corpus says. Both sides are compared in the
43
- * canonical serialized form, so semantic equality never spuriously fails. The build calls this so a
44
- * raw-git content edit, which leaves the committed manifest stale, fails the build loudly. */
42
+ /** A changed entry and the fields that differ between the built and committed manifests. */
43
+ export interface ManifestEntryDiff {
44
+ concept: string;
45
+ id: string;
46
+ fields: string[];
47
+ }
48
+ /** The drift between a freshly built manifest and the committed one, keyed by concept+id. */
49
+ export interface ManifestDiff {
50
+ added: ManifestEntry[];
51
+ removed: ManifestEntry[];
52
+ changed: ManifestEntryDiff[];
53
+ }
54
+ /** Compare a built manifest against a committed one, keyed by concept+id (the same identity
55
+ * upsertEntry and removeEntry use). A changed entry names the fields that differ. Pure, so it is
56
+ * unit-tested apart from any build. */
57
+ export declare function diffManifests(built: Manifest, committed: Manifest): ManifestDiff;
58
+ /** Throw if the committed manifest drifts from what the corpus says. The canonical serialized form
59
+ * is the fast-path equality guard, so semantic equality never spuriously fails. On a mismatch the
60
+ * error names the added, removed, and changed entries, so a raw-git content edit that leaves the
61
+ * committed manifest stale fails the build loudly with what drifted. */
45
62
  export declare function verifyManifest(built: Manifest, committedRaw: string): void;
46
63
  /** Replace the entry with the same concept and id, or add it. Order does not matter, since
47
64
  * serializeManifest sorts. This is the save path's incremental patch. */
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/lib/content/manifest.ts"],"names":[],"mappings":"AAQA,OAAO,EAAqB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,yFAAyF;AACzF,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAmBD,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAiBvH;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,IAAI,QAAQ,CAExC;AAMD;oGACoG;AACpG,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAW5D;AAED;;;oCAGoC;AACpC,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAqCnD;AAED;;+FAE+F;AAC/F,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAM1E;AAED;0EAC0E;AAC1E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAI9E;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAErF;AAED,2FAA2F;AAC3F,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;sFAEsF;AACtF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,EAAE,CAK3F;AAED;iGACiG;AACjG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,WAAW,CAG/G"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/lib/content/manifest.ts"],"names":[],"mappings":"AAQA,OAAO,EAAqB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,yFAAyF;AACzF,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAmBD,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAiBvH;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,IAAI,QAAQ,CAExC;AAMD;oGACoG;AACpG,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAW5D;AAED;;;oCAGoC;AACpC,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAqCnD;AAED,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAID;;wCAEwC;AACxC,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,YAAY,CAkBhF;AAWD;;;yEAGyE;AACzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAa1E;AAED;0EAC0E;AAC1E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAI9E;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAErF;AAED,2FAA2F;AAC3F,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;sFAEsF;AACtF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,EAAE,CAK3F;AAED;iGACiG;AACjG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,WAAW,CAG/G"}
@@ -104,13 +104,56 @@ export function parseManifest(raw) {
104
104
  }
105
105
  return { version: 1, entries: obj.entries };
106
106
  }
107
- /** Throw if the committed manifest drifts from what the corpus says. Both sides are compared in the
108
- * canonical serialized form, so semantic equality never spuriously fails. The build calls this so a
109
- * raw-git content edit, which leaves the committed manifest stale, fails the build loudly. */
110
- export function verifyManifest(built, committedRaw) {
111
- if (committedRaw !== serializeManifest(built)) {
112
- throw new Error('content manifest is stale: the committed file does not match the corpus. Regenerate it (npm run cairn:manifest) and commit the result.');
107
+ const keyOf = (e) => `${e.concept}/${e.id}`;
108
+ /** Compare a built manifest against a committed one, keyed by concept+id (the same identity
109
+ * upsertEntry and removeEntry use). A changed entry names the fields that differ. Pure, so it is
110
+ * unit-tested apart from any build. */
111
+ export function diffManifests(built, committed) {
112
+ const builtByKey = new Map(built.entries.map((e) => [keyOf(e), e]));
113
+ const committedByKey = new Map(committed.entries.map((e) => [keyOf(e), e]));
114
+ const added = built.entries.filter((e) => !committedByKey.has(keyOf(e)));
115
+ const removed = committed.entries.filter((e) => !builtByKey.has(keyOf(e)));
116
+ const changed = [];
117
+ for (const b of built.entries) {
118
+ const c = committedByKey.get(keyOf(b));
119
+ if (!c)
120
+ continue;
121
+ // ManifestEntry has no index signature, so read its keys through an unknown-cast record.
122
+ const br = b;
123
+ const cr = c;
124
+ const fields = [...new Set([...Object.keys(b), ...Object.keys(c)])].filter((k) => JSON.stringify(br[k]) !== JSON.stringify(cr[k]));
125
+ if (fields.length > 0)
126
+ changed.push({ concept: b.concept, id: b.id, fields });
113
127
  }
128
+ return { added, removed, changed };
129
+ }
130
+ /** Format a diff into a short human-readable block for a build error. */
131
+ function formatDiff(d) {
132
+ const lines = [];
133
+ for (const e of d.added)
134
+ lines.push(` + ${keyOf(e)}`);
135
+ for (const e of d.removed)
136
+ lines.push(` - ${keyOf(e)}`);
137
+ for (const e of d.changed)
138
+ lines.push(` ~ ${e.concept}/${e.id} (${e.fields.join(', ')})`);
139
+ return lines.join('\n');
140
+ }
141
+ /** Throw if the committed manifest drifts from what the corpus says. The canonical serialized form
142
+ * is the fast-path equality guard, so semantic equality never spuriously fails. On a mismatch the
143
+ * error names the added, removed, and changed entries, so a raw-git content edit that leaves the
144
+ * committed manifest stale fails the build loudly with what drifted. */
145
+ export function verifyManifest(built, committedRaw) {
146
+ const builtRaw = serializeManifest(built);
147
+ if (committedRaw === builtRaw)
148
+ return;
149
+ // Diff the canonical built form, not the raw one. serializeManifest sorts each entry's links, so a
150
+ // build whose links are in extraction order would otherwise report a false (links) drift for an
151
+ // entry whose link set is identical and only the order differs. Reuse the serialized form so both
152
+ // sides are canonical.
153
+ const diff = diffManifests(parseManifest(builtRaw), parseManifest(committedRaw));
154
+ throw new Error('content manifest is stale: the committed file does not match the corpus.\n' +
155
+ formatDiff(diff) +
156
+ '\nRegenerate it (npm run cairn:manifest) and commit the result.');
114
157
  }
115
158
  /** Replace the entry with the same concept and id, or add it. Order does not matter, since
116
159
  * serializeManifest sorts. This is the save path's incremental patch. */
@@ -3,7 +3,10 @@ import type { FrontmatterField, ValidationResult } from './types.js';
3
3
  * Validate raw frontmatter against a field list. Required text and date fields must be
4
4
  * non-empty; required tag fields must be non-empty lists. A present boolean coerces to `true`
5
5
  * and an unchecked one is omitted; a present tag field coerces to a string array and an empty
6
- * one is omitted; an empty optional text or date field is omitted, so the normalized data
6
+ * one is omitted, so validated data carries no key for an absent tag field (`tags` or `freetags`).
7
+ * The delivery read model
8
+ * (`ContentSummary.tags`) fills that case with an empty array; the two layers differ on purpose.
9
+ * An empty optional text or date field is omitted, so the normalized data
7
10
  * carries only meaningful values and committed frontmatter stays minimal. Returns the
8
11
  * normalized data, or field-keyed errors when any required field is empty.
9
12
  *
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/lib/content/validate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGrE;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,gBAAgB,EAAE,EAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,gBAAgB,CAoClB"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/lib/content/validate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGrE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,gBAAgB,EAAE,EAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,gBAAgB,CAoClB"}
@@ -3,7 +3,10 @@ import { dateInputValue, isCalendarDate } from './frontmatter.js';
3
3
  * Validate raw frontmatter against a field list. Required text and date fields must be
4
4
  * non-empty; required tag fields must be non-empty lists. A present boolean coerces to `true`
5
5
  * and an unchecked one is omitted; a present tag field coerces to a string array and an empty
6
- * one is omitted; an empty optional text or date field is omitted, so the normalized data
6
+ * one is omitted, so validated data carries no key for an absent tag field (`tags` or `freetags`).
7
+ * The delivery read model
8
+ * (`ContentSummary.tags`) fills that case with an empty array; the two layers differ on purpose.
9
+ * An empty optional text or date field is omitted, so the normalized data
7
10
  * carries only meaningful values and committed frontmatter stays minimal. Returns the
8
11
  * normalized data, or field-keyed errors when any required field is empty.
9
12
  *
@@ -15,6 +15,10 @@ export interface ContentSummary {
15
15
  title: string;
16
16
  date?: string;
17
17
  updated?: string;
18
+ /** The entry's tags, always present as an array and empty when the file declares none. This is the
19
+ * read-model normalization. It differs on purpose from the validated `frontmatter.tags`, which the
20
+ * validator omits when empty, so a published file carries no `tags: []` noise. Read `tags` here for
21
+ * a list; read `frontmatter.tags` only when you need the validated, possibly-absent value. */
18
22
  tags: string[];
19
23
  excerpt: string;
20
24
  wordCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"content-index.d.ts","sourceRoot":"","sources":["../../src/lib/delivery/content-index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,yFAAyF;AACzF,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B;yEACqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf;;mFAE+E;IAC/E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;wEAEwE;AACxE,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,cAAc;IAC/E,WAAW,EAAE,CAAC,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvD,GAAG,CAAC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC9C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,EAAE,CAAC;IACzE,OAAO,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,KAAK,CAAC,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,cAAc,CAAA;KAAE,CAAC;IACzE,sFAAsF;IACtF,QAAQ,IAAI,cAAc,EAAE,CAAC;CAC9B;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,EAAE,CAElE;AAqBD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,KAAK,EAAE,OAAO,EAAE,EAChB,UAAU,EAAE,iBAAiB,GAC5B,YAAY,CAAC,CAAC,CAAC,CA4EjB"}
1
+ {"version":3,"file":"content-index.d.ts","sourceRoot":"","sources":["../../src/lib/delivery/content-index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,yFAAyF;AACzF,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B;yEACqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;mGAG+F;IAC/F,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf;;mFAE+E;IAC/E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;wEAEwE;AACxE,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,cAAc;IAC/E,WAAW,EAAE,CAAC,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvD,GAAG,CAAC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC9C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,EAAE,CAAC;IACzE,OAAO,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,KAAK,CAAC,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,cAAc,CAAA;KAAE,CAAC;IACzE,sFAAsF;IACtF,QAAQ,IAAI,cAAc,EAAE,CAAC;CAC9B;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,EAAE,CAElE;AAqBD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,KAAK,EAAE,OAAO,EAAE,EAChB,UAAU,EAAE,iBAAiB,GAC5B,YAAY,CAAC,CAAC,CAAC,CA4EjB"}
@@ -0,0 +1,24 @@
1
+ export { createContentIndex, fromGlob } from './content-index.js';
2
+ export type { RawFile, ContentSummary, ContentEntry, ContentIndex, ContentProblem } from './content-index.js';
3
+ export { createSiteIndex } from './site-index.js';
4
+ export type { SiteIndex, ConceptIndex } from './site-index.js';
5
+ export { createSiteIndexes } from './site-indexes.js';
6
+ export type { SiteIndexes, SiteGlobs } from './site-indexes.js';
7
+ export { siteDescriptors } from './site-descriptors.js';
8
+ export { deriveExcerpt, wordCount } from './excerpt.js';
9
+ export { buildRssFeed, buildJsonFeed } from './feeds.js';
10
+ export type { FeedChannel, FeedItem } from './feeds.js';
11
+ export { buildSitemap } from './sitemap.js';
12
+ export type { SitemapUrl } from './sitemap.js';
13
+ export { buildRobots } from './robots.js';
14
+ export { buildSeoMeta } from './seo.js';
15
+ export type { SeoInput, SeoMeta } from './seo.js';
16
+ export { readSeoFields, resolveImageUrl } from './seo-fields.js';
17
+ export type { SeoFields } from './seo-fields.js';
18
+ export { paginate } from './paginate.js';
19
+ export type { Page } from './paginate.js';
20
+ export { rssResponse, jsonFeedResponse, sitemapResponse, robotsResponse } from './responses.js';
21
+ export { jsonLdScript } from './json-ld.js';
22
+ export { permalink } from '../content/permalink.js';
23
+ export { buildSiteManifest, buildLinkResolver } from './manifest.js';
24
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/lib/delivery/data.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9G,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,18 @@
1
+ // cairn-cms: the node-safe delivery data surface (@glw907/cairn-cms/delivery/data). The pure corpus
2
+ // projections a SvelteKit site or a plain-Node tool reads, with no @sveltejs/kit and no .svelte in
3
+ // the graph. The full ./delivery barrel re-exports this and adds the route loaders.
4
+ export { createContentIndex, fromGlob } from './content-index.js';
5
+ export { createSiteIndex } from './site-index.js';
6
+ export { createSiteIndexes } from './site-indexes.js';
7
+ export { siteDescriptors } from './site-descriptors.js';
8
+ export { deriveExcerpt, wordCount } from './excerpt.js';
9
+ export { buildRssFeed, buildJsonFeed } from './feeds.js';
10
+ export { buildSitemap } from './sitemap.js';
11
+ export { buildRobots } from './robots.js';
12
+ export { buildSeoMeta } from './seo.js';
13
+ export { readSeoFields, resolveImageUrl } from './seo-fields.js';
14
+ export { paginate } from './paginate.js';
15
+ export { rssResponse, jsonFeedResponse, sitemapResponse, robotsResponse } from './responses.js';
16
+ export { jsonLdScript } from './json-ld.js';
17
+ export { permalink } from '../content/permalink.js';
18
+ export { buildSiteManifest, buildLinkResolver } from './manifest.js';
@@ -1,26 +1,4 @@
1
- export { createContentIndex, fromGlob } from './content-index.js';
2
- export type { RawFile, ContentSummary, ContentEntry, ContentIndex, ContentProblem } from './content-index.js';
3
- export { createSiteIndex } from './site-index.js';
4
- export type { SiteIndex, ConceptIndex } from './site-index.js';
5
- export { createSiteIndexes } from './site-indexes.js';
6
- export type { SiteIndexes, SiteGlobs } from './site-indexes.js';
7
- export { siteDescriptors } from './site-descriptors.js';
8
- export { deriveExcerpt, wordCount } from './excerpt.js';
9
- export { buildRssFeed, buildJsonFeed } from './feeds.js';
10
- export type { FeedChannel, FeedItem } from './feeds.js';
11
- export { buildSitemap } from './sitemap.js';
12
- export type { SitemapUrl } from './sitemap.js';
13
- export { buildRobots } from './robots.js';
14
- export { buildSeoMeta } from './seo.js';
15
- export type { SeoInput, SeoMeta } from './seo.js';
16
- export { readSeoFields, resolveImageUrl } from './seo-fields.js';
17
- export type { SeoFields } from './seo-fields.js';
18
- export { paginate } from './paginate.js';
19
- export type { Page } from './paginate.js';
20
- export { rssResponse, jsonFeedResponse, sitemapResponse, robotsResponse } from './responses.js';
21
- export { jsonLdScript } from './json-ld.js';
22
- export { permalink } from '../content/permalink.js';
23
- export { buildSiteManifest, buildLinkResolver } from './manifest.js';
1
+ export * from './data.js';
24
2
  export { createPublicRoutes } from '../sveltekit/public-routes.js';
25
3
  export type { PublicRoutesDeps, ListData, TagData, TagIndexData, EntryData, } from '../sveltekit/public-routes.js';
26
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/delivery/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9G,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,SAAS,GACV,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/delivery/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,SAAS,GACV,MAAM,+BAA+B,CAAC"}
@@ -1,21 +1,6 @@
1
- // cairn-cms: the public delivery entry (@glw907/cairn-cms/delivery). The complete, canonical,
2
- // backend-free toolkit a SvelteKit site wires its public pages with: the content index and the
3
- // site resolver, the descriptor helper, the syndication and SEO builders, the endpoint response
4
- // helpers, the catch-all route loaders, and the head component. It imports nothing from auth,
5
- // github, or email, so importing it does not pull the server backend into a public bundle.
6
- export { createContentIndex, fromGlob } from './content-index.js';
7
- export { createSiteIndex } from './site-index.js';
8
- export { createSiteIndexes } from './site-indexes.js';
9
- export { siteDescriptors } from './site-descriptors.js';
10
- export { deriveExcerpt, wordCount } from './excerpt.js';
11
- export { buildRssFeed, buildJsonFeed } from './feeds.js';
12
- export { buildSitemap } from './sitemap.js';
13
- export { buildRobots } from './robots.js';
14
- export { buildSeoMeta } from './seo.js';
15
- export { readSeoFields, resolveImageUrl } from './seo-fields.js';
16
- export { paginate } from './paginate.js';
17
- export { rssResponse, jsonFeedResponse, sitemapResponse, robotsResponse } from './responses.js';
18
- export { jsonLdScript } from './json-ld.js';
19
- export { permalink } from '../content/permalink.js';
20
- export { buildSiteManifest, buildLinkResolver } from './manifest.js';
1
+ // cairn-cms: the public delivery entry (@glw907/cairn-cms/delivery). The node-safe data surface
2
+ // (re-exported from ./delivery/data) plus the SvelteKit catch-all route loaders. The head component
3
+ // lives at ./delivery/head. Importing this pulls @sveltejs/kit through the route loaders, so a
4
+ // plain-Node tool imports from ./delivery/data instead.
5
+ export * from './data.js';
21
6
  export { createPublicRoutes } from '../sveltekit/public-routes.js';
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export { buildMagicLinkMessage, cloudflareSend } from './email.js';
5
5
  export type { CairnAdapter, ConceptConfig, FrontmatterField, TextField, TextareaField, DateField, BooleanField, TagsField, FreeTagsField, ValidationResult, BackendConfig, SenderConfig, NavMenuConfig, AssetConfig, RoutingRule, ConceptDescriptor, ConceptUrlPolicy, CairnExtension, CairnRuntime, AdminPanel, FieldTypeDef, } from './content/types.js';
6
6
  export { CONCEPT_ROUTING, normalizeConcepts, findConcept } from './content/concepts.js';
7
7
  export { composeRuntime } from './content/compose.js';
8
+ export type { ComposeInput } from './content/compose.js';
8
9
  export { frontmatterFromForm, dateInputValue, serializeMarkdown, parseMarkdown, } from './content/frontmatter.js';
9
10
  export { defineFields } from './content/schema.js';
10
11
  export { defineAdapter } from './content/adapter.js';
@@ -13,8 +14,8 @@ export { isValidId, idFromFilename, filenameFromId, slugify, slugFromId, compose
13
14
  export type { DatePrefix } from './content/ids.js';
14
15
  export { parseCairnToken, extractCairnLinks, formatCairnToken, escapeLinkText } from './content/links.js';
15
16
  export type { CairnRef, LinkResolve } from './content/links.js';
16
- export { serializeManifest, parseManifest, emptyManifest, verifyManifest, upsertEntry, removeEntry, manifestEntryFromFile, manifestLinkResolver, inboundLinks, } from './content/manifest.js';
17
- export type { Manifest, ManifestEntry, LinkTarget, InboundLink } from './content/manifest.js';
17
+ export { serializeManifest, parseManifest, emptyManifest, verifyManifest, diffManifests, upsertEntry, removeEntry, manifestEntryFromFile, manifestLinkResolver, inboundLinks, } from './content/manifest.js';
18
+ export type { Manifest, ManifestEntry, ManifestDiff, ManifestEntryDiff, LinkTarget, InboundLink } from './content/manifest.js';
18
19
  export { defineRegistry, emptyValues } from './render/registry.js';
19
20
  export type { ComponentDef, ComponentRegistry, FieldType, AttributeField, SlotKind, SlotDef, ComponentValues, } from './render/registry.js';
20
21
  export { serializeComponent, parseComponent } from './render/component-grammar.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ export { isValidId, idFromFilename, filenameFromId, slugify, slugFromId, compose
12
12
  // builder and the request-time resolver ship from the delivery entry; this surface is the
13
13
  // grammar, the manifest operations, and their types a migrating site adopts.
14
14
  export { parseCairnToken, extractCairnLinks, formatCairnToken, escapeLinkText } from './content/links.js';
15
- export { serializeManifest, parseManifest, emptyManifest, verifyManifest, upsertEntry, removeEntry, manifestEntryFromFile, manifestLinkResolver, inboundLinks, } from './content/manifest.js';
15
+ export { serializeManifest, parseManifest, emptyManifest, verifyManifest, diffManifests, upsertEntry, removeEntry, manifestEntryFromFile, manifestLinkResolver, inboundLinks, } from './content/manifest.js';
16
16
  // Render engine (Plan 04): generic directive pipeline; sites own the component registry.
17
17
  export { defineRegistry, emptyValues } from './render/registry.js';
18
18
  export { serializeComponent, parseComponent } from './render/component-grammar.js';