@amplifyup/sdk 0.1.67 → 0.1.68

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.
@@ -1,4 +1,4 @@
1
- import { i as AmplifyUpTarget, y as ListRow } from './types-C32MgOiv.mjs';
1
+ import { i as AmplifyUpTarget, y as ListRow } from './types-CGeBbx84.mjs';
2
2
 
3
3
  /**
4
4
  * On-request variant selection (tier 3).
@@ -1,4 +1,4 @@
1
- import { i as AmplifyUpTarget, y as ListRow } from './types-C32MgOiv.js';
1
+ import { i as AmplifyUpTarget, y as ListRow } from './types-CGeBbx84.js';
2
2
 
3
3
  /**
4
4
  * On-request variant selection (tier 3).
package/dist/react.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { L as LayoutComponentProps, P as PageConfig, F as Field$1, l as FIELDS_BRAND, c as AmplifyUpConfig, e as AmplifyPageContextInput, C as ContentSource, A as AmplifyContentMeta } from './types-C32MgOiv.mjs';
3
- export { w as FieldRef, x as Fields, z as ImageValue, y as ListRow, B as PortableRef, Z as ZoneConfig, m as attachFieldEnvelopes, p as composerStoreKey, o as envelopeListRows, v as isBrandedFields, s as isFieldEnvelope, u as isReadOnlyRowField, q as listOwnerFromSpec, t as toFieldEnvelopes } from './types-C32MgOiv.mjs';
2
+ import { L as LayoutComponentProps, P as PageConfig, F as Field$1, l as FIELDS_BRAND, c as AmplifyUpConfig, e as AmplifyPageContextInput, C as ContentSource, A as AmplifyContentMeta } from './types-CGeBbx84.mjs';
3
+ export { w as FieldRef, x as Fields, z as ImageValue, y as ListRow, B as PortableRef, Z as ZoneConfig, m as attachFieldEnvelopes, p as composerStoreKey, o as envelopeListRows, v as isBrandedFields, s as isFieldEnvelope, u as isReadOnlyRowField, q as listOwnerFromSpec, t as toFieldEnvelopes } from './types-CGeBbx84.mjs';
4
4
  import react__default, { ReactNode } from 'react';
5
5
  export { AmplifyRenderer } from './AmplifyRenderer.mjs';
6
- export { Q as QueryContentError, e as QueryContentOptions, k as QueryFilter, l as QueryFilterOp, i as QueryPagination, h as QueryResult, m as QuerySort, j as QuerySpec, S as SelectVariantsError, a as SelectVariantsOptions, b as SelectVariantsResult, n as nextPageSpec, q as queryContent, d as searchSpec, s as selectVariants } from './query-DuRilU_n.mjs';
6
+ export { Q as QueryContentError, e as QueryContentOptions, k as QueryFilter, l as QueryFilterOp, i as QueryPagination, h as QueryResult, m as QuerySort, j as QuerySpec, S as SelectVariantsError, a as SelectVariantsOptions, b as SelectVariantsResult, n as nextPageSpec, q as queryContent, d as searchSpec, s as selectVariants } from './query-B_DU7yEm.mjs';
7
7
  export { i as isComposerPreview, a as isPreviewRequest, b as isWorkingContentRequest } from './preview-_vHmzRen.mjs';
8
8
 
9
9
  type RenderComponentContext = {
package/dist/react.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { L as LayoutComponentProps, P as PageConfig, F as Field$1, l as FIELDS_BRAND, c as AmplifyUpConfig, e as AmplifyPageContextInput, C as ContentSource, A as AmplifyContentMeta } from './types-C32MgOiv.js';
3
- export { w as FieldRef, x as Fields, z as ImageValue, y as ListRow, B as PortableRef, Z as ZoneConfig, m as attachFieldEnvelopes, p as composerStoreKey, o as envelopeListRows, v as isBrandedFields, s as isFieldEnvelope, u as isReadOnlyRowField, q as listOwnerFromSpec, t as toFieldEnvelopes } from './types-C32MgOiv.js';
2
+ import { L as LayoutComponentProps, P as PageConfig, F as Field$1, l as FIELDS_BRAND, c as AmplifyUpConfig, e as AmplifyPageContextInput, C as ContentSource, A as AmplifyContentMeta } from './types-CGeBbx84.js';
3
+ export { w as FieldRef, x as Fields, z as ImageValue, y as ListRow, B as PortableRef, Z as ZoneConfig, m as attachFieldEnvelopes, p as composerStoreKey, o as envelopeListRows, v as isBrandedFields, s as isFieldEnvelope, u as isReadOnlyRowField, q as listOwnerFromSpec, t as toFieldEnvelopes } from './types-CGeBbx84.js';
4
4
  import react__default, { ReactNode } from 'react';
5
5
  export { AmplifyRenderer } from './AmplifyRenderer.js';
6
- export { Q as QueryContentError, e as QueryContentOptions, k as QueryFilter, l as QueryFilterOp, i as QueryPagination, h as QueryResult, m as QuerySort, j as QuerySpec, S as SelectVariantsError, a as SelectVariantsOptions, b as SelectVariantsResult, n as nextPageSpec, q as queryContent, d as searchSpec, s as selectVariants } from './query-BLjZYjHJ.js';
6
+ export { Q as QueryContentError, e as QueryContentOptions, k as QueryFilter, l as QueryFilterOp, i as QueryPagination, h as QueryResult, m as QuerySort, j as QuerySpec, S as SelectVariantsError, a as SelectVariantsOptions, b as SelectVariantsResult, n as nextPageSpec, q as queryContent, d as searchSpec, s as selectVariants } from './query-Hay-oVYp.js';
7
7
  export { i as isComposerPreview, a as isPreviewRequest, b as isWorkingContentRequest } from './preview-_vHmzRen.js';
8
8
 
9
9
  type RenderComponentContext = {
package/dist/react.js CHANGED
@@ -440,6 +440,13 @@ function isFieldEnvelope(value) {
440
440
  const rec = value;
441
441
  return typeof rec.name === "string" && "value" in rec && !("url" in rec);
442
442
  }
443
+ var OBJECT_FIELD_KINDS = /* @__PURE__ */ new Set(["object", "array", "list"]);
444
+ function isLeafFieldKind(kind) {
445
+ if (typeof kind !== "string") return false;
446
+ const normalized = kind.trim().toLowerCase();
447
+ if (!normalized) return false;
448
+ return !OBJECT_FIELD_KINDS.has(normalized);
449
+ }
443
450
  function isPageResourceSentinel(value) {
444
451
  return !!value && typeof value === "object" && !Array.isArray(value) && typeof value.__amplifyupPageResource === "string";
445
452
  }
