@cmssy/next 16.0.0 → 16.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -4
- package/dist/{index-ZUEbpOlo.d.cts → index-D6hhjPH3.d.cts} +10 -2
- package/dist/{index-ZUEbpOlo.d.ts → index-D6hhjPH3.d.ts} +10 -2
- package/dist/index.cjs +15 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -1
- package/dist/server.cjs +64 -10
- package/dist/server.d.cts +17 -5
- package/dist/server.d.ts +17 -5
- package/dist/server.js +62 -11
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -45,10 +45,29 @@ the live-edit bridge. A published build does **not** require `editorOrigin`.
|
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
// app/api/draft/route.ts
|
|
48
|
-
import { createDraftRoute } from "@cmssy/next";
|
|
48
|
+
import { createDraftRoute } from "@cmssy/next/server";
|
|
49
49
|
export const GET = createDraftRoute(cmssy);
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Cache, and expire it on publish
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// app/[[...path]]/page.tsx
|
|
56
|
+
export const revalidate = 3600;
|
|
57
|
+
const cache = { revalidate };
|
|
58
|
+
export default createCmssyPage(cmssy, blocks, { editor: CmssyEditor, cache });
|
|
59
|
+
|
|
60
|
+
// app/api/revalidate/route.ts
|
|
61
|
+
import { createCmssyRevalidateRoute } from "@cmssy/next/server";
|
|
62
|
+
export const POST = createCmssyRevalidateRoute({
|
|
63
|
+
secret: process.env.CMSSY_WEBHOOK_SECRET,
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`cache` puts the SDK's published reads into the Next data cache under the
|
|
68
|
+
`cmssy-content` tag; the route expires that tag for a verified `content.changed`
|
|
69
|
+
webhook. Draft mode and the editor always read live.
|
|
70
|
+
|
|
52
71
|
## Edit-mode CSP
|
|
53
72
|
|
|
54
73
|
```ts
|
|
@@ -93,9 +112,13 @@ re-exported from `@cmssy/next` (and `@cmssy/core`).
|
|
|
93
112
|
|
|
94
113
|
## Exports
|
|
95
114
|
|
|
96
|
-
`createCmssyPage`, `
|
|
97
|
-
`
|
|
98
|
-
`
|
|
115
|
+
`@cmssy/next/server`: `createCmssyPage`, `createCmssyEditPage`,
|
|
116
|
+
`createDraftRoute`, `createCmssyRevalidateRoute`, `CmssyLayoutSlot`,
|
|
117
|
+
`resolveCmssyLayout`, `isCmssyEditMode`. `@cmssy/next/middleware`:
|
|
118
|
+
`createCmssyProxy`, `cmssyEditRewrite`, `applyCmssyCsp`, `isCmssyEditRequest`.
|
|
119
|
+
Root: `defineCmssyConfig`, `localizeHref`, `nextRetryMode`, `cmssyCachedFetch`,
|
|
120
|
+
`CMSSY_CONTENT_TAG` and the types. The full list, with signatures, is in
|
|
121
|
+
[docs/reference/sdk-api.md](../../docs/reference/sdk-api.md).
|
|
99
122
|
|
|
100
123
|
## License
|
|
101
124
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CmssyRetryMode, RetryOption, CmssyConfig } from '@cmssy/core';
|
|
1
|
+
import { CmssyRetryMode, FetchLike, RetryOption, CmssyConfig } from '@cmssy/core';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import { ComponentType } from 'react';
|
|
4
4
|
import { CmssyPageData, CmssyFormDefinition, BlockDefinition } from '@cmssy/react';
|
|
@@ -7,6 +7,13 @@ import { EditBridgeConfig } from '@cmssy/react/client';
|
|
|
7
7
|
declare const NEXT_BUILD_PHASE = "phase-production-build";
|
|
8
8
|
declare function nextRetryMode(): CmssyRetryMode;
|
|
9
9
|
|
|
10
|
+
declare const CMSSY_CONTENT_TAG = "cmssy-content";
|
|
11
|
+
interface CmssyDataCacheOptions {
|
|
12
|
+
revalidate: number | false;
|
|
13
|
+
tags?: string[];
|
|
14
|
+
}
|
|
15
|
+
declare function cmssyCachedFetch(cache: CmssyDataCacheOptions): FetchLike;
|
|
16
|
+
|
|
10
17
|
interface CmssyEditorProps {
|
|
11
18
|
page: CmssyPageData;
|
|
12
19
|
locale: string;
|
|
@@ -28,6 +35,7 @@ interface CreateCmssyPageOptions {
|
|
|
28
35
|
path?: string;
|
|
29
36
|
appContext?: CmssyAppContext;
|
|
30
37
|
retry?: RetryOption;
|
|
38
|
+
cache?: CmssyDataCacheOptions;
|
|
31
39
|
}
|
|
32
40
|
interface CatchAllParams {
|
|
33
41
|
path?: string[];
|
|
@@ -40,4 +48,4 @@ interface CatchAllProps {
|
|
|
40
48
|
declare function createCmssyPage(config: CmssyConfig, blocks: BlockDefinition[], options?: CreateCmssyPageOptions): ({ params, searchParams, }: CatchAllProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
41
49
|
declare function createCmssyEditPage(config: CmssyConfig, blocks: BlockDefinition[], options?: CreateCmssyPageOptions): ({ params, searchParams, }: CatchAllProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
42
50
|
|
|
43
|
-
export { type
|
|
51
|
+
export { type CmssyDataCacheOptions as C, NEXT_BUILD_PHASE as N, CMSSY_CONTENT_TAG as a, type CmssyAppContext as b, type CmssyEditorProps as c, type CreateCmssyPageOptions as d, cmssyCachedFetch as e, createCmssyEditPage as f, createCmssyPage as g, nextRetryMode as n };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CmssyRetryMode, RetryOption, CmssyConfig } from '@cmssy/core';
|
|
1
|
+
import { CmssyRetryMode, FetchLike, RetryOption, CmssyConfig } from '@cmssy/core';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import { ComponentType } from 'react';
|
|
4
4
|
import { CmssyPageData, CmssyFormDefinition, BlockDefinition } from '@cmssy/react';
|
|
@@ -7,6 +7,13 @@ import { EditBridgeConfig } from '@cmssy/react/client';
|
|
|
7
7
|
declare const NEXT_BUILD_PHASE = "phase-production-build";
|
|
8
8
|
declare function nextRetryMode(): CmssyRetryMode;
|
|
9
9
|
|
|
10
|
+
declare const CMSSY_CONTENT_TAG = "cmssy-content";
|
|
11
|
+
interface CmssyDataCacheOptions {
|
|
12
|
+
revalidate: number | false;
|
|
13
|
+
tags?: string[];
|
|
14
|
+
}
|
|
15
|
+
declare function cmssyCachedFetch(cache: CmssyDataCacheOptions): FetchLike;
|
|
16
|
+
|
|
10
17
|
interface CmssyEditorProps {
|
|
11
18
|
page: CmssyPageData;
|
|
12
19
|
locale: string;
|
|
@@ -28,6 +35,7 @@ interface CreateCmssyPageOptions {
|
|
|
28
35
|
path?: string;
|
|
29
36
|
appContext?: CmssyAppContext;
|
|
30
37
|
retry?: RetryOption;
|
|
38
|
+
cache?: CmssyDataCacheOptions;
|
|
31
39
|
}
|
|
32
40
|
interface CatchAllParams {
|
|
33
41
|
path?: string[];
|
|
@@ -40,4 +48,4 @@ interface CatchAllProps {
|
|
|
40
48
|
declare function createCmssyPage(config: CmssyConfig, blocks: BlockDefinition[], options?: CreateCmssyPageOptions): ({ params, searchParams, }: CatchAllProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
41
49
|
declare function createCmssyEditPage(config: CmssyConfig, blocks: BlockDefinition[], options?: CreateCmssyPageOptions): ({ params, searchParams, }: CatchAllProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
42
50
|
|
|
43
|
-
export { type
|
|
51
|
+
export { type CmssyDataCacheOptions as C, NEXT_BUILD_PHASE as N, CMSSY_CONTENT_TAG as a, type CmssyAppContext as b, type CmssyEditorProps as c, type CreateCmssyPageOptions as d, cmssyCachedFetch as e, createCmssyEditPage as f, createCmssyPage as g, nextRetryMode as n };
|
package/dist/index.cjs
CHANGED
|
@@ -11,6 +11,19 @@ function nextRetryMode() {
|
|
|
11
11
|
return phase === NEXT_BUILD_PHASE ? "build" : "interactive";
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
// src/data-cache.ts
|
|
15
|
+
var CMSSY_CONTENT_TAG = "cmssy-content";
|
|
16
|
+
function cmssyContentTags(tags = []) {
|
|
17
|
+
return [.../* @__PURE__ */ new Set([CMSSY_CONTENT_TAG, ...tags])];
|
|
18
|
+
}
|
|
19
|
+
function cmssyCachedFetch(cache) {
|
|
20
|
+
const next = {
|
|
21
|
+
revalidate: cache.revalidate,
|
|
22
|
+
tags: cmssyContentTags(cache.tags)
|
|
23
|
+
};
|
|
24
|
+
return (url, init) => fetch(url, { ...init, next });
|
|
25
|
+
}
|
|
26
|
+
|
|
14
27
|
Object.defineProperty(exports, "CMSSY_EDIT_HEADER", {
|
|
15
28
|
enumerable: true,
|
|
16
29
|
get: function () { return core.CMSSY_EDIT_HEADER; }
|
|
@@ -55,5 +68,7 @@ Object.defineProperty(exports, "verifyCmssyWebhook", {
|
|
|
55
68
|
enumerable: true,
|
|
56
69
|
get: function () { return core.verifyCmssyWebhook; }
|
|
57
70
|
});
|
|
71
|
+
exports.CMSSY_CONTENT_TAG = CMSSY_CONTENT_TAG;
|
|
58
72
|
exports.NEXT_BUILD_PHASE = NEXT_BUILD_PHASE;
|
|
73
|
+
exports.cmssyCachedFetch = cmssyCachedFetch;
|
|
59
74
|
exports.nextRetryMode = nextRetryMode;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_LOCALE_HEADER, CMSSY_SECRET_QUERY_PARAM, CmssyConfig, CmssyEnvConfig, CmssyLayout, CmssyPageData, CmssyPageMeta, CmssyPageSummary, CmssyRegion, CmssyRegionOf, CmssyRegionSettings, CmssyRegionSettingsOf, CmssyRetryMode, CmssyWebhookError, CmssyWebhookEvent, DEFAULT_CMSSY_EDITOR_ORIGINS, LayoutRegion, RetryOption, RetryPolicy, VerifyCmssyWebhookOptions, defineCmssyConfig, defineCmssyLayout, localizeHref, resolveEditorOrigin, verifyCmssyWebhook } from '@cmssy/core';
|
|
2
|
-
export {
|
|
2
|
+
export { a as CMSSY_CONTENT_TAG, b as CmssyAppContext, C as CmssyDataCacheOptions, c as CmssyEditorProps, d as CreateCmssyPageOptions, N as NEXT_BUILD_PHASE, e as cmssyCachedFetch, n as nextRetryMode } from './index-D6hhjPH3.cjs';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@cmssy/react';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_LOCALE_HEADER, CMSSY_SECRET_QUERY_PARAM, CmssyConfig, CmssyEnvConfig, CmssyLayout, CmssyPageData, CmssyPageMeta, CmssyPageSummary, CmssyRegion, CmssyRegionOf, CmssyRegionSettings, CmssyRegionSettingsOf, CmssyRetryMode, CmssyWebhookError, CmssyWebhookEvent, DEFAULT_CMSSY_EDITOR_ORIGINS, LayoutRegion, RetryOption, RetryPolicy, VerifyCmssyWebhookOptions, defineCmssyConfig, defineCmssyLayout, localizeHref, resolveEditorOrigin, verifyCmssyWebhook } from '@cmssy/core';
|
|
2
|
-
export {
|
|
2
|
+
export { a as CMSSY_CONTENT_TAG, b as CmssyAppContext, C as CmssyDataCacheOptions, c as CmssyEditorProps, d as CreateCmssyPageOptions, N as NEXT_BUILD_PHASE, e as cmssyCachedFetch, n as nextRetryMode } from './index-D6hhjPH3.js';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@cmssy/react';
|
package/dist/index.js
CHANGED
|
@@ -9,4 +9,17 @@ function nextRetryMode() {
|
|
|
9
9
|
return phase === NEXT_BUILD_PHASE ? "build" : "interactive";
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// src/data-cache.ts
|
|
13
|
+
var CMSSY_CONTENT_TAG = "cmssy-content";
|
|
14
|
+
function cmssyContentTags(tags = []) {
|
|
15
|
+
return [.../* @__PURE__ */ new Set([CMSSY_CONTENT_TAG, ...tags])];
|
|
16
|
+
}
|
|
17
|
+
function cmssyCachedFetch(cache) {
|
|
18
|
+
const next = {
|
|
19
|
+
revalidate: cache.revalidate,
|
|
20
|
+
tags: cmssyContentTags(cache.tags)
|
|
21
|
+
};
|
|
22
|
+
return (url, init) => fetch(url, { ...init, next });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { CMSSY_CONTENT_TAG, NEXT_BUILD_PHASE, cmssyCachedFetch, nextRetryMode };
|
package/dist/server.cjs
CHANGED
|
@@ -9,6 +9,7 @@ var internalServer = require('@cmssy/react/internal-server');
|
|
|
9
9
|
var internal = require('@cmssy/core/internal');
|
|
10
10
|
var core = require('@cmssy/core');
|
|
11
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
|
+
var cache = require('next/cache');
|
|
12
13
|
|
|
13
14
|
// src/server.ts
|
|
14
15
|
|
|
@@ -18,6 +19,19 @@ function nextRetryMode() {
|
|
|
18
19
|
const phase = typeof process !== "undefined" ? process.env?.NEXT_PHASE : void 0;
|
|
19
20
|
return phase === NEXT_BUILD_PHASE ? "build" : "interactive";
|
|
20
21
|
}
|
|
22
|
+
|
|
23
|
+
// src/data-cache.ts
|
|
24
|
+
var CMSSY_CONTENT_TAG = "cmssy-content";
|
|
25
|
+
function cmssyContentTags(tags = []) {
|
|
26
|
+
return [.../* @__PURE__ */ new Set([CMSSY_CONTENT_TAG, ...tags])];
|
|
27
|
+
}
|
|
28
|
+
function cmssyCachedFetch(cache) {
|
|
29
|
+
const next = {
|
|
30
|
+
revalidate: cache.revalidate,
|
|
31
|
+
tags: cmssyContentTags(cache.tags)
|
|
32
|
+
};
|
|
33
|
+
return (url, init) => fetch(url, { ...init, next });
|
|
34
|
+
}
|
|
21
35
|
function hasEditFlag(value) {
|
|
22
36
|
return Array.isArray(value) ? value.includes("1") : value === "1";
|
|
23
37
|
}
|
|
@@ -49,7 +63,8 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
49
63
|
workspaceSlug: config.workspaceSlug
|
|
50
64
|
};
|
|
51
65
|
const client = react.createCmssyClient(clientConfig);
|
|
52
|
-
const
|
|
66
|
+
const retryOptions = { retry: options?.retry ?? nextRetryMode() };
|
|
67
|
+
const cachedFetch = options?.cache ? cmssyCachedFetch(options.cache) : void 0;
|
|
53
68
|
const fixedPath = options?.path?.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
54
69
|
return async function CmssyCatchAllPage({
|
|
55
70
|
params,
|
|
@@ -70,6 +85,7 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
70
85
|
}
|
|
71
86
|
const editMode = isEnabled || editorActive;
|
|
72
87
|
const devAllowed = internal.isDevelopment() && Boolean(config.devToken?.trim());
|
|
88
|
+
const requestOptions = cachedFetch && !editMode && !devAllowed ? { ...retryOptions, fetch: cachedFetch } : retryOptions;
|
|
73
89
|
const siteLocales = await internal.resolveSiteLocales(clientConfig, requestOptions);
|
|
74
90
|
const { defaultLocale, locales: enabledLocales } = siteLocales;
|
|
75
91
|
const split = internal.splitLocaleFromPath(path, siteLocales);
|
|
@@ -253,10 +269,49 @@ function createDraftRoute(config) {
|
|
|
253
269
|
navigation.redirect(location);
|
|
254
270
|
};
|
|
255
271
|
}
|
|
272
|
+
var SIGNATURE_HEADER = "x-cmssy-signature";
|
|
273
|
+
function createCmssyRevalidateRoute(config) {
|
|
274
|
+
const tags = cmssyContentTags(config.tags);
|
|
275
|
+
const secrets = (Array.isArray(config.secret) ? config.secret : [config.secret]).filter((secret) => Boolean(secret));
|
|
276
|
+
return async function POST(request) {
|
|
277
|
+
if (secrets.length === 0) {
|
|
278
|
+
return new Response(
|
|
279
|
+
"cmssy: createCmssyRevalidateRoute has no signing secret - set CMSSY_WEBHOOK_SECRET to the secret cmssy shows for this webhook and pass it as `secret`",
|
|
280
|
+
{ status: 500 }
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
const body = await request.text();
|
|
284
|
+
try {
|
|
285
|
+
await core.verifyCmssyWebhook({
|
|
286
|
+
body,
|
|
287
|
+
signatureHeader: request.headers.get(SIGNATURE_HEADER),
|
|
288
|
+
secret: secrets,
|
|
289
|
+
toleranceSeconds: config.toleranceSeconds
|
|
290
|
+
});
|
|
291
|
+
} catch (err) {
|
|
292
|
+
if (err instanceof core.CmssyWebhookError) {
|
|
293
|
+
return new Response(err.message, { status: 401 });
|
|
294
|
+
}
|
|
295
|
+
throw err;
|
|
296
|
+
}
|
|
297
|
+
for (const tag of tags) cache.revalidateTag(tag, { expire: 0 });
|
|
298
|
+
return Response.json({ revalidated: tags });
|
|
299
|
+
};
|
|
300
|
+
}
|
|
256
301
|
async function isCmssyEditMode() {
|
|
257
302
|
const h = await headers.headers();
|
|
258
303
|
return h.get(core.CMSSY_EDIT_HEADER) === "1";
|
|
259
304
|
}
|
|
305
|
+
function resolveCmssyLayout(config, options) {
|
|
306
|
+
const { cache, ...rest } = options;
|
|
307
|
+
const live = rest.editMode || rest.preview === true;
|
|
308
|
+
const fetchImpl = rest.fetch ?? (cache && !live ? cmssyCachedFetch(cache) : void 0);
|
|
309
|
+
return react.resolveCmssyLayout(config, {
|
|
310
|
+
...rest,
|
|
311
|
+
retry: rest.retry ?? nextRetryMode(),
|
|
312
|
+
...fetchImpl ? { fetch: fetchImpl } : {}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
260
315
|
async function CmssyLayoutSlot({
|
|
261
316
|
config,
|
|
262
317
|
blocks,
|
|
@@ -269,9 +324,10 @@ async function CmssyLayoutSlot({
|
|
|
269
324
|
editable,
|
|
270
325
|
appContext,
|
|
271
326
|
retry,
|
|
327
|
+
cache,
|
|
272
328
|
children
|
|
273
329
|
}) {
|
|
274
|
-
const layout = await
|
|
330
|
+
const layout = await resolveCmssyLayout(config, {
|
|
275
331
|
region,
|
|
276
332
|
blocks,
|
|
277
333
|
editMode,
|
|
@@ -279,25 +335,23 @@ async function CmssyLayoutSlot({
|
|
|
279
335
|
editable,
|
|
280
336
|
...page !== void 0 ? { page } : {},
|
|
281
337
|
appContext,
|
|
282
|
-
retry
|
|
338
|
+
retry,
|
|
339
|
+
cache,
|
|
283
340
|
...explicitLocale !== void 0 ? { locale: explicitLocale } : { path: path ?? [] }
|
|
284
341
|
});
|
|
285
342
|
if (!children) return layout.element;
|
|
286
343
|
const { groups, settings, page: routed, element } = layout;
|
|
287
344
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({ groups, settings, page: routed, element }) });
|
|
288
345
|
}
|
|
289
|
-
function resolveCmssyLayout2(config, options) {
|
|
290
|
-
return react.resolveCmssyLayout(config, {
|
|
291
|
-
...options,
|
|
292
|
-
retry: options.retry ?? nextRetryMode()
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
346
|
|
|
347
|
+
exports.CMSSY_CONTENT_TAG = CMSSY_CONTENT_TAG;
|
|
296
348
|
exports.CmssyLayoutSlot = CmssyLayoutSlot;
|
|
297
349
|
exports.NEXT_BUILD_PHASE = NEXT_BUILD_PHASE;
|
|
350
|
+
exports.cmssyCachedFetch = cmssyCachedFetch;
|
|
298
351
|
exports.createCmssyEditPage = createCmssyEditPage;
|
|
299
352
|
exports.createCmssyPage = createCmssyPage;
|
|
353
|
+
exports.createCmssyRevalidateRoute = createCmssyRevalidateRoute;
|
|
300
354
|
exports.createDraftRoute = createDraftRoute;
|
|
301
355
|
exports.isCmssyEditMode = isCmssyEditMode;
|
|
302
356
|
exports.nextRetryMode = nextRetryMode;
|
|
303
|
-
exports.resolveCmssyLayout =
|
|
357
|
+
exports.resolveCmssyLayout = resolveCmssyLayout;
|
package/dist/server.d.cts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { C as CmssyDataCacheOptions } from './index-D6hhjPH3.cjs';
|
|
2
|
+
export { a as CMSSY_CONTENT_TAG, b as CmssyAppContext, c as CmssyEditorProps, d as CreateCmssyPageOptions, N as NEXT_BUILD_PHASE, e as cmssyCachedFetch, f as createCmssyEditPage, g as createCmssyPage, n as nextRetryMode } from './index-D6hhjPH3.cjs';
|
|
2
3
|
import { CmssyConfig, CmssyRegionOf, RetryOption } from '@cmssy/core';
|
|
3
4
|
export { CmssyRetryMode, RetryOption, RetryPolicy } from '@cmssy/core';
|
|
4
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
6
|
import { ComponentType, ReactNode } from 'react';
|
|
6
|
-
import { BlockDefinition, CmssyLayoutEditableProps, CmssyLayoutResolution, ResolveCmssyLayoutOptions } from '@cmssy/react';
|
|
7
|
-
export { CmssyLayoutEditableProps, CmssyLayoutResolution
|
|
7
|
+
import { BlockDefinition, CmssyLayoutEditableProps, CmssyLayoutResolution, ResolveCmssyLayoutOptions as ResolveCmssyLayoutOptions$1 } from '@cmssy/react';
|
|
8
|
+
export { CmssyLayoutEditableProps, CmssyLayoutResolution } from '@cmssy/react';
|
|
8
9
|
import '@cmssy/react/client';
|
|
9
10
|
|
|
10
11
|
type CmssyDraftRouteConfig = Pick<CmssyConfig, "draftSecret"> & {
|
|
@@ -12,6 +13,13 @@ type CmssyDraftRouteConfig = Pick<CmssyConfig, "draftSecret"> & {
|
|
|
12
13
|
};
|
|
13
14
|
declare function createDraftRoute(config: CmssyDraftRouteConfig): (request: Request) => Promise<Response>;
|
|
14
15
|
|
|
16
|
+
interface CmssyRevalidateRouteConfig {
|
|
17
|
+
secret: string | string[] | undefined;
|
|
18
|
+
tags?: string[];
|
|
19
|
+
toleranceSeconds?: number;
|
|
20
|
+
}
|
|
21
|
+
declare function createCmssyRevalidateRoute(config: CmssyRevalidateRouteConfig): (request: Request) => Promise<Response>;
|
|
22
|
+
|
|
15
23
|
declare function isCmssyEditMode(): Promise<boolean>;
|
|
16
24
|
|
|
17
25
|
type CmssyLayoutSlotRenderProps<C extends CmssyConfig = CmssyConfig, P extends CmssyRegionOf<C> = CmssyRegionOf<C>> = Pick<CmssyLayoutResolution<C, P>, "groups" | "settings" | "page" | "element">;
|
|
@@ -25,6 +33,7 @@ interface CmssyLayoutSlotBaseProps<C extends CmssyConfig, P extends CmssyRegionO
|
|
|
25
33
|
editable: ComponentType<CmssyLayoutEditableProps>;
|
|
26
34
|
appContext?: Record<string, unknown>;
|
|
27
35
|
retry?: RetryOption;
|
|
36
|
+
cache?: CmssyDataCacheOptions;
|
|
28
37
|
children?: (layout: CmssyLayoutSlotRenderProps<C, P>) => ReactNode;
|
|
29
38
|
}
|
|
30
39
|
type CmssyLayoutSlotLocaleSource = {
|
|
@@ -35,8 +44,11 @@ type CmssyLayoutSlotLocaleSource = {
|
|
|
35
44
|
path?: never;
|
|
36
45
|
};
|
|
37
46
|
type CmssyLayoutSlotProps<C extends CmssyConfig = CmssyConfig, P extends CmssyRegionOf<C> = CmssyRegionOf<C>> = CmssyLayoutSlotBaseProps<C, P> & CmssyLayoutSlotLocaleSource;
|
|
38
|
-
declare function CmssyLayoutSlot<C extends CmssyConfig, P extends CmssyRegionOf<C>>({ config, blocks, region, path, locale: explicitLocale, editMode, preview, page, editable, appContext, retry, children, }: CmssyLayoutSlotProps<C, P>): Promise<react_jsx_runtime.JSX.Element>;
|
|
47
|
+
declare function CmssyLayoutSlot<C extends CmssyConfig, P extends CmssyRegionOf<C>>({ config, blocks, region, path, locale: explicitLocale, editMode, preview, page, editable, appContext, retry, cache, children, }: CmssyLayoutSlotProps<C, P>): Promise<react_jsx_runtime.JSX.Element>;
|
|
39
48
|
|
|
49
|
+
type ResolveCmssyLayoutOptions<C extends CmssyConfig, P extends CmssyRegionOf<C>> = ResolveCmssyLayoutOptions$1<C, P> & {
|
|
50
|
+
cache?: CmssyDataCacheOptions;
|
|
51
|
+
};
|
|
40
52
|
declare function resolveCmssyLayout<C extends CmssyConfig, P extends CmssyRegionOf<C>>(config: C, options: ResolveCmssyLayoutOptions<C, P>): Promise<CmssyLayoutResolution<C, P>>;
|
|
41
53
|
|
|
42
|
-
export { type CmssyDraftRouteConfig, CmssyLayoutSlot, type CmssyLayoutSlotProps, type CmssyLayoutSlotRenderProps, createDraftRoute, isCmssyEditMode, resolveCmssyLayout };
|
|
54
|
+
export { CmssyDataCacheOptions, type CmssyDraftRouteConfig, CmssyLayoutSlot, type CmssyLayoutSlotProps, type CmssyLayoutSlotRenderProps, type CmssyRevalidateRouteConfig, type ResolveCmssyLayoutOptions, createCmssyRevalidateRoute, createDraftRoute, isCmssyEditMode, resolveCmssyLayout };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { C as CmssyDataCacheOptions } from './index-D6hhjPH3.js';
|
|
2
|
+
export { a as CMSSY_CONTENT_TAG, b as CmssyAppContext, c as CmssyEditorProps, d as CreateCmssyPageOptions, N as NEXT_BUILD_PHASE, e as cmssyCachedFetch, f as createCmssyEditPage, g as createCmssyPage, n as nextRetryMode } from './index-D6hhjPH3.js';
|
|
2
3
|
import { CmssyConfig, CmssyRegionOf, RetryOption } from '@cmssy/core';
|
|
3
4
|
export { CmssyRetryMode, RetryOption, RetryPolicy } from '@cmssy/core';
|
|
4
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
6
|
import { ComponentType, ReactNode } from 'react';
|
|
6
|
-
import { BlockDefinition, CmssyLayoutEditableProps, CmssyLayoutResolution, ResolveCmssyLayoutOptions } from '@cmssy/react';
|
|
7
|
-
export { CmssyLayoutEditableProps, CmssyLayoutResolution
|
|
7
|
+
import { BlockDefinition, CmssyLayoutEditableProps, CmssyLayoutResolution, ResolveCmssyLayoutOptions as ResolveCmssyLayoutOptions$1 } from '@cmssy/react';
|
|
8
|
+
export { CmssyLayoutEditableProps, CmssyLayoutResolution } from '@cmssy/react';
|
|
8
9
|
import '@cmssy/react/client';
|
|
9
10
|
|
|
10
11
|
type CmssyDraftRouteConfig = Pick<CmssyConfig, "draftSecret"> & {
|
|
@@ -12,6 +13,13 @@ type CmssyDraftRouteConfig = Pick<CmssyConfig, "draftSecret"> & {
|
|
|
12
13
|
};
|
|
13
14
|
declare function createDraftRoute(config: CmssyDraftRouteConfig): (request: Request) => Promise<Response>;
|
|
14
15
|
|
|
16
|
+
interface CmssyRevalidateRouteConfig {
|
|
17
|
+
secret: string | string[] | undefined;
|
|
18
|
+
tags?: string[];
|
|
19
|
+
toleranceSeconds?: number;
|
|
20
|
+
}
|
|
21
|
+
declare function createCmssyRevalidateRoute(config: CmssyRevalidateRouteConfig): (request: Request) => Promise<Response>;
|
|
22
|
+
|
|
15
23
|
declare function isCmssyEditMode(): Promise<boolean>;
|
|
16
24
|
|
|
17
25
|
type CmssyLayoutSlotRenderProps<C extends CmssyConfig = CmssyConfig, P extends CmssyRegionOf<C> = CmssyRegionOf<C>> = Pick<CmssyLayoutResolution<C, P>, "groups" | "settings" | "page" | "element">;
|
|
@@ -25,6 +33,7 @@ interface CmssyLayoutSlotBaseProps<C extends CmssyConfig, P extends CmssyRegionO
|
|
|
25
33
|
editable: ComponentType<CmssyLayoutEditableProps>;
|
|
26
34
|
appContext?: Record<string, unknown>;
|
|
27
35
|
retry?: RetryOption;
|
|
36
|
+
cache?: CmssyDataCacheOptions;
|
|
28
37
|
children?: (layout: CmssyLayoutSlotRenderProps<C, P>) => ReactNode;
|
|
29
38
|
}
|
|
30
39
|
type CmssyLayoutSlotLocaleSource = {
|
|
@@ -35,8 +44,11 @@ type CmssyLayoutSlotLocaleSource = {
|
|
|
35
44
|
path?: never;
|
|
36
45
|
};
|
|
37
46
|
type CmssyLayoutSlotProps<C extends CmssyConfig = CmssyConfig, P extends CmssyRegionOf<C> = CmssyRegionOf<C>> = CmssyLayoutSlotBaseProps<C, P> & CmssyLayoutSlotLocaleSource;
|
|
38
|
-
declare function CmssyLayoutSlot<C extends CmssyConfig, P extends CmssyRegionOf<C>>({ config, blocks, region, path, locale: explicitLocale, editMode, preview, page, editable, appContext, retry, children, }: CmssyLayoutSlotProps<C, P>): Promise<react_jsx_runtime.JSX.Element>;
|
|
47
|
+
declare function CmssyLayoutSlot<C extends CmssyConfig, P extends CmssyRegionOf<C>>({ config, blocks, region, path, locale: explicitLocale, editMode, preview, page, editable, appContext, retry, cache, children, }: CmssyLayoutSlotProps<C, P>): Promise<react_jsx_runtime.JSX.Element>;
|
|
39
48
|
|
|
49
|
+
type ResolveCmssyLayoutOptions<C extends CmssyConfig, P extends CmssyRegionOf<C>> = ResolveCmssyLayoutOptions$1<C, P> & {
|
|
50
|
+
cache?: CmssyDataCacheOptions;
|
|
51
|
+
};
|
|
40
52
|
declare function resolveCmssyLayout<C extends CmssyConfig, P extends CmssyRegionOf<C>>(config: C, options: ResolveCmssyLayoutOptions<C, P>): Promise<CmssyLayoutResolution<C, P>>;
|
|
41
53
|
|
|
42
|
-
export { type CmssyDraftRouteConfig, CmssyLayoutSlot, type CmssyLayoutSlotProps, type CmssyLayoutSlotRenderProps, createDraftRoute, isCmssyEditMode, resolveCmssyLayout };
|
|
54
|
+
export { CmssyDataCacheOptions, type CmssyDraftRouteConfig, CmssyLayoutSlot, type CmssyLayoutSlotProps, type CmssyLayoutSlotRenderProps, type CmssyRevalidateRouteConfig, type ResolveCmssyLayoutOptions, createCmssyRevalidateRoute, createDraftRoute, isCmssyEditMode, resolveCmssyLayout };
|
package/dist/server.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
import { draftMode, headers } from 'next/headers';
|
|
3
3
|
import { notFound, redirect } from 'next/navigation';
|
|
4
|
-
import { createCmssyClient, CmssyServerPage, resolveCmssyLayout } from '@cmssy/react';
|
|
4
|
+
import { createCmssyClient, CmssyServerPage, resolveCmssyLayout as resolveCmssyLayout$1 } from '@cmssy/react';
|
|
5
5
|
import { CmssyLocaleProvider } from '@cmssy/react/internal';
|
|
6
6
|
import { blocksToSchemas, resolveEditorBlockData } from '@cmssy/react/internal-server';
|
|
7
7
|
import { isDevelopment, resolveSiteLocales, splitLocaleFromPath, fetchPage, resolveForms, toCspOrigin, cmssySecretsMatch } from '@cmssy/core/internal';
|
|
8
|
-
import { CMSSY_SECRET_QUERY_PARAM, resolveEditorOrigin, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM } from '@cmssy/core';
|
|
8
|
+
import { CMSSY_SECRET_QUERY_PARAM, resolveEditorOrigin, verifyCmssyWebhook, CmssyWebhookError, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM } from '@cmssy/core';
|
|
9
9
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
10
|
+
import { revalidateTag } from 'next/cache';
|
|
10
11
|
|
|
11
12
|
// src/server.ts
|
|
12
13
|
|
|
@@ -16,6 +17,19 @@ function nextRetryMode() {
|
|
|
16
17
|
const phase = typeof process !== "undefined" ? process.env?.NEXT_PHASE : void 0;
|
|
17
18
|
return phase === NEXT_BUILD_PHASE ? "build" : "interactive";
|
|
18
19
|
}
|
|
20
|
+
|
|
21
|
+
// src/data-cache.ts
|
|
22
|
+
var CMSSY_CONTENT_TAG = "cmssy-content";
|
|
23
|
+
function cmssyContentTags(tags = []) {
|
|
24
|
+
return [.../* @__PURE__ */ new Set([CMSSY_CONTENT_TAG, ...tags])];
|
|
25
|
+
}
|
|
26
|
+
function cmssyCachedFetch(cache) {
|
|
27
|
+
const next = {
|
|
28
|
+
revalidate: cache.revalidate,
|
|
29
|
+
tags: cmssyContentTags(cache.tags)
|
|
30
|
+
};
|
|
31
|
+
return (url, init) => fetch(url, { ...init, next });
|
|
32
|
+
}
|
|
19
33
|
function hasEditFlag(value) {
|
|
20
34
|
return Array.isArray(value) ? value.includes("1") : value === "1";
|
|
21
35
|
}
|
|
@@ -47,7 +61,8 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
47
61
|
workspaceSlug: config.workspaceSlug
|
|
48
62
|
};
|
|
49
63
|
const client = createCmssyClient(clientConfig);
|
|
50
|
-
const
|
|
64
|
+
const retryOptions = { retry: options?.retry ?? nextRetryMode() };
|
|
65
|
+
const cachedFetch = options?.cache ? cmssyCachedFetch(options.cache) : void 0;
|
|
51
66
|
const fixedPath = options?.path?.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
52
67
|
return async function CmssyCatchAllPage({
|
|
53
68
|
params,
|
|
@@ -68,6 +83,7 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
68
83
|
}
|
|
69
84
|
const editMode = isEnabled || editorActive;
|
|
70
85
|
const devAllowed = isDevelopment() && Boolean(config.devToken?.trim());
|
|
86
|
+
const requestOptions = cachedFetch && !editMode && !devAllowed ? { ...retryOptions, fetch: cachedFetch } : retryOptions;
|
|
71
87
|
const siteLocales = await resolveSiteLocales(clientConfig, requestOptions);
|
|
72
88
|
const { defaultLocale, locales: enabledLocales } = siteLocales;
|
|
73
89
|
const split = splitLocaleFromPath(path, siteLocales);
|
|
@@ -251,10 +267,49 @@ function createDraftRoute(config) {
|
|
|
251
267
|
redirect(location);
|
|
252
268
|
};
|
|
253
269
|
}
|
|
270
|
+
var SIGNATURE_HEADER = "x-cmssy-signature";
|
|
271
|
+
function createCmssyRevalidateRoute(config) {
|
|
272
|
+
const tags = cmssyContentTags(config.tags);
|
|
273
|
+
const secrets = (Array.isArray(config.secret) ? config.secret : [config.secret]).filter((secret) => Boolean(secret));
|
|
274
|
+
return async function POST(request) {
|
|
275
|
+
if (secrets.length === 0) {
|
|
276
|
+
return new Response(
|
|
277
|
+
"cmssy: createCmssyRevalidateRoute has no signing secret - set CMSSY_WEBHOOK_SECRET to the secret cmssy shows for this webhook and pass it as `secret`",
|
|
278
|
+
{ status: 500 }
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
const body = await request.text();
|
|
282
|
+
try {
|
|
283
|
+
await verifyCmssyWebhook({
|
|
284
|
+
body,
|
|
285
|
+
signatureHeader: request.headers.get(SIGNATURE_HEADER),
|
|
286
|
+
secret: secrets,
|
|
287
|
+
toleranceSeconds: config.toleranceSeconds
|
|
288
|
+
});
|
|
289
|
+
} catch (err) {
|
|
290
|
+
if (err instanceof CmssyWebhookError) {
|
|
291
|
+
return new Response(err.message, { status: 401 });
|
|
292
|
+
}
|
|
293
|
+
throw err;
|
|
294
|
+
}
|
|
295
|
+
for (const tag of tags) revalidateTag(tag, { expire: 0 });
|
|
296
|
+
return Response.json({ revalidated: tags });
|
|
297
|
+
};
|
|
298
|
+
}
|
|
254
299
|
async function isCmssyEditMode() {
|
|
255
300
|
const h = await headers();
|
|
256
301
|
return h.get(CMSSY_EDIT_HEADER) === "1";
|
|
257
302
|
}
|
|
303
|
+
function resolveCmssyLayout(config, options) {
|
|
304
|
+
const { cache, ...rest } = options;
|
|
305
|
+
const live = rest.editMode || rest.preview === true;
|
|
306
|
+
const fetchImpl = rest.fetch ?? (cache && !live ? cmssyCachedFetch(cache) : void 0);
|
|
307
|
+
return resolveCmssyLayout$1(config, {
|
|
308
|
+
...rest,
|
|
309
|
+
retry: rest.retry ?? nextRetryMode(),
|
|
310
|
+
...fetchImpl ? { fetch: fetchImpl } : {}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
258
313
|
async function CmssyLayoutSlot({
|
|
259
314
|
config,
|
|
260
315
|
blocks,
|
|
@@ -267,6 +322,7 @@ async function CmssyLayoutSlot({
|
|
|
267
322
|
editable,
|
|
268
323
|
appContext,
|
|
269
324
|
retry,
|
|
325
|
+
cache,
|
|
270
326
|
children
|
|
271
327
|
}) {
|
|
272
328
|
const layout = await resolveCmssyLayout(config, {
|
|
@@ -277,18 +333,13 @@ async function CmssyLayoutSlot({
|
|
|
277
333
|
editable,
|
|
278
334
|
...page !== void 0 ? { page } : {},
|
|
279
335
|
appContext,
|
|
280
|
-
retry
|
|
336
|
+
retry,
|
|
337
|
+
cache,
|
|
281
338
|
...explicitLocale !== void 0 ? { locale: explicitLocale } : { path: path ?? [] }
|
|
282
339
|
});
|
|
283
340
|
if (!children) return layout.element;
|
|
284
341
|
const { groups, settings, page: routed, element } = layout;
|
|
285
342
|
return /* @__PURE__ */ jsx(Fragment, { children: children({ groups, settings, page: routed, element }) });
|
|
286
343
|
}
|
|
287
|
-
function resolveCmssyLayout2(config, options) {
|
|
288
|
-
return resolveCmssyLayout(config, {
|
|
289
|
-
...options,
|
|
290
|
-
retry: options.retry ?? nextRetryMode()
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
344
|
|
|
294
|
-
export { CmssyLayoutSlot, NEXT_BUILD_PHASE, createCmssyEditPage, createCmssyPage, createDraftRoute, isCmssyEditMode, nextRetryMode,
|
|
345
|
+
export { CMSSY_CONTENT_TAG, CmssyLayoutSlot, NEXT_BUILD_PHASE, cmssyCachedFetch, createCmssyEditPage, createCmssyPage, createCmssyRevalidateRoute, createDraftRoute, isCmssyEditMode, nextRetryMode, resolveCmssyLayout };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmssy/next",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.1.0",
|
|
4
4
|
"description": "Next.js App Router bindings for cmssy headless sites (createCmssyPage + draft preview)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cmssy",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"dist"
|
|
72
72
|
],
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@cmssy/react": "^16.
|
|
74
|
+
"@cmssy/react": "^16.1.0",
|
|
75
75
|
"next": ">=15",
|
|
76
76
|
"react": "^18.2.0 || ^19.0.0",
|
|
77
77
|
"react-dom": "^18.2.0 || ^19.0.0"
|
|
@@ -85,12 +85,12 @@
|
|
|
85
85
|
"tsup": "^8.3.0",
|
|
86
86
|
"typescript": "^5.6.0",
|
|
87
87
|
"vitest": "^2.1.0",
|
|
88
|
-
"@cmssy/react": "16.
|
|
88
|
+
"@cmssy/react": "16.1.0"
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@cmssy/types": "0.41.0",
|
|
92
92
|
"server-only": "^0.0.1",
|
|
93
|
-
"@cmssy/core": "16.
|
|
93
|
+
"@cmssy/core": "16.1.0"
|
|
94
94
|
},
|
|
95
95
|
"scripts": {
|
|
96
96
|
"build": "tsup",
|