@amplifyup/sdk 0.1.62 → 0.1.64

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.
@@ -409,6 +409,16 @@ function isComposerPreview() {
409
409
 
410
410
  // src/field-envelope.ts
411
411
  var FIELDS_BRAND = Symbol("amplifyup.fields");
412
+ var IDENTIFIER_KEYS = /* @__PURE__ */ new Set([
413
+ "id",
414
+ "_id",
415
+ "slug",
416
+ "key",
417
+ "_key",
418
+ "docId",
419
+ "_type",
420
+ "type"
421
+ ]);
412
422
  function isBrandedFields(value) {
413
423
  return !!value && typeof value === "object" && FIELDS_BRAND in value;
414
424
  }
@@ -430,6 +440,76 @@ function isPortableImageShape(value) {
430
440
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
431
441
  return "url" in value;
432
442
  }
443
+ function isIdentifierKey(key) {
444
+ return IDENTIFIER_KEYS.has(key);
445
+ }
446
+ function isRecordList(value) {
447
+ if (!Array.isArray(value) || value.length === 0) return false;
448
+ const sample = value.find((item) => item != null);
449
+ if (sample === void 0) return false;
450
+ if (typeof sample !== "object" || Array.isArray(sample)) return false;
451
+ if (isPortableImageShape(sample)) return false;
452
+ if (sample.$$typeof) return false;
453
+ return true;
454
+ }
455
+ function isFieldRef(value) {
456
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
457
+ const rec = value;
458
+ return typeof rec.providerId === "string" && !!rec.providerId && typeof rec.entity === "string" && !!rec.entity && typeof rec.id === "string" && !!rec.id;
459
+ }
460
+ function isListOwner(value) {
461
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
462
+ const rec = value;
463
+ return typeof rec.providerId === "string" && !!rec.providerId && typeof rec.entity === "string" && !!rec.entity;
464
+ }
465
+ function composerStoreKey(name, ref, layoutNodeId) {
466
+ if (isFieldRef(ref)) {
467
+ return `record:${ref.providerId}:${ref.entity}:${ref.id}:${name}`;
468
+ }
469
+ return layoutNodeId ? `page:${layoutNodeId}:${name}` : name;
470
+ }
471
+ function listOwnerFromConnection(conn) {
472
+ if (!conn || typeof conn !== "object") return void 0;
473
+ if (conn.mode === "query") {
474
+ const providerId = String(conn.spec?.providerId || "").trim();
475
+ const entity = String(conn.spec?.entity || "").trim();
476
+ return providerId && entity ? { providerId, entity } : void 0;
477
+ }
478
+ if (conn.mode === "item" || conn.mode === "items") {
479
+ const providerId = String(conn.providerId || "").trim();
480
+ const entity = String(conn.entity || "").trim();
481
+ return providerId && entity ? { providerId, entity } : void 0;
482
+ }
483
+ return void 0;
484
+ }
485
+ function listOwnerFromSpec(spec) {
486
+ const providerId = String(spec?.providerId || "").trim();
487
+ const entity = String(spec?.entity || "").trim();
488
+ return providerId && entity ? { providerId, entity } : void 0;
489
+ }
490
+ function isEnvelopeSources(value) {
491
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
492
+ const rec = value;
493
+ return rec.connections != null || rec.reads != null;
494
+ }
495
+ function normalizeEnvelopeSources(sources) {
496
+ if (!sources) return {};
497
+ if (isEnvelopeSources(sources) && !("mode" in sources)) {
498
+ return sources;
499
+ }
500
+ return { connections: sources };
501
+ }
502
+ function listOwnerForField(fieldName, props, sources) {
503
+ const { connections, reads } = normalizeEnvelopeSources(sources);
504
+ const resourceName = reads?.[fieldName]?.resource || fieldName;
505
+ const fromConn = listOwnerFromConnection(connections?.[resourceName]);
506
+ if (fromConn) return fromConn;
507
+ const paging = props?.[`${fieldName}Pagination`];
508
+ if (paging && typeof paging === "object" && !Array.isArray(paging)) {
509
+ return listOwnerFromSpec(paging.spec);
510
+ }
511
+ return void 0;
512
+ }
433
513
  function joinPath(prefix, key) {
434
514
  return prefix ? `${prefix}.${key}` : key;
435
515
  }
@@ -437,39 +517,101 @@ function emptyValue(raw) {
437
517
  if (raw === void 0) return null;
438
518
  return raw;
439
519
  }
440
- function toFieldEnvelopes(source, prefix = "") {
520
+ function rowId(raw) {
521
+ const candidates = [raw.id, raw._id, raw.docId, raw.key, raw._key];
522
+ for (const c of candidates) {
523
+ if (typeof c === "string" && c.trim()) return c;
524
+ }
525
+ return "";
526
+ }
527
+ function withLeaf(envelope, scope) {
528
+ if (isFieldRef(scope?.ref)) envelope.ref = scope.ref;
529
+ else if (scope?.readOnly) envelope.readOnly = true;
530
+ return envelope;
531
+ }
532
+ function toFieldEnvelopes(source, prefix = "", scope) {
533
+ const ctx = isFieldRef(scope) ? { ref: scope } : scope || {};
441
534
  const input = source && typeof source === "object" && !Array.isArray(source) ? source : {};
442
535
  if (isBrandedFields(input)) {
443
536
  return input;
444
537
  }
445
538
  const out = {};
446
539
  for (const [key, raw] of Object.entries(input)) {
540
+ if (isIdentifierKey(key) && (typeof raw === "string" || raw == null)) {
541
+ out[key] = raw ?? "";
542
+ continue;
543
+ }
447
544
  const path = joinPath(prefix, key);
448
545
  if (isFieldEnvelope(raw)) {
449
- out[key] = { value: raw.value ?? null, name: raw.name || path };
546
+ const inner = raw.value;
547
+ if (isRecordList(inner)) {
548
+ const owner = ctx.owners?.(key);
549
+ out[key] = {
550
+ value: envelopeListRows(inner, owner),
551
+ name: raw.name || path
552
+ };
553
+ continue;
554
+ }
555
+ out[key] = withLeaf(
556
+ { value: raw.value ?? null, name: raw.name || path },
557
+ raw.ref ? { ref: raw.ref } : ctx
558
+ );
559
+ continue;
560
+ }
561
+ if (isRecordList(raw)) {
562
+ const owner = ctx.owners?.(key);
563
+ out[key] = { value: envelopeListRows(raw, owner), name: path };
450
564
  continue;
451
565
  }
452
566
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
453
- out[key] = toFieldEnvelopes(raw, path);
567
+ out[key] = toFieldEnvelopes(raw, path, ctx);
454
568
  continue;
455
569
  }
456
- out[key] = { value: emptyValue(raw), name: path };
570
+ out[key] = withLeaf({ value: emptyValue(raw), name: path }, ctx);
457
571
  }
458
572
  return brandFields(out);
459
573
  }
460
- function attachFieldEnvelopes(props) {
574
+ function envelopeListRows(items, owner) {
575
+ return items.map((item) => envelopeListRow(item, owner));
576
+ }
577
+ function envelopeListRow(item, owner) {
578
+ if (isBrandedFields(item) && typeof item.id === "string") {
579
+ return item;
580
+ }
581
+ const raw = item && typeof item === "object" && !Array.isArray(item) ? item : {};
582
+ const id = rowId(raw);
583
+ const ref = isListOwner(owner) && id ? { providerId: owner.providerId, entity: owner.entity, id } : void 0;
584
+ const fields = toFieldEnvelopes(raw, "", {
585
+ ref,
586
+ readOnly: !ref
587
+ });
588
+ const row = fields;
589
+ if (typeof row.id !== "string") {
590
+ row.id = id;
591
+ }
592
+ return row;
593
+ }
594
+ function attachFieldEnvelopes(props, sources) {
461
595
  const raw = props && typeof props === "object" ? { ...props } : {};
462
596
  if (isBrandedFields(raw.fields)) return raw;
463
597
  const { fields: existing, ...content } = raw;
464
598
  const source = existing && typeof existing === "object" && !isFieldEnvelope(existing) ? existing : content;
465
- return { ...raw, fields: toFieldEnvelopes(source) };
599
+ return {
600
+ ...raw,
601
+ fields: toFieldEnvelopes(source, "", {
602
+ owners: (fieldName) => listOwnerForField(fieldName, source, sources)
603
+ })
604
+ };
466
605
  }
467
606
  function walkLayoutNodes(nodes) {
468
607
  if (!Array.isArray(nodes)) return;
469
608
  for (const node of nodes) {
470
609
  if (!node || typeof node !== "object") continue;
471
610
  const rec = node;
472
- rec.props = attachFieldEnvelopes(rec.props);
611
+ rec.props = attachFieldEnvelopes(rec.props, {
612
+ connections: rec.resources,
613
+ reads: rec.reads
614
+ });
473
615
  for (const slot of rec.slots || []) {
474
616
  walkLayoutNodes(slot.children);
475
617
  }
@@ -483,15 +625,36 @@ function envelopePageConfig(page) {
483
625
  }
484
626
  function collectFieldPatches(props) {
485
627
  const out = [];
628
+ const walkRows = (items) => {
629
+ for (const item of items) {
630
+ if (isBrandedFields(item) || item && typeof item === "object" && !Array.isArray(item) && !isFieldEnvelope(item)) {
631
+ walk(item, "");
632
+ }
633
+ }
634
+ };
486
635
  const walk = (obj, prefix) => {
487
636
  for (const [key, raw] of Object.entries(obj)) {
637
+ if (isIdentifierKey(key)) continue;
488
638
  if (key === "fields" && raw && typeof raw === "object" && !Array.isArray(raw) && !isFieldEnvelope(raw)) {
489
639
  walk(raw, prefix);
490
640
  continue;
491
641
  }
492
642
  const path = joinPath(prefix, key);
493
643
  if (isFieldEnvelope(raw)) {
494
- out.push({ name: raw.name || path, value: raw.value });
644
+ if (isRecordList(raw.value)) {
645
+ walkRows(raw.value);
646
+ continue;
647
+ }
648
+ const patch = {
649
+ name: raw.name || path,
650
+ value: raw.value
651
+ };
652
+ if (raw.ref) patch.ref = raw.ref;
653
+ out.push(patch);
654
+ continue;
655
+ }
656
+ if (isRecordList(raw)) {
657
+ walkRows(raw);
495
658
  continue;
496
659
  }
497
660
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
@@ -3234,39 +3397,62 @@ var ComposerFieldStore = class {
3234
3397
  if (set.size === 0) this.listeners.delete(name);
3235
3398
  };
3236
3399
  }
3400
+ keys() {
3401
+ return [...this.values.keys()];
3402
+ }
3403
+ delete(name) {
3404
+ if (!name || !this.values.has(name)) return;
3405
+ this.values.delete(name);
3406
+ const set = this.listeners.get(name);
3407
+ if (!set) return;
3408
+ for (const fn of set) fn();
3409
+ }
3237
3410
  };
3238
3411
  var ComposerStoreContext = react.createContext(null);
3239
- function matchesNode(eventNodeId, layoutNodeId) {
3240
- if (eventNodeId && layoutNodeId && String(eventNodeId) !== String(layoutNodeId)) {
3241
- return false;
3242
- }
3243
- return true;
3412
+ var ComposerNodeContext = react.createContext(void 0);
3413
+ function applyComposerPatch(store, name, value, ref, layoutNodeId) {
3414
+ store.set(composerStoreKey(name, ref, layoutNodeId), value);
3244
3415
  }
3245
3416
  function ComposerProvider({
3246
- layoutNodeId,
3247
3417
  children
3248
3418
  }) {
3419
+ const existing = react.useContext(ComposerStoreContext);
3249
3420
  const storeRef = react.useRef(null);
3250
3421
  if (!storeRef.current) storeRef.current = new ComposerFieldStore();
3251
- const store = storeRef.current;
3422
+ const store = existing || storeRef.current;
3252
3423
  react.useEffect(() => {
3253
- const applyField = (fieldName, value, nodeId) => {
3424
+ if (existing) return;
3425
+ const applyField = (fieldName, value, nodeId, ref) => {
3254
3426
  if (!fieldName || typeof fieldName !== "string") return;
3255
- if (!matchesNode(nodeId, layoutNodeId)) return;
3256
- store.set(fieldName, value);
3427
+ const fieldRef = isFieldRef(ref) ? ref : void 0;
3428
+ const layoutNodeId = typeof nodeId === "string" && nodeId ? nodeId : void 0;
3429
+ applyComposerPatch(store, fieldName, value, fieldRef, layoutNodeId);
3257
3430
  };
3258
3431
  const applyProps = (nextProps, nodeId) => {
3259
3432
  if (!nextProps || typeof nextProps !== "object" || Array.isArray(nextProps)) {
3260
3433
  return;
3261
3434
  }
3262
- if (!matchesNode(nodeId, layoutNodeId)) return;
3263
- for (const patch of collectFieldPatches(nextProps)) {
3264
- store.set(patch.name, patch.value);
3435
+ const layoutNodeId = typeof nodeId === "string" && nodeId ? nodeId : void 0;
3436
+ for (const patch of collectFieldPatches(
3437
+ nextProps
3438
+ )) {
3439
+ applyComposerPatch(
3440
+ store,
3441
+ patch.name,
3442
+ patch.value,
3443
+ patch.ref,
3444
+ patch.ref ? void 0 : layoutNodeId
3445
+ );
3265
3446
  }
3266
3447
  };
3267
3448
  const onPatch = (event) => {
3268
3449
  const detail = event.detail || {};
3269
- applyField(detail.fieldName, detail.value, detail.layoutNodeId);
3450
+ applyField(
3451
+ detail.fieldName,
3452
+ detail.value,
3453
+ detail.layoutNodeId,
3454
+ detail.ref
3455
+ );
3270
3456
  };
3271
3457
  const onPropsPatch = (event) => {
3272
3458
  const detail = event.detail || {};
@@ -3278,7 +3464,12 @@ function ComposerProvider({
3278
3464
  return;
3279
3465
  }
3280
3466
  if (event.data?.type !== "AMPLIFYUP_FIELD_PATCH") return;
3281
- applyField(event.data.fieldName, event.data.value, event.data.layoutNodeId);
3467
+ applyField(
3468
+ event.data.fieldName,
3469
+ event.data.value,
3470
+ event.data.layoutNodeId,
3471
+ event.data.ref
3472
+ );
3282
3473
  };
3283
3474
  window.addEventListener("amplifyup:field-patch", onPatch);
3284
3475
  window.addEventListener("amplifyup:props-patch", onPropsPatch);
@@ -3288,7 +3479,8 @@ function ComposerProvider({
3288
3479
  window.removeEventListener("amplifyup:props-patch", onPropsPatch);
3289
3480
  window.removeEventListener("message", onMessage);
3290
3481
  };
3291
- }, [layoutNodeId, store]);
3482
+ }, [existing, store]);
3483
+ if (existing) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
3292
3484
  return /* @__PURE__ */ jsxRuntime.jsx(ComposerStoreContext.Provider, { value: store, children });
3293
3485
  }
3294
3486
  function MaybeComposerProvider({
@@ -3298,7 +3490,7 @@ function MaybeComposerProvider({
3298
3490
  }) {
3299
3491
  const content = react.useMemo(() => children, [children]);
3300
3492
  if (!enabled) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: content });
3301
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { layoutNodeId, children });
3493
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ComposerNodeContext.Provider, { value: layoutNodeId, children }) });
3302
3494
  }
3303
3495
  react.createContext(null);
3304
3496
  var usePathname = null;
@@ -3775,7 +3967,7 @@ function AmplifyRendererInner({
3775
3967
  if (layoutTree.length === 0) {
3776
3968
  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." }) }) });
3777
3969
  }
3778
- return /* @__PURE__ */ jsxRuntime.jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsxRuntime.jsx(
3970
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsxRuntime.jsx(
3779
3971
  "div",
3780
3972
  {
3781
3973
  "data-slot-id": "main",
@@ -3784,7 +3976,7 @@ function AmplifyRendererInner({
3784
3976
  "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
3785
3977
  children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: renderNode(node) }, node.id))
3786
3978
  }
3787
- ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: renderNode(node) }, node.id)) });
3979
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: renderNode(node) }, node.id)) }) });
3788
3980
  }
3789
3981
  var AmplifyRenderer = react.memo(AmplifyRendererInner);
3790
3982