@amplifyup/sdk 0.1.66 → 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.
@@ -434,6 +434,13 @@ function isFieldEnvelope(value) {
434
434
  const rec = value;
435
435
  return typeof rec.name === "string" && "value" in rec && !("url" in rec);
436
436
  }
437
+ var OBJECT_FIELD_KINDS = /* @__PURE__ */ new Set(["object", "array", "list"]);
438
+ function isLeafFieldKind(kind) {
439
+ if (typeof kind !== "string") return false;
440
+ const normalized = kind.trim().toLowerCase();
441
+ if (!normalized) return false;
442
+ return !OBJECT_FIELD_KINDS.has(normalized);
443
+ }
437
444
  function isPageResourceSentinel(value) {
438
445
  return !!value && typeof value === "object" && !Array.isArray(value) && typeof value.__amplifyupPageResource === "string";
439
446
  }
@@ -570,6 +577,10 @@ function toFieldEnvelopes(source, prefix = "", scope) {
570
577
  out[key] = { value: envelopeListRows(raw, owner), name: path };
571
578
  continue;
572
579
  }
580
+ if (ctx.leaf?.(path)) {
581
+ out[key] = withLeaf({ value: emptyValue(raw), name: path }, ctx);
582
+ continue;
583
+ }
573
584
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
574
585
  out[key] = toFieldEnvelopes(raw, path, ctx);
575
586
  continue;
@@ -598,15 +609,33 @@ function envelopeListRow(item, owner) {
598
609
  }
599
610
  return row;
600
611
  }
612
+ var warnedMissingFieldKind = /* @__PURE__ */ new Set();
613
+ function warnMissingFieldKind(fieldName) {
614
+ if (process.env.NODE_ENV === "production") return;
615
+ if (warnedMissingFieldKind.has(fieldName)) return;
616
+ warnedMissingFieldKind.add(fieldName);
617
+ console.warn(
618
+ `[AmplifyUp SDK] Field "${fieldName}" has no schema kind; using value-shape detection. Republish the component definition so its fields carry a type.`
619
+ );
620
+ }
601
621
  function attachFieldEnvelopes(props, sources) {
602
622
  const raw = props && typeof props === "object" ? { ...props } : {};
603
623
  if (isBrandedFields(raw.fields)) return raw;
604
624
  const { fields: existing, ...content } = raw;
605
625
  const source = existing && typeof existing === "object" && !isFieldEnvelope(existing) ? existing : content;
626
+ const { reads } = normalizeEnvelopeSources(sources);
627
+ if (reads) {
628
+ for (const [fieldName, read] of Object.entries(reads)) {
629
+ if (!read?.kind) warnMissingFieldKind(fieldName);
630
+ }
631
+ }
606
632
  return {
607
633
  ...raw,
608
634
  fields: toFieldEnvelopes(source, "", {
609
- owners: (fieldName) => listOwnerForField(fieldName, source, sources)
635
+ owners: (fieldName) => listOwnerForField(fieldName, source, sources),
636
+ // Top-level field paths equal field names; nested paths have no schema
637
+ // entry and fall back to shape-based handling.
638
+ leaf: (path) => isLeafFieldKind(reads?.[path]?.kind)
610
639
  })
611
640
  };
612
641
  }
