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.
Files changed (98) hide show
  1. package/README.md +301 -93
  2. package/dist/adapters/astro/PreviewBoundary.astro +66 -0
  3. package/dist/adapters/astro/RichText.astro +6 -0
  4. package/dist/adapters/astro/index.d.ts +165 -134
  5. package/dist/adapters/astro/index.js +1 -1
  6. package/dist/adapters/astro/index.js.map +1 -1
  7. package/dist/adapters/astro/middleware-entry.d.ts +4 -9
  8. package/dist/adapters/astro/middleware-entry.js +1 -1
  9. package/dist/adapters/astro/middleware-entry.js.map +1 -1
  10. package/dist/adapters/nextjs/index.d.ts +13 -80
  11. package/dist/adapters/nextjs/index.js +1 -1
  12. package/dist/adapters/nextjs/index.js.map +1 -1
  13. package/dist/adapters/nuxt/index.d.ts +46 -106
  14. package/dist/adapters/nuxt/index.js +1 -1
  15. package/dist/adapters/nuxt/index.js.map +1 -1
  16. package/dist/adapters/sveltekit/index.d.ts +10 -75
  17. package/dist/adapters/sveltekit/index.js +1 -1
  18. package/dist/adapters/sveltekit/index.js.map +1 -1
  19. package/dist/client.cjs +2 -0
  20. package/dist/client.cjs.map +1 -0
  21. package/dist/client.d.cts +747 -0
  22. package/dist/client.d.ts +747 -0
  23. package/dist/client.js +2 -0
  24. package/dist/client.js.map +1 -0
  25. package/dist/codegen-astro.d.ts +5 -27
  26. package/dist/codegen-astro.js +1 -1
  27. package/dist/codegen-astro.js.map +1 -1
  28. package/dist/codegen-cli.d.ts +3 -16
  29. package/dist/codegen-cli.js +1 -1
  30. package/dist/codegen-cli.js.map +1 -1
  31. package/dist/codegen.cjs +1 -1
  32. package/dist/codegen.cjs.map +1 -1
  33. package/dist/codegen.d.cts +37 -124
  34. package/dist/codegen.d.ts +37 -124
  35. package/dist/codegen.js +1 -1
  36. package/dist/codegen.js.map +1 -1
  37. package/dist/core.cjs +1 -1
  38. package/dist/core.cjs.map +1 -1
  39. package/dist/core.d.cts +647 -1100
  40. package/dist/core.d.ts +647 -1100
  41. package/dist/core.js +1 -1
  42. package/dist/core.js.map +1 -1
  43. package/dist/doctor-cli.d.ts +3 -28
  44. package/dist/doctor-cli.js +1 -1
  45. package/dist/doctor-cli.js.map +1 -1
  46. package/dist/doctor.d.ts +16 -32
  47. package/dist/doctor.js +1 -1
  48. package/dist/doctor.js.map +1 -1
  49. package/dist/fragment.cjs +2 -0
  50. package/dist/fragment.cjs.map +1 -0
  51. package/dist/fragment.d.cts +333 -0
  52. package/dist/fragment.d.ts +333 -0
  53. package/dist/fragment.js +2 -0
  54. package/dist/fragment.js.map +1 -0
  55. package/dist/index.cjs +1 -1
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +885 -1531
  58. package/dist/index.d.ts +885 -1531
  59. package/dist/index.js +1 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/lexical.cjs +2 -0
  62. package/dist/lexical.cjs.map +1 -0
  63. package/dist/lexical.d.cts +90 -0
  64. package/dist/lexical.d.ts +90 -0
  65. package/dist/lexical.js +2 -0
  66. package/dist/lexical.js.map +1 -0
  67. package/dist/middleware-CEPsY1P7.d.ts +40 -0
  68. package/dist/migrate.d.ts +73 -0
  69. package/dist/migrate.js +2 -0
  70. package/dist/migrate.js.map +1 -0
  71. package/dist/options-CEzzfHJu.d.ts +197 -0
  72. package/dist/payload.cjs +1 -1
  73. package/dist/payload.cjs.map +1 -1
  74. package/dist/payload.d.cts +11 -80
  75. package/dist/payload.d.ts +11 -80
  76. package/dist/payload.js +1 -1
  77. package/dist/payload.js.map +1 -1
  78. package/dist/plugins.cjs +2 -0
  79. package/dist/plugins.cjs.map +1 -0
  80. package/dist/plugins.d.cts +509 -0
  81. package/dist/plugins.d.ts +509 -0
  82. package/dist/plugins.js +2 -0
  83. package/dist/plugins.js.map +1 -0
  84. package/dist/{probe-tMHdim5y.d.ts → probe-CYtvj_Lm.d.ts} +43 -77
  85. package/dist/server.cjs +2 -0
  86. package/dist/server.cjs.map +1 -0
  87. package/dist/server.d.cts +435 -0
  88. package/dist/server.d.ts +435 -0
  89. package/dist/server.js +2 -0
  90. package/dist/server.js.map +1 -0
  91. package/dist/structural.cjs +3 -0
  92. package/dist/structural.cjs.map +1 -0
  93. package/dist/structural.d.cts +243 -0
  94. package/dist/structural.d.ts +243 -0
  95. package/dist/structural.js +3 -0
  96. package/dist/structural.js.map +1 -0
  97. package/package.json +86 -7
  98. 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-DD4Hwomt.js';
2
- export { a as LivePreviewMiddleware, N as NONCE_LOCALS_KEY, c as createLivePreviewMiddleware } from '../../middleware-DD4Hwomt.js';
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 Payload Live Preview.
6
- *
7
- * Drop into `astro.config.mjs`:
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
- * Helpers for embedding the live preview manually in `.astro` templates.
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
- * Server-side preview-intent detection.
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
- /** The individual signals the predicate can consider. */
164
- type PreviewSignal = 'query' | 'fetch-dest' | 'referer';
165
- interface PreviewRequestOptions {
166
- /**
167
- * Which signals count as preview intent. Default: all three.
168
- * Restricting this to `['query']` reduces accidental activation, but
169
- * an explicit `?preview=true` is still client-controlled and must not
170
- * authorize response changes or privileged data access by itself.
171
- */
172
- readonly signals?: readonly PreviewSignal[];
173
- /**
174
- * Query parameters (with values `true` or `1`) that signal preview
175
- * intent. Default: `['preview', 'draft', 'livePreview']`.
176
- */
177
- readonly queryParams?: readonly string[];
178
- /**
179
- * Treat `Sec-Fetch-Dest: iframe` as a preview-intent signal. Default `true`.
180
- * Legacy alias for excluding `'fetch-dest'` from `signals`.
181
- */
182
- readonly checkFetchDest?: boolean;
183
- /**
184
- * Admin origins whose `Referer` signals preview intent, e.g.
185
- * `['https://cms.example.com']`. Referer matching is not HTTP-request
186
- * authentication.
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 minimal request surface the predicate needs. The standard
192
- * `Request` satisfies it structurally, and server frameworks without
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
- interface PreviewRequestLike {
196
- readonly url: string;
197
- readonly headers: {
198
- get(name: string): string | null;
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
- * Detect whether `request` carries live-preview intent. See the module
203
- * docblock for the exact signals and the required authorization
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
- declare function isPreviewRequest(request: PreviewRequestLike, options?: PreviewRequestOptions): boolean;
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, LivePreviewAstroOptions, type PreviewRequestLike, type PreviewRequestOptions, type RenderScriptOptions, isPreviewRequest, livePreview, renderLivePreviewScript };
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 };