@contentrain/query 7.0.15 → 7.1.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/README.md +53 -0
- package/dist/astro/index.cjs +142 -0
- package/dist/astro/index.d.cts +81 -0
- package/dist/astro/index.d.cts.map +1 -0
- package/dist/astro/index.d.mts +81 -0
- package/dist/astro/index.d.mts.map +1 -0
- package/dist/astro/index.mjs +143 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/cdn/index.d.mts +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/frontmatter-CVjPyhOq.mjs +248 -0
- package/dist/frontmatter-CVjPyhOq.mjs.map +1 -0
- package/dist/frontmatter-DSFLOTwS.cjs +287 -0
- package/dist/{generate-mpKW9Y8v.mjs → generate-B7jooE0f.mjs} +4 -244
- package/dist/generate-B7jooE0f.mjs.map +1 -0
- package/dist/{generate-DN3mAbvC.cjs → generate-D3C6itur.cjs} +14 -254
- package/dist/generator/generate.cjs +1 -1
- package/dist/generator/generate.mjs +1 -1
- package/dist/{index-TgljULTn.d.mts → index-DYWwX7xL.d.mts} +1 -1
- package/dist/{index-TgljULTn.d.mts.map → index-DYWwX7xL.d.mts.map} +1 -1
- package/dist/index.d.mts +1 -1
- package/package.json +38 -14
- package/dist/generate-mpKW9Y8v.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -398,6 +398,55 @@ Behavior:
|
|
|
398
398
|
| Caching | In-memory (embedded) | ETag-based HTTP cache + optional bundle preload |
|
|
399
399
|
| Use case | SSG, build-time | SSR, client-side, serverless |
|
|
400
400
|
|
|
401
|
+
## 🚀 Astro Content Layer
|
|
402
|
+
|
|
403
|
+
`contentrain generate` gives application code a typed client. Astro would
|
|
404
|
+
rather own the content itself, so pages can use `getCollection()`, `getEntry()`,
|
|
405
|
+
`reference()` and render documents with `<Content />`. `@contentrain/query/astro`
|
|
406
|
+
reads the same `.contentrain` files the generator reads — one project, one
|
|
407
|
+
answer about what its content is.
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
// src/content.config.ts
|
|
411
|
+
import { defineCollection, z } from 'astro:content'
|
|
412
|
+
import { contentrainLoader } from '@contentrain/query/astro'
|
|
413
|
+
|
|
414
|
+
export const collections = {
|
|
415
|
+
posts: defineCollection({
|
|
416
|
+
loader: contentrainLoader({ model: 'blog-post', locale: 'en' }),
|
|
417
|
+
schema: z.object({ title: z.string(), publishedAt: z.string() }).passthrough(),
|
|
418
|
+
}),
|
|
419
|
+
articles: defineCollection({ loader: contentrainLoader({ model: 'blog-article' }) }),
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
```astro
|
|
424
|
+
---
|
|
425
|
+
import { getCollection, getEntry, render } from 'astro:content'
|
|
426
|
+
const posts = await getCollection('posts')
|
|
427
|
+
const article = await getEntry('articles', 'en/welcome-post')
|
|
428
|
+
const { Content } = await render(article)
|
|
429
|
+
---
|
|
430
|
+
<ul>{posts.map((p) => <li>{p.data.title}</li>)}</ul>
|
|
431
|
+
<Content />
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
| Model kind | Becomes |
|
|
435
|
+
|---|---|
|
|
436
|
+
| `collection` | One entry per record; `data.id` is the entry id |
|
|
437
|
+
| `document` | One entry per file — frontmatter in `data`, markdown in `body`, rendered so `<Content />` works |
|
|
438
|
+
| `dictionary` | One entry per key (`{ key, value }`) — a key is a semantic address, and a single blob would make `getEntry()` useless on it |
|
|
439
|
+
| `singleton` | One entry, id `<model>` (or the locale) |
|
|
440
|
+
|
|
441
|
+
`locale` picks one language; omit it on an i18n model and every supported locale
|
|
442
|
+
loads with ids prefixed (`en/my-post`) — Astro ids are unique per collection, so
|
|
443
|
+
without the prefix one language would overwrite the other. `root` points at the
|
|
444
|
+
project holding `.contentrain` (default: `process.cwd()`).
|
|
445
|
+
|
|
446
|
+
Astro is not a dependency, not even a peer: the loader is structurally what
|
|
447
|
+
`defineCollection` accepts, so any Astro 5 version works and non-Astro consumers
|
|
448
|
+
of this package carry nothing extra.
|
|
449
|
+
|
|
401
450
|
## CommonJS Usage
|
|
402
451
|
|
|
403
452
|
Generated clients support CommonJS through `init()`:
|
|
@@ -450,6 +499,10 @@ CDN transport:
|
|
|
450
499
|
|
|
451
500
|
- `@contentrain/query/cdn` — CDN client with `HttpTransport`, async query classes, `MediaAccessor`, `FormsClient`, `ConversationClient`
|
|
452
501
|
|
|
502
|
+
Astro content layer:
|
|
503
|
+
|
|
504
|
+
- `@contentrain/query/astro` — `contentrainLoader()` for `defineCollection({ loader })`
|
|
505
|
+
|
|
453
506
|
## 🧠 Design Constraints
|
|
454
507
|
|
|
455
508
|
This package intentionally:
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_frontmatter = require("../frontmatter-DSFLOTwS.cjs");
|
|
3
|
+
let node_path = require("node:path");
|
|
4
|
+
let node_url = require("node:url");
|
|
5
|
+
//#region src/astro/loader.ts
|
|
6
|
+
/**
|
|
7
|
+
* A loader for one Contentrain model.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* // src/content.config.ts
|
|
11
|
+
* import { defineCollection } from 'astro:content'
|
|
12
|
+
* import { contentrainLoader } from '@contentrain/query/astro'
|
|
13
|
+
*
|
|
14
|
+
* export const collections = {
|
|
15
|
+
* posts: defineCollection({ loader: contentrainLoader({ model: 'blog-post', locale: 'en' }) }),
|
|
16
|
+
* articles: defineCollection({ loader: contentrainLoader({ model: 'blog-article' }) }),
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Each model kind maps to the shape Astro can actually use:
|
|
21
|
+
* collection → one entry per record · document → one entry per file, markdown
|
|
22
|
+
* in `body` (and rendered, so `<Content />` works) · dictionary → one entry per
|
|
23
|
+
* key, because a single blob would make `getEntry()` useless · singleton → one
|
|
24
|
+
* entry, id `<model>` or the locale.
|
|
25
|
+
*/
|
|
26
|
+
function contentrainLoader(options) {
|
|
27
|
+
const root = options.root ?? process.cwd();
|
|
28
|
+
let watching = false;
|
|
29
|
+
return {
|
|
30
|
+
name: `contentrain:${options.model}`,
|
|
31
|
+
async load(context) {
|
|
32
|
+
const manifest = await require_frontmatter.readProjectManifest(root);
|
|
33
|
+
const model = manifest.models.find((m) => m.id === options.model);
|
|
34
|
+
if (!model) {
|
|
35
|
+
const known = manifest.models.map((m) => m.id).join(", ") || "none";
|
|
36
|
+
throw new Error(`contentrainLoader: model "${options.model}" not found in ${(0, node_path.join)(root, ".contentrain", "models")}. Models here: ${known}.`);
|
|
37
|
+
}
|
|
38
|
+
const refs = manifest.contentFiles.filter((ref) => ref.modelId === model.id && (options.locale === void 0 || ref.locale === options.locale));
|
|
39
|
+
if (options.locale !== void 0 && refs.length === 0 && model.i18n) context.logger?.warn(`contentrainLoader: model "${model.id}" has no content for locale "${options.locale}" — collection is empty.`);
|
|
40
|
+
const prefixLocale = model.i18n === true && options.locale === void 0;
|
|
41
|
+
const entries = (await Promise.all(refs.map((ref) => entriesOf(ref, model, prefixLocale)))).flat();
|
|
42
|
+
const siteRoot = toPath(context.config?.root);
|
|
43
|
+
context.store.clear();
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
const data = context.parseData ? await context.parseData({
|
|
46
|
+
id: entry.id,
|
|
47
|
+
data: entry.data,
|
|
48
|
+
filePath: entry.filePath
|
|
49
|
+
}) : entry.data;
|
|
50
|
+
const filePath = siteRoot === void 0 ? void 0 : (0, node_path.relative)(siteRoot, entry.filePath);
|
|
51
|
+
context.store.set({
|
|
52
|
+
id: entry.id,
|
|
53
|
+
data,
|
|
54
|
+
...filePath === void 0 || filePath.startsWith("..") || (0, node_path.isAbsolute)(filePath) ? {} : { filePath },
|
|
55
|
+
...entry.body === void 0 ? {} : { body: entry.body },
|
|
56
|
+
...context.generateDigest ? { digest: context.generateDigest(entry.data) } : {},
|
|
57
|
+
...entry.body !== void 0 && context.renderMarkdown ? { rendered: await context.renderMarkdown(entry.body) } : {}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
context.logger?.info(`Loaded ${entries.length} ${model.kind} ${entries.length === 1 ? "entry" : "entries"} from ${model.id}`);
|
|
61
|
+
if (context.watcher && !watching) {
|
|
62
|
+
watching = true;
|
|
63
|
+
const paths = new Set(refs.map((ref) => ref.filePath));
|
|
64
|
+
for (const path of paths) context.watcher.add(path);
|
|
65
|
+
context.watcher.add((0, node_path.join)(root, ".contentrain", "models", `${model.id}.json`));
|
|
66
|
+
const reload = (path) => {
|
|
67
|
+
if (!paths.has(path) && !path.endsWith(`${model.id}.json`)) return;
|
|
68
|
+
this.load(context);
|
|
69
|
+
};
|
|
70
|
+
context.watcher.on("change", reload);
|
|
71
|
+
context.watcher.on("add", reload);
|
|
72
|
+
context.watcher.on("unlink", reload);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Astro hands `config.root` as a file URL; tests and other hosts may use a path. */
|
|
78
|
+
function toPath(root) {
|
|
79
|
+
if (root === void 0) return void 0;
|
|
80
|
+
if (typeof root !== "string") return (0, node_url.fileURLToPath)(root);
|
|
81
|
+
return root.startsWith("file:") ? (0, node_url.fileURLToPath)(root) : root;
|
|
82
|
+
}
|
|
83
|
+
async function entriesOf(ref, model, prefixLocale) {
|
|
84
|
+
const prefix = prefixLocale && ref.locale ? `${ref.locale}/` : "";
|
|
85
|
+
const withLocale = (data) => ref.locale === null ? data : {
|
|
86
|
+
...data,
|
|
87
|
+
locale: ref.locale
|
|
88
|
+
};
|
|
89
|
+
switch (ref.kind) {
|
|
90
|
+
case "collection": {
|
|
91
|
+
const raw = await require_frontmatter.readJson(ref.filePath);
|
|
92
|
+
if (!raw) return [];
|
|
93
|
+
return Object.entries(raw).toSorted(([a], [b]) => a.localeCompare(b, "en")).map(([id, fields]) => ({
|
|
94
|
+
id: `${prefix}${id}`,
|
|
95
|
+
data: withLocale({
|
|
96
|
+
id,
|
|
97
|
+
...fields
|
|
98
|
+
}),
|
|
99
|
+
filePath: ref.filePath
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
case "singleton": {
|
|
103
|
+
const raw = await require_frontmatter.readJson(ref.filePath);
|
|
104
|
+
if (!raw) return [];
|
|
105
|
+
return [{
|
|
106
|
+
id: prefix ? `${ref.locale}` : model.id,
|
|
107
|
+
data: withLocale(raw),
|
|
108
|
+
filePath: ref.filePath
|
|
109
|
+
}];
|
|
110
|
+
}
|
|
111
|
+
case "dictionary": {
|
|
112
|
+
const raw = await require_frontmatter.readJson(ref.filePath);
|
|
113
|
+
if (!raw) return [];
|
|
114
|
+
return Object.entries(raw).toSorted(([a], [b]) => a.localeCompare(b, "en")).map(([key, value]) => ({
|
|
115
|
+
id: `${prefix}${key}`,
|
|
116
|
+
data: withLocale({
|
|
117
|
+
key,
|
|
118
|
+
value
|
|
119
|
+
}),
|
|
120
|
+
filePath: ref.filePath
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
case "document": {
|
|
124
|
+
const text = await require_frontmatter.readText(ref.filePath);
|
|
125
|
+
if (text === null) return [];
|
|
126
|
+
const { frontmatter, body } = require_frontmatter.parseFrontmatter(text, require_frontmatter.stringLikeFieldKeys(model));
|
|
127
|
+
const slug = ref.slug ?? model.id;
|
|
128
|
+
return [{
|
|
129
|
+
id: `${prefix}${slug}`,
|
|
130
|
+
data: withLocale({
|
|
131
|
+
slug,
|
|
132
|
+
...frontmatter
|
|
133
|
+
}),
|
|
134
|
+
body,
|
|
135
|
+
filePath: ref.filePath
|
|
136
|
+
}];
|
|
137
|
+
}
|
|
138
|
+
default: return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
exports.contentrainLoader = contentrainLoader;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//#region src/astro/loader.d.ts
|
|
2
|
+
/** The slice of Astro's `LoaderContext` this loader uses. */
|
|
3
|
+
interface ContentrainLoaderContext {
|
|
4
|
+
store: {
|
|
5
|
+
clear: () => void;
|
|
6
|
+
set: (entry: {
|
|
7
|
+
id: string;
|
|
8
|
+
data: Record<string, unknown>;
|
|
9
|
+
body?: string;
|
|
10
|
+
digest?: string;
|
|
11
|
+
rendered?: {
|
|
12
|
+
html: string;
|
|
13
|
+
metadata?: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
filePath?: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
};
|
|
18
|
+
logger?: {
|
|
19
|
+
info: (msg: string) => void;
|
|
20
|
+
warn: (msg: string) => void;
|
|
21
|
+
};
|
|
22
|
+
/** Astro's resolved config; only `root` is read, to make file paths relative. */
|
|
23
|
+
config?: {
|
|
24
|
+
root?: URL | string;
|
|
25
|
+
};
|
|
26
|
+
generateDigest?: (data: unknown) => string;
|
|
27
|
+
parseData?: (entry: {
|
|
28
|
+
id: string;
|
|
29
|
+
data: Record<string, unknown>;
|
|
30
|
+
filePath?: string;
|
|
31
|
+
}) => Promise<Record<string, unknown>>;
|
|
32
|
+
renderMarkdown?: (content: string) => Promise<{
|
|
33
|
+
html: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}>;
|
|
36
|
+
watcher?: {
|
|
37
|
+
add: (path: string) => void;
|
|
38
|
+
on: (event: string, cb: (path: string) => void) => void;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Structurally Astro's `Loader`. */
|
|
42
|
+
interface ContentrainLoader {
|
|
43
|
+
name: string;
|
|
44
|
+
load: (context: ContentrainLoaderContext) => Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
interface ContentrainLoaderOptions {
|
|
47
|
+
/** Model id — the `id` in `.contentrain/models/<id>.json`. */
|
|
48
|
+
model: string;
|
|
49
|
+
/** Project root holding `.contentrain`. Default: `process.cwd()`. */
|
|
50
|
+
root?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Load only this locale. Omitted on an i18n model, every supported locale is
|
|
53
|
+
* loaded and entry ids are prefixed (`en/my-post`) so the two languages of one
|
|
54
|
+
* post do not collide — Astro ids are unique per collection.
|
|
55
|
+
*/
|
|
56
|
+
locale?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A loader for one Contentrain model.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* // src/content.config.ts
|
|
63
|
+
* import { defineCollection } from 'astro:content'
|
|
64
|
+
* import { contentrainLoader } from '@contentrain/query/astro'
|
|
65
|
+
*
|
|
66
|
+
* export const collections = {
|
|
67
|
+
* posts: defineCollection({ loader: contentrainLoader({ model: 'blog-post', locale: 'en' }) }),
|
|
68
|
+
* articles: defineCollection({ loader: contentrainLoader({ model: 'blog-article' }) }),
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* Each model kind maps to the shape Astro can actually use:
|
|
73
|
+
* collection → one entry per record · document → one entry per file, markdown
|
|
74
|
+
* in `body` (and rendered, so `<Content />` works) · dictionary → one entry per
|
|
75
|
+
* key, because a single blob would make `getEntry()` useless · singleton → one
|
|
76
|
+
* entry, id `<model>` or the locale.
|
|
77
|
+
*/
|
|
78
|
+
declare function contentrainLoader(options: ContentrainLoaderOptions): ContentrainLoader;
|
|
79
|
+
//#endregion
|
|
80
|
+
export { type ContentrainLoader, type ContentrainLoaderContext, type ContentrainLoaderOptions, contentrainLoader };
|
|
81
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/astro/loader.ts"],"mappings":";;UAsBiB,wBAAA;EACf,KAAA;IACE,KAAA;IACA,GAAA,GAAM,KAAA;MACJ,EAAA;MACA,IAAA,EAAM,MAAA;MACN,IAAA;MACA,MAAA;MACA,QAAA;QAAa,IAAA;QAAc,QAAA,GAAW,MAAA;MAAA;MACtC,QAAA;IAAA;EAAA;EAGJ,MAAA;IAAW,IAAA,GAAO,GAAA;IAAsB,IAAA,GAAO,GAAA;EAAA;EAN3C;EAQJ,MAAA;IAAW,IAAA,GAAO,GAAA;EAAA;EAClB,cAAA,IAAkB,IAAA;EAClB,SAAA,IAAa,KAAA;IAAS,EAAA;IAAY,IAAA,EAAM,MAAA;IAAyB,QAAA;EAAA,MAAwB,OAAA,CAAQ,MAAA;EACjG,cAAA,IAAkB,OAAA,aAAoB,OAAA;IAAU,IAAA;IAAc,QAAA,GAAW,MAAA;EAAA;EACzE,OAAA;IAAY,GAAA,GAAM,IAAA;IAAuB,EAAA,GAAK,KAAA,UAAe,EAAA,GAAK,IAAA;EAAA;AAAA;;UAInD,iBAAA;EACf,IAAA;EACA,IAAA,GAAO,OAAA,EAAS,wBAAA,KAA6B,OAAA;AAAA;AAAA,UAG9B,wBAAA;EAXkF;EAajG,KAAA;EAZkB;EAclB,IAAA;EAdgD;;;;;EAoBhD,MAAA;AAAA;;;;;;AAfF;;;;;;;;;;;AAKA;;;;iBAwCgB,iBAAA,CAAkB,OAAA,EAAS,wBAAA,GAA2B,iBAAA"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//#region src/astro/loader.d.ts
|
|
2
|
+
/** The slice of Astro's `LoaderContext` this loader uses. */
|
|
3
|
+
interface ContentrainLoaderContext {
|
|
4
|
+
store: {
|
|
5
|
+
clear: () => void;
|
|
6
|
+
set: (entry: {
|
|
7
|
+
id: string;
|
|
8
|
+
data: Record<string, unknown>;
|
|
9
|
+
body?: string;
|
|
10
|
+
digest?: string;
|
|
11
|
+
rendered?: {
|
|
12
|
+
html: string;
|
|
13
|
+
metadata?: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
filePath?: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
};
|
|
18
|
+
logger?: {
|
|
19
|
+
info: (msg: string) => void;
|
|
20
|
+
warn: (msg: string) => void;
|
|
21
|
+
};
|
|
22
|
+
/** Astro's resolved config; only `root` is read, to make file paths relative. */
|
|
23
|
+
config?: {
|
|
24
|
+
root?: URL | string;
|
|
25
|
+
};
|
|
26
|
+
generateDigest?: (data: unknown) => string;
|
|
27
|
+
parseData?: (entry: {
|
|
28
|
+
id: string;
|
|
29
|
+
data: Record<string, unknown>;
|
|
30
|
+
filePath?: string;
|
|
31
|
+
}) => Promise<Record<string, unknown>>;
|
|
32
|
+
renderMarkdown?: (content: string) => Promise<{
|
|
33
|
+
html: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}>;
|
|
36
|
+
watcher?: {
|
|
37
|
+
add: (path: string) => void;
|
|
38
|
+
on: (event: string, cb: (path: string) => void) => void;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Structurally Astro's `Loader`. */
|
|
42
|
+
interface ContentrainLoader {
|
|
43
|
+
name: string;
|
|
44
|
+
load: (context: ContentrainLoaderContext) => Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
interface ContentrainLoaderOptions {
|
|
47
|
+
/** Model id — the `id` in `.contentrain/models/<id>.json`. */
|
|
48
|
+
model: string;
|
|
49
|
+
/** Project root holding `.contentrain`. Default: `process.cwd()`. */
|
|
50
|
+
root?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Load only this locale. Omitted on an i18n model, every supported locale is
|
|
53
|
+
* loaded and entry ids are prefixed (`en/my-post`) so the two languages of one
|
|
54
|
+
* post do not collide — Astro ids are unique per collection.
|
|
55
|
+
*/
|
|
56
|
+
locale?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A loader for one Contentrain model.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* // src/content.config.ts
|
|
63
|
+
* import { defineCollection } from 'astro:content'
|
|
64
|
+
* import { contentrainLoader } from '@contentrain/query/astro'
|
|
65
|
+
*
|
|
66
|
+
* export const collections = {
|
|
67
|
+
* posts: defineCollection({ loader: contentrainLoader({ model: 'blog-post', locale: 'en' }) }),
|
|
68
|
+
* articles: defineCollection({ loader: contentrainLoader({ model: 'blog-article' }) }),
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* Each model kind maps to the shape Astro can actually use:
|
|
73
|
+
* collection → one entry per record · document → one entry per file, markdown
|
|
74
|
+
* in `body` (and rendered, so `<Content />` works) · dictionary → one entry per
|
|
75
|
+
* key, because a single blob would make `getEntry()` useless · singleton → one
|
|
76
|
+
* entry, id `<model>` or the locale.
|
|
77
|
+
*/
|
|
78
|
+
declare function contentrainLoader(options: ContentrainLoaderOptions): ContentrainLoader;
|
|
79
|
+
//#endregion
|
|
80
|
+
export { type ContentrainLoader, type ContentrainLoaderContext, type ContentrainLoaderOptions, contentrainLoader };
|
|
81
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/astro/loader.ts"],"mappings":";;UAsBiB,wBAAA;EACf,KAAA;IACE,KAAA;IACA,GAAA,GAAM,KAAA;MACJ,EAAA;MACA,IAAA,EAAM,MAAA;MACN,IAAA;MACA,MAAA;MACA,QAAA;QAAa,IAAA;QAAc,QAAA,GAAW,MAAA;MAAA;MACtC,QAAA;IAAA;EAAA;EAGJ,MAAA;IAAW,IAAA,GAAO,GAAA;IAAsB,IAAA,GAAO,GAAA;EAAA;EAN3C;EAQJ,MAAA;IAAW,IAAA,GAAO,GAAA;EAAA;EAClB,cAAA,IAAkB,IAAA;EAClB,SAAA,IAAa,KAAA;IAAS,EAAA;IAAY,IAAA,EAAM,MAAA;IAAyB,QAAA;EAAA,MAAwB,OAAA,CAAQ,MAAA;EACjG,cAAA,IAAkB,OAAA,aAAoB,OAAA;IAAU,IAAA;IAAc,QAAA,GAAW,MAAA;EAAA;EACzE,OAAA;IAAY,GAAA,GAAM,IAAA;IAAuB,EAAA,GAAK,KAAA,UAAe,EAAA,GAAK,IAAA;EAAA;AAAA;;UAInD,iBAAA;EACf,IAAA;EACA,IAAA,GAAO,OAAA,EAAS,wBAAA,KAA6B,OAAA;AAAA;AAAA,UAG9B,wBAAA;EAXkF;EAajG,KAAA;EAZkB;EAclB,IAAA;EAdgD;;;;;EAoBhD,MAAA;AAAA;;;;;;AAfF;;;;;;;;;;;AAKA;;;;iBAwCgB,iBAAA,CAAkB,OAAA,EAAS,wBAAA,GAA2B,iBAAA"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { a as readJson, n as stringLikeFieldKeys, o as readText, r as readProjectManifest, t as parseFrontmatter } from "../frontmatter-CVjPyhOq.mjs";
|
|
2
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
//#region src/astro/loader.ts
|
|
5
|
+
/**
|
|
6
|
+
* A loader for one Contentrain model.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* // src/content.config.ts
|
|
10
|
+
* import { defineCollection } from 'astro:content'
|
|
11
|
+
* import { contentrainLoader } from '@contentrain/query/astro'
|
|
12
|
+
*
|
|
13
|
+
* export const collections = {
|
|
14
|
+
* posts: defineCollection({ loader: contentrainLoader({ model: 'blog-post', locale: 'en' }) }),
|
|
15
|
+
* articles: defineCollection({ loader: contentrainLoader({ model: 'blog-article' }) }),
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Each model kind maps to the shape Astro can actually use:
|
|
20
|
+
* collection → one entry per record · document → one entry per file, markdown
|
|
21
|
+
* in `body` (and rendered, so `<Content />` works) · dictionary → one entry per
|
|
22
|
+
* key, because a single blob would make `getEntry()` useless · singleton → one
|
|
23
|
+
* entry, id `<model>` or the locale.
|
|
24
|
+
*/
|
|
25
|
+
function contentrainLoader(options) {
|
|
26
|
+
const root = options.root ?? process.cwd();
|
|
27
|
+
let watching = false;
|
|
28
|
+
return {
|
|
29
|
+
name: `contentrain:${options.model}`,
|
|
30
|
+
async load(context) {
|
|
31
|
+
const manifest = await readProjectManifest(root);
|
|
32
|
+
const model = manifest.models.find((m) => m.id === options.model);
|
|
33
|
+
if (!model) {
|
|
34
|
+
const known = manifest.models.map((m) => m.id).join(", ") || "none";
|
|
35
|
+
throw new Error(`contentrainLoader: model "${options.model}" not found in ${join(root, ".contentrain", "models")}. Models here: ${known}.`);
|
|
36
|
+
}
|
|
37
|
+
const refs = manifest.contentFiles.filter((ref) => ref.modelId === model.id && (options.locale === void 0 || ref.locale === options.locale));
|
|
38
|
+
if (options.locale !== void 0 && refs.length === 0 && model.i18n) context.logger?.warn(`contentrainLoader: model "${model.id}" has no content for locale "${options.locale}" — collection is empty.`);
|
|
39
|
+
const prefixLocale = model.i18n === true && options.locale === void 0;
|
|
40
|
+
const entries = (await Promise.all(refs.map((ref) => entriesOf(ref, model, prefixLocale)))).flat();
|
|
41
|
+
const siteRoot = toPath(context.config?.root);
|
|
42
|
+
context.store.clear();
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const data = context.parseData ? await context.parseData({
|
|
45
|
+
id: entry.id,
|
|
46
|
+
data: entry.data,
|
|
47
|
+
filePath: entry.filePath
|
|
48
|
+
}) : entry.data;
|
|
49
|
+
const filePath = siteRoot === void 0 ? void 0 : relative(siteRoot, entry.filePath);
|
|
50
|
+
context.store.set({
|
|
51
|
+
id: entry.id,
|
|
52
|
+
data,
|
|
53
|
+
...filePath === void 0 || filePath.startsWith("..") || isAbsolute(filePath) ? {} : { filePath },
|
|
54
|
+
...entry.body === void 0 ? {} : { body: entry.body },
|
|
55
|
+
...context.generateDigest ? { digest: context.generateDigest(entry.data) } : {},
|
|
56
|
+
...entry.body !== void 0 && context.renderMarkdown ? { rendered: await context.renderMarkdown(entry.body) } : {}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
context.logger?.info(`Loaded ${entries.length} ${model.kind} ${entries.length === 1 ? "entry" : "entries"} from ${model.id}`);
|
|
60
|
+
if (context.watcher && !watching) {
|
|
61
|
+
watching = true;
|
|
62
|
+
const paths = new Set(refs.map((ref) => ref.filePath));
|
|
63
|
+
for (const path of paths) context.watcher.add(path);
|
|
64
|
+
context.watcher.add(join(root, ".contentrain", "models", `${model.id}.json`));
|
|
65
|
+
const reload = (path) => {
|
|
66
|
+
if (!paths.has(path) && !path.endsWith(`${model.id}.json`)) return;
|
|
67
|
+
this.load(context);
|
|
68
|
+
};
|
|
69
|
+
context.watcher.on("change", reload);
|
|
70
|
+
context.watcher.on("add", reload);
|
|
71
|
+
context.watcher.on("unlink", reload);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Astro hands `config.root` as a file URL; tests and other hosts may use a path. */
|
|
77
|
+
function toPath(root) {
|
|
78
|
+
if (root === void 0) return void 0;
|
|
79
|
+
if (typeof root !== "string") return fileURLToPath(root);
|
|
80
|
+
return root.startsWith("file:") ? fileURLToPath(root) : root;
|
|
81
|
+
}
|
|
82
|
+
async function entriesOf(ref, model, prefixLocale) {
|
|
83
|
+
const prefix = prefixLocale && ref.locale ? `${ref.locale}/` : "";
|
|
84
|
+
const withLocale = (data) => ref.locale === null ? data : {
|
|
85
|
+
...data,
|
|
86
|
+
locale: ref.locale
|
|
87
|
+
};
|
|
88
|
+
switch (ref.kind) {
|
|
89
|
+
case "collection": {
|
|
90
|
+
const raw = await readJson(ref.filePath);
|
|
91
|
+
if (!raw) return [];
|
|
92
|
+
return Object.entries(raw).toSorted(([a], [b]) => a.localeCompare(b, "en")).map(([id, fields]) => ({
|
|
93
|
+
id: `${prefix}${id}`,
|
|
94
|
+
data: withLocale({
|
|
95
|
+
id,
|
|
96
|
+
...fields
|
|
97
|
+
}),
|
|
98
|
+
filePath: ref.filePath
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
case "singleton": {
|
|
102
|
+
const raw = await readJson(ref.filePath);
|
|
103
|
+
if (!raw) return [];
|
|
104
|
+
return [{
|
|
105
|
+
id: prefix ? `${ref.locale}` : model.id,
|
|
106
|
+
data: withLocale(raw),
|
|
107
|
+
filePath: ref.filePath
|
|
108
|
+
}];
|
|
109
|
+
}
|
|
110
|
+
case "dictionary": {
|
|
111
|
+
const raw = await readJson(ref.filePath);
|
|
112
|
+
if (!raw) return [];
|
|
113
|
+
return Object.entries(raw).toSorted(([a], [b]) => a.localeCompare(b, "en")).map(([key, value]) => ({
|
|
114
|
+
id: `${prefix}${key}`,
|
|
115
|
+
data: withLocale({
|
|
116
|
+
key,
|
|
117
|
+
value
|
|
118
|
+
}),
|
|
119
|
+
filePath: ref.filePath
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
case "document": {
|
|
123
|
+
const text = await readText(ref.filePath);
|
|
124
|
+
if (text === null) return [];
|
|
125
|
+
const { frontmatter, body } = parseFrontmatter(text, stringLikeFieldKeys(model));
|
|
126
|
+
const slug = ref.slug ?? model.id;
|
|
127
|
+
return [{
|
|
128
|
+
id: `${prefix}${slug}`,
|
|
129
|
+
data: withLocale({
|
|
130
|
+
slug,
|
|
131
|
+
...frontmatter
|
|
132
|
+
}),
|
|
133
|
+
body,
|
|
134
|
+
filePath: ref.filePath
|
|
135
|
+
}];
|
|
136
|
+
}
|
|
137
|
+
default: return [];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { contentrainLoader };
|
|
142
|
+
|
|
143
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/astro/loader.ts"],"sourcesContent":["// Astro content-layer loader for a `.contentrain` project.\n//\n// `contentrain generate` produces a typed client for application code; Astro\n// wants its content in the content layer instead, so pages can query it with\n// `getCollection()` and render documents with `<Content />`. This loader reads\n// the same `.contentrain` files the generator reads — through the same manifest\n// — so a project never has two answers about what its content is.\n//\n// Astro is NOT a dependency here, not even a peer: the returned object is\n// structurally what `defineCollection({ loader })` accepts, and the context is\n// typed by the small surface this loader actually uses. That keeps\n// @contentrain/query dependency-free and usable from any Astro 5 version.\n\nimport type { ModelDefinition } from '@contentrain/types'\nimport { isAbsolute, join, relative } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { ContentFileRef } from '../generator/config-reader.js'\nimport { readProjectManifest } from '../generator/config-reader.js'\nimport { readJson, readText } from '../generator/utils.js'\nimport { parseFrontmatter, stringLikeFieldKeys } from '../shared/frontmatter.js'\n\n/** The slice of Astro's `LoaderContext` this loader uses. */\nexport interface ContentrainLoaderContext {\n store: {\n clear: () => void\n set: (entry: {\n id: string\n data: Record<string, unknown>\n body?: string\n digest?: string\n rendered?: { html: string, metadata?: Record<string, unknown> }\n filePath?: string\n }) => void\n }\n logger?: { info: (msg: string) => void, warn: (msg: string) => void }\n /** Astro's resolved config; only `root` is read, to make file paths relative. */\n config?: { root?: URL | string }\n generateDigest?: (data: unknown) => string\n parseData?: (entry: { id: string, data: Record<string, unknown>, filePath?: string }) => Promise<Record<string, unknown>>\n renderMarkdown?: (content: string) => Promise<{ html: string, metadata?: Record<string, unknown> }>\n watcher?: { add: (path: string) => void, on: (event: string, cb: (path: string) => void) => void }\n}\n\n/** Structurally Astro's `Loader`. */\nexport interface ContentrainLoader {\n name: string\n load: (context: ContentrainLoaderContext) => Promise<void>\n}\n\nexport interface ContentrainLoaderOptions {\n /** Model id — the `id` in `.contentrain/models/<id>.json`. */\n model: string\n /** Project root holding `.contentrain`. Default: `process.cwd()`. */\n root?: string\n /**\n * Load only this locale. Omitted on an i18n model, every supported locale is\n * loaded and entry ids are prefixed (`en/my-post`) so the two languages of one\n * post do not collide — Astro ids are unique per collection.\n */\n locale?: string\n}\n\ninterface Entry {\n id: string\n data: Record<string, unknown>\n body?: string\n filePath: string\n}\n\n/**\n * A loader for one Contentrain model.\n *\n * ```ts\n * // src/content.config.ts\n * import { defineCollection } from 'astro:content'\n * import { contentrainLoader } from '@contentrain/query/astro'\n *\n * export const collections = {\n * posts: defineCollection({ loader: contentrainLoader({ model: 'blog-post', locale: 'en' }) }),\n * articles: defineCollection({ loader: contentrainLoader({ model: 'blog-article' }) }),\n * }\n * ```\n *\n * Each model kind maps to the shape Astro can actually use:\n * collection → one entry per record · document → one entry per file, markdown\n * in `body` (and rendered, so `<Content />` works) · dictionary → one entry per\n * key, because a single blob would make `getEntry()` useless · singleton → one\n * entry, id `<model>` or the locale.\n */\nexport function contentrainLoader(options: ContentrainLoaderOptions): ContentrainLoader {\n const root = options.root ?? process.cwd()\n let watching = false\n\n return {\n name: `contentrain:${options.model}`,\n async load(context) {\n const manifest = await readProjectManifest(root)\n const model = manifest.models.find(m => m.id === options.model)\n if (!model) {\n const known = manifest.models.map(m => m.id).join(', ') || 'none'\n throw new Error(\n `contentrainLoader: model \"${options.model}\" not found in ${join(root, '.contentrain', 'models')}. Models here: ${known}.`,\n )\n }\n\n const refs = manifest.contentFiles.filter(ref =>\n ref.modelId === model.id && (options.locale === undefined || ref.locale === options.locale),\n )\n if (options.locale !== undefined && refs.length === 0 && model.i18n) {\n context.logger?.warn(\n `contentrainLoader: model \"${model.id}\" has no content for locale \"${options.locale}\" — collection is empty.`,\n )\n }\n // Prefix ids only when one collection really holds several languages;\n // a single-locale load keeps the natural id so routes stay clean.\n const prefixLocale = model.i18n === true && options.locale === undefined\n\n const perFile = await Promise.all(refs.map(ref => entriesOf(ref, model, prefixLocale)))\n const entries = perFile.flat()\n // Astro rejects an absolute filePath (\"must be relative to the site\n // root\"), and a `.contentrain` outside the Astro root has no relative\n // form it accepts — there we send none rather than a path it refuses.\n const siteRoot = toPath(context.config?.root)\n\n context.store.clear()\n for (const entry of entries) {\n const data = context.parseData\n ? await context.parseData({ id: entry.id, data: entry.data, filePath: entry.filePath })\n : entry.data\n const filePath = siteRoot === undefined ? undefined : relative(siteRoot, entry.filePath)\n context.store.set({\n id: entry.id,\n data,\n ...(filePath === undefined || filePath.startsWith('..') || isAbsolute(filePath) ? {} : { filePath }),\n ...(entry.body === undefined ? {} : { body: entry.body }),\n ...(context.generateDigest ? { digest: context.generateDigest(entry.data) } : {}),\n ...(entry.body !== undefined && context.renderMarkdown\n ? { rendered: await context.renderMarkdown(entry.body) }\n : {}),\n })\n }\n context.logger?.info(`Loaded ${entries.length} ${model.kind} ${entries.length === 1 ? 'entry' : 'entries'} from ${model.id}`)\n\n // Dev server: reload when the files behind this collection change. The\n // listener is registered once — `load` runs again on every change, and a\n // listener per run would multiply the work on every save.\n if (context.watcher && !watching) {\n watching = true\n const paths = new Set(refs.map(ref => ref.filePath))\n for (const path of paths) context.watcher.add(path)\n context.watcher.add(join(root, '.contentrain', 'models', `${model.id}.json`))\n const reload = (path: string) => {\n if (!paths.has(path) && !path.endsWith(`${model.id}.json`)) return\n void this.load(context)\n }\n context.watcher.on('change', reload)\n context.watcher.on('add', reload)\n context.watcher.on('unlink', reload)\n }\n },\n }\n}\n\n/** Astro hands `config.root` as a file URL; tests and other hosts may use a path. */\nfunction toPath(root: URL | string | undefined): string | undefined {\n if (root === undefined) return undefined\n if (typeof root !== 'string') return fileURLToPath(root)\n return root.startsWith('file:') ? fileURLToPath(root) : root\n}\n\nasync function entriesOf(ref: ContentFileRef, model: ModelDefinition, prefixLocale: boolean): Promise<Entry[]> {\n const prefix = prefixLocale && ref.locale ? `${ref.locale}/` : ''\n const withLocale = (data: Record<string, unknown>): Record<string, unknown> =>\n ref.locale === null ? data : { ...data, locale: ref.locale }\n\n switch (ref.kind) {\n case 'collection': {\n const raw = await readJson<Record<string, Record<string, unknown>>>(ref.filePath)\n if (!raw) return []\n return Object.entries(raw)\n .toSorted(([a], [b]) => a.localeCompare(b, 'en'))\n .map(([id, fields]) => ({\n id: `${prefix}${id}`,\n data: withLocale({ id, ...fields }),\n filePath: ref.filePath,\n }))\n }\n\n case 'singleton': {\n const raw = await readJson<Record<string, unknown>>(ref.filePath)\n if (!raw) return []\n return [{\n id: prefix ? `${ref.locale}` : model.id,\n data: withLocale(raw),\n filePath: ref.filePath,\n }]\n }\n\n case 'dictionary': {\n // One entry per key: a dictionary key is a semantic address, and a single\n // blob entry would make getEntry() and reference() useless on it.\n const raw = await readJson<Record<string, string>>(ref.filePath)\n if (!raw) return []\n return Object.entries(raw)\n .toSorted(([a], [b]) => a.localeCompare(b, 'en'))\n .map(([key, value]) => ({\n id: `${prefix}${key}`,\n data: withLocale({ key, value }),\n filePath: ref.filePath,\n }))\n }\n\n case 'document': {\n const text = await readText(ref.filePath)\n if (text === null) return []\n const { frontmatter, body } = parseFrontmatter(text, stringLikeFieldKeys(model))\n const slug = ref.slug ?? model.id\n return [{\n id: `${prefix}${slug}`,\n data: withLocale({ slug, ...frontmatter }),\n body,\n filePath: ref.filePath,\n }]\n }\n\n default:\n return []\n }\n}\n"],"mappings":"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"}
|
package/dist/cdn/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as CdnDocumentQuery, E as CdnCollectionQuery, F as DocumentDataSource, I as DocumentIndexEntry, L as SingletonDataSource, M as TransportConfig, N as CollectionDataSource, P as DictionaryDataSource, S as MediaManifest, T as CdnSingletonAccessor, _ as FormsClient, a as ConversationClient, b as MediaAsset, c as ConversationHistory, d as ConversationSendOptions, f as ConversationToolResult, g as FormSubmitResult, h as FormFieldConfig, i as ContentrainError, j as HttpTransport, l as ConversationMessage, m as FormConfig, n as ContentrainCDNConfig, o as ConversationClientConfig, p as ConversationUsage, r as createContentrain, s as ConversationContext, t as ContentrainCDNClient, u as ConversationResponse, v as FormsClientConfig, w as CdnDictionaryAccessor, x as MediaAssetMeta, y as MediaAccessor } from "../index-
|
|
1
|
+
import { C as CdnDocumentQuery, E as CdnCollectionQuery, F as DocumentDataSource, I as DocumentIndexEntry, L as SingletonDataSource, M as TransportConfig, N as CollectionDataSource, P as DictionaryDataSource, S as MediaManifest, T as CdnSingletonAccessor, _ as FormsClient, a as ConversationClient, b as MediaAsset, c as ConversationHistory, d as ConversationSendOptions, f as ConversationToolResult, g as FormSubmitResult, h as FormFieldConfig, i as ContentrainError, j as HttpTransport, l as ConversationMessage, m as FormConfig, n as ContentrainCDNConfig, o as ConversationClientConfig, p as ConversationUsage, r as createContentrain, s as ConversationContext, t as ContentrainCDNClient, u as ConversationResponse, v as FormsClientConfig, w as CdnDictionaryAccessor, x as MediaAssetMeta, y as MediaAccessor } from "../index-DYWwX7xL.mjs";
|
|
2
2
|
export { CdnCollectionQuery, CdnDictionaryAccessor, CdnDocumentQuery, CdnSingletonAccessor, CollectionDataSource, ContentrainCDNClient, ContentrainCDNConfig, ContentrainError, ConversationClient, ConversationClientConfig, ConversationContext, ConversationHistory, ConversationMessage, ConversationResponse, ConversationSendOptions, ConversationToolResult, ConversationUsage, DictionaryDataSource, DocumentDataSource, DocumentIndexEntry, FormConfig, FormFieldConfig, FormSubmitResult, FormsClient, FormsClientConfig, HttpTransport, MediaAccessor, MediaAsset, MediaAssetMeta, MediaManifest, SingletonDataSource, TransportConfig, createContentrain };
|
package/dist/cli.cjs
CHANGED
package/dist/cli.mjs
CHANGED