payload-live-preview 2.0.0-rc.1 → 2.0.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.
Files changed (87) hide show
  1. package/README.md +16 -12
  2. package/dist/adapters/astro/index.d.ts +8 -8
  3. package/dist/adapters/astro/index.js +1 -1
  4. package/dist/adapters/astro/index.js.map +1 -1
  5. package/dist/adapters/astro/middleware-entry.d.ts +3 -3
  6. package/dist/adapters/astro/middleware-entry.js +1 -1
  7. package/dist/adapters/astro/middleware-entry.js.map +1 -1
  8. package/dist/adapters/nextjs/index.d.ts +19 -14
  9. package/dist/adapters/nextjs/index.js +1 -1
  10. package/dist/adapters/nextjs/index.js.map +1 -1
  11. package/dist/adapters/nuxt/index.d.ts +4 -4
  12. package/dist/adapters/nuxt/index.js +1 -1
  13. package/dist/adapters/nuxt/index.js.map +1 -1
  14. package/dist/adapters/nuxt/module.d.ts +1 -1
  15. package/dist/adapters/react/index.d.ts +2 -1
  16. package/dist/adapters/react/index.js.map +1 -1
  17. package/dist/adapters/sveltekit/index.d.ts +5 -5
  18. package/dist/adapters/sveltekit/index.js +1 -1
  19. package/dist/adapters/sveltekit/index.js.map +1 -1
  20. package/dist/adapters/vue/index.js.map +1 -1
  21. package/dist/client.cjs +1 -1
  22. package/dist/client.cjs.map +1 -1
  23. package/dist/client.d.cts +2 -2
  24. package/dist/client.d.ts +2 -2
  25. package/dist/client.js +1 -1
  26. package/dist/client.js.map +1 -1
  27. package/dist/codegen-astro.js +1 -1
  28. package/dist/codegen-astro.js.map +1 -1
  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.js +1 -1
  34. package/dist/codegen.js.map +1 -1
  35. package/dist/core.cjs +1 -1
  36. package/dist/core.cjs.map +1 -1
  37. package/dist/core.d.cts +2 -2
  38. package/dist/core.d.ts +2 -2
  39. package/dist/core.js +1 -1
  40. package/dist/core.js.map +1 -1
  41. package/dist/doctor-cli.d.ts +1 -1
  42. package/dist/doctor-cli.js +1 -1
  43. package/dist/doctor-cli.js.map +1 -1
  44. package/dist/doctor.d.ts +4 -2
  45. package/dist/doctor.js +1 -1
  46. package/dist/doctor.js.map +1 -1
  47. package/dist/{fragment-endpoint-3Mlz7GDz.d.ts → fragment-endpoint-DATKU183.d.ts} +2 -2
  48. package/dist/fragment.cjs.map +1 -1
  49. package/dist/fragment.d.cts +2 -2
  50. package/dist/fragment.d.ts +2 -2
  51. package/dist/fragment.js.map +1 -1
  52. package/dist/index.cjs +1 -1
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +4 -4
  55. package/dist/index.d.ts +4 -4
  56. package/dist/index.js +1 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/lean.cjs +1 -1
  59. package/dist/lean.cjs.map +1 -1
  60. package/dist/lean.js +1 -1
  61. package/dist/lean.js.map +1 -1
  62. package/dist/lexical.cjs +1 -1
  63. package/dist/lexical.cjs.map +1 -1
  64. package/dist/lexical.js +1 -1
  65. package/dist/lexical.js.map +1 -1
  66. package/dist/{locals-DBXDMxOA.d.ts → locals-CNUGYbA_.d.ts} +1 -1
  67. package/dist/{middleware-Bx9I7PXW.d.ts → middleware-CWObDO37.d.ts} +2 -2
  68. package/dist/migrate.d.ts +6 -0
  69. package/dist/migrate.js +1 -1
  70. package/dist/migrate.js.map +1 -1
  71. package/dist/{options-BW1eqXvc.d.ts → options-uHKrDM2U.d.ts} +2 -1
  72. package/dist/plugins.cjs +1 -1
  73. package/dist/plugins.cjs.map +1 -1
  74. package/dist/plugins.d.cts +2 -2
  75. package/dist/plugins.d.ts +2 -2
  76. package/dist/plugins.js +1 -1
  77. package/dist/plugins.js.map +1 -1
  78. package/dist/{probe-5ZLRBSmh.d.ts → probe-wmvfVEsI.d.ts} +16 -2
  79. package/dist/server.cjs.map +1 -1
  80. package/dist/server.d.cts +1 -1
  81. package/dist/server.d.ts +1 -1
  82. package/dist/server.js.map +1 -1
  83. package/dist/structural.cjs +2 -2
  84. package/dist/structural.cjs.map +1 -1
  85. package/dist/structural.js +2 -2
  86. package/dist/structural.js.map +1 -1
  87. package/package.json +6 -3
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  > **Live preview for Payload CMS in Astro** — and any other server-rendered or static frontend (SvelteKit, Nuxt, Next.js, plain HTML).
10
10
 
