@seedprotocol/sdk 0.4.20 → 0.4.21

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.
Files changed (181) hide show
  1. package/dist/{ArweaveClient-Ck4wflb3.js → ArweaveClient-Cz9ZLiEV.js} +3 -3
  2. package/dist/{ArweaveClient-Ck4wflb3.js.map → ArweaveClient-Cz9ZLiEV.js.map} +1 -1
  3. package/dist/{ArweaveClient-C1bakApw.js → ArweaveClient-DxpJnJXU.js} +3 -3
  4. package/dist/{ArweaveClient-C1bakApw.js.map → ArweaveClient-DxpJnJXU.js.map} +1 -1
  5. package/dist/{Db-CCMLWMi-.js → Db-CXwQVLZv.js} +41 -4
  6. package/dist/Db-CXwQVLZv.js.map +1 -0
  7. package/dist/{Db-YFg99EDt.js → Db-DkTBncAM.js} +4 -4
  8. package/dist/{Db-YFg99EDt.js.map → Db-DkTBncAM.js.map} +1 -1
  9. package/dist/{EasClient-BmYeAnq7.js → EasClient-DjpbHjU9.js} +2 -2
  10. package/dist/{EasClient-Bqzb-xF2.js.map → EasClient-DjpbHjU9.js.map} +1 -1
  11. package/dist/{EasClient-Bqzb-xF2.js → EasClient-JYkmHxu1.js} +2 -2
  12. package/dist/{EasClient-BmYeAnq7.js.map → EasClient-JYkmHxu1.js.map} +1 -1
  13. package/dist/{FileManager-rVAH7uNp.js → FileManager-CKyoLrBP.js} +2 -2
  14. package/dist/{FileManager-rVAH7uNp.js.map → FileManager-CKyoLrBP.js.map} +1 -1
  15. package/dist/{FileManager-Ba1qAT8_.js → FileManager-DHnyb040.js} +34 -5
  16. package/dist/FileManager-DHnyb040.js.map +1 -0
  17. package/dist/{ModelProperty-Csj84uQv.js → ModelProperty-DWtv9fQr.js} +24 -24
  18. package/dist/{ModelProperty-Csj84uQv.js.map → ModelProperty-DWtv9fQr.js.map} +1 -1
  19. package/dist/{PathResolver-CzhXp_OH.js → PathResolver-Ce4K9acQ.js} +2 -2
  20. package/dist/{PathResolver-CzhXp_OH.js.map → PathResolver-Ce4K9acQ.js.map} +1 -1
  21. package/dist/{PathResolver-B5XBxiLt.js → PathResolver-pmw--Ea2.js} +2 -2
  22. package/dist/{PathResolver-B5XBxiLt.js.map → PathResolver-pmw--Ea2.js.map} +1 -1
  23. package/dist/{QueryClient-5NAcOOvw.js → QueryClient-OUjfvY3g.js} +2 -2
  24. package/dist/{QueryClient-5NAcOOvw.js.map → QueryClient-OUjfvY3g.js.map} +1 -1
  25. package/dist/{QueryClient-BqpbpJEP.js → QueryClient-unspcsWa.js} +2 -2
  26. package/dist/{QueryClient-BqpbpJEP.js.map → QueryClient-unspcsWa.js.map} +1 -1
  27. package/dist/{Schema-QjwZN91G.js → Schema-CqqcEexA.js} +38 -38
  28. package/dist/{Schema-QjwZN91G.js.map → Schema-CqqcEexA.js.map} +1 -1
  29. package/dist/{SchemaValidationService-Cwkeb4fG.js → SchemaValidationService-Cb-b4kpD.js} +2 -2
  30. package/dist/{SchemaValidationService-Cwkeb4fG.js.map → SchemaValidationService-Cb-b4kpD.js.map} +1 -1
  31. package/dist/{backfillMetadataPropertyIds-DCYUHZDQ.js → backfillMetadataPropertyIds-CRyRez3h.js} +2 -2
  32. package/dist/{backfillMetadataPropertyIds-DCYUHZDQ.js.map → backfillMetadataPropertyIds-CRyRez3h.js.map} +1 -1
  33. package/dist/cjs/{ModelProperty-m4dACdoX.js → ModelProperty-sNx_ZQZX.js} +17 -17
  34. package/dist/cjs/{ModelProperty-m4dACdoX.js.map → ModelProperty-sNx_ZQZX.js.map} +1 -1
  35. package/dist/cjs/{Schema-DlSTkGtE.js → Schema-B4RRA-0g.js} +20 -20
  36. package/dist/cjs/{Schema-DlSTkGtE.js.map → Schema-B4RRA-0g.js.map} +1 -1
  37. package/dist/cjs/{SchemaValidationService-C06zlv2z.js → SchemaValidationService-DCflhpcI.js} +2 -2
  38. package/dist/cjs/{SchemaValidationService-C06zlv2z.js.map → SchemaValidationService-DCflhpcI.js.map} +1 -1
  39. package/dist/cjs/{backfillMetadataPropertyIds-gyFrK_ny.js → backfillMetadataPropertyIds-DhAXAuSf.js} +2 -2
  40. package/dist/cjs/{backfillMetadataPropertyIds-gyFrK_ny.js.map → backfillMetadataPropertyIds-DhAXAuSf.js.map} +1 -1
  41. package/dist/cjs/{getItem-gFz18nL2.js → getItem-lyM2x5pT.js} +5 -3
  42. package/dist/cjs/getItem-lyM2x5pT.js.map +1 -0
  43. package/dist/cjs/{getPublishPayload-DHNfV-GE.js → getPublishPayload-DP2fm4q8.js} +125 -26
  44. package/dist/cjs/getPublishPayload-DP2fm4q8.js.map +1 -0
  45. package/dist/cjs/{getPublishUploads-Dt-3g6eW.js → getPublishUploads-DdVy-5fK.js} +55 -14
  46. package/dist/cjs/getPublishUploads-DdVy-5fK.js.map +1 -0
  47. package/dist/cjs/{getSegmentedItemProperties-D3XpxCt8.js → getSegmentedItemProperties-DtHofn5i.js} +3 -3
  48. package/dist/cjs/{getSegmentedItemProperties-D3XpxCt8.js.map → getSegmentedItemProperties-DtHofn5i.js.map} +1 -1
  49. package/dist/cjs/{index-CHrEZZ71.js → index-D1qR8xnb.js} +1053 -386
  50. package/dist/cjs/index-D1qR8xnb.js.map +1 -0
  51. package/dist/cjs/{index-4M2KX6s4.js → index-DTkoTvcq.js} +5 -3
  52. package/dist/cjs/index-DTkoTvcq.js.map +1 -0
  53. package/dist/cjs/{ownership-CC_YF-XC.js → ownership-DanM_n8E.js} +4 -4
  54. package/dist/cjs/ownership-DanM_n8E.js.map +1 -0
  55. package/dist/cjs/{property-DtCxuPrc.js → property-BQokoaRe.js} +6 -4
  56. package/dist/cjs/{property-DtCxuPrc.js.map → property-BQokoaRe.js.map} +1 -1
  57. package/dist/db/drizzle/drizzle/0011_normalize_placeholder_uids.sql +9 -0
  58. package/dist/db/drizzle/drizzle/0012_html_embedded_image_co_publish.sql +10 -0
  59. package/dist/db/drizzle/drizzle/meta/_journal.json +14 -0
  60. package/dist/{getItem-CpjN3MFQ.js → getItem-VI3QqdZH.js} +5 -3
  61. package/dist/getItem-VI3QqdZH.js.map +1 -0
  62. package/dist/{getPublishPayload-CMhy9jfz.js → getPublishPayload-DpYwi-rd.js} +129 -30
  63. package/dist/getPublishPayload-DpYwi-rd.js.map +1 -0
  64. package/dist/{getPublishUploads-DTE4SEWk.js → getPublishUploads-DS2dQ4Ho.js} +55 -14
  65. package/dist/getPublishUploads-DS2dQ4Ho.js.map +1 -0
  66. package/dist/{getSegmentedItemProperties-DzPjQtcg.js → getSegmentedItemProperties-Bz5B4DSA.js} +3 -3
  67. package/dist/{getSegmentedItemProperties-DzPjQtcg.js.map → getSegmentedItemProperties-Bz5B4DSA.js.map} +1 -1
  68. package/dist/{index-C1HlP_fU.js → index-BrD_NNaX.js} +1054 -393
  69. package/dist/index-BrD_NNaX.js.map +1 -0
  70. package/dist/index-Cqf_DxkJ.js +19 -0
  71. package/dist/index-Cqf_DxkJ.js.map +1 -0
  72. package/dist/{index-dDmXPEJC.js → index-DdzhrbkF.js} +3 -2
  73. package/dist/index-DdzhrbkF.js.map +1 -0
  74. package/dist/main.cjs +1 -1
  75. package/dist/main.js +528 -41
  76. package/dist/main.js.map +1 -1
  77. package/dist/node.js +10 -10
  78. package/dist/{ownership-C7GyMbsf.js → ownership-BK6suksO.js} +4 -4
  79. package/dist/ownership-BK6suksO.js.map +1 -0
  80. package/dist/{property-BNt7Dkmw.js → property-C63Ddzap.js} +6 -6
  81. package/dist/{property-BNt7Dkmw.js.map → property-C63Ddzap.js.map} +1 -1
  82. package/dist/{queries-D09IIJg_.js → queries-BGuWjEqt.js} +2 -2
  83. package/dist/{queries-D09IIJg_.js.map → queries-BGuWjEqt.js.map} +1 -1
  84. package/dist/seedSchema/HtmlEmbeddedImageCoPublishSchema.ts +25 -0
  85. package/dist/seedSchema/index.ts +1 -0
  86. package/dist/src/Item/Item.d.ts +1 -1
  87. package/dist/src/Item/Item.d.ts.map +1 -1
  88. package/dist/src/Item/service/actors/loadOrCreateItem.d.ts.map +1 -1
  89. package/dist/src/Item/service/itemMachineSingle.d.ts +1 -1
  90. package/dist/src/ItemProperty/ItemProperty.d.ts +2 -2
  91. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  92. package/dist/src/ItemProperty/service/propertyMachine.d.ts +1 -1
  93. package/dist/src/Model/Model.d.ts +1 -1
  94. package/dist/src/Model/index.d.ts +1 -0
  95. package/dist/src/Model/index.d.ts.map +1 -1
  96. package/dist/src/Model/service/modelMachine.d.ts +3 -3
  97. package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +2 -2
  98. package/dist/src/Schema/Schema.d.ts +1 -1
  99. package/dist/src/Schema/service/schemaMachine.d.ts +3 -3
  100. package/dist/src/browser/db/drizzleFiles.d.ts +3 -1
  101. package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
  102. package/dist/src/browser/helpers/FileManager.d.ts.map +1 -1
  103. package/dist/src/client/ClientManager.d.ts.map +1 -1
  104. package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
  105. package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
  106. package/dist/src/client/events.d.ts +8 -0
  107. package/dist/src/client/events.d.ts.map +1 -0
  108. package/dist/src/db/read/batchLatestPublishedVersionBySeedLocalIds.d.ts +10 -0
  109. package/dist/src/db/read/batchLatestPublishedVersionBySeedLocalIds.d.ts.map +1 -0
  110. package/dist/src/db/read/getItem.d.ts.map +1 -1
  111. package/dist/src/db/read/getItemData.d.ts.map +1 -1
  112. package/dist/src/db/read/getItems.d.ts +9 -0
  113. package/dist/src/db/read/getItems.d.ts.map +1 -1
  114. package/dist/src/db/read/getLatestPublishedVersionRow.d.ts +11 -0
  115. package/dist/src/db/read/getLatestPublishedVersionRow.d.ts.map +1 -0
  116. package/dist/src/db/read/getMetadataAttestationUidsForSeedUid.d.ts.map +1 -1
  117. package/dist/src/db/read/getPublishPayload.d.ts.map +1 -1
  118. package/dist/src/db/read/getPublishPendingDiff.d.ts +3 -3
  119. package/dist/src/db/read/getPublishPendingDiff.d.ts.map +1 -1
  120. package/dist/src/db/read/getPublishUploads.d.ts +10 -0
  121. package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
  122. package/dist/src/db/read/getSeedPublishState.d.ts +21 -0
  123. package/dist/src/db/read/getSeedPublishState.d.ts.map +1 -0
  124. package/dist/src/db/read/subqueries/versionData.d.ts +7 -0
  125. package/dist/src/db/read/subqueries/versionData.d.ts.map +1 -1
  126. package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts +17 -0
  127. package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -0
  128. package/dist/src/db/write/updateSeedUid.d.ts +3 -1
  129. package/dist/src/db/write/updateSeedUid.d.ts.map +1 -1
  130. package/dist/src/db/write/updateVersionUid.d.ts +3 -1
  131. package/dist/src/db/write/updateVersionUid.d.ts.map +1 -1
  132. package/dist/src/helpers/ArweaveClient/uploadApiVerification.d.ts +5 -1
  133. package/dist/src/helpers/ArweaveClient/uploadApiVerification.d.ts.map +1 -1
  134. package/dist/src/helpers/constants.d.ts +2 -0
  135. package/dist/src/helpers/constants.d.ts.map +1 -1
  136. package/dist/src/helpers/easUid.d.ts +13 -0
  137. package/dist/src/helpers/easUid.d.ts.map +1 -0
  138. package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts +55 -0
  139. package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -0
  140. package/dist/src/helpers/index.d.ts +2 -0
  141. package/dist/src/helpers/index.d.ts.map +1 -1
  142. package/dist/src/helpers/mediaRef.d.ts +72 -0
  143. package/dist/src/helpers/mediaRef.d.ts.map +1 -0
  144. package/dist/src/helpers/ownership.d.ts +2 -2
  145. package/dist/src/helpers/property/index.d.ts +30 -0
  146. package/dist/src/helpers/property/index.d.ts.map +1 -1
  147. package/dist/src/helpers/publishConfig.d.ts +3 -4
  148. package/dist/src/helpers/publishConfig.d.ts.map +1 -1
  149. package/dist/src/helpers/waitForEntityIdle.d.ts.map +1 -1
  150. package/dist/src/index.d.ts +13 -1
  151. package/dist/src/index.d.ts.map +1 -1
  152. package/dist/src/interfaces/IItem.d.ts +1 -1
  153. package/dist/src/interfaces/IItem.d.ts.map +1 -1
  154. package/dist/src/seedSchema/HtmlEmbeddedImageCoPublishSchema.d.ts +122 -0
  155. package/dist/src/seedSchema/HtmlEmbeddedImageCoPublishSchema.d.ts.map +1 -0
  156. package/dist/src/seedSchema/index.d.ts +1 -0
  157. package/dist/src/seedSchema/index.d.ts.map +1 -1
  158. package/dist/src/services/write/writeProcessMachine.d.ts +1 -1
  159. package/dist/src/types/index.d.ts +6 -0
  160. package/dist/src/types/index.d.ts.map +1 -1
  161. package/dist/src/types/item.d.ts +3 -0
  162. package/dist/src/types/item.d.ts.map +1 -1
  163. package/dist/src/types/machines.d.ts +2 -0
  164. package/dist/src/types/machines.d.ts.map +1 -1
  165. package/package.json +2 -1
  166. package/dist/Db-CCMLWMi-.js.map +0 -1
  167. package/dist/FileManager-Ba1qAT8_.js.map +0 -1
  168. package/dist/cjs/getItem-gFz18nL2.js.map +0 -1
  169. package/dist/cjs/getPublishPayload-DHNfV-GE.js.map +0 -1
  170. package/dist/cjs/getPublishUploads-Dt-3g6eW.js.map +0 -1
  171. package/dist/cjs/index-4M2KX6s4.js.map +0 -1
  172. package/dist/cjs/index-CHrEZZ71.js.map +0 -1
  173. package/dist/cjs/ownership-CC_YF-XC.js.map +0 -1
  174. package/dist/getItem-CpjN3MFQ.js.map +0 -1
  175. package/dist/getPublishPayload-CMhy9jfz.js.map +0 -1
  176. package/dist/getPublishUploads-DTE4SEWk.js.map +0 -1
  177. package/dist/index-C1HlP_fU.js.map +0 -1
  178. package/dist/index-DvUyNZc9.js +0 -19
  179. package/dist/index-DvUyNZc9.js.map +0 -1
  180. package/dist/index-dDmXPEJC.js.map +0 -1
  181. package/dist/ownership-C7GyMbsf.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { waitFor, fromCallback, fromPromise, setup, assign, createActor } from 'xstate';
