@decocms/nextjs 8.5.2 → 8.7.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 (51) hide show
  1. package/README.md +82 -15
  2. package/dist/DraftPreviewIndicator.d.ts.map +1 -1
  3. package/dist/DraftPreviewIndicator.js +4 -3
  4. package/dist/DraftPreviewIndicator.js.map +1 -1
  5. package/dist/assignments.d.ts +95 -0
  6. package/dist/assignments.d.ts.map +1 -0
  7. package/dist/assignments.js +229 -0
  8. package/dist/assignments.js.map +1 -0
  9. package/dist/draft.d.ts +36 -10
  10. package/dist/draft.d.ts.map +1 -1
  11. package/dist/draft.js +38 -12
  12. package/dist/draft.js.map +1 -1
  13. package/dist/drafts.d.ts +39 -60
  14. package/dist/drafts.d.ts.map +1 -1
  15. package/dist/drafts.js +58 -117
  16. package/dist/drafts.js.map +1 -1
  17. package/dist/index.d.ts +5 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +5 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/instrumentation/index.d.ts +1 -1
  22. package/dist/instrumentation/index.js +3 -3
  23. package/dist/instrumentation/index.js.map +1 -1
  24. package/dist/proxy/index.d.ts +175 -35
  25. package/dist/proxy/index.d.ts.map +1 -1
  26. package/dist/proxy/index.js +242 -41
  27. package/dist/proxy/index.js.map +1 -1
  28. package/dist/server/index.d.ts +59 -20
  29. package/dist/server/index.d.ts.map +1 -1
  30. package/dist/server/index.js +143 -25
  31. package/dist/server/index.js.map +1 -1
  32. package/dist/server/slot.d.ts +25 -4
  33. package/dist/server/slot.d.ts.map +1 -1
  34. package/dist/server/slot.js +13 -9
  35. package/dist/server/slot.js.map +1 -1
  36. package/dist/visitor.d.ts +16 -0
  37. package/dist/visitor.d.ts.map +1 -0
  38. package/dist/visitor.js +16 -0
  39. package/dist/visitor.js.map +1 -0
  40. package/package.json +3 -3
  41. package/src/DraftPreviewIndicator.tsx +4 -3
  42. package/src/assignments.ts +278 -0
  43. package/src/config/index.cjs +1 -1
  44. package/src/draft.ts +43 -12
  45. package/src/drafts.ts +71 -126
  46. package/src/index.ts +5 -2
  47. package/src/instrumentation/index.ts +3 -3
  48. package/src/proxy/index.ts +371 -59
  49. package/src/server/index.ts +173 -33
  50. package/src/server/slot.ts +33 -5
  51. package/src/visitor.ts +16 -0
@@ -1,5 +1,6 @@
1
1
  /**
2
- * `@decocms/nextjs/proxy`: draft previews in a Next.js proxy (`proxy.ts`, or
2
+ * `@decocms/nextjs/proxy`: draft previews, the visitor and what a request's
3
+ * content gives it, decided once, in a Next.js proxy (`proxy.ts`, or
3
4
  * `middleware.ts` before Next 16). No React and no block map: pass the proxy
4
5
  * a CMS handle made with an empty block map and the app's options, which
5
6
  * shares the app's instance (one per process) without pulling the site's
@@ -10,73 +11,212 @@
10
11
  * export const proxyCms = createCMS({ blocks: {}, ...cmsConfig });
11
12
  * ```
12
13
  *
13
- * A site with a proxy of its own calls the pieces (`decideDraft`, then
14
- * `draftRequestHeaders` on the request it forwards, then `applyDraft` on the
15
- * response); a site without one exports `draftProxy(...)`.
14
+ * A site with a proxy of its own calls the pieces (`decideDraft`,
15
+ * `decideVisitor` and `decideAssignments`, then `draftRequestHeaders`,
16
+ * `visitorRequestHeaders` and `assignmentsRequestHeaders` on the request it
17
+ * forwards, then `applyDraft` and `applyVisitor` on the response); a site
18
+ * without one exports `draftProxy(...)`.
16
19
  *
17
- * Statically rendered pages can't read a draft, so a drafted request to one
18
- * is rewritten onto a dynamic draft route (`/_draft/<path>`, mounted as
20
+ * The proxy decides: the version (`decideDraft`: a Studio link's draft or old
21
+ * release, after the host allowlist, with the preview's moment and switched
22
+ * tests and campaigns), the visitor (`decideVisitor`: `readVisitor` from
23
+ * `@decocms/blocks/experiments`, the `deco_segment` cookie or a new visitor)
24
+ * and, from both, each test and campaign on or off (`decideAssignments`:
25
+ * `cms.client({ version, visitor, date, experiments, campaigns })` resolving
26
+ * the saved `experiments` and `campaigns` blocks). It forwards them on
27
+ * `x-deco-version`, `x-deco-visitor` and `x-deco-assignments` (copies from
28
+ * outside are always removed), and the page builds
29
+ * `cms.client({ version, experiments, campaigns })` from them
30
+ * (`contentClient`), deciding nothing again. It sends the visitor's cookie on
31
+ * a first visit only, never from a preview.
32
+ *
33
+ * Cached (ISR) pages can't read a request, so a preview request (any draft
34
+ * signal: `?__draft=` with any value, `off` included, or the draft cookie) is
35
+ * rewritten onto a dynamic draft route, never cached, and answers
36
+ * `Cache-Control: max-age=0, no-cache, must-revalidate`; a drafted request
37
+ * is rewritten onto it (`/_draft/<path>`, mounted as
19
38
  * `app/%5Fdraft/...`: a literal `_draft` folder is private in Next and never
20
- * routes).
39
+ * routes), and a published one onto the assignments route
40
+ * (`/_assignments/<assignments>/<path>`, `rewriteToAssignmentsRoute`), where
41
+ * `assignedClient` from `@decocms/nextjs/server` builds the client from the
42
+ * path.
43
+ *
44
+ * The binding caches nothing. A site that caches in front of its pages (a
45
+ * CDN keyed on a request header) keys on the request's assignments, never on
46
+ * the visitor: `assignmentsKey(await decideAssignments(proxyCms, draft,
47
+ * visitor))`, `""` when there are none.
21
48
  *
22
49
  * The proxy measures no requests: it runs before Next routes and renders the
23
50
  * page. `http.server.request.duration` comes from Next's own request span
24
51
  * (`register` from `@decocms/nextjs/instrumentation`).
25
52
  */
