@cmssy/next 4.7.1 → 5.0.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.
@@ -0,0 +1,185 @@
1
+ 'use strict';
2
+
3
+ var server = require('next/server');
4
+ var react = require('@cmssy/react');
5
+ var core = require('@cmssy/core');
6
+
7
+ // src/preset/proxy.ts
8
+ var CMSSY_EDIT_PATH_PREFIX = "/cmssy-edit";
9
+ async function cmssyEditRewrite(request, config, options = {}) {
10
+ const { pathname, searchParams } = request.nextUrl;
11
+ if (pathname.startsWith(CMSSY_EDIT_PATH_PREFIX)) return null;
12
+ if (!searchParams.getAll(core.CMSSY_EDIT_QUERY_PARAM).includes("1")) return null;
13
+ const provided = searchParams.get(core.CMSSY_SECRET_QUERY_PARAM);
14
+ if (!provided || !config.draftSecret) return null;
15
+ if (!await core.cmssySecretsMatch(provided, config.draftSecret)) return null;
16
+ const url = request.nextUrl.clone();
17
+ url.pathname = `${CMSSY_EDIT_PATH_PREFIX}${pathname === "/" ? "" : pathname}`;
18
+ warnIfEditRouteMissing(url);
19
+ return server.NextResponse.rewrite(
20
+ url,
21
+ options.requestHeaders ? { request: { headers: options.requestHeaders } } : void 0
22
+ );
23
+ }
24
+ function createCmssyEditMiddleware(config) {
25
+ return async function cmssyEditMiddleware(request) {
26
+ return await cmssyEditRewrite(request, config) ?? server.NextResponse.next();
27
+ };
28
+ }
29
+ var probed = false;
30
+ function warnIfEditRouteMissing(url) {
31
+ if (process.env.NODE_ENV === "production" || probed) return;
32
+ probed = true;
33
+ void fetch(url, { method: "HEAD" }).then((response) => {
34
+ if (response.status !== 404) return;
35
+ console.error(
36
+ `[cmssy] The editor request was rewritten to ${url.pathname}, but nothing is mounted there (404). Add the edit route:
37
+
38
+ // app/cmssy-edit/[[...path]]/page.tsx
39
+ export const dynamic = "force-dynamic";
40
+ export default createCmssyEditPage(cmssy, blocks, { editor: CmssyEditor });
41
+
42
+ Until then the editor preview stays blank.`
43
+ );
44
+ }).catch(() => {
45
+ });
46
+ }
47
+ function createCmssyProxy(config, options = {}) {
48
+ return async function cmssyProxy(request) {
49
+ const { pathname } = request.nextUrl;
50
+ const requestHeaders = new Headers(request.headers);
51
+ requestHeaders.delete(core.CMSSY_EDIT_HEADER);
52
+ requestHeaders.delete(core.CMSSY_LOCALE_HEADER);
53
+ const locale = await core.localeForPathname(config, pathname);
54
+ requestHeaders.set(core.CMSSY_LOCALE_HEADER, locale);
55
+ const editHeaders = new Headers(requestHeaders);
56
+ editHeaders.set(core.CMSSY_EDIT_HEADER, "1");
57
+ const editRewrite = await cmssyEditRewrite(request, config, {
58
+ requestHeaders: editHeaders
59
+ });
60
+ if (editRewrite) {
61
+ core.applyCmssyCsp(editRewrite, { editorOrigin: config.editorOrigin });
62
+ return editRewrite;
63
+ }
64
+ if (options.stripLocalePrefix && pathname.startsWith(`/${locale}`)) {
65
+ const { defaultLocale } = await react.resolveSiteLocales(config);
66
+ if (locale !== defaultLocale) {
67
+ const url = request.nextUrl.clone();
68
+ url.pathname = pathname.slice(locale.length + 1) || "/";
69
+ return server.NextResponse.rewrite(url, {
70
+ request: { headers: requestHeaders }
71
+ });
72
+ }
73
+ }
74
+ return server.NextResponse.next({ request: { headers: requestHeaders } });
75
+ };
76
+ }
77
+ var cmssyProxyMatcher = ["/((?!_next/|api/|.*\\..*).*)"];
78
+ async function resolveLocaleFromPathname(config, pathname) {
79
+ const segments = pathname.split("/").filter(Boolean);
80
+ const hasStaticLocales = !!config.enabledLocales?.length;
81
+ const fetched = config.defaultLocale && hasStaticLocales ? null : await react.resolveSiteLocales({
82
+ apiUrl: config.apiUrl,
83
+ org: config.org,
84
+ workspaceSlug: config.workspaceSlug
85
+ });
86
+ const siteLocales = {
87
+ defaultLocale: config.defaultLocale ?? fetched.defaultLocale,
88
+ locales: hasStaticLocales ? config.enabledLocales : fetched.locales
89
+ };
90
+ return react.splitLocaleFromPath(segments, siteLocales).locale;
91
+ }
92
+ function createCmssyLocaleMiddleware(config) {
93
+ return async function cmssyLocaleMiddleware(request) {
94
+ const locale = await resolveLocaleFromPathname(
95
+ config,
96
+ request.nextUrl.pathname
97
+ );
98
+ const headers = new Headers(request.headers);
99
+ headers.set(core.CMSSY_LOCALE_HEADER, locale);
100
+ return server.NextResponse.next({ request: { headers } });
101
+ };
102
+ }
103
+ function isPrefetch(request) {
104
+ return request.headers.get("next-router-prefetch") !== null || request.headers.get("purpose") === "prefetch" || (request.headers.get("sec-purpose") ?? "").includes("prefetch");
105
+ }
106
+ function createCmssyAuthMiddleware(config) {
107
+ const auth = core.assertAuthConfig(config);
108
+ return async function cmssyAuthMiddleware(request) {
109
+ const raw = request.cookies.get(core.CMSSY_SESSION_COOKIE)?.value;
110
+ if (!raw) return server.NextResponse.next();
111
+ const session = await core.openSession(
112
+ raw,
113
+ auth.sessionSecret,
114
+ config.workspaceSlug
115
+ );
116
+ if (!session) {
117
+ const response = server.NextResponse.next();
118
+ response.cookies.set(core.CMSSY_SESSION_COOKIE, "", {
119
+ ...core.sessionCookieOptions(),
120
+ maxAge: 0
121
+ });
122
+ return response;
123
+ }
124
+ if (!core.isAccessExpired(session)) return server.NextResponse.next();
125
+ if (isPrefetch(request)) return server.NextResponse.next();
126
+ let payload = null;
127
+ try {
128
+ const result = await core.backendRefresh(config, session.refreshToken);
129
+ payload = core.toSessionPayload(result);
130
+ } catch {
131
+ return server.NextResponse.next();
132
+ }
133
+ if (!payload) {
134
+ const cleared = server.NextResponse.next();
135
+ cleared.cookies.set(core.CMSSY_SESSION_COOKIE, "", {
136
+ ...core.sessionCookieOptions(),
137
+ maxAge: 0
138
+ });
139
+ return cleared;
140
+ }
141
+ const sealed = await core.sealSession(
142
+ payload,
143
+ auth.sessionSecret,
144
+ config.workspaceSlug
145
+ );
146
+ request.cookies.set(core.CMSSY_SESSION_COOKIE, sealed);
147
+ const refreshed = server.NextResponse.next({ request });
148
+ refreshed.cookies.set(core.CMSSY_SESSION_COOKIE, sealed, core.sessionCookieOptions());
149
+ return refreshed;
150
+ };
151
+ }
152
+ async function isCmssyEditRequest(request, config) {
153
+ if (request.cookies.has("__prerender_bypass")) return true;
154
+ return core.isVerifiedEditUrl(request.nextUrl, config);
155
+ }
156
+
157
+ Object.defineProperty(exports, "CMSSY_EDIT_HEADER", {
158
+ enumerable: true,
159
+ get: function () { return core.CMSSY_EDIT_HEADER; }
160
+ });
161
+ Object.defineProperty(exports, "CMSSY_LOCALE_HEADER", {
162
+ enumerable: true,
163
+ get: function () { return core.CMSSY_LOCALE_HEADER; }
164
+ });
165
+ Object.defineProperty(exports, "applyCmssyCsp", {
166
+ enumerable: true,
167
+ get: function () { return core.applyCmssyCsp; }
168
+ });
169
+ Object.defineProperty(exports, "cmssyCspHeaders", {
170
+ enumerable: true,
171
+ get: function () { return core.cmssyCspHeaders; }
172
+ });
173
+ Object.defineProperty(exports, "localeForPathname", {
174
+ enumerable: true,
175
+ get: function () { return core.localeForPathname; }
176
+ });
177
+ exports.CMSSY_EDIT_PATH_PREFIX = CMSSY_EDIT_PATH_PREFIX;
178
+ exports.cmssyEditRewrite = cmssyEditRewrite;
179
+ exports.cmssyProxyMatcher = cmssyProxyMatcher;
180
+ exports.createCmssyAuthMiddleware = createCmssyAuthMiddleware;
181
+ exports.createCmssyEditMiddleware = createCmssyEditMiddleware;
182
+ exports.createCmssyLocaleMiddleware = createCmssyLocaleMiddleware;
183
+ exports.createCmssyProxy = createCmssyProxy;
184
+ exports.isCmssyEditRequest = isCmssyEditRequest;
185
+ exports.resolveLocaleFromPathname = resolveLocaleFromPathname;
@@ -0,0 +1,106 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { CmssyConfig } from '@cmssy/core';
3
+ export { CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CmssyCspOptions, applyCmssyCsp, cmssyCspHeaders, localeForPathname } from '@cmssy/core';
4
+
5
+ interface CmssyProxyOptions {
6
+ /**
7
+ * Strip the language prefix before the app sees it, so static routes like
8
+ * `/shop/cart` serve `/no/shop/cart` too. Leave it off for a catch-all app
9
+ * that reads the language off the path itself.
10
+ */
11
+ stripLocalePrefix?: boolean;
12
+ }
13
+ /**
14
+ * The whole middleware a cmssy app needs, in the order it has to happen:
15
+ *
16
+ * 1. resolve the language and pass it on (a route cannot read the prefix it
17
+ * never sees);
18
+ * 2. send a VERIFIED editor request to /cmssy-edit, carrying that language and
19
+ * the edit flag - the public pages are static, and a static page never sees
20
+ * the query string that would put it in edit mode;
21
+ * 3. strip the language prefix for everything else, if asked.
22
+ *
23
+ * The order is not a detail: resolve the locale after the rewrite and the editor
24
+ * preview renders in the wrong language; forget the edit flag and the header and
25
+ * footer become markup the editor can select but not fill. Both mistakes shipped
26
+ * before this existed.
27
+ */
28
+ declare function createCmssyProxy(config: CmssyConfig, options?: CmssyProxyOptions): (request: NextRequest) => Promise<NextResponse>;
29
+ /**
30
+ * The matcher a cmssy app wants: everything except Next internals, API routes
31
+ * and files with an extension.
32
+ *
33
+ * Next parses `export const config` at COMPILE time, so it rejects an imported
34
+ * constant - copy this value into your proxy literally:
35
+ *
36
+ * export const config = { matcher: ["/((?!_next/|api/|.*\\..*).*)"] };
37
+ */
38
+ declare const cmssyProxyMatcher: string[];
39
+
40
+ /**
41
+ * Where the middleware rewrites editor-preview traffic. Mount the matching
42
+ * dynamic route in the consumer app:
43
+ *
44
+ * app/cmssy-edit/[[...path]]/page.tsx
45
+ * export const dynamic = "force-dynamic";
46
+ * export default createCmssyEditPage(cmssy, blocks, { editor: Editor });
47
+ */
48
+ declare const CMSSY_EDIT_PATH_PREFIX = "/cmssy-edit";
49
+ /**
50
+ * Rewrite VERIFIED editor requests (`cmssyEdit=1` + a `cmssySecret` matching
51
+ * the site's draft secret, CMS-948) onto the dedicated dynamic edit route, so
52
+ * the public catch-all can stay fully static. A static page never sees its
53
+ * query string - this rewrite is what makes the editor iframe work at all
54
+ * once ISR is on. Draft-mode preview (the authenticated /api/draft cookie) is
55
+ * NOT rewritten: it renders draft content on the public route via
56
+ * `draftMode()`, without the editor. Returns null for normal traffic so it
57
+ * composes with other middleware.
58
+ */
59
+ declare function cmssyEditRewrite(request: NextRequest, config: {
60
+ draftSecret: string;
61
+ }, options?: {
62
+ /**
63
+ * Headers to forward to the edit route, for a site whose middleware tells
64
+ * the app something the path alone does not - a resolved locale, say.
65
+ * Without them the editor preview renders in the default language while the
66
+ * public page renders in the visitor's.
67
+ */
68
+ requestHeaders?: Headers;
69
+ }): Promise<NextResponse | null>;
70
+ /** Standalone middleware when the consumer has no other middleware to compose. */
71
+ declare function createCmssyEditMiddleware(config: {
72
+ draftSecret: string;
73
+ }): (request: NextRequest) => Promise<NextResponse>;
74
+
75
+ /**
76
+ * Resolves the active locale from a pathname's leading segment. Uses the
77
+ * config's static `defaultLocale` + `enabledLocales` when both are set (no
78
+ * network); otherwise fetches the workspace locales (cached).
79
+ */
80
+ declare function resolveLocaleFromPathname(config: CmssyConfig, pathname: string): Promise<string>;
81
+ /**
82
+ * Middleware that derives the locale from the URL path prefix and forwards it as
83
+ * the `x-cmssy-locale` request header, so server components that can't read the
84
+ * path (root layout) resolve the right locale via `getCmssyLocale`.
85
+ */
86
+ declare function createCmssyLocaleMiddleware(config: CmssyConfig): (request: NextRequest) => Promise<NextResponse>;
87
+
88
+ type CmssyAuthMiddleware = (request: NextRequest) => Promise<NextResponse>;
89
+ declare function createCmssyAuthMiddleware(config: CmssyConfig): CmssyAuthMiddleware;
90
+
91
+ interface EditRequestLike {
92
+ cookies: {
93
+ has: (name: string) => boolean;
94
+ };
95
+ nextUrl: {
96
+ searchParams: {
97
+ getAll: (name: string) => string[];
98
+ get: (name: string) => string | null;
99
+ };
100
+ };
101
+ }
102
+ declare function isCmssyEditRequest(request: EditRequestLike, config: {
103
+ draftSecret: string;
104
+ }): Promise<boolean>;
105
+
106
+ export { CMSSY_EDIT_PATH_PREFIX, type CmssyAuthMiddleware, type CmssyProxyOptions, cmssyEditRewrite, cmssyProxyMatcher, createCmssyAuthMiddleware, createCmssyEditMiddleware, createCmssyLocaleMiddleware, createCmssyProxy, isCmssyEditRequest, resolveLocaleFromPathname };
@@ -0,0 +1,106 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { CmssyConfig } from '@cmssy/core';
3
+ export { CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CmssyCspOptions, applyCmssyCsp, cmssyCspHeaders, localeForPathname } from '@cmssy/core';
4
+
5
+ interface CmssyProxyOptions {
6
+ /**
7
+ * Strip the language prefix before the app sees it, so static routes like
8
+ * `/shop/cart` serve `/no/shop/cart` too. Leave it off for a catch-all app
9
+ * that reads the language off the path itself.
10
+ */
11
+ stripLocalePrefix?: boolean;
12
+ }
13
+ /**
14
+ * The whole middleware a cmssy app needs, in the order it has to happen:
15
+ *
16
+ * 1. resolve the language and pass it on (a route cannot read the prefix it
17
+ * never sees);
18
+ * 2. send a VERIFIED editor request to /cmssy-edit, carrying that language and
19
+ * the edit flag - the public pages are static, and a static page never sees
20
+ * the query string that would put it in edit mode;
21
+ * 3. strip the language prefix for everything else, if asked.
22
+ *
23
+ * The order is not a detail: resolve the locale after the rewrite and the editor
24
+ * preview renders in the wrong language; forget the edit flag and the header and
25
+ * footer become markup the editor can select but not fill. Both mistakes shipped
26
+ * before this existed.
27
+ */
28
+ declare function createCmssyProxy(config: CmssyConfig, options?: CmssyProxyOptions): (request: NextRequest) => Promise<NextResponse>;
29
+ /**
30
+ * The matcher a cmssy app wants: everything except Next internals, API routes
31
+ * and files with an extension.
32
+ *
33
+ * Next parses `export const config` at COMPILE time, so it rejects an imported
34
+ * constant - copy this value into your proxy literally:
35
+ *
36
+ * export const config = { matcher: ["/((?!_next/|api/|.*\\..*).*)"] };
37
+ */
38
+ declare const cmssyProxyMatcher: string[];
39
+
40
+ /**
41
+ * Where the middleware rewrites editor-preview traffic. Mount the matching
42
+ * dynamic route in the consumer app:
43
+ *
44
+ * app/cmssy-edit/[[...path]]/page.tsx
45
+ * export const dynamic = "force-dynamic";
46
+ * export default createCmssyEditPage(cmssy, blocks, { editor: Editor });
47
+ */
48
+ declare const CMSSY_EDIT_PATH_PREFIX = "/cmssy-edit";
49
+ /**
50
+ * Rewrite VERIFIED editor requests (`cmssyEdit=1` + a `cmssySecret` matching
51
+ * the site's draft secret, CMS-948) onto the dedicated dynamic edit route, so
52
+ * the public catch-all can stay fully static. A static page never sees its
53
+ * query string - this rewrite is what makes the editor iframe work at all
54
+ * once ISR is on. Draft-mode preview (the authenticated /api/draft cookie) is
55
+ * NOT rewritten: it renders draft content on the public route via
56
+ * `draftMode()`, without the editor. Returns null for normal traffic so it
57
+ * composes with other middleware.
58
+ */
59
+ declare function cmssyEditRewrite(request: NextRequest, config: {
60
+ draftSecret: string;
61
+ }, options?: {
62
+ /**
63
+ * Headers to forward to the edit route, for a site whose middleware tells
64
+ * the app something the path alone does not - a resolved locale, say.
65
+ * Without them the editor preview renders in the default language while the
66
+ * public page renders in the visitor's.
67
+ */
68
+ requestHeaders?: Headers;
69
+ }): Promise<NextResponse | null>;
70
+ /** Standalone middleware when the consumer has no other middleware to compose. */
71
+ declare function createCmssyEditMiddleware(config: {
72
+ draftSecret: string;
73
+ }): (request: NextRequest) => Promise<NextResponse>;
74
+
75
+ /**
76
+ * Resolves the active locale from a pathname's leading segment. Uses the
77
+ * config's static `defaultLocale` + `enabledLocales` when both are set (no
78
+ * network); otherwise fetches the workspace locales (cached).
79
+ */
80
+ declare function resolveLocaleFromPathname(config: CmssyConfig, pathname: string): Promise<string>;
81
+ /**
82
+ * Middleware that derives the locale from the URL path prefix and forwards it as
83
+ * the `x-cmssy-locale` request header, so server components that can't read the
84
+ * path (root layout) resolve the right locale via `getCmssyLocale`.
85
+ */
86
+ declare function createCmssyLocaleMiddleware(config: CmssyConfig): (request: NextRequest) => Promise<NextResponse>;
87
+
88
+ type CmssyAuthMiddleware = (request: NextRequest) => Promise<NextResponse>;
89
+ declare function createCmssyAuthMiddleware(config: CmssyConfig): CmssyAuthMiddleware;
90
+
91
+ interface EditRequestLike {
92
+ cookies: {
93
+ has: (name: string) => boolean;
94
+ };
95
+ nextUrl: {
96
+ searchParams: {
97
+ getAll: (name: string) => string[];
98
+ get: (name: string) => string | null;
99
+ };
100
+ };
101
+ }
102
+ declare function isCmssyEditRequest(request: EditRequestLike, config: {
103
+ draftSecret: string;
104
+ }): Promise<boolean>;
105
+
106
+ export { CMSSY_EDIT_PATH_PREFIX, type CmssyAuthMiddleware, type CmssyProxyOptions, cmssyEditRewrite, cmssyProxyMatcher, createCmssyAuthMiddleware, createCmssyEditMiddleware, createCmssyLocaleMiddleware, createCmssyProxy, isCmssyEditRequest, resolveLocaleFromPathname };
@@ -0,0 +1,156 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { resolveSiteLocales, splitLocaleFromPath } from '@cmssy/react';
3
+ import { CMSSY_EDIT_QUERY_PARAM, CMSSY_SECRET_QUERY_PARAM, cmssySecretsMatch, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, localeForPathname, applyCmssyCsp, assertAuthConfig, CMSSY_SESSION_COOKIE, openSession, sessionCookieOptions, isAccessExpired, backendRefresh, toSessionPayload, sealSession, isVerifiedEditUrl } from '@cmssy/core';
4
+ export { CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, applyCmssyCsp, cmssyCspHeaders, localeForPathname } from '@cmssy/core';
5
+
6
+ // src/preset/proxy.ts
7
+ var CMSSY_EDIT_PATH_PREFIX = "/cmssy-edit";
8
+ async function cmssyEditRewrite(request, config, options = {}) {
9
+ const { pathname, searchParams } = request.nextUrl;
10
+ if (pathname.startsWith(CMSSY_EDIT_PATH_PREFIX)) return null;
11
+ if (!searchParams.getAll(CMSSY_EDIT_QUERY_PARAM).includes("1")) return null;
12
+ const provided = searchParams.get(CMSSY_SECRET_QUERY_PARAM);
13
+ if (!provided || !config.draftSecret) return null;
14
+ if (!await cmssySecretsMatch(provided, config.draftSecret)) return null;
15
+ const url = request.nextUrl.clone();
16
+ url.pathname = `${CMSSY_EDIT_PATH_PREFIX}${pathname === "/" ? "" : pathname}`;
17
+ warnIfEditRouteMissing(url);
18
+ return NextResponse.rewrite(
19
+ url,
20
+ options.requestHeaders ? { request: { headers: options.requestHeaders } } : void 0
21
+ );
22
+ }
23
+ function createCmssyEditMiddleware(config) {
24
+ return async function cmssyEditMiddleware(request) {
25
+ return await cmssyEditRewrite(request, config) ?? NextResponse.next();
26
+ };
27
+ }
28
+ var probed = false;
29
+ function warnIfEditRouteMissing(url) {
30
+ if (process.env.NODE_ENV === "production" || probed) return;
31
+ probed = true;
32
+ void fetch(url, { method: "HEAD" }).then((response) => {
33
+ if (response.status !== 404) return;
34
+ console.error(
35
+ `[cmssy] The editor request was rewritten to ${url.pathname}, but nothing is mounted there (404). Add the edit route:
36
+
37
+ // app/cmssy-edit/[[...path]]/page.tsx
38
+ export const dynamic = "force-dynamic";
39
+ export default createCmssyEditPage(cmssy, blocks, { editor: CmssyEditor });
40
+
41
+ Until then the editor preview stays blank.`
42
+ );
43
+ }).catch(() => {
44
+ });
45
+ }
46
+ function createCmssyProxy(config, options = {}) {
47
+ return async function cmssyProxy(request) {
48
+ const { pathname } = request.nextUrl;
49
+ const requestHeaders = new Headers(request.headers);
50
+ requestHeaders.delete(CMSSY_EDIT_HEADER);
51
+ requestHeaders.delete(CMSSY_LOCALE_HEADER);
52
+ const locale = await localeForPathname(config, pathname);
53
+ requestHeaders.set(CMSSY_LOCALE_HEADER, locale);
54
+ const editHeaders = new Headers(requestHeaders);
55
+ editHeaders.set(CMSSY_EDIT_HEADER, "1");
56
+ const editRewrite = await cmssyEditRewrite(request, config, {
57
+ requestHeaders: editHeaders
58
+ });
59
+ if (editRewrite) {
60
+ applyCmssyCsp(editRewrite, { editorOrigin: config.editorOrigin });
61
+ return editRewrite;
62
+ }
63
+ if (options.stripLocalePrefix && pathname.startsWith(`/${locale}`)) {
64
+ const { defaultLocale } = await resolveSiteLocales(config);
65
+ if (locale !== defaultLocale) {
66
+ const url = request.nextUrl.clone();
67
+ url.pathname = pathname.slice(locale.length + 1) || "/";
68
+ return NextResponse.rewrite(url, {
69
+ request: { headers: requestHeaders }
70
+ });
71
+ }
72
+ }
73
+ return NextResponse.next({ request: { headers: requestHeaders } });
74
+ };
75
+ }
76
+ var cmssyProxyMatcher = ["/((?!_next/|api/|.*\\..*).*)"];
77
+ async function resolveLocaleFromPathname(config, pathname) {
78
+ const segments = pathname.split("/").filter(Boolean);
79
+ const hasStaticLocales = !!config.enabledLocales?.length;
80
+ const fetched = config.defaultLocale && hasStaticLocales ? null : await resolveSiteLocales({
81
+ apiUrl: config.apiUrl,
82
+ org: config.org,
83
+ workspaceSlug: config.workspaceSlug
84
+ });
85
+ const siteLocales = {
86
+ defaultLocale: config.defaultLocale ?? fetched.defaultLocale,
87
+ locales: hasStaticLocales ? config.enabledLocales : fetched.locales
88
+ };
89
+ return splitLocaleFromPath(segments, siteLocales).locale;
90
+ }
91
+ function createCmssyLocaleMiddleware(config) {
92
+ return async function cmssyLocaleMiddleware(request) {
93
+ const locale = await resolveLocaleFromPathname(
94
+ config,
95
+ request.nextUrl.pathname
96
+ );
97
+ const headers = new Headers(request.headers);
98
+ headers.set(CMSSY_LOCALE_HEADER, locale);
99
+ return NextResponse.next({ request: { headers } });
100
+ };
101
+ }
102
+ function isPrefetch(request) {
103
+ return request.headers.get("next-router-prefetch") !== null || request.headers.get("purpose") === "prefetch" || (request.headers.get("sec-purpose") ?? "").includes("prefetch");
104
+ }
105
+ function createCmssyAuthMiddleware(config) {
106
+ const auth = assertAuthConfig(config);
107
+ return async function cmssyAuthMiddleware(request) {
108
+ const raw = request.cookies.get(CMSSY_SESSION_COOKIE)?.value;
109
+ if (!raw) return NextResponse.next();
110
+ const session = await openSession(
111
+ raw,
112
+ auth.sessionSecret,
113
+ config.workspaceSlug
114
+ );
115
+ if (!session) {
116
+ const response = NextResponse.next();
117
+ response.cookies.set(CMSSY_SESSION_COOKIE, "", {
118
+ ...sessionCookieOptions(),
119
+ maxAge: 0
120
+ });
121
+ return response;
122
+ }
123
+ if (!isAccessExpired(session)) return NextResponse.next();
124
+ if (isPrefetch(request)) return NextResponse.next();
125
+ let payload = null;
126
+ try {
127
+ const result = await backendRefresh(config, session.refreshToken);
128
+ payload = toSessionPayload(result);
129
+ } catch {
130
+ return NextResponse.next();
131
+ }
132
+ if (!payload) {
133
+ const cleared = NextResponse.next();
134
+ cleared.cookies.set(CMSSY_SESSION_COOKIE, "", {
135
+ ...sessionCookieOptions(),
136
+ maxAge: 0
137
+ });
138
+ return cleared;
139
+ }
140
+ const sealed = await sealSession(
141
+ payload,
142
+ auth.sessionSecret,
143
+ config.workspaceSlug
144
+ );
145
+ request.cookies.set(CMSSY_SESSION_COOKIE, sealed);
146
+ const refreshed = NextResponse.next({ request });
147
+ refreshed.cookies.set(CMSSY_SESSION_COOKIE, sealed, sessionCookieOptions());
148
+ return refreshed;
149
+ };
150
+ }
151
+ async function isCmssyEditRequest(request, config) {
152
+ if (request.cookies.has("__prerender_bypass")) return true;
153
+ return isVerifiedEditUrl(request.nextUrl, config);
154
+ }
155
+
156
+ export { CMSSY_EDIT_PATH_PREFIX, cmssyEditRewrite, cmssyProxyMatcher, createCmssyAuthMiddleware, createCmssyEditMiddleware, createCmssyLocaleMiddleware, createCmssyProxy, isCmssyEditRequest, resolveLocaleFromPathname };