payload-react-router 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +263 -2
  3. package/dist/client/PayloadRootProviders.d.ts +22 -0
  4. package/dist/client/PayloadRootProviders.js +29 -0
  5. package/dist/client/PayloadRootProviders.js.map +1 -0
  6. package/dist/client/RouterAdapter.d.ts +14 -0
  7. package/dist/client/RouterAdapter.js +64 -0
  8. package/dist/client/RouterAdapter.js.map +1 -0
  9. package/dist/client/navigation.d.ts +11 -0
  10. package/dist/client/navigation.js +31 -0
  11. package/dist/client/navigation.js.map +1 -0
  12. package/dist/exports/client.d.ts +2 -0
  13. package/dist/exports/client.js +3 -0
  14. package/dist/exports/client.js.map +1 -0
  15. package/dist/exports/server.d.ts +10 -0
  16. package/dist/exports/server.js +11 -0
  17. package/dist/exports/server.js.map +1 -0
  18. package/dist/exports/vite.d.ts +1 -0
  19. package/dist/exports/vite.js +2 -0
  20. package/dist/exports/vite.js.map +1 -0
  21. package/dist/server/adminPage.d.ts +50 -0
  22. package/dist/server/adminPage.js +136 -0
  23. package/dist/server/adminPage.js.map +1 -0
  24. package/dist/server/auth.d.ts +16 -0
  25. package/dist/server/auth.js +17 -0
  26. package/dist/server/auth.js.map +1 -0
  27. package/dist/server/cookies.d.ts +3 -0
  28. package/dist/server/cookies.js +27 -0
  29. package/dist/server/cookies.js.map +1 -0
  30. package/dist/server/graphql.d.ts +9 -0
  31. package/dist/server/graphql.js +114 -0
  32. package/dist/server/graphql.js.map +1 -0
  33. package/dist/server/initAdminContext.d.ts +17 -0
  34. package/dist/server/initAdminContext.js +39 -0
  35. package/dist/server/initAdminContext.js.map +1 -0
  36. package/dist/server/layout.d.ts +28 -0
  37. package/dist/server/layout.js +37 -0
  38. package/dist/server/layout.js.map +1 -0
  39. package/dist/server/middleware.d.ts +16 -0
  40. package/dist/server/middleware.js +35 -0
  41. package/dist/server/middleware.js.map +1 -0
  42. package/dist/server/requestStore.d.ts +29 -0
  43. package/dist/server/requestStore.js +54 -0
  44. package/dist/server/requestStore.js.map +1 -0
  45. package/dist/server/rest.d.ts +34 -0
  46. package/dist/server/rest.js +54 -0
  47. package/dist/server/rest.js.map +1 -0
  48. package/dist/server/searchParams.d.ts +6 -0
  49. package/dist/server/searchParams.js +13 -0
  50. package/dist/server/searchParams.js.map +1 -0
  51. package/dist/server/serverAdapter.d.ts +28 -0
  52. package/dist/server/serverAdapter.js +79 -0
  53. package/dist/server/serverAdapter.js.map +1 -0
  54. package/dist/server/serverFunctions.d.ts +21 -0
  55. package/dist/server/serverFunctions.js +25 -0
  56. package/dist/server/serverFunctions.js.map +1 -0
  57. package/dist/vite/config/external.d.ts +43 -0
  58. package/dist/vite/config/external.js +102 -0
  59. package/dist/vite/config/external.js.map +1 -0
  60. package/dist/vite/config/optimizeDeps.d.ts +24 -0
  61. package/dist/vite/config/optimizeDeps.js +162 -0
  62. package/dist/vite/config/optimizeDeps.js.map +1 -0
  63. package/dist/vite/config/scss.d.ts +13 -0
  64. package/dist/vite/config/scss.js +29 -0
  65. package/dist/vite/config/scss.js.map +1 -0
  66. package/dist/vite/devConfigReload.d.ts +13 -0
  67. package/dist/vite/devConfigReload.js +74 -0
  68. package/dist/vite/devConfigReload.js.map +1 -0
  69. package/dist/vite/devConfigReload.server.d.ts +1 -0
  70. package/dist/vite/devConfigReload.server.js +62 -0
  71. package/dist/vite/devConfigReload.server.js.map +1 -0
  72. package/dist/vite/devConfigReloadEvent.d.ts +8 -0
  73. package/dist/vite/devConfigReloadEvent.js +9 -0
  74. package/dist/vite/devConfigReloadEvent.js.map +1 -0
  75. package/dist/vite/index.d.ts +31 -0
  76. package/dist/vite/index.js +148 -0
  77. package/dist/vite/index.js.map +1 -0
  78. package/dist/vite/workarounds/clientModuleResolution.d.ts +13 -0
  79. package/dist/vite/workarounds/clientModuleResolution.js +80 -0
  80. package/dist/vite/workarounds/clientModuleResolution.js.map +1 -0
  81. package/dist/vite/workarounds/reactDomServerInRsc.d.ts +26 -0
  82. package/dist/vite/workarounds/reactDomServerInRsc.js +84 -0
  83. package/dist/vite/workarounds/reactDomServerInRsc.js.map +1 -0
  84. package/dist/vite/workarounds/stripDistStyleImports.d.ts +20 -0
  85. package/dist/vite/workarounds/stripDistStyleImports.js +140 -0
  86. package/dist/vite/workarounds/stripDistStyleImports.js.map +1 -0
  87. package/dist/vite/workarounds/stubPrettierInClient.d.ts +12 -0
  88. package/dist/vite/workarounds/stubPrettierInClient.js +32 -0
  89. package/dist/vite/workarounds/stubPrettierInClient.js.map +1 -0
  90. package/dist/vite/workarounds/wrapCjsForClient.d.ts +14 -0
  91. package/dist/vite/workarounds/wrapCjsForClient.js +104 -0
  92. package/dist/vite/workarounds/wrapCjsForClient.js.map +1 -0
  93. package/package.json +79 -4
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sakuga Software
4
+
5
+ The Vite plugin under src/vite is ported from @payloadcms/tanstack-start:
6
+ Copyright (c) 2018-2026 Payload CMS, LLC <info@payloadcms.com>
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,264 @@
1
- # Temporary Holding Version
1
+ # payload-react-router
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Mounts the [Payload](https://payloadcms.com) admin panel, REST API and GraphQL API inside a
4
+ **React Router 8** app. It implements Payload's framework-adapter contracts (server, router,
5
+ view and layout adapters, server functions); `@payloadcms/ui` is used unmodified.
6
+
7
+ > **Status: experimental.** It runs on React Router's **RSC Framework Mode**, which React
8
+ > Router itself ships as `unstable_` ("subject to breaking changes in minor/patch releases").
9
+ > Payload's admin is built from React Server Components, so RSC is required, not optional —
10
+ > see [Why RSC](#why-rsc). Versions are pinned for that reason.
11
+
12
+ | Tested with | Version |
13
+ | --- | --- |
14
+ | `payload`, `@payloadcms/*` | `4.0.0-canary.39` |
15
+ | `react-router`, `@react-router/dev`, `@react-router/serve` | `8.4.0` |
16
+ | `@vitejs/plugin-rsc` | `0.5.35` (0.5.26 fails the build; 0.5.36 trips a React Router build invariant) |
17
+ | `react`, `react-dom`, `react-server-dom-webpack` | `19.3.0` |
18
+ | Vite | `8.x` |
19
+ | Node.js | `>= 24.15` (Payload 4) |
20
+
21
+ The adapter is exercised by a demo app: SQLite, Lexical, drafts + autosave, uploads, two
22
+ locales, a global, and a website that reads content through the Local API. A 26-test Playwright
23
+ bench runs on that app against both the production build and `vite dev`, with the adapter
24
+ installed from the packed tarball. The demo app is in a private repository for now; the
25
+ scenarios and results are in [`docs/COMPAT.md`](./docs/COMPAT.md).
26
+
27
+ ## Adding Payload to a React Router app
28
+
29
+ ### 1. Dependencies
30
+
31
+ ```bash
32
+ pnpm add payload @payloadcms/ui @payloadcms/translations @payloadcms/graphql graphql \
33
+ @payloadcms/db-sqlite @payloadcms/richtext-lexical payload-react-router \
34
+ react@19.3.0 react-dom@19.3.0 react-server-dom-webpack@19.3.0 \
35
+ react-router@8.4.0 @react-router/serve@8.4.0
36
+ pnpm add -D @react-router/dev@8.4.0 @vitejs/plugin-rsc@0.5.35 vite sass-embedded
37
+ ```
38
+
39
+ ### 2. Switch the app to RSC Framework Mode
40
+
41
+ ```ts
42
+ // vite.config.ts
43
+ import { unstable_reactRouterRSC as reactRouterRSC } from '@react-router/dev/vite'
44
+ import rsc from '@vitejs/plugin-rsc'
45
+ import { payload } from 'payload-react-router/vite'
46
+ import { defineConfig } from 'vite'
47
+
48
+ export default defineConfig({
49
+ plugins: [payload({ payloadConfigPath: './payload.config.ts' }), reactRouterRSC(), rsc()],
50
+ })
51
+ ```
52
+
53
+ `react-router.config.ts` needs nothing special (`ssr: true`, the default). React Router's RSC
54
+ mode does not support `splitRouteModules`, `serverBundles`, `presets` or `buildEnd`.
55
+
56
+ Existing routes keep working: a route with a `default` export is a client component, as
57
+ before; a route can opt into a server component by exporting `ServerComponent` instead. The
58
+ `.server.ts` file convention is not enforced in RSC mode — use the `server-only` package if
59
+ you rely on it.
60
+
61
+ The `payload()` plugin adds the `@payload-config` alias, SCSS importers, SSR externals,
62
+ dependency-optimizer lists and a handful of Vite-level workarounds Payload needs (ported from
63
+ `@payloadcms/tanstack-start`).
64
+
65
+ ### 3. Payload config
66
+
67
+ ```ts
68
+ // payload.config.ts
69
+ export default buildConfig({
70
+ admin: {
71
+ importMap: {
72
+ baseDir: import.meta.dirname,
73
+ // The Payload CLI only knows the Next.js and TanStack Start folder layouts.
74
+ importMapFile: path.resolve(import.meta.dirname, 'app/routes/payload/importMap.js'),
75
+ },
76
+ },
77
+ // In production this file is bundled into build/server/: anchor runtime paths
78
+ // (SQLite file, upload staticDir) on process.cwd(), not import.meta.dirname.
79
+ db: sqliteAdapter({ client: { url: `file:${path.resolve(process.cwd(), 'payload.db')}` } }),
80
+ // ...
81
+ })
82
+ ```
83
+
84
+ Generate the import map whenever admin components change:
85
+
86
+ ```bash
87
+ PAYLOAD_CONFIG_PATH=./payload.config.ts pnpm payload generate:importmap
88
+ ```
89
+
90
+ and add `app/routes/payload/importMap.d.ts`:
91
+
92
+ ```ts
93
+ import type { ImportMap } from 'payload'
94
+ export declare const importMap: ImportMap
95
+ ```
96
+
97
+ ### 4. Routes
98
+
99
+ ```ts
100
+ // app/routes.ts
101
+ import { index, layout, route, type RouteConfig } from '@react-router/dev/routes'
102
+
103
+ export default [
104
+ layout('routes/site/layout.tsx', [index('routes/site/home.tsx') /* your site */]),
105
+ layout('routes/payload/layout.tsx', { id: 'payload' }, [route('admin/*', 'routes/payload/admin.tsx')]),
106
+ route('api/*', 'routes/payload/api.ts'),
107
+ ] satisfies RouteConfig
108
+ ```
109
+
110
+ The admin renders its own `<html>` (theme, language and direction attributes), so the root
111
+ route must not. Let each layout route own its document:
112
+
113
+ ```tsx
114
+ // app/root.tsx
115
+ import { Outlet } from 'react-router'
116
+ import { payloadMiddleware } from 'payload-react-router/server'
117
+
118
+ export const middleware = [payloadMiddleware]
119
+
120
+ export function ServerComponent() {
121
+ return <Outlet />
122
+ }
123
+ ```
124
+
125
+ `payloadMiddleware` must be on the root route: it scopes every request (documents, data
126
+ requests, server functions, resource routes) so Payload can read headers and set cookies.
127
+
128
+ ```tsx
129
+ // app/routes/payload/server-functions.ts
130
+ 'use server'
131
+ import type { ServerFunctionClientArgs } from 'payload'
132
+ import config from '@payload-config'
133
+ import { handleServerFunctions } from 'payload-react-router/server'
134
+ import { importMap } from './importMap.js'
135
+
136
+ export async function serverFunction(args: ServerFunctionClientArgs, _revalidation?: FormData) {
137
+ return handleServerFunctions({ ...args, config, importMap })
138
+ }
139
+ ```
140
+
141
+ ```tsx
142
+ // app/routes/payload/layout.tsx — the admin document and providers
143
+ import config from '@payload-config'
144
+ import '@payloadcms/ui/css/app.css'
145
+ import { PayloadAdminLayout } from 'payload-react-router/server'
146
+ import { Outlet } from 'react-router'
147
+ import { importMap } from './importMap.js'
148
+ import { serverFunction } from './server-functions'
149
+
150
+ export function ServerComponent() {
151
+ return (
152
+ <PayloadAdminLayout config={config} importMap={importMap} serverFunction={serverFunction}>
153
+ <Outlet />
154
+ </PayloadAdminLayout>
155
+ )
156
+ }
157
+ ```
158
+
159
+ ```tsx
160
+ // app/routes/payload/admin.tsx — /admin and every admin view
161
+ import config from '@payload-config'
162
+ import { AdminPage, loadAdminPage } from 'payload-react-router/server'
163
+ import type { Route } from './+types/admin'
164
+ import { importMap } from './importMap.js'
165
+
166
+ export const loader = ({ params, request }: Route.LoaderArgs) =>
167
+ loadAdminPage({ config, importMap, request, splat: params['*'] })
168
+
169
+ export function ServerComponent({ loaderData }: Route.ComponentProps) {
170
+ return <AdminPage {...loaderData} />
171
+ }
172
+ ```
173
+
174
+ ```ts
175
+ // app/routes/payload/api.ts — REST + GraphQL
176
+ import config from '@payload-config'
177
+ import { createAPIRoute } from 'payload-react-router/server'
178
+
179
+ export const { action, loader, middleware } = createAPIRoute({ config })
180
+ ```
181
+
182
+ ### 5. Reading content from the site (Local API)
183
+
184
+ ```tsx
185
+ // app/routes/site/home.tsx
186
+ import config from '@payload-config'
187
+ import { getPayload } from 'payload'
188
+
189
+ export async function loader() {
190
+ const payload = await getPayload({ config })
191
+ const posts = await payload.find({ collection: 'posts', overrideAccess: false })
192
+ return { posts: posts.docs }
193
+ }
194
+ ```
195
+
196
+ Same process, no HTTP hop, no token. Pass `overrideAccess: false` so collection access control
197
+ decides what anonymous visitors see.
198
+
199
+ ### 6. Production
200
+
201
+ ```bash
202
+ pnpm react-router build
203
+ pnpm react-router-serve ./build/server/index.js
204
+ ```
205
+
206
+ The schema is pushed automatically in development only. For production, create migrations
207
+ (`payload migrate:create`) and pass them as `prodMigrations` to the database adapter, or run
208
+ `payload migrate` before starting.
209
+
210
+ ## API
211
+
212
+ `payload-react-router/vite`
213
+
214
+ - `payload({ payloadConfigPath, devServerExternalPackages?, silenceDependencyWarnings? })`
215
+
216
+ `payload-react-router/server`
217
+
218
+ - `payloadMiddleware` — root route middleware (request scope + `Set-Cookie`).
219
+ - `PayloadAdminLayout` — admin document + providers (server component).
220
+ - `loadAdminPage({ config, importMap, request, splat })` / `AdminPage` — admin views.
221
+ - `handleServerFunctions` — Payload's server-function dispatcher.
222
+ - `createAPIRoute({ config })` / `handleAPIRoute({ config, request })` — REST + GraphQL.
223
+ - `login` / `logout` / `refresh` — Payload auth functions bound to this adapter.
224
+ - `reactRouterServerAdapter`, `createPageRenderServerAdapter`, `initAdminContext`,
225
+ `getRequestI18n`, `getRequest`, `serializeCookie` — lower-level pieces.
226
+
227
+ `payload-react-router/client`
228
+
229
+ - `ReactRouterAdapter` — Payload's router contract on React Router hooks.
230
+ - `PayloadRootProviders` — `RootProviders` bound to the router adapter.
231
+
232
+ ## How it maps to Payload's contracts
233
+
234
+ | Contract | Implementation |
235
+ | --- | --- |
236
+ | `ServerAdapter` | Per-request `AsyncLocalStorage` opened by `payloadMiddleware`. Headers/cookies come from the `Request`; `setCookie` is appended to the response. `redirect`/`notFound`/`forbidden`/`unauthorized`/`permanentRedirect` throw React Router responses with real 302/404/403/401/308 statuses. |
237
+ | View adapter | `loadAdminPage` calls `renderRoot` in the route loader and renders the tree to completion, so a `redirect()`/`notFound()` raised deep inside a view still becomes a real redirect or a 404 page. |
238
+ | Layout adapter | `PayloadAdminLayout` (server component) renders `DocumentRoot` and providers. |
239
+ | Router adapter | `useNavigate` / `navigate(-1)` / `useRevalidator().revalidate()` / `Link`; `replaceState` uses the History API, which React Router does not observe. |
240
+ | Server functions | A real `'use server'` function: results, including React nodes, travel over Flight as with Next.js. Calls opt out of React Router's automatic revalidation (`$SKIP_REVALIDATION`); Payload refreshes explicitly. |
241
+ | REST / GraphQL | Resource route → `handleEndpoints`; `POST /api/graphql` → GraphQL handler; `OPTIONS` answered by a route middleware. |
242
+
243
+ The full contract-by-contract comparison with `@payloadcms/next` and
244
+ `@payloadcms/tanstack-start`, and every issue found in the contracts, are in
245
+ [`docs/NOTES.md`](./docs/NOTES.md) (in French). Test coverage is in
246
+ [`docs/COMPAT.md`](./docs/COMPAT.md).
247
+
248
+ ## Why RSC
249
+
250
+ Payload's admin views (`renderRoot`), its root layout and its server functions are React
251
+ Server Components: they are async, run server-only code, and return React elements to the
252
+ client (a rendered document, a list, form fields with custom server components). Without an
253
+ RSC runtime they cannot render — `@payloadcms/tanstack-start` enables RSC for the same reason.
254
+ A plain "SSR + loaders" React Router app cannot host the admin without changing
255
+ `@payloadcms/ui`.
256
+
257
+ ## Known limitations
258
+
259
+ - React Router RSC mode is `unstable_`; pin versions and re-run the bench on upgrades.
260
+ - Mounting the admin at `/` (Payload's `admin-root` setup) is untested; TanStack skips it too.
261
+ - The Payload CLI does not detect React Router: use `importMapFile` and `PAYLOAD_CONFIG_PATH`.
262
+ - Each admin page is rendered to completion on the server before streaming starts (needed
263
+ to turn in-view redirects into real redirects; TanStack does the same).
264
+ - Live preview and cloud storage adapters are not covered by the bench yet.
@@ -0,0 +1,22 @@
1
+ import type { RootLayoutData } from '@payloadcms/ui/layouts/Root/getRootLayoutData';
2
+ import type { ServerFunctionClientArgs } from 'payload';
3
+ import type { ReactNode } from 'react';
4
+ /**
5
+ * Signature of the app's `'use server'` function. The second argument is the
6
+ * revalidation opt-out added by {@link PayloadRootProviders}; the server side
7
+ * ignores it.
8
+ */
9
+ export type PayloadServerFunction = (args: ServerFunctionClientArgs, revalidation?: FormData) => Promise<unknown>;
10
+ export type PayloadRootProvidersProps = {
11
+ children: ReactNode;
12
+ data: RootLayoutData;
13
+ serverFunction: PayloadServerFunction;
14
+ };
15
+ declare global {
16
+ interface Window {
17
+ /** Set once the admin has hydrated. End-to-end tests wait for it before interacting. */
18
+ __PAYLOAD_ADMIN_HYDRATED__?: boolean;
19
+ }
20
+ }
21
+ /** Payload's `RootProviders`, bound to React Router. Rendered by `PayloadAdminLayout`. */
22
+ export declare function PayloadRootProviders({ children, data, serverFunction }: PayloadRootProvidersProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { RootProviders } from '@payloadcms/ui';
4
+ import React, { useCallback, useEffect } from 'react';
5
+ import { ReactRouterAdapter } from "./RouterAdapter.js";
6
+ /**
7
+ * React Router re-renders the current route after *every* server function
8
+ * call, unless the call carries a `FormData` with a `$SKIP_REVALIDATION` entry
9
+ * (`react-router/lib/rsc/server.rsc.ts`, `processServerAction`).
10
+ *
11
+ * Payload calls server functions constantly — `form-state` runs on every
12
+ * keystroke — and refreshes explicitly with `router.refresh()` when it needs
13
+ * fresh server output, the way Next's server actions behave. Without the
14
+ * opt-out each keystroke would re-render the whole admin page.
15
+ */
16
+ function skipRevalidation() {
17
+ const formData = new FormData();
18
+ formData.set('$SKIP_REVALIDATION', '1');
19
+ return formData;
20
+ }
21
+ /** Payload's `RootProviders`, bound to React Router. Rendered by `PayloadAdminLayout`. */
22
+ export function PayloadRootProviders({ children, data, serverFunction }) {
23
+ const callServerFunction = useCallback((args) => serverFunction(args, skipRevalidation()), [serverFunction]);
24
+ useEffect(() => {
25
+ window.__PAYLOAD_ADMIN_HYDRATED__ = true;
26
+ }, []);
27
+ return (_jsx(RootProviders, { data: data, RouterAdapter: ReactRouterAdapter, serverFunction: callServerFunction, children: children }));
28
+ }
29
+ //# sourceMappingURL=PayloadRootProviders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PayloadRootProviders.js","sourceRoot":"","sources":["../../src/client/PayloadRootProviders.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAMZ,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAqB,CAAA;AAYxD;;;;;;;;;GASG;AACH,SAAS,gBAAgB;IACvB,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAA;IAC/B,QAAQ,CAAC,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAA;IACvC,OAAO,QAAQ,CAAA;AACjB,CAAC;AAeD,0FAA0F;AAC1F,MAAM,UAAU,oBAAoB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAA6B;IAChG,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAClD,CAAC,cAAc,CAAC,CACjB,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,0BAA0B,GAAG,IAAI,CAAA;IAC1C,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,aAAa,IAAC,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,YAC7F,QAAQ,GACK,CACjB,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { RouterAdapterComponent } from 'payload';
2
+ /**
3
+ * Payload's `RouterAdapter` contract implemented with React Router hooks.
4
+ *
5
+ * - `push` / `replace` → `useNavigate()`; `scroll: false` → `preventScrollReset`.
6
+ * - `back` → `navigate(-1)`.
7
+ * - `refresh` → `useRevalidator().revalidate()`, which in RSC mode re-renders the
8
+ * matched server routes, like Next's `router.refresh()`.
9
+ * - `replaceState` → the History API directly: React Router does not observe
10
+ * `history.replaceState`, so the URL changes without a server round trip
11
+ * (the list view relies on that). TanStack needs a private flag for this.
12
+ * - While React Router navigates or revalidates, Payload's progress bar is held.
13
+ */
14
+ export declare const ReactRouterAdapter: RouterAdapterComponent;
@@ -0,0 +1,64 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { RouterAdapterContext, useRouteTransition } from '@payloadcms/ui';
4
+ import React, { useCallback, useEffect, useMemo } from 'react';
5
+ import { Link, useLocation, useNavigate, useNavigation, useParams, useRevalidator, } from 'react-router';
6
+ import { normalizeNavigationTarget, toAdminParams } from "./navigation.js";
7
+ const ReactRouterLink = ({ children, href, prefetch, ref, replace, scroll, ...rest }) => (_jsx(Link, { prefetch: prefetch === false ? 'none' : 'intent', preventScrollReset: scroll === false, ref: ref, replace: replace, to: href, ...rest, children: children }));
8
+ const currentLocation = () => ({
9
+ origin: window.location.origin,
10
+ pathname: window.location.pathname,
11
+ search: window.location.search,
12
+ });
13
+ /**
14
+ * Payload's `RouterAdapter` contract implemented with React Router hooks.
15
+ *
16
+ * - `push` / `replace` → `useNavigate()`; `scroll: false` → `preventScrollReset`.
17
+ * - `back` → `navigate(-1)`.
18
+ * - `refresh` → `useRevalidator().revalidate()`, which in RSC mode re-renders the
19
+ * matched server routes, like Next's `router.refresh()`.
20
+ * - `replaceState` → the History API directly: React Router does not observe
21
+ * `history.replaceState`, so the URL changes without a server round trip
22
+ * (the list view relies on that). TanStack needs a private flag for this.
23
+ * - While React Router navigates or revalidates, Payload's progress bar is held.
24
+ */
25
+ export const ReactRouterAdapter = ({ children }) => {
26
+ const navigate = useNavigate();
27
+ const location = useLocation();
28
+ const params = useParams();
29
+ const navigation = useNavigation();
30
+ const revalidator = useRevalidator();
31
+ const { holdRouteTransition } = useRouteTransition();
32
+ const isBusy = navigation.state !== 'idle' || revalidator.state !== 'idle';
33
+ useEffect(() => (isBusy ? holdRouteTransition() : undefined), [holdRouteTransition, isBusy]);
34
+ const push = useCallback((path, options) => {
35
+ void navigate(normalizeNavigationTarget(path, currentLocation()), {
36
+ preventScrollReset: options?.scroll === false,
37
+ });
38
+ }, [navigate]);
39
+ const replace = useCallback((path, options) => {
40
+ void navigate(normalizeNavigationTarget(path, currentLocation()), {
41
+ preventScrollReset: options?.scroll === false,
42
+ replace: true,
43
+ });
44
+ }, [navigate]);
45
+ const back = useCallback(() => void navigate(-1), [navigate]);
46
+ const { revalidate } = revalidator;
47
+ const refresh = useCallback(() => void revalidate(), [revalidate]);
48
+ const replaceState = useCallback((url) => {
49
+ // Keep React Router's history entry state (key / index) intact.
50
+ window.history.replaceState(window.history.state, '', url);
51
+ }, []);
52
+ const router = useMemo(() => ({ back, push, refresh, replace, replaceState }), [back, push, refresh, replace, replaceState]);
53
+ const adaptedParams = useMemo(() => toAdminParams(params), [params]);
54
+ const searchParams = useMemo(() => new URLSearchParams(location.search), [location.search]);
55
+ const value = useMemo(() => ({
56
+ Link: ReactRouterLink,
57
+ params: adaptedParams,
58
+ pathname: location.pathname,
59
+ router,
60
+ searchParams,
61
+ }), [adaptedParams, location.pathname, router, searchParams]);
62
+ return _jsx(RouterAdapterContext, { value: value, children: children });
63
+ };
64
+ //# sourceMappingURL=RouterAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterAdapter.js","sourceRoot":"","sources":["../../src/client/RouterAdapter.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Turns the targets Payload hands the router into an in-app path:
3
+ * same-origin absolute URLs, bare `?query` and bare `#hash`.
4
+ */
5
+ export declare function normalizeNavigationTarget(target: string, current: {
6
+ origin: string;
7
+ pathname: string;
8
+ search: string;
9
+ }): string;
10
+ /** Maps `params['*']` of the `admin/*` splat onto Next's `segments` shape. */
11
+ export declare function toAdminParams(params: Record<string, string | undefined>): Record<string, string | string[]>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Turns the targets Payload hands the router into an in-app path:
3
+ * same-origin absolute URLs, bare `?query` and bare `#hash`.
4
+ */
5
+ export function normalizeNavigationTarget(target, current) {
6
+ if (/^https?:\/\//.test(target)) {
7
+ const url = new URL(target);
8
+ return url.origin === current.origin ? `${url.pathname}${url.search}${url.hash}` : target;
9
+ }
10
+ if (target.startsWith('?')) {
11
+ return `${current.pathname}${target}`;
12
+ }
13
+ if (target.startsWith('#')) {
14
+ return `${current.pathname}${current.search}${target}`;
15
+ }
16
+ return target;
17
+ }
18
+ /** Maps `params['*']` of the `admin/*` splat onto Next's `segments` shape. */
19
+ export function toAdminParams(params) {
20
+ const adapted = {};
21
+ for (const [key, value] of Object.entries(params)) {
22
+ if (value !== undefined) {
23
+ adapted[key] = value;
24
+ }
25
+ }
26
+ if (typeof params['*'] === 'string') {
27
+ adapted.segments = params['*'].split('/').filter(Boolean);
28
+ }
29
+ return adapted;
30
+ }
31
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/client/navigation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAc,EACd,OAA6D;IAE7D,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;QAC3B,OAAO,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;IAC3F,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,MAAM,EAAE,CAAA;IACvC,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAA;IACxD,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAC3B,MAA0C;IAE1C,MAAM,OAAO,GAAsC,EAAE,CAAA;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PayloadRootProviders, type PayloadRootProvidersProps, type PayloadServerFunction, } from '../client/PayloadRootProviders.tsx';
2
+ export { ReactRouterAdapter } from '../client/RouterAdapter.tsx';
@@ -0,0 +1,3 @@
1
+ export { PayloadRootProviders, } from "../client/PayloadRootProviders.js";
2
+ export { ReactRouterAdapter } from "../client/RouterAdapter.js";
3
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,GAGrB,MAAM,mCAAoC,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA6B,CAAA"}
@@ -0,0 +1,10 @@
1
+ export { AdminPage, type AdminPageData, type AdminPageMeta, loadAdminPage, type LoadAdminPageArgs } from '../server/adminPage.tsx';
2
+ export { login, logout, refresh } from '../server/auth.ts';
3
+ export { getRequestI18n, initAdminContext, type ReactRouterInitAdminContextArgs, } from '../server/initAdminContext.ts';
4
+ export { PayloadAdminLayout, type PayloadAdminLayoutProps } from '../server/layout.tsx';
5
+ export { payloadMiddleware } from '../server/middleware.ts';
6
+ export { getRequest } from '../server/requestStore.ts';
7
+ export { createAPIRoute, handleAPIRoute } from '../server/rest.ts';
8
+ export { serializeCookie } from '../server/cookies.ts';
9
+ export { createPageRenderServerAdapter, type PageNavIntent, reactRouterServerAdapter, } from '../server/serverAdapter.ts';
10
+ export { handleServerFunctions } from '../server/serverFunctions.ts';
@@ -0,0 +1,11 @@
1
+ export { AdminPage, loadAdminPage } from "../server/adminPage.js";
2
+ export { login, logout, refresh } from "../server/auth.js";
3
+ export { getRequestI18n, initAdminContext, } from "../server/initAdminContext.js";
4
+ export { PayloadAdminLayout } from "../server/layout.js";
5
+ export { payloadMiddleware } from "../server/middleware.js";
6
+ export { getRequest } from "../server/requestStore.js";
7
+ export { createAPIRoute, handleAPIRoute } from "../server/rest.js";
8
+ export { serializeCookie } from "../server/cookies.js";
9
+ export { createPageRenderServerAdapter, reactRouterServerAdapter, } from "../server/serverAdapter.js";
10
+ export { handleServerFunctions } from "../server/serverFunctions.js";
11
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/exports/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA0C,aAAa,EAA0B,MAAM,wBAAyB,CAAA;AAClI,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EACL,cAAc,EACd,gBAAgB,GAEjB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,kBAAkB,EAAgC,MAAM,qBAAsB,CAAA;AACvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EACL,6BAA6B,EAE7B,wBAAwB,GACzB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA"}
@@ -0,0 +1 @@
1
+ export { payload, type PayloadVitePluginOptions } from '../vite/index.ts';
@@ -0,0 +1,2 @@
1
+ export { payload } from "../vite/index.js";
2
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","sourceRoot":"","sources":["../../src/exports/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAiC,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,50 @@
1
+ import type { ImportMap, SanitizedConfig } from 'payload';
2
+ import type { ReactNode } from 'react';
3
+ import { data } from 'react-router';
4
+ export type LoadAdminPageArgs = {
5
+ config: Promise<SanitizedConfig> | SanitizedConfig;
6
+ importMap: ImportMap;
7
+ request: Request;
8
+ /** `params['*']` of the `admin/*` splat route: the path after `/admin/`. */
9
+ splat?: string;
10
+ };
11
+ export type AdminPageData = {
12
+ /** Plain-string page metadata, rendered as `<title>` / `<meta>` by {@link AdminPage}. */
13
+ meta: AdminPageMeta;
14
+ /** The rendered admin view, ready to be returned from a server component. */
15
+ page: ReactNode;
16
+ };
17
+ export type AdminPageMeta = {
18
+ description?: string;
19
+ title?: string;
20
+ };
21
+ /**
22
+ * Loads one admin page for the `admin/*` splat route. Call it from the route
23
+ * `loader` and render the result with {@link AdminPage}:
24
+ *
25
+ * ```tsx
26
+ * export const loader = ({ params, request }: Route.LoaderArgs) =>
27
+ * loadAdminPage({ config, importMap, request, splat: params['*'] })
28
+ *
29
+ * export function ServerComponent({ loaderData }: Route.ComponentProps) {
30
+ * return <AdminPage {...loaderData} />
31
+ * }
32
+ * ```
33
+ *
34
+ * Navigation becomes React Router primitives: a redirect is thrown as
35
+ * `redirect()`, and an unknown or forbidden page returns Payload's not-found
36
+ * view (with the admin chrome) under an HTTP 404.
37
+ */
38
+ export declare function loadAdminPage({ config: configInput, importMap, request, splat, }: LoadAdminPageArgs): Promise<AdminPageData | ReturnType<typeof data<AdminPageData>>>;
39
+ /**
40
+ * Renders a page loaded by {@link loadAdminPage}, with its `<title>` hoisted by React.
41
+ *
42
+ * `page` is typed `unknown` on purpose: React Router's generated route types
43
+ * describe loader data as if it were turbo-stream serialized, which mangles
44
+ * `ReactNode`. In RSC mode loader data travels as Flight, so the element arrives
45
+ * intact and can be passed straight through: `<AdminPage {...loaderData} />`.
46
+ */
47
+ export declare function AdminPage({ meta, page }: {
48
+ meta: AdminPageMeta;
49
+ page: unknown;
50
+ }): import("react/jsx-runtime").JSX.Element;