26
- import type { CMS } from "@decocms/blocks";
53
+ import type { CMS, RequestVersion } from "@decocms/blocks";
54
+ import { type Visitor } from "@decocms/blocks/experiments";
27
55
  import { type NextRequest, NextResponse } from "next/server.js";
28
- import { type PreviewPolicy } from "../drafts.ts";
29
- export { inferredPreviewHosts, type PreviewPolicy, previewHostDecision, requestLike, } from "../drafts.ts";
30
- /** What the proxy needs from the CMS: the site's declared preview hosts and their check. */
31
- export type CMSHandle = Pick<CMS, "draftPointer" | "settings" | "forRelease">;
56
+ import { type RequestAssignments } from "../assignments.ts";
57
+ export { requestLike } from "../drafts.ts";
58
+ /**
59
+ * What the draft decision needs from the CMS: its preview host check, the
60
+ * release, and the draft a link names (read once before the page renders).
61
+ */
62
+ export type CMSHandle = Pick<CMS, "readVersion" | "forRelease" | "forDraft" | "checkRelease">;
32
63
  /** What the proxy does with a request's draft state. */
33
64
  export interface DraftDecision {
34
- /** The draft this request renders, after the host check; `null` for the release. */
35
- pointer: string | null;
36
- /** The `Set-Cookie` the response carries: storing a draft link's pointer, or ending a preview. */
65
+ /**
66
+ * What this request's Studio link asks for, after the host check: the
67
+ * version (a draft pointer, or a release's commit SHA) and the preview's
68
+ * moment and switched tests and campaigns, in the shape of
69
+ * `cms.client()`'s options; `null` for the current release.
70
+ */
71
+ version: RequestVersion | null;
72
+ /** The `Set-Cookie` the response carries: storing a link's version, or ending a preview. */
37
73
  setCookie: string | null;
74
+ /**
75
+ * The request carries a draft signal at all (`?__draft=` with any value, or
76
+ * the draft cookie): it renders on the draft route, never from a cache,
77
+ * and answers `draftResponseHeaders`, whatever `version` is.
78
+ */
79
+ preview?: boolean;
80
+ /**
81
+ * The link named a draft that can't be read (deleted, or its host
82
+ * failing): the release renders, the cookie is expired when the draft is
83
+ * gone (a failure that may pass leaves it), and the pages show
84
+ * the calm notice (`x-deco-draft-unavailable`), never an error page.
85
+ */
86
+ unavailable?: true;
87
+ /**
88
+ * The release check made for this draft request (`cms.checkRelease()`),
89
+ * forwarded on `x-deco-release-check`: the host check, the draft read here
90
+ * and the page's all wait for it, so the request reads `latest.json` once.
91
+ */
92
+ releaseCheck?: string;
38
93
  }
