@krantho/persistence-fs 0.0.0-stage → 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Descoped
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,15 @@
1
+ import type { ContentDocument, ContentQuery, QueryPage, QueryProjection } from '@krantho/persistence';
2
+ /** A document read for a query: `full` needs the rendered HTML and sections, the rest do not */
3
+ export type QueriedDocument = Omit<ContentDocument, 'html' | 'sections'> & Partial<Pick<ContentDocument, 'html' | 'sections'>>;
4
+ /** Where a query reads the files of the adapter's collections */
5
+ export interface QuerySource {
6
+ /** The collections the adapter was given a directory for */
7
+ collections(): string[];
8
+ /** The slugs of a collection's files */
9
+ slugs(collection: string): Promise<string[]>;
10
+ /** One file as a document; rendered (HTML and sections) only when `render` is set */
11
+ read(collection: string, slug: string, render: boolean): Promise<QueriedDocument>;
12
+ }
13
+ /** Run a content query over the files of the adapter's collections */
14
+ export declare function runContentQuery<P extends QueryProjection>(source: QuerySource, spec: ContentQuery<P>): Promise<QueryPage<P>>;
15
+ //# sourceMappingURL=content-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-query.d.ts","sourceRoot":"","sources":["../src/content-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAKZ,SAAS,EACT,eAAe,EAChB,MAAM,sBAAsB,CAAA;AAO7B,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,UAAU,CAAC,GACtE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAA;AAErD,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,WAAW,IAAI,MAAM,EAAE,CAAA;IACvB,wCAAwC;IACxC,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC5C,qFAAqF;IACrF,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAClF;AAuGD,sEAAsE;AACtE,wBAAsB,eAAe,CAAC,CAAC,SAAS,eAAe,EAC7D,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAiBvB"}
@@ -0,0 +1,122 @@
1
+ import { isDirectSortColumn, isSafeSortField } from '@krantho/persistence';
2
+ /** Characters of a snippet before the match, and from the match on */
3
+ const SNIPPET_BEFORE = 80;
4
+ const SNIPPET_LENGTH = 200;
5
+ /** The text of a document each match target searches */
6
+ function targetText(doc, target) {
7
+ if (target === 'slug')
8
+ return doc.meta.slug;
9
+ if (target === 'fields')
10
+ return JSON.stringify(doc.fields);
11
+ return doc.body;
12
+ }
13
+ /**
14
+ * The snippet of the first match: from the body when it matches there, else from the
15
+ * fields' JSON. Positions count characters (code points), as `substr` does in SQL, and
16
+ * the position found in the folded text applies to the original.
17
+ */
18
+ function snippetOf(doc, targets, needle) {
19
+ for (const target of ['body', 'fields']) {
20
+ if (!targets.includes(target))
21
+ continue;
22
+ const text = targetText(doc, target);
23
+ const index = text.toLowerCase().indexOf(needle);
24
+ if (index < 0)
25
+ continue;
26
+ const before = Array.from(text.slice(0, index)).length;
27
+ const start = Math.max(0, before - SNIPPET_BEFORE);
28
+ return Array.from(text)
29
+ .slice(start, start + SNIPPET_LENGTH)
30
+ .join('')
31
+ .replace(/\s+/g, ' ');
32
+ }
33
+ return undefined;
34
+ }
35
+ /** Whether any target contains the folded needle */
36
+ function matches(doc, targets, needle) {
37
+ return targets.some((target) => targetText(doc, target).toLowerCase().includes(needle));
38
+ }
39
+ /** The value a sort field orders a document by; a document without it sorts first */
40
+ function sortValue(doc, field) {
41
+ const direct = {
42
+ slug: doc.meta.slug,
43
+ status: doc.meta.status,
44
+ locale: doc.meta.locale,
45
+ created_at: doc.meta.createdAt,
46
+ };
47
+ if (isDirectSortColumn(field))
48
+ return direct[field];
49
+ const value = isSafeSortField(field) ? doc.fields[field] : undefined;
50
+ if (typeof value === 'number' || typeof value === 'string')
51
+ return value;
52
+ return value === undefined || value === null ? null : String(value);
53
+ }
54
+ /** Order two values as SQL does: nulls first, numbers numerically, text by code unit */
55
+ function compareValues(a, b) {
56
+ if (a === b)
57
+ return 0;
58
+ if (a === null)
59
+ return -1;
60
+ if (b === null)
61
+ return 1;
62
+ if (typeof a === 'number' && typeof b === 'number')
63
+ return a - b;
64
+ const left = String(a);
65
+ const right = String(b);
66
+ return left < right ? -1 : left > right ? 1 : 0;
67
+ }
68
+ /** Order two documents: the requested sort, then `collection, slug, locale` so paging is stable */
69
+ function compareDocuments(sort) {
70
+ const [field, direction] = sort ? sort.split(':') : [];
71
+ const sign = direction === 'desc' ? -1 : 1;
72
+ return (a, b) => {
73
+ const ordered = field ? sign * compareValues(sortValue(a, field), sortValue(b, field)) : 0;
74
+ return (ordered ||
75
+ compareValues(a.meta.collection, b.meta.collection) ||
76
+ compareValues(a.meta.slug, b.meta.slug) ||
77
+ compareValues(a.meta.locale, b.meta.locale));
78
+ };
79
+ }
80
+ /** The documents of the query's collections that its state, status and locale admit */
81
+ async function candidates(source, spec) {
82
+ const render = spec.projection === 'full';
83
+ const found = [];
84
+ for (const collection of spec.collections ?? source.collections()) {
85
+ for (const slug of await source.slugs(collection)) {
86
+ const doc = await source.read(collection, slug, render);
87
+ if (spec.locale && doc.meta.locale !== spec.locale)
88
+ continue;
89
+ // A file is one version and is live when published: `current` and `published` read the same file
90
+ if (spec.state === 'published' && doc.meta.status !== 'published')
91
+ continue;
92
+ if (spec.state === 'current' && spec.status && doc.meta.status !== spec.status)
93
+ continue;
94
+ found.push(doc);
95
+ }
96
+ }
97
+ return found;
98
+ }
99
+ function projected(projection, doc) {
100
+ if (projection === 'meta')
101
+ return doc.meta;
102
+ if (projection === 'summary')
103
+ return { meta: doc.meta, fields: doc.fields, metadata: doc.metadata };
104
+ return doc;
105
+ }
106
+ /** Run a content query over the files of the adapter's collections */
107
+ export async function runContentQuery(source, spec) {
108
+ const needle = spec.match?.text.toLowerCase() ?? '';
109
+ const matched = (await candidates(source, spec)).filter((doc) => !spec.match || matches(doc, spec.match.in, needle));
110
+ matched.sort(compareDocuments(spec.sort));
111
+ const start = spec.offset ?? 0;
112
+ const end = spec.limit === undefined ? undefined : start + spec.limit;
113
+ const page = matched.slice(start, end);
114
+ const hasMore = end !== undefined && matched.length > end;
115
+ const items = page.map((doc) => {
116
+ const item = projected(spec.projection, doc);
117
+ const snippet = spec.match ? snippetOf(doc, spec.match.in, needle) : undefined;
118
+ return snippet === undefined ? item : { ...item, snippet };
119
+ });
120
+ return { items, hasMore };
121
+ }
122
+ //# sourceMappingURL=content-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-query.js","sourceRoot":"","sources":["../src/content-query.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE1E,sEAAsE;AACtE,MAAM,cAAc,GAAG,EAAE,CAAA;AACzB,MAAM,cAAc,GAAG,GAAG,CAAA;AAgB1B,wDAAwD;AACxD,SAAS,UAAU,CAAC,GAAoB,EAAE,MAAmB;IAC3D,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAA;IAC3C,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAC1D,OAAO,GAAG,CAAC,IAAI,CAAA;AACjB,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAChB,GAAoB,EACpB,OAA+B,EAC/B,MAAc;IAEd,KAAK,MAAM,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAU,EAAE,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAQ;QACvC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAChD,IAAI,KAAK,GAAG,CAAC;YAAE,SAAQ;QACvB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAA;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,CAAA;QAClD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;aACpB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc,CAAC;aACpC,IAAI,CAAC,EAAE,CAAC;aACR,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,oDAAoD;AACpD,SAAS,OAAO,CAAC,GAAoB,EAAE,OAA+B,EAAE,MAAc;IACpF,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;AACzF,CAAC;AAED,qFAAqF;AACrF,SAAS,SAAS,CAAC,GAAoB,EAAE,KAAa;IACpD,MAAM,MAAM,GAAqC;QAC/C,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;QACnB,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;QACvB,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;QACvB,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS;KAC/B,CAAA;IACD,IAAI,kBAAkB,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACnD,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACpE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACxE,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACrE,CAAC;AAED,wFAAwF;AACxF,SAAS,aAAa,CAAC,CAAyB,EAAE,CAAyB;IACzE,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IACrB,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC,CAAA;IACzB,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,CAAC,CAAA;IACxB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IAChE,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACtB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACvB,OAAO,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACjD,CAAC;AAED,mGAAmG;AACnG,SAAS,gBAAgB,CAAC,IAAwB;IAChD,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACtD,MAAM,IAAI,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1C,OAAO,CAAC,CAAkB,EAAE,CAAkB,EAAU,EAAE;QACxD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC1F,OAAO,CACL,OAAO;YACP,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;YACnD,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACvC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAC5C,CAAA;IACH,CAAC,CAAA;AACH,CAAC;AAED,uFAAuF;AACvF,KAAK,UAAU,UAAU,CAAC,MAAmB,EAAE,IAAkB;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,KAAK,MAAM,CAAA;IACzC,MAAM,KAAK,GAAsB,EAAE,CAAA;IACnC,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAClE,KAAK,MAAM,IAAI,IAAI,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;YACvD,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;gBAAE,SAAQ;YAC5D,iGAAiG;YACjG,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW;gBAAE,SAAQ;YAC3E,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;gBAAE,SAAQ;YACxF,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,SAAS,CAAC,UAA2B,EAAE,GAAoB;IAClE,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,GAAG,CAAC,IAA2B,CAAA;IACjE,IAAI,UAAU,KAAK,SAAS;QAC1B,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAA;IACvE,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAmB,EACnB,IAAqB;IAErB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,CAAA;IACnD,MAAM,OAAO,GAAG,CAAC,MAAM,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CACrD,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAC5D,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAEzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAA;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACrE,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACtC,MAAM,OAAO,GAAG,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAoD,CAAA;QAC/F,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9E,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAA;IAC5D,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAC3B,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { type ContentMetadata, type IContentLoader } from '@krantho/core';
2
+ import type { ContentDocument, ContentQuery, IPersistenceAdapter, PersistenceConfig, QueryPage, QueryProjection, WriteContentData } from '@krantho/persistence';
3
+ /** Construction options for {@link FileSystemAdapter} */
4
+ export interface FileSystemAdapterOptions extends Partial<PersistenceConfig> {
5
+ /**
6
+ * Each collection's directory, by collection name. A collection without one
7
+ * keeps its files in `contentPath`.
8
+ */
9
+ directories?: ReadonlyMap<string, string> | undefined;
10
+ /**
11
+ * Locale of a markdown file whose frontmatter declares none: the site's
12
+ * default locale, `site.defaultLocale` in the krantho configuration.
13
+ */
14
+ defaultLocale: string;
15
+ /**
16
+ * Status for a markdown file whose frontmatter declares none.
17
+ *
18
+ * A deployment sets this through `content.defaultStatus.filesystem`.
19
+ */
20
+ defaultStatus?: string | undefined;
21
+ }
22
+ export declare class FileSystemAdapter implements IPersistenceAdapter, IContentLoader {
23
+ private readonly contentPath;
24
+ private readonly directories;
25
+ private readonly defaultStatus;
26
+ private readonly defaultLocale;
27
+ constructor(config: FileSystemAdapterOptions);
28
+ exists(slug: string): Promise<boolean>;
29
+ read(slug: string): Promise<string>;
30
+ getMetadata(slug: string): Promise<Pick<ContentMetadata, 'size' | 'lastModified'>>;
31
+ listSlugs(): Promise<string[]>;
32
+ /** The document of a collection's file, whatever locale is named: a file holds one document */
33
+ getContent(collection: string, slug: string, _locale?: string | undefined): Promise<ContentDocument | null>;
34
+ /** A file is live when its status (frontmatter, or the default) is published */
35
+ getPublished(collection: string, slug: string, locale?: string | undefined): Promise<ContentDocument | null>;
36
+ /** The one read behind every list, over the files of the collections the adapter has a directory for */
37
+ query<P extends QueryProjection>(spec: ContentQuery<P>): Promise<QueryPage<P>>;
38
+ writeContent(data: WriteContentData): Promise<void>;
39
+ /** Removes the collection's file, whatever locale is named: a file holds one document */
40
+ deleteContent(collection: string, slug: string, _locale?: string | undefined): Promise<void>;
41
+ /** A collection's file, parsed and rendered as the content import renders it */
42
+ private readDocument;
43
+ /** A collection's file, parsed; rendered (HTML and sections) only when `render` is set */
44
+ private readFile;
45
+ private directoryOf;
46
+ private filePath;
47
+ private resolveContentPath;
48
+ }
49
+ //# sourceMappingURL=filesystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,cAAc,EAGpB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EAGZ,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,gBAAgB,EACjB,MAAM,sBAAsB,CAAA;AAU7B,yDAAyD;AACzD,MAAM,WAAW,wBAAyB,SAAQ,OAAO,CAAC,iBAAiB,CAAC;IAC1E;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IACrD;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAyCD,qBAAa,iBAAkB,YAAW,mBAAmB,EAAE,cAAc;IAC3E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;gBAE1B,MAAM,EAAE,wBAAwB;IAQtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAStC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC;IAQlF,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpC,+FAA+F;IACzF,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQlC,gFAAgF;IAC1E,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAKlC,wGAAwG;IAClG,KAAK,CAAC,CAAC,SAAS,eAAe,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAW9E,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBzD,yFAAyF;IACnF,aAAa,CACjB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAAC,IAAI,CAAC;IAIhB,gFAAgF;YAClE,YAAY;IAI1B,0FAA0F;YAC5E,QAAQ;IA2BtB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,kBAAkB;CAG3B"}
@@ -0,0 +1,170 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { DEFAULT_FRONTMATTER_STATUS, renderContent, splitFrontmatter, } from '@krantho/core';
4
+ import { authoredMetadata, repositoryFrontmatter, repositoryMarkdown } from '@krantho/persistence';
5
+ import matter from 'gray-matter';
6
+ import { runContentQuery } from './content-query.js';
7
+ const DEFAULT_FS_CONFIG = {
8
+ contentPath: 'content/pages',
9
+ seoPath: 'content/seo',
10
+ };
11
+ /** A file's publication state from its frontmatter status */
12
+ function fileState(status) {
13
+ return status === 'published' || status === 'archived' ? status : 'draft';
14
+ }
15
+ /**
16
+ * A file's document metadata. A file is one version with no history: it is
17
+ * live when its status is published, so it can hold no changes ahead of what
18
+ * visitors see — a save to a published file is live at once.
19
+ */
20
+ function fileMeta(collection, slug, locale, status, modified) {
21
+ const state = fileState(status);
22
+ return {
23
+ collection,
24
+ slug,
25
+ locale,
26
+ version: 1,
27
+ liveVersion: state === 'published' ? 1 : null,
28
+ status: state,
29
+ source: 'filesystem',
30
+ changedBy: null,
31
+ createdAt: modified.toISOString(),
32
+ };
33
+ }
34
+ /** The status a write leaves a file in: publishing publishes, a save keeps the file's status */
35
+ function statusAfterWrite(data, previous) {
36
+ if (data.publication === 'publish')
37
+ return 'published';
38
+ if (data.publication === 'unpublish')
39
+ return 'draft';
40
+ if (data.publication === 'archive')
41
+ return 'archived';
42
+ return previous ?? 'draft';
43
+ }
44
+ export class FileSystemAdapter {
45
+ contentPath;
46
+ directories;
47
+ defaultStatus;
48
+ defaultLocale;
49
+ constructor(config) {
50
+ const merged = { ...DEFAULT_FS_CONFIG, ...config };
51
+ this.contentPath = merged.contentPath;
52
+ this.directories = config.directories ?? new Map();
53
+ this.defaultLocale = config.defaultLocale;
54
+ this.defaultStatus = config.defaultStatus ?? DEFAULT_FRONTMATTER_STATUS;
55
+ }
56
+ async exists(slug) {
57
+ try {
58
+ await fs.access(this.resolveContentPath(slug));
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ async read(slug) {
66
+ return fs.readFile(this.resolveContentPath(slug), 'utf-8');
67
+ }
68
+ async getMetadata(slug) {
69
+ const stat = await fs.stat(this.resolveContentPath(slug));
70
+ return {
71
+ size: stat.size,
72
+ lastModified: stat.mtime,
73
+ };
74
+ }
75
+ async listSlugs() {
76
+ return slugsIn(this.contentPath);
77
+ }
78
+ /** The document of a collection's file, whatever locale is named: a file holds one document */
79
+ async getContent(collection, slug, _locale) {
80
+ try {
81
+ return await this.readDocument(collection, slug);
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ /** A file is live when its status (frontmatter, or the default) is published */
88
+ async getPublished(collection, slug, locale) {
89
+ const doc = await this.getContent(collection, slug, locale);
90
+ return doc?.meta.status === 'published' ? doc : null;
91
+ }
92
+ /** The one read behind every list, over the files of the collections the adapter has a directory for */
93
+ async query(spec) {
94
+ return runContentQuery({
95
+ collections: () => [...this.directories.keys()],
96
+ slugs: (collection) => slugsIn(this.directoryOf(collection)),
97
+ read: (collection, slug, render) => this.readFile(collection, slug, render),
98
+ }, spec);
99
+ }
100
+ async writeContent(data) {
101
+ const filePath = this.filePath(data.collection, data.slug);
102
+ const previous = await this.getContent(data.collection, data.slug);
103
+ // Merge content fields + the status back into YAML frontmatter for file storage
104
+ const content = repositoryMarkdown({
105
+ identity: {
106
+ collection: data.collection,
107
+ slug: data.slug,
108
+ locale: data.locale ?? this.defaultLocale,
109
+ },
110
+ fields: { ...data.fields, status: statusAfterWrite(data, previous?.meta.status) },
111
+ body: data.body,
112
+ metadata: data.metadata ?? {},
113
+ contract: data.contract ?? null,
114
+ defaults: data.defaults ?? [],
115
+ });
116
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
117
+ await fs.writeFile(filePath, content, 'utf-8');
118
+ }
119
+ /** Removes the collection's file, whatever locale is named: a file holds one document */
120
+ async deleteContent(collection, slug, _locale) {
121
+ await fs.unlink(this.filePath(collection, slug));
122
+ }
123
+ /** A collection's file, parsed and rendered as the content import renders it */
124
+ async readDocument(collection, slug) {
125
+ return (await this.readFile(collection, slug, true));
126
+ }
127
+ /** A collection's file, parsed; rendered (HTML and sections) only when `render` is set */
128
+ async readFile(collection, slug, render) {
129
+ const filePath = this.filePath(collection, slug);
130
+ const raw = await fs.readFile(filePath, 'utf-8');
131
+ const parsed = matter(raw);
132
+ const { fields, status, locale } = splitFrontmatter(parsed.data, this.defaultLocale, this.defaultStatus);
133
+ const stat = await fs.stat(filePath);
134
+ const document = {
135
+ meta: fileMeta(collection, slug, locale, status, stat.mtime),
136
+ fields,
137
+ ...authoredMetadata(repositoryFrontmatter(parsed.data)),
138
+ body: parsed.content,
139
+ };
140
+ if (!render)
141
+ return document;
142
+ // As the content import renders a file, so both providers store the same HTML; pages
143
+ // substitute @-notation when they render
144
+ const { html, sections } = await renderContent(fields, parsed.content, { atNotation: false });
145
+ return { ...document, html, sections };
146
+ }
147
+ directoryOf(collection) {
148
+ return this.directories.get(collection) ?? this.contentPath;
149
+ }
150
+ filePath(collection, slug) {
151
+ return path.join(this.directoryOf(collection), `${slug}.md`);
152
+ }
153
+ resolveContentPath(slug) {
154
+ return path.join(this.contentPath, `${slug}.md`);
155
+ }
156
+ }
157
+ /** The slugs of the markdown files in a directory; none when the directory does not exist yet */
158
+ async function slugsIn(directory) {
159
+ let entries;
160
+ try {
161
+ entries = await fs.readdir(directory);
162
+ }
163
+ catch (error) {
164
+ if (error.code === 'ENOENT')
165
+ return [];
166
+ throw error;
167
+ }
168
+ return entries.filter((entry) => entry.endsWith('.md')).map((entry) => entry.slice(0, -3));
169
+ }
170
+ //# sourceMappingURL=filesystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { IPersistenceAdapter, PersistenceConfig } from '@krantho/persistence';
2
+ export type { FileSystemAdapterOptions } from './filesystem.js';
3
+ export { FileSystemAdapter } from './filesystem.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAClF,YAAY,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { FileSystemAdapter } from './filesystem.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "@krantho/persistence-fs",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "homepage": "https://krantho.com",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/descoped/krantho.git",
9
+ "directory": "packages/persistence-fs"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/descoped/krantho/issues"
13
+ },
14
+ "type": "module",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "dependencies": {
25
+ "gray-matter": "^4.0.3",
26
+ "yaml": "^2.9.0",
27
+ "@krantho/core": "1.0.0",
28
+ "@krantho/persistence": "1.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^25.9.9",
32
+ "typescript": "^6.0.3"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "typecheck": "tsc --noEmit",
37
+ "clean": "rm -rf dist"
38
+ }
6
39
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.