@cmssy/react 18.0.0 → 19.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/dist/index.cjs CHANGED
@@ -407,7 +407,9 @@ async function resolveCmssyLayoutSlot(config, options) {
407
407
  path,
408
408
  locale: explicitLocale,
409
409
  retry,
410
- fetch: fetchImpl
410
+ fetch: fetchImpl,
411
+ layoutStore,
412
+ onTransientLayoutFailure = "throw"
411
413
  } = options;
412
414
  const requestOptions = {
413
415
  retry: retry ?? "build",
@@ -418,12 +420,31 @@ async function resolveCmssyLayoutSlot(config, options) {
418
420
  const locale$1 = explicitLocale ?? fromPath.locale;
419
421
  const slugSegments = fromPath.path ?? [];
420
422
  const page = layoutSlotPage(explicitPage ?? "/" + slugSegments.join("/"));
421
- const groups = await internal.fetchLayouts(config, page.slug, {
422
- previewSecret: editMode || preview ? config.draftSecret : void 0,
423
- ...requestOptions
424
- });
423
+ const previewSecret = editMode || preview ? config.draftSecret : void 0;
424
+ let groups = [];
425
+ let unavailable;
426
+ try {
427
+ groups = await internal.readThroughLayoutStore(
428
+ layoutStore,
429
+ internal.layoutStoreKey(config, page.slug, previewSecret),
430
+ () => internal.fetchLayouts(config, page.slug, {
431
+ previewSecret,
432
+ ...requestOptions
433
+ })
434
+ );
435
+ } catch (error) {
436
+ if (onTransientLayoutFailure !== "degrade" || !core.isTransientRequestError(error)) {
437
+ throw error;
438
+ }
439
+ unavailable = {
440
+ status: error.status,
441
+ ...error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {},
442
+ message: error.message
443
+ };
444
+ }
425
445
  const base = {
426
446
  groups,
447
+ ...unavailable ? { unavailable } : {},
427
448
  settings: groups.find((g) => g.region === region)?.settings ?? null,
428
449
  page,
429
450
  locale: locale$1,
@@ -504,6 +525,56 @@ async function CmssyServerLayout({
504
525
  })
505
526
  ) });
506
527
  }