39
- export { DRAFT_ROUTE_PREFIX } from "../draft.ts";
94
+ export { ASSIGNMENTS_HEADER, ASSIGNMENTS_ROUTE_PREFIX, assignmentsKey, assignmentsRoutePath, assignmentsSegment, isAssignmentsRoutePath, type PathAssignments, parseAssignmentsSegment, type RequestAssignments, readAssignments, } from "../assignments.ts";
95
+ export { DRAFT_ROUTE_PREFIX, VERSION_HEADER } from "../draft.ts";
40
96
  /**
41
- * The draft a request renders and the cookie its response sets, under
42
- * `policy` (the same options the pages pass to `bindDraft`). A request with
43
- * no `?__draft=` and no draft cookie never reaches the CMS.
97
+ * The version a request renders and the cookie its response sets, on a host
98
+ * the CMS allows (as the pages' `bindDraft` checks again). A request with
99
+ * no `?__draft=` and no draft cookie never reaches the CMS. A draft request
100
+ * checks for the latest release once (`cms.checkRelease()`), shared by the
101
+ * host check, the read below and the page. A draft pointer
102
+ * is read once here (`forDraft(...).revision()`, the read the page makes
103
+ * again): a draft that can't be read gives the release and `unavailable`.
44
104
  */
45
- export declare function decideDraft(cms: CMSHandle, request: NextRequest | Request, policy?: PreviewPolicy): Promise<DraftDecision>;
105
+ export declare function decideDraft(cms: CMSHandle, request: NextRequest | Request): Promise<DraftDecision>;
46
106
  /**
47
- * The request headers to forward: the accepted pointer on `x-deco-draft`, so
48
- * the root layout can bind the draft on the same request (a layout gets no
107
+ * The request headers to forward: the accepted version on `x-deco-version`,
108
+ * so the root layout can bind the draft on the same request (a layout gets no
49
109
  * `searchParams`, and on a draft link the cookie is only on the response).
50
- * A copy that arrives from outside is always removed.
110
+ * A copy that arrives from outside is always removed, and so are any
111
+ * `x-deco-visitor` and `x-deco-assignments` (`visitorRequestHeaders` and
112
+ * `assignmentsRequestHeaders` set the proxy's own).
51
113
  */
52
114
  export declare function draftRequestHeaders(request: NextRequest | Request, decision: DraftDecision): Headers;
115
+ /** The visitor of one request. */
116
+ export interface VisitorDecision {
117
+ /** Who is visiting: the `deco_segment` cookie's visitor, or a new one. */
118
+ visitor: Visitor;
119
+ /** The `deco_segment` `Set-Cookie`, on a first visit to the live site; `null` otherwise. */
120
+ setCookie: string | null;
121
+ }
122
+ /**
123
+ * The visitor of a request (`readVisitor`: the `deco_segment` cookie, or a
124
+ * new visitor when it had no id) and the cookie to send back, only on a first
125
+ * visit and never from a preview (`draft` holds a version): Studio is not a
126
+ * visitor. Reads no content.
127
+ */
128
+ export declare function decideVisitor(request: NextRequest | Request, draft: DraftDecision): VisitorDecision;
129
+ /**
130
+ * The forwarded headers with the visitor on `x-deco-visitor`. Pass it the
131
+ * headers `draftRequestHeaders` gave, which already removed a copy from
132
+ * outside.
133
+ */
134
+ export declare function visitorRequestHeaders(headers: Headers, decision: VisitorDecision): Headers;
135
+ /** The `deco_segment` cookie on the response, on a first visit. */
136
+ export declare function applyVisitor<R extends Response>(response: R, decision: VisitorDecision): R;
137
+ /**
138
+ * Each test and campaign on or off for this request, decided once:
139
+ * `cms.client({ visitor, ...version, releaseCheck })` (the visitor, the Studio
140
+ * link's version, moment and switched tests and campaigns, and the request's
141
+ * release check) resolving the saved
142
+ * `experiments` and `campaigns` blocks. Missing blocks, or content that
143
+ * doesn't load, give none, never an error.
144
+ */
145
+ export declare function decideAssignments(cms: Pick<CMS, "client">, draft: DraftDecision, visitor: VisitorDecision): Promise<RequestAssignments>;
146
+ /**
147
+ * The forwarded headers with the decided tests and campaigns on
148
+ * `x-deco-assignments` (`assignmentsSegment`), for `bindDraft` and
149
+ * `contentClient`. Pass it the headers `draftRequestHeaders` gave.
150
+ */
151
+ export declare function assignmentsRequestHeaders(headers: Headers, assignments: RequestAssignments): Headers;
53
152
  /** Whether `pathname` is on the draft route: a site answers a direct hit there with its 404. */
54
153
  export declare function isDraftRoutePath(pathname: string): boolean;
