@cmssy/next 9.10.0 → 10.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 +9 -10
- package/dist/index.cjs +4 -8
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/middleware.cjs +10 -93
- package/dist/middleware.d.cts +2 -17
- package/dist/middleware.d.ts +2 -17
- package/dist/middleware.js +5 -73
- package/dist/server.cjs +23 -872
- package/dist/server.d.cts +5 -199
- package/dist/server.d.ts +5 -199
- package/dist/server.js +12 -847
- package/package.json +3 -8
- package/dist/client.cjs +0 -29
- package/dist/client.d.cts +0 -19
- package/dist/client.d.ts +0 -19
- package/dist/client.js +0 -16
package/dist/server.cjs
CHANGED
|
@@ -4,32 +4,13 @@ require('server-only');
|
|
|
4
4
|
var headers = require('next/headers');
|
|
5
5
|
var navigation = require('next/navigation');
|
|
6
6
|
var react = require('@cmssy/react');
|
|
7
|
-
var
|
|
7
|
+
var internal$1 = require('@cmssy/react/internal');
|
|
8
|
+
var internalServer = require('@cmssy/react/internal-server');
|
|
9
|
+
var internal = require('@cmssy/core/internal');
|
|
8
10
|
var core = require('@cmssy/core');
|
|
9
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
12
|
|
|
11
13
|
// src/server.ts
|
|
12
|
-
async function readValidSession(config) {
|
|
13
|
-
const auth = core.assertAuthConfig(config);
|
|
14
|
-
const jar = await headers.cookies();
|
|
15
|
-
const raw = jar.get(core.CMSSY_SESSION_COOKIE)?.value;
|
|
16
|
-
if (!raw) return null;
|
|
17
|
-
const session = await core.openSession(
|
|
18
|
-
raw,
|
|
19
|
-
auth.sessionSecret,
|
|
20
|
-
config.workspaceSlug
|
|
21
|
-
);
|
|
22
|
-
if (!session || core.isAccessExpired(session)) return null;
|
|
23
|
-
return session;
|
|
24
|
-
}
|
|
25
|
-
async function getCmssyUser(config) {
|
|
26
|
-
const session = await readValidSession(config);
|
|
27
|
-
return session?.user ?? null;
|
|
28
|
-
}
|
|
29
|
-
async function getCmssyAccessToken(config) {
|
|
30
|
-
const session = await readValidSession(config);
|
|
31
|
-
return session?.accessToken ?? null;
|
|
32
|
-
}
|
|
33
14
|
function hasEditFlag(value) {
|
|
34
15
|
return Array.isArray(value) ? value.includes("1") : value === "1";
|
|
35
16
|
}
|
|
@@ -40,7 +21,7 @@ async function resolveEditorRequest(query, draftSecret) {
|
|
|
40
21
|
if (!hasEditFlag(query[core.CMSSY_EDIT_QUERY_PARAM])) return false;
|
|
41
22
|
const provided = firstValue(query[core.CMSSY_SECRET_QUERY_PARAM]);
|
|
42
23
|
if (!provided || !draftSecret) return false;
|
|
43
|
-
return
|
|
24
|
+
return internal.cmssySecretsMatch(provided, draftSecret);
|
|
44
25
|
}
|
|
45
26
|
function createCmssyPage(config, blocks, options) {
|
|
46
27
|
return buildCmssyPageRenderer(config, blocks, options, false);
|
|
@@ -60,7 +41,7 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
60
41
|
org: config.org,
|
|
61
42
|
workspaceSlug: config.workspaceSlug
|
|
62
43
|
};
|
|
63
|
-
const client
|
|
44
|
+
const client = react.createCmssyClient(clientConfig);
|
|
64
45
|
const fixedPath = options?.path?.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
65
46
|
return async function CmssyCatchAllPage({
|
|
66
47
|
params,
|
|
@@ -73,27 +54,27 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
73
54
|
const query = searchParams ? await searchParams : {};
|
|
74
55
|
editorActive = await resolveEditorRequest(query, config.draftSecret);
|
|
75
56
|
if (!editorActive) {
|
|
76
|
-
if (
|
|
57
|
+
if (internal.isDevelopment()) {
|
|
77
58
|
return renderEditDiagnosticsPage(config, query);
|
|
78
59
|
}
|
|
79
60
|
navigation.notFound();
|
|
80
61
|
}
|
|
81
62
|
}
|
|
82
63
|
const editMode = isEnabled || editorActive;
|
|
83
|
-
const devAllowed =
|
|
64
|
+
const devAllowed = internal.isDevelopment() && Boolean(config.devToken?.trim());
|
|
84
65
|
let locale;
|
|
85
66
|
let pagePath = path;
|
|
86
|
-
const siteLocales = await
|
|
67
|
+
const siteLocales = await internal.resolveSiteLocales(clientConfig);
|
|
87
68
|
const { defaultLocale, locales: enabledLocales } = siteLocales;
|
|
88
69
|
if (config.resolveLocale) {
|
|
89
70
|
locale = await config.resolveLocale();
|
|
90
71
|
} else {
|
|
91
|
-
const split =
|
|
72
|
+
const split = internal.splitLocaleFromPath(path, siteLocales);
|
|
92
73
|
locale = split.locale;
|
|
93
74
|
pagePath = split.path;
|
|
94
75
|
}
|
|
95
|
-
const devWorkspaceId = devAllowed ? await client
|
|
96
|
-
const page = await
|
|
76
|
+
const devWorkspaceId = devAllowed ? await client.resolveWorkspaceId() : void 0;
|
|
77
|
+
const page = await internal.fetchPage(clientConfig, pagePath, {
|
|
97
78
|
previewSecret: editMode ? config.draftSecret : void 0,
|
|
98
79
|
devPreview: devAllowed || void 0,
|
|
99
80
|
devToken: devAllowed ? config.devToken : void 0,
|
|
@@ -107,7 +88,7 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
107
88
|
'cmssy: edit/dev mode requires options.editor \u2014 pass a "use client" editor that imports your blocks and renders <CmssyEditablePage blocks={blocks} \u2026 />'
|
|
108
89
|
);
|
|
109
90
|
}
|
|
110
|
-
const resolvedForms = await
|
|
91
|
+
const resolvedForms = await internal.resolveForms(
|
|
111
92
|
clientConfig,
|
|
112
93
|
page.blocks,
|
|
113
94
|
locale,
|
|
@@ -121,7 +102,7 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
121
102
|
};
|
|
122
103
|
if (editorActive && Editor) {
|
|
123
104
|
const bridgeOrigin = resolveBridgeOrigin(config.editorOrigin);
|
|
124
|
-
const editorData = await
|
|
105
|
+
const editorData = await internalServer.resolveEditorBlockData({
|
|
125
106
|
page,
|
|
126
107
|
blocks,
|
|
127
108
|
locale,
|
|
@@ -131,7 +112,7 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
131
112
|
isPreview: true,
|
|
132
113
|
config
|
|
133
114
|
});
|
|
134
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
115
|
+
return /* @__PURE__ */ jsxRuntime.jsx(internal$1.CmssyLocaleProvider, { value: localeContext, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
135
116
|
Editor,
|
|
136
117
|
{
|
|
137
118
|
page,
|
|
@@ -145,28 +126,17 @@ function buildCmssyPageRenderer(config, blocks, options, editRoute) {
|
|
|
145
126
|
}
|
|
146
127
|
) });
|
|
147
128
|
}
|
|
148
|
-
|
|
149
|
-
if (config.auth) {
|
|
150
|
-
try {
|
|
151
|
-
const user = await getCmssyUser(config);
|
|
152
|
-
auth = {
|
|
153
|
-
isAuthenticated: !!user,
|
|
154
|
-
member: user ? { recordId: user.recordId, email: user.email } : null
|
|
155
|
-
};
|
|
156
|
-
} catch {
|
|
157
|
-
auth = void 0;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
129
|
+
const auth = void 0;
|
|
160
130
|
let workspace;
|
|
161
131
|
try {
|
|
162
132
|
workspace = {
|
|
163
|
-
id: await client
|
|
133
|
+
id: await client.resolveWorkspaceId(),
|
|
164
134
|
slug: config.workspaceSlug
|
|
165
135
|
};
|
|
166
136
|
} catch {
|
|
167
137
|
workspace = void 0;
|
|
168
138
|
}
|
|
169
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
139
|
+
return /* @__PURE__ */ jsxRuntime.jsx(internal$1.CmssyLocaleProvider, { value: localeContext, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
170
140
|
react.CmssyServerPage,
|
|
171
141
|
{
|
|
172
142
|
page,
|
|
@@ -211,812 +181,18 @@ async function resolveDevOrigin() {
|
|
|
211
181
|
function resolveBridgeOrigin(editorOrigin) {
|
|
212
182
|
const resolved = core.resolveEditorOrigin(editorOrigin);
|
|
213
183
|
const origins = (Array.isArray(resolved) ? resolved : [resolved]).map(
|
|
214
|
-
(origin) =>
|
|
184
|
+
(origin) => internal.toCspOrigin(origin.trim())
|
|
215
185
|
);
|
|
216
186
|
if (origins.length === 0) {
|
|
217
187
|
throw new Error("cmssy: editorOrigin must be set to frame the editor");
|
|
218
188
|
}
|
|
219
|
-
if (origins.includes("*") && !
|
|
189
|
+
if (origins.includes("*") && !internal.isDevelopment()) {
|
|
220
190
|
throw new Error(
|
|
221
191
|
"cmssy: editorOrigin '*' is only allowed in development; set a concrete editor origin (e.g. https://cmssy.io) for production"
|
|
222
192
|
);
|
|
223
193
|
}
|
|
224
194
|
return origins.length === 1 ? origins[0] : origins;
|
|
225
195
|
}
|
|
226
|
-
function DefaultNotFound() {
|
|
227
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
228
|
-
"main",
|
|
229
|
-
{
|
|
230
|
-
style: {
|
|
231
|
-
minHeight: "60vh",
|
|
232
|
-
display: "flex",
|
|
233
|
-
flexDirection: "column",
|
|
234
|
-
alignItems: "center",
|
|
235
|
-
justifyContent: "center",
|
|
236
|
-
gap: "0.5rem",
|
|
237
|
-
textAlign: "center",
|
|
238
|
-
padding: "2rem"
|
|
239
|
-
},
|
|
240
|
-
children: [
|
|
241
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { style: { fontSize: "2rem", fontWeight: 700, margin: 0 }, children: "404" }),
|
|
242
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, opacity: 0.7 }, children: "Page not found" })
|
|
243
|
-
]
|
|
244
|
-
}
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
function createCmssyNotFound(config, blocks, options) {
|
|
248
|
-
if (!Array.isArray(blocks)) {
|
|
249
|
-
throw new Error(
|
|
250
|
-
"cmssy: createCmssyNotFound(config, blocks) requires a blocks array \u2014 pass your defineBlock(...) array"
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
const clientConfig = {
|
|
254
|
-
apiUrl: config.apiUrl,
|
|
255
|
-
org: config.org,
|
|
256
|
-
workspaceSlug: config.workspaceSlug
|
|
257
|
-
};
|
|
258
|
-
const fallback = options?.fallback ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultNotFound, {});
|
|
259
|
-
return async function CmssyNotFound() {
|
|
260
|
-
try {
|
|
261
|
-
const siteConfig = await react.fetchSiteConfig(clientConfig);
|
|
262
|
-
const notFoundPageId = siteConfig?.notFoundPageId;
|
|
263
|
-
if (!notFoundPageId) return fallback;
|
|
264
|
-
const page = await react.fetchPageById(clientConfig, notFoundPageId);
|
|
265
|
-
if (!page || page.blocks.length === 0) return fallback;
|
|
266
|
-
const { defaultLocale, locales: enabledLocales } = await react.resolveSiteLocales(clientConfig);
|
|
267
|
-
const locale = config.resolveLocale ? await config.resolveLocale() : defaultLocale;
|
|
268
|
-
const resolvedForms = await react.resolveForms(
|
|
269
|
-
clientConfig,
|
|
270
|
-
page.blocks,
|
|
271
|
-
locale,
|
|
272
|
-
defaultLocale
|
|
273
|
-
);
|
|
274
|
-
const forms = Object.keys(resolvedForms).length > 0 ? resolvedForms : void 0;
|
|
275
|
-
const localeContext = {
|
|
276
|
-
current: locale,
|
|
277
|
-
default: defaultLocale,
|
|
278
|
-
enabled: enabledLocales
|
|
279
|
-
};
|
|
280
|
-
return /* @__PURE__ */ jsxRuntime.jsx(client.CmssyLocaleProvider, { value: localeContext, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
281
|
-
react.CmssyServerPage,
|
|
282
|
-
{
|
|
283
|
-
page,
|
|
284
|
-
blocks,
|
|
285
|
-
locale,
|
|
286
|
-
defaultLocale,
|
|
287
|
-
enabledLocales,
|
|
288
|
-
forms
|
|
289
|
-
}
|
|
290
|
-
) });
|
|
291
|
-
} catch (err) {
|
|
292
|
-
if (typeof console !== "undefined") {
|
|
293
|
-
console.warn("[cmssy] not-found page render failed", err);
|
|
294
|
-
}
|
|
295
|
-
return fallback;
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
async function isCmssyEditMode() {
|
|
300
|
-
const h = await headers.headers();
|
|
301
|
-
return h.get(core.CMSSY_EDIT_HEADER) === "1";
|
|
302
|
-
}
|
|
303
|
-
async function getCmssyLocale(config, options) {
|
|
304
|
-
if (options?.path !== void 0) {
|
|
305
|
-
return core.localeForPath(config, options.path);
|
|
306
|
-
}
|
|
307
|
-
const { headers: headers3 } = await import('next/headers');
|
|
308
|
-
const headerList = await headers3();
|
|
309
|
-
const fromHeader = headerList.get(core.CMSSY_LOCALE_HEADER);
|
|
310
|
-
if (fromHeader) return fromHeader;
|
|
311
|
-
const { defaultLocale } = await core.resolveSiteLocales(config);
|
|
312
|
-
return defaultLocale;
|
|
313
|
-
}
|
|
314
|
-
async function CmssyLayoutSlot({
|
|
315
|
-
config,
|
|
316
|
-
blocks,
|
|
317
|
-
position,
|
|
318
|
-
page = "/",
|
|
319
|
-
editable
|
|
320
|
-
}) {
|
|
321
|
-
const editMode = await isCmssyEditMode();
|
|
322
|
-
const [groups, locale, siteLocales] = await Promise.all([
|
|
323
|
-
react.fetchLayouts(
|
|
324
|
-
config,
|
|
325
|
-
page,
|
|
326
|
-
editMode ? { previewSecret: config.draftSecret } : void 0
|
|
327
|
-
),
|
|
328
|
-
getCmssyLocale(config),
|
|
329
|
-
react.resolveSiteLocales(config)
|
|
330
|
-
]);
|
|
331
|
-
if (editMode && editable) {
|
|
332
|
-
const origin = core.resolveEditorOrigin(config.editorOrigin);
|
|
333
|
-
const Editable = editable;
|
|
334
|
-
const editorData = await react.resolveEditorLayoutBlockData({
|
|
335
|
-
groups,
|
|
336
|
-
blocks,
|
|
337
|
-
position,
|
|
338
|
-
locale,
|
|
339
|
-
defaultLocale: siteLocales.defaultLocale,
|
|
340
|
-
enabledLocales: siteLocales.locales,
|
|
341
|
-
isPreview: true,
|
|
342
|
-
config
|
|
343
|
-
});
|
|
344
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
345
|
-
Editable,
|
|
346
|
-
{
|
|
347
|
-
groups,
|
|
348
|
-
position,
|
|
349
|
-
locale,
|
|
350
|
-
defaultLocale: siteLocales.defaultLocale,
|
|
351
|
-
enabledLocales: siteLocales.locales,
|
|
352
|
-
edit: {
|
|
353
|
-
editorOrigin: (Array.isArray(origin) ? origin[0] : origin) ?? ""
|
|
354
|
-
},
|
|
355
|
-
data: editorData.data,
|
|
356
|
-
resolvedContent: editorData.content
|
|
357
|
-
}
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
361
|
-
react.CmssyServerLayout,
|
|
362
|
-
{
|
|
363
|
-
groups,
|
|
364
|
-
blocks,
|
|
365
|
-
position,
|
|
366
|
-
locale,
|
|
367
|
-
defaultLocale: siteLocales.defaultLocale,
|
|
368
|
-
enabledLocales: siteLocales.locales,
|
|
369
|
-
config,
|
|
370
|
-
editMode
|
|
371
|
-
}
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// src/seo-base-url.ts
|
|
376
|
-
function trimTrailingSlash(url) {
|
|
377
|
-
return url.replace(/\/+$/, "");
|
|
378
|
-
}
|
|
379
|
-
async function resolveSeoBaseUrl(config, option) {
|
|
380
|
-
if (typeof option === "function") return trimTrailingSlash(await option());
|
|
381
|
-
if (typeof option === "string" && option) return trimTrailingSlash(option);
|
|
382
|
-
if (config.siteUrl) return trimTrailingSlash(config.siteUrl);
|
|
383
|
-
const { headers: headers3 } = await import('next/headers');
|
|
384
|
-
const h = await headers3();
|
|
385
|
-
const host = h.get("host");
|
|
386
|
-
if (!host) return "";
|
|
387
|
-
const protocol = isLocalHost(host) ? "http" : "https";
|
|
388
|
-
return `${protocol}://${host}`;
|
|
389
|
-
}
|
|
390
|
-
function isLocalHost(host) {
|
|
391
|
-
const hostname = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "");
|
|
392
|
-
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname === "::1") {
|
|
393
|
-
return true;
|
|
394
|
-
}
|
|
395
|
-
const ipv4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
|
|
396
|
-
if (!ipv4) return false;
|
|
397
|
-
const [a, b] = [Number(ipv4[1]), Number(ipv4[2])];
|
|
398
|
-
return a === 127 || a === 0 || a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31;
|
|
399
|
-
}
|
|
400
|
-
function pick(value, locale, defaultLocale) {
|
|
401
|
-
if (!value) return "";
|
|
402
|
-
if (typeof value === "string") return value;
|
|
403
|
-
return value[locale] || value[defaultLocale] || Object.values(value)[0] || "";
|
|
404
|
-
}
|
|
405
|
-
async function buildCmssyMetadata(config, path, options = {}) {
|
|
406
|
-
const clientConfig = {
|
|
407
|
-
apiUrl: config.apiUrl,
|
|
408
|
-
org: config.org,
|
|
409
|
-
workspaceSlug: config.workspaceSlug
|
|
410
|
-
};
|
|
411
|
-
const [siteConfig, baseUrl] = await Promise.all([
|
|
412
|
-
react.fetchSiteConfig(clientConfig).catch(() => null),
|
|
413
|
-
resolveSeoBaseUrl(config, options.baseUrl)
|
|
414
|
-
]);
|
|
415
|
-
const { defaultLocale, locales: enabledLocales } = core.localesFromSiteConfig(siteConfig);
|
|
416
|
-
const segments = Array.isArray(path) ? path : path ? path.split("/").filter(Boolean) : void 0;
|
|
417
|
-
const fromPath = react.splitLocaleFromPath(segments, {
|
|
418
|
-
defaultLocale,
|
|
419
|
-
locales: enabledLocales
|
|
420
|
-
});
|
|
421
|
-
const locale = options.locale ?? (fromPath.locale !== defaultLocale ? fromPath.locale : await config.resolveLocale?.() ?? defaultLocale);
|
|
422
|
-
const slug = react.normalizeSlug(fromPath.path);
|
|
423
|
-
const meta = await react.fetchPageMeta(clientConfig, slug).catch(() => null);
|
|
424
|
-
const siteName = pick(siteConfig?.siteName, locale, defaultLocale) || siteConfig?.branding?.brandName || void 0;
|
|
425
|
-
const title = pick(meta?.seoTitle, locale, defaultLocale) || pick(meta?.displayName, locale, defaultLocale) || siteName || "";
|
|
426
|
-
const description = pick(meta?.seoDescription, locale, defaultLocale);
|
|
427
|
-
const keywords = meta?.seoKeywords?.length ? meta.seoKeywords : void 0;
|
|
428
|
-
const image = options.image ?? siteConfig?.branding?.ogImageUrl ?? void 0;
|
|
429
|
-
const canonical = baseUrl ? `${baseUrl}${core.localizedPath(slug, locale, defaultLocale)}` : void 0;
|
|
430
|
-
const languages = baseUrl && enabledLocales.length > 1 ? {
|
|
431
|
-
...Object.fromEntries(
|
|
432
|
-
enabledLocales.map((l) => [
|
|
433
|
-
l,
|
|
434
|
-
`${baseUrl}${core.localizedPath(slug, l, defaultLocale)}`
|
|
435
|
-
])
|
|
436
|
-
),
|
|
437
|
-
// What to serve a reader whose language none of these match.
|
|
438
|
-
"x-default": `${baseUrl}${core.localizedPath(slug, defaultLocale, defaultLocale)}`
|
|
439
|
-
} : void 0;
|
|
440
|
-
return {
|
|
441
|
-
...baseUrl ? { metadataBase: new URL(baseUrl) } : {},
|
|
442
|
-
...title ? { title } : {},
|
|
443
|
-
...description ? { description } : {},
|
|
444
|
-
...keywords ? { keywords } : {},
|
|
445
|
-
...canonical || languages ? {
|
|
446
|
-
alternates: {
|
|
447
|
-
...canonical ? { canonical } : {},
|
|
448
|
-
...languages ? { languages } : {}
|
|
449
|
-
}
|
|
450
|
-
} : {},
|
|
451
|
-
openGraph: {
|
|
452
|
-
...title ? { title } : {},
|
|
453
|
-
...description ? { description } : {},
|
|
454
|
-
...canonical ? { url: canonical } : {},
|
|
455
|
-
...siteName ? { siteName } : {},
|
|
456
|
-
type: options.ogType ?? "website",
|
|
457
|
-
locale,
|
|
458
|
-
...image ? { images: [{ url: image }] } : {}
|
|
459
|
-
},
|
|
460
|
-
twitter: {
|
|
461
|
-
card: image ? options.twitterCard ?? "summary_large_image" : "summary",
|
|
462
|
-
...title ? { title } : {},
|
|
463
|
-
...description ? { description } : {},
|
|
464
|
-
...image ? { images: [image] } : {}
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// src/create-cmssy-robots.ts
|
|
470
|
-
function createCmssyRobots(config, options = {}) {
|
|
471
|
-
return async function robots() {
|
|
472
|
-
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
473
|
-
const rules = options.rules ?? {
|
|
474
|
-
userAgent: "*",
|
|
475
|
-
allow: "/",
|
|
476
|
-
disallow: options.disallow ?? ["/api/"]
|
|
477
|
-
};
|
|
478
|
-
const includeSitemap = options.sitemap !== false && Boolean(baseUrl);
|
|
479
|
-
return {
|
|
480
|
-
rules,
|
|
481
|
-
...includeSitemap ? { sitemap: `${baseUrl}/sitemap.xml` } : {},
|
|
482
|
-
...options.host && baseUrl ? { host: baseUrl } : {}
|
|
483
|
-
};
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
function createCmssySitemap(config, options = {}) {
|
|
487
|
-
const clientConfig = {
|
|
488
|
-
apiUrl: config.apiUrl,
|
|
489
|
-
org: config.org,
|
|
490
|
-
workspaceSlug: config.workspaceSlug
|
|
491
|
-
};
|
|
492
|
-
return async function sitemap() {
|
|
493
|
-
let pages = [];
|
|
494
|
-
try {
|
|
495
|
-
pages = await react.fetchPages(clientConfig);
|
|
496
|
-
} catch (err) {
|
|
497
|
-
if (typeof console !== "undefined") {
|
|
498
|
-
console.warn("[cmssy] sitemap page fetch failed", err);
|
|
499
|
-
}
|
|
500
|
-
pages = [];
|
|
501
|
-
}
|
|
502
|
-
let siteConfig = null;
|
|
503
|
-
try {
|
|
504
|
-
siteConfig = await react.fetchSiteConfig(clientConfig);
|
|
505
|
-
} catch {
|
|
506
|
-
siteConfig = null;
|
|
507
|
-
}
|
|
508
|
-
const notFoundPageId = siteConfig?.notFoundPageId ?? null;
|
|
509
|
-
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
510
|
-
const { defaultLocale, locales } = core.localesFromSiteConfig(siteConfig);
|
|
511
|
-
const excluded = new Set((options.excludeSlugs ?? []).map(core.normalizeSlug));
|
|
512
|
-
const languagesFor = (slug) => locales.length > 1 ? {
|
|
513
|
-
languages: {
|
|
514
|
-
...Object.fromEntries(
|
|
515
|
-
locales.map((locale) => [
|
|
516
|
-
locale,
|
|
517
|
-
`${baseUrl}${core.localizedPath(slug, locale, defaultLocale)}`
|
|
518
|
-
])
|
|
519
|
-
),
|
|
520
|
-
"x-default": `${baseUrl}${core.localizedPath(slug, defaultLocale, defaultLocale)}`
|
|
521
|
-
}
|
|
522
|
-
} : void 0;
|
|
523
|
-
const entries = pages.map((page) => ({ ...page, slug: core.normalizeSlug(page.slug) })).filter((page) => page.id !== notFoundPageId && !excluded.has(page.slug)).flatMap((page) => {
|
|
524
|
-
const lastModified = page.updatedAt ?? page.publishedAt ?? void 0;
|
|
525
|
-
const alternates = languagesFor(page.slug);
|
|
526
|
-
return locales.map((locale) => ({
|
|
527
|
-
url: `${baseUrl}${core.localizedPath(page.slug, locale, defaultLocale)}`,
|
|
528
|
-
...lastModified ? { lastModified: new Date(lastModified) } : {},
|
|
529
|
-
...alternates ? { alternates } : {}
|
|
530
|
-
}));
|
|
531
|
-
});
|
|
532
|
-
if (!options.extra) return entries;
|
|
533
|
-
const extra = typeof options.extra === "function" ? await options.extra({ baseUrl, defaultLocale, locales }) : options.extra;
|
|
534
|
-
return [...entries, ...extra];
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
var MAX_BODY_CHARS = 16 * 1024;
|
|
538
|
-
function json(body, status = 200) {
|
|
539
|
-
return new Response(JSON.stringify(body), {
|
|
540
|
-
status,
|
|
541
|
-
headers: {
|
|
542
|
-
"content-type": "application/json",
|
|
543
|
-
"cache-control": "no-store"
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
async function readBody(request) {
|
|
548
|
-
const contentType = request.headers.get("content-type") ?? "";
|
|
549
|
-
if (!contentType.toLowerCase().includes("application/json")) {
|
|
550
|
-
throw new Error("content-type must be application/json");
|
|
551
|
-
}
|
|
552
|
-
const text = await request.text();
|
|
553
|
-
if (text.length > MAX_BODY_CHARS) {
|
|
554
|
-
throw new Error("body too large");
|
|
555
|
-
}
|
|
556
|
-
if (!text) return {};
|
|
557
|
-
const parsed = JSON.parse(text);
|
|
558
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
559
|
-
throw new Error("body must be a JSON object");
|
|
560
|
-
}
|
|
561
|
-
return parsed;
|
|
562
|
-
}
|
|
563
|
-
function str(value) {
|
|
564
|
-
return typeof value === "string" ? value : "";
|
|
565
|
-
}
|
|
566
|
-
function plainObject(value) {
|
|
567
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
568
|
-
return value;
|
|
569
|
-
}
|
|
570
|
-
async function readSession(config, auth) {
|
|
571
|
-
const jar = await headers.cookies();
|
|
572
|
-
const raw = jar.get(core.CMSSY_SESSION_COOKIE)?.value;
|
|
573
|
-
if (!raw) return null;
|
|
574
|
-
return core.openSession(raw, auth.sessionSecret, config.workspaceSlug);
|
|
575
|
-
}
|
|
576
|
-
async function writeSession(config, auth, payload) {
|
|
577
|
-
const sealed = await core.sealSession(
|
|
578
|
-
payload,
|
|
579
|
-
auth.sessionSecret,
|
|
580
|
-
config.workspaceSlug
|
|
581
|
-
);
|
|
582
|
-
const jar = await headers.cookies();
|
|
583
|
-
jar.set(core.CMSSY_SESSION_COOKIE, sealed, core.sessionCookieOptions());
|
|
584
|
-
}
|
|
585
|
-
async function clearSession() {
|
|
586
|
-
const jar = await headers.cookies();
|
|
587
|
-
jar.set(core.CMSSY_SESSION_COOKIE, "", {
|
|
588
|
-
...core.sessionCookieOptions(),
|
|
589
|
-
maxAge: 0
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
async function refreshSession(config, auth, session) {
|
|
593
|
-
const result = await core.backendRefresh(config, session.refreshToken);
|
|
594
|
-
const payload = core.toSessionPayload(result);
|
|
595
|
-
if (!payload) {
|
|
596
|
-
await clearSession();
|
|
597
|
-
return null;
|
|
598
|
-
}
|
|
599
|
-
await writeSession(config, auth, payload);
|
|
600
|
-
return payload;
|
|
601
|
-
}
|
|
602
|
-
function createCmssyAuthRoute(config) {
|
|
603
|
-
const auth = core.assertAuthConfig(config);
|
|
604
|
-
async function handleSignIn(body) {
|
|
605
|
-
const identity = str(body.identity);
|
|
606
|
-
const password = str(body.password);
|
|
607
|
-
if (!identity || !password) {
|
|
608
|
-
return json({ ok: false, message: "Invalid credentials." }, 400);
|
|
609
|
-
}
|
|
610
|
-
const result = await core.backendSignIn(
|
|
611
|
-
config,
|
|
612
|
-
auth.modelSlug,
|
|
613
|
-
identity,
|
|
614
|
-
password
|
|
615
|
-
);
|
|
616
|
-
const payload = core.toSessionPayload(result);
|
|
617
|
-
if (!payload) {
|
|
618
|
-
return json({ ok: false, message: result.message }, 401);
|
|
619
|
-
}
|
|
620
|
-
await writeSession(config, auth, payload);
|
|
621
|
-
return json({ ok: true, user: payload.user });
|
|
622
|
-
}
|
|
623
|
-
async function handleRegister(body) {
|
|
624
|
-
const identity = str(body.identity);
|
|
625
|
-
const password = str(body.password);
|
|
626
|
-
if (!identity || !password) {
|
|
627
|
-
return json({ ok: false, message: "Invalid input." }, 400);
|
|
628
|
-
}
|
|
629
|
-
const result = await core.backendRegister(
|
|
630
|
-
config,
|
|
631
|
-
auth.modelSlug,
|
|
632
|
-
identity,
|
|
633
|
-
password,
|
|
634
|
-
plainObject(body.fields)
|
|
635
|
-
);
|
|
636
|
-
return json({ ok: result.success, message: result.message });
|
|
637
|
-
}
|
|
638
|
-
async function handleSignOut() {
|
|
639
|
-
const session = await readSession(config, auth);
|
|
640
|
-
if (session) {
|
|
641
|
-
await core.backendSignOut(config, session.refreshToken);
|
|
642
|
-
}
|
|
643
|
-
await clearSession();
|
|
644
|
-
return json({ ok: true });
|
|
645
|
-
}
|
|
646
|
-
async function handleSignOutEverywhere() {
|
|
647
|
-
let session = await readSession(config, auth);
|
|
648
|
-
if (session && core.isAccessExpired(session)) {
|
|
649
|
-
session = await refreshSession(config, auth, session);
|
|
650
|
-
}
|
|
651
|
-
if (session) {
|
|
652
|
-
await core.backendSignOutEverywhere(config, session.accessToken);
|
|
653
|
-
}
|
|
654
|
-
await clearSession();
|
|
655
|
-
return json({ ok: true });
|
|
656
|
-
}
|
|
657
|
-
async function handleRefresh() {
|
|
658
|
-
const session = await readSession(config, auth);
|
|
659
|
-
if (!session) {
|
|
660
|
-
return json({ ok: false, user: null }, 401);
|
|
661
|
-
}
|
|
662
|
-
const refreshed = await refreshSession(config, auth, session);
|
|
663
|
-
if (!refreshed) {
|
|
664
|
-
return json({ ok: false, user: null }, 401);
|
|
665
|
-
}
|
|
666
|
-
return json({ ok: true, user: refreshed.user });
|
|
667
|
-
}
|
|
668
|
-
async function handleMe() {
|
|
669
|
-
let session = await readSession(config, auth);
|
|
670
|
-
if (session && core.isAccessExpired(session)) {
|
|
671
|
-
session = await refreshSession(config, auth, session);
|
|
672
|
-
}
|
|
673
|
-
return json({ user: session?.user ?? null });
|
|
674
|
-
}
|
|
675
|
-
async function handleForgotPassword(body) {
|
|
676
|
-
const identity = str(body.identity);
|
|
677
|
-
if (!identity) {
|
|
678
|
-
return json({ ok: false, message: "Invalid input." }, 400);
|
|
679
|
-
}
|
|
680
|
-
const result = await core.backendForgotPassword(
|
|
681
|
-
config,
|
|
682
|
-
auth.modelSlug,
|
|
683
|
-
identity
|
|
684
|
-
);
|
|
685
|
-
return json({ ok: result.success, message: result.message });
|
|
686
|
-
}
|
|
687
|
-
async function handleResetPassword(body) {
|
|
688
|
-
const token = str(body.token);
|
|
689
|
-
const newPassword = str(body.newPassword);
|
|
690
|
-
if (!token || !newPassword) {
|
|
691
|
-
return json({ ok: false, message: "Invalid input." }, 400);
|
|
692
|
-
}
|
|
693
|
-
const result = await core.backendResetPassword(config, token, newPassword);
|
|
694
|
-
return json({ ok: result.success, message: result.message });
|
|
695
|
-
}
|
|
696
|
-
async function handleVerifyEmail(body) {
|
|
697
|
-
const token = str(body.token);
|
|
698
|
-
if (!token) {
|
|
699
|
-
return json({ ok: false, message: "Invalid input." }, 400);
|
|
700
|
-
}
|
|
701
|
-
const result = await core.backendVerifyEmail(config, token);
|
|
702
|
-
return json({ ok: result.success, message: result.message });
|
|
703
|
-
}
|
|
704
|
-
return {
|
|
705
|
-
async POST(request, context) {
|
|
706
|
-
const { action } = await context.params;
|
|
707
|
-
let body;
|
|
708
|
-
try {
|
|
709
|
-
body = await readBody(request);
|
|
710
|
-
} catch {
|
|
711
|
-
return json({ ok: false, message: "Invalid request body." }, 400);
|
|
712
|
-
}
|
|
713
|
-
try {
|
|
714
|
-
switch (action) {
|
|
715
|
-
case "sign-in":
|
|
716
|
-
return await handleSignIn(body);
|
|
717
|
-
case "register":
|
|
718
|
-
return await handleRegister(body);
|
|
719
|
-
case "sign-out":
|
|
720
|
-
return await handleSignOut();
|
|
721
|
-
case "sign-out-everywhere":
|
|
722
|
-
return await handleSignOutEverywhere();
|
|
723
|
-
case "refresh":
|
|
724
|
-
return await handleRefresh();
|
|
725
|
-
case "forgot-password":
|
|
726
|
-
return await handleForgotPassword(body);
|
|
727
|
-
case "reset-password":
|
|
728
|
-
return await handleResetPassword(body);
|
|
729
|
-
case "verify-email":
|
|
730
|
-
return await handleVerifyEmail(body);
|
|
731
|
-
default:
|
|
732
|
-
return json({ ok: false, message: "Not found." }, 404);
|
|
733
|
-
}
|
|
734
|
-
} catch {
|
|
735
|
-
return json({ ok: false, message: "Something went wrong." }, 500);
|
|
736
|
-
}
|
|
737
|
-
},
|
|
738
|
-
async GET(_request, context) {
|
|
739
|
-
const { action } = await context.params;
|
|
740
|
-
if (action !== "me") {
|
|
741
|
-
return json({ ok: false, message: "Not found." }, 404);
|
|
742
|
-
}
|
|
743
|
-
try {
|
|
744
|
-
return await handleMe();
|
|
745
|
-
} catch {
|
|
746
|
-
return json({ user: null });
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
var CMSSY_CART_COOKIE = "cmssy_cart";
|
|
752
|
-
var CART_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
|
|
753
|
-
var CART_TOKEN_BYTES = 32;
|
|
754
|
-
var MAX_BODY_CHARS2 = 16 * 1024;
|
|
755
|
-
function json2(body, status = 200) {
|
|
756
|
-
return new Response(JSON.stringify(body), {
|
|
757
|
-
status,
|
|
758
|
-
headers: {
|
|
759
|
-
"content-type": "application/json",
|
|
760
|
-
"cache-control": "no-store"
|
|
761
|
-
}
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
function cartCookieOptions() {
|
|
765
|
-
return {
|
|
766
|
-
httpOnly: true,
|
|
767
|
-
secure: process.env.NODE_ENV !== "development",
|
|
768
|
-
sameSite: "lax",
|
|
769
|
-
path: "/",
|
|
770
|
-
maxAge: CART_MAX_AGE_SECONDS
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
function mintToken() {
|
|
774
|
-
const bytes = new Uint8Array(CART_TOKEN_BYTES);
|
|
775
|
-
crypto.getRandomValues(bytes);
|
|
776
|
-
let binary = "";
|
|
777
|
-
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
778
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
779
|
-
}
|
|
780
|
-
async function readBody2(request) {
|
|
781
|
-
const contentType = request.headers.get("content-type") ?? "";
|
|
782
|
-
if (!contentType.toLowerCase().includes("application/json")) {
|
|
783
|
-
throw new Error("content-type must be application/json");
|
|
784
|
-
}
|
|
785
|
-
const text = await request.text();
|
|
786
|
-
if (text.length > MAX_BODY_CHARS2) throw new Error("body too large");
|
|
787
|
-
if (!text) return {};
|
|
788
|
-
const parsed = JSON.parse(text);
|
|
789
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
790
|
-
throw new Error("body must be a JSON object");
|
|
791
|
-
}
|
|
792
|
-
return parsed;
|
|
793
|
-
}
|
|
794
|
-
function str2(value) {
|
|
795
|
-
return typeof value === "string" ? value : "";
|
|
796
|
-
}
|
|
797
|
-
function plainObject2(value) {
|
|
798
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
799
|
-
return value;
|
|
800
|
-
}
|
|
801
|
-
function optionalStr(value) {
|
|
802
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
803
|
-
}
|
|
804
|
-
var ADDRESS_REQUIRED = [
|
|
805
|
-
"name",
|
|
806
|
-
"line1",
|
|
807
|
-
"postalCode",
|
|
808
|
-
"city",
|
|
809
|
-
"country"
|
|
810
|
-
];
|
|
811
|
-
var CmssyAddressError = class extends Error {
|
|
812
|
-
constructor(missing) {
|
|
813
|
-
super(
|
|
814
|
-
`cmssy: shippingAddress is missing required field(s): ${missing.join(
|
|
815
|
-
", "
|
|
816
|
-
)}. Expected { name, line1, postalCode, city, country } (plus optional company, line2, region, phone, vatId).`
|
|
817
|
-
);
|
|
818
|
-
this.missing = missing;
|
|
819
|
-
this.name = "CmssyAddressError";
|
|
820
|
-
}
|
|
821
|
-
missing;
|
|
822
|
-
};
|
|
823
|
-
function shippingAddress(value) {
|
|
824
|
-
if (value === void 0 || value === null) return null;
|
|
825
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
826
|
-
throw new CmssyAddressError([...ADDRESS_REQUIRED]);
|
|
827
|
-
}
|
|
828
|
-
const raw = value;
|
|
829
|
-
const missing = ADDRESS_REQUIRED.filter((key) => !optionalStr(raw[key]));
|
|
830
|
-
if (missing.length > 0) throw new CmssyAddressError(missing);
|
|
831
|
-
return {
|
|
832
|
-
name: optionalStr(raw.name),
|
|
833
|
-
company: optionalStr(raw.company),
|
|
834
|
-
line1: optionalStr(raw.line1),
|
|
835
|
-
line2: optionalStr(raw.line2),
|
|
836
|
-
postalCode: optionalStr(raw.postalCode),
|
|
837
|
-
city: optionalStr(raw.city),
|
|
838
|
-
region: optionalStr(raw.region),
|
|
839
|
-
country: optionalStr(raw.country),
|
|
840
|
-
phone: optionalStr(raw.phone),
|
|
841
|
-
vatId: optionalStr(raw.vatId)
|
|
842
|
-
};
|
|
843
|
-
}
|
|
844
|
-
function createCmssyCartRoute(config) {
|
|
845
|
-
async function ensureCartToken() {
|
|
846
|
-
const jar = await headers.cookies();
|
|
847
|
-
const existing = jar.get(CMSSY_CART_COOKIE)?.value;
|
|
848
|
-
if (existing) return existing;
|
|
849
|
-
const token = mintToken();
|
|
850
|
-
jar.set(CMSSY_CART_COOKIE, token, cartCookieOptions());
|
|
851
|
-
return token;
|
|
852
|
-
}
|
|
853
|
-
async function clearCartToken() {
|
|
854
|
-
const jar = await headers.cookies();
|
|
855
|
-
jar.set(CMSSY_CART_COOKIE, "", { ...cartCookieOptions(), maxAge: 0 });
|
|
856
|
-
}
|
|
857
|
-
async function memberAccessToken() {
|
|
858
|
-
if (!config.auth) return void 0;
|
|
859
|
-
const jar = await headers.cookies();
|
|
860
|
-
const raw = jar.get(core.CMSSY_SESSION_COOKIE)?.value;
|
|
861
|
-
if (!raw) return void 0;
|
|
862
|
-
const session = await core.openSession(
|
|
863
|
-
raw,
|
|
864
|
-
config.auth.sessionSecret,
|
|
865
|
-
config.workspaceSlug
|
|
866
|
-
);
|
|
867
|
-
if (!session || core.isAccessExpired(session)) return void 0;
|
|
868
|
-
return session.accessToken;
|
|
869
|
-
}
|
|
870
|
-
async function buildContext() {
|
|
871
|
-
const cartToken = await ensureCartToken();
|
|
872
|
-
const accessToken = await memberAccessToken();
|
|
873
|
-
return accessToken ? { cartToken, accessToken } : { cartToken };
|
|
874
|
-
}
|
|
875
|
-
return {
|
|
876
|
-
async POST(request, context) {
|
|
877
|
-
const { action } = await context.params;
|
|
878
|
-
let body;
|
|
879
|
-
try {
|
|
880
|
-
body = await readBody2(request);
|
|
881
|
-
} catch {
|
|
882
|
-
return json2({ message: "Invalid request body." }, 400);
|
|
883
|
-
}
|
|
884
|
-
try {
|
|
885
|
-
const ctx = await buildContext();
|
|
886
|
-
switch (action) {
|
|
887
|
-
case "cart":
|
|
888
|
-
return json2({ cart: await core.backendGetCart(config, ctx) });
|
|
889
|
-
case "add":
|
|
890
|
-
return json2({
|
|
891
|
-
cart: await core.backendAddToCart(config, ctx, {
|
|
892
|
-
recordId: str2(body.recordId),
|
|
893
|
-
quantity: typeof body.quantity === "number" ? body.quantity : 1,
|
|
894
|
-
variantSelections: body.variantSelections,
|
|
895
|
-
notes: typeof body.notes === "string" ? body.notes : void 0
|
|
896
|
-
})
|
|
897
|
-
});
|
|
898
|
-
case "update":
|
|
899
|
-
return json2({
|
|
900
|
-
cart: await core.backendUpdateItem(config, ctx, {
|
|
901
|
-
itemId: str2(body.itemId),
|
|
902
|
-
quantity: typeof body.quantity === "number" ? body.quantity : 0
|
|
903
|
-
})
|
|
904
|
-
});
|
|
905
|
-
case "remove":
|
|
906
|
-
return json2({
|
|
907
|
-
cart: await core.backendRemoveItem(config, ctx, str2(body.itemId))
|
|
908
|
-
});
|
|
909
|
-
case "clear":
|
|
910
|
-
return json2({ cart: await core.backendClearCart(config, ctx) });
|
|
911
|
-
case "apply-discount":
|
|
912
|
-
return json2({
|
|
913
|
-
cart: await core.backendApplyDiscount(config, ctx, str2(body.code))
|
|
914
|
-
});
|
|
915
|
-
case "remove-discount":
|
|
916
|
-
return json2({ cart: await core.backendRemoveDiscount(config, ctx) });
|
|
917
|
-
case "set-shipping":
|
|
918
|
-
return json2({
|
|
919
|
-
cart: await core.backendSetShippingMethod(
|
|
920
|
-
config,
|
|
921
|
-
ctx,
|
|
922
|
-
optionalStr(body.shippingMethodId)
|
|
923
|
-
)
|
|
924
|
-
});
|
|
925
|
-
case "merge":
|
|
926
|
-
return json2({ cart: await core.backendMergeCart(config, ctx) });
|
|
927
|
-
case "checkout": {
|
|
928
|
-
const order = await core.backendCheckout(config, ctx, {
|
|
929
|
-
customerEmail: str2(body.customerEmail),
|
|
930
|
-
poNumber: optionalStr(body.poNumber),
|
|
931
|
-
customerNote: optionalStr(body.customerNote),
|
|
932
|
-
shippingAddress: shippingAddress(body.shippingAddress)
|
|
933
|
-
});
|
|
934
|
-
await clearCartToken();
|
|
935
|
-
return json2({ order });
|
|
936
|
-
}
|
|
937
|
-
case "product":
|
|
938
|
-
return json2({
|
|
939
|
-
product: await core.backendProduct(
|
|
940
|
-
config,
|
|
941
|
-
ctx,
|
|
942
|
-
str2(body.modelSlug),
|
|
943
|
-
plainObject2(body.filter)
|
|
944
|
-
)
|
|
945
|
-
});
|
|
946
|
-
default:
|
|
947
|
-
return json2({ message: "Not found." }, 404);
|
|
948
|
-
}
|
|
949
|
-
} catch (err) {
|
|
950
|
-
if (err instanceof CmssyAddressError) {
|
|
951
|
-
return json2({ message: err.message, missing: err.missing }, 400);
|
|
952
|
-
}
|
|
953
|
-
return json2(
|
|
954
|
-
{
|
|
955
|
-
message: err instanceof Error ? err.message : "Commerce request failed"
|
|
956
|
-
},
|
|
957
|
-
502
|
|
958
|
-
);
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
var DEFAULT_LIMIT = 20;
|
|
964
|
-
var MAX_LIMIT = 100;
|
|
965
|
-
function json3(body, status = 200) {
|
|
966
|
-
return new Response(JSON.stringify(body), {
|
|
967
|
-
status,
|
|
968
|
-
headers: {
|
|
969
|
-
"content-type": "application/json",
|
|
970
|
-
"cache-control": "no-store"
|
|
971
|
-
}
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
function createCmssyOrdersRoute(config) {
|
|
975
|
-
async function memberAccessToken() {
|
|
976
|
-
if (!config.auth) return void 0;
|
|
977
|
-
const jar = await headers.cookies();
|
|
978
|
-
const raw = jar.get(core.CMSSY_SESSION_COOKIE)?.value;
|
|
979
|
-
if (!raw) return void 0;
|
|
980
|
-
const session = await core.openSession(
|
|
981
|
-
raw,
|
|
982
|
-
config.auth.sessionSecret,
|
|
983
|
-
config.workspaceSlug
|
|
984
|
-
);
|
|
985
|
-
if (!session || core.isAccessExpired(session)) return void 0;
|
|
986
|
-
return session.accessToken;
|
|
987
|
-
}
|
|
988
|
-
return {
|
|
989
|
-
async GET(request) {
|
|
990
|
-
const accessToken = await memberAccessToken();
|
|
991
|
-
if (!accessToken) {
|
|
992
|
-
return json3({ message: "Not signed in." }, 401);
|
|
993
|
-
}
|
|
994
|
-
const url = new URL(request.url);
|
|
995
|
-
try {
|
|
996
|
-
const id = url.searchParams.get("id");
|
|
997
|
-
if (id) {
|
|
998
|
-
return json3({ order: await core.backendMyOrder(config, accessToken, id) });
|
|
999
|
-
}
|
|
1000
|
-
const skip = Math.max(
|
|
1001
|
-
0,
|
|
1002
|
-
Math.floor(Number(url.searchParams.get("skip")) || 0)
|
|
1003
|
-
);
|
|
1004
|
-
const limitParam = Math.floor(Number(url.searchParams.get("limit")));
|
|
1005
|
-
const limit = Number.isFinite(limitParam) && limitParam > 0 ? Math.min(limitParam, MAX_LIMIT) : DEFAULT_LIMIT;
|
|
1006
|
-
const result = await core.backendMyOrders(config, accessToken, {
|
|
1007
|
-
skip,
|
|
1008
|
-
limit
|
|
1009
|
-
});
|
|
1010
|
-
return json3(result);
|
|
1011
|
-
} catch (err) {
|
|
1012
|
-
return json3(
|
|
1013
|
-
{ message: err instanceof Error ? err.message : "Orders error" },
|
|
1014
|
-
502
|
|
1015
|
-
);
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
196
|
var MIN_SECRET_LENGTH = 16;
|
|
1021
197
|
function safeRedirect(redirect2, fallback) {
|
|
1022
198
|
if (!redirect2 || !redirect2.startsWith("/")) return fallback;
|
|
@@ -1053,7 +229,7 @@ function createDraftRoute(config) {
|
|
|
1053
229
|
);
|
|
1054
230
|
}
|
|
1055
231
|
const secret = url.searchParams.get("secret");
|
|
1056
|
-
if (!secret || !await
|
|
232
|
+
if (!secret || !await internal.cmssySecretsMatch(secret, config.draftSecret)) {
|
|
1057
233
|
return new Response("Invalid draft secret", { status: 401 });
|
|
1058
234
|
}
|
|
1059
235
|
const location = safeRedirect(
|
|
@@ -1065,37 +241,12 @@ function createDraftRoute(config) {
|
|
|
1065
241
|
navigation.redirect(location);
|
|
1066
242
|
};
|
|
1067
243
|
}
|
|
1068
|
-
async function
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
} catch {
|
|
1072
|
-
return void 0;
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
async function fetchProducts(config, options) {
|
|
1076
|
-
const locale = options.locale ?? await requestLocale(config);
|
|
1077
|
-
return core.fetchProducts(config, { ...options, locale });
|
|
1078
|
-
}
|
|
1079
|
-
async function fetchProduct(config, options) {
|
|
1080
|
-
const locale = options.locale ?? await requestLocale(config);
|
|
1081
|
-
return core.fetchProduct(config, { ...options, locale });
|
|
244
|
+
async function isCmssyEditMode() {
|
|
245
|
+
const h = await headers.headers();
|
|
246
|
+
return h.get(core.CMSSY_EDIT_HEADER) === "1";
|
|
1082
247
|
}
|
|
1083
248
|
|
|
1084
|
-
exports.CMSSY_CART_COOKIE = CMSSY_CART_COOKIE;
|
|
1085
|
-
exports.CmssyLayoutSlot = CmssyLayoutSlot;
|
|
1086
|
-
exports.buildCmssyMetadata = buildCmssyMetadata;
|
|
1087
|
-
exports.createCmssyAuthRoute = createCmssyAuthRoute;
|
|
1088
|
-
exports.createCmssyCartRoute = createCmssyCartRoute;
|
|
1089
249
|
exports.createCmssyEditPage = createCmssyEditPage;
|
|
1090
|
-
exports.createCmssyNotFound = createCmssyNotFound;
|
|
1091
|
-
exports.createCmssyOrdersRoute = createCmssyOrdersRoute;
|
|
1092
250
|
exports.createCmssyPage = createCmssyPage;
|
|
1093
|
-
exports.createCmssyRobots = createCmssyRobots;
|
|
1094
|
-
exports.createCmssySitemap = createCmssySitemap;
|
|
1095
251
|
exports.createDraftRoute = createDraftRoute;
|
|
1096
|
-
exports.fetchProduct = fetchProduct;
|
|
1097
|
-
exports.fetchProducts = fetchProducts;
|
|
1098
|
-
exports.getCmssyAccessToken = getCmssyAccessToken;
|
|
1099
|
-
exports.getCmssyLocale = getCmssyLocale;
|
|
1100
|
-
exports.getCmssyUser = getCmssyUser;
|
|
1101
252
|
exports.isCmssyEditMode = isCmssyEditMode;
|