payload-live-preview 1.8.0 → 2.0.0-beta.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 +301 -93
- package/dist/adapters/astro/PreviewBoundary.astro +66 -0
- package/dist/adapters/astro/RichText.astro +6 -0
- package/dist/adapters/astro/index.d.ts +165 -134
- package/dist/adapters/astro/index.js +1 -1
- package/dist/adapters/astro/index.js.map +1 -1
- package/dist/adapters/astro/middleware-entry.d.ts +4 -9
- package/dist/adapters/astro/middleware-entry.js +1 -1
- package/dist/adapters/astro/middleware-entry.js.map +1 -1
- package/dist/adapters/nextjs/index.d.ts +13 -80
- package/dist/adapters/nextjs/index.js +1 -1
- package/dist/adapters/nextjs/index.js.map +1 -1
- package/dist/adapters/nuxt/index.d.ts +46 -106
- package/dist/adapters/nuxt/index.js +1 -1
- package/dist/adapters/nuxt/index.js.map +1 -1
- package/dist/adapters/sveltekit/index.d.ts +10 -75
- package/dist/adapters/sveltekit/index.js +1 -1
- package/dist/adapters/sveltekit/index.js.map +1 -1
- package/dist/client.cjs +2 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +747 -0
- package/dist/client.d.ts +747 -0
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -0
- package/dist/codegen-astro.d.ts +5 -27
- package/dist/codegen-astro.js +1 -1
- package/dist/codegen-astro.js.map +1 -1
- package/dist/codegen-cli.d.ts +3 -16
- package/dist/codegen-cli.js +1 -1
- package/dist/codegen-cli.js.map +1 -1
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.cjs.map +1 -1
- package/dist/codegen.d.cts +37 -124
- package/dist/codegen.d.ts +37 -124
- package/dist/codegen.js +1 -1
- package/dist/codegen.js.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +647 -1100
- package/dist/core.d.ts +647 -1100
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/doctor-cli.d.ts +3 -28
- package/dist/doctor-cli.js +1 -1
- package/dist/doctor-cli.js.map +1 -1
- package/dist/doctor.d.ts +16 -32
- package/dist/doctor.js +1 -1
- package/dist/doctor.js.map +1 -1
- package/dist/fragment.cjs +2 -0
- package/dist/fragment.cjs.map +1 -0
- package/dist/fragment.d.cts +333 -0
- package/dist/fragment.d.ts +333 -0
- package/dist/fragment.js +2 -0
- package/dist/fragment.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +885 -1531
- package/dist/index.d.ts +885 -1531
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lexical.cjs +2 -0
- package/dist/lexical.cjs.map +1 -0
- package/dist/lexical.d.cts +90 -0
- package/dist/lexical.d.ts +90 -0
- package/dist/lexical.js +2 -0
- package/dist/lexical.js.map +1 -0
- package/dist/middleware-CEPsY1P7.d.ts +40 -0
- package/dist/migrate.d.ts +73 -0
- package/dist/migrate.js +2 -0
- package/dist/migrate.js.map +1 -0
- package/dist/options-CEzzfHJu.d.ts +197 -0
- package/dist/payload.cjs +1 -1
- package/dist/payload.cjs.map +1 -1
- package/dist/payload.d.cts +11 -80
- package/dist/payload.d.ts +11 -80
- package/dist/payload.js +1 -1
- package/dist/payload.js.map +1 -1
- package/dist/plugins.cjs +2 -0
- package/dist/plugins.cjs.map +1 -0
- package/dist/plugins.d.cts +509 -0
- package/dist/plugins.d.ts +509 -0
- package/dist/plugins.js +2 -0
- package/dist/plugins.js.map +1 -0
- package/dist/{probe-tMHdim5y.d.ts → probe-CYtvj_Lm.d.ts} +43 -77
- package/dist/server.cjs +2 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +435 -0
- package/dist/server.d.ts +435 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/structural.cjs +3 -0
- package/dist/structural.cjs.map +1 -0
- package/dist/structural.d.cts +243 -0
- package/dist/structural.d.ts +243 -0
- package/dist/structural.js +3 -0
- package/dist/structural.js.map +1 -0
- package/package.json +86 -7
- package/dist/middleware-DD4Hwomt.d.ts +0 -189
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* A stable anchor for a field that may be empty.
|
|
4
|
+
*
|
|
5
|
+
* The runtime can only patch elements that exist. A template that renders a
|
|
6
|
+
* binding only when the field is non-empty leaves the editor with nothing to
|
|
7
|
+
* see when they fill a previously empty field. `PreviewBoundary` renders the
|
|
8
|
+
* wrapper always: with content when the value is present, and as an empty,
|
|
9
|
+
* `hidden` element otherwise — out of layout and out of the accessibility
|
|
10
|
+
* tree, so a public visitor and a screen reader see exactly what they would
|
|
11
|
+
* have seen without live preview. When an update fills the field, the
|
|
12
|
+
* runtime removes `hidden`; when it empties it, the runtime hides the
|
|
13
|
+
* wrapper again.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
*
|
|
17
|
+
* ```astro
|
|
18
|
+
* ---
|
|
19
|
+
* import PreviewBoundary from 'payload-live-preview/astro/PreviewBoundary.astro';
|
|
20
|
+
* ---
|
|
21
|
+
* <PreviewBoundary field="subtitle" value={page.subtitle} as="p" class="lede">
|
|
22
|
+
* {page.subtitle}
|
|
23
|
+
* </PreviewBoundary>
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* `data-payload-strategy="patch"` is written explicitly: the wrapper is a
|
|
27
|
+
* patch target, and markup that needs the future fragment strategy says so
|
|
28
|
+
* with a different value.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
interface Props {
|
|
32
|
+
/** Payload field path to bind, e.g. `"subtitle"` or `"hero.caption"`. */
|
|
33
|
+
field: string;
|
|
34
|
+
/** The field's value, used only to decide whether the anchor starts hidden. */
|
|
35
|
+
value: unknown;
|
|
36
|
+
/** Wrapper tag. Default `div`. */
|
|
37
|
+
as?: string;
|
|
38
|
+
/** Renderer to force (`data-payload-type`), e.g. `richText`. */
|
|
39
|
+
type?: string;
|
|
40
|
+
/** Additional attributes are forwarded to the wrapper. */
|
|
41
|
+
[attribute: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { field, value, as = 'div', type, ...rest } = Astro.props as Props;
|
|
45
|
+
|
|
46
|
+
function isEmpty(candidate: unknown): boolean {
|
|
47
|
+
if (candidate === null || candidate === undefined) return true;
|
|
48
|
+
if (typeof candidate === 'string') return candidate.trim().length === 0;
|
|
49
|
+
if (Array.isArray(candidate)) return candidate.length === 0;
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const Tag = as;
|
|
54
|
+
const empty = isEmpty(value);
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
<Tag
|
|
58
|
+
{...rest}
|
|
59
|
+
data-payload-field={field}
|
|
60
|
+
data-payload-type={type}
|
|
61
|
+
data-payload-boundary=""
|
|
62
|
+
data-payload-strategy="patch"
|
|
63
|
+
hidden={empty ? true : undefined}
|
|
64
|
+
>
|
|
65
|
+
<slot />
|
|
66
|
+
</Tag>
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
* imported by your page before this component renders. Registrations
|
|
29
29
|
* are module/realm-local and do not automatically configure the
|
|
30
30
|
* prebuilt inline runtime.
|
|
31
|
+
*
|
|
32
|
+
* Their output is yours to escape here. The built-in renderers escape
|
|
33
|
+
* every value they interpolate, but the sanitizer that would catch a
|
|
34
|
+
* custom renderer's mistake needs a DOM, and there is none during SSR
|
|
35
|
+
* unless the project supplied one with `setSanitizerDocument()`. See
|
|
36
|
+
* docs/security.md §3.
|
|
31
37
|
*/
|
|
32
38
|
// Self-referencing import so the shipped copy in dist/ resolves
|
|
33
39
|
// through the package exports map in consumer projects.
|
|
@@ -1,36 +1,12 @@
|
|
|
1
|
-
import { L as LivePreviewAstroOptions } from '../../middleware-
|
|
2
|
-
export { a as LivePreviewMiddleware,
|
|
1
|
+
import { L as LivePreviewAstroOptions } from '../../middleware-CEPsY1P7.js';
|
|
2
|
+
export { a as LivePreviewMiddleware, c as createLivePreviewMiddleware } from '../../middleware-CEPsY1P7.js';
|
|
3
|
+
import { P as PreviewAuthorizationRequest, A as AuthorizedPreviewScope, a as AuthorizedPreviewContext } from '../../options-CEzzfHJu.js';
|
|
4
|
+
export { b as PreviewAdapterOptions, c as PreviewRequestLike, d as PreviewRequestOptions, h as hasPreviewIntent } from '../../options-CEzzfHJu.js';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
|
-
* Astro integration for
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* import { defineConfig } from 'astro/config';
|
|
11
|
-
* import { livePreview } from 'payload-live-preview/astro';
|
|
12
|
-
*
|
|
13
|
-
* export default defineConfig({
|
|
14
|
-
* integrations: [livePreview({ allowedOrigins: ['https://admin.example.com'] })],
|
|
15
|
-
* });
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* Two injection modes:
|
|
19
|
-
*
|
|
20
|
-
* - **`mode: 'inline'`** (default) — `injectScript('head-inline', …)`
|
|
21
|
-
* bakes the runtime into every page at build time. Right choice
|
|
22
|
-
* for `output: 'static'`, where no middleware runs at request
|
|
23
|
-
* time. The runtime stays inert outside the admin iframe.
|
|
24
|
-
* - **`mode: 'middleware'`** — registers the preview middleware via
|
|
25
|
-
* `addMiddleware()`: the runtime is injected at request time into
|
|
26
|
-
* requests carrying preview intent, and `frame-ancestors` CSP is
|
|
27
|
-
* managed. This is a delivery gate, not authentication. For
|
|
28
|
-
* authorization-gated response changes, register
|
|
29
|
-
* `createLivePreviewMiddleware()` manually after the application's
|
|
30
|
-
* server-side verifier. (`shouldInject` is not supported in this
|
|
31
|
-
* mode: options travel through a serialized virtual module.)
|
|
32
|
-
*
|
|
33
|
-
* @module @adapters/astro/integration
|
|
7
|
+
* The Astro integration for `astro.config.mjs`: `livePreview({ ... })`.
|
|
8
|
+
* Inline and loader modes deliver at build time; middleware mode registers
|
|
9
|
+
* the request-time middleware through a serialized options module.
|
|
34
10
|
*/
|
|
35
11
|
|
|
36
12
|
type ScriptStage = 'head-inline' | 'page' | 'before-hydration' | 'page-ssr';
|
|
@@ -41,7 +17,6 @@ interface VitePluginLike {
|
|
|
41
17
|
readonly configureServer?: (server: ViteDevServerLike) => void;
|
|
42
18
|
readonly generateBundle?: (this: RollupEmitContext) => void;
|
|
43
19
|
}
|
|
44
|
-
/** The one Rollup facility this needs: publishing a file into the output. */
|
|
45
20
|
interface RollupEmitContext {
|
|
46
21
|
emitFile: (file: {
|
|
47
22
|
type: 'asset';
|
|
@@ -49,7 +24,6 @@ interface RollupEmitContext {
|
|
|
49
24
|
source: string;
|
|
50
25
|
}) => void;
|
|
51
26
|
}
|
|
52
|
-
/** Just enough of Vite's dev server to serve one file. */
|
|
53
27
|
interface ViteDevServerLike {
|
|
54
28
|
readonly middlewares: {
|
|
55
29
|
use: (handler: (req: DevRequest, res: DevResponse, next: () => void) => void) => void;
|
|
@@ -85,124 +59,181 @@ interface AstroIntegrationLike {
|
|
|
85
59
|
readonly 'astro:config:setup': (ctx: AstroConfigSetupContext) => void;
|
|
86
60
|
};
|
|
87
61
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Build the Astro integration. The injected script auto-detects the
|
|
90
|
-
* browser preview context and stays inert on ordinary top-level pages.
|
|
91
|
-
* Browser-context detection does not authorize HTTP response changes.
|
|
92
|
-
*/
|
|
62
|
+
/** Build the integration. The injected runtime stays inert outside the admin's preview iframe. */
|
|
93
63
|
declare function livePreview(options?: LivePreviewAstroOptions): AstroIntegrationLike;
|
|
94
64
|
|
|
65
|
+
/** What a decision publishes for templates on `locals` (Astro, SvelteKit) or `event.context` (Nuxt). */
|
|
66
|
+
|
|
67
|
+
/** The request-scoped nonce, for templates that nonce their own scripts. */
|
|
68
|
+
declare const NONCE_LOCALS_KEY = "livePreviewNonce";
|
|
69
|
+
/** The verified `AuthorizedPreviewContext`; absent unless `authorizePreview` authorized. */
|
|
70
|
+
declare const AUTHORIZATION_LOCALS_KEY = "livePreviewAuthorization";
|
|
71
|
+
/** The hook's `PreviewAuthorizationOutcome`; absent when no hook ran. */
|
|
72
|
+
declare const AUTHORIZATION_OUTCOME_LOCALS_KEY = "livePreviewAuthorizationOutcome";
|
|
73
|
+
|
|
95
74
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* Most consumers should prefer the `livePreview()` integration which
|
|
99
|
-
* auto-injects the script. This module exists for advanced cases where
|
|
100
|
-
* the script needs to live inside a specific layout or behind a
|
|
101
|
-
* conditional.
|
|
102
|
-
*
|
|
103
|
-
* Usage in a `.astro` file:
|
|
104
|
-
*
|
|
105
|
-
* ```astro
|
|
106
|
-
* ---
|
|
107
|
-
* import { renderLivePreviewScript } from 'payload-live-preview/astro';
|
|
108
|
-
* const script = renderLivePreviewScript({
|
|
109
|
-
* allowedOrigins: ['https://admin.example.com'],
|
|
110
|
-
* nonce: Astro.locals.livePreviewNonce,
|
|
111
|
-
* });
|
|
112
|
-
* ---
|
|
113
|
-
* <Fragment set:html={script} />
|
|
114
|
-
* ```
|
|
115
|
-
*
|
|
116
|
-
* @module @adapters/astro/component
|
|
75
|
+
* Manual embedding for `.astro` templates, for the cases the integration's
|
|
76
|
+
* automatic injection does not fit (one layout, a conditional).
|
|
117
77
|
*/
|
|
118
78
|
|
|
119
79
|
interface RenderScriptOptions extends LivePreviewAstroOptions {
|
|
120
|
-
/**
|
|
121
|
-
* CSP nonce to set on the `<script>` tag. Read from
|
|
122
|
-
* `Astro.locals.livePreviewNonce` after registering the live-preview
|
|
123
|
-
* middleware.
|
|
124
|
-
*/
|
|
80
|
+
/** CSP nonce for the tag; read it from `Astro.locals.livePreviewNonce`. */
|
|
125
81
|
readonly nonce?: string;
|
|
126
82
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Render the full `<script>` tag (wrapped with attributes) for embedding
|
|
129
|
-
* in a `.astro` layout. The result is a single string suitable for
|
|
130
|
-
* `set:html={…}`.
|
|
131
|
-
*/
|
|
83
|
+
/** The complete `<script>` tag, for `<Fragment set:html={renderLivePreviewScript(...)} />`. */
|
|
132
84
|
declare function renderLivePreviewScript(options?: RenderScriptOptions): string;
|
|
133
85
|
|
|
134
86
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* The live-preview runtime only ever activates inside the Payload
|
|
138
|
-
* admin's iframe, but the *server* still has to decide whether a
|
|
139
|
-
* request expresses preview intent before doing optional preview
|
|
140
|
-
* work. Adapters use this predicate as a delivery optimisation, and
|
|
141
|
-
* consumers with hand-rolled middleware can import it directly.
|
|
142
|
-
*
|
|
143
|
-
* IMPORTANT: every signal inspected here is controlled or triggerable
|
|
144
|
-
* by the client. A positive result is never proof of identity,
|
|
145
|
-
* authentication, or permission to read drafts. Before forwarding
|
|
146
|
-
* credentials, fetching draft data, bypassing caches, changing CSP,
|
|
147
|
-
* or injecting the runtime, verify the request with an application-
|
|
148
|
-
* owned server session or a short-lived signed authorization. Use the
|
|
149
|
-
* same verified decision for all of those effects.
|
|
150
|
-
*
|
|
151
|
-
* Preview intent is present when any of these hold:
|
|
152
|
-
*
|
|
153
|
-
* 1. A preview query parameter is present (`?preview=true`,
|
|
154
|
-
* `?draft=true`, `?livePreview=true` — configurable).
|
|
155
|
-
* 2. `Sec-Fetch-Dest: iframe` — the document is being loaded as an
|
|
156
|
-
* iframe, which is exactly how the Payload admin embeds it.
|
|
157
|
-
* (Sent by all evergreen browsers; absence never *excludes* a
|
|
158
|
-
* request, presence includes it.)
|
|
159
|
-
* 3. The `Referer` points at one of the given admin origins.
|
|
160
|
-
*
|
|
161
|
-
* @module @adapters/shared/preview-request
|
|
87
|
+
* The `payload-session` strategy: forward exactly one named cookie to
|
|
88
|
+
* `GET <serverURL>/api/<usersSlug>/me` and authorize when a user comes back.
|
|
162
89
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
readonly
|
|
183
|
-
/**
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
readonly adminOrigins?: readonly string[];
|
|
90
|
+
|
|
91
|
+
/** A `fetch`-compatible function, injectable for tests. */
|
|
92
|
+
type FetchLike = (input: string, init: {
|
|
93
|
+
readonly headers: Record<string, string>;
|
|
94
|
+
readonly signal: AbortSignal;
|
|
95
|
+
}) => Promise<{
|
|
96
|
+
readonly ok: boolean;
|
|
97
|
+
readonly status: number;
|
|
98
|
+
json(): Promise<unknown>;
|
|
99
|
+
}>;
|
|
100
|
+
interface PayloadSessionStrategy {
|
|
101
|
+
readonly type: 'payload-session';
|
|
102
|
+
/** Payload server origin, e.g. `https://cms.example.com`. */
|
|
103
|
+
readonly serverURL: string;
|
|
104
|
+
/** Auth collection slug; `users` unless the project renamed it. */
|
|
105
|
+
readonly usersSlug?: string;
|
|
106
|
+
/** Cookie name; Payload's default is `payload-token`. */
|
|
107
|
+
readonly cookieName?: string;
|
|
108
|
+
/** Upper bound for the `/me` round trip. Below 250 ms is raised to 250 ms; default 3000. */
|
|
109
|
+
readonly timeoutMs?: number;
|
|
110
|
+
/** Longest cookie value accepted; longer ones are refused as `invalid`. Default 4096. */
|
|
111
|
+
readonly maxCookieLength?: number;
|
|
112
|
+
readonly fetch?: FetchLike;
|
|
113
|
+
/** Clock, Unix milliseconds. Injectable for tests. */
|
|
114
|
+
readonly now?: () => number;
|
|
189
115
|
}
|
|
116
|
+
|
|
190
117
|
/**
|
|
191
|
-
* The
|
|
192
|
-
*
|
|
193
|
-
* fetch-style requests (e.g. Nitro/H3) can supply a tiny shim.
|
|
118
|
+
* The `signed-token` strategy: a short-lived HMAC-SHA256 token minted by the
|
|
119
|
+
* Payload side and verified by the site. Format and bindings: ADR 0006 §3.
|
|
194
120
|
*/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
121
|
+
|
|
122
|
+
/** The subset of Web Crypto the token strategy needs, injectable for environments that expose it elsewhere. */
|
|
123
|
+
interface SubtleCryptoLike {
|
|
124
|
+
readonly subtle: {
|
|
125
|
+
importKey(format: 'raw', keyData: Uint8Array, algorithm: {
|
|
126
|
+
readonly name: 'HMAC';
|
|
127
|
+
readonly hash: 'SHA-256';
|
|
128
|
+
}, extractable: false, keyUsages: readonly ('sign' | 'verify')[]): Promise<CryptoKey>;
|
|
129
|
+
sign(algorithm: 'HMAC', key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer>;
|
|
130
|
+
verify(algorithm: 'HMAC', key: CryptoKey, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
|
|
199
131
|
};
|
|
132
|
+
getRandomValues<T extends Uint8Array>(array: T): T;
|
|
200
133
|
}
|
|
134
|
+
/** Where a signed token is read from on the request. */
|
|
135
|
+
type PreviewTokenTransport = {
|
|
136
|
+
readonly kind: 'query';
|
|
137
|
+
readonly param?: string;
|
|
138
|
+
} | {
|
|
139
|
+
readonly kind: 'header';
|
|
140
|
+
readonly name?: string;
|
|
141
|
+
};
|
|
201
142
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* boundary. This compatibility name does not imply authentication.
|
|
143
|
+
* Optional replay store. Not shipped: a per-process memory is useless behind
|
|
144
|
+
* a load balancer, so the store is a deployment decision.
|
|
205
145
|
*/
|
|
206
|
-
|
|
146
|
+
interface PreviewTokenReplayStore {
|
|
147
|
+
isUsed(id: string): Promise<boolean> | boolean;
|
|
148
|
+
markUsed(id: string, expiresAt: number): Promise<void> | void;
|
|
149
|
+
}
|
|
150
|
+
interface SignedTokenStrategy {
|
|
151
|
+
readonly type: 'signed-token';
|
|
152
|
+
/** Shared secret, at least 32 bytes; shorter ones are refused on first use. */
|
|
153
|
+
readonly secret: string | Uint8Array;
|
|
154
|
+
/** The site origin tokens must name, e.g. `https://www.example.com`. */
|
|
155
|
+
readonly audience: string;
|
|
156
|
+
/** Purpose string tokens must carry. Default `live-preview`. */
|
|
157
|
+
readonly purpose?: string;
|
|
158
|
+
/** Default: query parameter `previewToken`. */
|
|
159
|
+
readonly transport?: PreviewTokenTransport;
|
|
160
|
+
/** Resolve the request's locale for the `loc` binding. Unset: tokens with `loc` are refused as `wrong-locale`. */
|
|
161
|
+
readonly locale?: (request: PreviewAuthorizationRequest) => string | undefined;
|
|
162
|
+
readonly replay?: PreviewTokenReplayStore;
|
|
163
|
+
readonly crypto?: SubtleCryptoLike;
|
|
164
|
+
readonly now?: () => number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Authorized preview context: the one verdict every privileged preview
|
|
169
|
+
* decision is keyed on. Intent (`?preview=true`, an iframe destination, a
|
|
170
|
+
* referer) is client-chosen; this turns a session, a signed token or the
|
|
171
|
+
* application's own verifier into a branded context. Threat model: ADR 0006.
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/** Claims a consumer verifier returns for a request it accepts. */
|
|
175
|
+
interface PreviewVerifierClaims {
|
|
176
|
+
readonly subject?: string;
|
|
177
|
+
readonly expiresAt?: number;
|
|
178
|
+
readonly scope?: AuthorizedPreviewScope;
|
|
179
|
+
readonly payloadHeaders?: Readonly<Record<string, string>>;
|
|
180
|
+
}
|
|
181
|
+
/** The application's own verification: claims authorize, `null` refuses, a throw is `unavailable`. */
|
|
182
|
+
interface VerifierStrategy {
|
|
183
|
+
readonly type: 'verifier';
|
|
184
|
+
readonly verify: (request: PreviewAuthorizationRequest) => Promise<PreviewVerifierClaims | null> | PreviewVerifierClaims | null;
|
|
185
|
+
readonly now?: () => number;
|
|
186
|
+
}
|
|
187
|
+
type PreviewAuthorizationStrategy = PayloadSessionStrategy | SignedTokenStrategy | VerifierStrategy;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The Astro fragment endpoint (ADR 0011): renders a registered component
|
|
191
|
+
* boundary from unsaved form state for an authorized preview, and nothing
|
|
192
|
+
* else. The browser names a registry id; the server decides what it renders.
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
/** Everything a registry entry may use to compute its props. */
|
|
196
|
+
interface FragmentRenderInput {
|
|
197
|
+
readonly id: string;
|
|
198
|
+
readonly key: string | undefined;
|
|
199
|
+
readonly revision: number;
|
|
200
|
+
readonly fields: Readonly<Record<string, unknown>>;
|
|
201
|
+
readonly locale: string | undefined;
|
|
202
|
+
readonly collectionSlug: string | undefined;
|
|
203
|
+
readonly globalSlug: string | undefined;
|
|
204
|
+
readonly route: string;
|
|
205
|
+
readonly authorization: AuthorizedPreviewContext;
|
|
206
|
+
readonly request: Request;
|
|
207
|
+
}
|
|
208
|
+
/** An Astro component as `import Hero from './Hero.astro'` yields it. */
|
|
209
|
+
type AstroComponentLike = object;
|
|
210
|
+
interface FragmentRegistryEntry<Props extends Record<string, unknown> = Record<string, unknown>> {
|
|
211
|
+
readonly component: AstroComponentLike;
|
|
212
|
+
/** Props for the component, computed from the input; never from request-controlled code. */
|
|
213
|
+
readonly props: (input: FragmentRenderInput) => Props | Promise<Props>;
|
|
214
|
+
}
|
|
215
|
+
type FragmentRegistry = Readonly<Record<string, FragmentRegistryEntry>>;
|
|
216
|
+
/** Renders a component with props to HTML; the default uses Astro's container API. */
|
|
217
|
+
type FragmentRenderer = (component: AstroComponentLike, props: Record<string, unknown>, input: FragmentRenderInput) => Promise<string>;
|
|
218
|
+
interface FragmentEndpointOptions {
|
|
219
|
+
/** The only things this endpoint can render. */
|
|
220
|
+
readonly registry: FragmentRegistry;
|
|
221
|
+
/** How a preview request is authorized; the same strategies as `authorizePreviewRequest()`. */
|
|
222
|
+
readonly authorize: PreviewAuthorizationStrategy;
|
|
223
|
+
/** Override the renderer (tests, other component systems). Default: Astro container. */
|
|
224
|
+
readonly render?: FragmentRenderer;
|
|
225
|
+
/** Origins besides the page's own that may call the endpoint. Default: none. */
|
|
226
|
+
readonly allowedOrigins?: readonly string[];
|
|
227
|
+
readonly limits?: {
|
|
228
|
+
/** Largest request body. Default 64 KiB. */
|
|
229
|
+
readonly bodyBytes?: number;
|
|
230
|
+
/** Render timeout. Default 5000 ms. */
|
|
231
|
+
readonly timeoutMs?: number;
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/** Build the endpoint; export it as the `POST` of a non-prerendered Astro API route. */
|
|
235
|
+
declare function createFragmentEndpoint(options: FragmentEndpointOptions): (context: {
|
|
236
|
+
readonly request: Request;
|
|
237
|
+
}) => Promise<Response>;
|
|
207
238
|
|
|
208
|
-
export { type AstroIntegrationLike,
|
|
239
|
+
export { AUTHORIZATION_LOCALS_KEY, AUTHORIZATION_OUTCOME_LOCALS_KEY, type AstroComponentLike, type AstroIntegrationLike, type FragmentEndpointOptions, type FragmentRegistry, type FragmentRegistryEntry, type FragmentRenderInput, type FragmentRenderer, LivePreviewAstroOptions, NONCE_LOCALS_KEY, type RenderScriptOptions, createFragmentEndpoint, livePreview, renderLivePreviewScript };
|