@elytracms/next 0.0.81 → 0.0.82

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.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ComponentRegistry } from '@elytracms/core/component-registry';
2
2
  export { defineComponent } from '@elytracms/core/component-registry';
3
- import { basePrimitives, getImplementation, renderComposition, ImageManifest, serializeListingQuery, RenderErrorBoundary, collectReferencedAssetIds, collectReferencedRelations, collectReferencedListings, collectReferencedRichTextLinks, normalizeImageSource } from '@elytracms/core/runtime-renderer';
3
+ import { basePrimitives, getImplementation, renderDocumentBodyItems, documentBodyItems, ImageManifest, serializeListingQuery, RenderErrorBoundary, documentBodyRichTextValues, documentBodyCompositionNodes, richTextEmbedsInValue, collectReferencedAssetIds, collectRichTextRefsInValue, collectReferencedRelations, collectReferencedListings, collectReferencedRichTextLinks, normalizeImageSource } from '@elytracms/core/runtime-renderer';
4
4
  import { isValidElement } from 'react';
5
5
  import { jsx, Fragment } from 'react/jsx-runtime';
6
6
  import { cacheTags, isSectionSourceId, parseCmsSourceQueryConfig, listQueryOfCmsConfig, isDocumentHistory, resolvedAsset, createContentClient, createContentContext } from '@elytracms/core/content';
7
- import { documentKey, splitPath, hierarchyMount, composePath, mergeRouteRecords, fallbackHomeRoutes, documentSchema, redirectRecordSchema } from '@elytracms/core/cms-core';
8
- export { documentSchema, fallbackHomeRoutes, localeConfigSchema, mergeRouteRecords, redirectRecordSchema, routeRecordSchema } from '@elytracms/core/cms-core';
7
+ import { documentKey, splitLocalePath, hierarchyMount, composePath, localeUrlPath, mergeRouteRecords, fallbackHomeRoutes, presentationBodyFields, splitPath, documentSchema, redirectRecordSchema } from '@elytracms/core/cms-core';
8
+ export { documentSchema, fallbackHomeRoutes, localeConfigSchema, localeUrlPath, mergeRouteRecords, redirectRecordSchema, routeRecordSchema, splitLocalePath } from '@elytracms/core/cms-core';
9
9
  import { revalidateTag, unstable_cache } from 'next/cache';
10
10
  import { draftMode } from 'next/headers';
11
11
  import { redirect, notFound, permanentRedirect } from 'next/navigation';
@@ -148,11 +148,16 @@ async function CanvasRenderer(props) {
148
148
  };
149
149
  const document = result.document;
150
150
  if (document) {
151
- const composition = compositionOf(document);
152
- return /* @__PURE__ */ jsx(Fragment, { children: renderComposition(composition, ctx) });
151
+ return /* @__PURE__ */ jsx(Fragment, { children: renderDocumentBodyItems(bodyItemsOf(document, props.presentation), ctx) });
153
152
  }
154
153
  return /* @__PURE__ */ jsx(MissingDocumentFallback, {});
155
154
  }
155
+ function bodyItemsOf(document, presentation) {
156
+ if (!document) return [];
157
+ const fields = presentation?.body ?? [];
158
+ if (fields.length > 0) return fields.flatMap((name) => documentBodyItems(document[name]));
159
+ return documentBodyItems(compositionOf(document));
160
+ }
156
161
  function compositionOf(document) {
157
162
  const body = document["body"];
158
163
  if (Array.isArray(body) || isComponentNodeValue(body)) return body;
@@ -164,11 +169,8 @@ function compositionOf(document) {
164
169
  }
165
170
  return void 0;
166
171
  }
