@elytracms/next 0.0.79 → 0.0.81

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.d.ts CHANGED
@@ -376,6 +376,52 @@ declare function createStaticContentSource(data: StaticContentData): ContentSnap
376
376
  */
377
377
  declare function createContentSnapshot(adapter: PersistenceAdapter, projectId: string, options?: ContentSnapshotOptions): Promise<ContentSnapshot>;
378
378
 
379
+ /**
380
+ * The locale ⇄ URL mapping, owned in ONE place (EC-486).
381
+ *
382
+ * The delivery host reads a request URL and derives `{ locale, path }`; the
383
+ * sitemap goes the other way, turning an enumerated `{ locale, path }` back
384
+ * into the URL a crawler will request. Those are inverse functions, and while
385
+ * they lived in two files they disagreed: a page whose top-level slug happens
386
+ * to equal a **non-default locale code** (`/de` in a project whose locales are
387
+ * `['en','de']`, default `en`) was published to `sitemap.xml` as
388
+ * `https://site/de`, which the host then split as *locale `de`, path `/`* and
389
+ * 404'd. Measured — see EC-486.
390
+ *
391
+ * Keeping both directions here makes the round-trip checkable, which is what
392
+ * {@link localeUrlPath} reports: some `{ locale, path }` pairs simply have **no
393
+ * URL that addresses them**, and a caller that publishes URLs must be able to
394
+ * tell rather than emit a link nothing serves.
395
+ */
396
+ /**
397
+ * Derive the request locale from a leading URL segment (`/de/about` → locale
398
+ * `de`, path `/about`) and return the remaining path. No prefix (or the
399
+ * default locale's own content at root) falls back to the default locale.
400
+ */
401
+ declare function splitLocalePath(url: string, locales: LocaleConfig): {
402
+ locale: Locale;
403
+ path: string;
404
+ };
405
+ interface LocaleUrlPath {
406
+ /** The request path a client uses to reach `path` in `locale`. */
407
+ urlPath: string;
408
+ /**
409
+ * Whether {@link splitLocalePath} recovers exactly the `{ locale, path }`
410
+ * this was built from. `false` means the pair is **unaddressable**: every URL
411
+ * that could denote it is read by the host as a different locale/path pair,
412
+ * so the content is unreachable and the URL must not be published.
413
+ */
414
+ addressable: boolean;
415
+ }
416
+ /**
417
+ * The inverse of {@link splitLocalePath}: default locale serves the root,
418
+ * other locales get a `/<locale>` prefix — then the result is round-tripped
419
+ * back through `splitLocalePath` so an unaddressable pair is reported rather
420
+ * than silently emitted (AGENTS.md §4: never a fallback that hides a broken
421
+ * state).
422
+ */
423
+ declare function localeUrlPath(path: string, locale: Locale, locales: LocaleConfig): LocaleUrlPath;
424
+
379
425
  /**
380
426
  * The pure half of the catch-all route helper (EC-144): URL → outcome, with
381
427
  * no Next.js imports — so redirects, 404s, locale handling, payload assembly,
@@ -458,15 +504,7 @@ type CanvasPageOutcome = {
458
504
  };
459
505
  /** Build the request path from a Next catch-all `slug` param. */
460
506
  declare function pathFromSlug(slug: readonly string[] | undefined): string;