@@ -579,6 +586,10 @@ function toFieldEnvelopes(source, prefix = "", scope) {
579
586
  out[key] = { value: envelopeListRows(raw, owner), name: path };
580
587
  continue;
581
588
  }
589
+ if (ctx.leaf?.(path)) {
590
+ out[key] = withLeaf({ value: emptyValue(raw), name: path }, ctx);
591
+ continue;
592
+ }
582
593
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
583
594
  out[key] = toFieldEnvelopes(raw, path, ctx);
584
595
  continue;
@@ -607,15 +618,33 @@ function envelopeListRow(item, owner) {
607
618
  }
608
619
  return row;
609
620
  }
621
+ var warnedMissingFieldKind = /* @__PURE__ */ new Set();
622
+ function warnMissingFieldKind(fieldName) {
623
+ if (process.env.NODE_ENV === "production") return;
624
+ if (warnedMissingFieldKind.has(fieldName)) return;
625
+ warnedMissingFieldKind.add(fieldName);
626
+ console.warn(
627
+ `[AmplifyUp SDK] Field "${fieldName}" has no schema kind; using value-shape detection. Republish the component definition so its fields carry a type.`
628
+ );
629
+ }
610
630
  function attachFieldEnvelopes(props, sources) {
611
631
  const raw = props && typeof props === "object" ? { ...props } : {};
612
632
  if (isBrandedFields(raw.fields)) return raw;
613
633
  const { fields: existing, ...content } = raw;
614
634
  const source = existing && typeof existing === "object" && !isFieldEnvelope(existing) ? existing : content;
635
+ const { reads } = normalizeEnvelopeSources(sources);
636
+ if (reads) {
637
+ for (const [fieldName, read] of Object.entries(reads)) {
638
+ if (!read?.kind) warnMissingFieldKind(fieldName);
639
+ }
640
+ }
615
641
  return {
616
642
  ...raw,
617
643
  fields: toFieldEnvelopes(source, "", {
618
- owners: (fieldName) => listOwnerForField(fieldName, source, sources)
644
+ owners: (fieldName) => listOwnerForField(fieldName, source, sources),
645
+ // Top-level field paths equal field names; nested paths have no schema
646
+ // entry and fall back to shape-based handling.
647
+ leaf: (path) => isLeafFieldKind(reads?.[path]?.kind)
619
648
  })
620
649
  };
621
650
  }