528
+ var cardStyle2 = {
529
+ boxSizing: "border-box",
530
+ margin: "8px 0",
531
+ padding: "12px 16px",
532
+ border: "1px dashed #f59e0b",
533
+ borderRadius: "8px",
534
+ background: "rgba(245, 158, 11, 0.08)",
535
+ color: "#b45309",
536
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
537
+ fontSize: "13px",
538
+ lineHeight: 1.5,
539
+ textAlign: "left"
540
+ };
541
+ var headingStyle2 = {
542
+ fontWeight: 700,
543
+ marginBottom: "4px"
544
+ };
545
+ var messageStyle2 = {
546
+ whiteSpace: "pre-wrap",
547
+ overflowWrap: "anywhere"
548
+ };
549
+ function retryHint(retryAfterMs) {
550
+ if (retryAfterMs === void 0) return "";
551
+ return ` Try again in ${Math.max(1, Math.ceil(retryAfterMs / 1e3))}s.`;
552
+ }
553
+ function LayoutUnavailableCard({
554
+ region,
555
+ unavailable
556
+ }) {
557
+ return /* @__PURE__ */ jsxRuntime.jsxs(
558
+ "div",
559
+ {
560
+ role: "alert",
561
+ "data-cmssy-layout-unavailable": region,
562
+ "data-cmssy-layout-status": unavailable.status,
563
+ style: cardStyle2,
564
+ children: [
565
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headingStyle2, children: [
566
+ 'Layout region "',
567
+ region,
568
+ '" could not be loaded (',
569
+ unavailable.status,
570
+ ").",
571
+ retryHint(unavailable.retryAfterMs)
572
+ ] }),
573
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: messageStyle2, children: unavailable.message })
574
+ ]
575
+ }
576
+ );
577
+ }
507
578
  async function resolveCmssyLayout(config, options) {
508
579
  const { editable: Editable, ...slotOptions } = options;
509
580
  if (slotOptions.editMode && !Editable) {
@@ -511,10 +582,10 @@ async function resolveCmssyLayout(config, options) {
511
582
  "cmssy: resolveCmssyLayout needs an `editable` component in edit mode - the editor bridge lives on the client"
512
583
  );
513
584
  }
514
- const resolved = await resolveCmssyLayoutSlot(
515
- config,
516
- slotOptions
517
- );
585
+ const resolved = await resolveCmssyLayoutSlot(config, {
586
+ onTransientLayoutFailure: "degrade",
587
+ ...slotOptions
588
+ });
518
589
  const { groups, settings, page, locale, defaultLocale, enabledLocales } = resolved;
519
590
  const shared = {
520
591
  groups,
@@ -525,25 +596,41 @@ async function resolveCmssyLayout(config, options) {
525
596
  enabledLocales,
526
597
  appContext: options.appContext
527
598
  };
528
- const element = slotOptions.editMode && Editable ? /* @__PURE__ */ jsxRuntime.jsx(
529
- Editable,
530
- {
531
- ...shared,
532
- edit: { editorOrigin: resolved.editorOrigin ?? "" },
533
- data: resolved.data,
534
- resolvedContent: resolved.resolvedContent
535
- }
536
- ) : /* @__PURE__ */ jsxRuntime.jsx(
537
- CmssyServerLayout,
538
- {
539
- ...shared,
540
- blocks: options.blocks,
541
- config,
542
- preview: slotOptions.preview
543
- }
544
- );
599
+ let element;
600
+ if (slotOptions.editMode && Editable) {
601
+ const editable = /* @__PURE__ */ jsxRuntime.jsx(
602
+ Editable,
603
+ {
604
+ ...shared,
605
+ edit: { editorOrigin: resolved.editorOrigin ?? "" },
606
+ data: resolved.data,
607
+ resolvedContent: resolved.resolvedContent
608
+ }
609
+ );
610
+ element = resolved.unavailable ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx(
612
+ LayoutUnavailableCard,
613
+ {
614
+ region: options.region,
615
+ unavailable: resolved.unavailable
616
+ }
617
+ ),
618
+ editable
619
+ ] }) : editable;
620
+ } else {
621
+ element = /* @__PURE__ */ jsxRuntime.jsx(
622
+ CmssyServerLayout,
623
+ {
624
+ ...shared,
625
+ blocks: options.blocks,
626
+ config,
627
+ preview: slotOptions.preview
628
+ }
629
+ );
630
+ }
545
631
  return {
546
632
  groups,
633
+ ...resolved.unavailable ? { unavailable: resolved.unavailable } : {},
547
634
  settings,
548
635
  page,
549
636
  locale,
@@ -955,6 +1042,10 @@ Object.defineProperty(exports, "CmssyRequestError", {
955
1042
  enumerable: true,
956
1043
  get: function () { return core.CmssyRequestError; }
957
1044
  });
1045
+ Object.defineProperty(exports, "MediaType", {
1046
+ enumerable: true,
1047
+ get: function () { return core.MediaType; }
1048
+ });
958
1049
  Object.defineProperty(exports, "PROTOCOL_VERSION", {
959
1050
  enumerable: true,
960
1051
  get: function () { return core.PROTOCOL_VERSION; }
@@ -983,6 +1074,18 @@ Object.defineProperty(exports, "mediaAlt", {
983
1074
  enumerable: true,
984
1075
  get: function () { return core.mediaAlt; }
985
1076
  });
1077
+ Object.defineProperty(exports, "mediaDuration", {
1078
+ enumerable: true,
1079
+ get: function () { return core.mediaDuration; }
1080
+ });
1081
+ Object.defineProperty(exports, "mediaType", {
1082
+ enumerable: true,
1083
+ get: function () { return core.mediaType; }
1084
+ });
1085
+ Object.defineProperty(exports, "mediaTypeValues", {
1086
+ enumerable: true,
1087
+ get: function () { return core.mediaTypeValues; }
1088
+ });
986
1089
  Object.defineProperty(exports, "mediaUrl", {
987
1090
  enumerable: true,
988
1091
  get: function () { return core.mediaUrl; }
package/dist/index.d.cts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { CmssyPageData, CmssyClientConfig, CmssyFormDefinition, CmssyBlockAuthContext, CmssyBlockWorkspace, CmssyLayoutGroup, CmssyBlockPage, RetryOption, FetchLike, CmssyConfig, CmssyRegionOf, CmssyRegionSettingsOf, RawBlock, CmssyBlockContext } from '@cmssy/core';
2
- export { AppToEditorMessage, BlockMeta, BlockPropsSchema, BlockRect, BlockSchema, BoundsMessage, BuildBlockContextExtra, ClickMessage, CmssyBlockAuthContext, CmssyBlockContext, CmssyBlockMember, CmssyBlockPage, CmssyBlockWorkspace, CmssyBranding, CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyFormField, CmssyFormSettings, CmssyFormSubmitResponse, CmssyLayout, CmssyLayoutGroup, CmssyLocaleContext, CmssyLocalizedValue, CmssyModelDefinition, CmssyModelRecord, CmssyPageData, CmssyPageMeta, CmssyPageSummary, CmssyRecordList, CmssyRegion, CmssyRegionOf, CmssyRegionSettings, CmssyRegionSettingsOf, CmssyRequestError, CmssyRetryMode, CmssySiteConfig, CmssyTypedDocument, EditorToAppMessage, FetchLike, FetchLikeResponse, FetchPageOptions, FieldControl, FieldDefinition, FieldType, GraphqlRequestOptions, InferBlockContent, LayoutRegion, LayoutRegionId, MediaLike, PROTOCOL_VERSION, ParentReadyMessage, PatchMessage, PostTarget, QueryScopedOptions, RawBlock, RawLayoutBlock, ReadyMessage, RetryOption, RetryPolicy, SelectMessage, SubmitFormInput, TypedField, createCmssyClient, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, mediaAlt, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor } from '@cmssy/core';
2
+ export { AppToEditorMessage, BlockMeta, BlockPropsSchema, BlockRect, BlockSchema, BoundsMessage, BuildBlockContextExtra, ClickMessage, CmssyBlockAuthContext, CmssyBlockContext, CmssyBlockMember, CmssyBlockPage, CmssyBlockWorkspace, CmssyBranding, CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyFormField, CmssyFormSettings, CmssyFormSubmitResponse, CmssyLayout, CmssyLayoutGroup, CmssyLocaleContext, CmssyLocalizedValue, CmssyModelDefinition, CmssyModelRecord, CmssyPageData, CmssyPageMeta, CmssyPageSummary, CmssyRecordList, CmssyRegion, CmssyRegionOf, CmssyRegionSettings, CmssyRegionSettingsOf, CmssyRequestError, CmssyRetryMode, CmssySiteConfig, CmssyTypedDocument, EditorToAppMessage, FetchLike, FetchLikeResponse, FetchPageOptions, FieldControl, FieldDefinition, FieldType, GraphqlRequestOptions, InferBlockContent, LayoutRegion, LayoutRegionId, MediaLike, MediaType, PROTOCOL_VERSION, ParentReadyMessage, PatchMessage, PostTarget, QueryScopedOptions, RawBlock, RawLayoutBlock, ReadyMessage, RetryOption, RetryPolicy, SelectMessage, SubmitFormInput, TypedField, createCmssyClient, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, mediaAlt, mediaDuration, mediaType, mediaTypeValues, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor } from '@cmssy/core';
3
3
  import { B as BlockDefinition, L as LayoutBlockPage, a as BlockMap } from './resolve-block-data-Bkracpae.cjs';
4
4
  export { b as BlockProps, E as EditorBlockData, R as ResolveBlockDataOptions, c as ResolveLayoutBlockDataOptions, d as buildBlockMap, e as defineBlock, r as resolveEditorBlockData, f as resolveEditorLayoutBlockData } from './resolve-block-data-Bkracpae.cjs';
5
5
  import { FieldDefinition } from '@cmssy/types';
6
6
  export { FieldCondition, FieldConditionGroup, FieldConditionLogic } from '@cmssy/types';
7
+ import { CmssyLayoutStore } from '@cmssy/core/internal';
7
8
  export { buildBlockContext } from '@cmssy/core/internal';
8
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
10
  import { ReactElement, ComponentType } from 'react';
@@ -35,6 +36,8 @@ interface ResolveCmssyLayoutSlotBase {
35
36
  appContext?: Record<string, unknown>;
36
37
  retry?: RetryOption;
37
38
  fetch?: FetchLike;
39
+ layoutStore?: CmssyLayoutStore;
40
+ onTransientLayoutFailure?: "throw" | "degrade";
38
41
  }
39
42
  type CmssyLayoutSlotLocaleSource = {
40
43
  path: string[];
@@ -44,8 +47,14 @@ type CmssyLayoutSlotLocaleSource = {
44
47
  path?: undefined;
45
48
  };
46
49
  type ResolveCmssyLayoutSlotOptions = ResolveCmssyLayoutSlotBase & CmssyLayoutSlotLocaleSource;
50
+ interface CmssyLayoutUnavailable {
51
+ status: number;
52
+ retryAfterMs?: number;
53
+ message: string;
54
+ }
47
55
  interface CmssyLayoutSlotResolution {
48
56
  groups: CmssyLayoutGroup[];
57
+ unavailable?: CmssyLayoutUnavailable;
49
58
  settings: Record<string, unknown> | null;
50
59
  page: CmssyBlockPage;
51
60
  locale: string;
@@ -78,6 +87,7 @@ type ResolveCmssyLayoutOptions<C extends CmssyConfig, P extends CmssyRegionOf<C>
78
87
  };
79
88
  interface CmssyLayoutResolution<C extends CmssyConfig = CmssyConfig, P extends CmssyRegionOf<C> = CmssyRegionOf<C>> {
80
89
  groups: CmssyLayoutGroup[];
90
+ unavailable?: CmssyLayoutUnavailable;
81
91
  settings: CmssyRegionSettingsOf<C, P> | null;
82
92
  page: CmssyBlockPage;
83
93
  locale: string;
@@ -160,4 +170,4 @@ interface UnknownBlockProps {
160
170
  }
161
171
  declare function UnknownBlock({ type }: UnknownBlockProps): react_jsx_runtime.JSX.Element;
162
172
 
163
- export { BlockDefinition, BlockMap, CmssyBlock, type CmssyBlockProps, CmssyBlocks, type CmssyBlocksProps, type CmssyLayoutEditableProps, CmssyLayoutRegion, type CmssyLayoutRegionProps, type CmssyLayoutResolution, type CmssyLayoutSlotLocaleSource, type CmssyLayoutSlotResolution, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, LayoutBlockPage, type ResolveCmssyLayoutOptions, type ResolveCmssyLayoutSlotOptions, UnknownBlock, type UnknownBlockProps, resolveCmssyLayout, resolveCmssyLayoutSlot };
173
+ export { BlockDefinition, BlockMap, CmssyBlock, type CmssyBlockProps, CmssyBlocks, type CmssyBlocksProps, type CmssyLayoutEditableProps, CmssyLayoutRegion, type CmssyLayoutRegionProps, type CmssyLayoutResolution, type CmssyLayoutSlotLocaleSource, type CmssyLayoutSlotResolution, type CmssyLayoutUnavailable, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, LayoutBlockPage, type ResolveCmssyLayoutOptions, type ResolveCmssyLayoutSlotOptions, UnknownBlock, type UnknownBlockProps, resolveCmssyLayout, resolveCmssyLayoutSlot };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { CmssyPageData, CmssyClientConfig, CmssyFormDefinition, CmssyBlockAuthContext, CmssyBlockWorkspace, CmssyLayoutGroup, CmssyBlockPage, RetryOption, FetchLike, CmssyConfig, CmssyRegionOf, CmssyRegionSettingsOf, RawBlock, CmssyBlockContext } from '@cmssy/core';
2
- export { AppToEditorMessage, BlockMeta, BlockPropsSchema, BlockRect, BlockSchema, BoundsMessage, BuildBlockContextExtra, ClickMessage, CmssyBlockAuthContext, CmssyBlockContext, CmssyBlockMember, CmssyBlockPage, CmssyBlockWorkspace, CmssyBranding, CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyFormField, CmssyFormSettings, CmssyFormSubmitResponse, CmssyLayout, CmssyLayoutGroup, CmssyLocaleContext, CmssyLocalizedValue, CmssyModelDefinition, CmssyModelRecord, CmssyPageData, CmssyPageMeta, CmssyPageSummary, CmssyRecordList, CmssyRegion, CmssyRegionOf, CmssyRegionSettings, CmssyRegionSettingsOf, CmssyRequestError, CmssyRetryMode, CmssySiteConfig, CmssyTypedDocument, EditorToAppMessage, FetchLike, FetchLikeResponse, FetchPageOptions, FieldControl, FieldDefinition, FieldType, GraphqlRequestOptions, InferBlockContent, LayoutRegion, LayoutRegionId, MediaLike, PROTOCOL_VERSION, ParentReadyMessage, PatchMessage, PostTarget, QueryScopedOptions, RawBlock, RawLayoutBlock, ReadyMessage, RetryOption, RetryPolicy, SelectMessage, SubmitFormInput, TypedField, createCmssyClient, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, mediaAlt, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor } from '@cmssy/core';
2
+ export { AppToEditorMessage, BlockMeta, BlockPropsSchema, BlockRect, BlockSchema, BoundsMessage, BuildBlockContextExtra, ClickMessage, CmssyBlockAuthContext, CmssyBlockContext, CmssyBlockMember, CmssyBlockPage, CmssyBlockWorkspace, CmssyBranding, CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyFormField, CmssyFormSettings, CmssyFormSubmitResponse, CmssyLayout, CmssyLayoutGroup, CmssyLocaleContext, CmssyLocalizedValue, CmssyModelDefinition, CmssyModelRecord, CmssyPageData, CmssyPageMeta, CmssyPageSummary, CmssyRecordList, CmssyRegion, CmssyRegionOf, CmssyRegionSettings, CmssyRegionSettingsOf, CmssyRequestError, CmssyRetryMode, CmssySiteConfig, CmssyTypedDocument, EditorToAppMessage, FetchLike, FetchLikeResponse, FetchPageOptions, FieldControl, FieldDefinition, FieldType, GraphqlRequestOptions, InferBlockContent, LayoutRegion, LayoutRegionId, MediaLike, MediaType, PROTOCOL_VERSION, ParentReadyMessage, PatchMessage, PostTarget, QueryScopedOptions, RawBlock, RawLayoutBlock, ReadyMessage, RetryOption, RetryPolicy, SelectMessage, SubmitFormInput, TypedField, createCmssyClient, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, mediaAlt, mediaDuration, mediaType, mediaTypeValues, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor } from '@cmssy/core';
3
3
  import { B as BlockDefinition, L as LayoutBlockPage, a as BlockMap } from './resolve-block-data-Bkracpae.js';
4
4
  export { b as BlockProps, E as EditorBlockData, R as ResolveBlockDataOptions, c as ResolveLayoutBlockDataOptions, d as buildBlockMap, e as defineBlock, r as resolveEditorBlockData, f as resolveEditorLayoutBlockData } from './resolve-block-data-Bkracpae.js';
5
5
  import { FieldDefinition } from '@cmssy/types';
6
6
  export { FieldCondition, FieldConditionGroup, FieldConditionLogic } from '@cmssy/types';
7
+ import { CmssyLayoutStore } from '@cmssy/core/internal';
7
8
  export { buildBlockContext } from '@cmssy/core/internal';
8
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
10
  import { ReactElement, ComponentType } from 'react';
@@ -35,6 +36,8 @@ interface ResolveCmssyLayoutSlotBase {
35
36
  appContext?: Record<string, unknown>;
36
37
  retry?: RetryOption;
37
38
  fetch?: FetchLike;
39
+ layoutStore?: CmssyLayoutStore;
40
+ onTransientLayoutFailure?: "throw" | "degrade";
38
41
  }
39
42
  type CmssyLayoutSlotLocaleSource = {
40
43
  path: string[];
@@ -44,8 +47,14 @@ type CmssyLayoutSlotLocaleSource = {
44
47
  path?: undefined;
45
48
  };
46
49
  type ResolveCmssyLayoutSlotOptions = ResolveCmssyLayoutSlotBase & CmssyLayoutSlotLocaleSource;
50
+ interface CmssyLayoutUnavailable {
51
+ status: number;
52
+ retryAfterMs?: number;
53
+ message: string;
54
+ }
47
55
  interface CmssyLayoutSlotResolution {
48
56
  groups: CmssyLayoutGroup[];
57
+ unavailable?: CmssyLayoutUnavailable;
49
58
  settings: Record<string, unknown> | null;
50
59
  page: CmssyBlockPage;
51
60
  locale: string;
@@ -78,6 +87,7 @@ type ResolveCmssyLayoutOptions<C extends CmssyConfig, P extends CmssyRegionOf<C>
78
87
  };
79
88
  interface CmssyLayoutResolution<C extends CmssyConfig = CmssyConfig, P extends CmssyRegionOf<C> = CmssyRegionOf<C>> {
80
89
  groups: CmssyLayoutGroup[];
90
+ unavailable?: CmssyLayoutUnavailable;
81
91
  settings: CmssyRegionSettingsOf<C, P> | null;
82
92
  page: CmssyBlockPage;
83
93
  locale: string;
@@ -160,4 +170,4 @@ interface UnknownBlockProps {
160
170
  }
161
171
  declare function UnknownBlock({ type }: UnknownBlockProps): react_jsx_runtime.JSX.Element;
162
172
 
163
- export { BlockDefinition, BlockMap, CmssyBlock, type CmssyBlockProps, CmssyBlocks, type CmssyBlocksProps, type CmssyLayoutEditableProps, CmssyLayoutRegion, type CmssyLayoutRegionProps, type CmssyLayoutResolution, type CmssyLayoutSlotLocaleSource, type CmssyLayoutSlotResolution, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, LayoutBlockPage, type ResolveCmssyLayoutOptions, type ResolveCmssyLayoutSlotOptions, UnknownBlock, type UnknownBlockProps, resolveCmssyLayout, resolveCmssyLayoutSlot };
173
+ export { BlockDefinition, BlockMap, CmssyBlock, type CmssyBlockProps, CmssyBlocks, type CmssyBlocksProps, type CmssyLayoutEditableProps, CmssyLayoutRegion, type CmssyLayoutRegionProps, type CmssyLayoutResolution, type CmssyLayoutSlotLocaleSource, type CmssyLayoutSlotResolution, type CmssyLayoutUnavailable, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, LayoutBlockPage, type ResolveCmssyLayoutOptions, type ResolveCmssyLayoutSlotOptions, UnknownBlock, type UnknownBlockProps, resolveCmssyLayout, resolveCmssyLayoutSlot };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { blocksToSchemas, resolveEditorOrigin, verifyCmssyEditToken, CMSSY_EDIT_TOKEN_HEADER } from '@cmssy/core';
2
- export { CmssyRequestError, PROTOCOL_VERSION, createCmssyClient, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, mediaAlt, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor } from '@cmssy/core';
3
- import { buildBlockContext, fetchLayouts, normalizeBlockContent, asBucket, layoutRegionIds, fetchPage, resolveSiteLocales as resolveSiteLocales$1, getBlockContentForLanguage, resolveRelationContent } from '@cmssy/core/internal';
1
+ import { blocksToSchemas, isTransientRequestError, resolveEditorOrigin, verifyCmssyEditToken, CMSSY_EDIT_TOKEN_HEADER } from '@cmssy/core';
2
+ export { CmssyRequestError, MediaType, PROTOCOL_VERSION, createCmssyClient, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, mediaAlt, mediaDuration, mediaType, mediaTypeValues, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor } from '@cmssy/core';
3
+ import { buildBlockContext, readThroughLayoutStore, layoutStoreKey, fetchLayouts, normalizeBlockContent, asBucket, layoutRegionIds, fetchPage, resolveSiteLocales as resolveSiteLocales$1, getBlockContentForLanguage, resolveRelationContent } from '@cmssy/core/internal';
4
4
  export { buildBlockContext } from '@cmssy/core/internal';
5
5
  import { createElement } from 'react';
6
6
  import { BlockErrorBoundary } from '@cmssy/react/block-error-boundary';
@@ -407,7 +407,9 @@ async function resolveCmssyLayoutSlot(config, options) {
407
407
  path,
408
408
  locale: explicitLocale,
409
409
  retry,
410
- fetch: fetchImpl
410
+ fetch: fetchImpl,
411
+ layoutStore,
412
+ onTransientLayoutFailure = "throw"
411
413
  } = options;
412
414
  const requestOptions = {
413
415
  retry: retry ?? "build",
@@ -418,12 +420,31 @@ async function resolveCmssyLayoutSlot(config, options) {
418
420
  const locale = explicitLocale ?? fromPath.locale;
419
421
  const slugSegments = fromPath.path ?? [];
420
422
  const page = layoutSlotPage(explicitPage ?? "/" + slugSegments.join("/"));
421
- const groups = await fetchLayouts(config, page.slug, {
422
- previewSecret: editMode || preview ? config.draftSecret : void 0,
423
- ...requestOptions
424
- });
423
+ const previewSecret = editMode || preview ? config.draftSecret : void 0;
424
+ let groups = [];
425
+ let unavailable;
426
+ try {
427
+ groups = await readThroughLayoutStore(
428
+ layoutStore,
429
+ layoutStoreKey(config, page.slug, previewSecret),
430
+ () => fetchLayouts(config, page.slug, {
431
+ previewSecret,
432
+ ...requestOptions
433
+ })
434
+ );
435
+ } catch (error) {
436
+ if (onTransientLayoutFailure !== "degrade" || !isTransientRequestError(error)) {
437
+ throw error;
438
+ }
439
+ unavailable = {
440
+ status: error.status,
441
+ ...error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {},
442
+ message: error.message
443
+ };
444
+ }
425
445
  const base = {
426
446
  groups,
447
+ ...unavailable ? { unavailable } : {},
427
448
  settings: groups.find((g) => g.region === region)?.settings ?? null,
428
449
  page,
429
450
  locale,
@@ -504,6 +525,56 @@ async function CmssyServerLayout({
504
525
  })
505
526
  ) });
506
527
  }
528
+ var cardStyle2 = {
529
+ boxSizing: "border-box",
530
+ margin: "8px 0",
531
+ padding: "12px 16px",
532
+ border: "1px dashed #f59e0b",
533
+ borderRadius: "8px",
534
+ background: "rgba(245, 158, 11, 0.08)",
535
+ color: "#b45309",
536
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
537
+ fontSize: "13px",
538
+ lineHeight: 1.5,
539
+ textAlign: "left"
540
+ };
541
+ var headingStyle2 = {
542
+ fontWeight: 700,
543
+ marginBottom: "4px"
544
+ };
545
+ var messageStyle2 = {
546
+ whiteSpace: "pre-wrap",
547
+ overflowWrap: "anywhere"
548
+ };
549
+ function retryHint(retryAfterMs) {
550
+ if (retryAfterMs === void 0) return "";
551
+ return ` Try again in ${Math.max(1, Math.ceil(retryAfterMs / 1e3))}s.`;
552
+ }
553
+ function LayoutUnavailableCard({
554
+ region,
555
+ unavailable
556
+ }) {
557
+ return /* @__PURE__ */ jsxs(
558
+ "div",
559
+ {
560
+ role: "alert",
561
+ "data-cmssy-layout-unavailable": region,
562
+ "data-cmssy-layout-status": unavailable.status,
563
+ style: cardStyle2,
564
+ children: [
565
+ /* @__PURE__ */ jsxs("div", { style: headingStyle2, children: [
566
+ 'Layout region "',
567
+ region,
568
+ '" could not be loaded (',
569
+ unavailable.status,
570
+ ").",
571
+ retryHint(unavailable.retryAfterMs)
572
+ ] }),
573
+ /* @__PURE__ */ jsx("div", { style: messageStyle2, children: unavailable.message })
574
+ ]
575
+ }
576
+ );
577
+ }
507
578
  async function resolveCmssyLayout(config, options) {
508
579
  const { editable: Editable, ...slotOptions } = options;
509
580
  if (slotOptions.editMode && !Editable) {
@@ -511,10 +582,10 @@ async function resolveCmssyLayout(config, options) {
511
582
  "cmssy: resolveCmssyLayout needs an `editable` component in edit mode - the editor bridge lives on the client"
512
583
  );
513
584
  }
514
- const resolved = await resolveCmssyLayoutSlot(
515
- config,
516
- slotOptions
517
- );
585
+ const resolved = await resolveCmssyLayoutSlot(config, {
586
+ onTransientLayoutFailure: "degrade",
587
+ ...slotOptions
588
+ });
518
589
  const { groups, settings, page, locale, defaultLocale, enabledLocales } = resolved;
519
590
  const shared = {
520
591
  groups,
@@ -525,25 +596,41 @@ async function resolveCmssyLayout(config, options) {
525
596
  enabledLocales,
526
597
  appContext: options.appContext
527
598
  };
528
- const element = slotOptions.editMode && Editable ? /* @__PURE__ */ jsx(
529
- Editable,
530
- {
531
- ...shared,
532
- edit: { editorOrigin: resolved.editorOrigin ?? "" },
533
- data: resolved.data,
534
- resolvedContent: resolved.resolvedContent
535
- }
536
- ) : /* @__PURE__ */ jsx(
537
- CmssyServerLayout,
538
- {
539
- ...shared,
540
- blocks: options.blocks,
541
- config,
542
- preview: slotOptions.preview
543
- }
544
- );
599
+ let element;
600
+ if (slotOptions.editMode && Editable) {
601
+ const editable = /* @__PURE__ */ jsx(
602
+ Editable,
603
+ {
604
+ ...shared,
605
+ edit: { editorOrigin: resolved.editorOrigin ?? "" },
606
+ data: resolved.data,
607
+ resolvedContent: resolved.resolvedContent
608
+ }
609
+ );
610
+ element = resolved.unavailable ? /* @__PURE__ */ jsxs(Fragment, { children: [
611
+ /* @__PURE__ */ jsx(
612
+ LayoutUnavailableCard,
613
+ {
614
+ region: options.region,
615
+ unavailable: resolved.unavailable
616
+ }
617
+ ),
618
+ editable
619
+ ] }) : editable;
620
+ } else {
621
+ element = /* @__PURE__ */ jsx(
622
+ CmssyServerLayout,
623
+ {
624
+ ...shared,
625
+ blocks: options.blocks,
626
+ config,
627
+ preview: slotOptions.preview
628
+ }
629
+ );
630
+ }
545
631
  return {
546
632
  groups,
633
+ ...resolved.unavailable ? { unavailable: resolved.unavailable } : {},
547
634
  settings,
548
635
  page,
549
636
  locale,
package/dist/spa.cjs CHANGED
@@ -207,7 +207,9 @@ async function resolveCmssyLayoutSlot(config, options) {
207
207
  path,
208
208
  locale: explicitLocale,
209
209
  retry,
210
- fetch: fetchImpl
210
+ fetch: fetchImpl,
211
+ layoutStore,
212
+ onTransientLayoutFailure = "throw"
211
213
  } = options;
212
214
  const requestOptions = {
213
215
  retry: retry ?? "build",
@@ -218,12 +220,31 @@ async function resolveCmssyLayoutSlot(config, options) {
218
220
  const locale$1 = explicitLocale ?? fromPath.locale;
219
221
  const slugSegments = fromPath.path ?? [];
220
222
  const page = layoutSlotPage(explicitPage ?? "/" + slugSegments.join("/"));
221
- const groups = await internal.fetchLayouts(config, page.slug, {
222
- previewSecret: editMode || preview ? config.draftSecret : void 0,
223
- ...requestOptions
224
- });
223
+ const previewSecret = editMode || preview ? config.draftSecret : void 0;
224
+ let groups = [];
225
+ let unavailable;
226
+ try {
227
+ groups = await internal.readThroughLayoutStore(
228
+ layoutStore,
229
+ internal.layoutStoreKey(config, page.slug, previewSecret),
230
+ () => internal.fetchLayouts(config, page.slug, {
231
+ previewSecret,
232
+ ...requestOptions
233
+ })
234
+ );
235
+ } catch (error) {
236
+ if (onTransientLayoutFailure !== "degrade" || !core.isTransientRequestError(error)) {
237
+ throw error;
238
+ }
239
+ unavailable = {
240
+ status: error.status,
241
+ ...error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {},
242
+ message: error.message
243
+ };
244
+ }
225
245
  const base = {
226
246
  groups,
247
+ ...unavailable ? { unavailable } : {},
227
248
  settings: groups.find((g) => g.region === region)?.settings ?? null,
228
249
  page,
229
250
  locale: locale$1,
package/dist/spa.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useMemo, useState, useRef, useEffect, useCallback, createElement } from 'react';
3
- import { layoutRegionIds, fetchPage, buildBlockContext, fetchLayouts, normalizeBlockContent, asBucket, getBlockContentForLanguage, resolveRelationContent } from '@cmssy/core/internal';
4
- import { resolveEditorOrigin, blocksToSchemas } from '@cmssy/core';
3
+ import { layoutRegionIds, fetchPage, buildBlockContext, readThroughLayoutStore, layoutStoreKey, fetchLayouts, normalizeBlockContent, asBucket, getBlockContentForLanguage, resolveRelationContent } from '@cmssy/core/internal';
4
+ import { isTransientRequestError, resolveEditorOrigin, blocksToSchemas } from '@cmssy/core';
5
5
  import { resolveSiteLocales, splitLocaleFromPath } from '@cmssy/core/internal/locale';
6
6
  import { BlockErrorBoundary } from '@cmssy/react/block-error-boundary';
7
7
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
@@ -205,7 +205,9 @@ async function resolveCmssyLayoutSlot(config, options) {
205
205
  path,
206
206
  locale: explicitLocale,
207
207
  retry,
208
- fetch: fetchImpl
208
+ fetch: fetchImpl,
209
+ layoutStore,
210
+ onTransientLayoutFailure = "throw"
209
211
  } = options;
210
212
  const requestOptions = {
211
213
  retry: retry ?? "build",
@@ -216,12 +218,31 @@ async function resolveCmssyLayoutSlot(config, options) {
216
218
  const locale = explicitLocale ?? fromPath.locale;
217
219
  const slugSegments = fromPath.path ?? [];
218
220
  const page = layoutSlotPage(explicitPage ?? "/" + slugSegments.join("/"));
219
- const groups = await fetchLayouts(config, page.slug, {
220
- previewSecret: editMode || preview ? config.draftSecret : void 0,
221
- ...requestOptions
222
- });
221
+ const previewSecret = editMode || preview ? config.draftSecret : void 0;
222
+ let groups = [];
223
+ let unavailable;
224
+ try {
225
+ groups = await readThroughLayoutStore(
226
+ layoutStore,
227
+ layoutStoreKey(config, page.slug, previewSecret),
228
+ () => fetchLayouts(config, page.slug, {
229
+ previewSecret,
230
+ ...requestOptions
231
+ })
232
+ );
233
+ } catch (error) {
234
+ if (onTransientLayoutFailure !== "degrade" || !isTransientRequestError(error)) {
235
+ throw error;
236
+ }
237
+ unavailable = {
238
+ status: error.status,
239
+ ...error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {},
240
+ message: error.message
241
+ };
242
+ }
223
243
  const base = {
224
244
  groups,
245
+ ...unavailable ? { unavailable } : {},
225
246
  settings: groups.find((g) => g.region === region)?.settings ?? null,
226
247
  page,
227
248
  locale,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmssy/react",
3
- "version": "18.0.0",
3
+ "version": "19.1.0",
4
4
  "description": "React blocks, renderers, data client and editor bridge for cmssy headless sites",
5
5
  "keywords": [
6
6
  "cmssy",
@@ -106,8 +106,8 @@
106
106
  "vitest": "^2.1.0"
107
107
  },
108
108
  "dependencies": {
109
- "@cmssy/types": "0.54.0",
110
- "@cmssy/core": "18.0.0"
109
+ "@cmssy/types": "0.59.0",
110
+ "@cmssy/core": "19.1.0"
111
111
  },
112
112
  "scripts": {
113
113
  "build": "tsup",