@cogenta/render 0.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/dist/astro/integration.d.ts +57 -0
- package/dist/astro/integration.d.ts.map +1 -0
- package/dist/astro/integration.js +72 -0
- package/dist/astro/integration.js.map +1 -0
- package/dist/build/index.d.ts +7 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +7 -0
- package/dist/build/index.js.map +1 -0
- package/dist/build/integration.d.ts +25 -0
- package/dist/build/integration.d.ts.map +1 -0
- package/dist/build/integration.js +41 -0
- package/dist/build/integration.js.map +1 -0
- package/dist/build/plan.d.ts +41 -0
- package/dist/build/plan.d.ts.map +1 -0
- package/dist/build/plan.js +48 -0
- package/dist/build/plan.js.map +1 -0
- package/dist/build/refusal.d.ts +14 -0
- package/dist/build/refusal.d.ts.map +1 -0
- package/dist/build/refusal.js +110 -0
- package/dist/build/refusal.js.map +1 -0
- package/dist/build/requirements.d.ts +59 -0
- package/dist/build/requirements.d.ts.map +1 -0
- package/dist/build/requirements.js +74 -0
- package/dist/build/requirements.js.map +1 -0
- package/dist/build/run-build.d.ts +43 -0
- package/dist/build/run-build.d.ts.map +1 -0
- package/dist/build/run-build.js +73 -0
- package/dist/build/run-build.js.map +1 -0
- package/dist/build/targets.d.ts +47 -0
- package/dist/build/targets.d.ts.map +1 -0
- package/dist/build/targets.js +69 -0
- package/dist/build/targets.js.map +1 -0
- package/dist/cache/index.d.ts +7 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +4 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/page-cache.d.ts +64 -0
- package/dist/cache/page-cache.d.ts.map +1 -0
- package/dist/cache/page-cache.js +128 -0
- package/dist/cache/page-cache.js.map +1 -0
- package/dist/cache/recorder.d.ts +49 -0
- package/dist/cache/recorder.d.ts.map +1 -0
- package/dist/cache/recorder.js +77 -0
- package/dist/cache/recorder.js.map +1 -0
- package/dist/cache/tags.d.ts +55 -0
- package/dist/cache/tags.d.ts.map +1 -0
- package/dist/cache/tags.js +62 -0
- package/dist/cache/tags.js.map +1 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/content/client.d.ts +35 -0
- package/dist/content/client.d.ts.map +1 -0
- package/dist/content/client.js +155 -0
- package/dist/content/client.js.map +1 -0
- package/dist/content/types.d.ts +104 -0
- package/dist/content/types.d.ts.map +1 -0
- package/dist/content/types.js +16 -0
- package/dist/content/types.js.map +1 -0
- package/dist/context/render-context.d.ts +31 -0
- package/dist/context/render-context.d.ts.map +1 -0
- package/dist/context/render-context.js +152 -0
- package/dist/context/render-context.js.map +1 -0
- package/dist/context/types.d.ts +49 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +2 -0
- package/dist/context/types.js.map +1 -0
- package/dist/images/errors.d.ts +20 -0
- package/dist/images/errors.d.ts.map +1 -0
- package/dist/images/errors.js +58 -0
- package/dist/images/errors.js.map +1 -0
- package/dist/images/format.d.ts +18 -0
- package/dist/images/format.d.ts.map +1 -0
- package/dist/images/format.js +34 -0
- package/dist/images/format.js.map +1 -0
- package/dist/images/geometry.d.ts +46 -0
- package/dist/images/geometry.d.ts.map +1 -0
- package/dist/images/geometry.js +127 -0
- package/dist/images/geometry.js.map +1 -0
- package/dist/images/index.d.ts +29 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +30 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/pipeline.d.ts +51 -0
- package/dist/images/pipeline.d.ts.map +1 -0
- package/dist/images/pipeline.js +105 -0
- package/dist/images/pipeline.js.map +1 -0
- package/dist/images/sharp.d.ts +57 -0
- package/dist/images/sharp.d.ts.map +1 -0
- package/dist/images/sharp.js +139 -0
- package/dist/images/sharp.js.map +1 -0
- package/dist/images/srcset.d.ts +33 -0
- package/dist/images/srcset.d.ts.map +1 -0
- package/dist/images/srcset.js +94 -0
- package/dist/images/srcset.js.map +1 -0
- package/dist/images/store.d.ts +32 -0
- package/dist/images/store.d.ts.map +1 -0
- package/dist/images/store.js +54 -0
- package/dist/images/store.js.map +1 -0
- package/dist/images/types.d.ts +128 -0
- package/dist/images/types.d.ts.map +1 -0
- package/dist/images/types.js +22 -0
- package/dist/images/types.js.map +1 -0
- package/dist/images/wasm.d.ts +43 -0
- package/dist/images/wasm.d.ts.map +1 -0
- package/dist/images/wasm.js +128 -0
- package/dist/images/wasm.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/pwa/build.d.ts +39 -0
- package/dist/pwa/build.d.ts.map +1 -0
- package/dist/pwa/build.js +38 -0
- package/dist/pwa/build.js.map +1 -0
- package/dist/pwa/client.d.ts +90 -0
- package/dist/pwa/client.d.ts.map +1 -0
- package/dist/pwa/client.js +76 -0
- package/dist/pwa/client.js.map +1 -0
- package/dist/pwa/index.d.ts +29 -0
- package/dist/pwa/index.d.ts.map +1 -0
- package/dist/pwa/index.js +22 -0
- package/dist/pwa/index.js.map +1 -0
- package/dist/pwa/manifest.d.ts +69 -0
- package/dist/pwa/manifest.d.ts.map +1 -0
- package/dist/pwa/manifest.js +108 -0
- package/dist/pwa/manifest.js.map +1 -0
- package/dist/pwa/offline.d.ts +44 -0
- package/dist/pwa/offline.d.ts.map +1 -0
- package/dist/pwa/offline.js +94 -0
- package/dist/pwa/offline.js.map +1 -0
- package/dist/pwa/service-worker.d.ts +71 -0
- package/dist/pwa/service-worker.d.ts.map +1 -0
- package/dist/pwa/service-worker.js +119 -0
- package/dist/pwa/service-worker.js.map +1 -0
- package/dist/pwa/strategy.d.ts +36 -0
- package/dist/pwa/strategy.d.ts.map +1 -0
- package/dist/pwa/strategy.js +180 -0
- package/dist/pwa/strategy.js.map +1 -0
- package/dist/pwa/sw-runtime.d.ts +109 -0
- package/dist/pwa/sw-runtime.d.ts.map +1 -0
- package/dist/pwa/sw-runtime.js +214 -0
- package/dist/pwa/sw-runtime.js.map +1 -0
- package/dist/pwa/types.d.ts +107 -0
- package/dist/pwa/types.d.ts.map +1 -0
- package/dist/pwa/types.js +18 -0
- package/dist/pwa/types.js.map +1 -0
- package/dist/pwa/version.d.ts +45 -0
- package/dist/pwa/version.d.ts.map +1 -0
- package/dist/pwa/version.js +89 -0
- package/dist/pwa/version.js.map +1 -0
- package/dist/skin/color.d.ts +50 -0
- package/dist/skin/color.d.ts.map +1 -0
- package/dist/skin/color.js +176 -0
- package/dist/skin/color.js.map +1 -0
- package/dist/skin/css.d.ts +19 -0
- package/dist/skin/css.d.ts.map +1 -0
- package/dist/skin/css.js +69 -0
- package/dist/skin/css.js.map +1 -0
- package/dist/skin/errors.d.ts +22 -0
- package/dist/skin/errors.d.ts.map +1 -0
- package/dist/skin/errors.js +59 -0
- package/dist/skin/errors.js.map +1 -0
- package/dist/skin/index.d.ts +15 -0
- package/dist/skin/index.d.ts.map +1 -0
- package/dist/skin/index.js +11 -0
- package/dist/skin/index.js.map +1 -0
- package/dist/skin/sheet.d.ts +42 -0
- package/dist/skin/sheet.d.ts.map +1 -0
- package/dist/skin/sheet.js +36 -0
- package/dist/skin/sheet.js.map +1 -0
- package/dist/skin/tokens.d.ts +90 -0
- package/dist/skin/tokens.d.ts.map +1 -0
- package/dist/skin/tokens.js +56 -0
- package/dist/skin/tokens.js.map +1 -0
- package/dist/skin/validate.d.ts +14 -0
- package/dist/skin/validate.d.ts.map +1 -0
- package/dist/skin/validate.js +272 -0
- package/dist/skin/validate.js.map +1 -0
- package/dist/theme/load-theme.d.ts +37 -0
- package/dist/theme/load-theme.d.ts.map +1 -0
- package/dist/theme/load-theme.js +102 -0
- package/dist/theme/load-theme.js.map +1 -0
- package/dist/theme/manifest.d.ts +48 -0
- package/dist/theme/manifest.d.ts.map +1 -0
- package/dist/theme/manifest.js +36 -0
- package/dist/theme/manifest.js.map +1 -0
- package/dist/theme/verify/forbidden.d.ts +39 -0
- package/dist/theme/verify/forbidden.d.ts.map +1 -0
- package/dist/theme/verify/forbidden.js +107 -0
- package/dist/theme/verify/forbidden.js.map +1 -0
- package/dist/theme/verify/scan-file.d.ts +15 -0
- package/dist/theme/verify/scan-file.d.ts.map +1 -0
- package/dist/theme/verify/scan-file.js +151 -0
- package/dist/theme/verify/scan-file.js.map +1 -0
- package/dist/theme/verify/scanner.d.ts +52 -0
- package/dist/theme/verify/scanner.d.ts.map +1 -0
- package/dist/theme/verify/scanner.js +304 -0
- package/dist/theme/verify/scanner.js.map +1 -0
- package/dist/theme/verify/verify-theme.d.ts +44 -0
- package/dist/theme/verify/verify-theme.d.ts.map +1 -0
- package/dist/theme/verify/verify-theme.js +179 -0
- package/dist/theme/verify/verify-theme.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tag vocabulary of the render cache.
|
|
3
|
+
*
|
|
4
|
+
* Four kinds of tag, and no more, because every tag is a promise the publish
|
|
5
|
+
* side has to keep: a tag nobody can emit on publication is a page that never
|
|
6
|
+
* gets invalidated.
|
|
7
|
+
*
|
|
8
|
+
* - `entry:<id>` — this exact entry was read.
|
|
9
|
+
* - `collection:<name>` — a *list* of this collection was read. Carried by list
|
|
10
|
+
* pages only, never by a detail page, which is precisely what makes
|
|
11
|
+
* "publishing one entry invalidates its page and the lists, and nothing
|
|
12
|
+
* else" true.
|
|
13
|
+
* - `media:<id>` — an image variant of this media was built.
|
|
14
|
+
* - `path:<path>` — a URL was resolved to an entry, or to nothing. The `path`
|
|
15
|
+
* tag is what invalidates a cached 404: there is no entry id to tag when the
|
|
16
|
+
* lookup came back empty.
|
|
17
|
+
*
|
|
18
|
+
* Entry ids are UUIDv7 and unique across every collection (`@cogenta/schema`
|
|
19
|
+
* `newId`), so an entry tag needs no collection segment — which is what lets
|
|
20
|
+
* `byPath`, which never learns the collection, tag the same entry as `entry()`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function entryTag(id: string): string;
|
|
23
|
+
export declare function collectionTag(collection: string): string;
|
|
24
|
+
export declare function mediaTag(id: string): string;
|
|
25
|
+
export declare function pathTag(path: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Trailing slashes and a missing leading slash are the same route to a reader
|
|
28
|
+
* and two different strings to a cache. Normalising here rather than at every
|
|
29
|
+
* call site is what stops `/blog/x` and `/blog/x/` from becoming two tags, one
|
|
30
|
+
* of which is never invalidated.
|
|
31
|
+
*/
|
|
32
|
+
export declare function normalisePath(path: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* A content change, as the publish side knows it.
|
|
35
|
+
*
|
|
36
|
+
* Publication, unpublication and deletion produce the same tags: all three
|
|
37
|
+
* change what a visitor sees, and all three must drop the same pages. There is
|
|
38
|
+
* deliberately no `kind` field — a cache that invalidates differently depending
|
|
39
|
+
* on the verb is a cache with three ways to be wrong instead of one.
|
|
40
|
+
*/
|
|
41
|
+
export interface ContentChange {
|
|
42
|
+
readonly collection: string;
|
|
43
|
+
readonly id: string;
|
|
44
|
+
/**
|
|
45
|
+
* Routes the entry occupied, or occupies now. Both are needed on a move:
|
|
46
|
+
* the old URL must stop resolving and the new one must stop 404-ing.
|
|
47
|
+
*/
|
|
48
|
+
readonly paths?: readonly string[] | undefined;
|
|
49
|
+
/** Media whose bytes changed. Rare — a re-crop, not a re-upload. */
|
|
50
|
+
readonly media?: readonly string[] | undefined;
|
|
51
|
+
}
|
|
52
|
+
/** Every tag a change invalidates. Deduplicated, order not significant. */
|
|
53
|
+
export declare function tagsForChange(change: ContentChange): readonly string[];
|
|
54
|
+
export declare function tagsForChanges(changes: readonly ContentChange[]): readonly string[];
|
|
55
|
+
//# sourceMappingURL=tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../src/cache/tags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IAC9C,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;CAC/C;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,MAAM,EAAE,CAKtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,MAAM,EAAE,CAInF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tag vocabulary of the render cache.
|
|
3
|
+
*
|
|
4
|
+
* Four kinds of tag, and no more, because every tag is a promise the publish
|
|
5
|
+
* side has to keep: a tag nobody can emit on publication is a page that never
|
|
6
|
+
* gets invalidated.
|
|
7
|
+
*
|
|
8
|
+
* - `entry:<id>` — this exact entry was read.
|
|
9
|
+
* - `collection:<name>` — a *list* of this collection was read. Carried by list
|
|
10
|
+
* pages only, never by a detail page, which is precisely what makes
|
|
11
|
+
* "publishing one entry invalidates its page and the lists, and nothing
|
|
12
|
+
* else" true.
|
|
13
|
+
* - `media:<id>` — an image variant of this media was built.
|
|
14
|
+
* - `path:<path>` — a URL was resolved to an entry, or to nothing. The `path`
|
|
15
|
+
* tag is what invalidates a cached 404: there is no entry id to tag when the
|
|
16
|
+
* lookup came back empty.
|
|
17
|
+
*
|
|
18
|
+
* Entry ids are UUIDv7 and unique across every collection (`@cogenta/schema`
|
|
19
|
+
* `newId`), so an entry tag needs no collection segment — which is what lets
|
|
20
|
+
* `byPath`, which never learns the collection, tag the same entry as `entry()`.
|
|
21
|
+
*/
|
|
22
|
+
const SEPARATOR = ':';
|
|
23
|
+
export function entryTag(id) {
|
|
24
|
+
return `entry${SEPARATOR}${id}`;
|
|
25
|
+
}
|
|
26
|
+
export function collectionTag(collection) {
|
|
27
|
+
return `collection${SEPARATOR}${collection}`;
|
|
28
|
+
}
|
|
29
|
+
export function mediaTag(id) {
|
|
30
|
+
return `media${SEPARATOR}${id}`;
|
|
31
|
+
}
|
|
32
|
+
export function pathTag(path) {
|
|
33
|
+
return `path${SEPARATOR}${normalisePath(path)}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Trailing slashes and a missing leading slash are the same route to a reader
|
|
37
|
+
* and two different strings to a cache. Normalising here rather than at every
|
|
38
|
+
* call site is what stops `/blog/x` and `/blog/x/` from becoming two tags, one
|
|
39
|
+
* of which is never invalidated.
|
|
40
|
+
*/
|
|
41
|
+
export function normalisePath(path) {
|
|
42
|
+
const withLeading = path.startsWith('/') ? path : `/${path}`;
|
|
43
|
+
const trimmed = withLeading.replace(/\/+$/u, '');
|
|
44
|
+
return trimmed.length === 0 ? '/' : trimmed;
|
|
45
|
+
}
|
|
46
|
+
/** Every tag a change invalidates. Deduplicated, order not significant. */
|
|
47
|
+
export function tagsForChange(change) {
|
|
48
|
+
const tags = new Set([entryTag(change.id), collectionTag(change.collection)]);
|
|
49
|
+
for (const path of change.paths ?? [])
|
|
50
|
+
tags.add(pathTag(path));
|
|
51
|
+
for (const id of change.media ?? [])
|
|
52
|
+
tags.add(mediaTag(id));
|
|
53
|
+
return [...tags];
|
|
54
|
+
}
|
|
55
|
+
export function tagsForChanges(changes) {
|
|
56
|
+
const tags = new Set();
|
|
57
|
+
for (const change of changes)
|
|
58
|
+
for (const tag of tagsForChange(change))
|
|
59
|
+
tags.add(tag);
|
|
60
|
+
return [...tags];
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/cache/tags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,SAAS,GAAG,GAAG,CAAA;AAErB,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,OAAO,QAAQ,SAAS,GAAG,EAAE,EAAE,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,OAAO,aAAa,SAAS,GAAG,UAAU,EAAE,CAAA;AAC9C,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,OAAO,QAAQ,SAAS,GAAG,EAAE,EAAE,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,OAAO,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,CAAA;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAA;IAC5D,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAChD,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAA;AAC7C,CAAC;AAsBD,2EAA2E;AAC3E,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACrF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC9D,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3D,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAiC;IAC9D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,MAAM,IAAI,OAAO;QAAE,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACpF,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;AAClB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the delivery plane needs to know, and deliberately nothing else.
|
|
3
|
+
*
|
|
4
|
+
* `site` is structurally the `site` block of `CogentaConfig`, so a resolved
|
|
5
|
+
* Cogenta configuration is assignable here without an import: the render
|
|
6
|
+
* package must not pull the control-plane configuration loader — and with it
|
|
7
|
+
* the database URL and every secret — into the process that runs theme code
|
|
8
|
+
* (ADR-0004).
|
|
9
|
+
*/
|
|
10
|
+
export interface SiteConfig {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly url: string;
|
|
13
|
+
readonly locales: readonly string[];
|
|
14
|
+
readonly defaultLocale: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ThemeConfig {
|
|
17
|
+
/** Package name or directory name of the active theme. */
|
|
18
|
+
readonly name: string;
|
|
19
|
+
/**
|
|
20
|
+
* Where the theme lives. Absolute, or relative to the working directory.
|
|
21
|
+
* Absent means "resolve `name` as a package from the working directory".
|
|
22
|
+
*/
|
|
23
|
+
readonly root?: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* How the renderer reaches the content API (ADR-0016).
|
|
27
|
+
*
|
|
28
|
+
* `token` is a read-only token carrying the rights of the `public` role. It is
|
|
29
|
+
* the *only* credential the delivery plane holds, and it can read nothing a
|
|
30
|
+
* visitor could not read anyway.
|
|
31
|
+
*/
|
|
32
|
+
export interface ContentApiConfig {
|
|
33
|
+
readonly url: string;
|
|
34
|
+
readonly token: string;
|
|
35
|
+
/** Mount point of the content routes under `url`. */
|
|
36
|
+
readonly basePath?: string | undefined;
|
|
37
|
+
}
|
|
38
|
+
export interface RenderConfig {
|
|
39
|
+
readonly site: SiteConfig;
|
|
40
|
+
readonly theme: ThemeConfig;
|
|
41
|
+
readonly content: ContentApiConfig;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validates a render configuration, and fails loudly rather than rendering a
|
|
45
|
+
* site against half a configuration.
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseRenderConfig(input: unknown): RenderConfig;
|
|
48
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CACnC;AAmBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAuB9D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { CogentaError } from '@cogenta/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
const siteSchema = z.object({
|
|
4
|
+
name: z.string().min(1),
|
|
5
|
+
url: z.url(),
|
|
6
|
+
locales: z.array(z.string().min(1)).min(1),
|
|
7
|
+
defaultLocale: z.string().min(1),
|
|
8
|
+
});
|
|
9
|
+
const renderConfigSchema = z.object({
|
|
10
|
+
site: siteSchema,
|
|
11
|
+
theme: z.object({ name: z.string().min(1), root: z.string().min(1).optional() }),
|
|
12
|
+
content: z.object({
|
|
13
|
+
url: z.url(),
|
|
14
|
+
token: z.string().min(1),
|
|
15
|
+
basePath: z.string().min(1).optional(),
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Validates a render configuration, and fails loudly rather than rendering a
|
|
20
|
+
* site against half a configuration.
|
|
21
|
+
*/
|
|
22
|
+
export function parseRenderConfig(input) {
|
|
23
|
+
const result = renderConfigSchema.safeParse(input);
|
|
24
|
+
if (!result.success) {
|
|
25
|
+
const problems = result.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`);
|
|
26
|
+
throw new CogentaError({
|
|
27
|
+
code: 'CONFIG_INVALID',
|
|
28
|
+
message: `The render configuration is not usable: ${problems.join('; ')}.`,
|
|
29
|
+
hint: 'A render configuration needs site.name, site.url, site.locales, site.defaultLocale, theme.name and a content API url plus read token.',
|
|
30
|
+
details: { problems },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const config = result.data;
|
|
34
|
+
if (!config.site.locales.includes(config.site.defaultLocale)) {
|
|
35
|
+
throw new CogentaError({
|
|
36
|
+
code: 'CONFIG_INVALID',
|
|
37
|
+
message: `The default locale "${config.site.defaultLocale}" is not in the site locales.`,
|
|
38
|
+
hint: `Add it to site.locales, or pick one of: ${config.site.locales.join(', ')}.`,
|
|
39
|
+
details: { defaultLocale: config.site.defaultLocale, locales: config.site.locales },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return config;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgDvB,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE;IACZ,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACjC,CAAC,CAAA;AAEF,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;IAChF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE;QACZ,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;KACvC,CAAC;CACH,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QAChG,MAAM,IAAI,YAAY,CAAC;YACrB,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,2CAA2C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAC1E,IAAI,EAAE,uIAAuI;YAC7I,OAAO,EAAE,EAAE,QAAQ,EAAE;SACtB,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;IAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,YAAY,CAAC;YACrB,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,uBAAuB,MAAM,CAAC,IAAI,CAAC,aAAa,+BAA+B;YACxF,IAAI,EAAE,2CAA2C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAClF,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;SACpF,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ContentApiConfig } from '../config.js';
|
|
2
|
+
import type { ContentClient, ResponseDependencies } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The content client of contract D, and it is HTTP on purpose (ADR-0016).
|
|
5
|
+
*
|
|
6
|
+
* It holds one credential — a read-only token carrying the rights of the
|
|
7
|
+
* `public` role — and it speaks to `@cogenta/api` over the network. It imports
|
|
8
|
+
* neither `@cogenta/schema` nor a database driver, and it could not use one:
|
|
9
|
+
* there is no connection in this process to use.
|
|
10
|
+
*
|
|
11
|
+
* A theme therefore cannot reach a draft even by asking for one. The refusal
|
|
12
|
+
* happens in the permission layer on the other side of the wire, where it can
|
|
13
|
+
* be enforced rather than promised.
|
|
14
|
+
*/
|
|
15
|
+
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
16
|
+
export interface ContentClientOptions extends ContentApiConfig {
|
|
17
|
+
/** Locale sent when a request does not name one. */
|
|
18
|
+
readonly locale?: string | undefined;
|
|
19
|
+
/** Injected in tests and by hosts with their own instrumentation. */
|
|
20
|
+
readonly fetch?: FetchLike | undefined;
|
|
21
|
+
/** Milliseconds before a request is abandoned. A slow API must not hang a build. */
|
|
22
|
+
readonly timeoutMs?: number | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Fired with what a response was actually built from, on every successful
|
|
25
|
+
* read — not only what the call asked for.
|
|
26
|
+
*
|
|
27
|
+
* This is the hook a render cache wires into. Without it, a page that embeds
|
|
28
|
+
* a related entry through server-side expansion tags only the entry it named
|
|
29
|
+
* directly, and stays stale forever after the related one changes: nothing in
|
|
30
|
+
* a direct request-response wrapping can see what the server inlined.
|
|
31
|
+
*/
|
|
32
|
+
readonly onDependencies?: ((dependencies: ResponseDependencies) => void) | undefined;
|
|
33
|
+
}
|
|
34
|
+
export declare function createContentClient(options: ContentClientOptions): ContentClient;
|
|
35
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/content/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,KAAK,EACV,aAAa,EAIb,oBAAoB,EACrB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEhF,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D,oDAAoD;IACpD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IACtC,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,YAAY,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;CACrF;AAiBD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAuIhF"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { CogentaError } from '@cogenta/core';
|
|
2
|
+
const DEFAULT_BASE_PATH = '/api/content';
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
4
|
+
export function createContentClient(options) {
|
|
5
|
+
const basePath = (options.basePath ?? DEFAULT_BASE_PATH).replace(/\/+$/u, '');
|
|
6
|
+
const origin = options.url.replace(/\/+$/u, '');
|
|
7
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
8
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
9
|
+
async function request(path, query) {
|
|
10
|
+
const url = new URL(`${origin}${basePath}${path}`);
|
|
11
|
+
for (const [key, value] of Object.entries(query))
|
|
12
|
+
url.searchParams.set(key, value);
|
|
13
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
14
|
+
let response;
|
|
15
|
+
try {
|
|
16
|
+
response = await doFetch(url.toString(), {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
signal,
|
|
19
|
+
headers: {
|
|
20
|
+
accept: 'application/json',
|
|
21
|
+
// The one credential of the delivery plane. Never logged, never put
|
|
22
|
+
// in an error, never handed to a theme (rule R7).
|
|
23
|
+
authorization: `Bearer ${options.token}`,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw new CogentaError({
|
|
29
|
+
code: 'CONTENT_API_FAILED',
|
|
30
|
+
message: `The content API could not be reached at ${url.pathname}.`,
|
|
31
|
+
hint: 'Check that the API is running and that content.url points at it. The renderer reads content over HTTP and has no other way in (ADR-0016).',
|
|
32
|
+
cause: error,
|
|
33
|
+
details: { path: url.pathname },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (response.status === 404)
|
|
37
|
+
return null;
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
throw await failure(response, url);
|
|
40
|
+
try {
|
|
41
|
+
return await response.json();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new CogentaError({
|
|
45
|
+
code: 'CONTENT_API_FAILED',
|
|
46
|
+
message: `The content API returned a body that is not JSON for ${url.pathname}.`,
|
|
47
|
+
hint: 'Check that content.url points at the Cogenta API and not at a proxy or an error page.',
|
|
48
|
+
cause: error,
|
|
49
|
+
details: { path: url.pathname, status: response.status },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function failure(response, url) {
|
|
54
|
+
const body = await response
|
|
55
|
+
.text()
|
|
56
|
+
.then(parseJson)
|
|
57
|
+
.catch(() => undefined);
|
|
58
|
+
const api = errorFrom(body);
|
|
59
|
+
const forbidden = response.status === 401 || response.status === 403;
|
|
60
|
+
return new CogentaError({
|
|
61
|
+
code: 'CONTENT_API_FAILED',
|
|
62
|
+
message: `The content API refused ${url.pathname} with ${response.status}${api === undefined ? '' : `: ${api}`}.`,
|
|
63
|
+
hint: forbidden
|
|
64
|
+
? 'The render token carries the rights of the `public` role only. A theme never sees a draft, by design — ask for published content, or render this page through a preview token.'
|
|
65
|
+
: 'Check the request the theme made against the query vocabulary of the content API.',
|
|
66
|
+
details: { path: url.pathname, status: response.status },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function entryFrom(payload) {
|
|
70
|
+
if (payload === null)
|
|
71
|
+
return null;
|
|
72
|
+
const envelope = payload;
|
|
73
|
+
reportDependencies(envelope);
|
|
74
|
+
return envelope.data ?? null;
|
|
75
|
+
}
|
|
76
|
+
// The API qualifies an entry dependency as `<collection>:<id>` so two
|
|
77
|
+
// collections can never collide in the same set; the render side only ever
|
|
78
|
+
// tags by id, because ids are UUIDv7 and unique across every collection
|
|
79
|
+
// (`@cogenta/schema` `newId`) — the qualifier has already done its job by the
|
|
80
|
+
// time it gets here.
|
|
81
|
+
function bareId(qualified) {
|
|
82
|
+
const separator = qualified.indexOf(':');
|
|
83
|
+
return separator === -1 ? qualified : qualified.slice(separator + 1);
|
|
84
|
+
}
|
|
85
|
+
function reportDependencies(envelope) {
|
|
86
|
+
if (options.onDependencies === undefined)
|
|
87
|
+
return;
|
|
88
|
+
const wire = envelope.meta?.dependencies;
|
|
89
|
+
if (wire === undefined)
|
|
90
|
+
return;
|
|
91
|
+
options.onDependencies({
|
|
92
|
+
entries: (wire.entries ?? []).map(bareId),
|
|
93
|
+
media: wire.media ?? [],
|
|
94
|
+
collections: wire.collections ?? [],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
entry: async (collection, id) => entryFrom(await request(`/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {})),
|
|
99
|
+
// Path resolution is a route lookup, not an entry lookup: the renderer
|
|
100
|
+
// knows a URL and nothing else. The API exposes it beside the collection
|
|
101
|
+
// routes, under a segment no collection can be named.
|
|
102
|
+
byPath: async (path) => entryFrom(await request('/-/by-path', { path })),
|
|
103
|
+
list: async (query) => {
|
|
104
|
+
const payload = await request(`/${encodeURIComponent(query.collection)}`, listQuery(query));
|
|
105
|
+
const envelope = payload;
|
|
106
|
+
if (envelope === null || !Array.isArray(envelope.data)) {
|
|
107
|
+
return { items: [], nextCursor: null, hasMore: false };
|
|
108
|
+
}
|
|
109
|
+
reportDependencies(envelope);
|
|
110
|
+
return {
|
|
111
|
+
items: envelope.data,
|
|
112
|
+
nextCursor: envelope.page?.nextCursor ?? null,
|
|
113
|
+
hasMore: envelope.page?.hasMore ?? false,
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
function listQuery(query) {
|
|
118
|
+
const parameters = {};
|
|
119
|
+
const locale = query.locale ?? options.locale;
|
|
120
|
+
if (locale !== undefined)
|
|
121
|
+
parameters.locale = locale;
|
|
122
|
+
if (query.filter !== undefined)
|
|
123
|
+
parameters.filter = JSON.stringify(query.filter);
|
|
124
|
+
if (query.sort !== undefined && query.sort.length > 0) {
|
|
125
|
+
parameters.sort = query.sort
|
|
126
|
+
.map((entry) => (entry.direction === 'desc' ? `-${entry.field}` : entry.field))
|
|
127
|
+
.join(',');
|
|
128
|
+
}
|
|
129
|
+
if (query.after !== undefined)
|
|
130
|
+
parameters.after = query.after;
|
|
131
|
+
if (query.limit !== undefined)
|
|
132
|
+
parameters.limit = String(query.limit);
|
|
133
|
+
if (query.depth !== undefined)
|
|
134
|
+
parameters.depth = String(query.depth);
|
|
135
|
+
return parameters;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function parseJson(text) {
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(text);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function errorFrom(body) {
|
|
147
|
+
if (typeof body !== 'object' || body === null)
|
|
148
|
+
return undefined;
|
|
149
|
+
const error = body.error;
|
|
150
|
+
if (typeof error !== 'object' || error === null)
|
|
151
|
+
return undefined;
|
|
152
|
+
const message = error.message;
|
|
153
|
+
return typeof message === 'string' ? message : undefined;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/content/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes a theme sees on the wire.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than imported from `@cogenta/schema`, and that is the
|
|
5
|
+
* whole point of ADR-0016: the delivery plane must not link against the
|
|
6
|
+
* content engine, because a type import is one refactor away from a value
|
|
7
|
+
* import, and a value import puts the database in the process that runs
|
|
8
|
+
* third-party theme code. What crosses the boundary is JSON over HTTP, so what
|
|
9
|
+
* is declared here is JSON — structurally the same as the engine's entries,
|
|
10
|
+
* deliberately not the same declaration.
|
|
11
|
+
*
|
|
12
|
+
* `MediaAsset` is the one exception, and it stays inside the delivery plane:
|
|
13
|
+
* the image pipeline lives here too, so this is not a link to the engine.
|
|
14
|
+
*/
|
|
15
|
+
import type { MediaAsset } from '../images/types.js';
|
|
16
|
+
export type ContentValues = Readonly<Record<string, unknown>>;
|
|
17
|
+
export interface ContentBlock {
|
|
18
|
+
/** Contract B's `_key`: stable across edits, reorders and translations. */
|
|
19
|
+
readonly key: string;
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
22
|
+
}
|
|
23
|
+
export type BlockZones = Readonly<Record<string, readonly ContentBlock[]>>;
|
|
24
|
+
export interface ContentEntry<TValues extends ContentValues = ContentValues> {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly locale: string;
|
|
27
|
+
readonly status: string;
|
|
28
|
+
readonly publishedAt: string | null;
|
|
29
|
+
readonly createdAt: string;
|
|
30
|
+
readonly updatedAt: string;
|
|
31
|
+
readonly translationOf: string | null;
|
|
32
|
+
readonly version: number;
|
|
33
|
+
readonly values: TValues;
|
|
34
|
+
readonly blocks: BlockZones;
|
|
35
|
+
}
|
|
36
|
+
export type FilterOperator = 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte' | 'in' | 'contains' | 'exists';
|
|
37
|
+
export interface FieldCondition {
|
|
38
|
+
readonly field: string;
|
|
39
|
+
readonly operator: FilterOperator;
|
|
40
|
+
readonly value: unknown;
|
|
41
|
+
}
|
|
42
|
+
export type Filter = FieldCondition | {
|
|
43
|
+
readonly and: readonly Filter[];
|
|
44
|
+
} | {
|
|
45
|
+
readonly or: readonly Filter[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The query vocabulary a theme has, and the whole of it (ADR-0016's assumed
|
|
49
|
+
* renunciation): no joins, no hand-tuned queries. A theme that needs more needs
|
|
50
|
+
* a plugin, which is exactly the boundary the decision wanted.
|
|
51
|
+
*/
|
|
52
|
+
export interface QueryRequest {
|
|
53
|
+
readonly collection: string;
|
|
54
|
+
readonly locale?: string | undefined;
|
|
55
|
+
readonly filter?: Filter | undefined;
|
|
56
|
+
readonly sort?: readonly {
|
|
57
|
+
readonly field: string;
|
|
58
|
+
readonly direction: 'asc' | 'desc';
|
|
59
|
+
}[];
|
|
60
|
+
readonly after?: string | undefined;
|
|
61
|
+
readonly limit?: number | undefined;
|
|
62
|
+
readonly depth?: number | undefined;
|
|
63
|
+
}
|
|
64
|
+
export interface Page<T> {
|
|
65
|
+
readonly items: readonly T[];
|
|
66
|
+
readonly nextCursor: string | null;
|
|
67
|
+
readonly hasMore: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** Contract D's `ctx.content`: the only door to data a theme has. */
|
|
70
|
+
export interface ContentClient {
|
|
71
|
+
entry(collection: string, id: string): Promise<ContentEntry | null>;
|
|
72
|
+
byPath(path: string): Promise<ContentEntry | null>;
|
|
73
|
+
list(request: QueryRequest): Promise<Page<ContentEntry>>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* What a response was actually built from, entries a server-side relation
|
|
77
|
+
* expansion inlined included.
|
|
78
|
+
*
|
|
79
|
+
* A render cache keyed on tags can only invalidate what it knows a page read,
|
|
80
|
+
* and a page only asks for the entry it names directly — an article's response
|
|
81
|
+
* carries its author inlined by `depth`, and the author's id never crosses this
|
|
82
|
+
* client as a request of its own. Without this, publishing a new author name
|
|
83
|
+
* leaves the article page stale with no symptom at all. `@cogenta/api` derives
|
|
84
|
+
* this from the serialised payload and sends it back on every read; declared
|
|
85
|
+
* again here, structurally, for the same reason every other wire type is
|
|
86
|
+
* (ADR-0016) — not imported from the package that computed it.
|
|
87
|
+
*/
|
|
88
|
+
export interface ResponseDependencies {
|
|
89
|
+
readonly entries: readonly string[];
|
|
90
|
+
readonly media: readonly string[];
|
|
91
|
+
readonly collections: readonly string[];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A media entity as a theme receives it.
|
|
95
|
+
*
|
|
96
|
+
* `kind` and `poster` are not decoration: `hero.media` and
|
|
97
|
+
* `mediaFigure.media` accept an image **or** a video (contract B), and without
|
|
98
|
+
* them `ctx.image()` cannot say which it returned — every video renders as a
|
|
99
|
+
* broken `<img>`. Contract D names `MediaReference` without defining it; this
|
|
100
|
+
* is the definition, and it is the same shape the image pipeline consumes so
|
|
101
|
+
* that one concept has one type.
|
|
102
|
+
*/
|
|
103
|
+
export type MediaReference = MediaAsset;
|
|
104
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/content/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAE7D,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACjD;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC,CAAA;AAE1E,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,aAAa,GAAG,aAAa;IACzE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAC5B;AAED,MAAM,MAAM,cAAc,GACtB,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,UAAU,GACV,QAAQ,CAAA;AAEZ,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,MAAM,MAAM,GACd,cAAc,GACd;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACnC;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAA;AAEtC;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,EAAE,CAAA;IACzF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAED,MAAM,WAAW,IAAI,CAAC,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAA;IACnE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAA;IAClD,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes a theme sees on the wire.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than imported from `@cogenta/schema`, and that is the
|
|
5
|
+
* whole point of ADR-0016: the delivery plane must not link against the
|
|
6
|
+
* content engine, because a type import is one refactor away from a value
|
|
7
|
+
* import, and a value import puts the database in the process that runs
|
|
8
|
+
* third-party theme code. What crosses the boundary is JSON over HTTP, so what
|
|
9
|
+
* is declared here is JSON — structurally the same as the engine's entries,
|
|
10
|
+
* deliberately not the same declaration.
|
|
11
|
+
*
|
|
12
|
+
* `MediaAsset` is the one exception, and it stays inside the delivery plane:
|
|
13
|
+
* the image pipeline lives here too, so this is not a link to the engine.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/content/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SiteConfig } from '../config.js';
|
|
2
|
+
import type { ContentClient } from '../content/types.js';
|
|
3
|
+
import type { RenderContext } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Builds the object a theme receives, and nothing the theme did not ask for.
|
|
6
|
+
*
|
|
7
|
+
* Every capability is a function the host supplies. That is what keeps the
|
|
8
|
+
* context honest: `link` cannot read the routing table because it is handed a
|
|
9
|
+
* resolver, and `image` cannot open a file because it only ever builds a URL.
|
|
10
|
+
*/
|
|
11
|
+
/** Messages per locale, then per key. Flat keys: `nav.home`, not nested objects. */
|
|
12
|
+
export type Messages = Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
13
|
+
export interface RenderContextOptions {
|
|
14
|
+
readonly site: SiteConfig;
|
|
15
|
+
readonly locale: string;
|
|
16
|
+
readonly url: URL | string;
|
|
17
|
+
readonly content: ContentClient;
|
|
18
|
+
readonly messages?: Messages | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Path of an entry, without the locale prefix, or null when the entry has no
|
|
21
|
+
* route. Supplied by the routing layer; the theme never sees it.
|
|
22
|
+
*/
|
|
23
|
+
readonly resolveEntryPath?: ((target: {
|
|
24
|
+
collection: string;
|
|
25
|
+
id: string;
|
|
26
|
+
}) => string | null) | undefined;
|
|
27
|
+
/** Where image variants are served from. */
|
|
28
|
+
readonly imageEndpoint?: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
export declare function createRenderContext(options: RenderContextOptions): RenderContext;
|
|
31
|
+
//# sourceMappingURL=render-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-context.d.ts","sourceRoot":"","sources":["../../src/context/render-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,qBAAqB,CAAA;AACxE,OAAO,KAAK,EAAyC,aAAa,EAAE,MAAM,YAAY,CAAA;AAEtF;;;;;;GAMG;AAEH,oFAAoF;AACpF,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;AAEjF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;IACxC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EACtB,CAAC,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,GAAG,IAAI,CAAC,GAC/D,SAAS,CAAA;IACb,4CAA4C;IAC5C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5C;AAMD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA4ChF"}
|