@decocms/nextjs 8.6.0 → 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.
@@ -34,8 +34,13 @@ import {
34
34
  parseAssignmentsSegment,
35
35
  withoutDarkTests,
36
36
  } from "../assignments.ts";
37
- import { DRAFT_PARAM, VERSION_HEADER } from "../draft.ts";
38
- import { allowedDraft, requestLike } from "../drafts.ts";
37
+ import {
38
+ DRAFT_PARAM,
39
+ DRAFT_UNAVAILABLE_HEADER,
40
+ RELEASE_CHECK_HEADER,
41
+ VERSION_HEADER,
42
+ } from "../draft.ts";
43
+ import { allowedDraft, draftReleaseCheck, requestLike } from "../drafts.ts";
39
44
  import { VISITOR_HEADER } from "../visitor.ts";
40
45
  import { activeDraftPointer, draftSlot } from "./slot.ts";
41
46
 
@@ -56,7 +61,7 @@ export interface BindDraftOptions {
56
61
  searchParams?: SearchParams;
57
62
  }
58
63
 
59
- type BindCMS = Pick<CMS, "readVersion" | "forRelease">;
64
+ type BindCMS = Pick<CMS, "readVersion" | "forRelease" | "checkRelease">;
60
65
 
61
66
  function firstParam(searchParams: SearchParams | undefined, key: string): string | null {
62
67
  const raw = searchParams?.[key];
@@ -123,12 +128,27 @@ async function bindVersion(cms: BindCMS, options: BindDraftOptions): Promise<boo
123
128
  const param = firstParam(searchParams, DRAFT_PARAM);
124
129
  if (param === "off") return false;
125
130
  const requestHeaders = await headers();
131
+ // The proxy read the link's draft and it's gone: the release, with the notice.
132
+ if (requestHeaders.get(DRAFT_UNAVAILABLE_HEADER) === "1") {
133
+ draftSlot().unavailable = true;
134
+ return false;
135
+ }
126
136
  const forwarded = param ?? requestHeaders.get(VERSION_HEADER);
127
137
  const query = forwarded ? `?${DRAFT_PARAM}=${encodeURIComponent(forwarded)}` : "";
128
138
  const request = requestLike(requestHeaders as Headers, `/${query}`);
129
- const version = request ? await allowedDraft(cms, request) : null;
139
+ if (request === null) return false;
140
+ // The proxy's release check for this request (`x-deco-release-check`), or one of its own:
141
+ // the host check here and the page's draft reads share it.
142
+ const releaseCheck = await draftReleaseCheck(
143
+ cms,
144
+ request,
145
+ requestHeaders.get(RELEASE_CHECK_HEADER),
146
+ );
147
+ const version = await allowedDraft(cms, request, releaseCheck);
130
148
  if (version === null) return false;
131
- draftSlot().version = version;
149
+ const slot = draftSlot();
150
+ slot.version = version;
151
+ slot.releaseCheck = releaseCheck ?? null;
132
152
  return true;
133
153
  }
134
154
 
@@ -140,8 +160,9 @@ async function bindVersion(cms: BindCMS, options: BindDraftOptions): Promise<boo
140
160
  * and campaigns decide instead. Create one per request.
141
161
  */
142
162
  export function contentClient(cms: Pick<CMS, "client">): Client {
143
- const { version, visitor, assignments } = draftSlot();
163
+ const { version, visitor, assignments, releaseCheck } = draftSlot();
144
164
  const options: ClientOptions = { visitor, version: version?.version ?? null };
165
+ if (version !== null && releaseCheck !== null) options.releaseCheck = releaseCheck;
145
166
  if (version?.date !== undefined) options.date = version.date;
146
167
  const experiments = over(version?.experiments, assignments?.experiments);
147
168
  const campaigns = over(version?.campaigns, assignments?.campaigns);
@@ -15,13 +15,28 @@ interface DraftSlot {
15
15
  version: RequestVersion | null;
16
16
  visitor: Visitor | null;
17
17
  assignments: PathAssignments | null;
18
+ /** The link named a draft that can't be read anymore: the page renders the release. */
19
+ unavailable: boolean;
20
+ /** The request's release check (`cms.checkRelease()`), which its draft reads wait for. */
21
+ releaseCheck: string | null;
18
22
  }
19
23
 
20
24
  export const draftSlot = cache(
21
- (): DraftSlot => ({ version: null, visitor: null, assignments: null }),
25
+ (): DraftSlot => ({
26
+ version: null,
27
+ visitor: null,
28
+ assignments: null,
29
+ unavailable: false,
30
+ releaseCheck: null,
31
+ }),
22
32
  );
23
33
 
24
34
  /** The version bound to this request (`bindDraft`), or `null` when it renders the current release. */
25
35
  export function activeDraftPointer(): string | null {
26
36
  return draftSlot().version?.version ?? null;
27
37
  }
38
+
39
+ /** Whether the request's link named a draft that can't be read anymore (`bindDraft`). */
40
+ export function draftUnavailable(): boolean {
41
+ return draftSlot().unavailable;
42
+ }