@cmssy/next 0.4.0 → 0.5.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/dist/index.cjs +89 -0
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +89 -2
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -244,6 +244,93 @@ function createCmssyNotFound(config, blocks, options) {
|
|
|
244
244
|
}
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
|
+
|
|
248
|
+
// src/seo-base-url.ts
|
|
249
|
+
function trimTrailingSlash(url) {
|
|
250
|
+
return url.replace(/\/+$/, "");
|
|
251
|
+
}
|
|
252
|
+
async function resolveSeoBaseUrl(config, option) {
|
|
253
|
+
if (typeof option === "function") return trimTrailingSlash(await option());
|
|
254
|
+
if (typeof option === "string" && option) return trimTrailingSlash(option);
|
|
255
|
+
if (config.siteUrl) return trimTrailingSlash(config.siteUrl);
|
|
256
|
+
const { headers: headers3 } = await import('next/headers');
|
|
257
|
+
const h = await headers3();
|
|
258
|
+
const host = h.get("host");
|
|
259
|
+
if (!host) return "";
|
|
260
|
+
const protocol = isLocalHost(host) ? "http" : "https";
|
|
261
|
+
return `${protocol}://${host}`;
|
|
262
|
+
}
|
|
263
|
+
function isLocalHost(host) {
|
|
264
|
+
const hostname = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "");
|
|
265
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname === "::1") {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
const ipv4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
|
|
269
|
+
if (!ipv4) return false;
|
|
270
|
+
const [a, b] = [Number(ipv4[1]), Number(ipv4[2])];
|
|
271
|
+
return a === 127 || a === 0 || a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/create-cmssy-robots.ts
|
|
275
|
+
function createCmssyRobots(config, options = {}) {
|
|
276
|
+
return async function robots() {
|
|
277
|
+
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
278
|
+
const rules = options.rules ?? {
|
|
279
|
+
userAgent: "*",
|
|
280
|
+
allow: "/",
|
|
281
|
+
disallow: options.disallow ?? ["/api/"]
|
|
282
|
+
};
|
|
283
|
+
const includeSitemap = options.sitemap !== false && Boolean(baseUrl);
|
|
284
|
+
return {
|
|
285
|
+
rules,
|
|
286
|
+
...includeSitemap ? { sitemap: `${baseUrl}/sitemap.xml` } : {},
|
|
287
|
+
...baseUrl ? { host: baseUrl } : {}
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function localizedPath(slug, locale, defaultLocale) {
|
|
292
|
+
const base = slug === "/" ? "" : slug;
|
|
293
|
+
return locale === defaultLocale ? base || "/" : `/${locale}${base}`;
|
|
294
|
+
}
|
|
295
|
+
function createCmssySitemap(config, options = {}) {
|
|
296
|
+
const clientConfig = {
|
|
297
|
+
apiUrl: config.apiUrl,
|
|
298
|
+
workspaceSlug: config.workspaceSlug
|
|
299
|
+
};
|
|
300
|
+
return async function sitemap() {
|
|
301
|
+
let pages = [];
|
|
302
|
+
try {
|
|
303
|
+
pages = await react.fetchPages(clientConfig);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
if (typeof console !== "undefined") {
|
|
306
|
+
console.warn("[cmssy] sitemap page fetch failed", err);
|
|
307
|
+
}
|
|
308
|
+
pages = [];
|
|
309
|
+
}
|
|
310
|
+
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
311
|
+
const defaultLocale = config.defaultLocale ?? "en";
|
|
312
|
+
const locales = config.enabledLocales && config.enabledLocales.length > 0 ? config.enabledLocales : [defaultLocale];
|
|
313
|
+
const entries = pages.map((page) => {
|
|
314
|
+
const lastModified = page.updatedAt ?? page.publishedAt ?? void 0;
|
|
315
|
+
const entry = {
|
|
316
|
+
url: `${baseUrl}${localizedPath(page.slug, defaultLocale, defaultLocale)}`,
|
|
317
|
+
...lastModified ? { lastModified: new Date(lastModified) } : {}
|
|
318
|
+
};
|
|
319
|
+
if (locales.length > 1) {
|
|
320
|
+
entry.alternates = {
|
|
321
|
+
languages: Object.fromEntries(
|
|
322
|
+
locales.map((locale) => [
|
|
323
|
+
locale,
|
|
324
|
+
`${baseUrl}${localizedPath(page.slug, locale, defaultLocale)}`
|
|
325
|
+
])
|
|
326
|
+
)
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
return entry;
|
|
330
|
+
});
|
|
331
|
+
return options.extra ? [...entries, ...options.extra] : entries;
|
|
332
|
+
};
|
|
333
|
+
}
|
|
247
334
|
var MIN_SECRET_LENGTH = 16;
|
|
248
335
|
function secretsMatch(a, b) {
|
|
249
336
|
const ha = crypto$1.createHash("sha256").update(a).digest();
|
|
@@ -1428,6 +1515,8 @@ exports.createCmssyLocaleMiddleware = createCmssyLocaleMiddleware;
|
|
|
1428
1515
|
exports.createCmssyNotFound = createCmssyNotFound;
|
|
1429
1516
|
exports.createCmssyOrdersRoute = createCmssyOrdersRoute;
|
|
1430
1517
|
exports.createCmssyPage = createCmssyPage;
|
|
1518
|
+
exports.createCmssyRobots = createCmssyRobots;
|
|
1519
|
+
exports.createCmssySitemap = createCmssySitemap;
|
|
1431
1520
|
exports.createDraftRoute = createDraftRoute;
|
|
1432
1521
|
exports.fetchProduct = fetchProduct;
|
|
1433
1522
|
exports.fetchProducts = fetchProducts;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import { CmssyPageData, CmssyFormDefinition, BlockDefinition, CmssyClientConfig, CmssyProduct, CmssyOrder } from '@cmssy/react';
|
|
4
4
|
import { EditBridgeConfig } from '@cmssy/react/client';
|
|
5
|
+
import { MetadataRoute } from 'next';
|
|
5
6
|
import { NextRequest, NextResponse } from 'next/server';
|
|
6
7
|
|
|
7
8
|
interface CmssyAuthConfig {
|
|
@@ -13,6 +14,12 @@ interface CmssyNextConfig {
|
|
|
13
14
|
workspaceSlug: string;
|
|
14
15
|
draftSecret: string;
|
|
15
16
|
editorOrigin: string | string[];
|
|
17
|
+
/**
|
|
18
|
+
* Canonical absolute site URL (e.g. https://cmssy.com), used by
|
|
19
|
+
* createCmssyRobots / createCmssySitemap. When omitted the helpers derive the
|
|
20
|
+
* origin from the request `host` header at render time (multi-domain safe).
|
|
21
|
+
*/
|
|
22
|
+
siteUrl?: string;
|
|
16
23
|
auth?: CmssyAuthConfig;
|
|
17
24
|
defaultLocale?: string;
|
|
18
25
|
/** All languages enabled on the workspace; exposed to blocks via context.locale.enabled. */
|
|
@@ -58,6 +65,43 @@ interface CreateCmssyNotFoundOptions {
|
|
|
58
65
|
*/
|
|
59
66
|
declare function createCmssyNotFound(config: CmssyNextConfig, blocks: BlockDefinition[], options?: CreateCmssyNotFoundOptions): () => Promise<string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<ReactNode> | null | undefined>;
|
|
60
67
|
|
|
68
|
+
interface SeoBaseUrlOption {
|
|
69
|
+
/**
|
|
70
|
+
* Override for the canonical origin. A string (e.g. https://cmssy.com) or a
|
|
71
|
+
* resolver. Falls back to `config.siteUrl`, then the request `host` header.
|
|
72
|
+
*/
|
|
73
|
+
baseUrl?: string | (() => string | Promise<string>);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface CreateCmssyRobotsOptions extends SeoBaseUrlOption {
|
|
77
|
+
/** Path prefixes to disallow. Defaults to `["/api/"]`. */
|
|
78
|
+
disallow?: string[];
|
|
79
|
+
/** Override the generated rules entirely. */
|
|
80
|
+
rules?: MetadataRoute.Robots["rules"];
|
|
81
|
+
/** Reference `${baseUrl}/sitemap.xml`. Defaults to true. */
|
|
82
|
+
sitemap?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Builds the default export for Next's `app/robots.ts`. Allows crawling, points
|
|
86
|
+
* to the sitemap, and reports the canonical host. Drop in as:
|
|
87
|
+
*
|
|
88
|
+
* export default createCmssyRobots(cmssy);
|
|
89
|
+
*/
|
|
90
|
+
declare function createCmssyRobots(config: CmssyNextConfig, options?: CreateCmssyRobotsOptions): () => Promise<MetadataRoute.Robots>;
|
|
91
|
+
|
|
92
|
+
interface CreateCmssySitemapOptions extends SeoBaseUrlOption {
|
|
93
|
+
/** Extra static entries appended to the generated page list. */
|
|
94
|
+
extra?: MetadataRoute.Sitemap;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Builds the default export for Next's `app/sitemap.ts` from the workspace's
|
|
98
|
+
* published pages. Emits one entry per page with per-locale `alternates` when
|
|
99
|
+
* the config enables multiple locales. Drop in as:
|
|
100
|
+
*
|
|
101
|
+
* export default createCmssySitemap(cmssy);
|
|
102
|
+
*/
|
|
103
|
+
declare function createCmssySitemap(config: CmssyNextConfig, options?: CreateCmssySitemapOptions): () => Promise<MetadataRoute.Sitemap>;
|
|
104
|
+
|
|
61
105
|
type CmssyDraftRouteConfig = Pick<CmssyNextConfig, "draftSecret"> & {
|
|
62
106
|
defaultRedirect?: string;
|
|
63
107
|
};
|
|
@@ -251,4 +295,4 @@ declare class CmssyWebhookError extends Error {
|
|
|
251
295
|
*/
|
|
252
296
|
declare function verifyCmssyWebhook(options: VerifyCmssyWebhookOptions): CmssyWebhookEvent;
|
|
253
297
|
|
|
254
|
-
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, type CmssyAuthConfig, type CmssyAuthMiddleware, type CmssyAuthRouteHandlers, type CmssyCartRouteHandlers, type CmssyCspOptions, type CmssyDraftRouteConfig, type CmssyEditorProps, type CmssyNextConfig, type CmssyOrdersRouteHandlers, type CmssySessionPayload, type CmssySessionUser, CmssyWebhookError, type CmssyWebhookEvent, type CmssyWebhookOrder, type CreateCmssyNotFoundOptions, type CreateCmssyPageOptions, type FetchProductOptions, type FetchProductsOptions, type MyOrdersResult, SESSION_MAX_AGE_SECONDS, type SessionCookieOptions, type VerifyCmssyWebhookOptions, applyCmssyCsp, assertAuthConfig, cmssyCspHeaders, createCmssyAuthMiddleware, createCmssyAuthRoute, createCmssyCartRoute, createCmssyLocaleMiddleware, createCmssyNotFound, createCmssyOrdersRoute, createCmssyPage, createDraftRoute, fetchProduct, fetchProducts, getCmssyAccessToken, getCmssyLocale, getCmssyUser, isAccessExpired, isCmssyEditMode, isCmssyEditRequest, localeForPathname, openSession, resolveLocaleFromPathname, sealSession, sessionCookieOptions, splitCmssyLocale, verifyCmssyWebhook };
|
|
298
|
+
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, type CmssyAuthConfig, type CmssyAuthMiddleware, type CmssyAuthRouteHandlers, type CmssyCartRouteHandlers, type CmssyCspOptions, type CmssyDraftRouteConfig, type CmssyEditorProps, type CmssyNextConfig, type CmssyOrdersRouteHandlers, type CmssySessionPayload, type CmssySessionUser, CmssyWebhookError, type CmssyWebhookEvent, type CmssyWebhookOrder, type CreateCmssyNotFoundOptions, type CreateCmssyPageOptions, type CreateCmssyRobotsOptions, type CreateCmssySitemapOptions, type FetchProductOptions, type FetchProductsOptions, type MyOrdersResult, SESSION_MAX_AGE_SECONDS, type SessionCookieOptions, type VerifyCmssyWebhookOptions, applyCmssyCsp, assertAuthConfig, cmssyCspHeaders, createCmssyAuthMiddleware, createCmssyAuthRoute, createCmssyCartRoute, createCmssyLocaleMiddleware, createCmssyNotFound, createCmssyOrdersRoute, createCmssyPage, createCmssyRobots, createCmssySitemap, createDraftRoute, fetchProduct, fetchProducts, getCmssyAccessToken, getCmssyLocale, getCmssyUser, isAccessExpired, isCmssyEditMode, isCmssyEditRequest, localeForPathname, openSession, resolveLocaleFromPathname, sealSession, sessionCookieOptions, splitCmssyLocale, verifyCmssyWebhook };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import { CmssyPageData, CmssyFormDefinition, BlockDefinition, CmssyClientConfig, CmssyProduct, CmssyOrder } from '@cmssy/react';
|
|
4
4
|
import { EditBridgeConfig } from '@cmssy/react/client';
|
|
5
|
+
import { MetadataRoute } from 'next';
|
|
5
6
|
import { NextRequest, NextResponse } from 'next/server';
|
|
6
7
|
|
|
7
8
|
interface CmssyAuthConfig {
|
|
@@ -13,6 +14,12 @@ interface CmssyNextConfig {
|
|
|
13
14
|
workspaceSlug: string;
|
|
14
15
|
draftSecret: string;
|
|
15
16
|
editorOrigin: string | string[];
|
|
17
|
+
/**
|
|
18
|
+
* Canonical absolute site URL (e.g. https://cmssy.com), used by
|
|
19
|
+
* createCmssyRobots / createCmssySitemap. When omitted the helpers derive the
|
|
20
|
+
* origin from the request `host` header at render time (multi-domain safe).
|
|
21
|
+
*/
|
|
22
|
+
siteUrl?: string;
|
|
16
23
|
auth?: CmssyAuthConfig;
|
|
17
24
|
defaultLocale?: string;
|
|
18
25
|
/** All languages enabled on the workspace; exposed to blocks via context.locale.enabled. */
|
|
@@ -58,6 +65,43 @@ interface CreateCmssyNotFoundOptions {
|
|
|
58
65
|
*/
|
|
59
66
|
declare function createCmssyNotFound(config: CmssyNextConfig, blocks: BlockDefinition[], options?: CreateCmssyNotFoundOptions): () => Promise<string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<ReactNode> | null | undefined>;
|
|
60
67
|
|
|
68
|
+
interface SeoBaseUrlOption {
|
|
69
|
+
/**
|
|
70
|
+
* Override for the canonical origin. A string (e.g. https://cmssy.com) or a
|
|
71
|
+
* resolver. Falls back to `config.siteUrl`, then the request `host` header.
|
|
72
|
+
*/
|
|
73
|
+
baseUrl?: string | (() => string | Promise<string>);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface CreateCmssyRobotsOptions extends SeoBaseUrlOption {
|
|
77
|
+
/** Path prefixes to disallow. Defaults to `["/api/"]`. */
|
|
78
|
+
disallow?: string[];
|
|
79
|
+
/** Override the generated rules entirely. */
|
|
80
|
+
rules?: MetadataRoute.Robots["rules"];
|
|
81
|
+
/** Reference `${baseUrl}/sitemap.xml`. Defaults to true. */
|
|
82
|
+
sitemap?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Builds the default export for Next's `app/robots.ts`. Allows crawling, points
|
|
86
|
+
* to the sitemap, and reports the canonical host. Drop in as:
|
|
87
|
+
*
|
|
88
|
+
* export default createCmssyRobots(cmssy);
|
|
89
|
+
*/
|
|
90
|
+
declare function createCmssyRobots(config: CmssyNextConfig, options?: CreateCmssyRobotsOptions): () => Promise<MetadataRoute.Robots>;
|
|
91
|
+
|
|
92
|
+
interface CreateCmssySitemapOptions extends SeoBaseUrlOption {
|
|
93
|
+
/** Extra static entries appended to the generated page list. */
|
|
94
|
+
extra?: MetadataRoute.Sitemap;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Builds the default export for Next's `app/sitemap.ts` from the workspace's
|
|
98
|
+
* published pages. Emits one entry per page with per-locale `alternates` when
|
|
99
|
+
* the config enables multiple locales. Drop in as:
|
|
100
|
+
*
|
|
101
|
+
* export default createCmssySitemap(cmssy);
|
|
102
|
+
*/
|
|
103
|
+
declare function createCmssySitemap(config: CmssyNextConfig, options?: CreateCmssySitemapOptions): () => Promise<MetadataRoute.Sitemap>;
|
|
104
|
+
|
|
61
105
|
type CmssyDraftRouteConfig = Pick<CmssyNextConfig, "draftSecret"> & {
|
|
62
106
|
defaultRedirect?: string;
|
|
63
107
|
};
|
|
@@ -251,4 +295,4 @@ declare class CmssyWebhookError extends Error {
|
|
|
251
295
|
*/
|
|
252
296
|
declare function verifyCmssyWebhook(options: VerifyCmssyWebhookOptions): CmssyWebhookEvent;
|
|
253
297
|
|
|
254
|
-
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, type CmssyAuthConfig, type CmssyAuthMiddleware, type CmssyAuthRouteHandlers, type CmssyCartRouteHandlers, type CmssyCspOptions, type CmssyDraftRouteConfig, type CmssyEditorProps, type CmssyNextConfig, type CmssyOrdersRouteHandlers, type CmssySessionPayload, type CmssySessionUser, CmssyWebhookError, type CmssyWebhookEvent, type CmssyWebhookOrder, type CreateCmssyNotFoundOptions, type CreateCmssyPageOptions, type FetchProductOptions, type FetchProductsOptions, type MyOrdersResult, SESSION_MAX_AGE_SECONDS, type SessionCookieOptions, type VerifyCmssyWebhookOptions, applyCmssyCsp, assertAuthConfig, cmssyCspHeaders, createCmssyAuthMiddleware, createCmssyAuthRoute, createCmssyCartRoute, createCmssyLocaleMiddleware, createCmssyNotFound, createCmssyOrdersRoute, createCmssyPage, createDraftRoute, fetchProduct, fetchProducts, getCmssyAccessToken, getCmssyLocale, getCmssyUser, isAccessExpired, isCmssyEditMode, isCmssyEditRequest, localeForPathname, openSession, resolveLocaleFromPathname, sealSession, sessionCookieOptions, splitCmssyLocale, verifyCmssyWebhook };
|
|
298
|
+
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, type CmssyAuthConfig, type CmssyAuthMiddleware, type CmssyAuthRouteHandlers, type CmssyCartRouteHandlers, type CmssyCspOptions, type CmssyDraftRouteConfig, type CmssyEditorProps, type CmssyNextConfig, type CmssyOrdersRouteHandlers, type CmssySessionPayload, type CmssySessionUser, CmssyWebhookError, type CmssyWebhookEvent, type CmssyWebhookOrder, type CreateCmssyNotFoundOptions, type CreateCmssyPageOptions, type CreateCmssyRobotsOptions, type CreateCmssySitemapOptions, type FetchProductOptions, type FetchProductsOptions, type MyOrdersResult, SESSION_MAX_AGE_SECONDS, type SessionCookieOptions, type VerifyCmssyWebhookOptions, applyCmssyCsp, assertAuthConfig, cmssyCspHeaders, createCmssyAuthMiddleware, createCmssyAuthRoute, createCmssyCartRoute, createCmssyLocaleMiddleware, createCmssyNotFound, createCmssyOrdersRoute, createCmssyPage, createCmssyRobots, createCmssySitemap, createDraftRoute, fetchProduct, fetchProducts, getCmssyAccessToken, getCmssyLocale, getCmssyUser, isAccessExpired, isCmssyEditMode, isCmssyEditRequest, localeForPathname, openSession, resolveLocaleFromPathname, sealSession, sessionCookieOptions, splitCmssyLocale, verifyCmssyWebhook };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { draftMode, headers, cookies } from 'next/headers';
|
|
2
2
|
import { notFound, redirect } from 'next/navigation';
|
|
3
|
-
import { resolveSiteLocales, splitLocaleFromPath, fetchPage, resolveForms, CmssyServerPage, fetchSiteConfig, fetchPageById, resolveWorkspaceId, graphqlRequest } from '@cmssy/react';
|
|
3
|
+
import { resolveSiteLocales, splitLocaleFromPath, fetchPage, resolveForms, CmssyServerPage, fetchSiteConfig, fetchPageById, fetchPages, resolveWorkspaceId, graphqlRequest } from '@cmssy/react';
|
|
4
4
|
import { CmssyLocaleProvider } from '@cmssy/react/client';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
import { createHmac, createHash, timingSafeEqual } from 'crypto';
|
|
@@ -242,6 +242,93 @@ function createCmssyNotFound(config, blocks, options) {
|
|
|
242
242
|
}
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
|
+
|
|
246
|
+
// src/seo-base-url.ts
|
|
247
|
+
function trimTrailingSlash(url) {
|
|
248
|
+
return url.replace(/\/+$/, "");
|
|
249
|
+
}
|
|
250
|
+
async function resolveSeoBaseUrl(config, option) {
|
|
251
|
+
if (typeof option === "function") return trimTrailingSlash(await option());
|
|
252
|
+
if (typeof option === "string" && option) return trimTrailingSlash(option);
|
|
253
|
+
if (config.siteUrl) return trimTrailingSlash(config.siteUrl);
|
|
254
|
+
const { headers: headers3 } = await import('next/headers');
|
|
255
|
+
const h = await headers3();
|
|
256
|
+
const host = h.get("host");
|
|
257
|
+
if (!host) return "";
|
|
258
|
+
const protocol = isLocalHost(host) ? "http" : "https";
|
|
259
|
+
return `${protocol}://${host}`;
|
|
260
|
+
}
|
|
261
|
+
function isLocalHost(host) {
|
|
262
|
+
const hostname = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "");
|
|
263
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname === "::1") {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
const ipv4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
|
|
267
|
+
if (!ipv4) return false;
|
|
268
|
+
const [a, b] = [Number(ipv4[1]), Number(ipv4[2])];
|
|
269
|
+
return a === 127 || a === 0 || a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/create-cmssy-robots.ts
|
|
273
|
+
function createCmssyRobots(config, options = {}) {
|
|
274
|
+
return async function robots() {
|
|
275
|
+
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
276
|
+
const rules = options.rules ?? {
|
|
277
|
+
userAgent: "*",
|
|
278
|
+
allow: "/",
|
|
279
|
+
disallow: options.disallow ?? ["/api/"]
|
|
280
|
+
};
|
|
281
|
+
const includeSitemap = options.sitemap !== false && Boolean(baseUrl);
|
|
282
|
+
return {
|
|
283
|
+
rules,
|
|
284
|
+
...includeSitemap ? { sitemap: `${baseUrl}/sitemap.xml` } : {},
|
|
285
|
+
...baseUrl ? { host: baseUrl } : {}
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function localizedPath(slug, locale, defaultLocale) {
|
|
290
|
+
const base = slug === "/" ? "" : slug;
|
|
291
|
+
return locale === defaultLocale ? base || "/" : `/${locale}${base}`;
|
|
292
|
+
}
|
|
293
|
+
function createCmssySitemap(config, options = {}) {
|
|
294
|
+
const clientConfig = {
|
|
295
|
+
apiUrl: config.apiUrl,
|
|
296
|
+
workspaceSlug: config.workspaceSlug
|
|
297
|
+
};
|
|
298
|
+
return async function sitemap() {
|
|
299
|
+
let pages = [];
|
|
300
|
+
try {
|
|
301
|
+
pages = await fetchPages(clientConfig);
|
|
302
|
+
} catch (err) {
|
|
303
|
+
if (typeof console !== "undefined") {
|
|
304
|
+
console.warn("[cmssy] sitemap page fetch failed", err);
|
|
305
|
+
}
|
|
306
|
+
pages = [];
|
|
307
|
+
}
|
|
308
|
+
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
309
|
+
const defaultLocale = config.defaultLocale ?? "en";
|
|
310
|
+
const locales = config.enabledLocales && config.enabledLocales.length > 0 ? config.enabledLocales : [defaultLocale];
|
|
311
|
+
const entries = pages.map((page) => {
|
|
312
|
+
const lastModified = page.updatedAt ?? page.publishedAt ?? void 0;
|
|
313
|
+
const entry = {
|
|
314
|
+
url: `${baseUrl}${localizedPath(page.slug, defaultLocale, defaultLocale)}`,
|
|
315
|
+
...lastModified ? { lastModified: new Date(lastModified) } : {}
|
|
316
|
+
};
|
|
317
|
+
if (locales.length > 1) {
|
|
318
|
+
entry.alternates = {
|
|
319
|
+
languages: Object.fromEntries(
|
|
320
|
+
locales.map((locale) => [
|
|
321
|
+
locale,
|
|
322
|
+
`${baseUrl}${localizedPath(page.slug, locale, defaultLocale)}`
|
|
323
|
+
])
|
|
324
|
+
)
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
return entry;
|
|
328
|
+
});
|
|
329
|
+
return options.extra ? [...entries, ...options.extra] : entries;
|
|
330
|
+
};
|
|
331
|
+
}
|
|
245
332
|
var MIN_SECRET_LENGTH = 16;
|
|
246
333
|
function secretsMatch(a, b) {
|
|
247
334
|
const ha = createHash("sha256").update(a).digest();
|
|
@@ -1410,4 +1497,4 @@ function verifyCmssyWebhook(options) {
|
|
|
1410
1497
|
return parsed;
|
|
1411
1498
|
}
|
|
1412
1499
|
|
|
1413
|
-
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, CmssyWebhookError, SESSION_MAX_AGE_SECONDS, applyCmssyCsp, assertAuthConfig, cmssyCspHeaders, createCmssyAuthMiddleware, createCmssyAuthRoute, createCmssyCartRoute, createCmssyLocaleMiddleware, createCmssyNotFound, createCmssyOrdersRoute, createCmssyPage, createDraftRoute, fetchProduct, fetchProducts, getCmssyAccessToken, getCmssyLocale, getCmssyUser, isAccessExpired, isCmssyEditMode, isCmssyEditRequest, localeForPathname, openSession, resolveLocaleFromPathname, sealSession, sessionCookieOptions, splitCmssyLocale, verifyCmssyWebhook };
|
|
1500
|
+
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, CmssyWebhookError, SESSION_MAX_AGE_SECONDS, applyCmssyCsp, assertAuthConfig, cmssyCspHeaders, createCmssyAuthMiddleware, createCmssyAuthRoute, createCmssyCartRoute, createCmssyLocaleMiddleware, createCmssyNotFound, createCmssyOrdersRoute, createCmssyPage, createCmssyRobots, createCmssySitemap, createDraftRoute, fetchProduct, fetchProducts, getCmssyAccessToken, getCmssyLocale, getCmssyUser, isAccessExpired, isCmssyEditMode, isCmssyEditRequest, localeForPathname, openSession, resolveLocaleFromPathname, sealSession, sessionCookieOptions, splitCmssyLocale, verifyCmssyWebhook };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmssy/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Next.js App Router bindings for cmssy headless sites (createCmssyPage + draft preview)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cmssy",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"dist"
|
|
42
42
|
],
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@cmssy/react": "^0.
|
|
44
|
+
"@cmssy/react": "^0.5.0",
|
|
45
45
|
"next": ">=15",
|
|
46
46
|
"react": "^18.2.0 || ^19.0.0",
|
|
47
47
|
"react-dom": "^18.2.0 || ^19.0.0"
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"tsup": "^8.3.0",
|
|
55
55
|
"typescript": "^5.6.0",
|
|
56
56
|
"vitest": "^2.1.0",
|
|
57
|
-
"@cmssy/react": "0.
|
|
57
|
+
"@cmssy/react": "0.5.0"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"jose": "^6.2.3"
|