@@ -890,6 +919,8 @@ function hydrateFieldsBag(bag, fields) {
890
919
  if (val && typeof val === "object" && !Array.isArray(val) && typeof val.name === "string" && "value" in val && !("url" in val)) {
891
920
  const env = val;
892
921
  out[key] = {
922
+ // Keep ref / readOnly / source — dropping them severs the write target.
923
+ ...val,
893
924
  name: env.name,
894
925
  value: isPageResourceSentinel2(env.value) ? hydratePageResourceValue(env.value, fields) : env.value
895
926
  };
@@ -971,6 +1002,51 @@ function sdkDebugOnce(key, ...args) {
971
1002
  console.log(...args);
972
1003
  }
973
1004
 
1005
+ // src/content/layoutProviderCache.ts
1006
+ var SETTLED_TTL_MS = 5e3;
1007
+ var inflight = /* @__PURE__ */ new Map();
1008
+ var settled = /* @__PURE__ */ new Map();
1009
+ function layoutProviderCacheKey(opts) {
1010
+ const route = (opts.route || "/").split("?")[0] || "/";
1011
+ return [
1012
+ route,
1013
+ opts.trackingId || "",
1014
+ opts.instanceId || "",
1015
+ opts.preview ? "1" : "0",
1016
+ opts.working ? "1" : "0",
1017
+ opts.zoneId || "",
1018
+ opts.compositionId || ""
1019
+ ].join("|");
1020
+ }
1021
+ function getSettledLayoutProvider(key) {
1022
+ const entry = settled.get(key);
1023
+ if (!entry) return void 0;
1024
+ if (Date.now() - entry.at > SETTLED_TTL_MS) {
1025
+ settled.delete(key);
1026
+ return void 0;
1027
+ }
1028
+ return entry.value;
1029
+ }
1030
+ function dedupeLayoutProviderFetch(key, fetchFn) {
1031
+ const cached = getSettledLayoutProvider(key);
1032
+ if (cached !== void 0) return Promise.resolve(cached);
1033
+ const existing = inflight.get(key);
1034
+ if (existing) return existing;
1035
+ const pending = fetchFn().then((value) => {
1036
+ settled.set(key, { value, at: Date.now() });
1037
+ return value;
1038
+ }).finally(() => {
1039
+ inflight.delete(key);
1040
+ });
1041
+ inflight.set(key, pending);
1042
+ return pending;
1043
+ }
1044
+ function previewLayoutReady(opts) {
1045
+ if (opts.hasClientLayout) return true;
1046
+ if (opts.clientLoading) return false;
1047
+ return opts.hasServerLayout;
1048
+ }
1049
+
974
1050
  // src/edge/normalizeRoute.ts
975
1051
  function normalizeRoute(route) {
976
1052
  let path = String(route || "").trim();
@@ -2384,6 +2460,32 @@ Available Console Commands:
2384
2460
  */
2385
2461
  async fetchPageConfig(route, preview = false) {
2386
2462
  const url = this.buildLayoutProviderUrl(route, preview);
2463
+ const pageSearch = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
2464
+ const cacheKey = layoutProviderCacheKey({
2465
+ route,
2466
+ trackingId: this.getTrackingId(),
2467
+ instanceId: getInstanceId(),
2468
+ preview,
2469
+ working: pageSearch ? isWorkingContentRequest(pageSearch) : false,
2470
+ zoneId: pageSearch?.get("zoneId"),
2471
+ compositionId: pageSearch?.get("compositionId")
2472
+ });
2473
+ return dedupeLayoutProviderFetch(cacheKey, async () => {
2474
+ const startedAt = Date.now();
2475
+ sdkDebug("[AmplifyUp SDK] layout/provider request", {
2476
+ route,
2477
+ at: new Date(startedAt).toISOString()
2478
+ });
2479
+ const page = await this.fetchPageConfigUncached(url);
2480
+ sdkDebug("[AmplifyUp SDK] layout/provider response", {
2481
+ route,
2482
+ durationMs: Date.now() - startedAt,
2483
+ hasPage: !!page
2484
+ });
2485
+ return page;
2486
+ });
2487
+ }
2488
+ async fetchPageConfigUncached(url) {
2387
2489
  const response = await fetch(url);
2388
2490
  if (!response.ok) {
2389
2491
  if (response.status === 404) {
@@ -2742,6 +2844,12 @@ Available Console Commands:
2742
2844
  );
2743
2845
  return;
2744
2846
  }
2847
+ if (event.data?.type === "AMPLIFYUP_LAYOUT_PATCH") {
2848
+ window.dispatchEvent(
2849
+ new CustomEvent("amplifyup:layout-patch", { detail: event.data })
2850
+ );
2851
+ return;
2852
+ }
2745
2853
  if (event.data?.type === "COMPONENT_DELETABLE_STATUS") {
2746
2854
  const { componentId, deletable, nodeId } = event.data;
2747
2855
  const element = document.querySelector(`[data-component-id="${componentId}"]`);
@@ -3782,6 +3890,13 @@ function getSDK(adapter) {
3782
3890
  var trackContentView = (contentId, contentType, properties) => getSDK().trackContentView(contentId, contentType, properties);
3783
3891
  var refreshEventTracking = () => getSDK().refreshEventTracking();
3784
3892
  getSDK();
3893
+ function useComposerPreviewFlag(force = false) {
3894
+ const [detected, setDetected] = React2.useState(false);
3895
+ React2.useEffect(() => {
3896
+ if (!force && isComposerPreview()) setDetected(true);
3897
+ }, [force]);
3898
+ return force || detected;
3899
+ }
3785
3900
 
3786
3901
  // src/composer-store.ts
3787
3902
  var ComposerFieldStore = class {
@@ -3998,16 +4113,9 @@ function NodeWithFields({
3998
4113
  renderComponent,
3999
4114
  composerPreview
4000
4115
  }) {
4001
- return /* @__PURE__ */ jsxRuntime.jsx(
4002
- MaybeComposerProvider,
4003
- {
4004
- enabled: !!(composerPreview || isComposerPreview()),
4005
- layoutNodeId: nodeId,
4006
- children: renderComponent(componentId, props, slots, {
4007
- layoutNodeId: nodeId
4008
- })
4009
- }
4010
- );
4116
+ return /* @__PURE__ */ jsxRuntime.jsx(MaybeComposerProvider, { enabled: !!composerPreview, layoutNodeId: nodeId, children: renderComponent(componentId, props, slots, {
4117
+ layoutNodeId: nodeId
4118
+ }) });
4011
4119
  }
4012
4120
  function AmplifyRendererInner({
4013
4121
  renderComponent,
@@ -4018,6 +4126,7 @@ function AmplifyRendererInner({
4018
4126
  composerPreview
4019
4127
  }) {
4020
4128
  const clientHook = useAmplifyUp();
4129
+ const composerPreviewFlag = useComposerPreviewFlag(!!composerPreview);
4021
4130
  const pageConfig = serverPageConfig || clientHook.pageConfig || null;
4022
4131
  const loading = serverPageConfig ? false : clientHook.loading;
4023
4132
  const error = serverPageConfig ? null : clientHook.error;
@@ -4370,7 +4479,7 @@ function AmplifyRendererInner({
4370
4479
  props: nodeRenderProps(node),
4371
4480
  slots: slotsToPass,
4372
4481
  renderComponent,
4373
- composerPreview
4482
+ composerPreview: composerPreviewFlag
4374
4483
  }
4375
4484
  )
4376
4485
  }
@@ -4383,7 +4492,7 @@ function AmplifyRendererInner({
4383
4492
  if (layoutTree.length === 0) {
4384
4493
  return /* @__PURE__ */ jsxRuntime.jsx("main", { children: emptyComponent || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
4385
4494
  }
4386
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsxRuntime.jsx(
4495
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("main", { children: composerPreviewFlag ? /* @__PURE__ */ jsxRuntime.jsx(
4387
4496
  "div",
4388
4497
  {
4389
4498
  "data-slot-id": "main",
@@ -4532,7 +4641,7 @@ function AmplifyPageContent({
4532
4641
  errorComponent
4533
4642
  }) {
4534
4643
  const client = useAmplifyUp();
4535
- const preview = forceComposerPreview || isComposerPreview();
4644
+ const preview = useComposerPreviewFlag(forceComposerPreview);
4536
4645
  const clientLayout = hasAmplifyLayout(client.pageConfig) ? client.pageConfig : null;
4537
4646
  const serverLayout = hasAmplifyLayout(pageConfigProp) ? pageConfigProp : null;
4538
4647
  let pageConfig = serverLayout ?? clientLayout;
@@ -4548,10 +4657,15 @@ function AmplifyPageContent({
4548
4657
  const previewCanvas = previewEmptyComponent ?? defaultPreviewCanvas();
4549
4658
  const previewLoading = previewLoadingComponent ?? previewCanvas;
4550
4659
  if (preview) {
4660
+ const ready = previewLayoutReady({
4661
+ clientLoading: client.loading,
4662
+ hasClientLayout: !!clientLayout,
4663
+ hasServerLayout: !!serverLayout
4664
+ });
4551
4665
  return /* @__PURE__ */ jsxRuntime.jsx(
4552
4666
  AmplifyRenderer,
4553
4667
  {
4554
- pageConfig: pageConfig ?? void 0,
4668
+ pageConfig: ready ? pageConfig ?? void 0 : void 0,
4555
4669
  renderComponent,
4556
4670
  composerPreview: true,
4557
4671
  loadingComponent: loadingComponent ?? previewLoading,
@@ -5011,6 +5125,18 @@ function warnNotScalarField(component, field, fieldValue) {
5011
5125
  }
5012
5126
  return false;
5013
5127
  }
5128
+ function assertNamedEnvelope(component, field) {
5129
+ if (process.env.NODE_ENV === "production") return;
5130
+ if (!field || typeof field !== "object" || Array.isArray(field)) return;
5131
+ const rec = field;
5132
+ if (!("value" in rec)) return;
5133
+ if (typeof rec.name === "string" && rec.name) return;
5134
+ throw new Error(
5135
+ `[AmplifyUp SDK] ${component} received an envelope-shaped object with a \`value\` but no \`name\` \u2014 a partial envelope was manufactured upstream (keys: ${Object.keys(
5136
+ rec
5137
+ ).join(", ")}). Find the producer; do not strip or rebuild envelopes.`
5138
+ );
5139
+ }
5014
5140
  var warnedReadOnlyFields = /* @__PURE__ */ new Set();
5015
5141
  function warnReadOnlyRowField(name) {
5016
5142
  if (process.env.NODE_ENV === "production") return;
@@ -5046,6 +5172,7 @@ function Field(props) {
5046
5172
  const hasField = isFieldEnvelope(field);
5047
5173
  const hasValue = hasOwnProp(props, "value");
5048
5174
  const { editName, fieldValue, ref } = useBoundField(field, value, name, "Field");
5175
+ assertNamedEnvelope("Field", field);
5049
5176
  warnProjectionProps("Field", hasField, hasValue, name);
5050
5177
  if (warnNotScalarField("Field", field, fieldValue)) {
5051
5178
  return null;
@@ -5106,6 +5233,7 @@ function RichText(props) {
5106
5233
  name,
5107
5234
  "RichText"
5108
5235
  );
5236
+ assertNamedEnvelope("RichText", field);
5109
5237
  if (!hasField && !hasValueProp && !name) {
5110
5238
  return null;
5111
5239
  }
@@ -5217,6 +5345,7 @@ function Image(props) {
5217
5345
  ...imgProps
5218
5346
  } = props;
5219
5347
  const context = React2.useContext(ComponentContext);
5348
+ assertNamedEnvelope("Image", field);
5220
5349
  const coerced = coerceImageField(field, value, name);
5221
5350
  const boundField = coerced.field;
5222
5351
  const hasField = isFieldEnvelope(boundField);
@@ -5452,6 +5581,13 @@ function AmplifyUpProvider({
5452
5581
  description: "This page has not been published yet.",
5453
5582
  layoutTree: []
5454
5583
  };
5584
+ if (result.pageConfig) {
5585
+ sdk.applyResolvedPageData(
5586
+ result.pageConfig.pageData || null,
5587
+ result.pageConfig.route,
5588
+ extractRouteParams(result.pageConfig.route, actualRoute)
5589
+ );
5590
+ }
5455
5591
  setInitialized(true);
5456
5592
  setSource((prev) => prev === result.source ? prev : result.source);
5457
5593
  setMeta(
@@ -5464,13 +5600,6 @@ function AmplifyUpProvider({
5464
5600
  }
5465
5601
  return nextConfig;
5466
5602
  });
5467
- if (result.pageConfig) {
5468
- sdk.applyResolvedPageData(
5469
- result.pageConfig.pageData || null,
5470
- result.pageConfig.route,
5471
- extractRouteParams(result.pageConfig.route, actualRoute)
5472
- );
5473
- }
5474
5603
  loadedRouteRef.current = actualRoute;
5475
5604
  } catch (err) {
5476
5605
  if (cancelled) return;
@@ -5497,6 +5626,39 @@ function AmplifyUpProvider({
5497
5626
  config.clientPersonalization,
5498
5627
  pageContextKey
5499
5628
  ]);
5629
+ React2.useEffect(() => {
5630
+ const applyLayoutTree = (layoutTree) => {
5631
+ if (!Array.isArray(layoutTree)) return;
5632
+ setPageConfig((prev) => {
5633
+ const next = envelopePageConfig({
5634
+ ...prev || {
5635
+ id: "patched",
5636
+ route: getActualRoute(),
5637
+ title: "",
5638
+ layoutTree: []
5639
+ },
5640
+ layoutTree
5641
+ });
5642
+ return next;
5643
+ });
5644
+ setLoading(false);
5645
+ };
5646
+ const onMessage = (event) => {
5647
+ if (event.data?.type === "AMPLIFYUP_LAYOUT_PATCH") {
5648
+ applyLayoutTree(event.data.layoutTree);
5649
+ }
5650
+ };
5651
+ const onCustom = (event) => {
5652
+ const detail = event.detail || {};
5653
+ applyLayoutTree(detail.layoutTree);
5654
+ };
5655
+ window.addEventListener("message", onMessage);
5656
+ window.addEventListener("amplifyup:layout-patch", onCustom);
5657
+ return () => {
5658
+ window.removeEventListener("message", onMessage);
5659
+ window.removeEventListener("amplifyup:layout-patch", onCustom);
5660
+ };
5661
+ }, []);
5500
5662
  return /* @__PURE__ */ jsxRuntime.jsx(
5501
5663
  AmplifyUpContext.Provider,
5502
5664
  {