@cmssy/next 0.5.3 → 0.5.4
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 +79 -7
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +80 -9
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -288,14 +288,24 @@ function createCmssyRobots(config, options = {}) {
|
|
|
288
288
|
};
|
|
289
289
|
};
|
|
290
290
|
}
|
|
291
|
+
|
|
292
|
+
// src/seo-paths.ts
|
|
293
|
+
function resolveSeoLocales(config, siteConfig) {
|
|
294
|
+
const defaultLocale = config.defaultLocale ?? siteConfig?.defaultLanguage ?? "en";
|
|
295
|
+
const locales = config.enabledLocales && config.enabledLocales.length > 0 ? config.enabledLocales : siteConfig?.enabledLanguages && siteConfig.enabledLanguages.length > 0 ? siteConfig.enabledLanguages : [defaultLocale];
|
|
296
|
+
return { defaultLocale, locales };
|
|
297
|
+
}
|
|
291
298
|
function normalizeSlug(slug) {
|
|
292
299
|
if (slug === "/" || slug === "") return "/";
|
|
293
300
|
return slug.startsWith("/") ? slug : `/${slug}`;
|
|
294
301
|
}
|
|
295
302
|
function localizedPath(slug, locale, defaultLocale) {
|
|
296
|
-
const normalized = slug
|
|
297
|
-
|
|
303
|
+
const normalized = normalizeSlug(slug);
|
|
304
|
+
const base = normalized === "/" ? "" : normalized;
|
|
305
|
+
return locale === defaultLocale ? base || "/" : `/${locale}${base}`;
|
|
298
306
|
}
|
|
307
|
+
|
|
308
|
+
// src/create-cmssy-sitemap.ts
|
|
299
309
|
function createCmssySitemap(config, options = {}) {
|
|
300
310
|
const clientConfig = {
|
|
301
311
|
apiUrl: config.apiUrl,
|
|
@@ -311,15 +321,15 @@ function createCmssySitemap(config, options = {}) {
|
|
|
311
321
|
}
|
|
312
322
|
pages = [];
|
|
313
323
|
}
|
|
314
|
-
let
|
|
324
|
+
let siteConfig = null;
|
|
315
325
|
try {
|
|
316
|
-
|
|
326
|
+
siteConfig = await react.fetchSiteConfig(clientConfig);
|
|
317
327
|
} catch {
|
|
318
|
-
|
|
328
|
+
siteConfig = null;
|
|
319
329
|
}
|
|
330
|
+
const notFoundPageId = siteConfig?.notFoundPageId ?? null;
|
|
320
331
|
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
321
|
-
const defaultLocale = config
|
|
322
|
-
const locales = config.enabledLocales && config.enabledLocales.length > 0 ? config.enabledLocales : [defaultLocale];
|
|
332
|
+
const { defaultLocale, locales } = resolveSeoLocales(config, siteConfig);
|
|
323
333
|
const excluded = new Set((options.excludeSlugs ?? []).map(normalizeSlug));
|
|
324
334
|
const entries = pages.map((page) => ({ ...page, slug: normalizeSlug(page.slug) })).filter((page) => page.id !== notFoundPageId && !excluded.has(page.slug)).map((page) => {
|
|
325
335
|
const lastModified = page.updatedAt ?? page.publishedAt ?? void 0;
|
|
@@ -342,6 +352,67 @@ function createCmssySitemap(config, options = {}) {
|
|
|
342
352
|
return options.extra ? [...entries, ...options.extra] : entries;
|
|
343
353
|
};
|
|
344
354
|
}
|
|
355
|
+
function pick(value, locale, defaultLocale) {
|
|
356
|
+
if (!value) return "";
|
|
357
|
+
if (typeof value === "string") return value;
|
|
358
|
+
return value[locale] || value[defaultLocale] || Object.values(value)[0] || "";
|
|
359
|
+
}
|
|
360
|
+
async function buildCmssyMetadata(config, path, options = {}) {
|
|
361
|
+
const clientConfig = {
|
|
362
|
+
apiUrl: config.apiUrl,
|
|
363
|
+
workspaceSlug: config.workspaceSlug
|
|
364
|
+
};
|
|
365
|
+
const [meta, siteConfig, baseUrl] = await Promise.all([
|
|
366
|
+
react.fetchPageMeta(clientConfig, path).catch(() => null),
|
|
367
|
+
react.fetchSiteConfig(clientConfig).catch(() => null),
|
|
368
|
+
resolveSeoBaseUrl(config, options.baseUrl)
|
|
369
|
+
]);
|
|
370
|
+
const { defaultLocale, locales: enabledLocales } = resolveSeoLocales(
|
|
371
|
+
config,
|
|
372
|
+
siteConfig
|
|
373
|
+
);
|
|
374
|
+
const locale = await config.resolveLocale?.() ?? defaultLocale;
|
|
375
|
+
const slug = react.normalizeSlug(path);
|
|
376
|
+
const siteName = pick(siteConfig?.siteName, locale, defaultLocale) || siteConfig?.branding?.brandName || void 0;
|
|
377
|
+
const title = pick(meta?.seoTitle, locale, defaultLocale) || pick(meta?.displayName, locale, defaultLocale) || siteName || "";
|
|
378
|
+
const description = pick(meta?.seoDescription, locale, defaultLocale);
|
|
379
|
+
const keywords = meta?.seoKeywords?.length ? meta.seoKeywords : void 0;
|
|
380
|
+
const image = options.image ?? siteConfig?.branding?.ogImageUrl ?? void 0;
|
|
381
|
+
const canonical = baseUrl ? `${baseUrl}${localizedPath(slug, locale, defaultLocale)}` : void 0;
|
|
382
|
+
const languages = baseUrl && enabledLocales.length > 1 ? Object.fromEntries(
|
|
383
|
+
enabledLocales.map((l) => [
|
|
384
|
+
l,
|
|
385
|
+
`${baseUrl}${localizedPath(slug, l, defaultLocale)}`
|
|
386
|
+
])
|
|
387
|
+
) : void 0;
|
|
388
|
+
return {
|
|
389
|
+
...baseUrl ? { metadataBase: new URL(baseUrl) } : {},
|
|
390
|
+
...title ? { title } : {},
|
|
391
|
+
...description ? { description } : {},
|
|
392
|
+
...keywords ? { keywords } : {},
|
|
393
|
+
...canonical || languages ? {
|
|
394
|
+
alternates: {
|
|
395
|
+
...canonical ? { canonical } : {},
|
|
396
|
+
...languages ? { languages } : {}
|
|
397
|
+
}
|
|
398
|
+
} : {},
|
|
399
|
+
openGraph: {
|
|
400
|
+
...title ? { title } : {},
|
|
401
|
+
...description ? { description } : {},
|
|
402
|
+
...canonical ? { url: canonical } : {},
|
|
403
|
+
...siteName ? { siteName } : {},
|
|
404
|
+
type: options.ogType ?? "website",
|
|
405
|
+
locale,
|
|
406
|
+
...image ? { images: [{ url: image }] } : {}
|
|
407
|
+
},
|
|
408
|
+
twitter: {
|
|
409
|
+
card: image ? options.twitterCard ?? "summary_large_image" : "summary",
|
|
410
|
+
...title ? { title } : {},
|
|
411
|
+
...description ? { description } : {},
|
|
412
|
+
...image ? { images: [image] } : {}
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
345
416
|
var MIN_SECRET_LENGTH = 16;
|
|
346
417
|
function secretsMatch(a, b) {
|
|
347
418
|
const ha = crypto$1.createHash("sha256").update(a).digest();
|
|
@@ -1518,6 +1589,7 @@ exports.CmssyWebhookError = CmssyWebhookError;
|
|
|
1518
1589
|
exports.SESSION_MAX_AGE_SECONDS = SESSION_MAX_AGE_SECONDS;
|
|
1519
1590
|
exports.applyCmssyCsp = applyCmssyCsp;
|
|
1520
1591
|
exports.assertAuthConfig = assertAuthConfig;
|
|
1592
|
+
exports.buildCmssyMetadata = buildCmssyMetadata;
|
|
1521
1593
|
exports.cmssyCspHeaders = cmssyCspHeaders;
|
|
1522
1594
|
exports.createCmssyAuthMiddleware = createCmssyAuthMiddleware;
|
|
1523
1595
|
exports.createCmssyAuthRoute = createCmssyAuthRoute;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +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
|
+
import { MetadataRoute, Metadata } from 'next';
|
|
6
6
|
import { NextRequest, NextResponse } from 'next/server';
|
|
7
7
|
|
|
8
8
|
interface CmssyAuthConfig {
|
|
@@ -114,6 +114,27 @@ interface CreateCmssySitemapOptions extends SeoBaseUrlOption {
|
|
|
114
114
|
*/
|
|
115
115
|
declare function createCmssySitemap(config: CmssyNextConfig, options?: CreateCmssySitemapOptions): () => Promise<MetadataRoute.Sitemap>;
|
|
116
116
|
|
|
117
|
+
interface BuildCmssyMetadataOptions extends SeoBaseUrlOption {
|
|
118
|
+
/** Override the Open Graph / Twitter image (defaults to workspace branding). */
|
|
119
|
+
image?: string;
|
|
120
|
+
/** Open Graph type. Defaults to "website". */
|
|
121
|
+
ogType?: string;
|
|
122
|
+
/** Twitter card. Defaults to "summary_large_image" when an image exists. */
|
|
123
|
+
twitterCard?: "summary" | "summary_large_image";
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Builds complete Next.js `Metadata` for a cmssy page from its SEO fields and
|
|
127
|
+
* the workspace branding: title/description/keywords, canonical + per-locale
|
|
128
|
+
* `hreflang` alternates, and Open Graph / Twitter cards (with the branding OG
|
|
129
|
+
* image). Use in a route's `generateMetadata`:
|
|
130
|
+
*
|
|
131
|
+
* export const generateMetadata = ({ params }) =>
|
|
132
|
+
* buildCmssyMetadata(cmssy, (await params).path);
|
|
133
|
+
*
|
|
134
|
+
* `path` is the catch-all segments with the locale prefix already stripped.
|
|
135
|
+
*/
|
|
136
|
+
declare function buildCmssyMetadata(config: CmssyNextConfig, path?: string | string[], options?: BuildCmssyMetadataOptions): Promise<Metadata>;
|
|
137
|
+
|
|
117
138
|
type CmssyDraftRouteConfig = Pick<CmssyNextConfig, "draftSecret"> & {
|
|
118
139
|
defaultRedirect?: string;
|
|
119
140
|
};
|
|
@@ -307,4 +328,4 @@ declare class CmssyWebhookError extends Error {
|
|
|
307
328
|
*/
|
|
308
329
|
declare function verifyCmssyWebhook(options: VerifyCmssyWebhookOptions): CmssyWebhookEvent;
|
|
309
330
|
|
|
310
|
-
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 };
|
|
331
|
+
export { type BuildCmssyMetadataOptions, 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, buildCmssyMetadata, 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,7 +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
|
+
import { MetadataRoute, Metadata } from 'next';
|
|
6
6
|
import { NextRequest, NextResponse } from 'next/server';
|
|
7
7
|
|
|
8
8
|
interface CmssyAuthConfig {
|
|
@@ -114,6 +114,27 @@ interface CreateCmssySitemapOptions extends SeoBaseUrlOption {
|
|
|
114
114
|
*/
|
|
115
115
|
declare function createCmssySitemap(config: CmssyNextConfig, options?: CreateCmssySitemapOptions): () => Promise<MetadataRoute.Sitemap>;
|
|
116
116
|
|
|
117
|
+
interface BuildCmssyMetadataOptions extends SeoBaseUrlOption {
|
|
118
|
+
/** Override the Open Graph / Twitter image (defaults to workspace branding). */
|
|
119
|
+
image?: string;
|
|
120
|
+
/** Open Graph type. Defaults to "website". */
|
|
121
|
+
ogType?: string;
|
|
122
|
+
/** Twitter card. Defaults to "summary_large_image" when an image exists. */
|
|
123
|
+
twitterCard?: "summary" | "summary_large_image";
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Builds complete Next.js `Metadata` for a cmssy page from its SEO fields and
|
|
127
|
+
* the workspace branding: title/description/keywords, canonical + per-locale
|
|
128
|
+
* `hreflang` alternates, and Open Graph / Twitter cards (with the branding OG
|
|
129
|
+
* image). Use in a route's `generateMetadata`:
|
|
130
|
+
*
|
|
131
|
+
* export const generateMetadata = ({ params }) =>
|
|
132
|
+
* buildCmssyMetadata(cmssy, (await params).path);
|
|
133
|
+
*
|
|
134
|
+
* `path` is the catch-all segments with the locale prefix already stripped.
|
|
135
|
+
*/
|
|
136
|
+
declare function buildCmssyMetadata(config: CmssyNextConfig, path?: string | string[], options?: BuildCmssyMetadataOptions): Promise<Metadata>;
|
|
137
|
+
|
|
117
138
|
type CmssyDraftRouteConfig = Pick<CmssyNextConfig, "draftSecret"> & {
|
|
118
139
|
defaultRedirect?: string;
|
|
119
140
|
};
|
|
@@ -307,4 +328,4 @@ declare class CmssyWebhookError extends Error {
|
|
|
307
328
|
*/
|
|
308
329
|
declare function verifyCmssyWebhook(options: VerifyCmssyWebhookOptions): CmssyWebhookEvent;
|
|
309
330
|
|
|
310
|
-
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 };
|
|
331
|
+
export { type BuildCmssyMetadataOptions, 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, buildCmssyMetadata, 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, fetchPages, resolveWorkspaceId, graphqlRequest } from '@cmssy/react';
|
|
3
|
+
import { resolveSiteLocales, splitLocaleFromPath, fetchPage, resolveForms, CmssyServerPage, fetchSiteConfig, fetchPageById, fetchPages, fetchPageMeta, normalizeSlug as normalizeSlug$1, 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';
|
|
@@ -286,14 +286,24 @@ function createCmssyRobots(config, options = {}) {
|
|
|
286
286
|
};
|
|
287
287
|
};
|
|
288
288
|
}
|
|
289
|
+
|
|
290
|
+
// src/seo-paths.ts
|
|
291
|
+
function resolveSeoLocales(config, siteConfig) {
|
|
292
|
+
const defaultLocale = config.defaultLocale ?? siteConfig?.defaultLanguage ?? "en";
|
|
293
|
+
const locales = config.enabledLocales && config.enabledLocales.length > 0 ? config.enabledLocales : siteConfig?.enabledLanguages && siteConfig.enabledLanguages.length > 0 ? siteConfig.enabledLanguages : [defaultLocale];
|
|
294
|
+
return { defaultLocale, locales };
|
|
295
|
+
}
|
|
289
296
|
function normalizeSlug(slug) {
|
|
290
297
|
if (slug === "/" || slug === "") return "/";
|
|
291
298
|
return slug.startsWith("/") ? slug : `/${slug}`;
|
|
292
299
|
}
|
|
293
300
|
function localizedPath(slug, locale, defaultLocale) {
|
|
294
|
-
const normalized = slug
|
|
295
|
-
|
|
301
|
+
const normalized = normalizeSlug(slug);
|
|
302
|
+
const base = normalized === "/" ? "" : normalized;
|
|
303
|
+
return locale === defaultLocale ? base || "/" : `/${locale}${base}`;
|
|
296
304
|
}
|
|
305
|
+
|
|
306
|
+
// src/create-cmssy-sitemap.ts
|
|
297
307
|
function createCmssySitemap(config, options = {}) {
|
|
298
308
|
const clientConfig = {
|
|
299
309
|
apiUrl: config.apiUrl,
|
|
@@ -309,15 +319,15 @@ function createCmssySitemap(config, options = {}) {
|
|
|
309
319
|
}
|
|
310
320
|
pages = [];
|
|
311
321
|
}
|
|
312
|
-
let
|
|
322
|
+
let siteConfig = null;
|
|
313
323
|
try {
|
|
314
|
-
|
|
324
|
+
siteConfig = await fetchSiteConfig(clientConfig);
|
|
315
325
|
} catch {
|
|
316
|
-
|
|
326
|
+
siteConfig = null;
|
|
317
327
|
}
|
|
328
|
+
const notFoundPageId = siteConfig?.notFoundPageId ?? null;
|
|
318
329
|
const baseUrl = await resolveSeoBaseUrl(config, options.baseUrl);
|
|
319
|
-
const defaultLocale = config
|
|
320
|
-
const locales = config.enabledLocales && config.enabledLocales.length > 0 ? config.enabledLocales : [defaultLocale];
|
|
330
|
+
const { defaultLocale, locales } = resolveSeoLocales(config, siteConfig);
|
|
321
331
|
const excluded = new Set((options.excludeSlugs ?? []).map(normalizeSlug));
|
|
322
332
|
const entries = pages.map((page) => ({ ...page, slug: normalizeSlug(page.slug) })).filter((page) => page.id !== notFoundPageId && !excluded.has(page.slug)).map((page) => {
|
|
323
333
|
const lastModified = page.updatedAt ?? page.publishedAt ?? void 0;
|
|
@@ -340,6 +350,67 @@ function createCmssySitemap(config, options = {}) {
|
|
|
340
350
|
return options.extra ? [...entries, ...options.extra] : entries;
|
|
341
351
|
};
|
|
342
352
|
}
|
|
353
|
+
function pick(value, locale, defaultLocale) {
|
|
354
|
+
if (!value) return "";
|
|
355
|
+
if (typeof value === "string") return value;
|
|
356
|
+
return value[locale] || value[defaultLocale] || Object.values(value)[0] || "";
|
|
357
|
+
}
|
|
358
|
+
async function buildCmssyMetadata(config, path, options = {}) {
|
|
359
|
+
const clientConfig = {
|
|
360
|
+
apiUrl: config.apiUrl,
|
|
361
|
+
workspaceSlug: config.workspaceSlug
|
|
362
|
+
};
|
|
363
|
+
const [meta, siteConfig, baseUrl] = await Promise.all([
|
|
364
|
+
fetchPageMeta(clientConfig, path).catch(() => null),
|
|
365
|
+
fetchSiteConfig(clientConfig).catch(() => null),
|
|
366
|
+
resolveSeoBaseUrl(config, options.baseUrl)
|
|
367
|
+
]);
|
|
368
|
+
const { defaultLocale, locales: enabledLocales } = resolveSeoLocales(
|
|
369
|
+
config,
|
|
370
|
+
siteConfig
|
|
371
|
+
);
|
|
372
|
+
const locale = await config.resolveLocale?.() ?? defaultLocale;
|
|
373
|
+
const slug = normalizeSlug$1(path);
|
|
374
|
+
const siteName = pick(siteConfig?.siteName, locale, defaultLocale) || siteConfig?.branding?.brandName || void 0;
|
|
375
|
+
const title = pick(meta?.seoTitle, locale, defaultLocale) || pick(meta?.displayName, locale, defaultLocale) || siteName || "";
|
|
376
|
+
const description = pick(meta?.seoDescription, locale, defaultLocale);
|
|
377
|
+
const keywords = meta?.seoKeywords?.length ? meta.seoKeywords : void 0;
|
|
378
|
+
const image = options.image ?? siteConfig?.branding?.ogImageUrl ?? void 0;
|
|
379
|
+
const canonical = baseUrl ? `${baseUrl}${localizedPath(slug, locale, defaultLocale)}` : void 0;
|
|
380
|
+
const languages = baseUrl && enabledLocales.length > 1 ? Object.fromEntries(
|
|
381
|
+
enabledLocales.map((l) => [
|
|
382
|
+
l,
|
|
383
|
+
`${baseUrl}${localizedPath(slug, l, defaultLocale)}`
|
|
384
|
+
])
|
|
385
|
+
) : void 0;
|
|
386
|
+
return {
|
|
387
|
+
...baseUrl ? { metadataBase: new URL(baseUrl) } : {},
|
|
388
|
+
...title ? { title } : {},
|
|
389
|
+
...description ? { description } : {},
|
|
390
|
+
...keywords ? { keywords } : {},
|
|
391
|
+
...canonical || languages ? {
|
|
392
|
+
alternates: {
|
|
393
|
+
...canonical ? { canonical } : {},
|
|
394
|
+
...languages ? { languages } : {}
|
|
395
|
+
}
|
|
396
|
+
} : {},
|
|
397
|
+
openGraph: {
|
|
398
|
+
...title ? { title } : {},
|
|
399
|
+
...description ? { description } : {},
|
|
400
|
+
...canonical ? { url: canonical } : {},
|
|
401
|
+
...siteName ? { siteName } : {},
|
|
402
|
+
type: options.ogType ?? "website",
|
|
403
|
+
locale,
|
|
404
|
+
...image ? { images: [{ url: image }] } : {}
|
|
405
|
+
},
|
|
406
|
+
twitter: {
|
|
407
|
+
card: image ? options.twitterCard ?? "summary_large_image" : "summary",
|
|
408
|
+
...title ? { title } : {},
|
|
409
|
+
...description ? { description } : {},
|
|
410
|
+
...image ? { images: [image] } : {}
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
343
414
|
var MIN_SECRET_LENGTH = 16;
|
|
344
415
|
function secretsMatch(a, b) {
|
|
345
416
|
const ha = createHash("sha256").update(a).digest();
|
|
@@ -1508,4 +1579,4 @@ function verifyCmssyWebhook(options) {
|
|
|
1508
1579
|
return parsed;
|
|
1509
1580
|
}
|
|
1510
1581
|
|
|
1511
|
-
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 };
|
|
1582
|
+
export { CMSSY_CART_COOKIE, CMSSY_EDIT_HEADER, CMSSY_LOCALE_HEADER, CMSSY_SESSION_COOKIE, CmssyWebhookError, SESSION_MAX_AGE_SECONDS, applyCmssyCsp, assertAuthConfig, buildCmssyMetadata, 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.5.
|
|
3
|
+
"version": "0.5.4",
|
|
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.5.
|
|
44
|
+
"@cmssy/react": "^0.5.4",
|
|
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.5.
|
|
57
|
+
"@cmssy/react": "0.5.4"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"jose": "^6.2.3"
|