@@ -853,6 +882,8 @@ function hydrateFieldsBag(bag, fields) {
853
882
  if (val && typeof val === "object" && !Array.isArray(val) && typeof val.name === "string" && "value" in val && !("url" in val)) {
854
883
  const env = val;
855
884
  out[key] = {
885
+ // Keep ref / readOnly / source — dropping them severs the write target.
886
+ ...val,
856
887
  name: env.name,
857
888
  value: isPageResourceSentinel2(env.value) ? hydratePageResourceValue(env.value, fields) : env.value
858
889
  };
@@ -934,6 +965,46 @@ function sdkDebugOnce(key, ...args) {
934
965
  console.log(...args);
935
966
  }
936
967
 
968
+ // src/content/layoutProviderCache.ts
969
+ var SETTLED_TTL_MS = 5e3;
970
+ var inflight = /* @__PURE__ */ new Map();
971
+ var settled = /* @__PURE__ */ new Map();
972
+ function layoutProviderCacheKey(opts) {
973
+ const route = (opts.route || "/").split("?")[0] || "/";
974
+ return [
975
+ route,
976
+ opts.trackingId || "",
977
+ opts.instanceId || "",
978
+ opts.preview ? "1" : "0",
979
+ opts.working ? "1" : "0",
980
+ opts.zoneId || "",
981
+ opts.compositionId || ""
982
+ ].join("|");
983
+ }
984
+ function getSettledLayoutProvider(key) {
985
+ const entry = settled.get(key);
986
+ if (!entry) return void 0;
987
+ if (Date.now() - entry.at > SETTLED_TTL_MS) {
988
+ settled.delete(key);
989
+ return void 0;
990
+ }
991
+ return entry.value;
992
+ }
993
+ function dedupeLayoutProviderFetch(key, fetchFn) {
994
+ const cached = getSettledLayoutProvider(key);
995
+ if (cached !== void 0) return Promise.resolve(cached);
996
+ const existing = inflight.get(key);
997
+ if (existing) return existing;
998
+ const pending = fetchFn().then((value) => {
999
+ settled.set(key, { value, at: Date.now() });
1000
+ return value;
1001
+ }).finally(() => {
1002
+ inflight.delete(key);
1003
+ });
1004
+ inflight.set(key, pending);
1005
+ return pending;
1006
+ }
1007
+
937
1008
  // src/index.ts
938
1009
  var DWELL_ACTIVITY_IDLE_MS = 2 * 60 * 1e3;
939
1010
  var DWELL_POLL_MS = 5e3;
@@ -1975,6 +2046,32 @@ Available Console Commands:
1975
2046
  */
1976
2047
  async fetchPageConfig(route, preview = false) {
1977
2048
  const url = this.buildLayoutProviderUrl(route, preview);
2049
+ const pageSearch = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
2050
+ const cacheKey = layoutProviderCacheKey({
2051
+ route,
2052
+ trackingId: this.getTrackingId(),
2053
+ instanceId: getInstanceId(),
2054
+ preview,
2055
+ working: pageSearch ? isWorkingContentRequest(pageSearch) : false,
2056
+ zoneId: pageSearch?.get("zoneId"),
2057
+ compositionId: pageSearch?.get("compositionId")
2058
+ });
2059
+ return dedupeLayoutProviderFetch(cacheKey, async () => {
2060
+ const startedAt = Date.now();
2061
+ sdkDebug("[AmplifyUp SDK] layout/provider request", {
2062
+ route,
2063
+ at: new Date(startedAt).toISOString()
2064
+ });
2065
+ const page = await this.fetchPageConfigUncached(url);
2066
+ sdkDebug("[AmplifyUp SDK] layout/provider response", {
2067
+ route,
2068
+ durationMs: Date.now() - startedAt,
2069
+ hasPage: !!page
2070
+ });
2071
+ return page;
2072
+ });
2073
+ }
2074
+ async fetchPageConfigUncached(url) {
1978
2075
  const response = await fetch(url);
1979
2076
  if (!response.ok) {
1980
2077
  if (response.status === 404) {
@@ -2333,6 +2430,12 @@ Available Console Commands:
2333
2430
  );
2334
2431
  return;
2335
2432
  }
2433
+ if (event.data?.type === "AMPLIFYUP_LAYOUT_PATCH") {
2434
+ window.dispatchEvent(
2435
+ new CustomEvent("amplifyup:layout-patch", { detail: event.data })
2436
+ );
2437
+ return;
2438
+ }
2336
2439
  if (event.data?.type === "COMPONENT_DELETABLE_STATUS") {
2337
2440
  const { componentId, deletable, nodeId } = event.data;
2338
2441
  const element = document.querySelector(`[data-component-id="${componentId}"]`);
@@ -3373,6 +3476,13 @@ function getSDK(adapter) {
3373
3476
  var trackContentView = (contentId, contentType, properties) => getSDK().trackContentView(contentId, contentType, properties);
3374
3477
  var refreshEventTracking = () => getSDK().refreshEventTracking();
3375
3478
  getSDK();
3479
+ function useComposerPreviewFlag(force = false) {
3480
+ const [detected, setDetected] = useState(false);
3481
+ useEffect(() => {
3482
+ if (!force && isComposerPreview()) setDetected(true);
3483
+ }, [force]);
3484
+ return force || detected;
3485
+ }
3376
3486
 
3377
3487
  // src/composer-store.ts
3378
3488
  var ComposerFieldStore = class {
@@ -3589,16 +3699,9 @@ function NodeWithFields({
3589
3699
  renderComponent,
3590
3700
  composerPreview
3591
3701
  }) {
3592
- return /* @__PURE__ */ jsx(
3593
- MaybeComposerProvider,
3594
- {
3595
- enabled: !!(composerPreview || isComposerPreview()),
3596
- layoutNodeId: nodeId,
3597
- children: renderComponent(componentId, props, slots, {
3598
- layoutNodeId: nodeId
3599
- })
3600
- }
3601
- );
3702
+ return /* @__PURE__ */ jsx(MaybeComposerProvider, { enabled: !!composerPreview, layoutNodeId: nodeId, children: renderComponent(componentId, props, slots, {
3703
+ layoutNodeId: nodeId
3704
+ }) });
3602
3705
  }
3603
3706
  function AmplifyRendererInner({
3604
3707
  renderComponent,
@@ -3609,6 +3712,7 @@ function AmplifyRendererInner({
3609
3712
  composerPreview
3610
3713
  }) {
3611
3714
  const clientHook = useAmplifyUp();
3715
+ const composerPreviewFlag = useComposerPreviewFlag(!!composerPreview);
3612
3716
  const pageConfig = serverPageConfig || clientHook.pageConfig || null;
3613
3717
  const loading = serverPageConfig ? false : clientHook.loading;
3614
3718
  const error = serverPageConfig ? null : clientHook.error;
@@ -3961,7 +4065,7 @@ function AmplifyRendererInner({
3961
4065
  props: nodeRenderProps(node),
3962
4066
  slots: slotsToPass,
3963
4067
  renderComponent,
3964
- composerPreview
4068
+ composerPreview: composerPreviewFlag
3965
4069
  }
3966
4070
  )
3967
4071
  }
@@ -3974,7 +4078,7 @@ function AmplifyRendererInner({
3974
4078
  if (layoutTree.length === 0) {
3975
4079
  return /* @__PURE__ */ jsx("main", { children: emptyComponent || /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
3976
4080
  }
3977
- return /* @__PURE__ */ jsx(ComposerProvider, { children: /* @__PURE__ */ jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsx(
4081
+ return /* @__PURE__ */ jsx(ComposerProvider, { children: /* @__PURE__ */ jsx("main", { children: composerPreviewFlag ? /* @__PURE__ */ jsx(
3978
4082
  "div",
3979
4083
  {
3980
4084
  "data-slot-id": "main",