461
- /**
462
- * Derive the request locale from a leading URL segment (`/de/about` → locale
463
- * `de`, path `/about`) and return the remaining path. No prefix (or the
464
- * default locale's own content at root) falls back to the default locale.
465
- */
466
- declare function splitLocalePath(url: string, locales: LocaleConfig): {
467
- locale: Locale;
468
- path: string;
469
- };
507
+
470
508
  interface ResolveCanvasPageOptions {
471
509
  payloads?: CanvasPayloadsFactory;
472
510
  /**
@@ -601,6 +639,16 @@ declare function canvasPageMetadata(result: ResolvePageResult, assets?: readonly
601
639
  * documents (composing each page's nested path from its parent chain) — no
602
640
  * params provider entry needed.
603
641
  *
642
+ * **Enumeration is a candidate list, not the output (EC-486).** Every branch
643
+ * above — static, provider-fed, and mount — only proposes paths; each one is
644
+ * then put back through `resolvePage`, and a path the resolver refuses is
645
+ * dropped. So the sitemap cannot claim a URL the delivery host would 404, even
646
+ * though the mount branch enumerates its collection independently of route
647
+ * precedence. Do not read the enumeration in isolation: the gate below it is
648
+ * what makes the two agree. What a mount enumerated and the resolver then
649
+ * refused is reported in {@link CanvasSitemapResult.skipped}, never dropped in
650
+ * silence.
651
+ *
604
652
  * Host usage (`app/sitemap.ts`):
605
653
  *
606
654
  * ```ts
@@ -1541,4 +1589,4 @@ declare function evaluatePreviewRequest(requestUrl: string | URL, expectedToken:
1541
1589
  */
1542
1590
  declare const PACKAGE = "@elytracms/next";
1543
1591
 
1544
- export { type AssetImageLoaderOptions, type BindingPayloads, type CacheWrapper, type CacheWrapperOptions, type CachedEntry, type CanvasCacheOptions, type CanvasContentRequest, type CanvasDataSource, type CanvasPageOutcome, type CanvasPayloadContext, type CanvasPayloadsFactory, CanvasRenderer, type CanvasRendererProps, type CanvasRequestInfo, type CanvasRoute, type CanvasRouteOptions, type CanvasRouteProps, type CanvasSitemapOptions, type CanvasSitemapResult, type ContentSnapshot, type ContentSnapshotOptions, type ContentSource, type CreateCanvasSitemapOptions, type DefineHostComponentsOptions, ELYTRA_HOST_ENV_KEYS, type ElytraHost, type ElytraHostEnv, type ElytraHostImageOptions, type ElytraHostOptions, ElytraImage, type ElytraImageAsset, type ElytraImageProps, type GlobalsConventions, type HostCanvasRouteOptions, type HostComponent, type HostComponents, type LiveContentOptions, type LoadGlobalsOptions, type MaterializeSourcePayloadsInput, type MaterializedSourcePayloads, type NextImagePrimitiveOptions, PACKAGE, type PreviewEvaluation, type PreviewRouteHandlers, type PreviewRouteOptions, REVALIDATE_SIGNATURE_HEADER, type ResolveCanvasPageOptions, type ResolveGlobalsOptions, type ResolvedLink, type ResolvedNavEntry, type ResolvedNavLink, type RevalidateEvaluation, type RevalidatePayload, type RevalidateRouteHandlers, type RevalidateRouteOptions, type SiteGlobals, type SitemapParamsProvider, type SitemapRouteContext, type SitemapSkippedRoute, type SourcePayloadError, type StaticContentData, assembleLiveSource, canvasPageMetadata, canvasSitemapEntries, collectBindingSourceIds, collectionCacheTag, createAssetImageLoader, createBindingResolver, createCanvasRoute, createCanvasSitemap, createContentSnapshot, createElytraHost, createPreviewDisableRoute, createPreviewRoute, createRevalidateRoute, createStaticContentSource, defaultBindingPayloads, defineHostComponents, docCacheTag, elytraHostImage, evaluatePreviewRequest, evaluateRevalidateRequest, firstBlockFullBleed, isSourcePayloadError, loadCachedEntry, loadLiveContent, materializeSourcePayloads, mergeCacheTags, nextCacheTags, nextImagePrimitive, pathFromSlug, projectSweepTag, resolveCanvasPage, resolveGlobals, resolveHostEnv, resolvePayloadToken, revalidatePayloadSchema, routeCacheTag, safeRedirectTarget, scopeCacheTag, signRevalidateBody, sourcePayloadError, splitLocalePath };
1592
+ export { type AssetImageLoaderOptions, type BindingPayloads, type CacheWrapper, type CacheWrapperOptions, type CachedEntry, type CanvasCacheOptions, type CanvasContentRequest, type CanvasDataSource, type CanvasPageOutcome, type CanvasPayloadContext, type CanvasPayloadsFactory, CanvasRenderer, type CanvasRendererProps, type CanvasRequestInfo, type CanvasRoute, type CanvasRouteOptions, type CanvasRouteProps, type CanvasSitemapOptions, type CanvasSitemapResult, type ContentSnapshot, type ContentSnapshotOptions, type ContentSource, type CreateCanvasSitemapOptions, type DefineHostComponentsOptions, ELYTRA_HOST_ENV_KEYS, type ElytraHost, type ElytraHostEnv, type ElytraHostImageOptions, type ElytraHostOptions, ElytraImage, type ElytraImageAsset, type ElytraImageProps, type GlobalsConventions, type HostCanvasRouteOptions, type HostComponent, type HostComponents, type LiveContentOptions, type LoadGlobalsOptions, type LocaleUrlPath, type MaterializeSourcePayloadsInput, type MaterializedSourcePayloads, type NextImagePrimitiveOptions, PACKAGE, type PreviewEvaluation, type PreviewRouteHandlers, type PreviewRouteOptions, REVALIDATE_SIGNATURE_HEADER, type ResolveCanvasPageOptions, type ResolveGlobalsOptions, type ResolvedLink, type ResolvedNavEntry, type ResolvedNavLink, type RevalidateEvaluation, type RevalidatePayload, type RevalidateRouteHandlers, type RevalidateRouteOptions, type SiteGlobals, type SitemapParamsProvider, type SitemapRouteContext, type SitemapSkippedRoute, type SourcePayloadError, type StaticContentData, assembleLiveSource, canvasPageMetadata, canvasSitemapEntries, collectBindingSourceIds, collectionCacheTag, createAssetImageLoader, createBindingResolver, createCanvasRoute, createCanvasSitemap, createContentSnapshot, createElytraHost, createPreviewDisableRoute, createPreviewRoute, createRevalidateRoute, createStaticContentSource, defaultBindingPayloads, defineHostComponents, docCacheTag, elytraHostImage, evaluatePreviewRequest, evaluateRevalidateRequest, firstBlockFullBleed, isSourcePayloadError, loadCachedEntry, loadLiveContent, localeUrlPath, materializeSourcePayloads, mergeCacheTags, nextCacheTags, nextImagePrimitive, pathFromSlug, projectSweepTag, resolveCanvasPage, resolveGlobals, resolveHostEnv, resolvePayloadToken, revalidatePayloadSchema, routeCacheTag, safeRedirectTarget, scopeCacheTag, signRevalidateBody, sourcePayloadError, splitLocalePath };
package/dist/index.js CHANGED
@@ -307,9 +307,6 @@ async function createContentSnapshot(adapter, projectId, options = {}) {
307
307
  assetUrl: (asset) => adapter.blobs.url(asset.storageKey)
308
308
  });