55
154
  /**
56
- * The rewrite of a drafted request onto the draft route, keeping its path and
57
- * forwarding the pointer; `null` when the request isn't drafted or is already
58
- * on the draft route.
155
+ * The rewrite of a preview request (a drafted one, or any other with a draft
156
+ * signal: `off`, a refused host, a draft that can't be read) onto the draft
157
+ * route, which is dynamic and never cached, keeping its path and forwarding
158
+ * the version and, when given, the visitor (`decideVisitor`) and the
159
+ * assignments (`decideAssignments`); `null` when the request isn't a preview
160
+ * or is already on the draft route.
161
+ */
162
+ export declare function rewriteToDraftRoute(request: NextRequest, decision: DraftDecision, visitor?: VisitorDecision, assignments?: RequestAssignments): NextResponse | null;
163
+ /**
164
+ * The rewrite of a published request onto the assignments route,
165
+ * `/_assignments/<assignments>/<path>`: each test on or off for the visitor
166
+ * and each campaign running or not now (`readAssignments` on the current
167
+ * release), as one path segment, so Next's own path-keyed cache (ISR, the
168
+ * full route cache) keeps one entry per set of assignments. Visitors on the
169
+ * same side of every test share a path; the visitor id is never in it, and
170
+ * the page reads neither the visitor nor the version (the proxy's headers are
171
+ * removed from the request it forwards), so Next can cache it. The page
172
+ * builds its client with `assignedClient` from `@decocms/nextjs/server`,
173
+ * `cms.client({ experiments, campaigns })` from the path: the proxy decides,
174
+ * the page renders that. A cached page (ISR, `revalidate = 600`) is about 10
175
+ * minutes stale (the first request after that still gets it while Next
176
+ * renders it again), a banner switching on late, which is accepted.
177
+ *
178
+ * `null` for a preview request (it renders on the draft route, never cached)
179
+ * and for a path already on the draft or assignments route. When the content
180
+ * saves tests or campaigns, the response is marked `Cache-Control: private,
181
+ * no-cache`: Next keeps one cached page per set of assignments, but the URL
182
+ * the visitor asked for answers by their cookie and the moment, so a CDN in
183
+ * front must not share it. Call it only for the paths the assignments route
184
+ * renders (the CMS's pages), and answer a direct hit on the route with a 404
185
+ * (`isAssignmentsRoutePath`).
59
186
  */
60
- export declare function rewriteToDraftRoute(request: NextRequest, decision: DraftDecision): NextResponse | null;
187
+ export declare function rewriteToAssignmentsRoute(cms: Pick<CMS, "client">, request: NextRequest, draft: DraftDecision, visitor: VisitorDecision): Promise<NextResponse | null>;
61
188
  /**
62
- * The cookie and the response headers of a draft: `Set-Cookie`, and for a
63
- * drafted response `Cache-Control: no-store, private`, `Vary: Cookie` and
189
+ * The cookie and the response headers of a preview: `Set-Cookie`, and for
190
+ * any request with a draft signal (`preview`, or a version)
191
+ * `Cache-Control: max-age=0, no-cache, must-revalidate`, `Vary: Cookie` and
64
192
  * `X-Robots-Tag: noindex, nofollow` (`draftResponseHeaders`). With the
65
- * pointer in a cookie a draft shares its URL with the published page, so a
66
- * cache keyed on the URL alone would serve it to visitors.
193
+ * version in a cookie a draft shares its URL with the published page, so a
194
+ * cache keyed on the URL alone would serve it to visitors. The proxy answers
195
+ * before the page renders, so it can't hold the cookie back from a failed
196
+ * render; `decideDraft` reads the draft first instead, and a draft that
197
+ * can't be read expires the cookie.
67
198
  */
68
199
  export declare function applyDraft<R extends Response>(response: R, decision: DraftDecision): R;
69
- export interface DraftProxyOptions extends PreviewPolicy {
200
+ export interface DraftProxyOptions {
70
201
  /**
71
202
  * Which drafted requests go to the draft route (a statically rendered
72
203
  * page's). Default: every drafted request outside the draft route. Return
73
204
  * `false` for a route that is already dynamic and binds the draft itself.
74
205
  */
75
206
  rewrite?: (request: NextRequest) => boolean;
207
+ /**
208
+ * Which published requests render on the assignments route
209
+ * (`rewriteToAssignmentsRoute`): the CMS's pages, when the site mounts
210
+ * `app/%5Fassignments/[assignments]/[[...path]]`. Default: none. A direct
211
+ * hit on the route gets a 404 once this is set.
212
+ */
213
+ assignments?: (request: NextRequest) => boolean;
76
214
  }
77
215
  /**
78
- * The whole draft flow for a site with no proxy of its own:
79
- * `export const proxy = draftProxy(proxyCms, { site: "my-store" })`.
216
+ * The whole flow for a site with no proxy of its own:
217
+ * `export const proxy = draftProxy(proxyCms)`. Every
218
+ * request it forwards carries the version, the visitor and the assignments
219
+ * it decided.
80
220
  */
81
- export declare function draftProxy(cms: CMSHandle, options?: DraftProxyOptions): (request: NextRequest) => Promise<NextResponse>;
221
+ export declare function draftProxy(cms: CMSHandle & Pick<CMS, "client">, options?: DraftProxyOptions): (request: NextRequest) => Promise<NextResponse>;
82
222
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,EAML,KAAK,aAAa,EAEnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,KAAK,aAAa,EAClB,mBAAmB,EACnB,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,4FAA4F;AAC5F,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC,CAAC;AAE9E,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kGAAkG;IAClG,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,WAAW,GAAG,OAAO,EAC9B,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,aAAa,CAAC,CAYxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,WAAW,GAAG,OAAO,EAC9B,QAAQ,EAAE,aAAa,GACtB,OAAO,CAKT;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,GACtB,YAAY,GAAG,IAAI,CAQrB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,aAAa,GAAG,CAAC,CAMtF;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,SAAS,EACd,OAAO,GAAE,iBAAsB,GAC9B,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAUjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"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"}
@@ -1,42 +1,176 @@
1
+ import { readVisitor, serializeVisitor } from "@decocms/blocks/experiments";
1
2
  import { NextResponse } from "next/server.js";