11
- **The missing piece for Astro + Payload.** The official live-preview packages are React and Vue hooks: they re-render a hydrated component tree, so they cannot touch server-produced Astro markup. This package makes the admin's real-time preview work where no client framework owns the page. Add one line to `astro.config.mjs`, mark what should update — one attribute per component on a server-rendered page, per field on a static one — and edits stream into the preview iframe as the editor types. No rebuild, no reload, no React.
11
+ **The missing piece for Astro + Payload.** The official live-preview packages are React and Vue hooks: they re-render a hydrated component tree, so they cannot touch server-produced Astro markup. This package makes the admin's real-time preview work where no client framework owns the page. Add one line to `astro.config.mjs`, mark what should update — one attribute per component on a server-rendered page with a fragment endpoint, per field on a static one — and edits stream into the preview iframe as the editor types. No rebuild, no reload, no React.
12
12
 
13
13
  The runtime is framework-agnostic: one script drives Astro, SvelteKit, Nuxt, Next.js and plain HTML. Astro is the first-class, end-to-end-tested path.
14
14
 
@@ -16,10 +16,10 @@ The runtime is framework-agnostic: one script drives Astro, SvelteKit, Nuxt, Nex
16
16
 
17
17
  ## Highlights
18
18
 
19
- - **One runtime, every frontend.** One TypeScript runtime compiled to a self-contained inline script of about 34 KB gzip — 26 KB with the lean artifact ([docs/options.md](docs/options.md)); the adapters for Astro, Next.js, SvelteKit and Nuxt only decide when to deliver it.
19
+ - **One runtime, every frontend.** One TypeScript runtime compiled to a self-contained inline script of about 35 KB gzip — 28 KB with the lean artifact ([docs/options.md](docs/options.md)); the adapters for Astro, Next.js, SvelteKit and Nuxt only decide when to deliver it.
20
20
  - **Payload 3.x native.** `serverURL` re-fetches the populated document, like the official client, so relationship and upload fields render as content rather than as IDs — but only when an edit needs one: typing into a text field costs no request, and a burst on a relationship costs two rather than one per keystroke.
21
- - **Complete Lexical renderer.** 16 node types including `upload`, `relationship`, `block`, `autolink`, tabs, indent and RTL, with automatic rich-text detection: `data-payload-field` alone is enough.
22
- - **Authorization before anything privileged.** Draft reads, runtime injection, CSP changes and binding attributes follow one verified decision per request; the client-controlled intent signals never unlock anything.
21
+ - **Complete Lexical renderer.** 20 node types including `upload`, `relationship`, `block`, `autolink`, tabs, indent and RTL, with automatic rich-text detection: `data-payload-field` alone is enough.
22
+ - **Authorization before anything privileged.** Wherever the runtime is injected at request time, draft reads, runtime injection, CSP changes and binding attributes follow one verified decision per request; Astro's default `inline` and `loader` modes inject at build time into every page, where the runtime does not start outside a preview frame. The client-controlled intent signals never unlock anything.
23
23
  - **Strict by default.** Escape-by-default sanitizer, URL and `srcset` validation, policed attribute writes, prototype-pollution guards, per-instance clients, typed bindings with `pll-codegen`.