2
2
  import { sqliteTable, integer, text, unique, int, blob, uniqueIndex } from 'drizzle-orm/sqlite-core';
3
- import { relations, eq, and, isNull, isNotNull, not, or, max, count, getTableColumns, sql, inArray, gt, desc } from 'drizzle-orm';
3
+ import { relations, and, eq, isNull, isNotNull, not, or, max, count, getTableColumns, sql, desc, inArray, gt } from 'drizzle-orm';
4
4
  import { customAlphabet } from 'nanoid';
5
5
  import * as nanoIdDictionary from 'nanoid-dictionary';
6
6
  import debug from 'debug';
@@ -304,6 +304,8 @@ const INTERNAL_DATA_TYPES = {
304
304
  eas: 'bytes32',
305
305
  },
306
306
  };
307
+ /** Full property names ending in `Id` that must not be stripped to a “base” name for `allProperties` keys. */
308
+ const PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP = new Set(['storageTransactionId']);
307
309
  const INTERNAL_PROPERTY_NAMES = [
308
310
  'localId',
309
311
  'uid',
@@ -388,6 +390,7 @@ var constants = /*#__PURE__*/Object.freeze({
388
390
  INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
389
391
  INTERNAL_SCHEMA_IDS: INTERNAL_SCHEMA_IDS,
390
392
  get ImageSize () { return ImageSize; },
393
+ PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP: PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP,
391
394
  SCHEMA_NJK: SCHEMA_NJK,
392
395
  SCHEMA_TS: SCHEMA_TS,
393
396
  SEED_CONFIG_FALLBACKS: SEED_CONFIG_FALLBACKS,
@@ -567,14 +570,19 @@ function getUploadApiArweaveDataUrl(baseUrl, txOrDataItemId) {
567
570
  const id = encodeURIComponent(txOrDataItemId);
568
571
  return `${base}/api/upload/arweave/data/${id}`;
569
572
  }
573
+ const DEFAULT_UPLOAD_STATUS_TIMEOUT_MS = 45000;
570
574
  /**
571
575
  * Presence check against the upload API data route (same semantics as
572
576
  * {@link BaseArweaveClient.getTransactionStatus} for gateways: 200 = present, 404 = missing).
573
577
  */
574
- async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItemId) {
578
+ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItemId, options) {
575
579
  const url = getUploadApiArweaveDataUrl(uploadApiBaseUrl, txOrDataItemId);
580
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_UPLOAD_STATUS_TIMEOUT_MS;
581
+ const controller = new AbortController();
582
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
576
583
  try {
577
- const response = await fetch(url);
584
+ const response = await fetch(url, { signal: controller.signal });
585
+ clearTimeout(timeoutId);
578
586
  if (response.status === 404) {
579
587
  return { status: 404, confirmed: null };
580
588
  }
@@ -586,7 +594,11 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
586
594
  }
587
595
  return { status: 200, confirmed: null };
588
596
  }
589
- catch {
597
+ catch (err) {
598
+ clearTimeout(timeoutId);
599
+ if (err instanceof Error && err.name === 'AbortError') {
600
+ return { status: 504, confirmed: null };
601
+ }
590
602
  return { status: 500, confirmed: null };
591
603
  }
592
604
  }
@@ -728,8 +740,18 @@ async function waitForEntityIdle(entity, options = {}) {
728
740
  const { timeout = 5000, throwOnError = true } = options;
729
741
  const service = entity.getService();
730
742
  const currentSnapshot = service.getSnapshot();
743
+ const isSnapshotIdle = (snapshot) => {
744
+ if (!('value' in snapshot) || snapshot.value !== 'idle') {
745
+ return false;
746
+ }
747
+ // ItemProperty: same condition as ItemProperty.save() — nested "saving" uses object state values
748
+ if (snapshot.context?.isSaving) {
749
+ return false;
750
+ }
751
+ return true;
752
+ };
731
753
  // Check current state first - if already idle, return immediately
732
- if ('value' in currentSnapshot && currentSnapshot.value === 'idle') {
754
+ if (isSnapshotIdle(currentSnapshot)) {
733
755
  return;
734
756
  }
735
757
  if ('value' in currentSnapshot && currentSnapshot.value === 'error') {
@@ -746,13 +768,18 @@ async function waitForEntityIdle(entity, options = {}) {
746
768
  }
747
769
  return true; // Accept error state if not throwing
748
770
  }
749
- return 'value' in snapshot && snapshot.value === 'idle';
771
+ return isSnapshotIdle(snapshot);
750
772
  }, { timeout });
751
773
  }
752
774
  catch (error) {
753
775
  if (error.message === 'Entity failed to load') {
754
776
  throw error;
755
777
  }
778
+ const msg = typeof error?.message === 'string' ? error.message : '';
779
+ const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
780
+ if (!throwOnError && isWaitForTimeout) {
781
+ return;
782
+ }
756
783
  throw new Error(`Entity loading timeout after ${timeout}ms`);
757
784
  }
758
785
  }
@@ -904,6 +931,11 @@ const TStorageType = Type.Union([
904
931
  Type.Literal('ItemStorage'), // Looks for a storageTransactionId property on the item
905
932
  Type.Literal('PropertyStorage'), // Looks for a storageTransactionId value on the property
906
933
  ]);
