@glw907/cairn-cms 0.60.1 → 0.62.1
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/CHANGELOG.md +69 -0
- package/dist/components/AdminLayout.svelte +22 -0
- package/dist/components/CairnAdmin.svelte +3 -0
- package/dist/components/CairnTidySettings.svelte +2 -2
- package/dist/components/CairnTidySettings.svelte.d.ts +1 -1
- package/dist/components/EditPage.svelte +116 -39
- package/dist/components/HelpHome.svelte +824 -0
- package/dist/components/HelpHome.svelte.d.ts +22 -0
- package/dist/components/MarkdownHelpDialog.svelte +4 -15
- package/dist/components/client-ingest.d.ts +16 -8
- package/dist/components/client-ingest.js +12 -6
- package/dist/components/editor-media.js +16 -8
- package/dist/components/editor-placeholder.d.ts +4 -2
- package/dist/components/editor-tidy.d.ts +24 -12
- package/dist/components/editor-tidy.js +8 -4
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/link-completion.d.ts +12 -6
- package/dist/components/link-completion.js +12 -6
- package/dist/components/markdown-directives.d.ts +9 -6
- package/dist/components/markdown-directives.js +9 -6
- package/dist/components/markdown-format.d.ts +7 -2
- package/dist/components/markdown-format.js +59 -28
- package/dist/components/markdown-reference.d.ts +8 -0
- package/dist/components/markdown-reference.js +22 -0
- package/dist/components/media-upload-outcome.d.ts +12 -6
- package/dist/components/objective-errors.d.ts +8 -4
- package/dist/components/objective-errors.js +8 -4
- package/dist/components/preview-doc.d.ts +4 -2
- package/dist/components/preview-doc.js +4 -2
- package/dist/components/spellcheck.d.ts +55 -29
- package/dist/components/spellcheck.js +39 -21
- package/dist/components/tidy-categorize.d.ts +20 -10
- package/dist/components/tidy-categorize.js +16 -8
- package/dist/components/tidy-validate.d.ts +12 -6
- package/dist/components/tidy-validate.js +20 -10
- package/dist/components/topbar-context.d.ts +4 -2
- package/dist/content/advisories.d.ts +51 -0
- package/dist/content/advisories.js +79 -0
- package/dist/content/compose.d.ts +4 -2
- package/dist/content/compose.js +1 -0
- package/dist/content/excerpt.js +4 -2
- package/dist/content/getting-started.d.ts +18 -0
- package/dist/content/getting-started.js +12 -0
- package/dist/content/links.d.ts +16 -8
- package/dist/content/links.js +12 -6
- package/dist/content/manifest.d.ts +36 -18
- package/dist/content/manifest.js +32 -16
- package/dist/content/media-refs.d.ts +4 -2
- package/dist/content/media-refs.js +4 -2
- package/dist/content/media-rewrite.d.ts +8 -4
- package/dist/content/media-rewrite.js +76 -38
- package/dist/content/schema.d.ts +20 -10
- package/dist/content/site-dictionary.d.ts +4 -2
- package/dist/content/site-dictionary.js +8 -4
- package/dist/content/types.d.ts +97 -42
- package/dist/delivery/content-index.d.ts +16 -8
- package/dist/delivery/feeds.js +4 -2
- package/dist/delivery/json-ld.d.ts +3 -0
- package/dist/delivery/json-ld.js +3 -0
- package/dist/delivery/manifest.d.ts +4 -2
- package/dist/delivery/manifest.js +4 -2
- package/dist/delivery/public-routes.d.ts +12 -6
- package/dist/delivery/public-routes.js +4 -2
- package/dist/delivery/seo-fields.d.ts +12 -6
- package/dist/delivery/seo-fields.js +8 -4
- package/dist/delivery/site-indexes.d.ts +4 -2
- package/dist/delivery/site-resolver.d.ts +4 -2
- package/dist/delivery/site-resolver.js +4 -2
- package/dist/doctor/cloudflare-api.d.ts +6 -0
- package/dist/doctor/cloudflare-api.js +6 -0
- package/dist/doctor/index.d.ts +12 -6
- package/dist/doctor/report.d.ts +3 -0
- package/dist/doctor/report.js +3 -0
- package/dist/doctor/run.d.ts +3 -0
- package/dist/doctor/run.js +3 -0
- package/dist/doctor/types.d.ts +10 -2
- package/dist/doctor/types.js +6 -0
- package/dist/doctor/wrangler-config.d.ts +7 -2
- package/dist/doctor/wrangler-config.js +3 -0
- package/dist/email.d.ts +4 -2
- package/dist/env.d.ts +0 -3
- package/dist/env.js +0 -3
- package/dist/github/branches.d.ts +4 -2
- package/dist/github/branches.js +4 -2
- package/dist/github/signing.d.ts +1 -1
- package/dist/github/signing.js +2 -2
- package/dist/log/events.d.ts +1 -1
- package/dist/media/bulk-delete-plan.d.ts +8 -4
- package/dist/media/config.d.ts +12 -6
- package/dist/media/config.js +16 -8
- package/dist/media/delivery-bucket.d.ts +4 -2
- package/dist/media/library-entry.d.ts +4 -2
- package/dist/media/library-entry.js +4 -2
- package/dist/media/manifest.d.ts +29 -15
- package/dist/media/manifest.js +29 -16
- package/dist/media/naming.d.ts +12 -6
- package/dist/media/naming.js +24 -12
- package/dist/media/orphan-scan.d.ts +4 -2
- package/dist/media/reconcile.d.ts +21 -11
- package/dist/media/reconcile.js +12 -6
- package/dist/media/reference.d.ts +8 -4
- package/dist/media/reference.js +12 -6
- package/dist/media/rewrite-plan.d.ts +12 -6
- package/dist/media/sniff.d.ts +4 -2
- package/dist/media/sniff.js +28 -14
- package/dist/media/store.d.ts +16 -8
- package/dist/media/store.js +4 -2
- package/dist/media/transform-url.d.ts +12 -6
- package/dist/media/transform-url.js +8 -4
- package/dist/media/usage.d.ts +8 -4
- package/dist/nav/site-config.d.ts +16 -8
- package/dist/render/component-grammar.d.ts +23 -10
- package/dist/render/component-grammar.js +19 -8
- package/dist/render/component-insert.d.ts +8 -4
- package/dist/render/component-insert.js +4 -2
- package/dist/render/component-reference.d.ts +4 -2
- package/dist/render/component-reference.js +4 -2
- package/dist/render/component-validate.d.ts +3 -0
- package/dist/render/component-validate.js +3 -0
- package/dist/render/glyph.d.ts +4 -2
- package/dist/render/glyph.js +4 -2
- package/dist/render/pipeline.d.ts +20 -10
- package/dist/render/pipeline.js +4 -2
- package/dist/render/registry.d.ts +40 -20
- package/dist/render/registry.js +16 -8
- package/dist/render/rehype-dispatch.d.ts +22 -8
- package/dist/render/rehype-dispatch.js +22 -8
- package/dist/render/remark-directives.d.ts +3 -0
- package/dist/render/remark-directives.js +3 -0
- package/dist/render/remark-figure.d.ts +4 -2
- package/dist/render/remark-figure.js +4 -2
- package/dist/render/resolve-links.d.ts +4 -2
- package/dist/render/resolve-links.js +4 -2
- package/dist/render/resolve-media.d.ts +16 -8
- package/dist/render/resolve-media.js +12 -6
- package/dist/sveltekit/admin-dispatch.d.ts +2 -0
- package/dist/sveltekit/admin-dispatch.js +9 -3
- package/dist/sveltekit/auth-routes.d.ts +3 -0
- package/dist/sveltekit/auth-routes.js +3 -0
- package/dist/sveltekit/cairn-admin.d.ts +16 -5
- package/dist/sveltekit/cairn-admin.js +26 -10
- package/dist/sveltekit/content-routes.d.ts +191 -86
- package/dist/sveltekit/content-routes.js +295 -107
- package/dist/sveltekit/editors-routes.d.ts +3 -0
- package/dist/sveltekit/editors-routes.js +3 -0
- package/dist/sveltekit/guard.d.ts +4 -2
- package/dist/sveltekit/guard.js +4 -2
- package/dist/sveltekit/https-required-page.d.ts +1 -1
- package/dist/sveltekit/https-required-page.js +1 -1
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/media-route.d.ts +1 -2
- package/dist/sveltekit/media-route.js +13 -8
- package/dist/sveltekit/nav-routes.d.ts +7 -2
- package/dist/sveltekit/nav-routes.js +3 -0
- package/dist/sveltekit/types.d.ts +4 -2
- package/dist/vite/index.d.ts +32 -16
- package/dist/vite/index.js +52 -26
- package/dist/vite/resolve-root.d.ts +8 -4
- package/dist/vite/resolve-root.js +4 -2
- package/package.json +7 -1
- package/src/lib/components/AdminLayout.svelte +22 -0
- package/src/lib/components/CairnAdmin.svelte +3 -0
- package/src/lib/components/CairnTidySettings.svelte +2 -2
- package/src/lib/components/ComponentForm.svelte +0 -1
- package/src/lib/components/EditPage.svelte +133 -41
- package/src/lib/components/HelpHome.svelte +850 -0
- package/src/lib/components/MarkdownHelpDialog.svelte +4 -15
- package/src/lib/components/client-ingest.ts +20 -10
- package/src/lib/components/editor-media.ts +20 -10
- package/src/lib/components/editor-placeholder.ts +12 -6
- package/src/lib/components/editor-tidy.ts +28 -14
- package/src/lib/components/index.ts +1 -0
- package/src/lib/components/link-completion.ts +12 -6
- package/src/lib/components/markdown-directives.ts +13 -8
- package/src/lib/components/markdown-format.ts +63 -30
- package/src/lib/components/markdown-reference.ts +30 -0
- package/src/lib/components/media-upload-outcome.ts +12 -6
- package/src/lib/components/objective-errors.ts +16 -8
- package/src/lib/components/preview-doc.ts +4 -2
- package/src/lib/components/spellcheck.ts +79 -41
- package/src/lib/components/tidy-categorize.ts +28 -14
- package/src/lib/components/tidy-validate.ts +28 -14
- package/src/lib/components/topbar-context.ts +4 -2
- package/src/lib/content/advisories.ts +141 -0
- package/src/lib/content/compose.ts +5 -2
- package/src/lib/content/excerpt.ts +4 -2
- package/src/lib/content/getting-started.ts +31 -0
- package/src/lib/content/links.ts +16 -8
- package/src/lib/content/manifest.ts +36 -18
- package/src/lib/content/media-refs.ts +4 -2
- package/src/lib/content/media-rewrite.ts +100 -50
- package/src/lib/content/schema.ts +20 -10
- package/src/lib/content/site-dictionary.ts +8 -4
- package/src/lib/content/types.ts +97 -42
- package/src/lib/delivery/content-index.ts +16 -8
- package/src/lib/delivery/feeds.ts +4 -2
- package/src/lib/delivery/json-ld.ts +3 -0
- package/src/lib/delivery/manifest.ts +4 -2
- package/src/lib/delivery/public-routes.ts +16 -8
- package/src/lib/delivery/seo-fields.ts +12 -6
- package/src/lib/delivery/site-indexes.ts +4 -2
- package/src/lib/delivery/site-resolver.ts +4 -2
- package/src/lib/doctor/cloudflare-api.ts +6 -0
- package/src/lib/doctor/index.ts +12 -6
- package/src/lib/doctor/report.ts +3 -0
- package/src/lib/doctor/run.ts +3 -0
- package/src/lib/doctor/types.ts +10 -2
- package/src/lib/doctor/wrangler-config.ts +7 -2
- package/src/lib/email.ts +4 -2
- package/src/lib/env.ts +0 -3
- package/src/lib/github/branches.ts +4 -2
- package/src/lib/github/signing.ts +2 -2
- package/src/lib/log/events.ts +1 -0
- package/src/lib/media/bulk-delete-plan.ts +8 -4
- package/src/lib/media/config.ts +24 -12
- package/src/lib/media/delivery-bucket.ts +4 -2
- package/src/lib/media/library-entry.ts +4 -2
- package/src/lib/media/manifest.ts +33 -18
- package/src/lib/media/naming.ts +24 -12
- package/src/lib/media/orphan-scan.ts +4 -2
- package/src/lib/media/reconcile.ts +21 -11
- package/src/lib/media/reference.ts +12 -6
- package/src/lib/media/rewrite-plan.ts +12 -6
- package/src/lib/media/sniff.ts +28 -14
- package/src/lib/media/store.ts +16 -8
- package/src/lib/media/transform-url.ts +12 -6
- package/src/lib/media/usage.ts +8 -4
- package/src/lib/nav/site-config.ts +16 -8
- package/src/lib/render/component-grammar.ts +23 -10
- package/src/lib/render/component-insert.ts +8 -4
- package/src/lib/render/component-reference.ts +4 -2
- package/src/lib/render/component-validate.ts +3 -0
- package/src/lib/render/glyph.ts +4 -2
- package/src/lib/render/pipeline.ts +20 -10
- package/src/lib/render/registry.ts +44 -22
- package/src/lib/render/rehype-dispatch.ts +22 -8
- package/src/lib/render/remark-directives.ts +3 -0
- package/src/lib/render/remark-figure.ts +4 -2
- package/src/lib/render/resolve-links.ts +4 -2
- package/src/lib/render/resolve-media.ts +16 -8
- package/src/lib/sveltekit/admin-dispatch.ts +10 -4
- package/src/lib/sveltekit/auth-routes.ts +3 -0
- package/src/lib/sveltekit/cairn-admin.ts +37 -15
- package/src/lib/sveltekit/content-routes.ts +492 -197
- package/src/lib/sveltekit/editors-routes.ts +3 -0
- package/src/lib/sveltekit/guard.ts +4 -2
- package/src/lib/sveltekit/https-required-page.ts +1 -1
- package/src/lib/sveltekit/index.ts +3 -0
- package/src/lib/sveltekit/media-route.ts +13 -8
- package/src/lib/sveltekit/nav-routes.ts +7 -2
- package/src/lib/sveltekit/types.ts +4 -2
- package/src/lib/vite/index.ts +60 -30
- package/src/lib/vite/resolve-root.ts +8 -4
package/src/lib/content/types.ts
CHANGED
|
@@ -22,6 +22,11 @@ interface FieldBase {
|
|
|
22
22
|
label: string;
|
|
23
23
|
/** A required field fails validation when empty (spec §7.4). */
|
|
24
24
|
required?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* One author-facing sentence shown under the field in the editor, in plain end-user language.
|
|
27
|
+
* Optional; render nothing when absent. Not a validation rule.
|
|
28
|
+
*/
|
|
29
|
+
description?: string;
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
/** A single-line text input. */
|
|
@@ -33,8 +38,10 @@ export interface TextField extends FieldBase {
|
|
|
33
38
|
max?: number;
|
|
34
39
|
/** Exact required character length. */
|
|
35
40
|
length?: number;
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
41
|
+
/**
|
|
42
|
+
* A regular-expression source string the value must match. Stored as a string so the field
|
|
43
|
+
* list stays plain serializable data; the validator compiles it.
|
|
44
|
+
*/
|
|
38
45
|
pattern?: string;
|
|
39
46
|
}
|
|
40
47
|
/** A multi-line text input. */
|
|
@@ -103,8 +110,10 @@ export type FrontmatterField =
|
|
|
103
110
|
| FreeTagsField
|
|
104
111
|
| ImageField;
|
|
105
112
|
|
|
106
|
-
/**
|
|
107
|
-
*
|
|
113
|
+
/**
|
|
114
|
+
* The stored value of an `image` field: a `media:` reference, a screen-reader description, and an
|
|
115
|
+
* optional caption.
|
|
116
|
+
*/
|
|
108
117
|
export interface ImageValue {
|
|
109
118
|
src: string;
|
|
110
119
|
alt: string;
|
|
@@ -138,8 +147,10 @@ export interface ConceptConfig<S extends ConceptSchema = ConceptSchema> {
|
|
|
138
147
|
singular?: string;
|
|
139
148
|
/** The concept's schema: the form projection, the generated validator, and the inferred type. */
|
|
140
149
|
schema: S;
|
|
141
|
-
/**
|
|
142
|
-
*
|
|
150
|
+
/**
|
|
151
|
+
* Frontmatter keys to surface on each `ContentSummary.fields`, so a list card reads an authored
|
|
152
|
+
* field without a per-entry detail read. Each key should also be declared in `schema`.
|
|
153
|
+
*/
|
|
143
154
|
summaryFields?: string[];
|
|
144
155
|
}
|
|
145
156
|
|
|
@@ -191,28 +202,38 @@ export interface NavMenuConfig {
|
|
|
191
202
|
* stylesheet.
|
|
192
203
|
*/
|
|
193
204
|
export interface PreviewConfig {
|
|
194
|
-
/**
|
|
195
|
-
*
|
|
205
|
+
/**
|
|
206
|
+
* Absolute or root-relative URLs of the site's compiled stylesheets, linked inside the
|
|
207
|
+
* preview document. A Vite `?url` import of the site's CSS resolves the hashed asset URL.
|
|
208
|
+
*/
|
|
196
209
|
stylesheets: string[];
|
|
197
210
|
/** Class list applied to the preview document's body, for theme or typography roots. */
|
|
198
211
|
bodyClass?: string;
|
|
199
|
-
/**
|
|
200
|
-
*
|
|
212
|
+
/**
|
|
213
|
+
* Class list for a wrapper element around the rendered content, reproducing the site's
|
|
214
|
+
* content container (a prose or measure class). Omitted renders the content bare.
|
|
215
|
+
*/
|
|
201
216
|
containerClass?: string;
|
|
202
|
-
/**
|
|
217
|
+
/**
|
|
218
|
+
* Per-concept overrides of bodyClass and containerClass, keyed by concept id. An entry's
|
|
203
219
|
* preview resolves the override for its concept over the top-level values; stylesheets are
|
|
204
|
-
* always shared.
|
|
220
|
+
* always shared.
|
|
221
|
+
*/
|
|
205
222
|
byConcept?: Record<string, { bodyClass?: string; containerClass?: string }>;
|
|
206
223
|
}
|
|
207
224
|
|
|
208
|
-
/**
|
|
209
|
-
*
|
|
225
|
+
/**
|
|
226
|
+
* The flat preview shape `editLoad` ships to the edit page: the top-level `PreviewConfig`
|
|
227
|
+
* values with the entry's concept override applied, and no `byConcept` map.
|
|
228
|
+
*/
|
|
210
229
|
export type ResolvedPreview = Omit<PreviewConfig, 'byConcept'>;
|
|
211
230
|
|
|
212
|
-
/**
|
|
231
|
+
/**
|
|
232
|
+
* A site's media configuration (seam 4). A site sets this to turn on R2-backed media: uploads,
|
|
213
233
|
* content-addressed storage, and Cloudflare Images variants. Omitting it leaves media off. The
|
|
214
234
|
* engine normalizes this into a `ResolvedAssetConfig` and merges the named variants over the
|
|
215
|
-
* built-in thumb, inline, card, and hero presets.
|
|
235
|
+
* built-in thumb, inline, card, and hero presets.
|
|
236
|
+
*/
|
|
216
237
|
export interface AssetConfig {
|
|
217
238
|
/** The R2 bucket binding name on the Worker, e.g. "MEDIA_BUCKET". Required when a site declares media. */
|
|
218
239
|
bucketBinding: string;
|
|
@@ -226,10 +247,12 @@ export interface AssetConfig {
|
|
|
226
247
|
allowedTypes?: string[];
|
|
227
248
|
/** Named transform presets, merged over the built-in thumb/inline/card/hero presets. */
|
|
228
249
|
variants?: Record<string, VariantSpec>;
|
|
229
|
-
/**
|
|
250
|
+
/**
|
|
251
|
+
* Whether Cloudflare Image Transformations are enabled for the zone (default false). The feature
|
|
230
252
|
* is a per-zone setting that the dashboard or API turns on; it cannot be flipped from a Worker. With
|
|
231
253
|
* it off, the media resolver serves the bare full-size delivery path and ignores any preset, so
|
|
232
|
-
* thumbnails stay correct (full-size-but-correct) rather than pointing at a dead /cdn-cgi/image URL.
|
|
254
|
+
* thumbnails stay correct (full-size-but-correct) rather than pointing at a dead /cdn-cgi/image URL.
|
|
255
|
+
*/
|
|
233
256
|
transformations?: boolean;
|
|
234
257
|
}
|
|
235
258
|
|
|
@@ -246,10 +269,18 @@ export interface CairnAdapter {
|
|
|
246
269
|
};
|
|
247
270
|
backend: BackendConfig;
|
|
248
271
|
sender: SenderConfig;
|
|
249
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* Optional contact a stuck editor is pointed to from the in-admin help (an email address, a URL,
|
|
274
|
+
* or a name and instruction). The help renders the hand-off only when this is set. Plain string,
|
|
275
|
+
* passed through verbatim.
|
|
276
|
+
*/
|
|
277
|
+
supportContact?: string;
|
|
278
|
+
/**
|
|
279
|
+
* The site's one renderer: the editor preview and every public page call it (design decision 4).
|
|
250
280
|
* `resolve` rewrites cairn: links to live permalinks; the build passes a site-resolver-backed
|
|
251
281
|
* one, the preview a manifest one. The trailing `resolveMedia` is additive and optional: the build
|
|
252
|
-
* passes a site-resolver-backed media resolver, the preview a manifest-backed one.
|
|
282
|
+
* passes a site-resolver-backed media resolver, the preview a manifest-backed one.
|
|
283
|
+
*/
|
|
253
284
|
render(
|
|
254
285
|
md: string,
|
|
255
286
|
opts?: {
|
|
@@ -258,24 +289,32 @@ export interface CairnAdapter {
|
|
|
258
289
|
resolveMedia?: import('../render/resolve-media.js').MediaResolve;
|
|
259
290
|
},
|
|
260
291
|
): string | Promise<string>;
|
|
261
|
-
/**
|
|
262
|
-
*
|
|
292
|
+
/**
|
|
293
|
+
* Repo-relative path to the committed content manifest. Defaults to src/content/.cairn/index.json
|
|
294
|
+
* in composeRuntime. It sits outside any concept directory, so content enumeration never globs it.
|
|
295
|
+
*/
|
|
263
296
|
manifestPath?: string;
|
|
264
|
-
/**
|
|
265
|
-
*
|
|
297
|
+
/**
|
|
298
|
+
* Repo-relative path to the committed media manifest. Defaults to src/content/.cairn/media.json,
|
|
299
|
+
* applied in composeRuntime. Sits outside any concept directory, like the content manifest.
|
|
300
|
+
*/
|
|
266
301
|
mediaManifestPath?: string;
|
|
267
|
-
/**
|
|
302
|
+
/**
|
|
303
|
+
* Repo-relative path to the committed personal dictionary file. Defaults to
|
|
268
304
|
* src/content/.cairn/dictionary.txt, applied in composeRuntime: the same `.cairn/` content root the
|
|
269
305
|
* manifests use, so the spec's `content/.cairn/dictionary.txt` resolves the same configurable way the
|
|
270
|
-
* manifest paths do. One word per line, sorted, comment lines allowed (see site-dictionary.ts).
|
|
306
|
+
* manifest paths do. One word per line, sorted, comment lines allowed (see site-dictionary.ts).
|
|
307
|
+
*/
|
|
271
308
|
dictionaryPath?: string;
|
|
272
309
|
/** Directive component registry; the renderer and the future palette derive from it (seam 3). */
|
|
273
310
|
registry?: ComponentRegistry;
|
|
274
311
|
/** The site's glyph name to SVG path-data map, for the admin icon picker and the renderer. */
|
|
275
312
|
icons?: IconSet;
|
|
276
313
|
navMenu?: NavMenuConfig;
|
|
277
|
-
/**
|
|
278
|
-
*
|
|
314
|
+
/**
|
|
315
|
+
* The live site's content styling for the preview frame. The admin's chrome isolation keeps
|
|
316
|
+
* the site's CSS out of the admin document, so the preview frame links these instead.
|
|
317
|
+
*/
|
|
279
318
|
preview?: PreviewConfig;
|
|
280
319
|
assets?: AssetConfig;
|
|
281
320
|
}
|
|
@@ -301,8 +340,10 @@ export interface ConceptDescriptor {
|
|
|
301
340
|
/** Concept id, the key under `content`, e.g. "posts". */
|
|
302
341
|
id: string;
|
|
303
342
|
label: string;
|
|
304
|
-
/**
|
|
305
|
-
*
|
|
343
|
+
/**
|
|
344
|
+
* The singular noun for the create affordances ("New post"); resolved from `ConceptConfig.singular`,
|
|
345
|
+
* defaulting to `label` when the config omits it.
|
|
346
|
+
*/
|
|
306
347
|
singular: string;
|
|
307
348
|
dir: string;
|
|
308
349
|
routing: RoutingRule;
|
|
@@ -311,8 +352,10 @@ export interface ConceptDescriptor {
|
|
|
311
352
|
/** Filename date-prefix granularity for a dated concept; resolved by `normalizeConcepts`. */
|
|
312
353
|
datePrefix: DatePrefix;
|
|
313
354
|
fields: FrontmatterField[];
|
|
314
|
-
/**
|
|
315
|
-
*
|
|
355
|
+
/**
|
|
356
|
+
* Frontmatter keys the index copies onto each summary's `fields` record. `normalizeConcepts`
|
|
357
|
+
* resolves it to `[]` when a concept omits `summaryFields`.
|
|
358
|
+
*/
|
|
316
359
|
summaryFields: string[];
|
|
317
360
|
validate(frontmatter: Record<string, unknown>, body: string): ValidationResult;
|
|
318
361
|
}
|
|
@@ -371,9 +414,13 @@ export interface CairnRuntime {
|
|
|
371
414
|
concepts: ConceptDescriptor[];
|
|
372
415
|
backend: BackendConfig;
|
|
373
416
|
sender: SenderConfig;
|
|
374
|
-
/** The
|
|
417
|
+
/** The support contact passed through from the adapter; the in-admin help reads it. Optional. */
|
|
418
|
+
supportContact?: string;
|
|
419
|
+
/**
|
|
420
|
+
* The site's one renderer: the editor preview and every public page call it (design decision 4).
|
|
375
421
|
* The trailing `resolveMedia` is additive and optional: the build passes a site-resolver-backed
|
|
376
|
-
* media resolver, the preview a manifest-backed one.
|
|
422
|
+
* media resolver, the preview a manifest-backed one.
|
|
423
|
+
*/
|
|
377
424
|
render(
|
|
378
425
|
md: string,
|
|
379
426
|
opts?: {
|
|
@@ -385,15 +432,19 @@ export interface CairnRuntime {
|
|
|
385
432
|
manifestPath: string;
|
|
386
433
|
/** The repo-relative path to the committed media manifest, defaulted in composeRuntime. */
|
|
387
434
|
mediaManifestPath: string;
|
|
388
|
-
/**
|
|
435
|
+
/**
|
|
436
|
+
* The repo-relative path to the committed personal dictionary file (one word per line, sorted),
|
|
389
437
|
* defaulted in composeRuntime to src/content/.cairn/dictionary.txt: the same `.cairn/` content root
|
|
390
438
|
* the manifests use. The edit load reads it and threads its words onto EditData; the
|
|
391
439
|
* addDictionaryWord action reads, merges, and commits it. Optional on the runtime so a hand-built
|
|
392
440
|
* runtime need not set it; composeRuntime always fills it, and the edit load and the action default
|
|
393
|
-
* a missing value to the same content-root path.
|
|
441
|
+
* a missing value to the same content-root path.
|
|
442
|
+
*/
|
|
394
443
|
dictionaryPath?: string;
|
|
395
|
-
/**
|
|
396
|
-
*
|
|
444
|
+
/**
|
|
445
|
+
* The adapter's asset config resolved once at compose: `{ enabled: false }` for a no-media site,
|
|
446
|
+
* otherwise the filled config the upload, storage, delivery, and resolver paths read.
|
|
447
|
+
*/
|
|
397
448
|
resolvedAssets: import('../media/config.js').ResolvedAssetConfig;
|
|
398
449
|
registry?: ComponentRegistry;
|
|
399
450
|
/** The site's glyph name to SVG path-data map, for the admin icon picker and the renderer. */
|
|
@@ -402,18 +453,22 @@ export interface CairnRuntime {
|
|
|
402
453
|
/** The live site's content styling for the preview frame; passed through from the adapter. */
|
|
403
454
|
preview?: PreviewConfig;
|
|
404
455
|
assets?: AssetConfig;
|
|
405
|
-
/**
|
|
456
|
+
/**
|
|
457
|
+
* The editor's spellcheck dictionary file, resolved once at compose from the site config's
|
|
406
458
|
* `spellcheck.dialect` (defaulting to US English). The edit load threads it onto EditData and the
|
|
407
459
|
* editor resolves it to a real asset URL on the main thread, so the Worker receives the URL and
|
|
408
460
|
* never reads config. Just the filename, e.g. "dictionary-en-us.txt". Optional on the runtime so a
|
|
409
461
|
* hand-built runtime need not set it; composeRuntime always fills it, and the edit load defaults a
|
|
410
|
-
* missing value to the US English dictionary.
|
|
462
|
+
* missing value to the US English dictionary.
|
|
463
|
+
*/
|
|
411
464
|
spellcheckDictionary?: string;
|
|
412
|
-
/**
|
|
465
|
+
/**
|
|
466
|
+
* The editor tidy (LLM copy-edit) settings, passed through from the site config. Optional on the
|
|
413
467
|
* runtime so a hand-built runtime need not set it; composeRuntime threads it from
|
|
414
468
|
* `siteConfig.tidy`. The tidy action reads `enabled` and `model` at call time, and builds its prompt
|
|
415
469
|
* from `conventions`. Absent (or `enabled` false) means tidy is off, and the action refuses with a
|
|
416
|
-
* fail(503) before any model call.
|
|
470
|
+
* fail(503) before any model call.
|
|
471
|
+
*/
|
|
417
472
|
tidy?: import('../nav/site-config.js').TidyConfig;
|
|
418
473
|
/** Admin panels contributed by extensions (Mode 2). Empty until Plan 09 wires the dispatch route. */
|
|
419
474
|
adminPanels?: AdminPanel[];
|
|
@@ -15,8 +15,10 @@ export interface RawFile {
|
|
|
15
15
|
|
|
16
16
|
/** The cheap, plain-data view of one entry, for lists, feeds, and the sitemap. */
|
|
17
17
|
export interface ContentSummary {
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
18
|
+
/**
|
|
19
|
+
* The descriptor id this entry belongs to, e.g. "posts". Lets a list or page branch per
|
|
20
|
+
* concept without re-deriving it from a proxy like `entry.date`.
|
|
21
|
+
*/
|
|
20
22
|
concept: string;
|
|
21
23
|
id: string;
|
|
22
24
|
slug: string;
|
|
@@ -24,23 +26,29 @@ export interface ContentSummary {
|
|
|
24
26
|
title: string;
|
|
25
27
|
date?: string;
|
|
26
28
|
updated?: string;
|
|
27
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The entry's tags, always present as an array and empty when the file declares none. This is the
|
|
28
31
|
* read-model normalization. It differs on purpose from the validated `frontmatter.tags`, which the
|
|
29
32
|
* validator omits when empty, so a published file carries no `tags: []` noise. Read `tags` here for
|
|
30
|
-
* a list; read `frontmatter.tags` only when you need the validated, possibly-absent value.
|
|
33
|
+
* a list; read `frontmatter.tags` only when you need the validated, possibly-absent value.
|
|
34
|
+
*/
|
|
31
35
|
tags: string[];
|
|
32
36
|
excerpt: string;
|
|
33
37
|
wordCount: number;
|
|
34
38
|
draft: boolean;
|
|
35
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* The frontmatter keys the descriptor nominated via `summaryFields`, read off the validated,
|
|
36
41
|
* normalized frontmatter. Held in a separate record so a nominated key cannot collide with a
|
|
37
|
-
* typed summary field. Empty when the concept declares no `summaryFields`.
|
|
42
|
+
* typed summary field. Empty when the concept declares no `summaryFields`.
|
|
43
|
+
*/
|
|
38
44
|
fields: Record<string, unknown>;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* The detail view: a summary plus the frontmatter and the body to render. The frontmatter
|
|
42
49
|
* type defaults to `Record<string, unknown>`; the typed-reads pass infers it from the concept
|
|
43
|
-
* fields. Generic now so that change does not break this signature.
|
|
50
|
+
* fields. Generic now so that change does not break this signature.
|
|
51
|
+
*/
|
|
44
52
|
export interface ContentEntry<F = Record<string, unknown>> extends ContentSummary {
|
|
45
53
|
frontmatter: F;
|
|
46
54
|
body: string;
|
|
@@ -30,8 +30,10 @@ function cdataSafe(value: string): string {
|
|
|
30
30
|
return value.replace(/]]>/g, ']]]]><![CDATA[>');
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
33
|
+
/**
|
|
34
|
+
* Parse a YYYY-MM-DD (or ISO) string as a UTC instant. Returns undefined for an absent or
|
|
35
|
+
* unparseable date, so a feed omits the date field rather than emit Invalid Date or throw.
|
|
36
|
+
*/
|
|
35
37
|
function parseFeedDate(date?: string): Date | undefined {
|
|
36
38
|
if (!date) return undefined;
|
|
37
39
|
const at = new Date(`${date.slice(0, 10)}T00:00:00.000Z`);
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
// The line separator U+2028 and paragraph separator U+2029 get the same treatment: they are
|
|
6
6
|
// legal inside a JSON string but unsafe in inline script text, where some parsers read them as
|
|
7
7
|
// line terminators, so an author pasting one into frontmatter would corrupt the JSON-LD block.
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
8
11
|
export function jsonLdScript(data: Record<string, unknown>): string {
|
|
9
12
|
const json = JSON.stringify(data)
|
|
10
13
|
.replace(/</g, '\\u003c')
|
|
@@ -11,8 +11,10 @@ import type { SiteConfig } from '../nav/site-config.js';
|
|
|
11
11
|
import type { CairnAdapter } from '../content/types.js';
|
|
12
12
|
import type { SiteGlobs } from './site-indexes.js';
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
14
|
+
/**
|
|
15
|
+
* Build the whole-corpus manifest from a site's adapter, config, and per-concept globs. Drafts are
|
|
16
|
+
* included and flagged, so the admin picker and the guards see the full graph.
|
|
17
|
+
*/
|
|
16
18
|
export function buildSiteManifest<A extends CairnAdapter>(adapter: A, config: SiteConfig, globs: SiteGlobs<A>): Manifest {
|
|
17
19
|
const globRecord = globs as Record<string, Record<string, string> | undefined>;
|
|
18
20
|
const manifest = emptyManifest();
|
|
@@ -25,12 +25,16 @@ export interface PublicRoutesDeps {
|
|
|
25
25
|
description: string;
|
|
26
26
|
/** Absolute feed URLs for the head's autodiscovery links. */
|
|
27
27
|
feeds?: { rss?: string; json?: string };
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
28
|
+
/**
|
|
29
|
+
* A site-wide default OG image, used when an entry declares none. Resolved to absolute like the
|
|
30
|
+
* canonical URL, so a relative path such as "/og/default.png" works.
|
|
31
|
+
*/
|
|
30
32
|
defaultImage?: string;
|
|
31
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a frontmatter `media:` hero reference to its delivery path. The site builds this from its
|
|
32
35
|
* committed `media.json` exactly as it builds the body resolver (`makeMediaResolver`). When absent,
|
|
33
|
-
* media is off and no `heroImage` projection is derived.
|
|
36
|
+
* media is off and no `heroImage` projection is derived.
|
|
37
|
+
*/
|
|
34
38
|
resolveMedia?: MediaResolve;
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -58,11 +62,13 @@ export interface EntryData {
|
|
|
58
62
|
seo: SeoMeta;
|
|
59
63
|
newer?: ContentSummary;
|
|
60
64
|
older?: ContentSummary;
|
|
61
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* The resolved hero image, a derived projection of the frontmatter `image` field. `url` is the
|
|
62
67
|
* root-relative delivery path for an `<img>`, `absoluteUrl` the origin-anchored form for the
|
|
63
68
|
* og:image, and `alt`/`caption` carry from the stored object. The canonical token is untouched:
|
|
64
69
|
* `entry.frontmatter.image.src` stays the `media:` token. Undefined when no hero is set, media is
|
|
65
|
-
* off, the reference does not parse, or the resolver finds no asset.
|
|
70
|
+
* off, the reference does not parse, or the resolver finds no asset.
|
|
71
|
+
*/
|
|
66
72
|
heroImage?: { url: string; absoluteUrl?: string; alt: string; caption?: string };
|
|
67
73
|
}
|
|
68
74
|
|
|
@@ -70,7 +76,8 @@ export interface EntryData {
|
|
|
70
76
|
export function createPublicRoutes(deps: PublicRoutesDeps) {
|
|
71
77
|
const { site, render, origin, siteName, description, feeds, defaultImage, resolveMedia } = deps;
|
|
72
78
|
|
|
73
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Derive the hero projection from an entry's frontmatter, without mutating it (locked decision 5).
|
|
74
81
|
* The hero lives at the conventional `image` key as the validated nested object `{ src, alt, caption }`;
|
|
75
82
|
* only an image field's validate arm produces an object-with-string-`src` shape, so detecting that
|
|
76
83
|
* structure is enough (a text field stores a string, a tags field an array). Returns undefined when
|
|
@@ -81,7 +88,8 @@ export function createPublicRoutes(deps: PublicRoutesDeps) {
|
|
|
81
88
|
* and renders in the editor, but its delivery resolution is not wired here yet, since the field
|
|
82
89
|
* declarations are not reachable in the delivery read path. Honoring a renamed `seo`-flagged field
|
|
83
90
|
* (and a second image field per concept) at delivery is a carried follow-up; every consumer today
|
|
84
|
-
* uses `image`.
|
|
91
|
+
* uses `image`.
|
|
92
|
+
*/
|
|
85
93
|
function deriveHeroImage(frontmatter: Record<string, unknown>): EntryData['heroImage'] {
|
|
86
94
|
if (!resolveMedia) return undefined;
|
|
87
95
|
const value = frontmatter.image;
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
// typed Record<string, unknown>; this reads the known head fields by name and coerces. Kept apart
|
|
4
4
|
// from seo.ts (the head builder) so reading frontmatter and building the head stay distinct concerns.
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* The head fields a concept can carry in frontmatter. Each is optional and omitted when absent.
|
|
7
8
|
* `author` is article-scoped downstream: the head builder emits `article:author` only for a dated
|
|
8
|
-
* entry, so an `author` on an undated Page is read here but not rendered.
|
|
9
|
+
* entry, so an `author` on an undated Page is read here but not rendered.
|
|
10
|
+
*/
|
|
9
11
|
export interface SeoFields {
|
|
10
12
|
description?: string;
|
|
11
13
|
image?: string;
|
|
@@ -15,11 +17,13 @@ export interface SeoFields {
|
|
|
15
17
|
|
|
16
18
|
const KEYS = ['description', 'image', 'robots', 'author'] as const;
|
|
17
19
|
|
|
18
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Read the known SEO head fields off an entry's normalized frontmatter. Keeps a present string,
|
|
19
22
|
* trimmed, and omits an absent, empty, or non-string value. Trimming the stored value keeps a stray
|
|
20
23
|
* `robots: " noindex "` from reaching the head tag with surrounding whitespace. The field must be
|
|
21
24
|
* declared in the concept's schema to survive the validate-once read; an undeclared key is not on the
|
|
22
|
-
* normalized frontmatter.
|
|
25
|
+
* normalized frontmatter.
|
|
26
|
+
*/
|
|
23
27
|
export function readSeoFields(frontmatter: Record<string, unknown>): SeoFields {
|
|
24
28
|
const fields: SeoFields = {};
|
|
25
29
|
for (const key of KEYS) {
|
|
@@ -29,11 +33,13 @@ export function readSeoFields(frontmatter: Record<string, unknown>): SeoFields {
|
|
|
29
33
|
return fields;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Resolve an author-supplied image path to an absolute URL against the site origin. An absolute or
|
|
33
38
|
* protocol-relative URL passes through; a root-relative path anchors to the origin; a malformed
|
|
34
39
|
* string returns undefined rather than throwing at build. The sites use a bare-domain origin, so a
|
|
35
40
|
* bare path also anchors to the origin root; against a sub-path origin it would resolve relative to
|
|
36
|
-
* that path, per the WHATWG URL rules.
|
|
41
|
+
* that path, per the WHATWG URL rules.
|
|
42
|
+
*/
|
|
37
43
|
export function resolveImageUrl(image: string, origin: string): string | undefined {
|
|
38
44
|
try {
|
|
39
45
|
const url = new URL(image, origin);
|
|
@@ -18,8 +18,10 @@ export type SiteGlobs<A extends CairnAdapter> = {
|
|
|
18
18
|
[K in keyof A['content']]?: Record<string, string>;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
*
|
|
21
|
+
/**
|
|
22
|
+
* The typed per-concept indexes plus the cross-concept `site` resolver. A concept literally named
|
|
23
|
+
* `site` is not supported, since `site` is the reserved resolver key.
|
|
24
|
+
*/
|
|
23
25
|
export type SiteIndexes<A extends CairnAdapter> = {
|
|
24
26
|
[K in keyof A['content']]: ContentIndex<
|
|
25
27
|
NonNullable<A['content'][K]> extends ConceptConfig<infer S> ? Infer<S> : Record<string, unknown>
|
|
@@ -93,8 +93,10 @@ export function createSiteResolver(concepts: ConceptIndex[], opts: { validate?:
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
/**
|
|
97
|
-
*
|
|
96
|
+
/**
|
|
97
|
+
* A resolver backed by the site resolver, for the build. A miss throws, so a dangling cairn: token
|
|
98
|
+
* fails the prerender (the build backstop). The preview uses manifestLinkResolver, which marks.
|
|
99
|
+
*/
|
|
98
100
|
export function buildLinkResolver(site: SiteResolver): LinkResolve {
|
|
99
101
|
return (ref) => {
|
|
100
102
|
const url = site.concept(ref.concept)?.byId(ref.id)?.permalink;
|
|
@@ -17,12 +17,18 @@ export const NO_ACCOUNT: CheckResult = skip(
|
|
|
17
17
|
'set CLOUDFLARE_API_TOKEN, and CLOUDFLARE_ACCOUNT_ID or a wrangler account_id, to run this check'
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
20
23
|
export function cfGet(ctx: DoctorContext, path: string): Promise<Response> {
|
|
21
24
|
return ctx.fetch(`${CF_API}${path}`, {
|
|
22
25
|
headers: { authorization: `Bearer ${ctx.cfToken}` },
|
|
23
26
|
});
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
26
32
|
export function cfPost(ctx: DoctorContext, path: string, body: unknown): Promise<Response> {
|
|
27
33
|
return ctx.fetch(`${CF_API}${path}`, {
|
|
28
34
|
method: 'POST',
|
package/src/lib/doctor/index.ts
CHANGED
|
@@ -25,8 +25,10 @@ export interface DoctorArgs {
|
|
|
25
25
|
from?: string;
|
|
26
26
|
repo?: string;
|
|
27
27
|
sendTest?: string;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
28
|
+
/**
|
|
29
|
+
* The live admin probe: a URL when --probe carried one, true for the bare flag (probe the
|
|
30
|
+
* PUBLIC_ORIGIN input), absent when the flag never appeared (the probe does not run).
|
|
31
|
+
*/
|
|
30
32
|
probe?: string | true;
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -91,12 +93,16 @@ export function contextFromEnv(
|
|
|
91
93
|
};
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* The lazy derivation sources the bin wires up: the adapter read through the consumer's own
|
|
95
98
|
* Vite resolution and the wrangler config's account_id. Each runs only when an input it feeds
|
|
96
|
-
* is still missing, so a doctor run with full flags touches neither.
|
|
99
|
+
* is still missing, so a doctor run with full flags touches neither.
|
|
100
|
+
*/
|
|
97
101
|
export interface DerivationSources {
|
|
98
|
-
/**
|
|
99
|
-
*
|
|
102
|
+
/**
|
|
103
|
+
* Returns `{ owner, repo, from, mediaBucketBinding }` off the adapter, or null when nothing is
|
|
104
|
+
* derivable.
|
|
105
|
+
*/
|
|
100
106
|
adapterFacts: () => Promise<{
|
|
101
107
|
owner?: string;
|
|
102
108
|
repo?: string;
|
package/src/lib/doctor/report.ts
CHANGED
|
@@ -11,6 +11,9 @@ const TAG: Record<CheckResult['status'], string> = {
|
|
|
11
11
|
skip: 'SKIP',
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
14
17
|
export function formatReport(results: { check: DoctorCheck; result: CheckResult }[]): string {
|
|
15
18
|
const lines = results.map(
|
|
16
19
|
({ check, result }) => `${TAG[result.status]} ${check.title}: ${result.detail}`
|
package/src/lib/doctor/run.ts
CHANGED
package/src/lib/doctor/types.ts
CHANGED
|
@@ -14,10 +14,16 @@ export function pass(detail: string): CheckResult {
|
|
|
14
14
|
return { status: 'pass', detail };
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
17
20
|
export function fail(detail: string): CheckResult {
|
|
18
21
|
return { status: 'fail', detail };
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
21
27
|
export function skip(detail: string): CheckResult {
|
|
22
28
|
return { status: 'skip', detail };
|
|
23
29
|
}
|
|
@@ -45,8 +51,10 @@ export interface DoctorContext {
|
|
|
45
51
|
cfAccountId?: string;
|
|
46
52
|
/** PUBLIC_ORIGIN, the env fallback when the wrangler vars carry none. */
|
|
47
53
|
publicOrigin?: string;
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
54
|
+
/**
|
|
55
|
+
* The adapter's media bucket binding (cairn.assets.bucketBinding), derived off the adapter.
|
|
56
|
+
* Undefined when the site declares no media assets; the media-bucket check skips in that case.
|
|
57
|
+
*/
|
|
50
58
|
mediaBucketBinding?: string;
|
|
51
59
|
/** GITHUB_APP_ID / GITHUB_APP_INSTALLATION_ID / GITHUB_APP_PRIVATE_KEY_B64. */
|
|
52
60
|
github?: { appId: string; installationId: string; privateKeyB64: string };
|
|
@@ -16,11 +16,16 @@ export interface WranglerFacts {
|
|
|
16
16
|
publicOrigin?: string;
|
|
17
17
|
/** The top-level account_id, when declared; a fallback for CLOUDFLARE_ACCOUNT_ID. */
|
|
18
18
|
accountId?: string;
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
19
|
+
/**
|
|
20
|
+
* The declared r2_buckets binding names; the conditional media check matches the adapter's
|
|
21
|
+
* bucketBinding against this. Not part of the hard config.bindings check (decision 9).
|
|
22
|
+
*/
|
|
21
23
|
r2Buckets: string[];
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
24
29
|
export async function readWranglerConfig(
|
|
25
30
|
readFile: DoctorContext['readFile']
|
|
26
31
|
): Promise<WranglerFacts | null> {
|
package/src/lib/email.ts
CHANGED
|
@@ -23,9 +23,11 @@ export interface AuthBranding {
|
|
|
23
23
|
replyTo?: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* The injected send. Production uses `cloudflareSend`; tests pass a sink. A thrown error's
|
|
27
28
|
* text reaches the structured log (scrubbed and truncated), so a custom sender must not embed
|
|
28
|
-
* the message body or the magic link in what it throws.
|
|
29
|
+
* the message body or the magic link in what it throws.
|
|
30
|
+
*/
|
|
29
31
|
export type SendMagicLink = (env: AuthEnv, message: MagicLinkMessage) => Promise<void>;
|
|
30
32
|
|
|
31
33
|
/** Build the confirmation email. The link is the only action; the copy stays plain. */
|