2
- import { DRAFT_HEADER, DRAFT_ROUTE_PREFIX, draftResponseHeaders } from "../draft.js";
3
- import { allowedDraft, draftCookie, endsPreview, fromDraftLink, hasDraftSignal, requestLike, } from "../drafts.js";
4
- export { inferredPreviewHosts, previewHostDecision, requestLike, } from "../drafts.js";
5
- export { DRAFT_ROUTE_PREFIX } from "../draft.js";
6
- const INERT = Object.freeze({ pointer: null, setCookie: null });
3
+ import { ASSIGNMENTS_HEADER, assignmentsRoutePath, assignmentsSegment, isAssignmentsRoutePath, readAssignmentsAndScope, } from "../assignments.js";
4
+ import { DRAFT_ROUTE_PREFIX, DRAFT_UNAVAILABLE_HEADER, draftResponseHeaders, RELEASE_CHECK_HEADER, VERSION_HEADER, } from "../draft.js";
5
+ import { allowedDraft, draftCookie, draftLinkValue, draftReleaseCheck, endsPreview, hasDraftSignal, requestLike, } from "../drafts.js";
6
+ import { VISITOR_HEADER } from "../visitor.js";
7
+ export { requestLike } from "../drafts.js";
8
+ export { ASSIGNMENTS_HEADER, ASSIGNMENTS_ROUTE_PREFIX, assignmentsKey, assignmentsRoutePath, assignmentsSegment, isAssignmentsRoutePath, parseAssignmentsSegment, readAssignments, } from "../assignments.js";
9
+ export { DRAFT_ROUTE_PREFIX, VERSION_HEADER } from "../draft.js";
10
+ const INERT = Object.freeze({ version: null, setCookie: null });
11
+ /** A preview that renders the release (`off`, a refused host, a value that doesn't parse). */
12
+ const RELEASE_PREVIEW = Object.freeze({
13
+ version: null,
14
+ setCookie: null,
15
+ preview: true,
16
+ });
7
17
  /**
8
- * The draft a request renders and the cookie its response sets, under
9
- * `policy` (the same options the pages pass to `bindDraft`). A request with
10
- * no `?__draft=` and no draft cookie never reaches the CMS.
18
+ * The version a request renders and the cookie its response sets, on a host
19
+ * the CMS allows (as the pages' `bindDraft` checks again). A request with
20
+ * no `?__draft=` and no draft cookie never reaches the CMS. A draft request
21
+ * checks for the latest release once (`cms.checkRelease()`), shared by the
22
+ * host check, the read below and the page. A draft pointer
23
+ * is read once here (`forDraft(...).revision()`, the read the page makes
24
+ * again): a draft that can't be read gives the release and `unavailable`.
11
25
  */