167
- function compositionNodesOf(document) {
168
- if (!document) return [];
169
- const composition = compositionOf(document);
170
- const candidates = Array.isArray(composition) ? composition : [composition];
171
- return candidates.filter((node) => isComponentNodeValue(node));
172
+ function compositionNodesOf(document, presentation) {
173
+ return documentBodyCompositionNodes(bodyItemsOf(document, presentation));
172
174
  }
173
175
  function isComponentNodeValue(value) {
174
176
  return typeof value === "object" && value !== null && typeof value.id === "string" && typeof value.componentId === "string";
@@ -219,9 +221,8 @@ function materializeSourcePayloads(input) {
219
221
  }
220
222
  return { payloads, tags };
221
223
  }
222
- var DEFAULT_LOCALES = { default: "en", locales: ["en"] };
223
224
  function createStaticContentSource(data) {
224
- const locales = data.locales ?? DEFAULT_LOCALES;
225
+ const locales = data.locales;
225
226
  const routes = data.routes ?? [];
226
227
  const redirects = data.redirects ?? [];
227
228
  const assetUrl = data.assetUrl ?? ((asset) => `asset://unresolved/${asset.storageKey}`);
@@ -265,10 +266,15 @@ function createStaticContentSource(data) {
265
266
  // dimensions. Baked into the (serializable) render outcome by the route
266
267
  // helper, so a cached page keeps its images during a backend outage.
267
268
  assets: () => [...assets.values()].map((record2) => resolvedAsset(record2, record2.url ?? assetUrl(record2))),
268
- ...data.sources ? { sources: data.sources } : {}
269
+ ...data.sources ? { sources: data.sources } : {},
270
+ // EC-499: the schema the route helper reads a collection's declared
271
+ // `presentation` from (which field is the delivery body, which component
272
+ // wraps it). Already prefetched for the lookup above — exposing it costs
273
+ // nothing and keeps the declaration reachable without a second wiring seam.
274
+ ...data.collections ? { collections: data.collections } : {}
269
275
  };
270
276
  }
271
- async function createContentSnapshot(adapter, projectId, options = {}) {
277
+ async function createContentSnapshot(adapter, projectId, options) {
272
278
  const schema = await adapter.cms.findSchema(projectId);
273
279
  const documentRecords = await adapter.cms.listDocuments(projectId);
274
280
  const versionRecords = await adapter.cms.listAllDocumentVersions(projectId);
@@ -297,7 +303,7 @@ async function createContentSnapshot(adapter, projectId, options = {}) {
297
303
  });
298
304
  return createStaticContentSource({
299
305
  projectId,
300
- ...options.locales ? { locales: options.locales } : {},
306
+ locales: options.locales,
301
307
  ...options.routes ? { routes: options.routes } : {},
302
308
  redirects: options.redirects ? [...options.redirects] : redirects,
303
309
  ...options.sources ? { sources: options.sources } : {},
@@ -307,42 +313,57 @@ async function createContentSnapshot(adapter, projectId, options = {}) {
307
313
  assetUrl: (asset) => adapter.blobs.url(asset.storageKey)
308
314
  });
309
315
  }
310
- function splitLocalePath(url, locales) {
311
- const segments = splitPath(url);
312
- const first = segments[0];
313
- if (first !== void 0 && first !== locales.default && locales.locales.includes(first)) {
314
- return { locale: first, path: "/" + segments.slice(1).join("/") };
315
- }
316
- return { locale: locales.default, path: "/" + segments.join("/") };
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 };
316
+ function canvasWrapContext(result, info) {
317
+ const collection = result.document?.collection;
318
+ return {
319
+ ...info,
320
+ ...collection !== void 0 ? { collection } : {},
321
+ document: result.document,
322
+ result
323
+ };
322
324
  }
323
325
  function pathFromSlug(slug) {
324
326
  return "/" + (slug ?? []).join("/");
325
327
  }
326
- function scopeAssetsToPage(allAssets, registry, result, resolveRelation) {
328
+ function scopeAssetsToPage(allAssets, registry, result, body, resolveRelation) {
327
329
  if (allAssets.length === 0) return allAssets;
328
330
  const ids = /* @__PURE__ */ new Set();
329
331
  const seen = /* @__PURE__ */ new Set();
330
- for (const node of compositionNodesOf(result.document)) {
332
+ for (const node of body.nodes) {
331
333
  collectReferencedAssetIds(node, registry, ids, resolveRelation, seen);
332
334
  }
335
+ for (const value of body.richTexts) {
336
+ collectRichTextRefsInValue(value, { onAsset: (id) => ids.add(id) });
337
+ }
333
338
  const ogImage = result.document?.["seoOgImage"];
334
339
  const ogImageId = typeof ogImage === "string" ? ogImage : ogImage && typeof ogImage === "object" && typeof ogImage.id === "string" ? ogImage.id : null;
335
340
  if (ogImageId) ids.add(ogImageId);
336
341
  return ids.size === 0 ? [] : allAssets.filter((asset) => ids.has(asset.id));
337
342
  }
338
- function pageCompositionNodes(result) {
339
- return [...compositionNodesOf(result.document)];
343
+ function pageBodyOf(result, presentation) {
344
+ const items2 = bodyItemsOf(result.document, presentation);
345
+ const richTexts = documentBodyRichTextValues(items2);
346
+ return {
347
+ nodes: [
348
+ ...documentBodyCompositionNodes(items2),
349
+ ...richTexts.flatMap((value) => richTextEmbedsInValue(value))
350
+ ],
351
+ richTexts
352
+ };
353
+ }
354
+ function presentationFor(source, result) {
355
+ const collectionId = result.document?.collection;
356
+ if (!collectionId || !source.collections) return void 0;
357
+ const collection = source.collections.find((candidate) => candidate.id === collectionId);
358
+ if (!collection?.presentation) return void 0;
359
+ const body = presentationBodyFields(collection);
360
+ return body.length > 0 ? { body: [...body] } : void 0;
340
361
  }
341
- function populatePageRelations(result, client, registry) {
362
+ function populatePageRelations(body, client, registry) {
342
363
  if (!registry) return { relations: {}, docKeys: [] };
343
364
  const refKeys = /* @__PURE__ */ new Set();
344
365
  const relations = collectReferencedRelations(
345
- pageCompositionNodes(result),
366
+ body.nodes,
346
367
  registry,
347
368
  (ref) => client.resolveRelation(ref),
348
369
  {},
@@ -350,11 +371,11 @@ function populatePageRelations(result, client, registry) {
350
371
  );
351
372
  return { relations, docKeys: [...refKeys] };
352
373
  }
353
- function populatePageListings(result, client, registry) {
374
+ function populatePageListings(body, client, registry) {
354
375
  if (!registry) return { listings: {}, tags: [] };
355
376
  const tags = [];
356
377
  const listings = collectReferencedListings(
357
- pageCompositionNodes(result),
378
+ body.nodes,
358
379
  registry,
359
380
  (query) => {
360
381
  const listed = client.listDocuments(query.collection, {
@@ -372,13 +393,20 @@ function populatePageListings(result, client, registry) {
372
393
  );
373
394
  return { listings, tags };
374
395
  }
375
- function populatePageLinks(result, client, registry) {
396
+ function populatePageLinks(body, client, registry) {
376
397
  if (!registry) return { links: {}, docKeys: [] };
377
398
  const refs = collectReferencedRichTextLinks(
378
- pageCompositionNodes(result),
399
+ body.nodes,
379
400
  registry,
380
401
  (ref) => client.resolveRelation(ref)
381
402
  );
403
+ for (const value of body.richTexts) {
404
+ collectRichTextRefsInValue(value, {
405
+ onLink: (ref) => {
406
+ refs[`${ref.collection}:${ref.id}`] = ref;
407
+ }
408
+ });
409
+ }
382
410
  const links = {};
383
411
  for (const [key, ref] of Object.entries(refs)) {
384
412
  const url = client.resolveLink(ref);
@@ -421,11 +449,14 @@ async function resolveCanvasPage(source, url, perspective, options = {}) {
421
449
  });
422
450
  payloads = { ...payloads, ...custom };
423
451
  }
452
+ const presentation = presentationFor(source, result);
453
+ const body = pageBodyOf(result, presentation);
424
454
  const allAssets = source.assets?.() ?? [];
425
455
  const bakedAssets = options.registry ? scopeAssetsToPage(
426
456
  allAssets,
427
457
  options.registry,
428
458
  result,
459
+ body,
429
460
  (ref) => client.resolveRelation(ref)
430
461
  ) : allAssets;
431
462
  const assetTags = cacheTags({
@@ -433,17 +464,17 @@ async function resolveCanvasPage(source, url, perspective, options = {}) {
433
464
  locale: result.tags.locale
434
465
  });
435
466
  const { relations, docKeys: relationDocKeys } = populatePageRelations(
436
- result,
467
+ body,
437
468
  client,
438
469
  options.registry
439
470
  );
440
471
  const relationTags = cacheTags({ docs: relationDocKeys, locale: result.tags.locale });
441
472
  const { listings, tags: listingTags } = populatePageListings(
442
- result,
473
+ body,
443
474
  client,
444
475
  options.registry
445
476
  );
446
- const { links, docKeys: linkDocKeys } = populatePageLinks(result, client, options.registry);
477
+ const { links, docKeys: linkDocKeys } = populatePageLinks(body, client, options.registry);
447
478
  const linkTags = cacheTags({ docs: linkDocKeys, locale: result.tags.locale });
448
479
  return {
449
480
  kind: "render",
@@ -453,6 +484,7 @@ async function resolveCanvasPage(source, url, perspective, options = {}) {
453
484
  relations,
454
485
  listings,
455
486
  links,
487
+ ...presentation ? { presentation } : {},
456
488
  tags: mergeCacheTags(
457
489
  result.tags,
458
490
  ...extraTags,
@@ -611,8 +643,8 @@ function createCanvasRoute(options) {
611
643
  return outcome.permanent ? permanentRedirect(outcome.target) : redirect(outcome.target);
612
644
  case "not-found":
613
645
  return notFound();
614
- case "render":
615
- return /* @__PURE__ */ jsx(
646
+ case "render": {
647
+ const rendered = /* @__PURE__ */ jsx(
616
648
  CanvasRenderer,
617
649
  {
618
650
  result: outcome.result,
@@ -621,9 +653,13 @@ function createCanvasRoute(options) {
621
653
  assets: outcome.assets,
622
654
  relations: outcome.relations,
623
655
  listings: outcome.listings,
624
- links: outcome.links
656
+ links: outcome.links,
657
+ presentation: outcome.presentation
625
658
  }
626
659
  );
660
+ if (!options.wrap) return rendered;
661
+ return options.wrap(rendered, canvasWrapContext(outcome.result, { url, perspective }));
662
+ }
627
663
  }
628
664
  };
629
665
  const generateMetadata = async (props) => {
@@ -831,7 +867,7 @@ function createRevalidateRoute(options) {
831
867
  { status: evaluation.status, headers: cors }
832
868
  );
833
869
  }
834
- for (const tag of evaluation.payload.tags) revalidateTag(tag, "max");
870
+ for (const tag of evaluation.payload.tags) revalidateTag(tag, { expire: 0 });
835
871
  return Response.json({ revalidated: evaluation.payload.tags }, { headers: cors });
836
872
  },
837
873
  async OPTIONS() {
@@ -935,8 +971,8 @@ function elytraHostImage(options = {}) {
935
971
  }
936
972
 
937
973
  // src/full-bleed.ts
938
- function firstBlockFullBleed(document, registry) {
939
- const first = compositionNodesOf(document)[0];
974
+ function firstBlockFullBleed(document, registry, presentation) {
975
+ const first = compositionNodesOf(document, presentation)[0];
940
976
  if (!first) return false;
941
977
  return registry.getManifest(first.componentId)?.presentation?.fullBleed === true;
942
978
  }
@@ -1320,6 +1356,6 @@ function createElytraHost(options) {
1320
1356
  }
1321
1357
  var PACKAGE = "@elytracms/next";
1322
1358
 
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 };
1359
+ export { CanvasRenderer, ELYTRA_HOST_ENV_KEYS, ElytraImage, PACKAGE, REVALIDATE_SIGNATURE_HEADER, assembleLiveSource, bodyItemsOf, 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 };
1324
1360
  //# sourceMappingURL=index.js.map
1325
1361
  //# sourceMappingURL=index.js.map