@cmssy/next 10.8.0 → 10.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/middleware.cjs +34 -5
- package/dist/middleware.d.cts +20 -2
- package/dist/middleware.d.ts +20 -2
- package/dist/middleware.js +34 -5
- package/package.json +3 -3
package/dist/middleware.cjs
CHANGED
|
@@ -45,12 +45,41 @@ Until then the editor preview stays blank.`
|
|
|
45
45
|
}).catch(() => {
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
+
var DEFAULT_COOKIE_OPTIONS = {
|
|
49
|
+
httpOnly: true,
|
|
50
|
+
sameSite: "lax",
|
|
51
|
+
secure: process.env.NODE_ENV === "production",
|
|
52
|
+
path: "/"
|
|
53
|
+
};
|
|
54
|
+
function mergeCookieHeader(header, writes) {
|
|
55
|
+
const written = new Set(writes.map((write) => write.name));
|
|
56
|
+
const kept = (header ?? "").split(/; */).filter(Boolean).filter((cookie) => !written.has(cookie.split("=")[0] ?? ""));
|
|
57
|
+
const added = writes.filter((write) => write.value).map((write) => `${write.name}=${write.value}`);
|
|
58
|
+
return [...kept, ...added].join("; ");
|
|
59
|
+
}
|
|
48
60
|
function createCmssyProxy(config, options = {}) {
|
|
49
61
|
return async function cmssyProxy(request) {
|
|
50
62
|
const { pathname } = request.nextUrl;
|
|
51
63
|
const requestHeaders = new Headers(request.headers);
|
|
52
64
|
requestHeaders.delete(core.CMSSY_EDIT_HEADER);
|
|
53
65
|
requestHeaders.delete(locale.CMSSY_LOCALE_HEADER);
|
|
66
|
+
const writes = await options.cookies?.(request) ?? [];
|
|
67
|
+
if (writes.length > 0) {
|
|
68
|
+
requestHeaders.set(
|
|
69
|
+
"cookie",
|
|
70
|
+
mergeCookieHeader(requestHeaders.get("cookie"), writes)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const persist = (response) => {
|
|
74
|
+
for (const write of writes) {
|
|
75
|
+
response.cookies.set(write.name, write.value, {
|
|
76
|
+
...DEFAULT_COOKIE_OPTIONS,
|
|
77
|
+
...write.value ? {} : { maxAge: 0 },
|
|
78
|
+
...write.options
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return response;
|
|
82
|
+
};
|
|
54
83
|
const locale$1 = await locale.localeForPathname(config, pathname);
|
|
55
84
|
requestHeaders.set(locale.CMSSY_LOCALE_HEADER, locale$1);
|
|
56
85
|
const editHeaders = new Headers(requestHeaders);
|
|
@@ -60,19 +89,19 @@ function createCmssyProxy(config, options = {}) {
|
|
|
60
89
|
});
|
|
61
90
|
if (editRewrite) {
|
|
62
91
|
core.applyCmssyCsp(editRewrite, { editorOrigin: config.editorOrigin });
|
|
63
|
-
return editRewrite;
|
|
92
|
+
return persist(editRewrite);
|
|
64
93
|
}
|
|
65
94
|
if (options.stripLocalePrefix && pathname.startsWith(`/${locale$1}`)) {
|
|
66
95
|
const { defaultLocale } = await locale.resolveSiteLocales(config);
|
|
67
96
|
if (locale$1 !== defaultLocale) {
|
|
68
97
|
const url = request.nextUrl.clone();
|
|
69
98
|
url.pathname = pathname.slice(locale$1.length + 1) || "/";
|
|
70
|
-
return
|
|
71
|
-
request: { headers: requestHeaders }
|
|
72
|
-
|
|
99
|
+
return persist(
|
|
100
|
+
server.NextResponse.rewrite(url, { request: { headers: requestHeaders } })
|
|
101
|
+
);
|
|
73
102
|
}
|
|
74
103
|
}
|
|
75
|
-
return server.NextResponse.next({ request: { headers: requestHeaders } });
|
|
104
|
+
return persist(server.NextResponse.next({ request: { headers: requestHeaders } }));
|
|
76
105
|
};
|
|
77
106
|
}
|
|
78
107
|
var cmssyProxyMatcher = ["/((?!_next/|api/|.*\\..*).*)"];
|
package/dist/middleware.d.cts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NextResponse, NextRequest } from 'next/server';
|
|
2
2
|
import { CmssyConfig } from '@cmssy/core';
|
|
3
3
|
export { CMSSY_EDIT_HEADER, CmssyCspOptions, applyCmssyCsp } from '@cmssy/core';
|
|
4
4
|
|
|
5
|
+
/** A cookie the proxy writes on this request. An empty value deletes it. */
|
|
6
|
+
interface CmssyProxyCookie {
|
|
7
|
+
name: string;
|
|
8
|
+
value: string;
|
|
9
|
+
/** Passed to `response.cookies.set`; defaults to httpOnly + sameSite lax. */
|
|
10
|
+
options?: Omit<Parameters<NextResponse["cookies"]["set"]>[2], "name" | "value">;
|
|
11
|
+
}
|
|
5
12
|
interface CmssyProxyOptions {
|
|
6
13
|
/**
|
|
7
14
|
* Strip the language prefix before the app sees it, so static routes like
|
|
@@ -9,6 +16,17 @@ interface CmssyProxyOptions {
|
|
|
9
16
|
* that reads the language off the path itself.
|
|
10
17
|
*/
|
|
11
18
|
stripLocalePrefix?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Cookies this request has to write - a refreshed session, a freshly minted
|
|
21
|
+
* cart id. They are set on the response AND merged into the cookie header the
|
|
22
|
+
* app is about to be rendered with, so THIS render already sees them; setting
|
|
23
|
+
* them on the response alone means the value only arrives on the next
|
|
24
|
+
* navigation, which is how a signed-in visitor renders signed-out once.
|
|
25
|
+
*
|
|
26
|
+
* It is the escape hatch that keeps an app from re-implementing the whole
|
|
27
|
+
* preset - locale, edit rewrite and CSP included - to add one cookie.
|
|
28
|
+
*/
|
|
29
|
+
cookies?: (request: NextRequest) => Promise<CmssyProxyCookie[]> | CmssyProxyCookie[];
|
|
12
30
|
}
|
|
13
31
|
/**
|
|
14
32
|
* The whole middleware a cmssy app needs, in the order it has to happen:
|
|
@@ -87,4 +105,4 @@ declare function isCmssyEditRequest(request: EditRequestLike, config: {
|
|
|
87
105
|
draftSecret: string;
|
|
88
106
|
}): Promise<boolean>;
|
|
89
107
|
|
|
90
|
-
export { CMSSY_EDIT_PATH_PREFIX, type CmssyProxyOptions, cmssyEditRewrite, cmssyProxyMatcher, createCmssyEditMiddleware, createCmssyProxy, isCmssyEditRequest };
|
|
108
|
+
export { CMSSY_EDIT_PATH_PREFIX, type CmssyProxyCookie, type CmssyProxyOptions, cmssyEditRewrite, cmssyProxyMatcher, createCmssyEditMiddleware, createCmssyProxy, isCmssyEditRequest };
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NextResponse, NextRequest } from 'next/server';
|
|
2
2
|
import { CmssyConfig } from '@cmssy/core';
|
|
3
3
|
export { CMSSY_EDIT_HEADER, CmssyCspOptions, applyCmssyCsp } from '@cmssy/core';
|
|
4
4
|
|
|
5
|
+
/** A cookie the proxy writes on this request. An empty value deletes it. */
|
|
6
|
+
interface CmssyProxyCookie {
|
|
7
|
+
name: string;
|
|
8
|
+
value: string;
|
|
9
|
+
/** Passed to `response.cookies.set`; defaults to httpOnly + sameSite lax. */
|
|
10
|
+
options?: Omit<Parameters<NextResponse["cookies"]["set"]>[2], "name" | "value">;
|
|
11
|
+
}
|
|
5
12
|
interface CmssyProxyOptions {
|
|
6
13
|
/**
|
|
7
14
|
* Strip the language prefix before the app sees it, so static routes like
|
|
@@ -9,6 +16,17 @@ interface CmssyProxyOptions {
|
|
|
9
16
|
* that reads the language off the path itself.
|
|
10
17
|
*/
|
|
11
18
|
stripLocalePrefix?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Cookies this request has to write - a refreshed session, a freshly minted
|
|
21
|
+
* cart id. They are set on the response AND merged into the cookie header the
|
|
22
|
+
* app is about to be rendered with, so THIS render already sees them; setting
|
|
23
|
+
* them on the response alone means the value only arrives on the next
|
|
24
|
+
* navigation, which is how a signed-in visitor renders signed-out once.
|
|
25
|
+
*
|
|
26
|
+
* It is the escape hatch that keeps an app from re-implementing the whole
|
|
27
|
+
* preset - locale, edit rewrite and CSP included - to add one cookie.
|
|
28
|
+
*/
|
|
29
|
+
cookies?: (request: NextRequest) => Promise<CmssyProxyCookie[]> | CmssyProxyCookie[];
|
|
12
30
|
}
|
|
13
31
|
/**
|
|
14
32
|
* The whole middleware a cmssy app needs, in the order it has to happen:
|
|
@@ -87,4 +105,4 @@ declare function isCmssyEditRequest(request: EditRequestLike, config: {
|
|
|
87
105
|
draftSecret: string;
|
|
88
106
|
}): Promise<boolean>;
|
|
89
107
|
|
|
90
|
-
export { CMSSY_EDIT_PATH_PREFIX, type CmssyProxyOptions, cmssyEditRewrite, cmssyProxyMatcher, createCmssyEditMiddleware, createCmssyProxy, isCmssyEditRequest };
|
|
108
|
+
export { CMSSY_EDIT_PATH_PREFIX, type CmssyProxyCookie, type CmssyProxyOptions, cmssyEditRewrite, cmssyProxyMatcher, createCmssyEditMiddleware, createCmssyProxy, isCmssyEditRequest };
|
package/dist/middleware.js
CHANGED
|
@@ -44,12 +44,41 @@ Until then the editor preview stays blank.`
|
|
|
44
44
|
}).catch(() => {
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
+
var DEFAULT_COOKIE_OPTIONS = {
|
|
48
|
+
httpOnly: true,
|
|
49
|
+
sameSite: "lax",
|
|
50
|
+
secure: process.env.NODE_ENV === "production",
|
|
51
|
+
path: "/"
|
|
52
|
+
};
|
|
53
|
+
function mergeCookieHeader(header, writes) {
|
|
54
|
+
const written = new Set(writes.map((write) => write.name));
|
|
55
|
+
const kept = (header ?? "").split(/; */).filter(Boolean).filter((cookie) => !written.has(cookie.split("=")[0] ?? ""));
|
|
56
|
+
const added = writes.filter((write) => write.value).map((write) => `${write.name}=${write.value}`);
|
|
57
|
+
return [...kept, ...added].join("; ");
|
|
58
|
+
}
|
|
47
59
|
function createCmssyProxy(config, options = {}) {
|
|
48
60
|
return async function cmssyProxy(request) {
|
|
49
61
|
const { pathname } = request.nextUrl;
|
|
50
62
|
const requestHeaders = new Headers(request.headers);
|
|
51
63
|
requestHeaders.delete(CMSSY_EDIT_HEADER);
|
|
52
64
|
requestHeaders.delete(CMSSY_LOCALE_HEADER);
|
|
65
|
+
const writes = await options.cookies?.(request) ?? [];
|
|
66
|
+
if (writes.length > 0) {
|
|
67
|
+
requestHeaders.set(
|
|
68
|
+
"cookie",
|
|
69
|
+
mergeCookieHeader(requestHeaders.get("cookie"), writes)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const persist = (response) => {
|
|
73
|
+
for (const write of writes) {
|
|
74
|
+
response.cookies.set(write.name, write.value, {
|
|
75
|
+
...DEFAULT_COOKIE_OPTIONS,
|
|
76
|
+
...write.value ? {} : { maxAge: 0 },
|
|
77
|
+
...write.options
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return response;
|
|
81
|
+
};
|
|
53
82
|
const locale = await localeForPathname(config, pathname);
|
|
54
83
|
requestHeaders.set(CMSSY_LOCALE_HEADER, locale);
|
|
55
84
|
const editHeaders = new Headers(requestHeaders);
|
|
@@ -59,19 +88,19 @@ function createCmssyProxy(config, options = {}) {
|
|
|
59
88
|
});
|
|
60
89
|
if (editRewrite) {
|
|
61
90
|
applyCmssyCsp(editRewrite, { editorOrigin: config.editorOrigin });
|
|
62
|
-
return editRewrite;
|
|
91
|
+
return persist(editRewrite);
|
|
63
92
|
}
|
|
64
93
|
if (options.stripLocalePrefix && pathname.startsWith(`/${locale}`)) {
|
|
65
94
|
const { defaultLocale } = await resolveSiteLocales(config);
|
|
66
95
|
if (locale !== defaultLocale) {
|
|
67
96
|
const url = request.nextUrl.clone();
|
|
68
97
|
url.pathname = pathname.slice(locale.length + 1) || "/";
|
|
69
|
-
return
|
|
70
|
-
request: { headers: requestHeaders }
|
|
71
|
-
|
|
98
|
+
return persist(
|
|
99
|
+
NextResponse.rewrite(url, { request: { headers: requestHeaders } })
|
|
100
|
+
);
|
|
72
101
|
}
|
|
73
102
|
}
|
|
74
|
-
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
103
|
+
return persist(NextResponse.next({ request: { headers: requestHeaders } }));
|
|
75
104
|
};
|
|
76
105
|
}
|
|
77
106
|
var cmssyProxyMatcher = ["/((?!_next/|api/|.*\\..*).*)"];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmssy/next",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.9.1",
|
|
4
4
|
"description": "Next.js App Router bindings for cmssy headless sites (createCmssyPage + draft preview)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cmssy",
|
|
@@ -65,12 +65,12 @@
|
|
|
65
65
|
"tsup": "^8.3.0",
|
|
66
66
|
"typescript": "^5.6.0",
|
|
67
67
|
"vitest": "^2.1.0",
|
|
68
|
-
"@cmssy/react": "10.
|
|
68
|
+
"@cmssy/react": "10.9.1"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@cmssy/types": "0.32.0",
|
|
72
72
|
"server-only": "^0.0.1",
|
|
73
|
-
"@cmssy/core": "10.
|
|
73
|
+
"@cmssy/core": "10.9.1"
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|
|
76
76
|
"build": "tsup",
|