934
+ /** How publish handles `data:image/*` URIs inside Html storage. Only applies when `dataType === 'Html'`. */
935
+ const THtmlEmbeddedDataUriPolicy = Type.Union([
936
+ Type.Literal('materialize'),
937
+ Type.Literal('preserve'),
938
+ ]);
907
939
  const TProperty = Type.Object({
908
940
  id: Type.Optional(Type.String()), // schemaFileId (string) - public ID
909
941
  _dbId: Type.Optional(Type.Number()), // Database integer ID - internal only
@@ -921,6 +953,8 @@ const TProperty = Type.Object({
921
953
  filenameSuffix: Type.Optional(Type.String()),
922
954
  validation: Type.Optional(TValidationRules),
923
955
  required: Type.Optional(Type.Boolean()),
956
+ /** When set on an Html property: `materialize` uploads embedded images as Image seeds and rewrites src; `preserve` leaves data URIs. */
957
+ htmlEmbeddedDataUriPolicy: Type.Optional(THtmlEmbeddedDataUriPolicy),
924
958
  });
925
959
  const TPropertyConstructor = Type.Function([
926
960
  Type.Optional(Type.Union([Type.String(), TStorageType, Type.Undefined()])),
@@ -928,6 +962,14 @@ const TPropertyConstructor = Type.Function([
928
962
  Type.Optional(Type.Union([Type.String(), Type.Boolean()])),
929
963
  ], TProperty);
930
964
  const TPropertyDefs = Type.Record(TPropertyDataType, TPropertyConstructor);
965
+ function htmlPropertyFactory(opts) {
966
+ return {
967
+ dataType: ModelPropertyDataTypes.Html,
968
+ ...(opts?.htmlEmbeddedDataUriPolicy
969
+ ? { htmlEmbeddedDataUriPolicy: opts.htmlEmbeddedDataUriPolicy }
970
+ : {}),
971
+ };
972
+ }
931
973
  const Property = {
932
974
  Text: (storageType, localStorageDir, filenameSuffix) => ({
933
975
  dataType: ModelPropertyDataTypes.Text,
@@ -960,7 +1002,8 @@ const Property = {
960
1002
  Image: () => ({ dataType: ModelPropertyDataTypes.Image }),
961
1003
  Boolean: () => ({ dataType: ModelPropertyDataTypes.Boolean }),
962
1004
  Date: () => ({ dataType: ModelPropertyDataTypes.Date }),
963
- Html: () => ({ dataType: ModelPropertyDataTypes.Html }),
1005
+ Html: htmlPropertyFactory,
1006
+ /** `Html` opts are not representable in `TPropertyConstructor`; keep runtime shape via double assert. */
964
1007
  };
965
1008
  const PropertyMetadataKey = Symbol('property');
966
1009
  const PropertyConstructor = (propertyType) => {
@@ -979,6 +1022,7 @@ const Relation = (ref, refValueType, required) => PropertyConstructor(Property.R
979
1022
  const List = (refValueType, ref) => PropertyConstructor(Property.List(refValueType, ref));
980
1023
  const Boolean$1 = () => PropertyConstructor(Property.Boolean());
981
1024
  const Date$1 = () => PropertyConstructor(Property.Date());
1025
+ const Html = (opts) => PropertyConstructor(htmlPropertyFactory(opts));
982
1026
 
983
1027
  /**
984
1028
  * For a schema property key like `authors` (List of Relation to Identity), returns the
@@ -1136,24 +1180,499 @@ function normalizeRelationPropertyValue(value) {
1136
1180
  if (typeof o.seedLocalId === 'string' && o.seedLocalId.trim() !== '') {
1137
1181
  return o.seedLocalId.trim();
1138
1182
  }
1139
- if (typeof o.seedUid === 'string' && o.seedUid.trim() !== '') {
1140
- return o.seedUid.trim();
1183
+ if (typeof o.seedUid === 'string' && o.seedUid.trim() !== '') {
1184
+ return o.seedUid.trim();
1185
+ }
1186
+ }
1187
+ return undefined;
1188
+ }
1189
+ /** getCorrectId only accepts 10-char local ids and 0x66 uids; local seed refs can be up to 21 chars. */
1190
+ const LOCAL_SEED_REF = /^[a-zA-Z0-9_-]{10,21}$/;
1191
+ /** Resolve seed ids from a single string (context propertyValue or DB row). */
1192
+ function resolveSeedIdsFromRefString(s) {
1193
+ const fromCorrect = parseLocalIdOrUid(s);
1194
+ if (fromCorrect.localId || fromCorrect.uid) {
1195
+ return { seedLocalId: fromCorrect.localId, seedUid: fromCorrect.uid };
1196
+ }
1197
+ if (LOCAL_SEED_REF.test(s) && !s.startsWith('0x')) {
1198
+ return { seedLocalId: s };
1199
+ }
1200
+ return {};
1201
+ }
1202
+
1203
+ const seeds = sqliteTable('seeds', {
1204
+ localId: text('local_id').unique(),
1205
+ uid: text('uid'),
1206
+ schemaUid: text('schema_uid'),
1207
+ type: text('type'),
1208
+ publisher: text('publisher'),
1209
+ attestationRaw: text('attestation_raw'),
1210
+ attestationCreatedAt: int('attestation_created_at'),
1211
+ createdAt: int('created_at'),
1212
+ updatedAt: int('updated_at'),
1213
+ _markedForDeletion: int('_marked_for_deletion'),
1214
+ revokedAt: int('revoked_at'),
1215
+ });
1216
+
1217
+ const versions = sqliteTable('versions', {
1218
+ localId: text('local_id').unique(),
1219
+ uid: text('uid'),
1220
+ seedLocalId: text('seed_local_id'),
1221
+ seedUid: text('seed_uid'),
1222
+ seedType: text('seed_type'),
1223
+ note: text('note'),
1224
+ createdAt: int('created_at'),
1225
+ updatedAt: int('updated_at'),
1226
+ attestationCreatedAt: int('attestation_created_at'),
1227
+ attestationRaw: text('attestation_raw'),
1228
+ publisher: text('publisher'),
1229
+ });
1230
+
1231
+ const metadata$1 = sqliteTable('metadata', {
1232
+ localId: text('local_id').unique(),
1233
+ uid: text('uid'),
1234
+ propertyId: integer('property_id').references(() => properties.id),
1235
+ propertyName: text('property_name'),
1236
+ propertyValue: text('property_value'),
1237
+ schemaUid: text('schema_uid'),
1238
+ modelType: text('model_type'),
1239
+ seedLocalId: text('seed_local_id'),
1240
+ seedUid: text('seed_uid'),
1241
+ versionLocalId: text('version_local_id'),
1242
+ versionUid: text('version_uid'),
1243
+ easDataType: text('eas_data_type'),
1244
+ refValueType: text('ref_value_type'),
1245
+ refModelUid: text('ref_schema_uid'),
1246
+ refSeedType: text('ref_seed_type'),
1247
+ refResolvedValue: text('ref_resolved_value'),
1248
+ refResolvedDisplayValue: text('ref_resolved_display_value'),
1249
+ localStorageDir: text('local_storage_dir'),
1250
+ attestationRaw: text('attestation_raw'),
1251
+ attestationCreatedAt: int('attestation_created_at'),
1252
+ contentHash: text('content_hash'),
1253
+ createdAt: int('created_at'),
1254
+ updatedAt: int('updated_at'),
1255
+ publisher: text('publisher'),
1256
+ });
1257
+
1258
+ const appState = sqliteTable('appState', {
1259
+ key: text('key').unique(),
1260
+ value: text('value'),
1261
+ createdAt: int('created_at'),
1262
+ updatedAt: int('updated_at'),
1263
+ });
1264
+
1265
+ const modelUids = sqliteTable('model_uids', {
1266
+ id: int('id').primaryKey({ autoIncrement: true }),
1267
+ uid: text('uid').notNull(),
1268
+ modelId: int('model_id')
1269
+ .notNull()
1270
+ .unique()
1271
+ .references(() => models$1.id),
1272
+ });
1273
+ const modelRelations = relations(modelUids, ({ one }) => ({
1274
+ model: one(models$1),
1275
+ }));
1276
+
1277
+ const propertyUids = sqliteTable('property_uids', {
1278
+ id: int('id').primaryKey({ autoIncrement: true }),
1279
+ uid: text('uid').notNull(),
1280
+ propertyId: int('property_id')
1281
+ .notNull()
1282
+ .unique()
1283
+ .references(() => properties.id),
1284
+ });
1285
+ const propertyUidRelations = relations(propertyUids, ({ one }) => ({
1286
+ property: one(properties),
1287
+ }));
1288
+
1289
+ const config = sqliteTable('config', {
1290
+ id: integer('id').primaryKey({ autoIncrement: true }),
1291
+ key: text('key').notNull(),
1292
+ text: text('text'),
1293
+ json: text('json'),
1294
+ blob: blob('blob'),
1295
+ });
1296
+
1297
+ const schemas = sqliteTable('schemas', {
1298
+ id: integer('id').primaryKey({ autoIncrement: true }),
1299
+ name: text('name').notNull(),
1300
+ version: integer('version').notNull(),
1301
+ schemaFileId: text('schema_file_id'), // ID from JSON file for change tracking - must be unique
1302
+ schemaData: text('schema_data'), // Full JSON schema content (SchemaFileFormat as JSON string)
1303
+ isDraft: integer('is_draft', { mode: 'boolean' }), // true if schema is in draft/editing state, false if published to file
1304
+ isEdited: integer('is_edited', { mode: 'boolean' }), // true if schema has been edited locally, false if matches schema file
1305
+ createdAt: int('created_at'),
1306
+ updatedAt: int('updated_at'),
1307
+ }, (table) => {
1308
+ return {
1309
+ uniqueSchemaFileId: unique('unique_schema_schema_file_id').on(table.schemaFileId),
1310
+ };
1311
+ });
1312
+
1313
+ var SchemaSchema = /*#__PURE__*/Object.freeze({
1314
+ __proto__: null,
1315
+ schemas: schemas
1316
+ });
1317
+
1318
+ const modelSchemas = sqliteTable('model_schemas', {
1319
+ id: integer('id').primaryKey({ autoIncrement: true }),
1320
+ modelId: integer('model_id').references(() => models$1.id),
1321
+ schemaId: integer('schema_id').references(() => schemas.id),
1322
+ });
1323
+
1324
+ var ModelSchemaSchema = /*#__PURE__*/Object.freeze({
1325
+ __proto__: null,
1326
+ modelSchemas: modelSchemas
1327
+ });
1328
+
1329
+ const publishProcesses = sqliteTable('publish_processes', {
1330
+ id: int('id').primaryKey({ autoIncrement: true }),
1331
+ seedLocalId: text('seed_local_id').notNull(),
1332
+ modelName: text('model_name').notNull(),
1333
+ schemaId: text('schema_id'),
1334
+ status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed' | 'interrupted'
1335
+ startedAt: int('started_at').notNull(),
1336
+ completedAt: int('completed_at'),
1337
+ errorMessage: text('error_message'),
1338
+ errorStep: text('error_step'),
1339
+ errorDetails: text('error_details'),
1340
+ persistedSnapshot: text('persisted_snapshot').notNull(),
1341
+ seedId: text('seed_id'),
1342
+ existingSeedUid: text('existing_seed_uid'),
1343
+ createdAt: int('created_at'),
1344
+ updatedAt: int('updated_at'),
1345
+ });
1346
+
1347
+ const uploadProcesses = sqliteTable('upload_processes', {
1348
+ id: int('id').primaryKey({ autoIncrement: true }),
1349
+ reimbursementConfirmed: int('reimbursement_confirmed').notNull(), // 0 or 1 for boolean
1350
+ reimbursementTransactionId: text('reimbursement_transaction_id'),
1351
+ transactionKeys: text('transaction_keys'),
1352
+ persistedSnapshot: text('persisted_snapshot').notNull(), // JSON string
1353
+ createdAt: int('created_at'),
1354
+ updatedAt: int('updated_at'),
1355
+ });
1356
+
1357
+ /** Background job: resolve L1 tx id and wait for L1 confirmation after bundler publish. */
1358
+ const arweaveL1FinalizeJobs = sqliteTable('arweave_l1_finalize_jobs', {
1359
+ id: int('id').primaryKey({ autoIncrement: true }),
1360
+ seedLocalId: text('seed_local_id').notNull(),
1361
+ dataItemId: text('data_item_id').notNull(),
1362
+ /** L1 bundle / anchor transaction id from gateway GraphQL `bundledIn.id`. */
1363
+ l1TransactionId: text('l1_transaction_id'),
1364
+ bundleId: text('bundle_id'),
1365
+ versionLocalId: text('version_local_id'),
1366
+ itemPropertyName: text('item_property_name'),
1367
+ /** `pending_l1` | `confirmed` | `failed` */
1368
+ phase: text('phase').notNull(),
1369
+ statusJson: text('status_json'),
1370
+ errorMessage: text('error_message'),
1371
+ createdAt: int('created_at').notNull(),
1372
+ updatedAt: int('updated_at').notNull(),
1373
+ }, (table) => ({
1374
+ dataItemIdUnique: uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
1375
+ }));
1376
+
1377
+ /**
1378
+ * Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
1379
+ * Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
1380
+ */
1381
+ const htmlEmbeddedImageCoPublish = sqliteTable('html_embedded_image_co_publish', {
1382
+ id: int('id').primaryKey({ autoIncrement: true }),
1383
+ parentSeedLocalId: text('parent_seed_local_id').notNull(),
1384
+ htmlSeedLocalId: text('html_seed_local_id').notNull(),
1385
+ imageSeedLocalId: text('image_seed_local_id').notNull(),
1386
+ /** Stable dedup key (e.g. sha256 of data URI or normalized URI string). */
1387
+ stableKey: text('stable_key').notNull(),
1388
+ createdAt: int('created_at').notNull(),
1389
+ }, (t) => [
1390
+ uniqueIndex('html_embed_co_pub_parent_html_stable').on(t.parentSeedLocalId, t.htmlSeedLocalId, t.stableKey),
1391
+ ]);
1392
+
1393
+ const seedUidToStorageTransactionId = new Map();
1394
+ const getStorageTransactionIdForSeedUid = async (seedUid) => {
1395
+ if (seedUidToStorageTransactionId.has(seedUid)) {
1396
+ return seedUidToStorageTransactionId.get(seedUid);
1397
+ }
1398
+ const appDb = BaseDb.getAppDb();
1399
+ const results = (await appDb
1400
+ .select({
1401
+ storageTransactionId: metadata$1.propertyValue,
1402
+ })
1403
+ .from(metadata$1)
1404
+ .where(and(eq(metadata$1.seedUid, seedUid), eq(metadata$1.propertyName, 'storageTransactionId'))));
1405
+ if (!results || results.length === 0) {
1406
+ return;
1407
+ }
1408
+ seedUidToStorageTransactionId.set(seedUid, results[0].storageTransactionId);
1409
+ return results[0].storageTransactionId;
1410
+ };
1411
+
1412
+ const logger$v = debug('seedSdk:helpers:mediaRef');
1413
+ /** Typical Arweave transaction id: 43 URL-safe base64 characters. */
1414
+ const ARWEAVE_TX_ID = /^[a-zA-Z0-9_-]{43}$/;
1415
+ function trimOrEmpty(raw) {
1416
+ if (raw == null)
1417
+ return '';
1418
+ return typeof raw === 'string' ? raw.trim() : String(raw).trim();
1419
+ }
1420
+ function coalesceStringField(item, key) {
1421
+ const v = item[key];
1422
+ if (v == null)
1423
+ return '';
1424
+ if (typeof v === 'string')
1425
+ return v.trim();
1426
+ if (typeof v === 'number' || typeof v === 'boolean')
1427
+ return String(v);
1428
+ return '';
1429
+ }
1430
+ /**
1431
+ * Try JSON relation payloads and plain relation id strings.
1432
+ */
1433
+ function unwrapRelationString(raw) {
1434
+ const t = raw.trim();
1435
+ if (!t)
1436
+ return t;
1437
+ try {
1438
+ const parsed = JSON.parse(t);
1439
+ const fromObj = normalizeRelationPropertyValue(parsed);
1440
+ if (fromObj)
1441
+ return fromObj;
1442
+ }
1443
+ catch {
1444
+ // not JSON
1445
+ }
1446
+ return t;
1447
+ }
1448
+ /**
1449
+ * Pure, sync classification of a media-related string from feeds or XML.
1450
+ */
1451
+ function classifyMediaRef(raw, options) {
1452
+ const s = trimOrEmpty(raw);
1453
+ if (!s) {
1454
+ return { kind: 'empty' };
1455
+ }
1456
+ const treatAs = options?.treatAs;
1457
+ if (treatAs === 'url') {
1458
+ return { kind: 'url', href: s };
1459
+ }
1460
+ if (treatAs === 'arweaveTx') {
1461
+ return { kind: 'arweaveTxId', txId: s };
1462
+ }
1463
+ if (treatAs === 'seedUid') {
1464
+ if (s.startsWith('0x') && s.length === 66) {
1465
+ return { kind: 'seedUid', uid: s };
1466
+ }
1467
+ return { kind: 'unknown', raw: s };
1468
+ }
1469
+ if (s.startsWith('http://') || s.startsWith('https://') || s.startsWith('blob:') || s.startsWith('data:')) {
1470
+ return { kind: 'url', href: s };
1471
+ }
1472
+ const unwrapped = unwrapRelationString(s);
1473
+ const ids = resolveSeedIdsFromRefString(unwrapped);
1474
+ if (ids.seedUid) {
1475
+ return { kind: 'seedUid', uid: ids.seedUid };
1476
+ }
1477
+ if (ids.seedLocalId) {
1478
+ return { kind: 'seedLocalId', localId: ids.seedLocalId };
1479
+ }
1480
+ if (unwrapped.startsWith('0x') && unwrapped.length === 66) {
1481
+ return { kind: 'seedUid', uid: unwrapped };
1482
+ }
1483
+ if (ARWEAVE_TX_ID.test(unwrapped) && !unwrapped.startsWith('0x')) {
1484
+ return { kind: 'arweaveTxId', txId: unwrapped };
1485
+ }
1486
+ return { kind: 'unknown', raw: s };
1487
+ }
1488
+ /**
1489
+ * Same as convertTxIdToImage but local to this module to avoid circular imports with helpers/index.
1490
+ */
1491
+ async function tryLocalBlobUrlFromTxId(txId) {
1492
+ const imageFilePath = BaseFileManager.getFilesPath('images', txId);
1493
+ const fileExists = await BaseFileManager.pathExists(imageFilePath);
1494
+ if (!fileExists) {
1495
+ logger$v(`[tryLocalBlobUrlFromTxId] ${imageFilePath} does not exist`);
1496
+ return undefined;
1497
+ }
1498
+ const buffer = await BaseFileManager.readFileAsBuffer(imageFilePath);
1499
+ let arrayBuffer;
1500
+ if (buffer instanceof Blob) {
1501
+ arrayBuffer = await buffer.arrayBuffer();
1502
+ }
1503
+ else if (buffer instanceof ArrayBuffer) {
1504
+ arrayBuffer = buffer;
1505
+ }
1506
+ else {
1507
+ const sliced = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
1508
+ if (sliced instanceof SharedArrayBuffer) {
1509
+ const uint8Array = new Uint8Array(sliced);
1510
+ arrayBuffer = uint8Array.buffer.slice(0);
1511
+ }
1512
+ else {
1513
+ arrayBuffer = sliced;
1514
+ }
1515
+ }
1516
+ const uint = new Uint8Array(arrayBuffer);
1517
+ const imageBlob = new Blob([uint]);
1518
+ return URL.createObjectURL(imageBlob);
1519
+ }
1520
+ async function resolveTxId(txId) {
1521
+ const local = await tryLocalBlobUrlFromTxId(txId);
1522
+ if (local) {
1523
+ return { status: 'ready', href: local, source: 'localBlob' };
1524
+ }
1525
+ return {
1526
+ status: 'ready',
1527
+ href: BaseArweaveClient.getRawUrl(txId),
1528
+ source: 'gateway',
1529
+ };
1530
+ }
1531
+ /**
1532
+ * Resolve a classified media reference to a display URL (https/blob/data), using local files when present.
1533
+ */
1534
+ async function resolveMediaRef(raw, options) {
1535
+ const classification = classifyMediaRef(raw, options);
1536
+ switch (classification.kind) {
1537
+ case 'empty':
1538
+ return { status: 'empty' };
1539
+ case 'url':
1540
+ return {
1541
+ status: 'ready',
1542
+ href: classification.href,
1543
+ source: 'direct',
1544
+ };
1545
+ case 'seedLocalId':
1546
+ return {
1547
+ status: 'unresolved',
1548
+ reason: 'seed_local_id_not_portable',
1549
+ classification,
1550
+ };
1551
+ case 'unknown':
1552
+ return {
1553
+ status: 'unresolved',
1554
+ reason: 'unknown_ref',
1555
+ classification,
1556
+ };
1557
+ case 'arweaveTxId':
1558
+ return resolveTxId(classification.txId);
1559
+ case 'seedUid': {
1560
+ const appDb = BaseDb.getAppDb();
1561
+ if (!appDb) {
1562
+ return {
1563
+ status: 'unresolved',
1564
+ reason: 'seed_uid_requires_app_db',
1565
+ classification,
1566
+ };
1567
+ }
1568
+ const storageTransactionId = await getStorageTransactionIdForSeedUid(classification.uid);
1569
+ if (!storageTransactionId) {
1570
+ return {
1571
+ status: 'unresolved',
1572
+ reason: 'seed_uid_no_storage_transaction',
1573
+ classification,
1574
+ };
1575
+ }
1576
+ return resolveTxId(storageTransactionId);
1577
+ }
1578
+ default:
1579
+ return {
1580
+ status: 'unresolved',
1581
+ reason: 'unknown_ref',
1582
+ classification,
1583
+ };
1584
+ }
1585
+ }
1586
+ /**
1587
+ * Read a string field from a parsed item, trying camelCase and snake_case keys.
1588
+ */
1589
+ function getFeedItemStringField(item, key) {
1590
+ const direct = coalesceStringField(item, key);
1591
+ if (direct)
1592
+ return direct;
1593
+ const snake = key.replace(/[A-Z]/g, (l) => `_${l.toLowerCase()}`);
1594
+ if (snake !== key) {
1595
+ const alt = coalesceStringField(item, snake);
1596
+ if (alt)
1597
+ return alt;
1598
+ }
1599
+ const parts = key.split('_');
1600
+ if (parts.length > 1) {
1601
+ const camel = parts[0] + parts.slice(1).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join('');
1602
+ const alt2 = coalesceStringField(item, camel);
1603
+ if (alt2)
1604
+ return alt2;
1605
+ }
1606
+ return '';
1607
+ }
1608
+ /**
1609
+ * Apply a field manifest to a plain feed item: classify media/file fields; pass through html/text.
1610
+ */
1611
+ function normalizeFeedItemFields(item, manifest) {
1612
+ const out = {};
1613
+ for (const [fieldKey, descriptor] of Object.entries(manifest)) {
1614
+ const raw = getFeedItemStringField(item, fieldKey);
1615
+ if (!raw) {
1616
+ out[fieldKey] = undefined;
1617
+ continue;
1618
+ }
1619
+ if (descriptor.role === 'html') {
1620
+ out[fieldKey] = { role: 'html', raw };
1621
+ continue;
1622
+ }
1623
+ if (descriptor.role === 'text') {
1624
+ out[fieldKey] = { role: 'text', raw };
1625
+ continue;
1141
1626
  }
1627
+ const classification = classifyMediaRef(raw, { treatAs: descriptor.treatAs });
1628
+ out[fieldKey] = {
1629
+ role: descriptor.role,
1630
+ raw,
1631
+ classification,
1632
+ };
1142
1633
  }
1143
- return undefined;
1634
+ return out;
1144
1635
  }
1145
- /** getCorrectId only accepts 10-char local ids and 0x66 uids; local seed refs can be up to 21 chars. */
1146
- const LOCAL_SEED_REF = /^[a-zA-Z0-9_-]{10,21}$/;
1147
- /** Resolve seed ids from a single string (context propertyValue or DB row). */
1148
- function resolveSeedIdsFromRefString(s) {
1149
- const fromCorrect = parseLocalIdOrUid(s);
1150
- if (fromCorrect.localId || fromCorrect.uid) {
1151
- return { seedLocalId: fromCorrect.localId, seedUid: fromCorrect.uid };
1152
- }
1153
- if (LOCAL_SEED_REF.test(s) && !s.startsWith('0x')) {
1154
- return { seedLocalId: s };
1155
- }
1156
- return {};
1636
+
1637
+ /**
1638
+ * True when the value is not a real EAS attestation UID stored in SQLite
1639
+ * (missing, empty, legacy 'NULL' sentinel, or zero bytes32).
1640
+ */
1641
+ function isPlaceholderUid(value) {
1642
+ if (value == null || value === '')
1643
+ return true;
1644
+ if (value === 'NULL')
1645
+ return true;
1646
+ const v = value.trim();
1647
+ if (v === '')
1648
+ return true;
1649
+ if (v.toLowerCase() === ZERO_BYTES32.toLowerCase())
1650
+ return true;
1651
+ return false;
1652
+ }
1653
+ /**
1654
+ * Strict EAS attestation UID: 0x-prefixed 32-byte hex (case-insensitive 0x / hex body).
1655
+ * Excludes placeholders and ZERO_BYTES32.
1656
+ */
1657
+ function isValidEasAttestationUid(value) {
1658
+ if (isPlaceholderUid(value))
1659
+ return false;
1660
+ const v = String(value).trim();
1661
+ if (!/^0x/i.test(v))
1662
+ return false;
1663
+ const hex = v.slice(2);
1664
+ if (hex.length !== 64)
1665
+ return false;
1666
+ return /^[0-9a-fA-F]{64}$/.test(hex);
1667
+ }
1668
+ /** Normalize bytes32 hex strings for case-insensitive comparison (schema UIDs, etc.). */
1669
+ function normalizeBytes32Hex(value) {
1670
+ if (value == null || value === '')
1671
+ return '';
1672
+ const raw = String(value).trim();
1673
+ const body = raw.startsWith('0x') || raw.startsWith('0X') ? raw.slice(2) : raw;
1674
+ const hex = body.replace(/[^0-9a-fA-F]/g, '0').padStart(64, '0').slice(-64);
1675
+ return ('0x' + hex).toLowerCase();
1157
1676
  }
1158
1677
 
1159
1678
  function pickLatestPropertyAttestationsByRefAndSchema(attestations) {
@@ -1343,6 +1862,7 @@ var index = /*#__PURE__*/Object.freeze({
1343
1862
  BaseFileManager: BaseFileManager,
1344
1863
  BaseQueryClient: BaseQueryClient,
1345
1864
  capitalizeFirstLetter: capitalizeFirstLetter,
1865
+ classifyMediaRef: classifyMediaRef,
1346
1866
  convertTxIdToImage: convertTxIdToImage,
1347
1867
  generateId: generateId,
1348
1868
  getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
@@ -1351,6 +1871,7 @@ var index = /*#__PURE__*/Object.freeze({
1351
1871
  getCorrectId: getCorrectId,
1352
1872
  getDataTypeFromString: getDataTypeFromString,
1353
1873
  getExecutionTime: getExecutionTime,
1874
+ getFeedItemStringField: getFeedItemStringField,
1354
1875
  getGetAdditionalSyncAddresses: getGetAdditionalSyncAddresses,
1355
1876
  getGetPublisherForNewSeeds: getGetPublisherForNewSeeds,
1356
1877
  getMetadataPropertyNamesForQuery: getMetadataPropertyNamesForQuery,
@@ -1364,13 +1885,18 @@ var index = /*#__PURE__*/Object.freeze({
1364
1885
  identifyString: identifyString,
1365
1886
  isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
1366
1887
  isBinary: isBinary,
1888
+ isPlaceholderUid: isPlaceholderUid,
1889
+ isValidEasAttestationUid: isValidEasAttestationUid,
1367
1890
  listRelationStoragePropertyName: listRelationStoragePropertyName,
1368
1891
  needsMetadataIdSuffix: needsMetadataIdSuffix,
1892
+ normalizeBytes32Hex: normalizeBytes32Hex,
1893
+ normalizeFeedItemFields: normalizeFeedItemFields,
1369
1894
  normalizeRelationPropertyValue: normalizeRelationPropertyValue,
1370
1895
  normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
1371
1896
  parseEasRelationPropertyName: parseEasRelationPropertyName,
1372
1897
  pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
1373
1898
  queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
1899
+ resolveMediaRef: resolveMediaRef,
1374
1900
  resolveMetadataRecord: resolveMetadataRecord,
1375
1901
  resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
1376
1902
  resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
@@ -1396,7 +1922,7 @@ const createPropertyInstances = async (propertyFileIds) => {
1396
1922
  return;
1397
1923
  }
1398
1924
  try {
1399
- const mod = await import('./ModelProperty-Csj84uQv.js');
1925
+ const mod = await import('./ModelProperty-DWtv9fQr.js');
1400
1926
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
1401
1927
  if (!ModelProperty) {
1402
1928
  logger$t('createPropertyInstances: ModelProperty not available from dynamic import');
@@ -1580,7 +2106,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
1580
2106
  // Step 2: Fallback to Schema context (only if database doesn't have the model)
1581
2107
  // This handles the case where model exists in schema file but not yet in database
1582
2108
  try {
1583
- const _mod_0 = await import('./Schema-QjwZN91G.js');
2109
+ const _mod_0 = await import('./Schema-CqqcEexA.js');
1584
2110
  const _ns_0 = _mod_0.b;
1585
2111
  const schemaMod = _ns_0;
1586
2112
  const { Schema } = schemaMod;
@@ -1826,7 +2352,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
1826
2352
  }
1827
2353
  // Mark schema as draft when a new model is created so saveNewVersion() can persist it
1828
2354
  try {
1829
- const _mod_1 = await import('./Schema-QjwZN91G.js');
2355
+ const _mod_1 = await import('./Schema-CqqcEexA.js');
1830
2356
  const _ns_1 = _mod_1.b;
1831
2357
  const schemaMod = _ns_1;
1832
2358
  const { Schema } = schemaMod;
@@ -1872,10 +2398,10 @@ const validateModel = fromCallback(({ sendBack, input: { context } }) => {
1872
2398
  const _validateModel = async () => {
1873
2399
  try {
1874
2400
  // Use dynamic imports to break circular dependencies
1875
- const validationServiceMod = await import('./SchemaValidationService-Cwkeb4fG.js');
2401
+ const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
1876
2402
  const { SchemaValidationService } = validationServiceMod;
1877
2403
  const validationService = new SchemaValidationService();
1878
- const _mod_2 = await import('./Schema-QjwZN91G.js');
2404
+ const _mod_2 = await import('./Schema-CqqcEexA.js');
1879
2405
  const _ns_2 = _mod_2.b;
1880
2406
  const schemaMod = _ns_2;
1881
2407
  const { Schema } = schemaMod;
@@ -1987,7 +2513,7 @@ const createModelProperties = fromCallback(({ sendBack, input }) => {
1987
2513
  return;
1988
2514
  }
1989
2515
  logger$r(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
1990
- const mod = await import('./ModelProperty-Csj84uQv.js');
2516
+ const mod = await import('./ModelProperty-DWtv9fQr.js');
1991
2517
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
1992
2518
  if (!ModelProperty) {
1993
2519
  logger$r('ModelProperty not available from dynamic import');
@@ -2091,7 +2617,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2091
2617
  const structureMsg = `[validateEntity] Validating model structure`;
2092
2618
  logger$q(structureMsg);
2093
2619
  // Use existing Model validation
2094
- const validationServiceMod = await import('./SchemaValidationService-Cwkeb4fG.js');
2620
+ const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2095
2621
  const { SchemaValidationService } = validationServiceMod;
2096
2622
  const validationService = new SchemaValidationService();
2097
2623
  // Validate model structure
@@ -2109,7 +2635,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2109
2635
  if (entityInput.entityData.schemaName) {
2110
2636
  try {
2111
2637
  logger$q(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
2112
- const _mod_3 = await import('./Schema-QjwZN91G.js');
2638
+ const _mod_3 = await import('./Schema-CqqcEexA.js');
2113
2639
  const _ns_3 = _mod_3.b;
2114
2640
  const schemaMod = _ns_3;
2115
2641
  const { Schema } = schemaMod;
@@ -2147,7 +2673,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2147
2673
  }
2148
2674
  else if (entityInput.entityType === 'modelProperty') {
2149
2675
  // Use existing ModelProperty validation
2150
- const validationServiceMod = await import('./SchemaValidationService-Cwkeb4fG.js');
2676
+ const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2151
2677
  const { SchemaValidationService } = validationServiceMod;
2152
2678
  const validationService = new SchemaValidationService();
2153
2679
  // Validate property structure
@@ -2162,7 +2688,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2162
2688
  // If schema name and model name provided, validate against schema
2163
2689
  if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
2164
2690
  try {
2165
- const _mod_4 = await import('./Schema-QjwZN91G.js');
2691
+ const _mod_4 = await import('./Schema-CqqcEexA.js');
2166
2692
  const _ns_4 = _mod_4.b;
2167
2693
  const schemaMod = _ns_4;
2168
2694
  const { Schema } = schemaMod;
@@ -2193,7 +2719,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2193
2719
  }
2194
2720
  else if (entityInput.entityType === 'schema') {
2195
2721
  // Schema validation - use existing validation
2196
- const validationServiceMod = await import('./SchemaValidationService-Cwkeb4fG.js');
2722
+ const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2197
2723
  const { SchemaValidationService } = validationServiceMod;
2198
2724
  const validationService = new SchemaValidationService();
2199
2725
  const schemaResult = validationService.validateSchema(entityInput.entityData);
@@ -2222,180 +2748,6 @@ const validateEntity = fromPromise(async ({ input }) => {
2222
2748
  // @ts-ignore - XState v5 type inference bug: fromPromise incorrectly expects output type to match input type
2223
2749
  });
2224
2750
 
2225
- const seeds = sqliteTable('seeds', {
2226
- localId: text('local_id').unique(),
2227
- uid: text('uid'),
2228
- schemaUid: text('schema_uid'),
2229
- type: text('type'),
2230
- publisher: text('publisher'),
2231
- attestationRaw: text('attestation_raw'),
2232
- attestationCreatedAt: int('attestation_created_at'),
2233
- createdAt: int('created_at'),
2234
- updatedAt: int('updated_at'),
2235
- _markedForDeletion: int('_marked_for_deletion'),
2236
- revokedAt: int('revoked_at'),
2237
- });
2238
-
2239
- const versions = sqliteTable('versions', {
2240
- localId: text('local_id').unique(),
2241
- uid: text('uid'),
2242
- seedLocalId: text('seed_local_id'),
2243
- seedUid: text('seed_uid'),
2244
- seedType: text('seed_type'),
2245
- note: text('note'),
2246
- createdAt: int('created_at'),
2247
- updatedAt: int('updated_at'),
2248
- attestationCreatedAt: int('attestation_created_at'),
2249
- attestationRaw: text('attestation_raw'),
2250
- publisher: text('publisher'),
2251
- });
2252
-
2253
- const metadata$1 = sqliteTable('metadata', {
2254
- localId: text('local_id').unique(),
2255
- uid: text('uid'),
2256
- propertyId: integer('property_id').references(() => properties.id),
2257
- propertyName: text('property_name'),
2258
- propertyValue: text('property_value'),
2259
- schemaUid: text('schema_uid'),
2260
- modelType: text('model_type'),
2261
- seedLocalId: text('seed_local_id'),
2262
- seedUid: text('seed_uid'),
2263
- versionLocalId: text('version_local_id'),
2264
- versionUid: text('version_uid'),
2265
- easDataType: text('eas_data_type'),
2266
- refValueType: text('ref_value_type'),
2267
- refModelUid: text('ref_schema_uid'),
2268
- refSeedType: text('ref_seed_type'),
2269
- refResolvedValue: text('ref_resolved_value'),
2270
- refResolvedDisplayValue: text('ref_resolved_display_value'),
2271
- localStorageDir: text('local_storage_dir'),
2272
- attestationRaw: text('attestation_raw'),
2273
- attestationCreatedAt: int('attestation_created_at'),
2274
- contentHash: text('content_hash'),
2275
- createdAt: int('created_at'),
2276
- updatedAt: int('updated_at'),
2277
- publisher: text('publisher'),
2278
- });
2279
-
2280
- const appState = sqliteTable('appState', {
2281
- key: text('key').unique(),
2282
- value: text('value'),
2283
- createdAt: int('created_at'),
2284
- updatedAt: int('updated_at'),
2285
- });
2286
-
2287
- const modelUids = sqliteTable('model_uids', {
2288
- id: int('id').primaryKey({ autoIncrement: true }),
2289
- uid: text('uid').notNull(),
2290
- modelId: int('model_id')
2291
- .notNull()
2292
- .unique()
2293
- .references(() => models$1.id),
2294
- });
2295
- const modelRelations = relations(modelUids, ({ one }) => ({
2296
- model: one(models$1),
2297
- }));
2298
-
2299
- const propertyUids = sqliteTable('property_uids', {
2300
- id: int('id').primaryKey({ autoIncrement: true }),
2301
- uid: text('uid').notNull(),
2302
- propertyId: int('property_id')
2303
- .notNull()
2304
- .unique()
2305
- .references(() => properties.id),
2306
- });
2307
- const propertyUidRelations = relations(propertyUids, ({ one }) => ({
2308
- property: one(properties),
2309
- }));
2310
-
2311
- const config = sqliteTable('config', {
2312
- id: integer('id').primaryKey({ autoIncrement: true }),
2313
- key: text('key').notNull(),
2314
- text: text('text'),
2315
- json: text('json'),
2316
- blob: blob('blob'),
2317
- });
2318
-
2319
- const schemas = sqliteTable('schemas', {
2320
- id: integer('id').primaryKey({ autoIncrement: true }),
2321
- name: text('name').notNull(),
2322
- version: integer('version').notNull(),
2323
- schemaFileId: text('schema_file_id'), // ID from JSON file for change tracking - must be unique
2324
- schemaData: text('schema_data'), // Full JSON schema content (SchemaFileFormat as JSON string)
2325
- isDraft: integer('is_draft', { mode: 'boolean' }), // true if schema is in draft/editing state, false if published to file
2326
- isEdited: integer('is_edited', { mode: 'boolean' }), // true if schema has been edited locally, false if matches schema file
2327
- createdAt: int('created_at'),
2328
- updatedAt: int('updated_at'),
2329
- }, (table) => {
2330
- return {
2331
- uniqueSchemaFileId: unique('unique_schema_schema_file_id').on(table.schemaFileId),
2332
- };
2333
- });
2334
-
2335
- var SchemaSchema = /*#__PURE__*/Object.freeze({
2336
- __proto__: null,
2337
- schemas: schemas
2338
- });
2339
-
2340
- const modelSchemas = sqliteTable('model_schemas', {
2341
- id: integer('id').primaryKey({ autoIncrement: true }),
2342
- modelId: integer('model_id').references(() => models$1.id),
2343
- schemaId: integer('schema_id').references(() => schemas.id),
2344
- });
2345
-
2346
- var ModelSchemaSchema = /*#__PURE__*/Object.freeze({
2347
- __proto__: null,
2348
- modelSchemas: modelSchemas
2349
- });
2350
-
2351
- const publishProcesses = sqliteTable('publish_processes', {
2352
- id: int('id').primaryKey({ autoIncrement: true }),
2353
- seedLocalId: text('seed_local_id').notNull(),
2354
- modelName: text('model_name').notNull(),
2355
- schemaId: text('schema_id'),
2356
- status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed' | 'interrupted'
2357
- startedAt: int('started_at').notNull(),
2358
- completedAt: int('completed_at'),
2359
- errorMessage: text('error_message'),
2360
- errorStep: text('error_step'),
2361
- errorDetails: text('error_details'),
2362
- persistedSnapshot: text('persisted_snapshot').notNull(),
2363
- seedId: text('seed_id'),
2364
- existingSeedUid: text('existing_seed_uid'),
2365
- createdAt: int('created_at'),
2366
- updatedAt: int('updated_at'),
2367
- });
2368
-
2369
- const uploadProcesses = sqliteTable('upload_processes', {
2370
- id: int('id').primaryKey({ autoIncrement: true }),
2371
- reimbursementConfirmed: int('reimbursement_confirmed').notNull(), // 0 or 1 for boolean
2372
- reimbursementTransactionId: text('reimbursement_transaction_id'),
2373
- transactionKeys: text('transaction_keys'),
2374
- persistedSnapshot: text('persisted_snapshot').notNull(), // JSON string
2375
- createdAt: int('created_at'),
2376
- updatedAt: int('updated_at'),
2377
- });
2378
-
2379
- /** Background job: resolve L1 tx id and wait for L1 confirmation after bundler publish. */
2380
- const arweaveL1FinalizeJobs = sqliteTable('arweave_l1_finalize_jobs', {
2381
- id: int('id').primaryKey({ autoIncrement: true }),
2382
- seedLocalId: text('seed_local_id').notNull(),
2383
- dataItemId: text('data_item_id').notNull(),
2384
- /** L1 bundle / anchor transaction id from gateway GraphQL `bundledIn.id`. */
2385
- l1TransactionId: text('l1_transaction_id'),
2386
- bundleId: text('bundle_id'),
2387
- versionLocalId: text('version_local_id'),
2388
- itemPropertyName: text('item_property_name'),
2389
- /** `pending_l1` | `confirmed` | `failed` */
2390
- phase: text('phase').notNull(),
2391
- statusJson: text('status_json'),
2392
- errorMessage: text('error_message'),
2393
- createdAt: int('created_at').notNull(),
2394
- updatedAt: int('updated_at').notNull(),
2395
- }, (table) => ({
2396
- dataItemIdUnique: uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
2397
- }));
2398
-
2399
2751
  const logger$p = debug('seedSdk:helpers:db');
2400
2752
  /**
2401
2753
  * Resolve property_id from model name/type and property name.
@@ -4319,7 +4671,7 @@ const writeToDatabase = fromCallback(({ sendBack, input }) => {
4319
4671
  // initial write completes is not overwritten by the stale requestWrite payload.
4320
4672
  let dataToWrite = input.entityData;
4321
4673
  try {
4322
- const mod = await import('./ModelProperty-Csj84uQv.js');
4674
+ const mod = await import('./ModelProperty-DWtv9fQr.js');
4323
4675
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
4324
4676
  if (ModelProperty && typeof ModelProperty.getById === 'function') {
4325
4677
  const instance = ModelProperty.getById(input.entityId);
@@ -4699,7 +5051,7 @@ const modelMachine = setup({
4699
5051
  // Create ModelProperty instances for any new property IDs
4700
5052
  if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
4701
5053
  // Import and create instances asynchronously (fire-and-forget)
4702
- import('./ModelProperty-Csj84uQv.js').then(({ ModelProperty }) => {
5054
+ import('./ModelProperty-DWtv9fQr.js').then(({ ModelProperty }) => {
4703
5055
  const createPromises = newPropertyIds.map(async (propertyFileId) => {
4704
5056
  try {
4705
5057
  const property = await ModelProperty.createById(propertyFileId);
@@ -5771,9 +6123,9 @@ const createVersion = async ({ seedLocalId, seedUid, seedType, uid, }) => {
5771
6123
  localId: newVersionLocalId,
5772
6124
  createdAt: Date.now(),
5773
6125
  seedLocalId,
5774
- seedUid: seedUid ?? 'NULL',
6126
+ seedUid: seedUid ?? null,
5775
6127
  seedType,
5776
- uid: uid || 'NULL',
6128
+ uid: uid ?? null,
5777
6129
  ...(publisher != null && publisher !== '' && { publisher }),
5778
6130
  });
5779
6131
  return newVersionLocalId;
@@ -5788,12 +6140,12 @@ const hydrateNewItem = fromCallback(({ sendBack, input: { context } }) => {
5788
6140
  }
5789
6141
  newSeedLocalId = await createSeed({
5790
6142
  type: modelName.toLowerCase(),
5791
- seedUid: seedUid ?? 'NULL',
6143
+ ...(seedUid && seedUid !== 'NULL' ? { seedUid } : {}),
5792
6144
  });
5793
6145
  await createVersion({
5794
6146
  seedLocalId: newSeedLocalId,
5795
6147
  seedType: modelName.toLowerCase(),
5796
- uid: versionUid ?? 'NULL',
6148
+ ...(versionUid && versionUid !== 'NULL' ? { uid: versionUid } : {}),
5797
6149
  });
5798
6150
  };
5799
6151
  _hydrateNewItem().then(() => {
@@ -5925,28 +6277,145 @@ const reload = fromCallback(({ sendBack, input: { context } }) => {
5925
6277
  });
5926
6278
  });
5927
6279
 
6280
+ /**
6281
+ * Per-seed aggregates (all versions) plus the latest version row by
6282
+ * (created_at DESC, local_id DESC) via max(created_at) then max(local_id) tie-break.
6283
+ *
6284
+ * For `publishedVersionUid` / `publishedVersionLocalId` on list rows, see `getItemsData`
6285
+ * (batched resolution aligned with `getLatestPublishedVersionRow`).
6286
+ */
5928
6287
  const getVersionData$1 = () => {
5929
6288
  const appDb = BaseDb.getAppDb();
6289
+ const versionStats = appDb.$with('version_stats').as(appDb
6290
+ .select({
6291
+ seedLocalId: versions.seedLocalId,
6292
+ versionsCount: count(versions.localId).as('versionsCount'),
6293
+ lastVersionPublishedAt: max(versions.attestationCreatedAt).as('lastVersionPublishedAt'),
6294
+ lastLocalUpdateAt: max(versions.createdAt).as('lastLocalUpdateAt'),
6295
+ maxCreatedAt: max(versions.createdAt).as('maxCreatedAt'),
6296
+ })
6297
+ .from(versions)
6298
+ .groupBy(versions.seedLocalId));
6299
+ const latestVersionIds = appDb.$with('latest_version_ids').as(appDb
6300
+ .with(versionStats)
6301
+ .select({
6302
+ seedLocalId: versions.seedLocalId,
6303
+ latestVersionLocalId: max(versions.localId).as('latestVersionLocalId'),
6304
+ })
6305
+ .from(versions)
6306
+ .innerJoin(versionStats, and(eq(versions.seedLocalId, versionStats.seedLocalId), eq(versions.createdAt, versionStats.maxCreatedAt)))
6307
+ .groupBy(versions.seedLocalId));
5930
6308
  return appDb.$with('versionData').as(appDb
6309
+ .with(versionStats, latestVersionIds)
6310
+ .select({
6311
+ seedLocalId: versionStats.seedLocalId,
6312
+ seedUid: versions.seedUid,
6313
+ latestVersionUid: versions.uid,
6314
+ latestVersionLocalId: latestVersionIds.latestVersionLocalId,
6315
+ versionsCount: versionStats.versionsCount,
6316
+ lastVersionPublishedAt: versionStats.lastVersionPublishedAt,
6317
+ lastLocalUpdateAt: versionStats.lastLocalUpdateAt,
6318
+ })
6319
+ .from(versionStats)
6320
+ .innerJoin(latestVersionIds, eq(versionStats.seedLocalId, latestVersionIds.seedLocalId))
6321
+ .innerJoin(versions, and(eq(versions.seedLocalId, latestVersionIds.seedLocalId), eq(versions.localId, latestVersionIds.latestVersionLocalId))));
6322
+ };
6323
+
6324
+ var versionData = /*#__PURE__*/Object.freeze({
6325
+ __proto__: null,
6326
+ getVersionData: getVersionData$1
6327
+ });
6328
+
6329
+ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
6330
+ const appDb = BaseDb.getAppDb();
6331
+ const whereClauses = [];
6332
+ if (seedLocalId && seedUid) {
6333
+ const orClause = or(eq(metadata$1.seedLocalId, seedLocalId), eq(metadata$1.seedUid, seedUid));
6334
+ if (orClause)
6335
+ whereClauses.push(orClause);
6336
+ }
6337
+ else if (seedLocalId) {
6338
+ whereClauses.push(eq(metadata$1.seedLocalId, seedLocalId));
6339
+ }
6340
+ else if (seedUid) {
6341
+ whereClauses.push(eq(metadata$1.seedUid, seedUid));
6342
+ }
6343
+ const metadataColumns = getTableColumns(metadata$1);
6344
+ return appDb.$with('metadataLatest').as(appDb
5931
6345
  .select({
5932
- seedLocalId: versions.seedLocalId,
5933
- seedUid: versions.seedUid,
5934
- latestVersionUid: versions.uid,
5935
- latestVersionLocalId: versions.localId,
5936
- versionsCount: count(versions.localId).as('versionsCount'),
5937
- lastVersionPublishedAt: max(versions.attestationCreatedAt).as('lastVersionPublishedAt'),
5938
- lastLocalUpdateAt: max(versions.createdAt).as('lastLocalUpdateAt'),
6346
+ ...metadataColumns,
6347
+ rowNum: sql.raw(`
6348
+ ROW_NUMBER() OVER (
6349
+ PARTITION BY property_name
6350
+ ORDER BY COALESCE(attestation_created_at, created_at) DESC
6351
+ )
6352
+ `).as('rowNum')
5939
6353
  })
5940
- .from(versions)
5941
- .groupBy(versions.seedLocalId));
6354
+ .from(metadata$1)
6355
+ .where(and(...whereClauses)));
5942
6356
  };
5943
6357
 
5944
- var versionData = /*#__PURE__*/Object.freeze({
6358
+ var metadataLatest = /*#__PURE__*/Object.freeze({
5945
6359
  __proto__: null,
5946
- getVersionData: getVersionData$1
6360
+ getMetadataLatest: getMetadataLatest
5947
6361
  });
5948
6362
 
5949
6363
  const logger$l = debug('seedSdk:item:actors:loadOrCreateItem');
6364
+ /**
6365
+ * Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
6366
+ */
6367
+ function normalizeMetadataRowToInstanceKey(metaRow, propertySchemas) {
6368
+ let propertyName = metaRow.propertyName;
6369
+ if (!propertyName)
6370
+ return undefined;
6371
+ const listSchemaKey = resolveStorageNameToSchemaName(propertySchemas, propertyName);
6372
+ if (listSchemaKey) {
6373
+ propertyName = listSchemaKey;
6374
+ }
6375
+ else {
6376
+ const baseName = toSchemaPropertyName(propertyName);
6377
+ const refSeedType = metaRow.refSeedType;
6378
+ const isRefTypeFromMeta = refSeedType === 'file' ||
6379
+ refSeedType === 'image' ||
6380
+ refSeedType === 'relation' ||
6381
+ refSeedType === 'html';
6382
+ if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
6383
+ propertyName = baseName;
6384
+ }
6385
+ }
6386
+ return propertyName;
6387
+ }
6388
+ function metadataValueStrength(row) {
6389
+ const v = row?.propertyValue;
6390
+ if (v == null || v === '')
6391
+ return 0;
6392
+ return String(v).trim().length;
6393
+ }
6394
+ /** When storage + schema names map to the same key, prefer non-empty, then richer payload, then newer row. */
6395
+ function pickBetterMetadataRowForSameInstance(a, b) {
6396
+ const sa = metadataValueStrength(a);
6397
+ const sb = metadataValueStrength(b);
6398
+ if (sa > 0 && sb === 0)
6399
+ return a;
6400
+ if (sb > 0 && sa === 0)
6401
+ return b;
6402
+ if (sa !== sb)
6403
+ return sa > sb ? a : b;
6404
+ const ta = a.attestationCreatedAt ?? a.createdAt ?? 0;
6405
+ const tb = b.attestationCreatedAt ?? b.createdAt ?? 0;
6406
+ return ta >= tb ? a : b;
6407
+ }
6408
+ function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
6409
+ const byKey = new Map();
6410
+ for (const metaRow of metadataRows) {
6411
+ const key = normalizeMetadataRowToInstanceKey(metaRow, propertySchemas);
6412
+ if (!key)
6413
+ continue;
6414
+ const existing = byKey.get(key);
6415
+ byKey.set(key, existing ? pickBetterMetadataRowForSameInstance(existing, metaRow) : metaRow);
6416
+ }
6417
+ return Array.from(byKey.values());
6418
+ }
5950
6419
  /**
5951
6420
  * Create ItemProperty instances for all metadata records plus placeholder instances
5952
6421
  * for model schema properties that have no metadata. Ensures items (e.g. Image) have
@@ -5982,7 +6451,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
5982
6451
  const schemaNameToTry = model$1?.schemaName;
5983
6452
  if (schemaNameToTry) {
5984
6453
  try {
5985
- const _mod_5 = await import('./Schema-QjwZN91G.js');
6454
+ const _mod_5 = await import('./Schema-CqqcEexA.js');
5986
6455
  const _ns_5 = _mod_5.b;
5987
6456
  const { Schema } = _ns_5;
5988
6457
  const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
@@ -6033,13 +6502,14 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6033
6502
  }
6034
6503
  }
6035
6504
  if (Object.keys(propertySchemas).length === 0) {
6036
- const schemaMod = await import('./index-DvUyNZc9.js');
6505
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
6037
6506
  const { ModelPropertyDataTypes } = schemaMod;
6038
6507
  const KNOWN_MODEL_FALLBACKS = {
6039
6508
  Post: {
6040
6509
  html: { dataType: ModelPropertyDataTypes.Html },
6041
6510
  summary: { dataType: ModelPropertyDataTypes.Text },
6042
6511
  title: { dataType: ModelPropertyDataTypes.Text },
6512
+ authors: { dataType: ModelPropertyDataTypes.List, ref: 'Identity' },
6043
6513
  },
6044
6514
  };
6045
6515
  if (KNOWN_MODEL_FALLBACKS[modelName]) {
@@ -6048,17 +6518,14 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6048
6518
  }
6049
6519
  }
6050
6520
  }
6051
- // Build map of metadata by propertyName for lookup
6052
- const metadataByProperty = new Map();
6053
- for (const metaRow of metadataRows) {
6054
- if (metaRow.propertyName) {
6055
- metadataByProperty.set(metaRow.propertyName, metaRow);
6056
- }
6057
- }
6521
+ // Collapse rows that map to the same instance key (e.g. authorIdentityIds + authors -> authors).
6522
+ // ItemProperty.create cache does not sync propertyValue on hit; processing order would otherwise
6523
+ // let an empty "authors" row overwrite a populated storage row.
6524
+ const dedupedMetadataRows = dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas);
6058
6525
  // Create instances for all metadata records
6059
6526
  // For File/Image/Relation, metadata is stored with Id suffix (e.g. "textId") but schema defines base name ("text").
6060
6527
  // Normalize to schema name so we don't create duplicate properties (text + textId).
6061
- for (const metaRow of metadataRows) {
6528
+ for (const metaRow of dedupedMetadataRows) {
6062
6529
  try {
6063
6530
  let propertyName = metaRow.propertyName;
6064
6531
  if (!propertyName) {
@@ -6082,7 +6549,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6082
6549
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
6083
6550
  let propSchema = propertySchemas[propertyName];
6084
6551
  if (!propSchema && isRefTypeFromMeta) {
6085
- const schemaMod = await import('./index-DvUyNZc9.js');
6552
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
6086
6553
  const { ModelPropertyDataTypes } = schemaMod;
6087
6554
  propSchema = {
6088
6555
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -6272,18 +6739,26 @@ const loadOrCreateItem = fromCallback(({ sendBack, input: { context } }) => {
6272
6739
  });
6273
6740
  return;
6274
6741
  }
6275
- // Step 3: Query metadata table to find all metadata records that reference that version
6742
+ // Step 3: Latest metadata row per property_name for this seed (matches loadOrCreateProperty /
6743
+ // getItemProperties). Strict version_local_id = latest would drop properties whose rows lag version bumps.
6744
+ const metadataLatest = getMetadataLatest({
6745
+ seedLocalId: resolvedSeedLocalId,
6746
+ seedUid: resolvedSeedUid,
6747
+ });
6276
6748
  const metadataRecords = await db
6749
+ .with(metadataLatest)
6277
6750
  .select()
6278
- .from(metadata$1)
6279
- .where(and(eq(metadata$1.seedLocalId, resolvedSeedLocalId), eq(metadata$1.versionLocalId, latestVersionLocalId)));
6280
- logger$l(`Found ${metadataRecords.length} metadata records for version ${latestVersionLocalId}`);
6751
+ .from(metadataLatest)
6752
+ .where(eq(metadataLatest.rowNum, 1));
6753
+ logger$l(`Found ${metadataRecords.length} latest-per-property metadata rows for seed ${resolvedSeedLocalId} (latestVersionLocalId=${latestVersionLocalId} used for placeholders only)`);
6281
6754
  // Step 4: Create ItemProperty instances from metadata records + placeholders for model schema properties
6282
6755
  // Always call when we have a valid version so placeholders are created for properties without metadata
6283
6756
  const propertyInstances = await createItemPropertyInstances(metadataRecords, resolvedSeedLocalId, resolvedSeedUid, modelName, latestVersionLocalId, latestVersionUid);
6284
6757
  // Step 4b: Wait for all property machines to reach idle so HTML/File content is loaded before Item is ready.
6285
6758
  // Without this, post.html returns seed ID on first render because loadOrCreateProperty hasn't finished.
6286
- await Promise.all(Array.from(propertyInstances.values()).map((prop) => waitForEntityIdle(prop, { timeout: 5000, throwOnError: false })));
6759
+ // Publish/attestation can keep properties in `saving` for many seconds; 5s caused timeouts during EAS work.
6760
+ const propertyIdleTimeoutMs = 120000;
6761
+ await Promise.all(Array.from(propertyInstances.values()).map((prop) => waitForEntityIdle(prop, { timeout: propertyIdleTimeoutMs, throwOnError: false })));
6287
6762
  // Step 5: Return loaded item data with property instances
6288
6763
  sendBack({
6289
6764
  type: 'loadOrCreateItemSuccess',
@@ -6300,6 +6775,7 @@ const loadOrCreateItem = fromCallback(({ sendBack, input: { context } }) => {
6300
6775
  createdAt: seedRecord.createdAt || Date.now(),
6301
6776
  publisher: seedRecord.publisher ?? undefined,
6302
6777
  revokedAt: seedRecord.revokedAt ?? undefined,
6778
+ // One id per property_name (latest row), not the full set of rows for latest version
6303
6779
  _metadataIds: metadataRecords.map((r) => r.localId || r.uid).filter(Boolean),
6304
6780
  propertyInstances,
6305
6781
  },
@@ -6330,9 +6806,9 @@ const runPublish = fromCallback(({ sendBack, input: { context } }) => {
6330
6806
  sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
6331
6807
  return;
6332
6808
  }
6333
- const getPublishUploadsMod = await import('./getPublishUploads-DTE4SEWk.js');
6809
+ const getPublishUploadsMod = await import('./getPublishUploads-DS2dQ4Ho.js');
6334
6810
  const { getPublishUploads } = getPublishUploadsMod;
6335
- const getPublishPayloadMod = await import('./getPublishPayload-CMhy9jfz.js');
6811
+ const getPublishPayloadMod = await import('./getPublishPayload-DpYwi-rd.js');
6336
6812
  const { getPublishPayload } = getPublishPayloadMod;
6337
6813
  const uploads = await getPublishUploads(item);
6338
6814
  let uploadedTransactions = [];
@@ -6624,40 +7100,6 @@ const itemMachineSingle = setup({
6624
7100
  },
6625
7101
  });
6626
7102
 
6627
- const getMetadataLatest = ({ seedLocalId, seedUid }) => {
6628
- const appDb = BaseDb.getAppDb();
6629
- const whereClauses = [];
6630
- if (seedLocalId && seedUid) {
6631
- const orClause = or(eq(metadata$1.seedLocalId, seedLocalId), eq(metadata$1.seedUid, seedUid));
6632
- if (orClause)
6633
- whereClauses.push(orClause);
6634
- }
6635
- else if (seedLocalId) {
6636
- whereClauses.push(eq(metadata$1.seedLocalId, seedLocalId));
6637
- }
6638
- else if (seedUid) {
6639
- whereClauses.push(eq(metadata$1.seedUid, seedUid));
6640
- }
6641
- const metadataColumns = getTableColumns(metadata$1);
6642
- return appDb.$with('metadataLatest').as(appDb
6643
- .select({
6644
- ...metadataColumns,
6645
- rowNum: sql.raw(`
6646
- ROW_NUMBER() OVER (
6647
- PARTITION BY property_name
6648
- ORDER BY COALESCE(attestation_created_at, created_at) DESC
6649
- )
6650
- `).as('rowNum')
6651
- })
6652
- .from(metadata$1)
6653
- .where(and(...whereClauses)));
6654
- };
6655
-
6656
- var metadataLatest = /*#__PURE__*/Object.freeze({
6657
- __proto__: null,
6658
- getMetadataLatest: getMetadataLatest
6659
- });
6660
-
6661
7103
  const getItemProperties = async ({ seedLocalId, seedUid, edited, }) => {
6662
7104
  const appDb = BaseDb.getAppDb();
6663
7105
  const whereClauses = [isNotNull(metadata$1.propertyName)];
@@ -6712,6 +7154,35 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
6712
7154
  return rows[0];
6713
7155
  };
6714
7156
 
7157
+ /**
7158
+ * Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
7159
+ * Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
7160
+ */
7161
+ async function getLatestPublishedVersionRow(seedLocalId) {
7162
+ const appDb = BaseDb.getAppDb();
7163
+ if (!appDb || !seedLocalId)
7164
+ return null;
7165
+ const vRows = await appDb
7166
+ .select({
7167
+ localId: versions.localId,
7168
+ uid: versions.uid,
7169
+ attestationCreatedAt: versions.attestationCreatedAt,
7170
+ })
7171
+ .from(versions)
7172
+ .where(eq(versions.seedLocalId, seedLocalId))
7173
+ .orderBy(desc(versions.createdAt));
7174
+ for (const vr of vRows) {
7175
+ if (vr.uid && isValidEasAttestationUid(vr.uid)) {
7176
+ return {
7177
+ uid: vr.uid,
7178
+ localId: vr.localId ?? null,
7179
+ attestationCreatedAt: vr.attestationCreatedAt ?? null,
7180
+ };
7181
+ }
7182
+ }
7183
+ return null;
7184
+ }
7185
+
6715
7186
  const logger$j = debug('seedSdk:db:read:getItemData');
6716
7187
  const getItemData = async ({ modelName, seedLocalId, seedUid, }) => {
6717
7188
  if (!seedLocalId && !seedUid) {
@@ -6780,21 +7251,51 @@ const getItemData = async ({ modelName, seedLocalId, seedUid, }) => {
6780
7251
  lastVersionPublishedAt: null,
6781
7252
  latestVersionUid: null,
6782
7253
  latestVersionLocalId: null,
7254
+ publishedVersionUid: null,
7255
+ publishedVersionLocalId: null,
7256
+ lastLocalUpdateAt: null,
6783
7257
  };
6784
7258
  try {
6785
- const versionRows = await appDb
7259
+ const allVersions = await appDb
6786
7260
  .select({
6787
- versionsCount: count(versions.localId).as('versionsCount'),
6788
- lastVersionPublishedAt: max(versions.attestationCreatedAt).as('lastVersionPublishedAt'),
6789
- latestVersionUid: max(versions.uid).as('latestVersionUid'),
6790
- latestVersionLocalId: max(versions.localId).as('latestVersionLocalId'),
7261
+ localId: versions.localId,
7262
+ uid: versions.uid,
7263
+ createdAt: versions.createdAt,
7264
+ attestationCreatedAt: versions.attestationCreatedAt,
6791
7265
  })
6792
7266
  .from(versions)
6793
- .where(eq(versions.seedLocalId, resolvedSeedLocalId))
6794
- .groupBy(versions.seedLocalId)
6795
- .limit(1);
6796
- if (versionRows && versionRows.length > 0) {
6797
- versionRow = versionRows[0];
7267
+ .where(eq(versions.seedLocalId, resolvedSeedLocalId));
7268
+ if (allVersions.length > 0) {
7269
+ const sorted = [...allVersions].sort((a, b) => {
7270
+ const ca = a.createdAt ?? 0;
7271
+ const cb = b.createdAt ?? 0;
7272
+ if (cb !== ca)
7273
+ return cb - ca;
7274
+ return String(b.localId ?? '').localeCompare(String(a.localId ?? ''));
7275
+ });
7276
+ const latest = sorted[0];
7277
+ let lastPub = null;
7278
+ for (const v of allVersions) {
7279
+ const t = v.attestationCreatedAt;
7280
+ if (t != null && (lastPub == null || t > lastPub))
7281
+ lastPub = t;
7282
+ }
7283
+ let lastLocal = 0;
7284
+ for (const v of allVersions) {
7285
+ const t = v.createdAt ?? 0;
7286
+ if (t > lastLocal)
7287
+ lastLocal = t;
7288
+ }
7289
+ const published = await getLatestPublishedVersionRow(resolvedSeedLocalId);
7290
+ versionRow = {
7291
+ versionsCount: allVersions.length,
7292
+ lastVersionPublishedAt: lastPub,
7293
+ latestVersionUid: latest.uid ?? null,
7294
+ latestVersionLocalId: latest.localId ?? null,
7295
+ publishedVersionUid: published?.uid ?? null,
7296
+ publishedVersionLocalId: published?.localId ?? null,
7297
+ lastLocalUpdateAt: lastLocal || null,
7298
+ };
6798
7299
  }
6799
7300
  }
6800
7301
  catch (error) {
@@ -6826,11 +7327,65 @@ const getItemData = async ({ modelName, seedLocalId, seedUid, }) => {
6826
7327
  return itemData;
6827
7328
  };
6828
7329
 
7330
+ /**
7331
+ * One round-trip for list views: for each seed, the same row as {@link getLatestPublishedVersionRow}
7332
+ * (newest `created_at` whose `uid` is a valid EAS attestation id).
7333
+ */
7334
+ async function batchLatestPublishedVersionBySeedLocalIds(seedLocalIds) {
7335
+ const out = new Map();
7336
+ if (seedLocalIds.length === 0)
7337
+ return out;
7338
+ const appDb = BaseDb.getAppDb();
7339
+ if (!appDb)
7340
+ return out;
7341
+ const rows = await appDb
7342
+ .select({
7343
+ seedLocalId: versions.seedLocalId,
7344
+ localId: versions.localId,
7345
+ uid: versions.uid,
7346
+ createdAt: versions.createdAt,
7347
+ })
7348
+ .from(versions)
7349
+ .where(inArray(versions.seedLocalId, seedLocalIds));
7350
+ const bySeed = new Map();
7351
+ for (const r of rows) {
7352
+ const sid = r.seedLocalId;
7353
+ if (!sid)
7354
+ continue;
7355
+ const list = bySeed.get(sid) ?? [];
7356
+ list.push(r);
7357
+ bySeed.set(sid, list);
7358
+ }
7359
+ for (const [sid, list] of bySeed) {
7360
+ const sorted = [...list].sort((a, b) => {
7361
+ const ca = a.createdAt ?? 0;
7362
+ const cb = b.createdAt ?? 0;
7363
+ if (cb !== ca)
7364
+ return cb - ca;
7365
+ return String(b.localId ?? '').localeCompare(String(a.localId ?? ''));
7366
+ });
7367
+ const hit = sorted.find((r) => r.uid && isValidEasAttestationUid(r.uid));
7368
+ if (hit?.uid) {
7369
+ out.set(sid, { uid: hit.uid, localId: hit.localId ?? null });
7370
+ }
7371
+ }
7372
+ return out;
7373
+ }
7374
+
7375
+ /**
7376
+ * List item rows for list UIs. Only includes seeds that have at least one version.
7377
+ *
7378
+ * - `includeEas: false` (default): drafts only — `seeds.uid` is null, empty, legacy `'NULL'`, or zero-bytes32.
7379
+ * On-chain seeds (real EAS seed UID) require `includeEas: true`.
7380
+ * - `latestVersionUid` / `latestVersionLocalId`: head version **row** by `created_at` (may be unattested).
7381
+ * - `publishedVersionUid` / `publishedVersionLocalId`: filled in a second batched read (same rules as
7382
+ * `getLatestPublishedVersionRow`).
7383
+ */
6829
7384
  const getItemsData = async ({ modelName, deleted, includeEas = false, addressFilter, }) => {
6830
7385
  const appDb = BaseDb.getAppDb();
6831
7386
  const conditions = [];
6832
7387
  if (!includeEas) {
6833
- conditions.push(or(isNull(seeds.uid), eq(seeds.uid, '')));
7388
+ conditions.push(or(isNull(seeds.uid), eq(seeds.uid, ''), eq(seeds.uid, 'NULL'), eq(seeds.uid, ZERO_BYTES32)));
6834
7389
  }
6835
7390
  if (modelName) {
6836
7391
  conditions.push(eq(seeds.type, toSnakeCase$1(modelName)));
@@ -6879,10 +7434,20 @@ const getItemsData = async ({ modelName, deleted, includeEas = false, addressFil
6879
7434
  .from(seeds)
6880
7435
  .leftJoin(versionData, eq(seeds.localId, versionData.seedLocalId))
6881
7436
  .where(and(gt(versionData.versionsCount, 0), ...conditions))
6882
- .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC'))
6883
- .groupBy(seeds.localId);
7437
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
6884
7438
  const itemsData = (await query);
6885
- return itemsData;
7439
+ const seedIds = itemsData
7440
+ .map((r) => r.seedLocalId)
7441
+ .filter((id) => typeof id === 'string' && id !== '');
7442
+ const publishedBySeed = await batchLatestPublishedVersionBySeedLocalIds(seedIds);
7443
+ return itemsData.map((row) => {
7444
+ const pub = row.seedLocalId ? publishedBySeed.get(row.seedLocalId) : undefined;
7445
+ return {
7446
+ ...row,
7447
+ publishedVersionUid: pub?.uid,
7448
+ publishedVersionLocalId: pub?.localId ?? undefined,
7449
+ };
7450
+ });
6886
7451
  };
6887
7452
 
6888
7453
  const resolveRemoteStorage = fromCallback(({ sendBack, input: { context } }) => {
@@ -7049,25 +7614,6 @@ const initialize = fromCallback(({ sendBack, input: { context } }) => {
7049
7614
  });
7050
7615
  });
7051
7616
 
7052
- const seedUidToStorageTransactionId = new Map();
7053
- const getStorageTransactionIdForSeedUid = async (seedUid) => {
7054
- if (seedUidToStorageTransactionId.has(seedUid)) {
7055
- return seedUidToStorageTransactionId.get(seedUid);
7056
- }
7057
- const appDb = BaseDb.getAppDb();
7058
- const results = (await appDb
7059
- .select({
7060
- storageTransactionId: metadata$1.propertyValue,
7061
- })
7062
- .from(metadata$1)
7063
- .where(and(eq(metadata$1.seedUid, seedUid), eq(metadata$1.propertyName, 'storageTransactionId'))));
7064
- if (!results || results.length === 0) {
7065
- return;
7066
- }
7067
- seedUidToStorageTransactionId.set(seedUid, results[0].storageTransactionId);
7068
- return results[0].storageTransactionId;
7069
- };
7070
-
7071
7617
  const getRelationValueData = async (propertyValue) => {
7072
7618
  const appDb = BaseDb.getAppDb();
7073
7619
  const rows = (await appDb
@@ -7097,7 +7643,7 @@ const resolveRelatedValue = fromCallback(({ sendBack, input: { context } }) => {
7097
7643
  const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
7098
7644
  const _resolveRelatedValue = async () => {
7099
7645
  // Use dynamic import to break circular dependency
7100
- const schemaMod = await import('./index-DvUyNZc9.js');
7646
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
7101
7647
  const { ModelPropertyDataTypes } = schemaMod;
7102
7648
  if (!propertyValue || !isRelation || populatedFromDb) {
7103
7649
  return;
@@ -7473,7 +8019,7 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
7473
8019
  // to use dynamically imported ModelPropertyDataTypes
7474
8020
  const _hydrateFromDb = async () => {
7475
8021
  // Use dynamic import to break circular dependency
7476
- const schemaMod = await import('./index-DvUyNZc9.js');
8022
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
7477
8023
  const { ModelPropertyDataTypes } = schemaMod;
7478
8024
  const appDb = BaseDb.getAppDb();
7479
8025
  const whereClauses = [];
@@ -7778,7 +8324,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
7778
8324
  };
7779
8325
  // Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
7780
8326
  try {
7781
- const { getPropertySchema } = await import('./property-BNt7Dkmw.js');
8327
+ const { getPropertySchema } = await import('./property-C63Ddzap.js');
7782
8328
  let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
7783
8329
  if (!schemaFromFile?.validation) {
7784
8330
  // Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
@@ -8162,9 +8708,9 @@ const analyzeInput = fromCallback(({ sendBack, input: { context, event } }) => {
8162
8708
  }
8163
8709
  const _analyzeInput = async () => {
8164
8710
  // Use dynamic import to break circular dependency
8165
- const schemaMod = await import('./index-DvUyNZc9.js');
8711
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
8166
8712
  const { ModelPropertyDataTypes } = schemaMod;
8167
- const { SchemaValidationService } = await import('./SchemaValidationService-Cwkeb4fG.js');
8713
+ const { SchemaValidationService } = await import('./SchemaValidationService-Cb-b4kpD.js');
8168
8714
  let propertyName = propertyNameRaw;
8169
8715
  if (!propertyName) {
8170
8716
  throw new Error('propertyName is required');
@@ -8362,7 +8908,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8362
8908
  propertyRecordSchema?.validation &&
8363
8909
  metadataValues.propertyValue != null &&
8364
8910
  metadataValues.propertyValue !== '') {
8365
- const { SchemaValidationService } = await import('./SchemaValidationService-Cwkeb4fG.js');
8911
+ const { SchemaValidationService } = await import('./SchemaValidationService-Cb-b4kpD.js');
8366
8912
  const validationService = new SchemaValidationService();
8367
8913
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
8368
8914
  if (!validationResult.isValid && validationResult.errors.length > 0) {
@@ -8949,7 +9495,7 @@ const saveRelation = fromCallback(({ sendBack, input: { context, event } }) => {
8949
9495
  }
8950
9496
  const _saveRelation = async () => {
8951
9497
  // Use dynamic import to break circular dependency
8952
- const schemaMod = await import('./index-DvUyNZc9.js');
9498
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
8953
9499
  const { ModelPropertyDataTypes } = schemaMod;
8954
9500
  if (!propertyNameRaw) {
8955
9501
  throw new Error('propertyName is required');
@@ -9964,7 +10510,9 @@ class ItemProperty {
9964
10510
  }
9965
10511
  }
9966
10512
  }
9967
- if (!this._alias && propertyName.endsWith('Id')) {
10513
+ if (!this._alias &&
10514
+ propertyName.endsWith('Id') &&
10515
+ !PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP.has(propertyName)) {
9968
10516
  this._alias = propertyName.slice(0, -2);
9969
10517
  }
9970
10518
  else if (!this._alias && propertyName.endsWith('Ids')) {
@@ -9981,7 +10529,7 @@ class ItemProperty {
9981
10529
  return;
9982
10530
  }
9983
10531
  // Use dynamic import to break circular dependency
9984
- const schemaMod = await import('./index-DvUyNZc9.js');
10532
+ const schemaMod = await import('./index-Cqf_DxkJ.js');
9985
10533
  const { ModelPropertyDataTypes } = schemaMod;
9986
10534
  const { context } = snapshot;
9987
10535
  const { propertyRecordSchema } = context;
@@ -10139,7 +10687,7 @@ class ItemProperty {
10139
10687
  const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
10140
10688
  const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
10141
10689
  const propertyNameVariant = propertyNames.length > 1 ? propertyNames[1] : undefined;
10142
- const _mod_6 = await import('./index-dDmXPEJC.js');
10690
+ const _mod_6 = await import('./index-DdzhrbkF.js');
10143
10691
  const _ns_6 = _mod_6.s;
10144
10692
  const seedSchemaMod = _ns_6;
10145
10693
  const { metadata } = seedSchemaMod;
@@ -10840,7 +11388,7 @@ class ItemProperty {
10840
11388
  }
10841
11389
  async save() {
10842
11390
  const ctx = this._getSnapshotContext();
10843
- const { assertItemOwned } = await import('./ownership-C7GyMbsf.js');
11391
+ const { assertItemOwned } = await import('./ownership-BK6suksO.js');
10844
11392
  await assertItemOwned({
10845
11393
  seedLocalId: ctx?.seedLocalId ?? undefined,
10846
11394
  seedUid: ctx?.seedUid ?? undefined,
@@ -10933,7 +11481,7 @@ class ItemProperty {
10933
11481
  if (!propertyName || (!seedLocalId && !seedUid))
10934
11482
  return;
10935
11483
  if (db) {
10936
- const _mod_7 = await import('./index-dDmXPEJC.js');
11484
+ const _mod_7 = await import('./index-DdzhrbkF.js');
10937
11485
  const _ns_7 = _mod_7.s;
10938
11486
  const seedSchemaMod = _ns_7;
10939
11487
  const { metadata } = seedSchemaMod;
@@ -11079,7 +11627,7 @@ const deleteItem = async ({ seedLocalId, seedUid }) => {
11079
11627
  * Updates seedUid and optionally publisher. Publisher is immutable once set:
11080
11628
  * we never overwrite an existing publisher (set at creation or from attestation).
11081
11629
  */
11082
- const updateSeedUid = async ({ seedLocalId, seedUid, publisher, }) => {
11630
+ const updateSeedUid = async ({ seedLocalId, seedUid, publisher, attestationCreatedAt, }) => {
11083
11631
  if (!seedLocalId || !seedUid) {
11084
11632
  return;
11085
11633
  }
@@ -11100,6 +11648,7 @@ const updateSeedUid = async ({ seedLocalId, seedUid, publisher, }) => {
11100
11648
  .set({
11101
11649
  uid: seedUid,
11102
11650
  ...(shouldSetPublisher && { publisher }),
11651
+ ...(attestationCreatedAt != null && { attestationCreatedAt }),
11103
11652
  updatedAt: Date.now(),
11104
11653
  })
11105
11654
  .where(eq(seeds.localId, seedLocalId));
@@ -11180,7 +11729,7 @@ class Item {
11180
11729
  });
11181
11730
  };
11182
11731
  this.unpublish = async () => {
11183
- const { assertItemOwned } = await import('./ownership-C7GyMbsf.js');
11732
+ const { assertItemOwned } = await import('./ownership-BK6suksO.js');
11184
11733
  const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
11185
11734
  await assertItemOwned(this);
11186
11735
  const seedUid = this.seedUid;
@@ -11204,7 +11753,7 @@ class Item {
11204
11753
  this._service.send({ type: 'updateContext', revokedAt });
11205
11754
  };
11206
11755
  this.publish = async () => {
11207
- const { assertItemOwned } = await import('./ownership-C7GyMbsf.js');
11756
+ const { assertItemOwned } = await import('./ownership-BK6suksO.js');
11208
11757
  await assertItemOwned(this);
11209
11758
  this._service.send({ type: 'startPublish' });
11210
11759
  return new Promise((resolve, reject) => {
@@ -11240,21 +11789,26 @@ class Item {
11240
11789
  };
11241
11790
  this.getPublishUploads = async (options) => {
11242
11791
  // Use dynamic import to break circular dependency
11243
- const getPublishUploadsMod = await import('./getPublishUploads-DTE4SEWk.js');
11792
+ const getPublishUploadsMod = await import('./getPublishUploads-DS2dQ4Ho.js');
11244
11793
  const { getPublishUploads } = getPublishUploadsMod;
11245
11794
  return await getPublishUploads(this, [], undefined, options);
11246
11795
  };
11247
11796
  this.getPublishPayload = async (uploadedTransactions, options) => {
11248
- const getPublishPayloadMod = await import('./getPublishPayload-CMhy9jfz.js');
11797
+ const getPublishPayloadMod = await import('./getPublishPayload-DpYwi-rd.js');
11249
11798
  const { getPublishPayload } = getPublishPayloadMod;
11250
11799
  return await getPublishPayload(this, uploadedTransactions, options);
11251
11800
  };
11252
- this.persistSeedUid = async (publisher) => {
11801
+ this.persistSeedUid = async (publisher, attestationCreatedAtMs) => {
11253
11802
  const ctx = this._getSnapshotContext();
11254
11803
  const seedLocalId = ctx.seedLocalId;
11255
11804
  const seedUid = ctx.seedUid;
11256
11805
  if (seedLocalId && seedUid && typeof seedUid === 'string' && seedUid.length > 0) {
11257
- await updateSeedUid({ seedLocalId, seedUid, publisher });
11806
+ await updateSeedUid({
11807
+ seedLocalId,
11808
+ seedUid,
11809
+ publisher,
11810
+ ...(attestationCreatedAtMs != null && { attestationCreatedAt: attestationCreatedAtMs }),
11811
+ });
11258
11812
  }
11259
11813
  };
11260
11814
  const { modelName, seedUid, schemaUid, seedLocalId, latestVersionLocalId, latestVersionUid, modelInstance, publisher, } = initialValues;
@@ -11298,7 +11852,9 @@ class Item {
11298
11852
  transformedKey = key.slice(0, -3); // Remove 'Ids'
11299
11853
  transformedKey = pluralize(transformedKey);
11300
11854
  }
11301
- if (!propertyInstance.alias && key.endsWith('Id')) {
11855
+ if (!propertyInstance.alias &&
11856
+ key.endsWith('Id') &&
11857
+ !PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP.has(key)) {
11302
11858
  transformedKey = key.slice(0, -2); // Remove 'Id'
11303
11859
  }
11304
11860
  propertiesObj[transformedKey] = propertyInstance;
@@ -11372,9 +11928,8 @@ class Item {
11372
11928
  const modelPropertyNames = this._getModelPropertyNames(schemaNameForModel);
11373
11929
  const schemaKeys = modelPropertyNames.length > 0 ? modelPropertyNames : Object.keys(propertySchemas);
11374
11930
  // Normalize Id-suffix keys from initialValues: metadata stores textId but schema defines text
11375
- const ID_SUFFIX_NO_NORMALIZE = new Set(['storageTransactionId']);
11376
11931
  const normalizedKeysFromInitial = keysFromInitial.map((key) => {
11377
- if (key.endsWith('Id') && !ID_SUFFIX_NO_NORMALIZE.has(key)) {
11932
+ if (key.endsWith('Id') && !PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP.has(key)) {
11378
11933
  const baseName = key.slice(0, -2);
11379
11934
  if (schemaKeys.length > 0 && schemaKeys.includes(baseName))
11380
11935
  return baseName;
@@ -11430,7 +11985,18 @@ class Item {
11430
11985
  }
11431
11986
  if (!waitForReady)
11432
11987
  return instance;
11433
- await waitForEntityIdle(instance, { timeout: readyTimeout });
11988
+ try {
11989
+ await waitForEntityIdle(instance, { timeout: readyTimeout });
11990
+ }
11991
+ catch (err) {
11992
+ try {
11993
+ instance.unload();
11994
+ }
11995
+ catch {
11996
+ /* best-effort cache cleanup */
11997
+ }
11998
+ throw err;
11999
+ }
11434
12000
  return instance;
11435
12001
  }
11436
12002
  if (!this.instanceCache.has(seedId)) {
@@ -11528,7 +12094,18 @@ class Item {
11528
12094
  });
11529
12095
  if (!waitForReady)
11530
12096
  return proxiedInstance;
11531
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
12097
+ try {
12098
+ await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
12099
+ }
12100
+ catch (err) {
12101
+ try {
12102
+ proxiedInstance.unload();
12103
+ }
12104
+ catch {
12105
+ /* best-effort cache cleanup */
12106
+ }
12107
+ throw err;
12108
+ }
11532
12109
  return proxiedInstance;
11533
12110
  }
11534
12111
  }
@@ -11700,7 +12277,18 @@ class Item {
11700
12277
  });
11701
12278
  if (!waitForReady)
11702
12279
  return proxiedInstance;
11703
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
12280
+ try {
12281
+ await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
12282
+ }
12283
+ catch (err) {
12284
+ try {
12285
+ proxiedInstance.unload();
12286
+ }
12287
+ catch {
12288
+ /* best-effort cache cleanup */
12289
+ }
12290
+ throw err;
12291
+ }
11704
12292
  return proxiedInstance;
11705
12293
  }
11706
12294
  /**
@@ -12135,8 +12723,16 @@ class Item {
12135
12723
  }
12136
12724
  setupState.subscriptionSetUp = true;
12137
12725
  logger(`[Item._setupLiveQuerySubscription] Setting up liveQuery for seedLocalId: ${seedLocalId}`);
12726
+ const itemActor = this._service;
12727
+ const sendToItemMachine = (event) => {
12728
+ const status = itemActor.getSnapshot().status;
12729
+ if (status === 'stopped' || status === 'done') {
12730
+ return;
12731
+ }
12732
+ itemActor.send(event);
12733
+ };
12138
12734
  try {
12139
- const _mod_8 = await import('./index-dDmXPEJC.js');
12735
+ const _mod_8 = await import('./index-DdzhrbkF.js');
12140
12736
  const _ns_8 = _mod_8.s;
12141
12737
  const seedSchemaMod = _ns_8;
12142
12738
  const { seeds, versions, metadata } = seedSchemaMod;
@@ -12212,7 +12808,7 @@ class Item {
12212
12808
  }
12213
12809
  }
12214
12810
  // Update context with latest version info
12215
- this._service.send({
12811
+ sendToItemMachine({
12216
12812
  type: 'updateContext',
12217
12813
  latestVersionLocalId: currentVersionLocalId,
12218
12814
  latestVersionUid: seedRecord.latestVersionUid,
@@ -12267,7 +12863,7 @@ class Item {
12267
12863
  const seedRow = seedRows[0];
12268
12864
  logger(`[Item._setupLiveQuerySubscription] Seed updated in database`);
12269
12865
  // Update context with seed data
12270
- this._service.send({
12866
+ sendToItemMachine({
12271
12867
  type: 'updateContext',
12272
12868
  seedLocalId: seedRow.localId,
12273
12869
  seedUid: seedRow.uid || undefined,
@@ -12338,7 +12934,7 @@ class Item {
12338
12934
  modelName: itemModelName,
12339
12935
  });
12340
12936
  if (property) {
12341
- this._service.send({
12937
+ sendToItemMachine({
12342
12938
  type: 'addPropertyInstance',
12343
12939
  propertyName,
12344
12940
  propertyInstance: property,
@@ -12357,7 +12953,7 @@ class Item {
12357
12953
  }
12358
12954
  }
12359
12955
  // Update context with latest version info
12360
- this._service.send({
12956
+ sendToItemMachine({
12361
12957
  type: 'updateContext',
12362
12958
  latestVersionLocalId,
12363
12959
  latestVersionUid: latestVersion.uid || undefined,
@@ -12447,7 +13043,7 @@ class Item {
12447
13043
  * Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
12448
13044
  */
12449
13045
  async destroy() {
12450
- const { assertItemOwned } = await import('./ownership-C7GyMbsf.js');
13046
+ const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12451
13047
  await assertItemOwned(this);
12452
13048
  const context = this._getSnapshotContext();
12453
13049
  const cacheKey = context.seedUid || context.seedLocalId;
@@ -12508,37 +13104,6 @@ function normalizeAddressConfig(addresses) {
12508
13104
  };
12509
13105
  }
12510
13106
 
12511
- const isNode = () => {
12512
- return (typeof process !== 'undefined' &&
12513
- process.versions != null &&
12514
- process.versions.node != null);
12515
- };
12516
- const isBrowser = () => {
12517
- return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
12518
- };
12519
- const isElectron = () => {
12520
- return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
12521
- };
12522
-
12523
- /**
12524
- * @deprecated Use BaseArweaveClient.setHost() instead.
12525
- * This function is kept for backward compatibility but will be removed in a future version.
12526
- */
12527
- const setArweaveDomain = (newDomain) => {
12528
- BaseArweaveClient.setHost(newDomain);
12529
- };
12530
-
12531
- const logger$c = debug('seedSdk:services:events');
12532
- const handleServiceSaveState = (event) => {
12533
- const { state, serviceId } = event;
12534
- logger$c(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
12535
- // TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
12536
- // localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
12537
- };
12538
- const setupServicesEventHandlers = () => {
12539
- eventEmitter.addListener('service.saveState.request', handleServiceSaveState);
12540
- };
12541
-
12542
13107
  // Dynamic import to break circular dependency: Model -> BaseItem -> ... -> getModelSchemas -> Model
12543
13108
  // import { Model } from '@/Model/Model'
12544
13109
  const schemaStringToModelRecord = new Map();
@@ -13109,6 +13674,37 @@ const syncDbWithEasHandler = throttle(async (_) => {
13109
13674
  trailing: false,
13110
13675
  });
13111
13676
 
13677
+ const isNode = () => {
13678
+ return (typeof process !== 'undefined' &&
13679
+ process.versions != null &&
13680
+ process.versions.node != null);
13681
+ };
13682
+ const isBrowser = () => {
13683
+ return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
13684
+ };
13685
+ const isElectron = () => {
13686
+ return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
13687
+ };
13688
+
13689
+ /**
13690
+ * @deprecated Use BaseArweaveClient.setHost() instead.
13691
+ * This function is kept for backward compatibility but will be removed in a future version.
13692
+ */
13693
+ const setArweaveDomain = (newDomain) => {
13694
+ BaseArweaveClient.setHost(newDomain);
13695
+ };
13696
+
13697
+ const logger$c = debug('seedSdk:services:events');
13698
+ const handleServiceSaveState = (event) => {
13699
+ const { state, serviceId } = event;
13700
+ logger$c(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
13701
+ // TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
13702
+ // localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
13703
+ };
13704
+ const setupServicesEventHandlers = () => {
13705
+ eventEmitter.addListener('service.saveState.request', handleServiceSaveState);
13706
+ };
13707
+
13112
13708
  const setupAllItemsEventHandlers = () => {
13113
13709
  eventEmitter.addListener('syncDbWithEas', syncDbWithEasHandler);
13114
13710
  };
@@ -13182,20 +13778,20 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13182
13778
  let PathResolver;
13183
13779
  let EasClient;
13184
13780
  if (isBrowser()) {
13185
- FileManager = (await import('./FileManager-Ba1qAT8_.js')).FileManager;
13186
- Db = (await import('./Db-CCMLWMi-.js')).Db;
13187
- QueryClient = (await import('./QueryClient-BqpbpJEP.js')).QueryClient;
13188
- ArweaveClient = (await import('./ArweaveClient-Ck4wflb3.js')).ArweaveClient;
13189
- PathResolver = (await import('./PathResolver-B5XBxiLt.js')).PathResolver;
13190
- EasClient = (await import('./EasClient-Bqzb-xF2.js')).EasClient;
13781
+ FileManager = (await import('./FileManager-DHnyb040.js')).FileManager;
13782
+ Db = (await import('./Db-CXwQVLZv.js')).Db;
13783
+ QueryClient = (await import('./QueryClient-unspcsWa.js')).QueryClient;
13784
+ ArweaveClient = (await import('./ArweaveClient-Cz9ZLiEV.js')).ArweaveClient;
13785
+ PathResolver = (await import('./PathResolver-pmw--Ea2.js')).PathResolver;
13786
+ EasClient = (await import('./EasClient-DjpbHjU9.js')).EasClient;
13191
13787
  }
13192
13788
  else if (isNode()) {
13193
- FileManager = (await import('./FileManager-rVAH7uNp.js')).FileManager;
13194
- Db = (await import('./Db-YFg99EDt.js')).Db;
13195
- QueryClient = (await import('./QueryClient-5NAcOOvw.js')).QueryClient;
13196
- ArweaveClient = (await import('./ArweaveClient-C1bakApw.js')).ArweaveClient;
13197
- PathResolver = (await import('./PathResolver-CzhXp_OH.js')).PathResolver;
13198
- EasClient = (await import('./EasClient-BmYeAnq7.js')).EasClient;
13789
+ FileManager = (await import('./FileManager-CKyoLrBP.js')).FileManager;
13790
+ Db = (await import('./Db-DkTBncAM.js')).Db;
13791
+ QueryClient = (await import('./QueryClient-OUjfvY3g.js')).QueryClient;
13792
+ ArweaveClient = (await import('./ArweaveClient-DxpJnJXU.js')).ArweaveClient;
13793
+ PathResolver = (await import('./PathResolver-Ce4K9acQ.js')).PathResolver;
13794
+ EasClient = (await import('./EasClient-JYkmHxu1.js')).EasClient;
13199
13795
  }
13200
13796
  else {
13201
13797
  throw new Error(`Unable to determine environment. isBrowser()=${isBrowser()}, isNode()=${isNode()}. Platform-specific implementations could not be loaded.`);
@@ -13269,6 +13865,7 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13269
13865
  dbConfig,
13270
13866
  schemaFile,
13271
13867
  schema,
13868
+ syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? false,
13272
13869
  } });
13273
13870
  if (arweaveDomain) {
13274
13871
  setArweaveDomain(arweaveDomain);
@@ -16192,8 +16789,64 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
16192
16789
  };
16193
16790
  });
16194
16791
 
16792
+ /** Emitted by the client manager after `app_state.addresses` is written (post-`setAddresses`). */
16793
+ const ADDRESSES_PERSISTED_EVENT = 'addresses.persisted';
16794
+ function parseAddressesPersistedPayload(value) {
16795
+ if (!value || typeof value !== 'object') {
16796
+ return { owned: [], watched: [] };
16797
+ }
16798
+ const v = value;
16799
+ const owned = Array.isArray(v.owned)
16800
+ ? v.owned.filter((a) => typeof a === 'string')
16801
+ : [];
16802
+ const watched = Array.isArray(v.watched)
16803
+ ? v.watched.filter((a) => typeof a === 'string')
16804
+ : [];
16805
+ return { owned, watched };
16806
+ }
16807
+
16195
16808
  const { UNINITIALIZED, PLATFORM_CLASSES_INIT, FILE_SYSTEM_INIT, DB_INIT, SAVE_CONFIG, PROCESS_SCHEMA_FILES, ADD_MODELS_TO_STORE, ADD_MODELS_TO_DB, IDLE, } = ClientManagerState;
16196
16809
  const { UPDATE_CONTEXT, PLATFORM_CLASSES_READY, FILE_SYSTEM_READY, DB_READY, SAVE_CONFIG_SUCCESS, SAVE_APP_STATE_SUCCESS, SET_ADDRESSES, ADD_MODELS_TO_STORE_SUCCESS, ADD_MODELS_TO_DB_SUCCESS, PROCESS_SCHEMA_FILES_SUCCESS, } = ClientManagerEvents;
16810
+ const logSyncAfterAddressSave = debug("seedSdk:client:clientManagerMachine:syncAfterAddressSave");
16811
+ function addressesFromPersistedAddressValue(value) {
16812
+ if (!value || typeof value !== "object")
16813
+ return [];
16814
+ const v = value;
16815
+ const owned = Array.isArray(v.owned)
16816
+ ? v.owned.filter((a) => typeof a === "string")
16817
+ : [];
16818
+ const watched = Array.isArray(v.watched)
16819
+ ? v.watched.filter((a) => typeof a === "string")
16820
+ : [];
16821
+ const seen = new Set();
16822
+ const out = [];
16823
+ for (const a of [...owned, ...watched]) {
16824
+ const k = a.toLowerCase();
16825
+ if (!seen.has(k)) {
16826
+ seen.add(k);
16827
+ out.push(a);
16828
+ }
16829
+ }
16830
+ return out;
16831
+ }
16832
+ function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
16833
+ if (!context.syncFromEasOnAddressChange)
16834
+ return;
16835
+ if (event.key !== "addresses")
16836
+ return;
16837
+ const merged = addressesFromPersistedAddressValue(event.value);
16838
+ if (merged.length === 0)
16839
+ return;
16840
+ void runSyncFromEas({ addresses: merged }).catch((err) => {
16841
+ logSyncAfterAddressSave("runSyncFromEas after address save failed", err);
16842
+ });
16843
+ }
16844
+ function emitAddressesPersistedIfAddressesKey(event) {
16845
+ if (event.key !== "addresses")
16846
+ return;
16847
+ const payload = parseAddressesPersistedPayload(event.value);
16848
+ eventEmitter.emit(ADDRESSES_PERSISTED_EVENT, payload);
16849
+ }
16197
16850
  const clientManagerMachine = setup({
16198
16851
  types: {
16199
16852
  context: {},
@@ -16352,12 +17005,18 @@ const clientManagerMachine = setup({
16352
17005
  }),
16353
17006
  on: {
16354
17007
  [SAVE_APP_STATE_SUCCESS]: {
16355
- actions: assign(({ event }) => {
16356
- const { key, value } = event;
16357
- return {
16358
- isSaving: false
16359
- };
16360
- }),
17008
+ actions: [
17009
+ assign(({ event }) => {
17010
+ return {
17011
+ isSaving: false,
17012
+ };
17013
+ }),
17014
+ ({ context, event }) => maybeRunSyncFromEasAfterAddressSave({
17015
+ context,
17016
+ event: event,
17017
+ }),
17018
+ ({ event }) => emitAddressesPersistedIfAddressesKey(event),
17019
+ ],
16361
17020
  },
16362
17021
  [SET_ADDRESSES]: {
16363
17022
  actions: [
@@ -16396,6 +17055,7 @@ const clientManager = createActor(clientManagerMachine, {
16396
17055
  isInitialized: false,
16397
17056
  addressesSet: false,
16398
17057
  isSaving: false,
17058
+ syncFromEasOnAddressChange: false,
16399
17059
  }
16400
17060
  });
16401
17061
  const subscription = clientManager.subscribe((snapshot) => {
@@ -16444,6 +17104,7 @@ const clientInstance = {
16444
17104
  isInitialized: false,
16445
17105
  addressesSet: false,
16446
17106
  isSaving: false,
17107
+ syncFromEasOnAddressChange: false,
16447
17108
  endpoints: undefined,
16448
17109
  addresses: undefined,
16449
17110
  ownedAddresses: undefined,
@@ -16730,7 +17391,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
16730
17391
  // Lazy import cache for ModelProperty to avoid circular dependency
16731
17392
  // Eagerly start loading to minimize delay on first access
16732
17393
  let ModelPropertyClass = null;
16733
- const modelPropertyImportPromise = import('./ModelProperty-Csj84uQv.js')
17394
+ const modelPropertyImportPromise = import('./ModelProperty-DWtv9fQr.js')
16734
17395
  .then(module => {
16735
17396
  ModelPropertyClass = module.ModelProperty;
16736
17397
  return ModelPropertyClass;
@@ -16747,7 +17408,7 @@ function getModelProperty() {
16747
17408
  }
16748
17409
  // Lazy import cache for Schema to avoid circular dependency
16749
17410
  let SchemaClass = null;
16750
- const schemaImportPromise = (async () => { const _mod_9 = await import('./Schema-QjwZN91G.js'); return _mod_9.b; })()
17411
+ const schemaImportPromise = (async () => { const _mod_9 = await import('./Schema-CqqcEexA.js'); return _mod_9.b; })()
16751
17412
  .then(module => {
16752
17413
  SchemaClass = module.Schema;
16753
17414
  return SchemaClass;
@@ -18487,5 +19148,5 @@ var Model$1 = /*#__PURE__*/Object.freeze({
18487
19148
  const TModelValues = Type.Record(Type.String(), Type.Any());
18488
19149
  const TModelSchema = Type.Record(Type.String(), TProperty);
18489
19150
 
18490
- export { SEED_CONFIG_FILE as $, versions as A, Boolean$1 as B, modelPropertiesToObject as C, Date$1 as D, parseListPropertyValueFromStorage as E, File$1 as F, getCorrectId as G, INTERNAL_PROPERTY_NAMES as H, Image as I, Json as J, defaultAttestationData as K, List as L, Model as M, Number$1 as N, INTERNAL_DATA_TYPES as O, Property as P, toSnakeCase as Q, Relation as R, getEasSchemaUidForSchemaDefinition as S, TModelValues as T, getEasSchemaForItemProperty as U, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as V, getItemData as W, resolveStorageNameToSchemaName as X, appState as Y, ZERO_BYTES32 as Z, BasePathResolver as _, TModelSchema as a, SeedModels as a$, SEED_CONFIG_FALLBACKS as a0, BaseEasClient as a1, EAS_ENDPOINT as a2, BaseQueryClient as a3, arweaveL1FinalizeJobs as a4, config as a5, metadata$1 as a6, modelRelations as a7, modelSchemas as a8, modelUids as a9, waitForEntityIdle as aA, createReactiveProxy as aB, findEntity as aC, forceRemoveFromCaches as aD, runDestroyLifecycle as aE, getModelId as aF, getClient as aG, ClientManagerState as aH, MachineIds as aI, createNewItem as aJ, getVersionData$1 as aK, getMetadataLatest as aL, loadAllSchemasFromDb as aM, propertyMachine as aN, SEED_PROTOCOL_SCHEMA_NAME as aO, ImageSize as aP, setSchemaUidForSchemaDefinition as aQ, setSchemaUidForModel as aR, getModelSchemasFromEas as aS, getItemVersionsFromEas as aT, getItemPropertiesFromEas as aU, getCanonicalItemPropertiesFromEas as aV, getEasSchemaUidBySchemaName as aW, getSeedsFromSchemaUids as aX, getSeedsBySchemaName as aY, withExcludeRevokedFilter as aZ, pickLatestPropertyAttestationsByRefAndSchema as a_, modelsRelations as aa, propertiesRelations as ab, propertyUidRelations as ac, propertyUids as ad, publishProcesses as ae, schemas as af, uploadProcesses as ag, graphql as ah, getPropertyIdForModelAndName as ai, saveAppState as aj, addModelsToDb$1 as ak, SCHEMA_NJK as al, ItemProperty as am, eventEmitter as an, ClientManager as ao, INIT_SCRIPT_SUCCESS_MESSAGE as ap, SCHEMA_TS as aq, getRefValueType as ar, importJsonSchema as as, loadSchemaFromFile as at, readJsonImportFile as au, syncSchemaFromSource as av, transformImportToSchemaFile as aw, writeProcessMachine as ax, getModelIdByFileId as ay, generateId as az, ModelPropertyDataTypes as b, DEFAULT_ARWEAVE_HOST as b0, DEFAULT_ARWEAVE_GATEWAYS as b1, DEFAULT_ARWEAVE_GRAPHQL_URL as b2, updateSeedRevokedAt as b3, getAddressesForItemsFilter as b4, getArweaveUrlForTransaction as b5, normalizeUploadApiBaseUrl as b6, getUploadApiArweaveDataUrl as b7, getUploadPipelineTransactionStatus as b8, getUploadApiArweaveStatusUrl as b9, db as bA, eas as bB, getPropertyData$1 as bC, schema as bD, SEEDPROTOCOL_Seed_Protocol_v1 as bE, Model$1 as bF, getArweaveUploadStatus as ba, isArweaveL1AnchoringComplete as bb, queryArweaveGatewayTransaction as bc, setUploadExecutor as bd, getUploadExecutor as be, setGetPublisherForNewSeeds as bf, getGetPublisherForNewSeeds as bg, setRevokeExecutor as bh, getRevokeExecutor as bi, setAdditionalSyncAddresses as bj, createSchema as bk, readSchema as bl, listCompleteSchemaFiles as bm, getSchemaNameFromId as bn, addSchemaToDb as bo, createModelsFromJson as bp, loadModelsFromDbForSchema as bq, getLatestSchemaVersion as br, isInternalSchema as bs, createModelFromJson as bt, ConflictError as bu, unloadEntity as bv, clearDestroySubscriptions as bw, setupEntityLiveQuery as bx, ModelSchema as by, BaseFileManager$1 as bz, TPropertyDataType as c, TStorageType as d, TProperty as e, TPropertyConstructor as f, TPropertyDefs as g, PropertyMetadataKey as h, PropertyConstructor as i, Text as j, DEFAULT_TEXT_MAX_LENGTH as k, TValidationRules as l, getOwnedAddressesFromDb as m, normalizeDataType as n, BaseDb as o, getGetAdditionalSyncAddresses as p, normalizeRelationPropertyValue as q, resolveSeedIdsFromRefString as r, seeds as s, Item as t, BaseFileManager as u, getContentHash as v, BaseArweaveClient as w, getEasSchemaUidForModel as x, models$1 as y, properties as z };
18491
- //# sourceMappingURL=index-C1HlP_fU.js.map
19151
+ export { getItemData as $, models$1 as A, Boolean$1 as B, properties as C, Date$1 as D, isValidEasAttestationUid as E, File$1 as F, getLatestPublishedVersionRow as G, Html as H, Image as I, Json as J, modelPropertiesToObject as K, List as L, Model as M, Number$1 as N, parseListPropertyValueFromStorage as O, Property as P, getCorrectId as Q, Relation as R, INTERNAL_PROPERTY_NAMES as S, TModelValues as T, defaultAttestationData as U, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as V, INTERNAL_DATA_TYPES as W, toSnakeCase as X, getEasSchemaUidForSchemaDefinition as Y, ZERO_BYTES32 as Z, getEasSchemaForItemProperty as _, TModelSchema as a, setSchemaUidForModel as a$, resolveStorageNameToSchemaName as a0, appState as a1, BasePathResolver as a2, SEED_CONFIG_FILE as a3, SEED_CONFIG_FALLBACKS as a4, BaseEasClient as a5, EAS_ENDPOINT as a6, BaseQueryClient as a7, arweaveL1FinalizeJobs as a8, config as a9, syncSchemaFromSource as aA, transformImportToSchemaFile as aB, writeProcessMachine as aC, getModelIdByFileId as aD, generateId as aE, waitForEntityIdle as aF, createReactiveProxy as aG, findEntity as aH, forceRemoveFromCaches as aI, runDestroyLifecycle as aJ, getModelId as aK, isPlaceholderUid as aL, normalizeBytes32Hex as aM, getArweaveUrlForTransaction as aN, ADDRESSES_PERSISTED_EVENT as aO, parseAddressesPersistedPayload as aP, getClient as aQ, ClientManagerState as aR, MachineIds as aS, createNewItem as aT, getVersionData$1 as aU, getMetadataLatest as aV, loadAllSchemasFromDb as aW, propertyMachine as aX, SEED_PROTOCOL_SCHEMA_NAME as aY, ImageSize as aZ, setSchemaUidForSchemaDefinition as a_, metadata$1 as aa, modelRelations as ab, modelSchemas as ac, modelUids as ad, modelsRelations as ae, propertiesRelations as af, propertyUidRelations as ag, propertyUids as ah, publishProcesses as ai, schemas as aj, uploadProcesses as ak, versions as al, graphql as am, getPropertyIdForModelAndName as an, saveAppState as ao, addModelsToDb$1 as ap, SCHEMA_NJK as aq, ItemProperty as ar, eventEmitter as as, ClientManager as at, INIT_SCRIPT_SUCCESS_MESSAGE as au, SCHEMA_TS as av, getRefValueType as aw, importJsonSchema as ax, loadSchemaFromFile as ay, readJsonImportFile as az, ModelPropertyDataTypes as b, getModelSchemasFromEas as b0, getItemVersionsFromEas as b1, getItemPropertiesFromEas as b2, getCanonicalItemPropertiesFromEas as b3, getEasSchemaUidBySchemaName as b4, getSeedsFromSchemaUids as b5, getSeedsBySchemaName as b6, withExcludeRevokedFilter as b7, classifyMediaRef as b8, resolveMediaRef as b9, getSchemaNameFromId as bA, addSchemaToDb as bB, createModelsFromJson as bC, loadModelsFromDbForSchema as bD, getLatestSchemaVersion as bE, isInternalSchema as bF, createModelFromJson as bG, ConflictError as bH, unloadEntity as bI, clearDestroySubscriptions as bJ, setupEntityLiveQuery as bK, ModelSchema as bL, BaseFileManager$1 as bM, db as bN, eas as bO, getPropertyData$1 as bP, schema as bQ, SEEDPROTOCOL_Seed_Protocol_v1 as bR, Model$1 as bS, normalizeFeedItemFields as ba, getFeedItemStringField as bb, pickLatestPropertyAttestationsByRefAndSchema as bc, SeedModels as bd, DEFAULT_ARWEAVE_HOST as be, DEFAULT_ARWEAVE_GATEWAYS as bf, DEFAULT_ARWEAVE_GRAPHQL_URL as bg, updateSeedRevokedAt as bh, getAddressesForItemsFilter as bi, normalizeUploadApiBaseUrl as bj, getUploadApiArweaveDataUrl as bk, getUploadPipelineTransactionStatus as bl, getUploadApiArweaveStatusUrl as bm, getArweaveUploadStatus as bn, isArweaveL1AnchoringComplete as bo, queryArweaveGatewayTransaction as bp, setUploadExecutor as bq, getUploadExecutor as br, setGetPublisherForNewSeeds as bs, getGetPublisherForNewSeeds as bt, setRevokeExecutor as bu, getRevokeExecutor as bv, setAdditionalSyncAddresses as bw, createSchema as bx, readSchema as by, listCompleteSchemaFiles as bz, TPropertyDataType as c, TStorageType as d, THtmlEmbeddedDataUriPolicy as e, TProperty as f, TPropertyConstructor as g, TPropertyDefs as h, PropertyMetadataKey as i, PropertyConstructor as j, Text as k, DEFAULT_TEXT_MAX_LENGTH as l, TValidationRules as m, normalizeDataType as n, getOwnedAddressesFromDb as o, BaseDb as p, getGetAdditionalSyncAddresses as q, resolveSeedIdsFromRefString as r, seeds as s, normalizeRelationPropertyValue as t, Item as u, BaseFileManager as v, getContentHash as w, htmlEmbeddedImageCoPublish as x, BaseArweaveClient as y, getEasSchemaUidForModel as z };
19152
+ //# sourceMappingURL=index-BrD_NNaX.js.map