24
24
 
25
25
  ## Compatibility
@@ -46,9 +46,11 @@ Vite 5 through 8: that is what the supported framework majors install (Astro 7
46
46
 
47
47
  - Payload 2.x: captured-message integration tests and fieldSchemaJSON typing.
48
48
  - Payload 3.85.0: wire corpus captured from a real admin, replayed in tests/integration/wire-corpus.test.ts.
49
- - Payload 3.88.0: real admin E2E (examples/payload-backend) on every push, plus a wire corpus captured from it.
50
- - Payload latest: weekly protocol watch executes @payloadcms/live-preview@latest against the corpus.
51
- - Payload 4.0 pre-releases: weekly protocol watch against @payloadcms/live-preview@canary, early warning only.
49
+ - Payload 3.88.0: wire corpus captured from a real admin, replayed in tests/integration/wire-corpus.test.ts.
50
+ - Payload 3.89.0: real admin E2E (examples/payload-backend) on every push, plus a wire corpus captured from it.
51
+ - Payload 4.0.0-canary.33: wire corpus captured from a real Payload 4 admin in a one-off upgrade round, replayed in tests/integration/wire-corpus.test.ts; the fixture itself stays on 3.x.
52
+ - Payload latest: daily protocol watch executes @payloadcms/live-preview@latest against the corpus.
53
+ - Payload 4.0 pre-releases: daily protocol watch against @payloadcms/live-preview@canary, early warning only.
52
54
 
53
55
  <!-- compat-matrix:end -->
54
56
 
@@ -60,7 +62,7 @@ Vite 5 through 8: that is what the supported framework majors install (Astro 7
60
62
  npm install payload-live-preview
61
63
  ```
62
64
 
63
- Three entries cover most projects. The root `payload-live-preview` carries the client, the inline script generator, the renderers and the plugins. `payload-live-preview/astro`, `/nextjs`, `/sveltekit` and `/nuxt` hold one framework adapter each. `payload-live-preview/server` is the privileged surface for server code: `definePreview()`, `authorizePreviewRequest()`, `issuePreviewToken()` and `createPreviewBindings()`. The focused entries (`core`, `client`, `lexical`, `structural`, `plugins`, `fragment`, `payload`, `codegen`, `doctor`, `migrate`) are listed in [docs/options.md](docs/options.md).
65
+ Three entries cover most projects. The root `payload-live-preview` carries the client, the inline script generator, the renderers and the plugins. `payload-live-preview/astro`, `/nextjs`, `/sveltekit` and `/nuxt` hold one framework adapter each; `/nuxt-module` registers the Nuxt one from `nuxt.config.ts`. `payload-live-preview/server` is the privileged surface for server code: `definePreview()`, `authorizePreviewRequest()`, `issuePreviewToken()` and `createPreviewBindings()`. The focused entries (`core`, `client`, `lexical`, `structural`, `plugins`, `fragment`, `lean`, `payload`, `codegen`, `codegen/astro`, `annotate`, `doctor`, `migrate`) are listed in [docs/options.md](docs/options.md).
64
66
 
65
67
  ## Configure Payload
66
68
 
@@ -81,7 +83,7 @@ export default buildConfig({
81
83
  globals: {
82
84
  homepage: '/',
83
85
  },
84
- fallback: '/', // new drafts without a slug land here
86
+ fallback: '/', // unmapped documents, and resolvers that return '', land here
85
87
  }),
86
88
  breakpoints: [
87
89
  { label: 'Mobile', name: 'mobile', width: 375, height: 667 },
@@ -128,6 +130,8 @@ Then mark what should update. On a server-rendered page that is one attribute pe
128
130
  </section>
129
131
  ```
130
132
 
133
+ The attribute needs a renderer behind it: a route exporting `createFragmentEndpoint()` with `authorizePreview` or `authorize`, served at request time (an SSR adapter, `prerender = false` on that route), and its path in the options above as `fragments: { endpoint: '/payload/fragment' }` ([docs/hybrid.md](docs/hybrid.md)). Without `fragments` the bindings inside the boundary are patched instead (`LP0806`), and a boundary with none inside does not update.
134
+
131
135
  On a static build there is no server to render it, so the fields are bound individually — and inside a boundary too, for the ones an editor types into while watching, because a patch keeps focus and the caret where a re-render would not:
132
136
 
133
137
  ```astro
@@ -149,7 +153,7 @@ That is it: the inline script detects the admin's iframe and starts patching. Ri
149
153
 
150
154
  ## Patch, fragment, route
151
155
 
152
- A binding is patched in place by default. A `data-payload-fragment` boundary is rendered by your server from the unsaved form state instead — conditional sections, derived values, custom blocks, the component's own logic — and morphed in with focus and visitor state intact; the runtime posts the fields to a same-origin endpoint built with `createFragmentEndpoint()`, which every adapter entry exports — Astro renders through its container API, Next.js through `react-dom/server`, SvelteKit through `svelte/server`, Nuxt through `vue/server-renderer` — and patches the boundary's own bindings when the server cannot render. A binding in `<head>`, or one marked `data-payload-strategy="route"`, refreshes the whole route once per revision with scroll and focus kept. Markup, endpoint, deployment requirements and the abuse model: [docs/hybrid.md](docs/hybrid.md).
156
+ A binding is patched in place by default. A `data-payload-fragment` boundary is rendered by your server from the unsaved form state instead — conditional sections, derived values, custom blocks, the component's own logic — and morphed in with focus and visitor state intact; the runtime posts the fields to the same-origin endpoint named in `fragments: { endpoint }`, built with `createFragmentEndpoint()`, which every adapter entry exports — Astro renders through its container API, Next.js through `react-dom/server`, SvelteKit through `svelte/server`, Nuxt through `vue/server-renderer` — and patches the boundary's own bindings when the server cannot render. With `routeStrategy: true` or `fragments` set, a binding in `<head>`, or one marked `data-payload-strategy="route"`, refreshes the whole route once per revision with scroll and focus kept; without either it is patched like any other. Markup, endpoint, deployment requirements and the abuse model: [docs/hybrid.md](docs/hybrid.md).
153
157
 
154
158
  ## Events and plugins
155
159
 
@@ -167,7 +171,7 @@ Every event, transforms, custom field renderers, the built-in plugins and the pl
167
171
 
168
172
  ## Security model
169
173
 
170
- - **Preview intent is not authorization.** The query parameter, the iframe destination and the referer are client-controlled; the adapters count the query alone by default. `allowedOrigins` governs browser `postMessage` senders and `shouldInject` filters routes; neither authenticates the request. `authorizePreviewRequest()` does, and that one result controls draft reads, `private, no-store` caching, CSP changes and runtime injection.
174
+ - **Preview intent is not authorization.** The query parameter, the iframe destination and the referer are client-controlled; the adapters count the query alone by default. `allowedOrigins` governs browser `postMessage` senders and `shouldInject` filters routes; neither authenticates the request. `authorizePreviewRequest()` does, and wherever injection happens at request time that one result controls draft reads, `private, no-store` caching, CSP changes and runtime injection. Astro's build-time `inline` and `loader` modes decide nothing per request: every page carries the runtime or its bootstrap.
171
175
  - **Origin validation.** Every incoming message is checked against `allowedOrigins`; `document.referrer` is ignored by default, and after the first accepted update the runtime locks to that origin. The adapters merge a `frame-ancestors` policy for the admin origins without clobbering the rest of your CSP.
172
176
  - **Sanitization and URL validation.** Lexical and HTML writes pass a DOM sanitizer with a curated allow-list — `<script>`, `<form>`, `<iframe>`, `<svg>`, event handlers and `style` are rejected — and every `href`, `src`, `srcset` and `poster` must be `http(s)`, `mailto:`, `tel:` or relative; external links get `rel="noopener noreferrer"`.
173
177
  - **Binding attributes are disclosure.** `data-payload-field` names a CMS field and `data-payload-owner` a document. `createPreviewBindings({ authorization })` suppresses them, companions included, on public responses. Never key CSS off `data-payload-*`.
@@ -182,7 +186,7 @@ Full details in [docs/security.md](docs/security.md). Report vulnerabilities per
182
186
  - **The preview iframe refuses to load.** The host sets `X-Frame-Options` or a restrictive `frame-ancestors`. The adapters merge `frame-ancestors` on authorized preview responses; an `X-Frame-Options: DENY` from a proxy must go.
183
187
  - **The adapter refuses to start.** The strict default needs `authorizePreview`, a non-empty `allowedOrigins` (`https:` in production) and no referer trust; `defaults: 'v1'` stages a migration one row at a time.
184
188
 
185
- `inspect()` readings, `pll doctor` and every diagnostic code: [docs/troubleshooting.md](docs/troubleshooting.md).
189
+ `inspect()` readings, `pll doctor` and every diagnostic code: [docs/troubleshooting.md](docs/troubleshooting.md). `pll doctor` sends its preview request with `?preview=true`; a preview behind `authorizePreview` is audited with an editor's credential, such as `--header "x-preview-token: …"`.
186
190
 
187
191
  ## Documentation
188
192
 
@@ -1,10 +1,10 @@
1
- import { L as LivePreviewAstroOptions } from '../../middleware-Bx9I7PXW.js';
2
- export { a as LivePreviewMiddleware, c as createLivePreviewMiddleware } from '../../middleware-Bx9I7PXW.js';
3
- import { h as hasPreviewIntent } from '../../options-BW1eqXvc.js';
4
- export { P as PreviewAdapterOptions, a as PreviewRequestLike, b as PreviewRequestOptions, c as PreviewSignal } from '../../options-BW1eqXvc.js';
5
- import { F as FragmentEndpointOptions$1, a as FragmentRegistry$1, b as FragmentRegistryEntry$1, c as FragmentRenderer$1 } from '../../fragment-endpoint-3Mlz7GDz.js';
6
- export { d as FragmentRenderInput } from '../../fragment-endpoint-3Mlz7GDz.js';
7
- export { A as AUTHORIZATION_LOCALS_KEY, a as AUTHORIZATION_OUTCOME_LOCALS_KEY, L as LivePreviewLocals, N as NONCE_LOCALS_KEY } from '../../locals-DBXDMxOA.js';
1
+ import { L as LivePreviewAstroOptions } from '../../middleware-CWObDO37.js';
2
+ export { a as LivePreviewMiddleware, c as createLivePreviewMiddleware } from '../../middleware-CWObDO37.js';
3
+ import { h as hasPreviewIntent } from '../../options-uHKrDM2U.js';
4
+ export { P as PreviewAdapterOptions, a as PreviewRequestLike, b as PreviewRequestOptions, c as PreviewSignal } from '../../options-uHKrDM2U.js';
5
+ import { F as FragmentEndpointOptions$1, a as FragmentRegistry$1, b as FragmentRegistryEntry$1, c as FragmentRenderer$1 } from '../../fragment-endpoint-DATKU183.js';
6
+ export { d as FragmentRenderInput } from '../../fragment-endpoint-DATKU183.js';
7
+ export { A as AUTHORIZATION_LOCALS_KEY, a as AUTHORIZATION_OUTCOME_LOCALS_KEY, L as LivePreviewLocals, N as NONCE_LOCALS_KEY } from '../../locals-CNUGYbA_.js';
8
8
 
9
9
  /**
10
10
  * The Astro integration for `astro.config.mjs`: `livePreview({ ... })`.
@@ -87,7 +87,7 @@ declare function renderLivePreviewScript(options?: RenderScriptOptions): string;
87
87
  *
88
88
  * Measured against the published 1.8.1 declarations, entry by entry, not
89
89
  * guessed: `isPreviewRequest` was exported from the root **and** from
90
- * `./astro`, so it is re-exported from both. The other seven names 2.0 dropped
90
+ * `./astro`, so it is re-exported from both. The six names 2.0 dropped
91
91
  * moved behind `definePreview()` or changed shape, where an alias would restore
92
92
  * the very defaults the move removed (ADR 0007, ledger rows 1 and 9).
93
93
  */