@decocms/nextjs 8.0.0 → 8.4.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.
- package/README.md +77 -332
- package/dist/DraftPreviewIndicator.d.ts +7 -0
- package/dist/DraftPreviewIndicator.d.ts.map +1 -0
- package/dist/DraftPreviewIndicator.js +19 -0
- package/dist/DraftPreviewIndicator.js.map +1 -0
- package/dist/StudioBridge.d.ts +16 -0
- package/dist/StudioBridge.d.ts.map +1 -0
- package/dist/StudioBridge.js +17 -0
- package/dist/StudioBridge.js.map +1 -0
- package/dist/draft.d.ts +35 -0
- package/dist/draft.d.ts.map +1 -0
- package/dist/draft.js +43 -0
- package/dist/draft.js.map +1 -0
- package/dist/drafts.d.ts +94 -0
- package/dist/drafts.d.ts.map +1 -0
- package/dist/drafts.js +210 -0
- package/dist/drafts.js.map +1 -0
- package/dist/image-loader/index.d.ts +36 -0
- package/dist/image-loader/index.d.ts.map +1 -0
- package/dist/image-loader/index.js +27 -0
- package/dist/image-loader/index.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy/index.d.ts +79 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +92 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/server/index.d.ts +46 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +64 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/slot.d.ts +6 -0
- package/dist/server/slot.d.ts.map +1 -0
- package/dist/server/slot.js +13 -0
- package/dist/server/slot.js.map +1 -0
- package/dist/studio.d.ts +30 -0
- package/dist/studio.d.ts.map +1 -0
- package/dist/studio.js +55 -0
- package/dist/studio.js.map +1 -0
- package/package.json +41 -22
- package/src/DraftPreviewIndicator.tsx +17 -16
- package/src/StudioBridge.ts +23 -0
- package/src/config/index.cjs +78 -0
- package/src/config/index.d.cts +27 -0
- package/src/draft.ts +30 -210
- package/src/drafts.ts +229 -0
- package/src/image-loader/index.ts +62 -0
- package/src/index.ts +31 -43
- package/src/proxy/index.ts +161 -0
- package/src/server/index.ts +77 -0
- package/src/server/slot.ts +14 -0
- package/src/studio.ts +54 -0
- package/src/ClientOnlySection.tsx +0 -20
- package/src/DecoPageRenderer.test.tsx +0 -37
- package/src/DecoPageRenderer.tsx +0 -107
- package/src/DecoRootLayout.test.tsx +0 -22
- package/src/DecoRootLayout.tsx +0 -82
- package/src/DeferredSection.test.tsx +0 -27
- package/src/DeferredSection.tsx +0 -59
- package/src/DraftPreviewBadge.render.test.tsx +0 -16
- package/src/DraftPreviewBadge.test.ts +0 -37
- package/src/DraftPreviewBadge.tsx +0 -252
- package/src/SectionRenderer.test.tsx +0 -97
- package/src/SectionRenderer.tsx +0 -58
- package/src/config.cjs +0 -92
- package/src/config.d.cts +0 -4
- package/src/config.test.ts +0 -86
- package/src/createDecoPage.draft.test.tsx +0 -91
- package/src/createDecoPage.test.tsx +0 -63
- package/src/createDecoPage.tsx +0 -173
- package/src/createDecoPreviewPage.test.tsx +0 -71
- package/src/createDecoPreviewPage.tsx +0 -108
- package/src/decoMark.ts +0 -11
- package/src/draft.test.ts +0 -73
- package/src/draftConstants.test.ts +0 -21
- package/src/draftConstants.ts +0 -15
- package/src/draftMiddleware.test.ts +0 -147
- package/src/draftMiddleware.ts +0 -136
- package/src/routeHandlers.test.ts +0 -243
- package/src/routeHandlers.ts +0 -227
- package/src/setup.test.ts +0 -253
- package/src/setup.ts +0 -180
- package/tsconfig.json +0 -7
package/README.md
CHANGED
|
@@ -1,367 +1,112 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @decocms/nextjs
|
|
2
2
|
|
|
3
|
-
Deco
|
|
4
|
-
`@decocms/tanstack`. Four surfaces, composed together:
|
|
3
|
+
Deco CMS for any [Next.js](https://nextjs.org) App Router app. It makes no hosting assumptions: no CDN, ISR or platform behaviour is built in. It is a set of small helpers your site calls from its own proxy, layout, pages and `next.config`.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
wrapper that adds the rewrites and `transpilePackages` Deco's admin
|
|
8
|
-
protocol needs.
|
|
9
|
-
- **`@decocms/nextjs/routeHandlers`** — `createDecoRouteHandlers({ setup })`,
|
|
10
|
-
a single catch-all dispatcher for the whole Studio admin protocol
|
|
11
|
-
(decofile read/reload, meta schema, invoke, live previews).
|
|
12
|
-
- **`@decocms/nextjs`** — `createDecoPreviewPage({ setup })`, an App Router
|
|
13
|
-
Server Component that renders live previews through Next's RSC pipeline,
|
|
14
|
-
including sections marked with `"use client"`.
|
|
15
|
-
- **`@decocms/nextjs/setup`** — `createNextSetup(options)`, a one-call site
|
|
16
|
-
bootstrap: the Next.js analogue of Vite's
|
|
17
|
-
`createSiteSetup` + `createAdminSetup` + `import.meta.glob`.
|
|
5
|
+
Peers: `@decocms/blocks` (same version), `next` 16, `react` 19.
|
|
18
6
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
bun add @decocms/nextjs @decocms/blocks @decocms/blocks-admin
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
`next`, `react`, and `react-dom` are peer dependencies — the site already
|
|
30
|
-
has them.
|
|
31
|
-
|
|
32
|
-
## 1. `next.config` — `withDeco`
|
|
33
|
-
|
|
34
|
-
`withDeco` adds three rewrites (mapping the Studio-protocol URLs Next.js
|
|
35
|
-
cannot express as route segments onto `/deco/*`, where the catch-all route
|
|
36
|
-
below serves them) and appends the three `@decocms/*` packages (which ship
|
|
37
|
-
raw TypeScript, not a prebuilt `dist/`) to `transpilePackages`.
|
|
38
|
-
|
|
39
|
-
TypeScript (`next.config.ts`):
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
import type { NextConfig } from "next";
|
|
43
|
-
import { withDeco } from "@decocms/nextjs/config";
|
|
44
|
-
|
|
45
|
-
const nextConfig: NextConfig = {
|
|
46
|
-
// ...your own config
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export default withDeco(nextConfig);
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
CommonJS (`next.config.js`) — most Next.js sites still use this form:
|
|
53
|
-
|
|
54
|
-
```js
|
|
55
|
-
/** @type {import('next').NextConfig} */
|
|
56
|
-
const { withDeco } = require("@decocms/nextjs/config");
|
|
57
|
-
|
|
58
|
-
const nextConfig = {
|
|
59
|
-
// ...your own config
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
module.exports = withDeco(nextConfig);
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`withDeco` merges with a `rewrites`/`transpilePackages` you already have —
|
|
66
|
-
it never replaces them. If your own `rewrites()` returns the array form,
|
|
67
|
-
Deco's rewrites are prepended; if it returns the `{ beforeFiles, afterFiles,
|
|
68
|
-
fallback }` object form, Deco's rewrites are prepended to `beforeFiles`.
|
|
7
|
+
| Import | What it is for |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `@decocms/nextjs/proxy` | Draft previews in `proxy.ts`: `decideDraft`, `draftRequestHeaders`, `rewriteToDraftRoute`, `applyDraft`, `isDraftRoutePath`, or `draftProxy` for a site with no proxy of its own. No React and no block map. |
|
|
10
|
+
| `@decocms/nextjs/server` | Draft previews in Server Components: `bindDraft`, `activeDraftPointer`, `contentClient`. |
|
|
11
|
+
| `@decocms/nextjs` | `DraftPreviewIndicator` (the "Preview mode" badge on a draft page), `StudioBridge` (lets Studio's site editor drive the page) and `StudioPage` (tells it which page is on screen), plus the draft names and Studio's origins (below). |
|
|
12
|
+
| `@decocms/nextjs/config` | `withDeco(nextConfig)`: the draft header rules and Studio's dev origins. CommonJS, so `next.config.js` can `require()` it. |
|
|
13
|
+
| `@decocms/nextjs/image-loader` | `createDecoImageLoader(imageUrl)`: a next/image loader over an `ImageUrl` from `@decocms/blocks/image`. |
|
|
69
14
|
|
|
70
|
-
|
|
15
|
+
`createCMS` reads `NODE_ENV` to decide dev mode, so `next dev` never swaps the hosted release in over your local content; nothing needs passing. `createCMS({ dev })` still overrides it when a site needs to.
|
|
71
16
|
|
|
72
|
-
|
|
73
|
-
one file serves the entire admin protocol (decofile, meta, invoke, live
|
|
74
|
-
previews) for both the rewritten public URLs (`/.decofile`, `/live/_meta`,
|
|
75
|
-
`/live/previews/*`) and their `/deco/*` destinations directly.
|
|
17
|
+
## Drafts
|
|
76
18
|
|
|
77
19
|
```ts
|
|
78
|
-
// src/
|
|
79
|
-
|
|
80
|
-
|
|
20
|
+
// src/cms.config.ts: the options both CMS handles share, and where drafts preview
|
|
21
|
+
export const cmsConfig = { content };
|
|
22
|
+
export const preview = { site: "my-store" };
|
|
23
|
+
|
|
24
|
+
// src/cms.ts and src/cms.proxy.ts
|
|
25
|
+
export const cms = createCMS({ blocks, ...cmsConfig });
|
|
26
|
+
export const proxyCms = createCMS({ blocks: {}, ...cmsConfig }); // no block map in the proxy
|
|
27
|
+
|
|
28
|
+
// src/proxy.ts
|
|
29
|
+
export async function proxy(request: NextRequest) {
|
|
30
|
+
if (isDraftRoutePath(request.nextUrl.pathname)) return new NextResponse(null, { status: 404 });
|
|
31
|
+
const draft = await decideDraft(proxyCms, request, preview);
|
|
32
|
+
const response =
|
|
33
|
+
rewriteToDraftRoute(request, draft) ??
|
|
34
|
+
NextResponse.next({ request: { headers: draftRequestHeaders(request, draft) } });
|
|
35
|
+
return applyDraft(response, draft);
|
|
36
|
+
}
|
|
81
37
|
|
|
38
|
+
// src/app/%5Fdraft/[[...path]]/page.tsx: the dynamic draft route (a literal `_draft` folder never routes)
|
|
82
39
|
export const dynamic = "force-dynamic";
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
40
|
+
export default async function DraftPage({ params, searchParams }) {
|
|
41
|
+
await bindDraft(cms, { searchParams: await searchParams, ...preview });
|
|
42
|
+
const client = contentClient(cms);
|
|
43
|
+
// … resolve and render the page as on the published route …
|
|
44
|
+
return <>{page}<DraftPreviewIndicator /></>;
|
|
45
|
+
}
|
|
87
46
|
```
|
|
88
47
|
|
|
89
|
-
`
|
|
90
|
-
statically cached (decofile reloads, invoke calls, and previews all need a
|
|
91
|
-
fresh response per request).
|
|
48
|
+
Published pages stay static: the proxy sends only drafted requests to the draft route, sets the draft cookie, forwards the accepted pointer on `x-deco-draft` (removing any copy sent from outside), and marks the response `Cache-Control: no-store, private` and `X-Robots-Tag: noindex, nofollow`. A root layout that reads content calls `bindDraft(cms, preview)` too: it reads the forwarded header.
|
|
92
49
|
|
|
93
|
-
###
|
|
50
|
+
### Draft hosts
|
|
94
51
|
|
|
95
|
-
|
|
96
|
-
This path is intentionally not configurable: preview GET requests are always
|
|
97
|
-
redirected from the catch-all route to this App Router page, with the query
|
|
98
|
-
string preserved. Other admin requests, including `POST /deco/render`, remain
|
|
99
|
-
on the catch-all handler.
|
|
52
|
+
v7's allowlist. A draft link (`?__draft=`) previews on the preview hosts the site declares (the `CMS` block's `preview.hosts`, or `createCMS`'s; a site that declares none has none, as in v7) and always on the hosts Deco runs the site on, `<site>.deco.site` and `<site>.deco-cx.workers.dev`. `previewHosts: [...]` replaces the declared list (v7's `DECO_ALLOWED_PREVIEW_HOSTS`, such as `["localhost:3000"]` in development); `previewHosts: "none"` turns previews off on every host. Hosts compare exactly, port included, on the host the visitor asked for (`x-forwarded-host`, else `host`). Pass the same options to `decideDraft` and `bindDraft`. On a host that may not preview, the page renders the release; `?__draft=off` still ends a preview anywhere.
|
|
100
53
|
|
|
101
|
-
|
|
102
|
-
// src/app/deco/preview/[[...path]]/page.tsx
|
|
103
|
-
import { createDecoPreviewPage } from "@decocms/nextjs";
|
|
104
|
-
import { ensureSetup } from "../../../../deco/setup";
|
|
54
|
+
## The layout
|
|
105
55
|
|
|
106
|
-
|
|
56
|
+
```tsx
|
|
57
|
+
import { StudioBridge } from "@decocms/nextjs";
|
|
107
58
|
|
|
108
|
-
|
|
59
|
+
<body>
|
|
60
|
+
{children}
|
|
61
|
+
<StudioBridge site="my-store" />
|
|
62
|
+
</body>
|
|
109
63
|
```
|
|
110
64
|
|
|
111
|
-
|
|
112
|
-
produce plain HTML with `react-dom/server`, but that renderer cannot execute
|
|
113
|
-
the client-reference proxies Next creates for modules marked
|
|
114
|
-
`"use client"`. An App Router page is rendered by Next's React Server
|
|
115
|
-
Components pipeline, so it can render a server section tree containing
|
|
116
|
-
Client Components and preserve their hydration metadata.
|
|
117
|
-
|
|
118
|
-
Do not work around this error by removing `"use client"` from interactive
|
|
119
|
-
components. Keep sections and wrappers as Server Components when they only
|
|
120
|
-
render markup, but retain a Client Component boundary wherever hooks, event
|
|
121
|
-
handlers, browser APIs, or client-only context are required. The RSC preview
|
|
122
|
-
page exists so those two kinds of component can compose exactly as they do in
|
|
123
|
-
the storefront.
|
|
124
|
-
|
|
125
|
-
Importing the root barrel is correct in this `page.tsx`; the subpath-only
|
|
126
|
-
rule below applies specifically to `route.ts` files.
|
|
127
|
-
|
|
128
|
-
### Route-handler import rule: subpaths, never the root barrel
|
|
129
|
-
|
|
130
|
-
**Always import from `@decocms/nextjs/routeHandlers` (or `/config`,
|
|
131
|
-
`/setup`) in a `route.ts` file. Never `import { ... } from "@decocms/nextjs"`
|
|
132
|
-
there.**
|
|
133
|
-
|
|
134
|
-
App Router route handlers evaluate their entire module graph against
|
|
135
|
-
React's **react-server** build, and this happens regardless of any
|
|
136
|
-
`"use client"` directive in that graph — route handlers have no client
|
|
137
|
-
bundle to move a `"use client"` module into, so the directive is simply
|
|
138
|
-
ignored. The root barrel (`@decocms/nextjs`'s `.` export) re-exports the
|
|
139
|
-
render components (`DecoRootLayout`, `SectionRenderer`, `DecoPageRenderer`,
|
|
140
|
-
...), whose module graph reaches component code that uses client-only React
|
|
141
|
-
APIs (`createContext`, `useContext`, class components with
|
|
142
|
-
`componentDidCatch`, etc.) at module scope. Importing the root barrel from
|
|
143
|
-
a route file pulls that whole graph into react-server evaluation and
|
|
144
|
-
crashes at **import time**, before your handler ever runs, with errors like
|
|
145
|
-
`"...createContext is not a function"` or `"Class extends value undefined
|
|
146
|
-
is not a constructor"` — even if the route handler itself never touches
|
|
147
|
-
those components. The `/routeHandlers`, `/config`, and `/setup` subpaths
|
|
148
|
-
are each scoped to keep their own module graph free of component code, so
|
|
149
|
-
they're safe to import from anywhere, including a route file.
|
|
150
|
-
|
|
151
|
-
## 3. `src/deco/setup.ts` — `createNextSetup`
|
|
65
|
+
Studio's origins are the package's own (`STUDIO_ORIGINS`), so the bridge takes only the site's name. v7's "." edit shortcut is on by default (`editShortcut={false}` turns it off), and `nonce` is optional.
|
|
152
66
|
|
|
153
|
-
|
|
154
|
-
`.deco/` at the site root — the same default `@decocms/blocks-cli`'s
|
|
155
|
-
generators use everywhere else (framework artifacts live in the framework's
|
|
156
|
-
folder, not scattered across `src/`). `src/deco/setup.ts` isn't adjacent to
|
|
157
|
-
`.deco/`, so import it through a `deco/*` tsconfig path alias instead of a
|
|
158
|
-
relative path:
|
|
67
|
+
On a page that isn't in Studio's frame, "." (or Ctrl+Shift+E) opens the page in Studio's editor, and Ctrl or Cmd+"." opens it in a new tab; Studio asks a visitor who isn't signed in to sign in first. To open the right page, each CMS page tells the bridge its path template: the root layout stays across navigations, so the page renders the marker, next to the sections it resolved:
|
|
159
68
|
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
{
|
|
163
|
-
"compilerOptions": {
|
|
164
|
-
"paths": {
|
|
165
|
-
"deco/*": [".deco/*"]
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
// src/deco/setup.ts
|
|
173
|
-
import { createNextSetup } from "@decocms/nextjs/setup";
|
|
174
|
-
import blocks from "deco/blocksManifest.gen"; // .deco/blocksManifest.gen.ts — see below
|
|
175
|
-
import { sectionImports, sectionMeta, syncComponents, loadingFallbacks } from "deco/sections.gen";
|
|
69
|
+
```tsx
|
|
70
|
+
import { StudioPage } from "@decocms/nextjs";
|
|
176
71
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
sections: sectionImports,
|
|
181
|
-
conventions: { meta: sectionMeta, syncComponents, loadingFallbacks },
|
|
182
|
-
meta: () => import("deco/meta.gen.json").then((m) => m.default),
|
|
183
|
-
});
|
|
72
|
+
const match = matchRoute(pathname, { routes: pages });
|
|
73
|
+
// …
|
|
74
|
+
return <>{sections}<StudioPage pathTemplate={match.entry.path} /></>;
|
|
184
75
|
```
|
|
185
76
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
`generate-blocks-manifest` (from `@decocms/blocks-cli`) emits
|
|
189
|
-
`.deco/blocksManifest.gen.ts` — a module that **statically imports** every
|
|
190
|
-
`.deco/blocks/*.json` file (raw on-disk filename in the specifier; keys are
|
|
191
|
-
the filename minus `.json`, verbatim, exactly like
|
|
192
|
-
`loadDecofileDirectory`). Passing its default export as `blocks` with
|
|
193
|
-
`blocksDir: false` (as in the snippet above) makes the manifest the sole
|
|
194
|
-
block source and the bootstrap pure — no filesystem access.
|
|
195
|
-
|
|
196
|
-
Why this is the recommended wiring over the default `blocksDir` runtime
|
|
197
|
-
read:
|
|
198
|
-
|
|
199
|
-
- **CMS content hot-reloads in `next dev`.** The block JSONs are part of
|
|
200
|
-
Next's module graph, so editing one (Studio daemon write, sync, manual
|
|
201
|
-
edit) invalidates the server module graph, re-evaluates the setup module,
|
|
202
|
-
and rebuilds `createNextSetup`'s memo with the fresh content —
|
|
203
|
-
~120–165ms per edit, measured on a 500-block site. The runtime fs read is
|
|
204
|
-
invisible to the bundler: edits invalidate nothing and dev serves stale
|
|
205
|
-
content until a restart.
|
|
206
|
-
- **Deploys need no `outputFileTracingIncludes` hack** — the JSON is
|
|
207
|
-
bundled into the build output instead of read from disk at runtime.
|
|
208
|
-
|
|
209
|
-
Trade-offs to know about:
|
|
210
|
-
|
|
211
|
-
- **Content is baked at build time** in production. Studio's
|
|
212
|
-
`POST /.decofile` still overrides the in-memory snapshot at runtime
|
|
213
|
-
(live preview/publish keeps working on a warm instance); the baked
|
|
214
|
-
manifest is the cold-start baseline.
|
|
215
|
-
- **Adding or removing a block *file* requires re-running the generator**
|
|
216
|
-
(content edits to existing files do not). Wire it into the site's
|
|
217
|
-
`generate` chain — see the scripts section below.
|
|
218
|
-
|
|
219
|
-
If you skip the manifest, the default `blocksDir: ".deco/blocks"` runtime
|
|
220
|
-
read still works — just without dev reload, and your deploy must ship the
|
|
221
|
-
directory alongside the server bundle.
|
|
222
|
-
|
|
223
|
-
Keep the manifest out of any client-reachable import graph (import it only
|
|
224
|
-
from the server-side setup module) so 5MB of CMS JSON never lands in a
|
|
225
|
-
client bundle.
|
|
226
|
-
|
|
227
|
-
`createNextSetup` returns a **memoized** `ensureSetup()` function — a
|
|
228
|
-
successful bootstrap is cached for the life of the warm serverless
|
|
229
|
-
instance; a *rejected* bootstrap clears the memo so the next call retries
|
|
230
|
-
from scratch (the triggering call still rejects with the original error).
|
|
231
|
-
|
|
232
|
-
Three call sites need `ensureSetup()`:
|
|
233
|
-
|
|
234
|
-
1. **The catch-all route** (above) passes it as `{ setup: ensureSetup }` —
|
|
235
|
-
`createDecoRouteHandlers` awaits it before dispatching every admin
|
|
236
|
-
request.
|
|
237
|
-
2. **The root layout** (`app/layout.tsx`) must await it directly before
|
|
238
|
-
rendering, since page rendering (`createDecoPage`'s resolver) has no
|
|
239
|
-
setup hook of its own:
|
|
240
|
-
|
|
241
|
-
```tsx
|
|
242
|
-
// src/app/layout.tsx
|
|
243
|
-
import { DecoRootLayout } from "@decocms/nextjs";
|
|
244
|
-
import { ensureSetup } from "../deco/setup";
|
|
77
|
+
It renders a `<meta>` that React places in the `<head>`, so the page's own markup doesn't change. Without it, Studio picks the page from the URL.
|
|
245
78
|
|
|
246
|
-
|
|
247
|
-
await ensureSetup();
|
|
248
|
-
return <DecoRootLayout siteName="my-site">{children}</DecoRootLayout>;
|
|
249
|
-
}
|
|
250
|
-
```
|
|
79
|
+
## Names and Studio's origins
|
|
251
80
|
|
|
252
|
-
|
|
253
|
-
fine to import the root barrel here — see the rule above.)
|
|
254
|
-
3. **The RSC preview page** passes it to `createDecoPreviewPage`, as shown
|
|
255
|
-
above. The setup function is memoized, so these call sites share one
|
|
256
|
-
successful bootstrap per warm process.
|
|
81
|
+
For a site that needs them in its own code (a route that sets its own headers, a CSP it writes itself), `@decocms/nextjs` exports what the proxy, the pages and `withDeco` use: `DRAFT_PARAM` (`__draft`), `DRAFT_COOKIE` (`__deco_draft`), `DRAFT_HEADER` (`x-deco-draft`), `draftResponseHeaders(pointer)`, `STUDIO_ORIGINS`, `STUDIO_FRAME_ANCESTORS` and `isStudioOrigin(origin)`. They have the same values as `@decocms/tanstack`'s; each binding keeps its own copy and never imports the other.
|
|
257
82
|
|
|
258
|
-
|
|
83
|
+
## next.config
|
|
259
84
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
| `blocks` | Extra/override blocks, merged **over** the directory's blocks. Pass the manifest's default export here (with `blocksDir: false`) to make it the sole block source. |
|
|
264
|
-
| `sections` | The lazy section registry — `sectionImports` from `generate-sections --registry` (see below). |
|
|
265
|
-
| `conventions` | `{ meta, syncComponents, loadingFallbacks }` from `sections.gen.ts` — wires the `export const sync/layout/seo/cache/eager/clientOnly` conventions (see below). |
|
|
266
|
-
| `meta` | Lazy admin meta schema loader: `() => import("deco/meta.gen.json").then(m => m.default)`. Wire this even with a trivial schema — without it, `/deco/meta` (and its `/live/_meta` alias) 503s with `"Schema not initialized"`. |
|
|
267
|
-
| `renderShell` | Admin preview shell config (`{ css, fonts }`). |
|
|
268
|
-
| `previewWrapper` | Admin preview wrapper component. |
|
|
269
|
-
| `productionOrigins`, `customMatchers`, `onResolveError`, `onDanglingReference` | Passed through to `createSiteSetup`. |
|
|
270
|
-
| `extend` | Site-specific wiring that must run *after* core setup (section loaders, legacy SEO key shims, curated post-processing). Receives the loaded blocks. |
|
|
271
|
-
|
|
272
|
-
## 4. `package.json` scripts — non-colliding names
|
|
273
|
-
|
|
274
|
-
Add three codegen scripts. **Do not name any of these `generate:schema`** —
|
|
275
|
-
FastStore sites already own that script name for their own commerce-schema
|
|
276
|
-
codegen, and a collision silently shadows one of the two generators
|
|
277
|
-
depending on script-merge order. Use these names instead:
|
|
278
|
-
|
|
279
|
-
```json
|
|
280
|
-
{
|
|
281
|
-
"scripts": {
|
|
282
|
-
"generate:deco-meta": "tsx node_modules/@decocms/blocks-cli/scripts/generate-schema.ts",
|
|
283
|
-
"generate:deco-sections": "tsx node_modules/@decocms/blocks-cli/scripts/generate-sections.ts --registry",
|
|
284
|
-
"generate:deco-blocks": "tsx node_modules/@decocms/blocks-cli/scripts/generate-blocks-manifest.ts"
|
|
285
|
-
}
|
|
286
|
-
}
|
|
85
|
+
```js
|
|
86
|
+
const { withDeco } = require("@decocms/nextjs/config");
|
|
87
|
+
module.exports = withDeco({ images: { loader: "custom", loaderFile: "./src/image-loader.ts" } });
|
|
287
88
|
```
|
|
288
89
|
|
|
289
|
-
|
|
290
|
-
to `.deco/`, which is exactly where `src/deco/setup.ts` reads them from via
|
|
291
|
-
the `deco/*` path alias (see above). Only pass `--out`/`--out-file` if your
|
|
292
|
-
site has a reason to put the artifact somewhere else.
|
|
293
|
-
|
|
294
|
-
- `generate:deco-meta` runs `blocks-cli`'s `generate-schema.ts`, which scans
|
|
295
|
-
`src/sections/`, `src/loaders/`, and `src/apps/` for `Props` interfaces
|
|
296
|
-
and emits the JSON Schema the admin's `/deco/meta` endpoint serves, to
|
|
297
|
-
`.deco/meta.gen.json` by default.
|
|
298
|
-
- `generate:deco-sections` runs `generate-sections.ts` **with `--registry`**
|
|
299
|
-
— the flag that additionally emits `sectionImports`, the Next.js/webpack
|
|
300
|
-
equivalent of Vite's `import.meta.glob("./sections/**/*.tsx")` (Next has
|
|
301
|
-
no `import.meta.glob` or Vite plugin, so this is generated instead of
|
|
302
|
-
computed at build time). Without `--registry` you only get
|
|
303
|
-
`sectionMeta`/`syncComponents`/`loadingFallbacks`, not the lazy loader map
|
|
304
|
-
`setup.ts` needs for its `sections` option. Defaults to
|
|
305
|
-
`.deco/sections.gen.ts`.
|
|
306
|
-
- `generate:deco-blocks` runs `generate-blocks-manifest.ts`, which emits the
|
|
307
|
-
static-import blocks manifest (see the recommended-block-source section
|
|
308
|
-
above) to `.deco/blocksManifest.gen.ts` by default. Regeneration is
|
|
309
|
-
idempotent — an unchanged block set rewrites nothing, so no-op runs never
|
|
310
|
-
tickle Next's file watcher.
|
|
311
|
-
|
|
312
|
-
Run the first two any time `src/sections/` changes, and
|
|
313
|
-
`generate:deco-blocks` any time a block file is **added or removed** in
|
|
314
|
-
`.deco/blocks/` (content edits to existing files don't need it — the static
|
|
315
|
-
imports pick those up by themselves). Simplest is to wire all three into a
|
|
316
|
-
`predev`/`prebuild` `generate` chain.
|
|
90
|
+
`withDeco` puts v7's two draft header rules before your own (a `?__draft=` query, or the draft cookie: no-store, `Vary: Cookie`, noindex) and adds Studio's origins to `allowedDevOrigins`. Each can be turned off: `withDeco(config, { draftHeaders: false, studioOrigins: false })`. Next sets `Cache-Control` and `Vary` itself on dynamic pages, so only `X-Robots-Tag` is sure to arrive from these rules; the proxy's `applyDraft` sets all three on the responses it makes.
|
|
317
91
|
|
|
318
|
-
##
|
|
319
|
-
|
|
320
|
-
Every non-test `.tsx`/`.ts` file directly under `src/sections/` (recursively)
|
|
321
|
-
becomes a section key, keyed as `site/sections/<path-relative-to-sections-dir>`.
|
|
322
|
-
**This is not opt-in** — `generate-sections.ts` walks the whole directory
|
|
323
|
-
and turns every matching file into a registry entry, whether or not it
|
|
324
|
-
carries any convention exports. Files ending in `.test.ts(x)`, `.spec.ts(x)`,
|
|
325
|
-
`.stories.ts(x)`, or `.gen.ts(x)` are the only ones excluded.
|
|
326
|
-
|
|
327
|
-
The established pattern is a **thin re-export entry file** per section, with
|
|
328
|
-
the actual component implementation living elsewhere (e.g. alongside its
|
|
329
|
-
own subcomponents, styles, and tests, outside `src/sections/`):
|
|
92
|
+
## Images
|
|
330
93
|
|
|
331
94
|
```ts
|
|
332
|
-
// src/
|
|
333
|
-
|
|
334
|
-
|
|
95
|
+
// src/image-loader.ts
|
|
96
|
+
import { vtexCatalogWebp, vtexFileManager } from "@decocms/apps-vtex/image"; // your platform's helpers, if any
|
|
97
|
+
import { createImageUrl, decoCdn } from "@decocms/blocks/image";
|
|
98
|
+
import { createDecoImageLoader, nextImageOptimizer } from "@decocms/nextjs/image-loader";
|
|
99
|
+
|
|
100
|
+
const imageUrl = createImageUrl({
|
|
101
|
+
providers: [
|
|
102
|
+
vtexCatalogWebp(),
|
|
103
|
+
vtexFileManager({ via: "query" }),
|
|
104
|
+
decoCdn({ quality: "high", fit: "contain", layout: "quality-last" }),
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
export default createDecoImageLoader(imageUrl, { fallback: nextImageOptimizer });
|
|
335
108
|
```
|
|
336
109
|
|
|
337
|
-
|
|
338
|
-
CMS-addressable, instead of a directory contest between "real" component
|
|
339
|
-
code and registry wiring.
|
|
340
|
-
|
|
341
|
-
### Convention exports
|
|
342
|
-
|
|
343
|
-
A section's entry file (or the file it re-exports from — the scanner reads
|
|
344
|
-
the entry file's own source, so re-exported `export const` conventions must
|
|
345
|
-
be re-declared or forwarded on the entry file itself, not just the
|
|
346
|
-
implementation file) can opt into these, each read as a literal
|
|
347
|
-
`export const <name> = <value>`:
|
|
348
|
-
|
|
349
|
-
| Export | Effect |
|
|
350
|
-
| --- | --- |
|
|
351
|
-
| `export const sync = true` | Bundled synchronously (not lazy-loaded) — for above-the-fold, always-rendered sections. |
|
|
352
|
-
| `export const layout = true` | Cached as a layout section (Header, Footer, Theme) — resolved once, not per-page. |
|
|
353
|
-
| `export const seo = true` | SEO section — its resolved props are merged into page-level SEO. |
|
|
354
|
-
| `export const cache = "listing"` | SWR-cached section loader results, keyed by the given cache name. |
|
|
355
|
-
| `export const eager = true` | Prefers eager rendering (defers only past the fold threshold). |
|
|
356
|
-
| `export const neverDefer = true` | Always eager, ignoring the fold threshold entirely. |
|
|
357
|
-
| `export const clientOnly = true` | Skips SSR — client-only rendering. |
|
|
358
|
-
| `export function LoadingFallback` | Skeleton component shown while the section loads. |
|
|
359
|
-
|
|
360
|
-
## Verifying your setup
|
|
110
|
+
The loader knows no commerce platform: the site lists its platform's helpers (`@decocms/apps-vtex/image`, `@decocms/apps-shopify/image`) before the Deco CDN, and the first provider that takes a source makes its URL. Any other source goes to `fallback` (`nextImageOptimizer` uses Next's own `/_next/image`), or comes back unchanged. With the providers above, a Next storefront's current loader URLs come out byte for byte (`tests/nextjs-image-loader.golden.test.ts` in the repository), except an already-resized Deco CDN URL in content: it is now re-resized from its `src` instead of becoming `src=image`.
|
|
361
111
|
|
|
362
|
-
`examples/nextjs-smoke` in
|
|
363
|
-
Router build exercising all four surfaces end to end — `withDeco` rewrites,
|
|
364
|
-
the catch-all route, the RSC preview page, `createNextSetup`, and a resolved
|
|
365
|
-
page render. Its preview fixture is a real interactive Client Component, so
|
|
366
|
-
the build also guards the server/client boundary described above. Use it as
|
|
367
|
-
a working reference if any of the above doesn't compose the way you expect.
|
|
112
|
+
`examples/nextjs-binding-smoke` in the repository is a complete app, and its `bun run smoke` checks the whole flow on `next start`.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface DraftPreviewIndicatorProps {
|
|
3
|
+
/** Where "Exit preview" goes; default: the current URL with `?__draft=off`. */
|
|
4
|
+
exitHref?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function DraftPreviewIndicator({ exitHref }?: DraftPreviewIndicatorProps): ReactNode;
|
|
7
|
+
//# sourceMappingURL=DraftPreviewIndicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DraftPreviewIndicator.d.ts","sourceRoot":"","sources":["../src/DraftPreviewIndicator.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,0BAA0B;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,GAAE,0BAA+B,GAAG,SAAS,CAI9F"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The "Preview mode" badge for the request's draft: a Server Component that
|
|
4
|
+
* renders `DraftBadge` (`@decocms/blocks/preview`) only when `bindDraft`
|
|
5
|
+
* bound a draft, so a published page emits nothing.
|
|
6
|
+
*
|
|
7
|
+
* Render it inside the page, after `bindDraft` was awaited, never from a
|
|
8
|
+
* layout: a layout renders alongside the page that fills it, so it may run
|
|
9
|
+
* before the page bound its draft.
|
|
10
|
+
*/
|
|
11
|
+
import { DraftBadge } from "@decocms/blocks/preview";
|
|
12
|
+
import { activeDraftPointer } from "./server/slot.js";
|
|
13
|
+
export function DraftPreviewIndicator({ exitHref } = {}) {
|
|
14
|
+
const pointer = activeDraftPointer();
|
|
15
|
+
if (!pointer)
|
|
16
|
+
return null;
|
|
17
|
+
return _jsx(DraftBadge, { pointer: pointer, exitHref: exitHref });
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=DraftPreviewIndicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DraftPreviewIndicator.js","sourceRoot":"","sources":["../src/DraftPreviewIndicator.tsx"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAOtD,MAAM,UAAU,qBAAqB,CAAC,EAAE,QAAQ,EAAE,GAA+B,EAAE;IACjF,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAI,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `StudioBridge` of `@decocms/blocks/preview` with Studio's origins filled in
|
|
3
|
+
* (`STUDIO_ORIGINS`, `./studio.ts`): the package owns where Studio runs, so a
|
|
4
|
+
* site passes only its name. One inline script and no hooks, so a Server
|
|
5
|
+
* Component renders it as is.
|
|
6
|
+
*/
|
|
7
|
+
import { type StudioBridgeProps as BridgeScriptProps } from "@decocms/blocks/preview";
|
|
8
|
+
import { type ReactNode } from "react";
|
|
9
|
+
/** `site`, and optionally `editShortcut` and `nonce`; Studio's origins are the package's. */
|
|
10
|
+
export type StudioBridgeProps = Omit<BridgeScriptProps, "trustedOrigins">;
|
|
11
|
+
/**
|
|
12
|
+
* Lets Studio's site editor select and edit sections on the page when Studio
|
|
13
|
+
* frames it. Render it once, in the root layout's `<body>`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function StudioBridge(props: StudioBridgeProps): ReactNode;
|
|
16
|
+
//# sourceMappingURL=StudioBridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StudioBridge.d.ts","sourceRoot":"","sources":["../src/StudioBridge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAEL,KAAK,iBAAiB,IAAI,iBAAiB,EAC5C,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtD,6FAA6F;AAC7F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;AAE1E;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,SAAS,CAEhE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `StudioBridge` of `@decocms/blocks/preview` with Studio's origins filled in
|
|
3
|
+
* (`STUDIO_ORIGINS`, `./studio.ts`): the package owns where Studio runs, so a
|
|
4
|
+
* site passes only its name. One inline script and no hooks, so a Server
|
|
5
|
+
* Component renders it as is.
|
|
6
|
+
*/
|
|
7
|
+
import { StudioBridge as BridgeScript, } from "@decocms/blocks/preview";
|
|
8
|
+
import { createElement } from "react";
|
|
9
|
+
import { STUDIO_ORIGINS } from "./studio.js";
|
|
10
|
+
/**
|
|
11
|
+
* Lets Studio's site editor select and edit sections on the page when Studio
|
|
12
|
+
* frames it. Render it once, in the root layout's `<body>`.
|
|
13
|
+
*/
|
|
14
|
+
export function StudioBridge(props) {
|
|
15
|
+
return createElement(BridgeScript, { ...props, trustedOrigins: STUDIO_ORIGINS });
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=StudioBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StudioBridge.js","sourceRoot":"","sources":["../src/StudioBridge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,YAAY,IAAI,YAAY,GAE7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAkB,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAK7C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,OAAO,aAAa,CAAC,YAAY,EAAE,EAAE,GAAG,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;AACnF,CAAC"}
|
package/dist/draft.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The draft names and headers of a Deco Next.js site: the `?__draft=` link,
|
|
3
|
+
* the cookie that keeps a preview going, the request header the proxy hands
|
|
4
|
+
* the pages, and the response headers of a page rendered from a draft. The
|
|
5
|
+
* proxy reads and writes them (`./drafts.ts`, `./proxy`); the pages read the
|
|
6
|
+
* header (`./server`); `./config/index.cjs` repeats them (`config.test.ts`
|
|
7
|
+
* holds them equal). This package's own copy: it never imports
|
|
8
|
+
* `@decocms/tanstack`. No imports, no state: safe in every bundle.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The query parameter a draft link carries (`?__draft=<pointer>`, or `off` to
|
|
12
|
+
* end a preview). The proxy reads it after its host check; reading it
|
|
13
|
+
* directly would skip that check.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DRAFT_PARAM = "__draft";
|
|
16
|
+
/**
|
|
17
|
+
* The cookie that keeps a preview going after the first draft link. Like
|
|
18
|
+
* {@link DRAFT_PARAM}, the proxy reads it after its host check.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DRAFT_COOKIE = "__deco_draft";
|
|
21
|
+
/**
|
|
22
|
+
* The request header the proxy sets on the request it hands the pages once it
|
|
23
|
+
* accepted the draft: the pointer, already checked. The proxy removes any
|
|
24
|
+
* copy that arrives from outside, and `bindDraft` repeats the host check, so a
|
|
25
|
+
* client can't send one itself.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DRAFT_HEADER = "x-deco-draft";
|
|
28
|
+
/**
|
|
29
|
+
* The response headers of a page rendered from a draft: never stored by a
|
|
30
|
+
* browser or a CDN (`Cache-Control: no-store, private`, `Vary: Cookie`) and
|
|
31
|
+
* never indexed (`X-Robots-Tag: noindex, nofollow`). `{}` when `pointer` is
|
|
32
|
+
* `null`, so the result of the draft decision applies as is.
|
|
33
|
+
*/
|
|
34
|
+
export declare function draftResponseHeaders(pointer: string | null | undefined): Record<string, string>;
|
|
35
|
+
//# sourceMappingURL=draft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../src/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC;;;GAGG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO/F"}
|
package/dist/draft.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The draft names and headers of a Deco Next.js site: the `?__draft=` link,
|
|
3
|
+
* the cookie that keeps a preview going, the request header the proxy hands
|
|
4
|
+
* the pages, and the response headers of a page rendered from a draft. The
|
|
5
|
+
* proxy reads and writes them (`./drafts.ts`, `./proxy`); the pages read the
|
|
6
|
+
* header (`./server`); `./config/index.cjs` repeats them (`config.test.ts`
|
|
7
|
+
* holds them equal). This package's own copy: it never imports
|
|
8
|
+
* `@decocms/tanstack`. No imports, no state: safe in every bundle.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The query parameter a draft link carries (`?__draft=<pointer>`, or `off` to
|
|
12
|
+
* end a preview). The proxy reads it after its host check; reading it
|
|
13
|
+
* directly would skip that check.
|
|
14
|
+
*/
|
|
15
|
+
export const DRAFT_PARAM = "__draft";
|
|
16
|
+
/**
|
|
17
|
+
* The cookie that keeps a preview going after the first draft link. Like
|
|
18
|
+
* {@link DRAFT_PARAM}, the proxy reads it after its host check.
|
|
19
|
+
*/
|
|
20
|
+
export const DRAFT_COOKIE = "__deco_draft";
|
|
21
|
+
/**
|
|
22
|
+
* The request header the proxy sets on the request it hands the pages once it
|
|
23
|
+
* accepted the draft: the pointer, already checked. The proxy removes any
|
|
24
|
+
* copy that arrives from outside, and `bindDraft` repeats the host check, so a
|
|
25
|
+
* client can't send one itself.
|
|
26
|
+
*/
|
|
27
|
+
export const DRAFT_HEADER = "x-deco-draft";
|
|
28
|
+
/**
|
|
29
|
+
* The response headers of a page rendered from a draft: never stored by a
|
|
30
|
+
* browser or a CDN (`Cache-Control: no-store, private`, `Vary: Cookie`) and
|
|
31
|
+
* never indexed (`X-Robots-Tag: noindex, nofollow`). `{}` when `pointer` is
|
|
32
|
+
* `null`, so the result of the draft decision applies as is.
|
|
33
|
+
*/
|
|
34
|
+
export function draftResponseHeaders(pointer) {
|
|
35
|
+
if (!pointer)
|
|
36
|
+
return {};
|
|
37
|
+
return {
|
|
38
|
+
"Cache-Control": "no-store, private",
|
|
39
|
+
Vary: "Cookie",
|
|
40
|
+
"X-Robots-Tag": "noindex, nofollow",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=draft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../src/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAkC;IACrE,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO;QACL,eAAe,EAAE,mBAAmB;QACpC,IAAI,EAAE,QAAQ;QACd,cAAc,EAAE,mBAAmB;KACpC,CAAC;AACJ,CAAC"}
|