@payload-onpage/next 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  payload-onpage for the Next.js App Router: the session adapter (draft mode, editor binding, sealed preview grants), `<OnPage />`, `onpageContext()`, `isDraftEnabled()`, the `router.refresh()` renderer and the proxy for share links.
4
4
 
5
+ ![Editing a Payload CMS page in place: click the heading, type, and it autosaves as a draft](https://raw.githubusercontent.com/jellologic/payload-onpage/main/docs/media/edit-text.gif)
6
+
7
+ ![Previewing a draft at phone and tablet widths](https://raw.githubusercontent.com/jellologic/payload-onpage/main/docs/media/preview.gif)
8
+
5
9
  ```tsx
6
10
  // layout
7
11
  import { OnPage } from '@payload-onpage/next'
@@ -19,3 +23,5 @@ Entries: `.` (server: `OnPage`, session helpers), `./client` (`OnPageMount`, `On
19
23
  Part of [**payload-onpage**](https://github.com/jellologic/payload-onpage): on-page editing and draft previews for Payload CMS + Next.js. Start with the [getting started guide](https://github.com/jellologic/payload-onpage/blob/main/docs/getting-started.md).
20
24
 
21
25
  MIT licensed.
26
+
27
+ See the **[tour](https://github.com/jellologic/payload-onpage/blob/main/docs/tour.md)** and **[getting started](https://github.com/jellologic/payload-onpage/blob/main/docs/getting-started.md)**.
package/dist/client.d.ts CHANGED
@@ -1,23 +1,23 @@
1
- import type { DataSource, Locator, MediaLibrary } from '@payload-onpage/core';
1
+ import type { DataSource, Locator, MediaLibrary, OnPageMode } from '@payload-onpage/core';
2
2
  import type { FieldEditorDef, Messages } from '@payload-onpage/react';
3
3
  export interface OnPageMountProps {
4
- mode: 'edit' | 'view';
4
+ mode: OnPageMode;
5
5
  /** Opened from a shared preview link (no editing). */
6
- shared?: boolean;
6
+ shared?: boolean | undefined;
7
7
  /** Payload API route. Default "/api". */
8
- apiRoute?: string;
8
+ apiRoute?: string | undefined;
9
9
  /** Plugin endpoint prefix. Default "/onpage". */
10
- prefix?: string;
10
+ prefix?: `/${string}` | undefined;
11
11
  /** Payload admin route. Default "/admin". */
12
- adminRoute?: string;
12
+ adminRoute?: string | undefined;
13
13
  /** Locale to edit. Default: <html lang>. */
14
- locale?: string;
15
- editors?: Record<string, FieldEditorDef | null>;
16
- locator?: Locator;
17
- media?: MediaLibrary;
18
- dataSource?: DataSource;
14
+ locale?: string | undefined;
15
+ editors?: Record<string, FieldEditorDef | null> | undefined;
16
+ locator?: Locator | undefined;
17
+ media?: MediaLibrary | undefined;
18
+ dataSource?: DataSource | undefined;
19
19
  /** Override editor UI strings (see `defaultMessages` in @payload-onpage/react). */
20
- messages?: Messages;
20
+ messages?: Messages | undefined;
21
21
  }
22
22
  export declare function OnPageMount(props: OnPageMountProps): import("react").JSX.Element;
23
23
  export { OnPageClient } from '@payload-onpage/react/client';
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAErE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC,CAAA;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAElD;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAErE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,UAAU,CAAA;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,iDAAiD;IACjD,MAAM,CAAC,EAAE,IAAI,MAAM,EAAE,GAAG,SAAS,CAAA;IACjC,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAE3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC,GAAG,SAAS,CAAA;IAC3D,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAChC,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;IACnC,mFAAmF;IACnF,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAChC;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAElD;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA"}
package/dist/editor.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- /** The lazily loaded part of the Next adapter: the editor and the preview toolbar, wired to Next and Payload. */
2
- import React from 'react';
3
1
  import type { OnPageMountProps } from './client.tsx';
4
- export declare function NextEditor(props: OnPageMountProps): React.JSX.Element | null;
5
- export declare function NextPreview(props: OnPageMountProps): React.JSX.Element;
2
+ export declare function NextEditor(props: OnPageMountProps): import("react").JSX.Element | null;
3
+ export declare function NextPreview(props: OnPageMountProps): import("react").JSX.Element;
6
4
  //# sourceMappingURL=editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AAEA,iHAAiH;AACjH,OAAO,KAAkB,MAAM,OAAO,CAAA;AAMtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AA+BpD,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,4BAwBjD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,qBAUlD"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAoCpD,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,sCAwBjD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAUlD"}
package/dist/editor.js CHANGED
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  /** The lazily loaded part of the Next adapter: the editor and the preview toolbar, wired to Next and Payload. */
4
4
  import { useMemo } from 'react';
5
5
  import { usePathname, useSearchParams } from 'next/navigation.js';
6
- import { DEFAULTS } from '@payload-onpage/core';
6
+ import { DEFAULTS, ROUTES } from '@payload-onpage/core';
7
7
  import { payloadRest, payloadUploads } from '@payload-onpage/core/payload';
8
8
  import { OnPageEditor, PreviewToolbar, inPreviewFrame } from '@payload-onpage/react';
9
9
  import { lexicalEditors } from '@payload-onpage/lexical';
@@ -14,14 +14,18 @@ function useHere() {
14
14
  const qs = search?.toString();
15
15
  return `${pathname}${qs ? `?${qs}` : ''}`;
16
16
  }
17
+ /** Routes resolved once, with the defaults applied. */
18
+ const routesOf = (props) => {
19
+ const api = props.apiRoute ?? DEFAULTS.apiRoute;
20
+ const prefix = props.prefix ?? DEFAULTS.routePrefix;
21
+ return { api, prefix, base: `${api}${prefix}`, admin: props.adminRoute ?? DEFAULTS.adminRoute };
22
+ };
17
23
  function useLinks(props) {
18
24
  const here = useHere();
19
- const api = props.apiRoute ?? DEFAULTS.apiRoute;
20
- const base = `${api}${props.prefix ?? DEFAULTS.routePrefix}`;
21
- const admin = props.adminRoute ?? DEFAULTS.adminRoute;
25
+ const { base, admin } = routesOf(props);
22
26
  return useMemo(() => ({
23
- exit: `${base}/exit?path=${encodeURIComponent(here)}`,
24
- mode: (mode) => `${base}/mode?mode=${mode}&path=${encodeURIComponent(here)}`,
27
+ exit: `${base}${ROUTES.exit}?path=${encodeURIComponent(here)}`,
28
+ mode: (mode) => `${base}${ROUTES.mode}?mode=${mode}&path=${encodeURIComponent(here)}`,
25
29
  admin: (ref) => ref.kind === 'global'
26
30
  ? `${admin}/globals/${ref.slug}`
27
31
  : `${admin}/collections/${ref.slug}/${ref.id}`,
@@ -32,8 +36,8 @@ export function NextEditor(props) {
32
36
  const locale = props.locale ?? htmlLang();
33
37
  const links = useLinks(props);
34
38
  const renderer = useNextRefresh();
35
- const api = props.apiRoute ?? DEFAULTS.apiRoute;
36
- const dataSource = useMemo(() => props.dataSource ?? payloadRest({ apiBase: api, prefix: props.prefix }), [props.dataSource, api, props.prefix]);
39
+ const { api, prefix } = routesOf(props);
40
+ const dataSource = useMemo(() => props.dataSource ?? payloadRest({ apiBase: api, prefix }), [props.dataSource, api, prefix]);
37
41
  const media = useMemo(() => props.media ?? payloadUploads({ apiBase: api }), [props.media, api]);
38
42
  const editors = useMemo(() => ({ ...lexicalEditors, ...props.editors }), [props.editors]);
39
43
  if (inPreviewFrame())
@@ -1 +1 @@
1
- {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,9 +7,9 @@ export * from "./session.js";
7
7
  * renders nothing otherwise. Static-safe: it reads cookies only in draft mode.
8
8
  */
9
9
  export async function OnPage({ mount: Mount = OnPageMount, ...props }) {
10
- const mode = await getOnPageMode();
10
+ const [mode, shared] = await Promise.all([getOnPageMode(), isSharedPreview()]);
11
11
  if (!mode)
12
12
  return null;
13
- return _jsx(Mount, { ...props, mode: mode, shared: await isSharedPreview() });
13
+ return _jsx(Mount, { ...props, mode: mode, shared: shared });
14
14
  }
15
15
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";AAcA,OAAO,EAAE,WAAW,EAAyB,MAAM,aAAc,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE7D,cAAc,cAAc,CAAA;AAgB5B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,WAAW,EAAE,GAAG,KAAK,EAAe;IAChF,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,OAAO,KAAC,KAAK,OAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,EAAE,GAAI,CAAA;AAC1E,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";AAcA,OAAO,EAAE,WAAW,EAAyB,MAAM,aAAc,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE7D,cAAc,cAAc,CAAA;AAgB5B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,WAAW,EAAE,GAAG,KAAK,EAAe;IAChF,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC,CAAA;IAC9E,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,OAAO,KAAC,KAAK,OAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAI,CAAA;AACzD,CAAC"}
package/dist/proxy.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { NextResponse, type NextRequest } from 'next/server.js';
1
+ import { type NextMiddleware, type NextRequest } from 'next/server.js';
2
2
  export interface OnPageProxyOptions {
3
3
  /** Same secret as the plugin (default: Payload's `secret`, i.e. PAYLOAD_SECRET). */
4
4
  secret: string | undefined;
5
5
  }
6
6
  /** Request headers for the rest of the pipeline, with draft mode injected for a valid grant. */
7
7
  export declare function withOnPage(request: NextRequest, opts: OnPageProxyOptions, headers?: Headers): Promise<Headers>;
8
- export declare function createOnPageProxy(opts: OnPageProxyOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
8
+ export declare function createOnPageProxy(opts: OnPageProxyOptions): NextMiddleware;
9
9
  //# sourceMappingURL=proxy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE/D,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3B;AAeD,gGAAgG;AAChG,wBAAsB,UAAU,CAC9B,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,kBAAkB,EACxB,OAAO,GAAE,OAAsC,GAC9C,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,IAK5B,SAAS,WAAW,oCAGjD"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEpF,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3B;AAQD,gGAAgG;AAChG,wBAAsB,UAAU,CAC9B,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,kBAAkB,EACxB,OAAO,GAAE,OAAsC,GAC9C,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,cAAc,CAQ1E"}
package/dist/proxy.js CHANGED
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * Already have one? `NextResponse.next({ request: { headers: await withOnPage(request, { secret }) } })`
15
15
  */
16
- import { COOKIE, HEADER, SEAL_PURPOSE, samePath, unseal } from '@payload-onpage/core';
16
+ import { COOKIE, HEADER, SEAL_PURPOSE, isLivePreviewGrant, samePath, unseal, } from '@payload-onpage/core';
17
17
  import { NextResponse } from 'next/server.js';
18
18
  const withoutCookies = (header, names) => (header ?? '')
19
19
  .split(';')
@@ -28,12 +28,8 @@ export async function withOnPage(request, opts, headers = new Headers(request.he
28
28
  if (!sealed || !opts.secret)
29
29
  return headers;
30
30
  const grant = await unseal(sealed, opts.secret, SEAL_PURPOSE.previewCookie);
31
- if (!grant ||
32
- typeof grant.draft !== 'string' ||
33
- grant.exp * 1000 <= Date.now() ||
34
- !samePath(path, grant.path)) {
31
+ if (!isLivePreviewGrant(grant) || !samePath(path, grant.path))
35
32
  return headers;
36
- }
37
33
  const cookie = withoutCookies(headers.get('cookie'), [COOKIE.nextDraft, COOKIE.mode]);
38
34
  cookie.push(`${COOKIE.nextDraft}=${grant.draft}`, `${COOKIE.mode}=view`);
39
35
  headers.set('cookie', cookie.join('; '));
package/dist/proxy.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAA;AAc/D,MAAM,cAAc,GAAG,CAAC,MAAqB,EAAE,KAAe,EAAE,EAAE,CAChE,CAAC,MAAM,IAAI,EAAE,CAAC;KACX,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAElE,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAoB,EACpB,IAAwB,EACxB,UAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;IAE/C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAA;IACrC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA,CAAC,iCAAiC;IAC/D,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAA;IACzD,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAA;IAC3C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAe,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,aAAa,CAAC,CAAA;IACzF,IACE,CAAC,KAAK;QACN,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;QAC/B,KAAK,CAAC,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE;QAC9B,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAC3B,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACrF,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,OAAO,CAAC,CAAA;IACxE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACxC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IACxD,IAAI,CAAC,IAAI,CAAC,MAAM;QACd,OAAO,CAAC,IAAI,CACV,+FAA+F,CAChG,CAAA;IACH,OAAO,KAAK,UAAU,KAAK,CAAC,OAAoB;QAC9C,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IACrF,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,MAAM,EACN,MAAM,EACN,YAAY,EACZ,kBAAkB,EAClB,QAAQ,EACR,MAAM,GACP,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAyC,MAAM,gBAAgB,CAAA;AAOpF,MAAM,cAAc,GAAG,CAAC,MAAqB,EAAE,KAAe,EAAE,EAAE,CAChE,CAAC,MAAM,IAAI,EAAE,CAAC;KACX,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAElE,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAoB,EACpB,IAAwB,EACxB,UAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;IAE/C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAA;IACrC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA,CAAC,iCAAiC;IAC/D,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAA;IACzD,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAA;IAC3C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,aAAa,CAAC,CAAA;IAC3E,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,OAAO,CAAA;IAC7E,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACrF,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,OAAO,CAAC,CAAA;IACxE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACxC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IACxD,IAAI,CAAC,IAAI,CAAC,MAAM;QACd,OAAO,CAAC,IAAI,CACV,+FAA+F,CAChG,CAAA;IACH,OAAO,KAAK,UAAU,KAAK,CAAC,OAAoB;QAC9C,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IACrF,CAAC,CAAA;AACH,CAAC"}
package/dist/session.d.ts CHANGED
@@ -12,31 +12,33 @@
12
12
  * draft mode is on. Next exempts that read from prerender bailout, so pages
13
13
  * stay static for visitors.
14
14
  */
15
- import { type OnPageMode, type SessionAdapter } from '@payload-onpage/core';
15
+ import { CONTEXT_KEY, type OnPageMode, type SessionAdapter } from '@payload-onpage/core';
16
16
  export interface NextSessionOptions {
17
17
  /** How long an editor's edit/preview mode lasts, in seconds. Default 12 hours. */
18
18
  maxAge?: number;
19
19
  }
20
20
  export declare function nextSession(opts?: NextSessionOptions): SessionAdapter;
21
21
  /** "edit", "view" or null for this request. Safe to call anywhere (returns null outside a request). */
22
- export declare function getOnPageMode(): Promise<OnPageMode | null>;
22
+ export declare const getOnPageMode: () => Promise<OnPageMode | null>;
23
23
  /**
24
24
  * Should this request render drafts? `draftMode().isEnabled`, except that an
25
25
  * editor whose session ended (signed out) no longer sees drafts. Draft mode
26
26
  * turned on by something else (your own preview route) is respected.
27
27
  */
28
- export declare function isDraftEnabled(): Promise<boolean>;
28
+ export declare const isDraftEnabled: () => Promise<boolean>;
29
29
  /** Is this request a preview-link view (set by the proxy)? */
30
- export declare function isSharedPreview(): Promise<boolean>;
30
+ export declare const isSharedPreview: () => Promise<boolean>;
31
+ /** What `onpageContext()` adds to a Payload read in edit mode. */
32
+ export type OnPageReadContext = {
33
+ context?: {
34
+ [CONTEXT_KEY]: true;
35
+ };
36
+ };
31
37
  /**
32
38
  * Spread into Payload reads that feed the page: in edit mode it turns on
33
39
  * auto-mapping markers, otherwise it is empty.
34
40
  *
35
41
  * payload.find({ collection: 'pages', where, draft, ...(await onpageContext()) })
36
42
  */
37
- export declare function onpageContext(): Promise<{
38
- context?: {
39
- onpage: true;
40
- };
41
- }>;
43
+ export declare function onpageContext(): Promise<OnPageReadContext>;
42
44
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAA0B,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGnG,MAAM,WAAW,kBAAkB;IACjC,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAyBD,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,CAuCzE;AAED,uGAAuG;AACvG,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAQhE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CASvD;AAED,8DAA8D;AAC9D,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAOxD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,CAAC,CAE7E"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,WAAW,EAKX,KAAK,UAAU,EACf,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAA;AAG7B,MAAM,WAAW,kBAAkB;IACjC,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AA0CD,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,CA2BzE;AAED,uGAAuG;AACvG,eAAO,MAAM,aAAa,QAAO,OAAO,CAAC,UAAU,GAAG,IAAI,CAIhD,CAAA;AAEV;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,OAAO,CAAC,OAAO,CAKtC,CAAA;AAEX,8DAA8D;AAC9D,eAAO,MAAM,eAAe,QAAO,OAAO,CAAC,OAAO,CACwB,CAAA;AAE1E,kEAAkE;AAClE,MAAM,MAAM,iBAAiB,GAAG;IAAE,OAAO,CAAC,EAAE;QAAE,CAAC,WAAW,CAAC,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,CAAA;AAErE;;;;;GAKG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAEhE"}
package/dist/session.js CHANGED
@@ -12,21 +12,35 @@
12
12
  * draft mode is on. Next exempts that read from prerender bailout, so pages
13
13
  * stay static for visitors.
14
14
  */
15
- import { COOKIE, HEADER, sha256 } from '@payload-onpage/core';
15
+ import { CONTEXT_KEY, COOKIE, HEADER, isOnPageMode, sha256, } from '@payload-onpage/core';
16
16
  import { cookies, draftMode, headers } from 'next/headers.js';
17
+ /** Our cookies: server-only, same-site, whole site. */
18
+ const cookieBase = (secure) => ({ httpOnly: true, sameSite: 'lax', secure, path: '/' });
19
+ /**
20
+ * Runs `read` only in draft mode, so visitors' requests never touch cookies and
21
+ * pages stay static. Outside a request (build, scripts) it returns `fallback`.
22
+ */
23
+ async function inDraft(read, fallback) {
24
+ try {
25
+ return (await draftMode()).isEnabled ? await read() : fallback;
26
+ }
27
+ catch {
28
+ return fallback;
29
+ }
30
+ }
17
31
  const HASH_LENGTH = 32;
18
32
  const fingerprint = async (token) => (await sha256(token)).slice(0, HASH_LENGTH);
19
33
  /** `edit` | `view`, or `<mode>:<authCookie>:<hash>` when bound to a session. */
20
34
  async function modeValue(mode, jar, bindTo) {
21
35
  const token = bindTo ? jar.get(bindTo)?.value : undefined;
22
- return token && bindTo ? `${mode}:${bindTo}:${await fingerprint(token)}` : mode;
36
+ return token ? `${mode}:${bindTo}:${await fingerprint(token)}` : mode;
23
37
  }
24
38
  /** The mode a cookie value grants in this request, or null (unknown, or the bound session is gone). */
25
39
  async function readMode(raw, jar) {
26
40
  if (!raw)
27
41
  return null;
28
42
  const [mode, bound, hash] = raw.split(':');
29
- if (mode !== 'edit' && mode !== 'view')
43
+ if (!isOnPageMode(mode))
30
44
  return null;
31
45
  if (bound) {
32
46
  const token = jar.get(bound)?.value;
@@ -42,13 +56,7 @@ export function nextSession(opts = {}) {
42
56
  ;
43
57
  (await draftMode()).enable();
44
58
  const jar = await cookies();
45
- jar.set(COOKIE.mode, await modeValue(mode, jar, bindTo), {
46
- httpOnly: true,
47
- sameSite: 'lax',
48
- secure,
49
- path: '/',
50
- maxAge,
51
- });
59
+ jar.set(COOKIE.mode, await modeValue(mode, jar, bindTo), { ...cookieBase(secure), maxAge });
52
60
  jar.delete(COOKIE.preview);
53
61
  },
54
62
  async enableLink({ secure, path: _path, expiresAt, seal }) {
@@ -61,13 +69,7 @@ export function nextSession(opts = {}) {
61
69
  // Keep the draft secret server-side: the browser only gets the sealed grant.
62
70
  jar.delete(COOKIE.nextDraft);
63
71
  jar.delete(COOKIE.mode);
64
- jar.set(COOKIE.preview, await seal(draft), {
65
- httpOnly: true,
66
- sameSite: 'lax',
67
- secure,
68
- path: '/',
69
- expires: expiresAt,
70
- });
72
+ jar.set(COOKIE.preview, await seal(draft), { ...cookieBase(secure), expires: expiresAt });
71
73
  },
72
74
  async disable() {
73
75
  ;
@@ -80,45 +82,22 @@ export function nextSession(opts = {}) {
80
82
  };
81
83
  }
82
84
  /** "edit", "view" or null for this request. Safe to call anywhere (returns null outside a request). */
83
- export async function getOnPageMode() {
84
- try {
85
- if (!(await draftMode()).isEnabled)
86
- return null;
87
- const jar = await cookies();
88
- return await readMode(jar.get(COOKIE.mode)?.value, jar);
89
- }
90
- catch {
91
- return null;
92
- }
93
- }
85
+ export const getOnPageMode = () => inDraft(async () => {
86
+ const jar = await cookies();
87
+ return readMode(jar.get(COOKIE.mode)?.value, jar);
88
+ }, null);
94
89
  /**
95
90
  * Should this request render drafts? `draftMode().isEnabled`, except that an
96
91
  * editor whose session ended (signed out) no longer sees drafts. Draft mode
97
92
  * turned on by something else (your own preview route) is respected.
98
93
  */
99
- export async function isDraftEnabled() {
100
- try {
101
- if (!(await draftMode()).isEnabled)
102
- return false;
103
- const jar = await cookies();
104
- const raw = jar.get(COOKIE.mode)?.value;
105
- return raw === undefined || (await readMode(raw, jar)) !== null;
106
- }
107
- catch {
108
- return false;
109
- }
110
- }
94
+ export const isDraftEnabled = () => inDraft(async () => {
95
+ const jar = await cookies();
96
+ const raw = jar.get(COOKIE.mode)?.value;
97
+ return raw === undefined || (await readMode(raw, jar)) !== null;
98
+ }, false);
111
99
  /** Is this request a preview-link view (set by the proxy)? */
112
- export async function isSharedPreview() {
113
- try {
114
- if (!(await draftMode()).isEnabled)
115
- return false;
116
- return (await headers()).get(HEADER.shared) === '1';
117
- }
118
- catch {
119
- return false;
120
- }
121
- }
100
+ export const isSharedPreview = () => inDraft(async () => (await headers()).get(HEADER.shared) === '1', false);
122
101
  /**
123
102
  * Spread into Payload reads that feed the page: in edit mode it turns on
124
103
  * auto-mapping markers, otherwise it is empty.
@@ -126,6 +105,6 @@ export async function isSharedPreview() {
126
105
  * payload.find({ collection: 'pages', where, draft, ...(await onpageContext()) })
127
106
  */
128
107
  export async function onpageContext() {
129
- return (await getOnPageMode()) === 'edit' ? { context: { onpage: true } } : {};
108
+ return (await getOnPageMode()) === 'edit' ? { context: { [CONTEXT_KEY]: true } } : {};
130
109
  }
131
110
  //# sourceMappingURL=session.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,WAAW,EACX,MAAM,EACN,MAAM,EACN,YAAY,EACZ,MAAM,GAGP,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAU7D,uDAAuD;AACvD,MAAM,UAAU,GAAG,CAAC,MAAe,EAAE,EAAE,CACrC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAyB,CAAA;AAElF;;;GAGG;AACH,KAAK,UAAU,OAAO,CAAI,IAAsB,EAAE,QAAW;IAC3D,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAA;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAA;IACjB,CAAC;AACH,CAAC;AAED,MAAM,WAAW,GAAG,EAAE,CAAA;AACtB,MAAM,WAAW,GAAG,KAAK,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAA;AAExF,gFAAgF;AAChF,KAAK,UAAU,SAAS,CAAC,IAAgB,EAAE,GAAQ,EAAE,MAAe;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IACzD,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACvE,CAAC;AAED,uGAAuG;AACvG,KAAK,UAAU,QAAQ,CAAC,GAAuB,EAAE,GAAQ;IACvD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAA;IACrB,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC1C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACpC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,CAAA;QACnC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAA;IAChE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAA2B,EAAE;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,IAAI,CAAA;IACvC,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;YACnC,CAAC;YAAA,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;YAC7B,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;YAC3B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;YAC3F,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAC5B,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;YACvD,CAAC;YAAA,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;YAC7B,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;YAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,KAAK,CAAA;YAC9C,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;YACxF,6EAA6E;YAC7E,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC5B,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACvB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;QAC3F,CAAC;QACD,KAAK,CAAC,OAAO;YACX,CAAC;YAAA,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA;YAC9B,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;YAC3B,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACvB,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,EAAE,aAAa;KACvB,CAAA;AACH,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,MAAM,aAAa,GAAG,GAA+B,EAAE,CAC5D,OAAO,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;IAC3B,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;AACnD,CAAC,EAAE,IAAI,CAAC,CAAA;AAEV;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,GAAqB,EAAE,CACnD,OAAO,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;IAC3B,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,CAAA;IACvC,OAAO,GAAG,KAAK,SAAS,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAA;AACjE,CAAC,EAAE,KAAK,CAAC,CAAA;AAEX,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAqB,EAAE,CACpD,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,KAAK,CAAC,CAAA;AAK1E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,OAAO,CAAC,MAAM,aAAa,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AACvF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payload-onpage/next",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "payload-onpage for Next.js App Router: draft-mode session adapter, <OnPage />, onpageContext() and refresh rendering.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -15,12 +15,23 @@
15
15
  "keywords": [
16
16
  "payload",
17
17
  "payloadcms",
18
+ "payload-cms",
18
19
  "payload-plugin",
19
20
  "nextjs",
21
+ "next.js",
22
+ "app-router",
20
23
  "visual-editing",
21
- "live-preview",
24
+ "visual-editor",
22
25
  "inline-editing",
23
- "cms"
26
+ "front-end-editing",
27
+ "live-preview",
28
+ "draft-preview",
29
+ "preview-links",
30
+ "page-builder",
31
+ "wysiwyg",
32
+ "headless-cms",
33
+ "cms",
34
+ "react"
24
35
  ],
25
36
  "exports": {
26
37
  ".": {
@@ -61,9 +72,9 @@
61
72
  "provenance": true
62
73
  },
63
74
  "dependencies": {
64
- "@payload-onpage/core": "0.2.1",
65
- "@payload-onpage/react": "0.2.1",
66
- "@payload-onpage/lexical": "0.2.1"
75
+ "@payload-onpage/core": "0.3.1",
76
+ "@payload-onpage/react": "0.3.1",
77
+ "@payload-onpage/lexical": "0.3.1"
67
78
  },
68
79
  "peerDependencies": {
69
80
  "next": "^15.4.11 || ^16.3.8",
package/src/client.tsx CHANGED
@@ -5,28 +5,28 @@
5
5
  * is loaded only when someone is editing or previewing.
6
6
  */
7
7
  import dynamic from 'next/dynamic.js'
8
- import type { DataSource, Locator, MediaLibrary } from '@payload-onpage/core'
8
+ import type { DataSource, Locator, MediaLibrary, OnPageMode } from '@payload-onpage/core'
9
9
  import type { FieldEditorDef, Messages } from '@payload-onpage/react'
10
10
 
11
11
  export interface OnPageMountProps {
12
- mode: 'edit' | 'view'
12
+ mode: OnPageMode
13
13
  /** Opened from a shared preview link (no editing). */
14
- shared?: boolean
14
+ shared?: boolean | undefined
15
15
  /** Payload API route. Default "/api". */
16
- apiRoute?: string
16
+ apiRoute?: string | undefined
17
17
  /** Plugin endpoint prefix. Default "/onpage". */
18
- prefix?: string
18
+ prefix?: `/${string}` | undefined
19
19
  /** Payload admin route. Default "/admin". */
20
- adminRoute?: string
20
+ adminRoute?: string | undefined
21
21
  /** Locale to edit. Default: <html lang>. */
22
- locale?: string
22
+ locale?: string | undefined
23
23
  // Client-only options (pass them from your own 'use client' mount):
24
- editors?: Record<string, FieldEditorDef | null>
25
- locator?: Locator
26
- media?: MediaLibrary
27
- dataSource?: DataSource
24
+ editors?: Record<string, FieldEditorDef | null> | undefined
25
+ locator?: Locator | undefined
26
+ media?: MediaLibrary | undefined
27
+ dataSource?: DataSource | undefined
28
28
  /** Override editor UI strings (see `defaultMessages` in @payload-onpage/react). */
29
- messages?: Messages
29
+ messages?: Messages | undefined
30
30
  }
31
31
 
32
32
  const Editor = dynamic(() => import('./editor.tsx').then((m) => m.NextEditor), { ssr: false })
package/src/editor.tsx CHANGED
@@ -1,9 +1,9 @@
1
1
  'use client'
2
2
 
3
3
  /** The lazily loaded part of the Next adapter: the editor and the preview toolbar, wired to Next and Payload. */
4
- import React, { useMemo } from 'react'
4
+ import { useMemo } from 'react'
5
5
  import { usePathname, useSearchParams } from 'next/navigation.js'
6
- import { DEFAULTS, type DocRef } from '@payload-onpage/core'
6
+ import { DEFAULTS, ROUTES, type DocRef } from '@payload-onpage/core'
7
7
  import { payloadRest, payloadUploads } from '@payload-onpage/core/payload'
8
8
  import { OnPageEditor, PreviewToolbar, inPreviewFrame, type Links } from '@payload-onpage/react'
9
9
  import { lexicalEditors } from '@payload-onpage/lexical'
@@ -17,15 +17,20 @@ function useHere(): string {
17
17
  return `${pathname}${qs ? `?${qs}` : ''}`
18
18
  }
19
19
 
20
+ /** Routes resolved once, with the defaults applied. */
21
+ const routesOf = (props: OnPageMountProps) => {
22
+ const api = props.apiRoute ?? DEFAULTS.apiRoute
23
+ const prefix = props.prefix ?? DEFAULTS.routePrefix
24
+ return { api, prefix, base: `${api}${prefix}`, admin: props.adminRoute ?? DEFAULTS.adminRoute }
25
+ }
26
+
20
27
  function useLinks(props: OnPageMountProps): Links {
21
28
  const here = useHere()
22
- const api = props.apiRoute ?? DEFAULTS.apiRoute
23
- const base = `${api}${props.prefix ?? DEFAULTS.routePrefix}`
24
- const admin = props.adminRoute ?? DEFAULTS.adminRoute
29
+ const { base, admin } = routesOf(props)
25
30
  return useMemo<Links>(
26
31
  () => ({
27
- exit: `${base}/exit?path=${encodeURIComponent(here)}`,
28
- mode: (mode) => `${base}/mode?mode=${mode}&path=${encodeURIComponent(here)}`,
32
+ exit: `${base}${ROUTES.exit}?path=${encodeURIComponent(here)}`,
33
+ mode: (mode) => `${base}${ROUTES.mode}?mode=${mode}&path=${encodeURIComponent(here)}`,
29
34
  admin: (ref: DocRef) =>
30
35
  ref.kind === 'global'
31
36
  ? `${admin}/globals/${ref.slug}`
@@ -42,10 +47,10 @@ export function NextEditor(props: OnPageMountProps) {
42
47
  const locale = props.locale ?? htmlLang()
43
48
  const links = useLinks(props)
44
49
  const renderer = useNextRefresh()
45
- const api = props.apiRoute ?? DEFAULTS.apiRoute
50
+ const { api, prefix } = routesOf(props)
46
51
  const dataSource = useMemo(
47
- () => props.dataSource ?? payloadRest({ apiBase: api, prefix: props.prefix }),
48
- [props.dataSource, api, props.prefix],
52
+ () => props.dataSource ?? payloadRest({ apiBase: api, prefix }),
53
+ [props.dataSource, api, prefix],
49
54
  )
50
55
  const media = useMemo(() => props.media ?? payloadUploads({ apiBase: api }), [props.media, api])
51
56
  const editors = useMemo(() => ({ ...lexicalEditors, ...props.editors }), [props.editors])
package/src/index.tsx CHANGED
@@ -36,7 +36,7 @@ export interface OnPageProps extends Omit<OnPageMountProps, ClientOnly> {
36
36
  * renders nothing otherwise. Static-safe: it reads cookies only in draft mode.
37
37
  */
38
38
  export async function OnPage({ mount: Mount = OnPageMount, ...props }: OnPageProps) {
39
- const mode = await getOnPageMode()
39
+ const [mode, shared] = await Promise.all([getOnPageMode(), isSharedPreview()])
40
40
  if (!mode) return null
41
- return <Mount {...props} mode={mode} shared={await isSharedPreview()} />
41
+ return <Mount {...props} mode={mode} shared={shared} />
42
42
  }
package/src/proxy.ts CHANGED
@@ -13,21 +13,21 @@
13
13
  *
14
14
  * Already have one? `NextResponse.next({ request: { headers: await withOnPage(request, { secret }) } })`
15
15
  */
16
- import { COOKIE, HEADER, SEAL_PURPOSE, samePath, unseal } from '@payload-onpage/core'
17
- import { NextResponse, type NextRequest } from 'next/server.js'
16
+ import {
17
+ COOKIE,
18
+ HEADER,
19
+ SEAL_PURPOSE,
20
+ isLivePreviewGrant,
21
+ samePath,
22
+ unseal,
23
+ } from '@payload-onpage/core'
24
+ import { NextResponse, type NextMiddleware, type NextRequest } from 'next/server.js'
18
25
 
19
26
  export interface OnPageProxyOptions {
20
27
  /** Same secret as the plugin (default: Payload's `secret`, i.e. PAYLOAD_SECRET). */
21
28
  secret: string | undefined
22
29
  }
23
30
 
24
- interface PreviewGrant {
25
- path: string
26
- ref: string
27
- exp: number
28
- draft: string
29
- }
30
-
31
31
  const withoutCookies = (header: string | null, names: string[]) =>
32
32
  (header ?? '')
33
33
  .split(';')
@@ -45,15 +45,8 @@ export async function withOnPage(
45
45
  headers.set(HEADER.path, path)
46
46
  const sealed = request.cookies.get(COOKIE.preview)?.value
47
47
  if (!sealed || !opts.secret) return headers
48
- const grant = await unseal<PreviewGrant>(sealed, opts.secret, SEAL_PURPOSE.previewCookie)
49
- if (
50
- !grant ||
51
- typeof grant.draft !== 'string' ||
52
- grant.exp * 1000 <= Date.now() ||
53
- !samePath(path, grant.path)
54
- ) {
55
- return headers
56
- }
48
+ const grant = await unseal(sealed, opts.secret, SEAL_PURPOSE.previewCookie)
49
+ if (!isLivePreviewGrant(grant) || !samePath(path, grant.path)) return headers
57
50
  const cookie = withoutCookies(headers.get('cookie'), [COOKIE.nextDraft, COOKIE.mode])
58
51
  cookie.push(`${COOKIE.nextDraft}=${grant.draft}`, `${COOKIE.mode}=view`)
59
52
  headers.set('cookie', cookie.join('; '))
@@ -61,7 +54,7 @@ export async function withOnPage(
61
54
  return headers
62
55
  }
63
56
 
64
- export function createOnPageProxy(opts: OnPageProxyOptions) {
57
+ export function createOnPageProxy(opts: OnPageProxyOptions): NextMiddleware {
65
58
  if (!opts.secret)
66
59
  console.warn(
67
60
  'payload-onpage: createOnPageProxy() has no secret; preview links will show published content.',
package/src/session.ts CHANGED
@@ -12,7 +12,15 @@
12
12
  * draft mode is on. Next exempts that read from prerender bailout, so pages
13
13
  * stay static for visitors.
14
14
  */
15
- import { COOKIE, HEADER, sha256, type OnPageMode, type SessionAdapter } from '@payload-onpage/core'
15
+ import {
16
+ CONTEXT_KEY,
17
+ COOKIE,
18
+ HEADER,
19
+ isOnPageMode,
20
+ sha256,
21
+ type OnPageMode,
22
+ type SessionAdapter,
23
+ } from '@payload-onpage/core'
16
24
  import { cookies, draftMode, headers } from 'next/headers.js'
17
25
 
18
26
  export interface NextSessionOptions {
@@ -21,6 +29,23 @@ export interface NextSessionOptions {
21
29
  }
22
30
 
23
31
  type Jar = Awaited<ReturnType<typeof cookies>>
32
+ type CookieOptions = NonNullable<Parameters<Jar['set']>[2]>
33
+
34
+ /** Our cookies: server-only, same-site, whole site. */
35
+ const cookieBase = (secure: boolean) =>
36
+ ({ httpOnly: true, sameSite: 'lax', secure, path: '/' }) satisfies CookieOptions
37
+
38
+ /**
39
+ * Runs `read` only in draft mode, so visitors' requests never touch cookies and
40
+ * pages stay static. Outside a request (build, scripts) it returns `fallback`.
41
+ */
42
+ async function inDraft<T>(read: () => Promise<T>, fallback: T): Promise<T> {
43
+ try {
44
+ return (await draftMode()).isEnabled ? await read() : fallback
45
+ } catch {
46
+ return fallback
47
+ }
48
+ }
24
49
 
25
50
  const HASH_LENGTH = 32
26
51
  const fingerprint = async (token: string) => (await sha256(token)).slice(0, HASH_LENGTH)
@@ -28,14 +53,14 @@ const fingerprint = async (token: string) => (await sha256(token)).slice(0, HASH
28
53
  /** `edit` | `view`, or `<mode>:<authCookie>:<hash>` when bound to a session. */
29
54
  async function modeValue(mode: OnPageMode, jar: Jar, bindTo?: string): Promise<string> {
30
55
  const token = bindTo ? jar.get(bindTo)?.value : undefined
31
- return token && bindTo ? `${mode}:${bindTo}:${await fingerprint(token)}` : mode
56
+ return token ? `${mode}:${bindTo}:${await fingerprint(token)}` : mode
32
57
  }
33
58
 
34
59
  /** The mode a cookie value grants in this request, or null (unknown, or the bound session is gone). */
35
60
  async function readMode(raw: string | undefined, jar: Jar): Promise<OnPageMode | null> {
36
61
  if (!raw) return null
37
62
  const [mode, bound, hash] = raw.split(':')
38
- if (mode !== 'edit' && mode !== 'view') return null
63
+ if (!isOnPageMode(mode)) return null
39
64
  if (bound) {
40
65
  const token = jar.get(bound)?.value
41
66
  if (!token || (await fingerprint(token)) !== hash) return null
@@ -49,13 +74,7 @@ export function nextSession(opts: NextSessionOptions = {}): SessionAdapter {
49
74
  async enable(mode, { secure, bindTo }) {
50
75
  ;(await draftMode()).enable()
51
76
  const jar = await cookies()
52
- jar.set(COOKIE.mode, await modeValue(mode, jar, bindTo), {
53
- httpOnly: true,
54
- sameSite: 'lax',
55
- secure,
56
- path: '/',
57
- maxAge,
58
- })
77
+ jar.set(COOKIE.mode, await modeValue(mode, jar, bindTo), { ...cookieBase(secure), maxAge })
59
78
  jar.delete(COOKIE.preview)
60
79
  },
61
80
  async enableLink({ secure, path: _path, expiresAt, seal }) {
@@ -66,13 +85,7 @@ export function nextSession(opts: NextSessionOptions = {}): SessionAdapter {
66
85
  // Keep the draft secret server-side: the browser only gets the sealed grant.
67
86
  jar.delete(COOKIE.nextDraft)
68
87
  jar.delete(COOKIE.mode)
69
- jar.set(COOKIE.preview, await seal(draft), {
70
- httpOnly: true,
71
- sameSite: 'lax',
72
- secure,
73
- path: '/',
74
- expires: expiresAt,
75
- })
88
+ jar.set(COOKIE.preview, await seal(draft), { ...cookieBase(secure), expires: expiresAt })
76
89
  },
77
90
  async disable() {
78
91
  ;(await draftMode()).disable()
@@ -85,41 +98,30 @@ export function nextSession(opts: NextSessionOptions = {}): SessionAdapter {
85
98
  }
86
99
 
87
100
  /** "edit", "view" or null for this request. Safe to call anywhere (returns null outside a request). */
88
- export async function getOnPageMode(): Promise<OnPageMode | null> {
89
- try {
90
- if (!(await draftMode()).isEnabled) return null
101
+ export const getOnPageMode = (): Promise<OnPageMode | null> =>
102
+ inDraft(async () => {
91
103
  const jar = await cookies()
92
- return await readMode(jar.get(COOKIE.mode)?.value, jar)
93
- } catch {
94
- return null
95
- }
96
- }
104
+ return readMode(jar.get(COOKIE.mode)?.value, jar)
105
+ }, null)
97
106
 
98
107
  /**
99
108
  * Should this request render drafts? `draftMode().isEnabled`, except that an
100
109
  * editor whose session ended (signed out) no longer sees drafts. Draft mode
101
110
  * turned on by something else (your own preview route) is respected.
102
111
  */
103
- export async function isDraftEnabled(): Promise<boolean> {
104
- try {
105
- if (!(await draftMode()).isEnabled) return false
112
+ export const isDraftEnabled = (): Promise<boolean> =>
113
+ inDraft(async () => {
106
114
  const jar = await cookies()
107
115
  const raw = jar.get(COOKIE.mode)?.value
108
116
  return raw === undefined || (await readMode(raw, jar)) !== null
109
- } catch {
110
- return false
111
- }
112
- }
117
+ }, false)
113
118
 
114
119
  /** Is this request a preview-link view (set by the proxy)? */
115
- export async function isSharedPreview(): Promise<boolean> {
116
- try {
117
- if (!(await draftMode()).isEnabled) return false
118
- return (await headers()).get(HEADER.shared) === '1'
119
- } catch {
120
- return false
121
- }
122
- }
120
+ export const isSharedPreview = (): Promise<boolean> =>
121
+ inDraft(async () => (await headers()).get(HEADER.shared) === '1', false)
122
+
123
+ /** What `onpageContext()` adds to a Payload read in edit mode. */
124
+ export type OnPageReadContext = { context?: { [CONTEXT_KEY]: true } }
123
125
 
124
126
  /**
125
127
  * Spread into Payload reads that feed the page: in edit mode it turns on
@@ -127,6 +129,6 @@ export async function isSharedPreview(): Promise<boolean> {
127
129
  *
128
130
  * payload.find({ collection: 'pages', where, draft, ...(await onpageContext()) })
129
131
  */
130
- export async function onpageContext(): Promise<{ context?: { onpage: true } }> {
131
- return (await getOnPageMode()) === 'edit' ? { context: { onpage: true } } : {}
132
+ export async function onpageContext(): Promise<OnPageReadContext> {
133
+ return (await getOnPageMode()) === 'edit' ? { context: { [CONTEXT_KEY]: true } } : {}
132
134
  }