@glw907/cairn-cms 0.7.0 → 0.9.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.
- package/dist/components/ConceptList.svelte +8 -4
- package/dist/components/ConceptList.svelte.d.ts.map +1 -1
- package/dist/components/EditPage.svelte +4 -6
- package/dist/components/EditPage.svelte.d.ts +1 -3
- package/dist/components/EditPage.svelte.d.ts.map +1 -1
- package/dist/components/EditorToolbar.svelte +61 -0
- package/dist/components/EditorToolbar.svelte.d.ts +15 -0
- package/dist/components/EditorToolbar.svelte.d.ts.map +1 -0
- package/dist/components/MarkdownEditor.svelte +96 -57
- package/dist/components/MarkdownEditor.svelte.d.ts +5 -6
- package/dist/components/MarkdownEditor.svelte.d.ts.map +1 -1
- package/dist/components/markdown-format.d.ts +13 -0
- package/dist/components/markdown-format.d.ts.map +1 -0
- package/dist/components/markdown-format.js +23 -0
- package/dist/content/compose.d.ts +2 -2
- package/dist/content/compose.d.ts.map +1 -1
- package/dist/content/compose.js +2 -2
- package/dist/content/concepts.d.ts +7 -6
- package/dist/content/concepts.d.ts.map +1 -1
- package/dist/content/concepts.js +9 -6
- package/dist/content/ids.d.ts +14 -0
- package/dist/content/ids.d.ts.map +1 -1
- package/dist/content/ids.js +40 -0
- package/dist/content/permalink.d.ts +1 -0
- package/dist/content/permalink.d.ts.map +1 -1
- package/dist/content/permalink.js +1 -1
- package/dist/content/types.d.ts +12 -6
- package/dist/content/types.d.ts.map +1 -1
- package/dist/delivery/content-index.d.ts +1 -0
- package/dist/delivery/content-index.d.ts.map +1 -1
- package/dist/delivery/content-index.js +4 -2
- package/dist/delivery/site-index.d.ts +28 -0
- package/dist/delivery/site-index.d.ts.map +1 -0
- package/dist/delivery/site-index.js +38 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/nav/site-config.d.ts +5 -0
- package/dist/nav/site-config.d.ts.map +1 -1
- package/dist/nav/site-config.js +4 -0
- package/dist/render/pipeline.d.ts +1 -1
- package/dist/render/pipeline.js +1 -1
- package/dist/render/sanitize.js +2 -2
- package/dist/sveltekit/content-routes.d.ts.map +1 -1
- package/dist/sveltekit/content-routes.js +18 -8
- package/dist/sveltekit/public-routes.d.ts +11 -12
- package/dist/sveltekit/public-routes.d.ts.map +1 -1
- package/dist/sveltekit/public-routes.js +36 -35
- package/package.json +7 -3
- package/src/lib/components/ConceptList.svelte +8 -4
- package/src/lib/components/EditPage.svelte +4 -6
- package/src/lib/components/EditorToolbar.svelte +61 -0
- package/src/lib/components/MarkdownEditor.svelte +96 -57
- package/src/lib/components/markdown-format.ts +39 -0
- package/src/lib/content/compose.ts +3 -2
- package/src/lib/content/concepts.ts +10 -6
- package/src/lib/content/ids.ts +44 -0
- package/src/lib/content/permalink.ts +2 -2
- package/src/lib/content/types.ts +13 -6
- package/src/lib/delivery/content-index.ts +5 -2
- package/src/lib/delivery/site-index.ts +68 -0
- package/src/lib/index.ts +13 -1
- package/src/lib/nav/site-config.ts +8 -0
- package/src/lib/render/pipeline.ts +1 -1
- package/src/lib/render/sanitize.ts +2 -2
- package/src/lib/sveltekit/content-routes.ts +17 -7
- package/src/lib/sveltekit/public-routes.ts +38 -36
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permalink.d.ts","sourceRoot":"","sources":["../../src/lib/content/permalink.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAWpD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,iBAAiB,EAC7B,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"permalink.d.ts","sourceRoot":"","sources":["../../src/lib/content/permalink.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAWpD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,iBAAiB,EAC7B,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD,MAAM,CAgBR"}
|
|
@@ -13,7 +13,7 @@ function dateParts(date) {
|
|
|
13
13
|
export function permalink(descriptor, entry) {
|
|
14
14
|
return descriptor.permalink.replace(/:(\w+)/g, (_match, token) => {
|
|
15
15
|
if (token === 'slug')
|
|
16
|
-
return entry.
|
|
16
|
+
return entry.slug;
|
|
17
17
|
if (token === 'year' || token === 'month' || token === 'day') {
|
|
18
18
|
const parts = dateParts(entry.date);
|
|
19
19
|
if (!parts) {
|
package/dist/content/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ComponentRegistry } from '../render/registry.js';
|
|
2
|
+
import type { DatePrefix } from './ids.js';
|
|
2
3
|
/** Common to every frontmatter field: the frontmatter key, the form label, and whether it is required. */
|
|
3
4
|
interface FieldBase {
|
|
4
5
|
/** Frontmatter key and form input name. */
|
|
@@ -68,13 +69,16 @@ export interface ConceptConfig {
|
|
|
68
69
|
fields: FrontmatterField[];
|
|
69
70
|
/** Validate submitted frontmatter before any commit. */
|
|
70
71
|
validate(frontmatter: Record<string, unknown>, body: string): ValidationResult;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A concept's URL policy, set per concept in the YAML site-config (not the adapter). `permalink` is
|
|
75
|
+
* a `/`-prefixed pattern of literal segments and the tokens `:slug`, `:year`, `:month`, `:day`.
|
|
76
|
+
* `datePrefix` is the filename date-prefix granularity for a dated concept. Both default in
|
|
77
|
+
* `normalizeConcepts` when omitted.
|
|
78
|
+
*/
|
|
79
|
+
export interface ConceptUrlPolicy {
|
|
77
80
|
permalink?: string;
|
|
81
|
+
datePrefix?: DatePrefix;
|
|
78
82
|
}
|
|
79
83
|
/** The GitHub App backend a site reads from and commits to (spec §8). Plain data the GitHub engine (Plan 03) consumes. */
|
|
80
84
|
export interface BackendConfig {
|
|
@@ -154,6 +158,8 @@ export interface ConceptDescriptor {
|
|
|
154
158
|
routing: RoutingRule;
|
|
155
159
|
/** The resolved permalink pattern, defaulted by `normalizeConcepts`. */
|
|
156
160
|
permalink: string;
|
|
161
|
+
/** Filename date-prefix granularity for a dated concept; resolved by `normalizeConcepts`. */
|
|
162
|
+
datePrefix: DatePrefix;
|
|
157
163
|
fields: FrontmatterField[];
|
|
158
164
|
validate(frontmatter: Record<string, unknown>, body: string): ValidationResult;
|
|
159
165
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/content/types.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/content/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,EAAE,EAAE,MAAM,CAAC;IACX,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;CAChB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC3C,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;CAC1E;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,EAAE,CAElE;AAqBD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,iBAAiB,GAAG,YAAY,
|
|
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,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;CAChB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC3C,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;CAC1E;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,EAAE,CAElE;AAqBD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,iBAAiB,GAAG,YAAY,CA2DhG"}
|
|
@@ -3,7 +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 } from '../content/ids.js';
|
|
6
|
+
import { idFromFilename, slugFromId } from '../content/ids.js';
|
|
7
7
|
import { permalink } from '../content/permalink.js';
|
|
8
8
|
import { deriveExcerpt, wordCount } from './excerpt.js';
|
|
9
9
|
/** Map a Vite eager `?raw` glob record (`{ path: raw }`) to `RawFile[]`. */
|
|
@@ -31,11 +31,13 @@ function asTags(value) {
|
|
|
31
31
|
export function createContentIndex(files, descriptor) {
|
|
32
32
|
const entries = files.map((file) => {
|
|
33
33
|
const id = idFromFilename(basename(file.path));
|
|
34
|
+
const slug = slugFromId(id, descriptor.routing.dated ? descriptor.datePrefix : null);
|
|
34
35
|
const { frontmatter, body } = parseMarkdown(file.raw);
|
|
35
36
|
const date = asDate(frontmatter.date);
|
|
36
37
|
return {
|
|
37
38
|
id,
|
|
38
|
-
|
|
39
|
+
slug,
|
|
40
|
+
permalink: permalink(descriptor, { id, slug, date }),
|
|
39
41
|
title: asString(frontmatter.title) ?? id,
|
|
40
42
|
date,
|
|
41
43
|
updated: asDate(frontmatter.updated),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ConceptDescriptor } from '../content/types.js';
|
|
2
|
+
import type { ContentEntry, ContentIndex, ContentSummary } from './content-index.js';
|
|
3
|
+
/** One concept's descriptor paired with its built index. */
|
|
4
|
+
export interface ConceptIndex {
|
|
5
|
+
descriptor: ConceptDescriptor;
|
|
6
|
+
index: ContentIndex;
|
|
7
|
+
}
|
|
8
|
+
/** The cross-concept query surface a catch-all route and the sitemap read. */
|
|
9
|
+
export interface SiteIndex {
|
|
10
|
+
/** Resolve a request path (with or without a trailing slash) to its entry, or undefined. */
|
|
11
|
+
byPermalink(path: string): ContentEntry | undefined;
|
|
12
|
+
/** Newer/older neighbors within the entry's own concept, for prev/next links. */
|
|
13
|
+
adjacent(entry: ContentSummary): {
|
|
14
|
+
newer?: ContentSummary;
|
|
15
|
+
older?: ContentSummary;
|
|
16
|
+
};
|
|
17
|
+
/** Every entry's path across concepts, leading slash stripped, for SvelteKit `[...path]` prerender. */
|
|
18
|
+
entries(): {
|
|
19
|
+
path: string;
|
|
20
|
+
}[];
|
|
21
|
+
/** One concept's index, for its archive, tag, and feed loaders. */
|
|
22
|
+
concept(id: string): ContentIndex | undefined;
|
|
23
|
+
/** Every non-draft summary across concepts, for the site-wide sitemap. */
|
|
24
|
+
all(): ContentSummary[];
|
|
25
|
+
}
|
|
26
|
+
/** Union per-concept indexes into a site-level resolver; throw on a duplicate permalink. */
|
|
27
|
+
export declare function createSiteIndex(concepts: ConceptIndex[]): SiteIndex;
|
|
28
|
+
//# sourceMappingURL=site-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-index.d.ts","sourceRoot":"","sources":["../../src/lib/delivery/site-index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAErF,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,8EAA8E;AAC9E,MAAM,WAAW,SAAS;IACxB,4FAA4F;IAC5F,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IACpD,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG;QAAE,KAAK,CAAC,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,cAAc,CAAA;KAAE,CAAC;IACpF,uGAAuG;IACvG,OAAO,IAAI;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9B,mEAAmE;IACnE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC9C,0EAA0E;IAC1E,GAAG,IAAI,cAAc,EAAE,CAAC;CACzB;AAOD,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,CAkCnE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Strip a trailing slash from a path, keeping the root "/" intact. */
|
|
2
|
+
function normalizePath(path) {
|
|
3
|
+
return path.length > 1 ? path.replace(/\/+$/, '') : path;
|
|
4
|
+
}
|
|
5
|
+
/** Union per-concept indexes into a site-level resolver; throw on a duplicate permalink. */
|
|
6
|
+
export function createSiteIndex(concepts) {
|
|
7
|
+
const byPath = new Map();
|
|
8
|
+
const byId = new Map();
|
|
9
|
+
for (const { descriptor, index } of concepts) {
|
|
10
|
+
byId.set(descriptor.id, index);
|
|
11
|
+
for (const summary of index.all()) {
|
|
12
|
+
const existing = byPath.get(summary.permalink);
|
|
13
|
+
if (existing) {
|
|
14
|
+
throw new Error(`site index: "${existing.id}" and "${summary.id}" both resolve to "${summary.permalink}"`);
|
|
15
|
+
}
|
|
16
|
+
byPath.set(summary.permalink, { index, id: summary.id });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
byPermalink(path) {
|
|
21
|
+
const hit = byPath.get(normalizePath(path));
|
|
22
|
+
return hit ? hit.index.byId(hit.id) : undefined;
|
|
23
|
+
},
|
|
24
|
+
adjacent(entry) {
|
|
25
|
+
const hit = byPath.get(entry.permalink);
|
|
26
|
+
return hit ? hit.index.adjacent(entry.id) : {};
|
|
27
|
+
},
|
|
28
|
+
entries() {
|
|
29
|
+
return [...byPath.keys()].map((p) => ({ path: p.replace(/^\//, '') }));
|
|
30
|
+
},
|
|
31
|
+
concept(id) {
|
|
32
|
+
return byId.get(id);
|
|
33
|
+
},
|
|
34
|
+
all() {
|
|
35
|
+
return concepts.flatMap(({ index }) => index.all());
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,12 +2,13 @@ export { requireOrigin } from './env.js';
|
|
|
2
2
|
export type { Role, Editor, AuthEnv } from './auth/types.js';
|
|
3
3
|
export type { AuthBranding, MagicLinkMessage, SendMagicLink } from './email.js';
|
|
4
4
|
export { buildMagicLinkMessage, cloudflareSend } from './email.js';
|
|
5
|
-
export type { CairnAdapter, ConceptConfig, FrontmatterField, TextField, TextareaField, DateField, BooleanField, TagsField, FreeTagsField, ValidationResult, BackendConfig, SenderConfig, NavMenuConfig, AssetConfig, RoutingRule, ConceptDescriptor, CairnExtension, CairnRuntime, AdminPanel, FieldTypeDef, } from './content/types.js';
|
|
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
8
|
export { frontmatterFromForm, dateInputValue, serializeMarkdown, parseMarkdown, } from './content/frontmatter.js';
|
|
9
9
|
export { validateFields } from './content/validate.js';
|
|
10
|
-
export { isValidId, idFromFilename, filenameFromId, slugify } from './content/ids.js';
|
|
10
|
+
export { isValidId, idFromFilename, filenameFromId, slugify, slugFromId, composeDatedId, } from './content/ids.js';
|
|
11
|
+
export type { DatePrefix } from './content/ids.js';
|
|
11
12
|
export { defineRegistry } from './render/registry.js';
|
|
12
13
|
export type { ComponentDef, ComponentRegistry } from './render/registry.js';
|
|
13
14
|
export { glyph } from './render/glyph.js';
|
|
@@ -23,11 +24,13 @@ export { appJwt, installationToken, signingSelfTest } from './github/signing.js'
|
|
|
23
24
|
export { treeUrl, markdownFilesIn, listMarkdown, contentsUrl, readRaw, fileSha, commitFile, } from './github/repo.js';
|
|
24
25
|
export { appCredentials } from './github/credentials.js';
|
|
25
26
|
export type { GithubKeyEnv } from './github/credentials.js';
|
|
26
|
-
export { parseSiteConfig, extractMenu, setMenu, validateNavTree, MAX_NAV_NODES, NavValidationError, SiteConfigError, } from './nav/site-config.js';
|
|
27
|
+
export { parseSiteConfig, urlPolicyFrom, extractMenu, setMenu, validateNavTree, MAX_NAV_NODES, NavValidationError, SiteConfigError, } from './nav/site-config.js';
|
|
27
28
|
export type { NavNode, SiteConfig } from './nav/site-config.js';
|
|
28
29
|
export { permalink } from './content/permalink.js';
|
|
29
30
|
export { createContentIndex, fromGlob } from './delivery/content-index.js';
|
|
30
31
|
export type { RawFile, ContentSummary, ContentEntry, ContentIndex, } from './delivery/content-index.js';
|
|
32
|
+
export { createSiteIndex } from './delivery/site-index.js';
|
|
33
|
+
export type { SiteIndex, ConceptIndex } from './delivery/site-index.js';
|
|
31
34
|
export { deriveExcerpt, wordCount } from './delivery/excerpt.js';
|
|
32
35
|
export { buildRssFeed, buildJsonFeed } from './delivery/feeds.js';
|
|
33
36
|
export type { FeedChannel, FeedItem } from './delivery/feeds.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGnE,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,UAAU,EACV,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export { CONCEPT_ROUTING, normalizeConcepts, findConcept } from './content/conce
|
|
|
6
6
|
export { composeRuntime } from './content/compose.js';
|
|
7
7
|
export { frontmatterFromForm, dateInputValue, serializeMarkdown, parseMarkdown, } from './content/frontmatter.js';
|
|
8
8
|
export { validateFields } from './content/validate.js';
|
|
9
|
-
export { isValidId, idFromFilename, filenameFromId, slugify } from './content/ids.js';
|
|
9
|
+
export { isValidId, idFromFilename, filenameFromId, slugify, slugFromId, composeDatedId, } from './content/ids.js';
|
|
10
10
|
// Render engine (Plan 04): generic directive pipeline; sites own the component registry.
|
|
11
11
|
export { defineRegistry } from './render/registry.js';
|
|
12
12
|
export { glyph } from './render/glyph.js';
|
|
@@ -18,12 +18,13 @@ export { appJwt, installationToken, signingSelfTest } from './github/signing.js'
|
|
|
18
18
|
export { treeUrl, markdownFilesIn, listMarkdown, contentsUrl, readRaw, fileSha, commitFile, } from './github/repo.js';
|
|
19
19
|
export { appCredentials } from './github/credentials.js';
|
|
20
20
|
// Nav tree and site-config helpers (Plan 06).
|
|
21
|
-
export { parseSiteConfig, extractMenu, setMenu, validateNavTree, MAX_NAV_NODES, NavValidationError, SiteConfigError, } from './nav/site-config.js';
|
|
21
|
+
export { parseSiteConfig, urlPolicyFrom, extractMenu, setMenu, validateNavTree, MAX_NAV_NODES, NavValidationError, SiteConfigError, } from './nav/site-config.js';
|
|
22
22
|
// Public content delivery (public-delivery design): the query index, syndication, and
|
|
23
23
|
// discovery surface that sites read. Pure builders plus the one permalink resolver; the
|
|
24
24
|
// SvelteKit loaders live under the /sveltekit subpath.
|
|
25
25
|
export { permalink } from './content/permalink.js';
|
|
26
26
|
export { createContentIndex, fromGlob } from './delivery/content-index.js';
|
|
27
|
+
export { createSiteIndex } from './delivery/site-index.js';
|
|
27
28
|
export { deriveExcerpt, wordCount } from './delivery/excerpt.js';
|
|
28
29
|
export { buildRssFeed, buildJsonFeed } from './delivery/feeds.js';
|
|
29
30
|
export { buildSitemap } from './delivery/sitemap.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConceptUrlPolicy } from '../content/types.js';
|
|
1
2
|
/** One navigation node. An omitted or empty `url` is a label-only grouping header; no `children` is a leaf. */
|
|
2
3
|
export interface NavNode {
|
|
3
4
|
label: string;
|
|
@@ -31,6 +32,8 @@ export interface SiteConfig {
|
|
|
31
32
|
locale?: string;
|
|
32
33
|
/** Named navigation menus, each a NavNode[] (normalized by extractMenu). */
|
|
33
34
|
menus?: Record<string, unknown>;
|
|
35
|
+
/** Per-concept URL policy: the permalink pattern and date-prefix granularity, keyed by concept id. */
|
|
36
|
+
content?: Record<string, ConceptUrlPolicy>;
|
|
34
37
|
[key: string]: unknown;
|
|
35
38
|
}
|
|
36
39
|
export declare class SiteConfigError extends Error {
|
|
@@ -40,6 +43,8 @@ export declare class SiteConfigError extends Error {
|
|
|
40
43
|
export declare function parseSiteConfig(raw: string): SiteConfig;
|
|
41
44
|
/** Extract one named menu from a parsed config and validate it. Returns [] when the menu is absent. */
|
|
42
45
|
export declare function extractMenu(config: SiteConfig, name: string, maxDepth: number): NavNode[];
|
|
46
|
+
/** The per-concept URL policy from a parsed config, or an empty policy when the `content` key is absent. */
|
|
47
|
+
export declare function urlPolicyFrom(config: SiteConfig): Record<string, ConceptUrlPolicy>;
|
|
43
48
|
/**
|
|
44
49
|
* Replace one named menu in the YAML site-config text and reserialize, preserving every other
|
|
45
50
|
* top-level key (siteName, other menus, settings). Parses into a Document so the rest of the file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/lib/nav/site-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/lib/nav/site-config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,+GAA+G;AAC/G,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,iDAAiD;AACjD,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,+CAA+C;AAC/C,eAAO,MAAM,cAAc,OAAO,CAAC;AAKnC,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CA6B3E;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,sGAAsG;IACtG,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,uGAAuG;AACvG,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAUvD;AAED,uGAAuG;AACvG,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAIzF;AAED,4GAA4G;AAC5G,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAElF;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAO1E"}
|
package/dist/nav/site-config.js
CHANGED
|
@@ -84,6 +84,10 @@ export function extractMenu(config, name, maxDepth) {
|
|
|
84
84
|
return [];
|
|
85
85
|
return validateNavTree(menu, maxDepth);
|
|
86
86
|
}
|
|
87
|
+
/** The per-concept URL policy from a parsed config, or an empty policy when the `content` key is absent. */
|
|
88
|
+
export function urlPolicyFrom(config) {
|
|
89
|
+
return config.content ?? {};
|
|
90
|
+
}
|
|
87
91
|
/**
|
|
88
92
|
* Replace one named menu in the YAML site-config text and reserialize, preserving every other
|
|
89
93
|
* top-level key (siteName, other menus, settings). Parses into a Document so the rest of the file
|
|
@@ -8,7 +8,7 @@ export interface RendererOptions {
|
|
|
8
8
|
}
|
|
9
9
|
/** Compose a site's render pipeline from its component registry: directive syntax to
|
|
10
10
|
* stamped markers to registry-built hast. Returns `renderMarkdown` plus the remark/
|
|
11
|
-
* rehype plugin arrays (so the
|
|
11
|
+
* rehype plugin arrays (so the admin editor preview can reuse the exact same set). */
|
|
12
12
|
export declare function createRenderer(registry: ComponentRegistry, options?: RendererOptions): {
|
|
13
13
|
remarkPlugins: PluggableList;
|
|
14
14
|
rehypePlugins: PluggableList;
|
package/dist/render/pipeline.js
CHANGED
|
@@ -10,7 +10,7 @@ import { remarkDirectiveStamp } from './remark-directives.js';
|
|
|
10
10
|
import { rehypeDispatch } from './rehype-dispatch.js';
|
|
11
11
|
/** Compose a site's render pipeline from its component registry: directive syntax to
|
|
12
12
|
* stamped markers to registry-built hast. Returns `renderMarkdown` plus the remark/
|
|
13
|
-
* rehype plugin arrays (so the
|
|
13
|
+
* rehype plugin arrays (so the admin editor preview can reuse the exact same set). */
|
|
14
14
|
export function createRenderer(registry, options = {}) {
|
|
15
15
|
const remarkPlugins = [remarkDirective, [remarkDirectiveStamp, registry]];
|
|
16
16
|
const rehypePlugins = [rehypeRaw, [rehypeDispatch, registry, options.stagger], rehypeSlug];
|
package/dist/render/sanitize.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// The live preview's sanitize floor.
|
|
2
|
-
//
|
|
1
|
+
// The live preview's sanitize floor. The MarkdownEditor edits raw markdown and never sanitizes,
|
|
2
|
+
// so the admin preview pane is the one barrier between editor-authored markdown and the DOM.
|
|
3
3
|
// DOMPurify needs a DOM, and the preview renders only in the browser after mount, so DOMPurify
|
|
4
4
|
// loads through a dynamic import: the module never evaluates a DOM library on the Worker, and a
|
|
5
5
|
// server import of this file pulls in nothing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-routes.d.ts","sourceRoot":"","sources":["../../src/lib/sveltekit/content-routes.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7E,OAAO,KAAK,EAAE,YAAY,EAAqB,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAErD,wGAAwG;AACxG,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,gGAAgG;AAChG,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1C,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,yGAAyG;IACzG,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,oCAAoC;AACpC,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gFAAgF;IAChF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,6FAA6F;AAC7F,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,gGAAgG;AAChG,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACnC,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;CACnC;AAED,sFAAsF;AACtF,MAAM,WAAW,iBAAiB;IAChC,6FAA6F;IAC7F,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD;AAgBD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,GAAE,iBAAsB;wBAK1D,YAAY,KAAG,UAAU;yBAa1B,KAAK;sBAqBA,YAAY,KAAG,OAAO,CAAC,QAAQ,CAAC;0BAqB5B,YAAY,KAAG,OAAO,CAAC,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"content-routes.d.ts","sourceRoot":"","sources":["../../src/lib/sveltekit/content-routes.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7E,OAAO,KAAK,EAAE,YAAY,EAAqB,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAErD,wGAAwG;AACxG,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,gGAAgG;AAChG,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1C,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,yGAAyG;IACzG,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,oCAAoC;AACpC,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gFAAgF;IAChF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,6FAA6F;AAC7F,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,gGAAgG;AAChG,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACnC,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;CACnC;AAED,sFAAsF;AACtF,MAAM,WAAW,iBAAiB;IAChC,6FAA6F;IAC7F,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD;AAgBD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,GAAE,iBAAsB;wBAK1D,YAAY,KAAG,UAAU;yBAa1B,KAAK;sBAqBA,YAAY,KAAG,OAAO,CAAC,QAAQ,CAAC;0BAqB5B,YAAY,KAAG,OAAO,CAAC,KAAK,CAAC;sBAyCjC,YAAY,KAAG,OAAO,CAAC,QAAQ,CAAC;wBAgC9B,YAAY,KAAG,OAAO,CAAC,KAAK,CAAC;qBAtJ5C,YAAY,KAAK,OAAO,CAAC,MAAM,CAAC;EA+LnD"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { redirect, error } from '@sveltejs/kit';
|
|
6
6
|
import { findConcept } from '../content/concepts.js';
|
|
7
7
|
import { frontmatterFromForm, parseMarkdown, dateInputValue, serializeMarkdown } from '../content/frontmatter.js';
|
|
8
|
-
import { isValidId, slugify, filenameFromId } from '../content/ids.js';
|
|
8
|
+
import { isValidId, slugify, filenameFromId, composeDatedId } from '../content/ids.js';
|
|
9
9
|
import { appCredentials } from '../github/credentials.js';
|
|
10
10
|
import { listMarkdown, readRaw, commitFile } from '../github/repo.js';
|
|
11
11
|
import { installationToken } from '../github/signing.js';
|
|
@@ -82,22 +82,32 @@ export function createContentRoutes(runtime, deps = {}) {
|
|
|
82
82
|
return { ...base, entries: [], error: 'Could not load this content type from GitHub.' };
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
/** Create a new entry: validate the slug,
|
|
85
|
+
/** Create a new entry: validate the slug, compose a dated id when the concept is dated, refuse to clobber. */
|
|
86
86
|
async function createAction(event) {
|
|
87
87
|
sessionOf(event);
|
|
88
88
|
const concept = conceptOf(runtime, event.params);
|
|
89
89
|
const form = await event.request.formData();
|
|
90
|
-
const
|
|
90
|
+
const slug = String(form.get('slug') ?? '').trim() || slugify(String(form.get('title') ?? ''));
|
|
91
|
+
const date = String(form.get('date') ?? '').trim();
|
|
91
92
|
const bounce = (msg) => {
|
|
92
93
|
throw redirect(303, `/admin/${concept.id}?error=${encodeURIComponent(msg)}`);
|
|
93
94
|
};
|
|
94
|
-
if (!isValidId(
|
|
95
|
-
bounce('Enter a valid slug: lowercase letters, numbers, and hyphens.');
|
|
95
|
+
if (!isValidId(slug))
|
|
96
|
+
return bounce('Enter a valid slug: lowercase letters, numbers, and hyphens.');
|
|
97
|
+
let id = slug;
|
|
98
|
+
if (concept.routing.dated) {
|
|
99
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date))
|
|
100
|
+
return bounce('Pick a date for this entry.');
|
|
101
|
+
if (/^\d{4}-/.test(slug)) {
|
|
102
|
+
return bounce('Leave the date out of the slug; set it in the date field.');
|
|
103
|
+
}
|
|
104
|
+
id = composeDatedId(date, slug, concept.datePrefix);
|
|
105
|
+
}
|
|
96
106
|
const token = await mintToken(event.platform?.env ?? {});
|
|
97
|
-
const existing = await readRaw(runtime.backend, `${concept.dir}/${filenameFromId(
|
|
107
|
+
const existing = await readRaw(runtime.backend, `${concept.dir}/${filenameFromId(id)}`, token);
|
|
98
108
|
if (existing !== null)
|
|
99
|
-
bounce('An entry with that slug already exists.');
|
|
100
|
-
throw redirect(303, `/admin/${concept.id}/${
|
|
109
|
+
return bounce('An entry with that slug already exists.');
|
|
110
|
+
throw redirect(303, `/admin/${concept.id}/${id}?new=1`);
|
|
101
111
|
}
|
|
102
112
|
/** Coerce parsed frontmatter to the form-ready values the editor inputs expect. */
|
|
103
113
|
function formValues(fields, frontmatter) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ContentSummary, ContentEntry } from '../delivery/content-index.js';
|
|
2
|
+
import type { SiteIndex } from '../delivery/site-index.js';
|
|
2
3
|
/** Injected dependencies for the public loaders. */
|
|
3
4
|
export interface PublicRoutesDeps {
|
|
4
|
-
|
|
5
|
+
site: SiteIndex;
|
|
5
6
|
render: (md: string, opts?: {
|
|
6
7
|
stagger?: boolean;
|
|
7
8
|
}) => string | Promise<string>;
|
|
@@ -30,22 +31,20 @@ export interface EntryData {
|
|
|
30
31
|
newer?: ContentSummary;
|
|
31
32
|
older?: ContentSummary;
|
|
32
33
|
}
|
|
33
|
-
/** Build the public loaders for
|
|
34
|
+
/** Build the public loaders for a site's unified index. */
|
|
34
35
|
export declare function createPublicRoutes(deps: PublicRoutesDeps): {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
entryLoad: (event: {
|
|
37
|
+
url: URL;
|
|
38
|
+
}) => Promise<EntryData>;
|
|
39
|
+
archiveLoad: (conceptId: string) => ListData;
|
|
40
|
+
tagIndexLoad: (conceptId: string) => TagIndexData;
|
|
41
|
+
tagLoad: (conceptId: string, event: {
|
|
38
42
|
params: {
|
|
39
43
|
tag: string;
|
|
40
44
|
};
|
|
41
45
|
}) => TagData;
|
|
42
|
-
entryLoad: (event: {
|
|
43
|
-
params: {
|
|
44
|
-
slug: string;
|
|
45
|
-
};
|
|
46
|
-
}) => Promise<EntryData>;
|
|
47
46
|
entries: () => {
|
|
48
|
-
|
|
47
|
+
path: string;
|
|
49
48
|
}[];
|
|
50
49
|
};
|
|
51
50
|
//# sourceMappingURL=public-routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-routes.d.ts","sourceRoot":"","sources":["../../src/lib/sveltekit/public-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"public-routes.d.ts","sourceRoot":"","sources":["../../src/lib/sveltekit/public-routes.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,uDAAuD;AACvD,MAAM,WAAW,OAAQ,SAAQ,QAAQ;IACvC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACxC;AAED,oFAAoF;AACpF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB;uBAWvB;QAAE,GAAG,EAAE,GAAG,CAAA;KAAE,KAAG,OAAO,CAAC,SAAS,CAAC;6BAQjC,MAAM,KAAG,QAAQ;8BAKhB,MAAM,KAAG,YAAY;yBAK1B,MAAM,SAAS;QAAE,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAG,OAAO;mBAO5D;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE;EAKvC"}
|
|
@@ -1,44 +1,45 @@
|
|
|
1
|
-
// cairn-cms: public route loaders (
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// cairn-cms: public route loaders (dated-slug design). The factory closes over the site-level
|
|
2
|
+
// index, the runtime render, and the origin. entryLoad and entries are site-wide: one catch-all
|
|
3
|
+
// `[...path]` route resolves any concept by request path through `byPermalink`. The archive, tag,
|
|
4
|
+
// and tag-index loaders stay concept-scoped, keyed by concept id. The index is built in site code
|
|
5
|
+
// from globs, so it stays in the prerender graph and out of the runtime Worker.
|
|
5
6
|
import { error } from '@sveltejs/kit';
|
|
6
|
-
/** Build the public loaders for
|
|
7
|
+
/** Build the public loaders for a site's unified index. */
|
|
7
8
|
export function createPublicRoutes(deps) {
|
|
8
|
-
const {
|
|
9
|
-
/**
|
|
10
|
-
function
|
|
11
|
-
|
|
9
|
+
const { site, render, origin } = deps;
|
|
10
|
+
/** Resolve one concept's index by id, or a 404 (the route names an unconfigured concept). */
|
|
11
|
+
function indexOf(conceptId) {
|
|
12
|
+
const index = site.concept(conceptId);
|
|
13
|
+
if (!index)
|
|
14
|
+
throw error(404, `Unknown content type: ${conceptId}`);
|
|
15
|
+
return index;
|
|
12
16
|
}
|
|
13
|
-
/**
|
|
14
|
-
function tagIndexLoad() {
|
|
15
|
-
return { tags: index.allTags() };
|
|
16
|
-
}
|
|
17
|
-
/** One tag's entries, or a 404 when the tag has none. */
|
|
18
|
-
function tagLoad(event) {
|
|
19
|
-
const tag = event.params.tag;
|
|
20
|
-
const entries = index.byTag(tag);
|
|
21
|
-
if (entries.length === 0)
|
|
22
|
-
throw error(404, `No entries tagged "${tag}"`);
|
|
23
|
-
return { tag, entries };
|
|
24
|
-
}
|
|
25
|
-
/** One entry by slug, rendered through the site renderer, or a 404. */
|
|
17
|
+
/** One entry by request path, rendered through the site renderer, or a 404. */
|
|
26
18
|
async function entryLoad(event) {
|
|
27
|
-
const entry =
|
|
19
|
+
const entry = site.byPermalink(event.url.pathname);
|
|
28
20
|
if (!entry)
|
|
29
|
-
throw error(404, `Not found: ${event.
|
|
30
|
-
const { newer, older } =
|
|
31
|
-
return {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
throw error(404, `Not found: ${event.url.pathname}`);
|
|
22
|
+
const { newer, older } = site.adjacent(entry);
|
|
23
|
+
return { entry, html: await render(entry.body, { stagger: true }), canonicalUrl: origin + entry.permalink, newer, older };
|
|
24
|
+
}
|
|
25
|
+
/** The chronological archive for one concept: every non-draft summary, newest-first. */
|
|
26
|
+
function archiveLoad(conceptId) {
|
|
27
|
+
return { entries: indexOf(conceptId).all() };
|
|
28
|
+
}
|
|
29
|
+
/** All tags with counts for one concept, for a tag index page. */
|
|
30
|
+
function tagIndexLoad(conceptId) {
|
|
31
|
+
return { tags: indexOf(conceptId).allTags() };
|
|
32
|
+
}
|
|
33
|
+
/** One tag's entries for one concept, or a 404 when the tag has none. */
|
|
34
|
+
function tagLoad(conceptId, event) {
|
|
35
|
+
const entries = indexOf(conceptId).byTag(event.params.tag);
|
|
36
|
+
if (entries.length === 0)
|
|
37
|
+
throw error(404, `No entries tagged "${event.params.tag}"`);
|
|
38
|
+
return { tag: event.params.tag, entries };
|
|
38
39
|
}
|
|
39
|
-
/** Prerender enumeration: one `{
|
|
40
|
+
/** Prerender enumeration: one `{ path }` per entry across every concept. */
|
|
40
41
|
function entries() {
|
|
41
|
-
return
|
|
42
|
+
return site.entries();
|
|
42
43
|
}
|
|
43
|
-
return { archiveLoad, tagIndexLoad, tagLoad,
|
|
44
|
+
return { entryLoad, archiveLoad, tagIndexLoad, tagLoad, entries };
|
|
44
45
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glw907/cairn-cms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Embedded, magic-link, GitHub-committing CMS for SvelteKit/Cloudflare sites.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -56,13 +56,18 @@
|
|
|
56
56
|
],
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@sveltejs/kit": "^2",
|
|
59
|
-
"carta-md": "^4.11",
|
|
60
59
|
"svelte": "^5.0.0"
|
|
61
60
|
},
|
|
62
61
|
"dependencies": {
|
|
62
|
+
"@codemirror/commands": "^6.10.3",
|
|
63
|
+
"@codemirror/lang-markdown": "^6.5.0",
|
|
64
|
+
"@codemirror/language": "^6.12.3",
|
|
65
|
+
"@codemirror/state": "^6.6.0",
|
|
66
|
+
"@codemirror/view": "^6.43.0",
|
|
63
67
|
"@rodrigodagostino/svelte-sortable-list": "^2.1.17",
|
|
64
68
|
"@types/hast": "^3.0.4",
|
|
65
69
|
"@types/mdast": "^4.0.4",
|
|
70
|
+
"codemirror": "^6.0.2",
|
|
66
71
|
"dompurify": "^3.4.7",
|
|
67
72
|
"gray-matter": "^4",
|
|
68
73
|
"hastscript": "^9.0.1",
|
|
@@ -88,7 +93,6 @@
|
|
|
88
93
|
"@types/node": "^22.19.19",
|
|
89
94
|
"@vitest/browser": "^4.1.7",
|
|
90
95
|
"@vitest/browser-playwright": "^4.1.7",
|
|
91
|
-
"carta-md": "^4.11",
|
|
92
96
|
"playwright": "^1.60.0",
|
|
93
97
|
"publint": "^0.3.21",
|
|
94
98
|
"svelte": "^5.55",
|