309
309
  }
310
- function pathFromSlug(slug) {
311
- return "/" + (slug ?? []).join("/");
312
- }
313
310
  function splitLocalePath(url, locales) {
314
311
  const segments = splitPath(url);
315
312
  const first = segments[0];
@@ -318,6 +315,14 @@ function splitLocalePath(url, locales) {
318
315
  }
319
316
  return { locale: locales.default, path: "/" + segments.join("/") };
320
317
  }
318
+ function localeUrlPath(path, locale, locales) {
319
+ const urlPath = locale === locales.default ? path : path === "/" ? `/${locale}` : `/${locale}${path}`;
320
+ const round = splitLocalePath(urlPath, locales);
321
+ return { urlPath, addressable: round.locale === locale && round.path === path };
322
+ }
323
+ function pathFromSlug(slug) {
324
+ return "/" + (slug ?? []).join("/");
325
+ }
321
326
  function scopeAssetsToPage(allAssets, registry, result, resolveRelation) {
322
327
  if (allAssets.length === 0) return allAssets;
323
328
  const ids = /* @__PURE__ */ new Set();
@@ -653,10 +658,8 @@ function fillPattern(pattern, params) {
653
658
  }
654
659
  return "/" + segments.join("/");
655
660
  }
656
- function absoluteUrl(baseUrl, locale, defaultLocale, path) {
657
- const origin = baseUrl.replace(/\/+$/, "");
658
- if (locale === defaultLocale) return origin + path;
659
- return origin + (path === "/" ? `/${locale}` : `/${locale}${path}`);
661
+ function originOf(baseUrl) {
662
+ return baseUrl.replace(/\/+$/, "");
660
663
  }
661
664
  function canvasSitemapEntries(source, options) {
662
665
  const routes = options.routes ?? source.routes ?? [];
@@ -721,14 +724,32 @@ function canvasSitemapEntries(source, options) {
721
724
  paths.push(path);
722
725
  }
723
726
  }
727
+ let unresolved = 0;
724
728
  for (const path of paths) {
725
729
  const result = client.resolvePage(path, locale);
726
- if (result.status !== "ok") continue;
730
+ if (result.status !== "ok") {
731
+ if (result.status !== "redirect") unresolved += 1;
732
+ continue;
733
+ }
727
734
  if (result.document?.["seoNoindex"] === true) continue;
735
+ const { urlPath, addressable } = localeUrlPath(path, locale, locales);
736
+ if (!addressable) {
737
+ skip(
738
+ route,
739
+ `"${path}" (locale "${locale}") has no addressable URL \u2014 its first segment is read as a locale prefix`
740
+ );
741
+ continue;
742
+ }
728
743
  const perLocale = byPath.get(path) ?? /* @__PURE__ */ new Map();
729
- perLocale.set(locale, absoluteUrl(options.baseUrl, locale, locales.default, path));
744
+ perLocale.set(locale, originOf(options.baseUrl) + urlPath);
730
745
  byPath.set(path, perLocale);
731
746
  }
747
+ if (mount && paths.length > 0 && unresolved === paths.length) {
748
+ skip(
749
+ route,
750
+ `hierarchy mount over "${mount.collection}" composed ${paths.length} path(s) in locale "${locale}", none of which the resolver serves`
751
+ );
752
+ }
732
753
  }