12
- export async function decideDraft(cms, request, policy = {}) {
26
+ export async function decideDraft(cms, request) {
13
27
  const url = new URL(request.url);
14
28
  const like = requestLike(request.headers, url.pathname + url.search, url.host);
15
29
  if (like === null || !hasDraftSignal(like))
16
30
  return INERT;
17
31
  // Ending a preview is allowed on any host, so a cookie set earlier always goes.
18
32
  if (endsPreview(like))
19
- return { pointer: null, setCookie: draftCookie("", ["Max-Age=0"]) };
20
- const pointer = await allowedDraft(cms, like, policy);
21
- if (pointer === null)
22
- return INERT;
33
+ return { ...RELEASE_PREVIEW, setCookie: expiredCookie() };
34
+ // One release check per draft request, shared below and by the page.
35
+ const releaseCheck = await draftReleaseCheck(cms, like);
36
+ const version = await allowedDraft(cms, like, releaseCheck);
37
+ if (version === null)
38
+ return RELEASE_PREVIEW;
39
+ if (releaseCheck !== undefined) {
40
+ try {
41
+ await cms.forDraft(version.version, { releaseCheck }).revision();
42
+ }
43
+ catch (error) {
44
+ // Gone (deleted): the preview ends. Any other failure (the drafts' host
45
+ // down, a timeout) leaves the cookie alone, so the next request tries again.
46
+ const setCookie = isDraftGone(error) ? expiredCookie() : null;
47
+ return { ...RELEASE_PREVIEW, setCookie, unavailable: true };
48
+ }
49
+ }
50
+ const link = draftLinkValue(like);
23
51
  return {
24
- pointer,
25
- setCookie: fromDraftLink(like, pointer) ? draftCookie(encodeURIComponent(pointer)) : null,
52
+ version,
53
+ setCookie: link ? draftCookie(encodeURIComponent(link)) : null,
54
+ preview: true,
55
+ ...(releaseCheck === undefined ? {} : { releaseCheck }),
26
56
  };
27
57
  }
28
58
  /**
29
- * The request headers to forward: the accepted pointer on `x-deco-draft`, so
30
- * the root layout can bind the draft on the same request (a layout gets no
59
+ * Whether a draft read failed because the drafts' host no longer has the
60
+ * draft (`404`/`410`), as opposed to a failure that may pass (a `5xx`, a
61
+ * timeout, a network error). Reads the error and its causes.
62
+ */
63
+ function isDraftGone(error) {
64
+ for (let e = error, depth = 0; e instanceof Error && depth < 5; e = e.cause, depth++) {
65
+ if (/draft changes: HTTP (404|410)\b/.test(e.message))
66
+ return true;
67
+ }
68
+ return false;
69
+ }
70
+ /** The `Set-Cookie` that ends a preview. */
71
+ function expiredCookie() {
72
+ return draftCookie("", ["Max-Age=0"]);
73
+ }
74
+ /** The headers the proxy writes for the pages: never taken from outside. */
75
+ const OWN_HEADERS = [
76
+ VERSION_HEADER,
77
+ VISITOR_HEADER,
78
+ ASSIGNMENTS_HEADER,
79
+ DRAFT_UNAVAILABLE_HEADER,
80
+ RELEASE_CHECK_HEADER,
81
+ ];
82
+ /**
83
+ * The request headers to forward: the accepted version on `x-deco-version`,
84
+ * so the root layout can bind the draft on the same request (a layout gets no
31
85
  * `searchParams`, and on a draft link the cookie is only on the response).
32
- * A copy that arrives from outside is always removed.
86
+ * A copy that arrives from outside is always removed, and so are any
87
+ * `x-deco-visitor` and `x-deco-assignments` (`visitorRequestHeaders` and
88
+ * `assignmentsRequestHeaders` set the proxy's own).
33
89
  */
34
90
  export function draftRequestHeaders(request, decision) {
35
91
  const headers = new Headers(request.headers);
36
- if (decision.pointer)
37
- headers.set(DRAFT_HEADER, decision.pointer);
38
- else
39
- headers.delete(DRAFT_HEADER);
92
+ for (const name of OWN_HEADERS)
93
+ headers.delete(name);
94
+ if (decision.version)
95
+ headers.set(VERSION_HEADER, decision.version.version);
96
+ if (decision.version && decision.releaseCheck) {
97
+ headers.set(RELEASE_CHECK_HEADER, decision.releaseCheck);
98
+ }
99
+ if (decision.unavailable)
100
+ headers.set(DRAFT_UNAVAILABLE_HEADER, "1");
101
+ return headers;
102
+ }
103
+ /** Whether the visitor asked over https (`x-forwarded-proto` first, as a host in front reports it). */
104
+ function isHttps(request) {
105
+ const forwarded = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
106
+ if (forwarded)
107
+ return forwarded === "https";
108
+ return new URL(request.url).protocol === "https:";
109
+ }
110
+ /**
111
+ * The visitor of a request (`readVisitor`: the `deco_segment` cookie, or a
112
+ * new visitor when it had no id) and the cookie to send back, only on a first
113
+ * visit and never from a preview (`draft` holds a version): Studio is not a
114
+ * visitor. Reads no content.
115
+ */
116
+ export function decideVisitor(request, draft) {
117
+ // `readVisitor` makes the cookie `Secure` unless the request came over plain http.
118
+ const { visitor, cookie } = readVisitor({
119
+ url: isHttps(request) ? "https://localhost/" : "http://localhost/",
120
+ headers: request.headers,
121
+ });
122
+ return { visitor, setCookie: draft.version === null ? cookie : null };
123
+ }
124
+ /**
125
+ * The forwarded headers with the visitor on `x-deco-visitor`. Pass it the
126
+ * headers `draftRequestHeaders` gave, which already removed a copy from
127
+ * outside.
128
+ */
129
+ export function visitorRequestHeaders(headers, decision) {
130
+ const out = new Headers(headers);
131
+ out.set(VISITOR_HEADER, serializeVisitor(decision.visitor));
132
+ return out;
133
+ }
134
+ /** The `deco_segment` cookie on the response, on a first visit. */
135
+ export function applyVisitor(response, decision) {
136
+ if (decision.setCookie)
137
+ response.headers.append("set-cookie", decision.setCookie);
138
+ return response;
139
+ }
140
+ /**
141
+ * Each test and campaign on or off for this request, decided once:
142
+ * `cms.client({ visitor, ...version, releaseCheck })` (the visitor, the Studio
143
+ * link's version, moment and switched tests and campaigns, and the request's
144
+ * release check) resolving the saved
145
+ * `experiments` and `campaigns` blocks. Missing blocks, or content that
146
+ * doesn't load, give none, never an error.
147
+ */
148
+ export function decideAssignments(cms, draft, visitor) {
149
+ // A draft's read shares the request's release check (`decideDraft`), never one of its own.
150
+ const releaseCheck = draft.version ? draft.releaseCheck : undefined;
151
+ return readAssignmentsAndScope(cms, {
152
+ visitor: visitor.visitor,
153
+ ...draft.version,
154
+ ...(releaseCheck ? { releaseCheck } : {}),
155
+ }).then((read) => read.assignments);
156
+ }
157
+ /**
158
+ * The forwarded headers with the decided tests and campaigns on
159
+ * `x-deco-assignments` (`assignmentsSegment`), for `bindDraft` and
160
+ * `contentClient`. Pass it the headers `draftRequestHeaders` gave.
161
+ */
162
+ export function assignmentsRequestHeaders(headers, assignments) {
163
+ const out = new Headers(headers);
164
+ out.set(ASSIGNMENTS_HEADER, assignmentsSegment(assignments));
165
+ return out;
166
+ }
167
+ /** The request headers to forward: the version's and, when given, the visitor's and the assignments. */
168
+ function forwardedHeaders(request, draft, visitor, assignments) {
169
+ let headers = draftRequestHeaders(request, draft);
170
+ if (visitor !== undefined)
171
+ headers = visitorRequestHeaders(headers, visitor);
172
+ if (assignments !== undefined)
173
+ headers = assignmentsRequestHeaders(headers, assignments);
40
174
  return headers;
41
175
  }
42
176
  /** Whether `pathname` is on the draft route: a site answers a direct hit there with its 404. */
@@ -44,48 +178,115 @@ export function isDraftRoutePath(pathname) {
44
178
  return pathname === DRAFT_ROUTE_PREFIX || pathname.startsWith(`${DRAFT_ROUTE_PREFIX}/`);
45
179
  }
46
180
  /**
47
- * The rewrite of a drafted request onto the draft route, keeping its path and
48
- * forwarding the pointer; `null` when the request isn't drafted or is already
49
- * on the draft route.
181
+ * The rewrite of a preview request (a drafted one, or any other with a draft
182
+ * signal: `off`, a refused host, a draft that can't be read) onto the draft
183
+ * route, which is dynamic and never cached, keeping its path and forwarding
184
+ * the version and, when given, the visitor (`decideVisitor`) and the
185
+ * assignments (`decideAssignments`); `null` when the request isn't a preview
186
+ * or is already on the draft route.
50
187
  */
51
- export function rewriteToDraftRoute(request, decision) {
52
- if (!decision.pointer)
188
+ export function rewriteToDraftRoute(request, decision, visitor, assignments) {
189
+ if (!decision.version && !decision.preview)
53
190
  return null;
54
191
  const url = request.nextUrl.clone();
55
192
  if (isDraftRoutePath(url.pathname))
56
193
  return null;
57
194
  url.pathname = `${DRAFT_ROUTE_PREFIX}${url.pathname}`;
58
195
  return NextResponse.rewrite(url, {
59
- request: { headers: draftRequestHeaders(request, decision) },
196
+ request: { headers: forwardedHeaders(request, decision, visitor, assignments) },
60
197
  });
61
198
  }
199
+ /** An assignments-route response's `Cache-Control` when its content has tests or campaigns. */
200
+ const ASSIGNED_CACHE_CONTROL = "private, no-cache";
201
+ /**
202
+ * The rewrite of a published request onto the assignments route,
203
+ * `/_assignments/<assignments>/<path>`: each test on or off for the visitor
204
+ * and each campaign running or not now (`readAssignments` on the current
205
+ * release), as one path segment, so Next's own path-keyed cache (ISR, the
206
+ * full route cache) keeps one entry per set of assignments. Visitors on the
207
+ * same side of every test share a path; the visitor id is never in it, and
208
+ * the page reads neither the visitor nor the version (the proxy's headers are
209
+ * removed from the request it forwards), so Next can cache it. The page
210
+ * builds its client with `assignedClient` from `@decocms/nextjs/server`,
211
+ * `cms.client({ experiments, campaigns })` from the path: the proxy decides,
212
+ * the page renders that. A cached page (ISR, `revalidate = 600`) is about 10
213
+ * minutes stale (the first request after that still gets it while Next
214
+ * renders it again), a banner switching on late, which is accepted.
215
+ *
216
+ * `null` for a preview request (it renders on the draft route, never cached)
217
+ * and for a path already on the draft or assignments route. When the content
218
+ * saves tests or campaigns, the response is marked `Cache-Control: private,
219
+ * no-cache`: Next keeps one cached page per set of assignments, but the URL
220
+ * the visitor asked for answers by their cookie and the moment, so a CDN in
221
+ * front must not share it. Call it only for the paths the assignments route
222
+ * renders (the CMS's pages), and answer a direct hit on the route with a 404
223
+ * (`isAssignmentsRoutePath`).
224
+ */
225
+ export async function rewriteToAssignmentsRoute(cms, request, draft, visitor) {
226
+ if (draft.version || draft.preview)
227
+ return null;
228
+ const url = request.nextUrl.clone();
229
+ if (isDraftRoutePath(url.pathname) || isAssignmentsRoutePath(url.pathname))
230
+ return null;
231
+ const { assignments, varies } = await readAssignmentsAndScope(cms, { visitor: visitor.visitor });
232
+ url.pathname = assignmentsRoutePath(url.pathname, assignments);
233
+ const response = NextResponse.rewrite(url, {
234
+ request: { headers: draftRequestHeaders(request, INERT) },
235
+ });
236
+ // The URL the visitor asked for answers differently by their cookie and the moment: a
237
+ // shared cache in front (a CDN) must not keep Next's ISR `s-maxage` under it.
238
+ if (varies)
239
+ response.headers.set("Cache-Control", ASSIGNED_CACHE_CONTROL);
240
+ return response;
241
+ }
62
242
  /**
63
- * The cookie and the response headers of a draft: `Set-Cookie`, and for a
64
- * drafted response `Cache-Control: no-store, private`, `Vary: Cookie` and
243
+ * The cookie and the response headers of a preview: `Set-Cookie`, and for
244
+ * any request with a draft signal (`preview`, or a version)
245
+ * `Cache-Control: max-age=0, no-cache, must-revalidate`, `Vary: Cookie` and
65
246
  * `X-Robots-Tag: noindex, nofollow` (`draftResponseHeaders`). With the
66
- * pointer in a cookie a draft shares its URL with the published page, so a
67
- * cache keyed on the URL alone would serve it to visitors.
247
+ * version in a cookie a draft shares its URL with the published page, so a
248
+ * cache keyed on the URL alone would serve it to visitors. The proxy answers
249
+ * before the page renders, so it can't hold the cookie back from a failed
250
+ * render; `decideDraft` reads the draft first instead, and a draft that
251
+ * can't be read expires the cookie.
68
252
  */
69
253
  export function applyDraft(response, decision) {
70
254
  if (decision.setCookie)
71
255
  response.headers.append("set-cookie", decision.setCookie);
72
- for (const [name, value] of Object.entries(draftResponseHeaders(decision.pointer))) {
256
+ const preview = decision.preview === true || decision.version !== null;
257
+ for (const [name, value] of Object.entries(draftResponseHeaders(preview))) {
73
258
  response.headers.set(name, value);
74
259
  }
75
260
  return response;
76
261
  }
77
262
  /**
78
- * The whole draft flow for a site with no proxy of its own:
79
- * `export const proxy = draftProxy(proxyCms, { site: "my-store" })`.
263
+ * The whole flow for a site with no proxy of its own:
264
+ * `export const proxy = draftProxy(proxyCms)`. Every
265
+ * request it forwards carries the version, the visitor and the assignments
266
+ * it decided.
80
267
  */
81
268
  export function draftProxy(cms, options = {}) {
82
- const { rewrite = () => true, ...policy } = options;
269
+ const { rewrite = () => true, assignments } = options;
83
270
  return async (request) => {
84
- const decision = await decideDraft(cms, request, policy);
85
- const rewritten = rewrite(request) ? rewriteToDraftRoute(request, decision) : null;
86
- const response = rewritten ??
87
- NextResponse.next({ request: { headers: draftRequestHeaders(request, decision) } });
88
- return applyDraft(response, decision);
271
+ if (assignments && isAssignmentsRoutePath(request.nextUrl.pathname)) {
272
+ return new NextResponse(null, { status: 404 });
273
+ }
274
+ const decision = await decideDraft(cms, request);
275
+ const visitor = decideVisitor(request, decision);
276
+ const onAssignmentsRoute = decision.version === null && decision.preview !== true && assignments?.(request) === true;
277
+ const rewritten = onAssignmentsRoute
278
+ ? await rewriteToAssignmentsRoute(cms, request, decision, visitor)
279
+ : null;
280
+ let response = rewritten;
281
+ if (response === null) {
282
+ const decided = await decideAssignments(cms, decision, visitor);
283
+ response =
284
+ (rewrite(request) ? rewriteToDraftRoute(request, decision, visitor, decided) : null) ??
285
+ NextResponse.next({
286
+ request: { headers: forwardedHeaders(request, decision, visitor, decided) },
287
+ });
288
+ }
289
+ return applyVisitor(applyDraft(response, decision), visitor);
89
290
  };
90
291
  }
91
292
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"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"}