733
754
  }
734
755
  const entries = [];
@@ -1299,6 +1320,6 @@ function createElytraHost(options) {
1299
1320
  }
1300
1321
  var PACKAGE = "@elytracms/next";
1301
1322
 
1302
- export { CanvasRenderer, ELYTRA_HOST_ENV_KEYS, ElytraImage, PACKAGE, REVALIDATE_SIGNATURE_HEADER, assembleLiveSource, canvasPageMetadata, canvasSitemapEntries, collectBindingSourceIds, collectionCacheTag, createAssetImageLoader, createBindingResolver, createCanvasRoute, createCanvasSitemap, createContentSnapshot, createElytraHost, createPreviewDisableRoute, createPreviewRoute, createRevalidateRoute, createStaticContentSource, defaultBindingPayloads, defineHostComponents, docCacheTag, elytraHostImage, evaluatePreviewRequest, evaluateRevalidateRequest, firstBlockFullBleed, isSourcePayloadError, loadCachedEntry, loadLiveContent, materializeSourcePayloads, mergeCacheTags, nextCacheTags, nextImagePrimitive, pathFromSlug, projectSweepTag, resolveCanvasPage, resolveGlobals, resolveHostEnv, resolvePayloadToken, revalidatePayloadSchema, routeCacheTag, safeRedirectTarget, scopeCacheTag, signRevalidateBody, sourcePayloadError, splitLocalePath };
1323
+ export { CanvasRenderer, ELYTRA_HOST_ENV_KEYS, ElytraImage, PACKAGE, REVALIDATE_SIGNATURE_HEADER, assembleLiveSource, canvasPageMetadata, canvasSitemapEntries, collectBindingSourceIds, collectionCacheTag, createAssetImageLoader, createBindingResolver, createCanvasRoute, createCanvasSitemap, createContentSnapshot, createElytraHost, createPreviewDisableRoute, createPreviewRoute, createRevalidateRoute, createStaticContentSource, defaultBindingPayloads, defineHostComponents, docCacheTag, elytraHostImage, evaluatePreviewRequest, evaluateRevalidateRequest, firstBlockFullBleed, isSourcePayloadError, loadCachedEntry, loadLiveContent, localeUrlPath, materializeSourcePayloads, mergeCacheTags, nextCacheTags, nextImagePrimitive, pathFromSlug, projectSweepTag, resolveCanvasPage, resolveGlobals, resolveHostEnv, resolvePayloadToken, revalidatePayloadSchema, routeCacheTag, safeRedirectTarget, scopeCacheTag, signRevalidateBody, sourcePayloadError, splitLocalePath };
1303
1324
  //# sourceMappingURL=index.js.map
1304
1325
  //# sourceMappingURL=index.js.map