@seedprotocol/sdk 0.4.21 → 0.4.22

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 (174) hide show
  1. package/dist/{ArweaveClient-DxpJnJXU.js → ArweaveClient-B-vm2Xae.js} +3 -3
  2. package/dist/{ArweaveClient-DxpJnJXU.js.map → ArweaveClient-B-vm2Xae.js.map} +1 -1
  3. package/dist/{ArweaveClient-Cz9ZLiEV.js → ArweaveClient-C-eLH0zU.js} +3 -3
  4. package/dist/{ArweaveClient-Cz9ZLiEV.js.map → ArweaveClient-C-eLH0zU.js.map} +1 -1
  5. package/dist/{Db-CXwQVLZv.js → Db-B7whB3oJ.js} +107 -6
  6. package/dist/Db-B7whB3oJ.js.map +1 -0
  7. package/dist/{Db-DkTBncAM.js → Db-nir1xVHg.js} +4 -4
  8. package/dist/{Db-DkTBncAM.js.map → Db-nir1xVHg.js.map} +1 -1
  9. package/dist/{EasClient-DjpbHjU9.js → EasClient-BH_feMaX.js} +2 -2
  10. package/dist/{EasClient-JYkmHxu1.js.map → EasClient-BH_feMaX.js.map} +1 -1
  11. package/dist/{EasClient-JYkmHxu1.js → EasClient-CFguAKBp.js} +2 -2
  12. package/dist/{EasClient-DjpbHjU9.js.map → EasClient-CFguAKBp.js.map} +1 -1
  13. package/dist/{FileManager-CKyoLrBP.js → FileManager-BR3jtuSl.js} +2 -2
  14. package/dist/{FileManager-CKyoLrBP.js.map → FileManager-BR3jtuSl.js.map} +1 -1
  15. package/dist/{FileManager-DHnyb040.js → FileManager-C2uXql_C.js} +18 -2
  16. package/dist/FileManager-C2uXql_C.js.map +1 -0
  17. package/dist/{ModelProperty-DWtv9fQr.js → ModelProperty-CIeLasI4.js} +24 -24
  18. package/dist/{ModelProperty-DWtv9fQr.js.map → ModelProperty-CIeLasI4.js.map} +1 -1
  19. package/dist/{PathResolver-Ce4K9acQ.js → PathResolver-CZoSnHBU.js} +2 -2
  20. package/dist/{PathResolver-Ce4K9acQ.js.map → PathResolver-CZoSnHBU.js.map} +1 -1
  21. package/dist/{PathResolver-pmw--Ea2.js → PathResolver-DnrG1hUX.js} +2 -2
  22. package/dist/{PathResolver-pmw--Ea2.js.map → PathResolver-DnrG1hUX.js.map} +1 -1
  23. package/dist/{QueryClient-OUjfvY3g.js → QueryClient-DJOrJZRR.js} +3 -2
  24. package/dist/QueryClient-DJOrJZRR.js.map +1 -0
  25. package/dist/{QueryClient-unspcsWa.js → QueryClient-PqOg8mcw.js} +7 -3
  26. package/dist/QueryClient-PqOg8mcw.js.map +1 -0
  27. package/dist/{Schema-CqqcEexA.js → Schema-B3YQHTtu.js} +38 -38
  28. package/dist/{Schema-CqqcEexA.js.map → Schema-B3YQHTtu.js.map} +1 -1
  29. package/dist/{SchemaValidationService-Cb-b4kpD.js → SchemaValidationService-C4DIwn8Z.js} +2 -2
  30. package/dist/{SchemaValidationService-Cb-b4kpD.js.map → SchemaValidationService-C4DIwn8Z.js.map} +1 -1
  31. package/dist/{backfillMetadataPropertyIds-CRyRez3h.js → backfillMetadataPropertyIds-CBlRaU_M.js} +2 -2
  32. package/dist/{backfillMetadataPropertyIds-CRyRez3h.js.map → backfillMetadataPropertyIds-CBlRaU_M.js.map} +1 -1
  33. package/dist/cjs/{ModelProperty-sNx_ZQZX.js → ModelProperty-tfM38NL4.js} +17 -17
  34. package/dist/cjs/{ModelProperty-sNx_ZQZX.js.map → ModelProperty-tfM38NL4.js.map} +1 -1
  35. package/dist/cjs/{Schema-B4RRA-0g.js → Schema-44NqLqMV.js} +20 -20
  36. package/dist/cjs/{Schema-B4RRA-0g.js.map → Schema-44NqLqMV.js.map} +1 -1
  37. package/dist/cjs/{SchemaValidationService-DCflhpcI.js → SchemaValidationService-Cq_YBzFN.js} +2 -2
  38. package/dist/cjs/{SchemaValidationService-DCflhpcI.js.map → SchemaValidationService-Cq_YBzFN.js.map} +1 -1
  39. package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js → backfillMetadataPropertyIds-D1nLJAhB.js} +2 -2
  40. package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js.map → backfillMetadataPropertyIds-D1nLJAhB.js.map} +1 -1
  41. package/dist/cjs/{getItem-lyM2x5pT.js → getItem-BRoq91YU.js} +2 -2
  42. package/dist/cjs/{getItem-lyM2x5pT.js.map → getItem-BRoq91YU.js.map} +1 -1
  43. package/dist/cjs/{getPublishPayload-DP2fm4q8.js → getPublishPayload-ddl-1x6R.js} +11 -11
  44. package/dist/cjs/{getPublishPayload-DP2fm4q8.js.map → getPublishPayload-ddl-1x6R.js.map} +1 -1
  45. package/dist/cjs/{getPublishUploads-DdVy-5fK.js → getPublishUploads-BljRx4o4.js} +39 -6
  46. package/dist/cjs/getPublishUploads-BljRx4o4.js.map +1 -0
  47. package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js → getSegmentedItemProperties-iK5kepzl.js} +3 -3
  48. package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js.map → getSegmentedItemProperties-iK5kepzl.js.map} +1 -1
  49. package/dist/cjs/{index-D1qR8xnb.js → index-C6rrqy3z.js} +1980 -1113
  50. package/dist/cjs/index-C6rrqy3z.js.map +1 -0
  51. package/dist/cjs/{index-DTkoTvcq.js → index-DqSDhOp3.js} +3 -3
  52. package/dist/cjs/index-DqSDhOp3.js.map +1 -0
  53. package/dist/cjs/{ownership-DanM_n8E.js → ownership-CXlKAj4o.js} +2 -2
  54. package/dist/cjs/{ownership-DanM_n8E.js.map → ownership-CXlKAj4o.js.map} +1 -1
  55. package/dist/cjs/{property-BQokoaRe.js → property-2D7P6a2q.js} +4 -4
  56. package/dist/cjs/{property-BQokoaRe.js.map → property-2D7P6a2q.js.map} +1 -1
  57. package/dist/cjs/syncDbWithEas-DcKL-_Pb.js +610 -0
  58. package/dist/cjs/syncDbWithEas-DcKL-_Pb.js.map +1 -0
  59. package/dist/db/drizzle/drizzle/0013_eas_sync_processes.sql +12 -0
  60. package/dist/db/drizzle/drizzle/meta/0013_snapshot.json +1262 -0
  61. package/dist/db/drizzle/drizzle/meta/_journal.json +7 -0
  62. package/dist/{getItem-VI3QqdZH.js → getItem-CV3yTCRt.js} +2 -2
  63. package/dist/{getItem-VI3QqdZH.js.map → getItem-CV3yTCRt.js.map} +1 -1
  64. package/dist/{getPublishPayload-DpYwi-rd.js → getPublishPayload-Ddc_LGPs.js} +14 -14
  65. package/dist/{getPublishPayload-DpYwi-rd.js.map → getPublishPayload-Ddc_LGPs.js.map} +1 -1
  66. package/dist/{getPublishUploads-DS2dQ4Ho.js → getPublishUploads-Cf2J-5FR.js} +39 -6
  67. package/dist/getPublishUploads-Cf2J-5FR.js.map +1 -0
  68. package/dist/{getSegmentedItemProperties-Bz5B4DSA.js → getSegmentedItemProperties-B2mzArFD.js} +3 -3
  69. package/dist/{getSegmentedItemProperties-Bz5B4DSA.js.map → getSegmentedItemProperties-B2mzArFD.js.map} +1 -1
  70. package/dist/{index-Cqf_DxkJ.js → index-3Ekqb4QB.js} +3 -3
  71. package/dist/index-3Ekqb4QB.js.map +1 -0
  72. package/dist/{index-DdzhrbkF.js → index-BRo7D3s1.js} +3 -2
  73. package/dist/index-BRo7D3s1.js.map +1 -0
  74. package/dist/{index-BrD_NNaX.js → index-DUMXLKJr.js} +1991 -1125
  75. package/dist/index-DUMXLKJr.js.map +1 -0
  76. package/dist/main.cjs +1 -1
  77. package/dist/main.js +16 -41
  78. package/dist/main.js.map +1 -1
  79. package/dist/node.js +10 -10
  80. package/dist/{ownership-BK6suksO.js → ownership-TR-mIjJh.js} +2 -2
  81. package/dist/{ownership-BK6suksO.js.map → ownership-TR-mIjJh.js.map} +1 -1
  82. package/dist/{property-C63Ddzap.js → property-BSNWvgei.js} +6 -6
  83. package/dist/{property-C63Ddzap.js.map → property-BSNWvgei.js.map} +1 -1
  84. package/dist/{queries-BGuWjEqt.js → queries-0FZBThGQ.js} +2 -2
  85. package/dist/{queries-BGuWjEqt.js.map → queries-0FZBThGQ.js.map} +1 -1
  86. package/dist/seedSchema/EasSyncProcessSchema.ts +17 -0
  87. package/dist/seedSchema/index.ts +1 -0
  88. package/dist/src/Item/Item.d.ts +18 -0
  89. package/dist/src/Item/Item.d.ts.map +1 -1
  90. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  91. package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
  92. package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +1 -1
  93. package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts.map +1 -1
  94. package/dist/src/ItemProperty/service/propertyMachine.d.ts +4 -1
  95. package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
  96. package/dist/src/Model/service/modelMachine.d.ts +20 -20
  97. package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +2 -2
  98. package/dist/src/Schema/service/addModelsMachine.d.ts +1 -1
  99. package/dist/src/Schema/service/schemaMachine.d.ts +55 -55
  100. package/dist/src/browser/db/drizzleFiles.d.ts +3 -2
  101. package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
  102. package/dist/src/browser/helpers/QueryClient.d.ts.map +1 -1
  103. package/dist/src/client/ClientManager.d.ts.map +1 -1
  104. package/dist/src/client/actors/addModelsToDb.d.ts.map +1 -1
  105. package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
  106. package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
  107. package/dist/src/client/constants.d.ts +1 -0
  108. package/dist/src/client/constants.d.ts.map +1 -1
  109. package/dist/src/db/read/getPublishPendingDiff.d.ts.map +1 -1
  110. package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
  111. package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -1
  112. package/dist/src/db/write/easSyncProcess.d.ts +12 -0
  113. package/dist/src/db/write/easSyncProcess.d.ts.map +1 -0
  114. package/dist/src/db/write/updateItemPropertyValue.d.ts.map +1 -1
  115. package/dist/src/events/files/download.d.ts +5 -1
  116. package/dist/src/events/files/download.d.ts.map +1 -1
  117. package/dist/src/events/item/easSyncManager.d.ts +71 -0
  118. package/dist/src/events/item/easSyncManager.d.ts.map +1 -0
  119. package/dist/src/events/item/index.d.ts.map +1 -1
  120. package/dist/src/events/item/mergeEasSyncOptions.d.ts +7 -0
  121. package/dist/src/events/item/mergeEasSyncOptions.d.ts.map +1 -0
  122. package/dist/src/events/item/syncDbWithEas.d.ts +0 -3
  123. package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
  124. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts +17 -0
  125. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts.map +1 -1
  126. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts +6 -0
  127. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts.map +1 -1
  128. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts +16 -0
  129. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts.map +1 -0
  130. package/dist/src/helpers/FileManager/BaseFileManager.d.ts +1 -0
  131. package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
  132. package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts +16 -0
  133. package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts.map +1 -0
  134. package/dist/src/helpers/constants.d.ts +20 -5
  135. package/dist/src/helpers/constants.d.ts.map +1 -1
  136. package/dist/src/helpers/environment.d.ts +5 -0
  137. package/dist/src/helpers/environment.d.ts.map +1 -1
  138. package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -1
  139. package/dist/src/helpers/index.d.ts +1 -0
  140. package/dist/src/helpers/index.d.ts.map +1 -1
  141. package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts +8 -0
  142. package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts.map +1 -0
  143. package/dist/src/index.d.ts +7 -3
  144. package/dist/src/index.d.ts.map +1 -1
  145. package/dist/src/interfaces/IQueryClient.d.ts +4 -0
  146. package/dist/src/interfaces/IQueryClient.d.ts.map +1 -1
  147. package/dist/src/node/helpers/QueryClient.d.ts.map +1 -1
  148. package/dist/src/seedSchema/EasSyncProcessSchema.d.ts +190 -0
  149. package/dist/src/seedSchema/EasSyncProcessSchema.d.ts.map +1 -0
  150. package/dist/src/seedSchema/index.d.ts +1 -0
  151. package/dist/src/seedSchema/index.d.ts.map +1 -1
  152. package/dist/src/services/write/writeProcessMachine.d.ts +1 -1
  153. package/dist/src/types/fileManager.d.ts +5 -0
  154. package/dist/src/types/fileManager.d.ts.map +1 -1
  155. package/dist/src/types/index.d.ts +3 -2
  156. package/dist/src/types/index.d.ts.map +1 -1
  157. package/dist/src/types/machines.d.ts +1 -1
  158. package/dist/src/types/machines.d.ts.map +1 -1
  159. package/dist/syncDbWithEas-CaytdS8D.js +583 -0
  160. package/dist/syncDbWithEas-CaytdS8D.js.map +1 -0
  161. package/dist/updateSeedRevokedAt-CfUXirik.js +22 -0
  162. package/dist/updateSeedRevokedAt-CfUXirik.js.map +1 -0
  163. package/package.json +1 -1
  164. package/dist/Db-CXwQVLZv.js.map +0 -1
  165. package/dist/FileManager-DHnyb040.js.map +0 -1
  166. package/dist/QueryClient-OUjfvY3g.js.map +0 -1
  167. package/dist/QueryClient-unspcsWa.js.map +0 -1
  168. package/dist/cjs/getPublishUploads-DdVy-5fK.js.map +0 -1
  169. package/dist/cjs/index-D1qR8xnb.js.map +0 -1
  170. package/dist/cjs/index-DTkoTvcq.js.map +0 -1
  171. package/dist/getPublishUploads-DS2dQ4Ho.js.map +0 -1
  172. package/dist/index-BrD_NNaX.js.map +0 -1
  173. package/dist/index-Cqf_DxkJ.js.map +0 -1
  174. package/dist/index-DdzhrbkF.js.map +0 -1
@@ -198,6 +198,13 @@ class BaseFileManager {
198
198
  static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
199
199
  return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
200
200
  }
201
+ static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
202
+ return this.PlatformClass.downloadAllFiles({
203
+ transactionIds: [transactionId],
204
+ arweaveHost,
205
+ excludedTransactions,
206
+ });
207
+ }
201
208
  static resizeImage({ filePath, width, height }) {
202
209
  return this.PlatformClass.resizeImage({ filePath, width, height });
203
210
  }
@@ -406,8 +413,51 @@ var SeedModels;
406
413
  // Internal SDK schema that should not be created in app's files directory
407
414
  const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
408
415
  const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
409
- /** Default Arweave gateway host used across all packages */
410
- const DEFAULT_ARWEAVE_HOST = 'arweave.net';
416
+ /** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
417
+ const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
418
+ /**
419
+ * Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
420
+ * Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
421
+ */
422
+ const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
423
+ const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
424
+ /** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
425
+ function getDefaultArweaveReadGatewayHostsOrdered() {
426
+ if (typeof process === 'undefined' || !process.env) {
427
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
428
+ }
429
+ for (const key of READ_GATEWAYS_ENV_KEYS) {
430
+ const raw = process.env[key]?.trim();
431
+ if (raw) {
432
+ return raw.split(',').map((s) => s.trim()).filter(Boolean);
433
+ }
434
+ }
435
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
436
+ }
437
+ /**
438
+ * Deduped host list: primary first, then each default not already present (case-insensitive).
439
+ */
440
+ function mergePrimaryHostWithDefaults(primary, defaults) {
441
+ const seen = new Set();
442
+ const out = [];
443
+ const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
444
+ const add = (h) => {
445
+ const t = h.trim().replace(/\/$/, '');
446
+ if (!t)
447
+ return;
448
+ const k = keyOf(t);
449
+ if (seen.has(k))
450
+ return;
451
+ seen.add(k);
452
+ out.push(t);
453
+ };
454
+ add(primary);
455
+ for (const d of defaults)
456
+ add(d);
457
+ return out;
458
+ }
459
+ /** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
460
+ const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
411
461
  /**
412
462
  * Check if a schema is an internal SDK schema that should not be created in app files
413
463
  */
@@ -419,7 +469,9 @@ function isInternalSchema(schemaName, schemaId) {
419
469
  var constants = /*#__PURE__*/Object.freeze({
420
470
  __proto__: null,
421
471
  CLIENT_NOT_INITIALIZED: CLIENT_NOT_INITIALIZED,
472
+ DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
422
473
  DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
474
+ EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
423
475
  INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
424
476
  INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
425
477
  INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
@@ -437,7 +489,9 @@ var constants = /*#__PURE__*/Object.freeze({
437
489
  ZERO_BYTES: ZERO_BYTES,
438
490
  ZERO_BYTES32: ZERO_BYTES32,
439
491
  defaultAttestationData: defaultAttestationData,
440
- isInternalSchema: isInternalSchema
492
+ getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
493
+ isInternalSchema: isInternalSchema,
494
+ mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
441
495
  });
442
496
 
443
497
  function parseGateway(input) {
@@ -454,6 +508,8 @@ function parseGateway(input) {
454
508
  let _host = DEFAULT_ARWEAVE_HOST;
455
509
  let _protocol = 'https';
456
510
  let _hostExplicitlySet = false;
511
+ /** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
512
+ let _suppressEnvGatewayOverride = false;
457
513
  class BaseArweaveClient {
458
514
  static setPlatformClass(platformClass) {
459
515
  this.PlatformClass = platformClass;
@@ -466,7 +522,7 @@ class BaseArweaveClient {
466
522
  const envHost = typeof process !== 'undefined' && process.env
467
523
  ? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
468
524
  : undefined;
469
- if (envHost && !_hostExplicitlySet) {
525
+ if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
470
526
  return parseGateway(envHost);
471
527
  }
472
528
  }
@@ -504,6 +560,39 @@ class BaseArweaveClient {
504
560
  _host = parsed.host;
505
561
  _protocol = parsed.protocol;
506
562
  _hostExplicitlySet = true;
563
+ _suppressEnvGatewayOverride = false;
564
+ }
565
+ /**
566
+ * When true, read-path gateway probing does not change the host ({@link setHost}).
567
+ */
568
+ static isReadGatewayLocked() {
569
+ return _hostExplicitlySet;
570
+ }
571
+ /**
572
+ * @internal Clears env override suppression after probing (for test isolation).
573
+ */
574
+ static resetReadGatewaySelectionStateForTests() {
575
+ _suppressEnvGatewayOverride = false;
576
+ }
577
+ /**
578
+ * Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
579
+ * Used for seed `arweaveDomain`.
580
+ */
581
+ static setPreferredReadGateway(host) {
582
+ const parsed = parseGateway(host);
583
+ _host = parsed.host;
584
+ _protocol = parsed.protocol;
585
+ _hostExplicitlySet = false;
586
+ }
587
+ /**
588
+ * Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
589
+ */
590
+ static applyProbedReadGateway(host) {
591
+ const parsed = parseGateway(host);
592
+ _host = parsed.host;
593
+ _protocol = parsed.protocol;
594
+ _hostExplicitlySet = false;
595
+ _suppressEnvGatewayOverride = true;
507
596
  }
508
597
  /**
509
598
  * Get the GraphQL endpoint URL
@@ -587,6 +676,11 @@ class BaseArweaveClient {
587
676
  }
588
677
  }
589
678
 
679
+ var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
680
+ __proto__: null,
681
+ BaseArweaveClient: BaseArweaveClient
682
+ });
683
+
590
684
  /**
591
685
  * Trim and strip a trailing slash from an upload API base URL.
592
686
  */
@@ -638,6 +732,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
638
732
  }
639
733
  }
640
734
 
735
+ const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
736
+ const PROBE_TIMEOUT_MS = 5000;
737
+ let readGatewayCache = null;
738
+ let ensureInFlight = null;
739
+ /** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
740
+ function invalidateReadGatewayCache() {
741
+ readGatewayCache = null;
742
+ ensureInFlight = null;
743
+ }
744
+ /** Clears probe cache, env override suppression, and preferred host (for tests). */
745
+ function resetArweaveReadGatewayForTests() {
746
+ invalidateReadGatewayCache();
747
+ BaseArweaveClient.resetReadGatewaySelectionStateForTests();
748
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
749
+ BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
750
+ }
751
+ }
752
+ /**
753
+ * GET /info with timeout. Treat 2xx + JSON object as healthy.
754
+ */
755
+ async function probeGateway(baseUrl, signal) {
756
+ const url = `${baseUrl.replace(/\/$/, '')}/info`;
757
+ let timer;
758
+ const controller = new AbortController();
759
+ const effectiveSignal = signal ?? controller.signal;
760
+ if (!signal) {
761
+ timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
762
+ }
763
+ try {
764
+ const response = await fetch(url, {
765
+ method: 'GET',
766
+ signal: effectiveSignal,
767
+ headers: { Accept: 'application/json' },
768
+ });
769
+ if (!response.ok)
770
+ return false;
771
+ const text = await response.text();
772
+ if (!text.trim())
773
+ return false;
774
+ try {
775
+ const json = JSON.parse(text);
776
+ return typeof json === 'object' && json !== null;
777
+ }
778
+ catch {
779
+ return false;
780
+ }
781
+ }
782
+ catch {
783
+ return false;
784
+ }
785
+ finally {
786
+ if (timer)
787
+ clearTimeout(timer);
788
+ }
789
+ }
790
+ async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
791
+ for (const host of hosts) {
792
+ const h = host.trim().replace(/\/$/, '');
793
+ if (!h)
794
+ continue;
795
+ const baseUrl = `${protocol}://${h}`;
796
+ if (await probeGateway(baseUrl, signal)) {
797
+ return h;
798
+ }
799
+ }
800
+ return null;
801
+ }
802
+ function buildOrderedHostsForProbe() {
803
+ const primary = BaseArweaveClient.getHost();
804
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
805
+ return mergePrimaryHostWithDefaults(primary, defaults);
806
+ }
807
+ /**
808
+ * Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
809
+ * No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
810
+ * Uses a short TTL cache to avoid probing on every read.
811
+ */
812
+ async function ensureReadGatewaySelected(signal) {
813
+ if (BaseArweaveClient.isReadGatewayLocked()) {
814
+ return BaseArweaveClient.getHost();
815
+ }
816
+ const now = Date.now();
817
+ if (readGatewayCache && now < readGatewayCache.expiresAt) {
818
+ return readGatewayCache.host;
819
+ }
820
+ if (ensureInFlight) {
821
+ return ensureInFlight;
822
+ }
823
+ ensureInFlight = (async () => {
824
+ const ordered = buildOrderedHostsForProbe();
825
+ const protocol = BaseArweaveClient.getProtocol();
826
+ const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
827
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
828
+ if (picked) {
829
+ BaseArweaveClient.applyProbedReadGateway(picked);
830
+ }
831
+ }
832
+ readGatewayCache = {
833
+ host: BaseArweaveClient.getHost(),
834
+ expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
835
+ };
836
+ return readGatewayCache.host;
837
+ })();
838
+ try {
839
+ return await ensureInFlight;
840
+ }
841
+ finally {
842
+ ensureInFlight = null;
843
+ }
844
+ }
845
+
846
+ var selectReadGateway = /*#__PURE__*/Object.freeze({
847
+ __proto__: null,
848
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
849
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
850
+ probeGateway: probeGateway,
851
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
852
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
853
+ });
854
+
641
855
  const GATEWAY_TX_QUERY = `
642
856
  query ArweaveGatewayTransaction($id: String!) {
643
857
  transaction(id: $id) {
@@ -734,6 +948,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
734
948
  return null;
735
949
  }
736
950
  }
951
+ /**
952
+ * Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
953
+ * {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
954
+ * {@link getDefaultArweaveReadGatewayHostsOrdered}.
955
+ */
956
+ async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
957
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
958
+ const trimmed = graphqlUrl?.trim();
959
+ let protocol = 'https';
960
+ let preferredHost = null;
961
+ if (trimmed) {
962
+ try {
963
+ const u = new URL(trimmed);
964
+ protocol = u.protocol === 'http:' ? 'http' : 'https';
965
+ preferredHost = u.hostname || null;
966
+ }
967
+ catch {
968
+ preferredHost = null;
969
+ }
970
+ }
971
+ const ordered = preferredHost && preferredHost.length > 0
972
+ ? mergePrimaryHostWithDefaults(preferredHost, defaults)
973
+ : [...defaults];
974
+ const signal = init?.signal;
975
+ for (const host of ordered) {
976
+ const base = `${protocol}://${host}`;
977
+ if (!(await probeGateway(base, signal ?? undefined)))
978
+ continue;
979
+ const gqlUrl = `${protocol}://${host}/graphql`;
980
+ const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
981
+ if (result !== null) {
982
+ return result;
983
+ }
984
+ }
985
+ return null;
986
+ }
737
987
 
738
988
  class BaseEasClient {
739
989
  static setPlatformClass(platformClass) {
@@ -1409,6 +1659,19 @@ const arweaveL1FinalizeJobs = sqliteCore.sqliteTable('arweave_l1_finalize_jobs',
1409
1659
  dataItemIdUnique: sqliteCore.uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
1410
1660
  }));
1411
1661
 
1662
+ const easSyncProcesses = sqliteCore.sqliteTable('eas_sync_processes', {
1663
+ id: sqliteCore.int('id').primaryKey({ autoIncrement: true }),
1664
+ status: sqliteCore.text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
1665
+ startedAt: sqliteCore.int('started_at').notNull(),
1666
+ completedAt: sqliteCore.int('completed_at'),
1667
+ requestPayload: sqliteCore.text('request_payload').notNull(),
1668
+ errorMessage: sqliteCore.text('error_message'),
1669
+ errorDetails: sqliteCore.text('error_details'),
1670
+ persistedSnapshot: sqliteCore.text('persisted_snapshot').notNull(),
1671
+ createdAt: sqliteCore.int('created_at'),
1672
+ updatedAt: sqliteCore.int('updated_at'),
1673
+ });
1674
+
1412
1675
  /**
1413
1676
  * Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
1414
1677
  * Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
@@ -1430,6 +1693,7 @@ var schema$1 = /*#__PURE__*/Object.freeze({
1430
1693
  appState: appState,
1431
1694
  arweaveL1FinalizeJobs: arweaveL1FinalizeJobs,
1432
1695
  config: config,
1696
+ easSyncProcesses: easSyncProcesses,
1433
1697
  htmlEmbeddedImageCoPublish: htmlEmbeddedImageCoPublish,
1434
1698
  metadata: metadata$1,
1435
1699
  modelRelations: modelRelations,
@@ -1922,6 +2186,7 @@ var index = /*#__PURE__*/Object.freeze({
1922
2186
  capitalizeFirstLetter: capitalizeFirstLetter,
1923
2187
  classifyMediaRef: classifyMediaRef,
1924
2188
  convertTxIdToImage: convertTxIdToImage,
2189
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
1925
2190
  generateId: generateId,
1926
2191
  getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
1927
2192
  getArweaveUploadStatus: getArweaveUploadStatus,
@@ -1941,6 +2206,7 @@ var index = /*#__PURE__*/Object.freeze({
1941
2206
  getUploadExecutor: getUploadExecutor,
1942
2207
  getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
1943
2208
  identifyString: identifyString,
2209
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
1944
2210
  isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
1945
2211
  isBinary: isBinary,
1946
2212
  isPlaceholderUid: isPlaceholderUid,
@@ -1953,11 +2219,15 @@ var index = /*#__PURE__*/Object.freeze({
1953
2219
  normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
1954
2220
  parseEasRelationPropertyName: parseEasRelationPropertyName,
1955
2221
  pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
2222
+ probeGateway: probeGateway,
1956
2223
  queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
2224
+ queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
2225
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
1957
2226
  resolveMediaRef: resolveMediaRef,
1958
2227
  resolveMetadataRecord: resolveMetadataRecord,
1959
2228
  resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
1960
2229
  resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
2230
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
1961
2231
  setAdditionalSyncAddresses: setAdditionalSyncAddresses,
1962
2232
  setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
1963
2233
  setRevokeExecutor: setRevokeExecutor,
@@ -1980,7 +2250,7 @@ const createPropertyInstances = async (propertyFileIds) => {
1980
2250
  return;
1981
2251
  }
1982
2252
  try {
1983
- const mod = await Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); });
2253
+ const mod = await Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); });
1984
2254
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
1985
2255
  if (!ModelProperty) {
1986
2256
  logger$y('createPropertyInstances: ModelProperty not available from dynamic import');
@@ -2164,7 +2434,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
2164
2434
  // Step 2: Fallback to Schema context (only if database doesn't have the model)
2165
2435
  // This handles the case where model exists in schema file but not yet in database
2166
2436
  try {
2167
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2437
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
2168
2438
  const { Schema } = schemaMod;
2169
2439
  const schema = Schema.create(schemaName, { waitForReady: false });
2170
2440
  const schemaSnapshot = schema.getService().getSnapshot();
@@ -2408,7 +2678,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
2408
2678
  }
2409
2679
  // Mark schema as draft when a new model is created so saveNewVersion() can persist it
2410
2680
  try {
2411
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2681
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
2412
2682
  const { Schema } = schemaMod;
2413
2683
  const schema = Schema.create(schemaName, { waitForReady: false });
2414
2684
  schema.getService().send({ type: 'markAsDraft', propertyKey: 'schema:models' });
@@ -2452,10 +2722,10 @@ const validateModel = xstate.fromCallback(({ sendBack, input: { context } }) =>
2452
2722
  const _validateModel = async () => {
2453
2723
  try {
2454
2724
  // Use dynamic imports to break circular dependencies
2455
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
2725
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
2456
2726
  const { SchemaValidationService } = validationServiceMod;
2457
2727
  const validationService = new SchemaValidationService();
2458
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2728
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
2459
2729
  const { Schema } = schemaMod;
2460
2730
  // Validate model structure
2461
2731
  const structureResult = validationService.validateModelStructure(context);
@@ -2565,7 +2835,7 @@ const createModelProperties = xstate.fromCallback(({ sendBack, input }) => {
2565
2835
  return;
2566
2836
  }
2567
2837
  logger$w(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
2568
- const mod = await Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); });
2838
+ const mod = await Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); });
2569
2839
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
2570
2840
  if (!ModelProperty) {
2571
2841
  logger$w('ModelProperty not available from dynamic import');
@@ -2669,7 +2939,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2669
2939
  const structureMsg = `[validateEntity] Validating model structure`;
2670
2940
  logger$v(structureMsg);
2671
2941
  // Use existing Model validation
2672
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
2942
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
2673
2943
  const { SchemaValidationService } = validationServiceMod;
2674
2944
  const validationService = new SchemaValidationService();
2675
2945
  // Validate model structure
@@ -2687,7 +2957,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2687
2957
  if (entityInput.entityData.schemaName) {
2688
2958
  try {
2689
2959
  logger$v(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
2690
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2960
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
2691
2961
  const { Schema } = schemaMod;
2692
2962
  const schema = Schema.create(entityInput.entityData.schemaName, {
2693
2963
  waitForReady: false,
@@ -2723,7 +2993,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2723
2993
  }
2724
2994
  else if (entityInput.entityType === 'modelProperty') {
2725
2995
  // Use existing ModelProperty validation
2726
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
2996
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
2727
2997
  const { SchemaValidationService } = validationServiceMod;
2728
2998
  const validationService = new SchemaValidationService();
2729
2999
  // Validate property structure
@@ -2738,7 +3008,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2738
3008
  // If schema name and model name provided, validate against schema
2739
3009
  if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
2740
3010
  try {
2741
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
3011
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
2742
3012
  const { Schema } = schemaMod;
2743
3013
  const schema = Schema.create(entityInput.entityData._schemaName, {
2744
3014
  waitForReady: false,
@@ -2767,7 +3037,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2767
3037
  }
2768
3038
  else if (entityInput.entityType === 'schema') {
2769
3039
  // Schema validation - use existing validation
2770
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
3040
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
2771
3041
  const { SchemaValidationService } = validationServiceMod;
2772
3042
  const validationService = new SchemaValidationService();
2773
3043
  const schemaResult = validationService.validateSchema(entityInput.entityData);
@@ -4719,7 +4989,7 @@ const writeToDatabase = xstate.fromCallback(({ sendBack, input }) => {
4719
4989
  // initial write completes is not overwritten by the stale requestWrite payload.
4720
4990
  let dataToWrite = input.entityData;
4721
4991
  try {
4722
- const mod = await Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); });
4992
+ const mod = await Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); });
4723
4993
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
4724
4994
  if (ModelProperty && typeof ModelProperty.getById === 'function') {
4725
4995
  const instance = ModelProperty.getById(input.entityId);
@@ -5099,7 +5369,7 @@ const modelMachine = xstate.setup({
5099
5369
  // Create ModelProperty instances for any new property IDs
5100
5370
  if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
5101
5371
  // Import and create instances asynchronously (fire-and-forget)
5102
- Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); }).then(({ ModelProperty }) => {
5372
+ Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); }).then(({ ModelProperty }) => {
5103
5373
  const createPromises = newPropertyIds.map(async (propertyFileId) => {
5104
5374
  try {
5105
5375
  const property = await ModelProperty.createById(propertyFileId);
@@ -5402,6 +5672,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
5402
5672
  var MachineIds;
5403
5673
  (function (MachineIds) {
5404
5674
  MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
5675
+ MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
5405
5676
  MachineIds["GLOBAL"] = "@seedSdk/global";
5406
5677
  MachineIds["INTERNAL"] = "@seedSdk/internal";
5407
5678
  MachineIds["EAS"] = "@seedSdk/eas";
@@ -5474,7 +5745,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
5474
5745
  * This constant is kept for backward compatibility but will be removed in a future version.
5475
5746
  * Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
5476
5747
  */
5477
- ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'arweave.net';
5748
+ ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
5478
5749
 
5479
5750
  debug('seedSdk:item:service:actors:waitForDb');
5480
5751
  const waitForDb$1 = xstate.fromCallback(({ sendBack }) => {
@@ -6357,7 +6628,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
6357
6628
  rowNum: drizzleOrm.sql.raw(`
6358
6629
  ROW_NUMBER() OVER (
6359
6630
  PARTITION BY property_name
6360
- ORDER BY COALESCE(attestation_created_at, created_at) DESC
6631
+ ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
6361
6632
  )
6362
6633
  `).as('rowNum')
6363
6634
  })
@@ -6370,6 +6641,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
6370
6641
  getMetadataLatest: getMetadataLatest
6371
6642
  });
6372
6643
 
6644
+ /**
6645
+ * Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
6646
+ * `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
6647
+ */
6648
+ function metadataLatestFirstSortKey(row) {
6649
+ return {
6650
+ t: row.attestationCreatedAt ?? row.createdAt ?? 0,
6651
+ localId: String(row.localId ?? ''),
6652
+ };
6653
+ }
6654
+ /** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
6655
+ function compareMetadataRowsLatestFirst(a, b) {
6656
+ const ka = metadataLatestFirstSortKey(a);
6657
+ const kb = metadataLatestFirstSortKey(b);
6658
+ if (kb.t !== ka.t)
6659
+ return kb.t - ka.t;
6660
+ return kb.localId.localeCompare(ka.localId);
6661
+ }
6662
+
6373
6663
  const logger$q = debug('seedSdk:item:actors:loadOrCreateItem');
6374
6664
  /**
6375
6665
  * Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
@@ -6411,9 +6701,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
6411
6701
  return b;
6412
6702
  if (sa !== sb)
6413
6703
  return sa > sb ? a : b;
6414
- const ta = a.attestationCreatedAt ?? a.createdAt ?? 0;
6415
- const tb = b.attestationCreatedAt ?? b.createdAt ?? 0;
6416
- return ta >= tb ? a : b;
6704
+ const cmp = compareMetadataRowsLatestFirst(a, b);
6705
+ return cmp < 0 ? a : b;
6417
6706
  }
6418
6707
  function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
6419
6708
  const byKey = new Map();
@@ -6461,7 +6750,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6461
6750
  const schemaNameToTry = model$1?.schemaName;
6462
6751
  if (schemaNameToTry) {
6463
6752
  try {
6464
- const { Schema } = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
6753
+ const { Schema } = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
6465
6754
  const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
6466
6755
  const schemaContext = schemaInstance.getService().getSnapshot().context;
6467
6756
  if (schemaContext.models?.[modelName]?.properties) {
@@ -6510,7 +6799,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6510
6799
  }
6511
6800
  }
6512
6801
  if (Object.keys(propertySchemas).length === 0) {
6513
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
6802
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
6514
6803
  const { ModelPropertyDataTypes } = schemaMod;
6515
6804
  const KNOWN_MODEL_FALLBACKS = {
6516
6805
  Post: {
@@ -6557,7 +6846,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6557
6846
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
6558
6847
  let propSchema = propertySchemas[propertyName];
6559
6848
  if (!propSchema && isRefTypeFromMeta) {
6560
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
6849
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
6561
6850
  const { ModelPropertyDataTypes } = schemaMod;
6562
6851
  propSchema = {
6563
6852
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -6814,9 +7103,9 @@ const runPublish = xstate.fromCallback(({ sendBack, input: { context } }) => {
6814
7103
  sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
6815
7104
  return;
6816
7105
  }
6817
- const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-DdVy-5fK.js'); });
7106
+ const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-BljRx4o4.js'); });
6818
7107
  const { getPublishUploads } = getPublishUploadsMod;
6819
- const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-DP2fm4q8.js'); });
7108
+ const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-ddl-1x6R.js'); });
6820
7109
  const { getPublishPayload } = getPublishPayloadMod;
6821
7110
  const uploads = await getPublishUploads(item);
6822
7111
  let uploadedTransactions = [];
@@ -7162,6 +7451,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
7162
7451
  return rows[0];
7163
7452
  };
7164
7453
 
7454
+ var getSeedData$1 = /*#__PURE__*/Object.freeze({
7455
+ __proto__: null,
7456
+ getSeedData: getSeedData
7457
+ });
7458
+
7165
7459
  /**
7166
7460
  * Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
7167
7461
  * Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
@@ -7651,7 +7945,7 @@ const resolveRelatedValue = xstate.fromCallback(({ sendBack, input: { context }
7651
7945
  const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
7652
7946
  const _resolveRelatedValue = async () => {
7653
7947
  // Use dynamic import to break circular dependency
7654
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
7948
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
7655
7949
  const { ModelPropertyDataTypes } = schemaMod;
7656
7950
  if (!propertyValue || !isRelation || populatedFromDb) {
7657
7951
  return;
@@ -8014,174 +8308,814 @@ function parseListPropertyValueFromStorage(raw) {
8014
8308
  return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
8015
8309
  }
8016
8310
 
8017
- // Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
8018
- // import { ModelPropertyDataTypes } from '@/schema'
8019
- const logger$l = debug('seedSdk:property:actors:hydrateFromDb');
8020
- const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) => {
8021
- const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
8022
- if (!propertyNameRaw) {
8023
- throw new Error('propertyName is required');
8311
+ const eventEmitter = new EventEmitter();
8312
+
8313
+ const GET_FILES_METADATA = graphql(/* GraphQL */ `
8314
+ query GetFilesMetadata($where: AttestationWhereInput!) {
8315
+ filesMetadata: attestations(
8316
+ where: $where
8317
+ orderBy: [{ timeCreated: desc }]
8318
+ ) {
8319
+ ...attestationFields
8024
8320
  }
8025
- let propertyName = propertyNameRaw;
8026
- // Note: isRelation, isImage, isFile checks moved inside async function
8027
- // to use dynamically imported ModelPropertyDataTypes
8028
- const _hydrateFromDb = async () => {
8029
- // Use dynamic import to break circular dependency
8030
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
8031
- const { ModelPropertyDataTypes } = schemaMod;
8032
- const appDb = BaseDb.getAppDb();
8033
- const whereClauses = [];
8034
- // Re-check types with dynamically imported ModelPropertyDataTypes
8035
- // Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
8036
- const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
8037
- const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
8038
- propertyRecordSchema &&
8039
- propertyRecordSchema.ref &&
8040
- normalizedDataType === ModelPropertyDataTypes.Relation;
8041
- const isImageDynamic = propertyRecordSchema &&
8042
- (normalizedDataType === ModelPropertyDataTypes.Image ||
8043
- normalizedRefValueType === ModelPropertyDataTypes.Image);
8044
- propertyRecordSchema &&
8045
- normalizedDataType === ModelPropertyDataTypes.File;
8046
- const isHtmlDynamic = propertyRecordSchema &&
8047
- normalizedDataType === ModelPropertyDataTypes.Html;
8048
- // Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
8049
- const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
8050
- whereClauses.push(propertyNames.length > 1
8051
- ? drizzleOrm.or(...propertyNames.map((n) => drizzleOrm.eq(metadata$1.propertyName, n)))
8052
- : drizzleOrm.eq(metadata$1.propertyName, propertyNames[0]));
8053
- if (seedUid) {
8054
- whereClauses.push(drizzleOrm.eq(metadata$1.seedUid, seedUid));
8055
- }
8056
- if (seedLocalId) {
8057
- whereClauses.push(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId));
8058
- }
8059
- const rows = await appDb
8060
- .select()
8061
- .from(metadata$1)
8062
- .where(drizzleOrm.and(...whereClauses))
8063
- .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
8064
- if (!rows || !rows.length) {
8065
- return;
8066
- }
8067
- const firstRow = rows[0];
8068
- const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
8069
- let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
8070
- let propertyValueProcessed = propertyValueFromDb;
8071
- // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
8072
- if (isImageDynamic) {
8073
- let dir = localStorageDir;
8074
- if (!dir && isImageDynamic) {
8075
- dir = 'images';
8076
- }
8077
- dir = dir.replace(/^\//, '');
8078
- if (propertyValueFromDb &&
8079
- propertyValueFromDb.length === 66) {
8080
- // Here the storageTransactionId is stored on a different record and
8081
- // we want to add it as the refResolvedValue
8082
- const storageTransactionQuery = await appDb
8083
- .select({
8084
- propertyValue: metadata$1.propertyValue,
8085
- })
8086
- .from(metadata$1)
8087
- .where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, propertyValueFromDb), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))));
8088
- if (storageTransactionQuery && storageTransactionQuery.length > 0) {
8089
- const row = storageTransactionQuery[0];
8090
- refResolvedValue = row.propertyValue;
8091
- await updateMetadata({
8092
- localId,
8093
- refResolvedValue,
8094
- localStorageDir: '/images',
8095
- });
8096
- }
8097
- }
8098
- if (refResolvedValue) {
8099
- try {
8100
- const dirPath = BaseFileManager.getFilesPath(dir);
8101
- const dirExists = await BaseFileManager.pathExists(dirPath);
8102
- if (dirExists) {
8103
- const fs = await BaseFileManager.getFs();
8104
- const path = BaseFileManager.getPathModule();
8105
- const files = await fs.promises.readdir(dirPath);
8106
- const matchingFiles = files.filter((file) => {
8107
- return path.basename(file).includes(refResolvedValue);
8108
- });
8109
- let fileExists = false;
8110
- let filename;
8111
- let filePath;
8112
- if (matchingFiles && matchingFiles.length > 0) {
8113
- fileExists = true;
8114
- filename = matchingFiles[0];
8115
- filePath = BaseFileManager.getFilesPath(dir, filename);
8116
- }
8117
- localStorageDir = `/${dir}`;
8118
- if (fileExists && filename && filePath) {
8119
- const file = await BaseFileManager.readFile(filePath);
8120
- refResolvedDisplayValue = URL.createObjectURL(file);
8121
- // Do not persist blob URL - it is session-scoped
8122
- }
8123
- }
8124
- }
8125
- catch (e) {
8126
- logger$l('[hydrateFromDb] Image file resolution error', e);
8127
- }
8128
- }
8129
- }
8130
- if (propertyRecordSchema &&
8131
- normalizedDataType === ModelPropertyDataTypes.List &&
8132
- typeof propertyValueFromDb === 'string') {
8133
- propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
8134
- }
8135
- sendBack({
8136
- type: 'updateContext',
8137
- localId,
8138
- uid,
8139
- propertyValue: propertyValueProcessed,
8140
- seedLocalId: seedLocalIdFromDb,
8141
- seedUid: seedUidFromDb,
8142
- versionLocalId: versionLocalIdFromDb,
8143
- versionUid: versionUidFromDb,
8144
- schemaUid: schemaUidFromDb,
8145
- refValueType,
8146
- localStorageDir,
8147
- refResolvedValue,
8148
- refResolvedDisplayValue,
8149
- renderValue: refResolvedDisplayValue,
8150
- populatedFromDb: true,
8151
- });
8152
- if (propertyRecordSchema &&
8153
- propertyRecordSchema.storageType &&
8154
- propertyRecordSchema.storageType === 'ItemStorage') {
8155
- const itemMod = await Promise.resolve().then(function () { return Item$1; });
8156
- const { Item } = itemMod;
8157
- const item = await Item.find({
8158
- seedLocalId: seedLocalId ?? undefined,
8159
- modelName,
8160
- });
8161
- if (item) {
8162
- const dir = localStorageDir?.replace(/^\//, '') || 'files';
8163
- const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
8164
- const exists = await BaseFileManager.pathExists(filePath);
8165
- if (!exists) {
8166
- return;
8167
- }
8168
- const renderValue = await BaseFileManager.readFileAsString(filePath);
8169
- const property = item.properties.find(p => p.propertyName === propertyName);
8321
+ }
8322
+ `);
8323
+
8324
+ const getMetadata = async (props) => {
8325
+ const appDb = BaseDb.getAppDb();
8326
+ let storageTransactionId;
8327
+ if (props) {
8328
+ storageTransactionId = props.storageTransactionId;
8329
+ }
8330
+ const whereClauses = [];
8331
+ if (storageTransactionId) {
8332
+ whereClauses.push(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'));
8333
+ whereClauses.push(drizzleOrm.eq(metadata$1.propertyValue, storageTransactionId));
8334
+ }
8335
+ const metadataRows = await appDb
8336
+ .select()
8337
+ .from(metadata$1)
8338
+ .where(drizzleOrm.and(...whereClauses));
8339
+ if (!metadataRows || metadataRows.length === 0) {
8340
+ return;
8341
+ }
8342
+ return metadataRows[0];
8343
+ };
8344
+
8345
+ const saveMetadata = async (metadataRecord, metadataValues) => {
8346
+ if (!metadataRecord.localId) {
8347
+ return;
8348
+ }
8349
+ const appDb = BaseDb.getAppDb();
8350
+ await appDb
8351
+ .update(metadata$1)
8352
+ .set({
8353
+ ...metadataValues,
8354
+ updatedAt: Date.now(),
8355
+ })
8356
+ .where(drizzleOrm.eq(metadata$1.localId, metadataRecord.localId));
8357
+ };
8358
+
8359
+ const isNode = () => {
8360
+ return (typeof process !== 'undefined' &&
8361
+ process.versions != null &&
8362
+ process.versions.node != null);
8363
+ };
8364
+ const isBrowser = () => {
8365
+ return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
8366
+ };
8367
+ const isElectron = () => {
8368
+ return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
8369
+ };
8370
+ /**
8371
+ * Detects if code is running in an Electron renderer process.
8372
+ *
8373
+ * Uses multiple detection methods for robustness:
8374
+ * 1. Checks process.type === 'renderer' (most reliable)
8375
+ * 2. Falls back to checking if Electron is present and window/document exist
8376
+ *
8377
+ * @returns true if running in Electron renderer process, false otherwise
8378
+ */
8379
+ const isElectronRenderer = () => {
8380
+ // Method 1: Check process.type (most reliable - official Electron API)
8381
+ if (typeof process !== 'undefined' &&
8382
+ process.type === 'renderer') {
8383
+ return true;
8384
+ }
8385
+ // Method 2: Fallback - Electron + browser-like environment
8386
+ // Renderer processes have window/document, main process doesn't (in modern Electron)
8387
+ if (isElectron() &&
8388
+ typeof window !== 'undefined' &&
8389
+ typeof document !== 'undefined') {
8390
+ return true;
8391
+ }
8392
+ return false;
8393
+ };
8394
+ /**
8395
+ * True where OPFS-backed Arweave file downloads should run: normal browsers and
8396
+ * Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
8397
+ */
8398
+ const supportsOpfsFileDownloads = () => {
8399
+ return isBrowser() || isElectronRenderer();
8400
+ };
8401
+
8402
+ const logger$l = debug('seedSdk:files:download');
8403
+ const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
8404
+ /** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
8405
+ const GET_FILES_METADATA_STALE_MS = 120000;
8406
+ let bulkDownloadInFlight = null;
8407
+ const lazyDownloadInFlightByTransactionId = new Map();
8408
+ // syncDbFiles helper - internal service removed, functionality moved here
8409
+ const syncDbFiles = async (endpoints) => {
8410
+ // TODO: Implement syncDbFiles functionality if needed
8411
+ // This was previously in @/services/internal/helpers
8412
+ logger$l('[download] syncDbFiles called but not yet implemented');
8413
+ return Promise.resolve();
8414
+ };
8415
+ const getAppDbReady = async () => {
8416
+ if (!BaseDb.isAppDbReady()) {
8417
+ // Wait for ClientManager to be ready (DB_INIT state or later)
8418
+ const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
8419
+ const { getClient } = clientManagerMod;
8420
+ const clientManager = getClient();
8421
+ const clientService = clientManager.getService();
8422
+ await xstate.waitFor(clientService, (snapshot) => {
8423
+ const state = snapshot.value;
8424
+ return state === 'dbInit' ||
8425
+ state === 'saveConfig' ||
8426
+ state === 'processSchemaFiles' ||
8427
+ state === 'addModelsToStore' ||
8428
+ state === 'addModelsToDb' ||
8429
+ state === 'idle';
8430
+ }, { timeout: 30000 });
8431
+ }
8432
+ return BaseDb.getAppDb();
8433
+ };
8434
+ const getExcludedTransactions = async () => {
8435
+ const appDb = await getAppDbReady();
8436
+ if (!appDb) {
8437
+ return new Set();
8438
+ }
8439
+ const excludedTransactionsQuery = await appDb
8440
+ .select()
8441
+ .from(appState)
8442
+ .where(drizzleOrm.eq(appState.key, 'excludedTransactions'));
8443
+ const excludedTransactions = new Set();
8444
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
8445
+ const valueString = excludedTransactionsQuery[0].value;
8446
+ if (valueString) {
8447
+ const excludedTransactionsArray = JSON.parse(valueString);
8448
+ for (const txId of excludedTransactionsArray) {
8449
+ excludedTransactions.add(txId);
8450
+ }
8451
+ }
8452
+ }
8453
+ return excludedTransactions;
8454
+ };
8455
+ /** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
8456
+ const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
8457
+ const normalizeArweaveTxId = (raw) => {
8458
+ if (raw == null || raw === '')
8459
+ return undefined;
8460
+ const t = String(raw).trim();
8461
+ if (ARWEAVE_TX_ID_RE.test(t))
8462
+ return t;
8463
+ const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
8464
+ if (m)
8465
+ return m[1];
8466
+ // Values may be full gateway URLs or paths; scan for the embedded tx id.
8467
+ const embedded = t.match(/[a-z0-9_-]{43}/gi);
8468
+ if (embedded) {
8469
+ for (const candidate of embedded) {
8470
+ if (ARWEAVE_TX_ID_RE.test(candidate))
8471
+ return candidate;
8472
+ }
8473
+ }
8474
+ return undefined;
8475
+ };
8476
+ const mergeAddressLists = (a, b) => {
8477
+ const seen = new Set();
8478
+ const out = [];
8479
+ for (const addr of [...(a ?? []), ...(b ?? [])]) {
8480
+ if (!addr || !addr.trim())
8481
+ continue;
8482
+ const k = addr.toLowerCase();
8483
+ if (seen.has(k))
8484
+ continue;
8485
+ seen.add(k);
8486
+ out.push(addr);
8487
+ }
8488
+ return out;
8489
+ };
8490
+ const collectTransactionIdsFromLocalMetadata = async () => {
8491
+ const appDb = await getAppDbReady();
8492
+ if (!appDb) {
8493
+ return [];
8494
+ }
8495
+ const nameOr = drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'storage_transaction_id'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'));
8496
+ const propRows = await appDb
8497
+ .select({ propertyValue: metadata$1.propertyValue })
8498
+ .from(metadata$1)
8499
+ .where(drizzleOrm.and(nameOr, drizzleOrm.isNotNull(metadata$1.propertyValue)));
8500
+ const refRows = await appDb
8501
+ .select({ refResolvedValue: metadata$1.refResolvedValue })
8502
+ .from(metadata$1)
8503
+ .where(drizzleOrm.isNotNull(metadata$1.refResolvedValue));
8504
+ const ids = new Set();
8505
+ for (const row of propRows) {
8506
+ const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
8507
+ if (id)
8508
+ ids.add(id);
8509
+ }
8510
+ for (const row of refRows) {
8511
+ const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
8512
+ if (id)
8513
+ ids.add(id);
8514
+ }
8515
+ return Array.from(ids);
8516
+ };
8517
+ const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
8518
+ const transactionIds = [];
8519
+ for (const fileMetadata of filesMetadata) {
8520
+ // Validate and parse decodedDataJson
8521
+ if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
8522
+ console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
8523
+ continue;
8524
+ }
8525
+ let json;
8526
+ try {
8527
+ json = JSON.parse(fileMetadata.decodedDataJson);
8528
+ }
8529
+ catch (error) {
8530
+ console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
8531
+ continue;
8532
+ }
8533
+ if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
8534
+ console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
8535
+ continue;
8536
+ }
8537
+ const rawTx = json[0].value.value;
8538
+ if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
8539
+ continue;
8540
+ }
8541
+ const transactionId = normalizeArweaveTxId(rawTx.trim());
8542
+ if (!transactionId) {
8543
+ continue;
8544
+ }
8545
+ if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
8546
+ continue;
8547
+ }
8548
+ transactionIds.push(transactionId);
8549
+ }
8550
+ return transactionIds;
8551
+ };
8552
+ const downloadTransactionIds = async (rawTransactionIds, options) => {
8553
+ if (!supportsOpfsFileDownloads()) {
8554
+ return false;
8555
+ }
8556
+ const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
8557
+ if (transactionIds.length === 0) {
8558
+ return false;
8559
+ }
8560
+ const excludedTransactions = await getExcludedTransactions();
8561
+ const queryClient = BaseQueryClient.getQueryClient();
8562
+ const transactionIdsToDownload = [];
8563
+ await ensureReadGatewaySelected();
8564
+ for (const transactionId of transactionIds) {
8565
+ if (excludedTransactions.has(transactionId)) {
8566
+ continue;
8567
+ }
8568
+ try {
8569
+ // Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
8570
+ // CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
8571
+ let tags = [];
8572
+ try {
8573
+ tags = await queryClient.fetchQuery({
8574
+ queryKey: ['getTransactionTags', transactionId],
8575
+ queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
8576
+ });
8577
+ }
8578
+ catch {
8579
+ tags = [];
8580
+ }
8581
+ if (tags && tags.length > 0) {
8582
+ for (const { name, value } of tags) {
8583
+ if (name !== 'Content-SHA-256')
8584
+ continue;
8585
+ const metadataRecord = await getMetadata({
8586
+ storageTransactionId: transactionId,
8587
+ });
8588
+ if (metadataRecord) {
8589
+ await saveMetadata(metadataRecord, {
8590
+ contentHash: value,
8591
+ });
8592
+ }
8593
+ }
8594
+ }
8595
+ transactionIdsToDownload.push(transactionId);
8596
+ }
8597
+ catch (error) {
8598
+ logger$l(error);
8599
+ }
8600
+ }
8601
+ if (transactionIdsToDownload.length === 0) {
8602
+ return false;
8603
+ }
8604
+ if (transactionIdsToDownload.length === 1) {
8605
+ await BaseFileManager.downloadFileByTransactionId({
8606
+ transactionId: transactionIdsToDownload[0],
8607
+ arweaveHost: BaseArweaveClient.getHost(),
8608
+ excludedTransactions,
8609
+ });
8610
+ }
8611
+ else {
8612
+ await BaseFileManager.downloadAllFiles({
8613
+ transactionIds: transactionIdsToDownload,
8614
+ arweaveHost: BaseArweaveClient.getHost(),
8615
+ excludedTransactions,
8616
+ });
8617
+ }
8618
+ if (options?.resizeAllImages !== false) {
8619
+ await BaseFileManager.resizeAllImages({
8620
+ width: 480,
8621
+ height: 480,
8622
+ });
8623
+ }
8624
+ return true;
8625
+ };
8626
+ const runBulkDownloadWithDedupe = async (transactionIds) => {
8627
+ if (bulkDownloadInFlight) {
8628
+ return bulkDownloadInFlight;
8629
+ }
8630
+ bulkDownloadInFlight = (async () => {
8631
+ try {
8632
+ await downloadTransactionIds(transactionIds, { resizeAllImages: true });
8633
+ }
8634
+ finally {
8635
+ bulkDownloadInFlight = null;
8636
+ }
8637
+ })();
8638
+ return bulkDownloadInFlight;
8639
+ };
8640
+ const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
8641
+ if (!supportsOpfsFileDownloads()) {
8642
+ return;
8643
+ }
8644
+ await syncDbFiles();
8645
+ eventEmitter.emit('fs.downloadAll.success', { eventId });
8646
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
8647
+ };
8648
+ const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
8649
+ if (!supportsOpfsFileDownloads()) {
8650
+ return;
8651
+ }
8652
+ const addressesHint = Array.isArray(addressesHintOrPayload)
8653
+ ? addressesHintOrPayload
8654
+ : undefined;
8655
+ let fromDb = [];
8656
+ if (BaseDb.isAppDbReady()) {
8657
+ fromDb = await getAllAddressesFromDb();
8658
+ }
8659
+ if (!BaseDb.isAppDbReady()) {
8660
+ await getAppDbReady();
8661
+ fromDb = await getAllAddressesFromDb();
8662
+ }
8663
+ const addresses = mergeAddressLists(addressesHint, fromDb);
8664
+ if (!addresses || addresses.length === 0) {
8665
+ return;
8666
+ }
8667
+ const queryClient = BaseQueryClient.getQueryClient();
8668
+ const easClient = BaseEasClient.getEasClient();
8669
+ const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
8670
+ const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
8671
+ where: {
8672
+ attester: {
8673
+ in: addresses,
8674
+ },
8675
+ schema: {
8676
+ is: {
8677
+ id: {
8678
+ equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
8679
+ },
8680
+ },
8681
+ },
8682
+ },
8683
+ });
8684
+ let { filesMetadata } = await queryClient.fetchQuery({
8685
+ queryKey: filesMetadataQueryKey,
8686
+ queryFn: fetchFilesMetadata,
8687
+ staleTime: GET_FILES_METADATA_STALE_MS,
8688
+ });
8689
+ if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
8690
+ await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
8691
+ ({ filesMetadata } = await queryClient.fetchQuery({
8692
+ queryKey: filesMetadataQueryKey,
8693
+ queryFn: fetchFilesMetadata,
8694
+ staleTime: GET_FILES_METADATA_STALE_MS,
8695
+ }));
8696
+ }
8697
+ const filesRoot = BaseFileManager.getWorkingDir();
8698
+ await BaseFileManager.createDirIfNotExists(filesRoot);
8699
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
8700
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
8701
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
8702
+ const excludedTransactions = await getExcludedTransactions();
8703
+ const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
8704
+ const fromLocal = await collectTransactionIdsFromLocalMetadata();
8705
+ const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
8706
+ await runBulkDownloadWithDedupe(transactionIds);
8707
+ };
8708
+ const downloadTransactionIdWithDedupe = async (transactionId) => {
8709
+ if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
8710
+ return false;
8711
+ }
8712
+ const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
8713
+ const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
8714
+ if (existing) {
8715
+ return existing;
8716
+ }
8717
+ const inFlight = (async () => {
8718
+ try {
8719
+ const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
8720
+ return ok;
8721
+ }
8722
+ finally {
8723
+ lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
8724
+ }
8725
+ })();
8726
+ lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
8727
+ return inFlight;
8728
+ };
8729
+ const scheduleBulkFilesDownloadFromEasSyncThrottled = lodashEs.throttle((addressesHint) => {
8730
+ void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
8731
+ logger$l('[scheduleBulkFilesDownloadFromEasSync] failed', error);
8732
+ });
8733
+ }, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
8734
+ const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
8735
+ if (!supportsOpfsFileDownloads()) {
8736
+ return;
8737
+ }
8738
+ scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
8739
+ };
8740
+
8741
+ var download = /*#__PURE__*/Object.freeze({
8742
+ __proto__: null,
8743
+ downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
8744
+ downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
8745
+ downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
8746
+ scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
8747
+ });
8748
+
8749
+ /** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
8750
+ const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
8751
+ /** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
8752
+ const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
8753
+ function extractArweaveTransactionId(raw) {
8754
+ const t = raw.trim();
8755
+ const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
8756
+ if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
8757
+ return embedded[0];
8758
+ }
8759
+ return t;
8760
+ }
8761
+ /**
8762
+ * GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
8763
+ * arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
8764
+ */
8765
+ async function fetchHtmlViaRawAcrossGateways(txId) {
8766
+ const id = extractArweaveTransactionId(txId);
8767
+ if (!id || SEED_UID_HEX_RE.test(id))
8768
+ return undefined;
8769
+ try {
8770
+ const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
8771
+ await ensureReadGatewaySelected().catch(() => { });
8772
+ }
8773
+ catch {
8774
+ /* optional */
8775
+ }
8776
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8777
+ const protocol = BaseArweaveClient.getProtocol();
8778
+ const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
8779
+ for (const host of hosts) {
8780
+ const h = host.trim().replace(/\/$/, '');
8781
+ if (!h)
8782
+ continue;
8783
+ const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
8784
+ try {
8785
+ const res = await fetch(url, { method: 'GET', credentials: 'omit' });
8786
+ if (!res.ok)
8787
+ continue;
8788
+ const text = await res.text();
8789
+ if (typeof text === 'string' && text.length > 0) {
8790
+ return text;
8791
+ }
8792
+ }
8793
+ catch {
8794
+ /* next gateway */
8795
+ }
8796
+ }
8797
+ return undefined;
8798
+ }
8799
+ /**
8800
+ * Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
8801
+ * `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
8802
+ */
8803
+ async function resolveHtmlStorageSeedLocalId(propertyValue) {
8804
+ const pv = String(propertyValue ?? '').trim();
8805
+ if (!pv)
8806
+ return undefined;
8807
+ if (SEED_UID_HEX_RE.test(pv)) {
8808
+ const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
8809
+ return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
8810
+ }
8811
+ return pv;
8812
+ }
8813
+ /**
8814
+ * When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
8815
+ * Html storage seed's published Arweave transaction id on that child seed.
8816
+ */
8817
+ async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
8818
+ const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
8819
+ const pickTx = async (name) => {
8820
+ const row = await getPropertyData({ propertyName: name, seedLocalId });
8821
+ const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
8822
+ return v || undefined;
8823
+ };
8824
+ const txId = (await pickTx('storageTransactionId')) ??
8825
+ (await pickTx('transactionId')) ??
8826
+ (await pickTx('storage_transaction_id'));
8827
+ if (!txId || SEED_UID_HEX_RE.test(txId)) {
8828
+ return { txIdLen: 0, gatewayStringLen: 0 };
8829
+ }
8830
+ const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
8831
+ if (rawHtml && rawHtml.length > 0) {
8832
+ return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
8833
+ }
8834
+ try {
8835
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8836
+ const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
8837
+ string: true,
8838
+ });
8839
+ if (typeof data === 'string' && data.length > 0) {
8840
+ return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
8841
+ }
8842
+ }
8843
+ catch {
8844
+ /* offline / bad tx id */
8845
+ }
8846
+ try {
8847
+ const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
8848
+ await downloadTransactionIdWithDedupe(txId);
8849
+ const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
8850
+ if (await BaseFileManager.pathExists(retryFp)) {
8851
+ const s = await BaseFileManager.readFileAsString(retryFp);
8852
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8853
+ }
8854
+ const dirPath = BaseFileManager.getFilesPath('html');
8855
+ if (await BaseFileManager.pathExists(dirPath)) {
8856
+ const fs = await BaseFileManager.getFs();
8857
+ const pathMod = BaseFileManager.getPathModule();
8858
+ const files = await fs.promises.readdir(dirPath);
8859
+ const needle = txId.replace(/\.[^/.]+$/, '');
8860
+ const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
8861
+ if (match) {
8862
+ const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
8863
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8864
+ }
8865
+ }
8866
+ }
8867
+ catch {
8868
+ /* OPFS unsupported or download failed */
8869
+ }
8870
+ return { txIdLen: txId.length, gatewayStringLen: 0 };
8871
+ }
8872
+ /** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
8873
+ async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
8874
+ const pv = String(propertyValue ?? '').trim();
8875
+ if (!pv)
8876
+ return undefined;
8877
+ const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
8878
+ const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
8879
+ let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
8880
+ // OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
8881
+ if (!fileExists && fp) {
8882
+ await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
8883
+ fileExists = await BaseFileManager.pathExists(fp);
8884
+ }
8885
+ let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
8886
+ if (!body && localId) {
8887
+ const ar = await readHtmlBodyFromChildStorageArweave(localId);
8888
+ body = ar.body;
8889
+ }
8890
+ return body;
8891
+ }
8892
+
8893
+ // Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
8894
+ // import { ModelPropertyDataTypes } from '@/schema'
8895
+ const logger$k = debug('seedSdk:property:actors:hydrateFromDb');
8896
+ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) => {
8897
+ const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
8898
+ if (!propertyNameRaw) {
8899
+ throw new Error('propertyName is required');
8900
+ }
8901
+ let propertyName = propertyNameRaw;
8902
+ // Note: isRelation, isImage, isFile checks moved inside async function
8903
+ // to use dynamically imported ModelPropertyDataTypes
8904
+ const _hydrateFromDb = async () => {
8905
+ // Use dynamic import to break circular dependency
8906
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
8907
+ const { ModelPropertyDataTypes } = schemaMod;
8908
+ const appDb = BaseDb.getAppDb();
8909
+ const whereClauses = [];
8910
+ // Re-check types with dynamically imported ModelPropertyDataTypes
8911
+ // Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
8912
+ const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
8913
+ const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
8914
+ propertyRecordSchema &&
8915
+ propertyRecordSchema.ref &&
8916
+ normalizedDataType === ModelPropertyDataTypes.Relation;
8917
+ const isImageDynamic = propertyRecordSchema &&
8918
+ (normalizedDataType === ModelPropertyDataTypes.Image ||
8919
+ normalizedRefValueType === ModelPropertyDataTypes.Image);
8920
+ const isFileDynamic = propertyRecordSchema &&
8921
+ normalizedDataType === ModelPropertyDataTypes.File;
8922
+ const isHtmlDynamic = propertyRecordSchema &&
8923
+ normalizedDataType === ModelPropertyDataTypes.Html;
8924
+ // Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
8925
+ const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
8926
+ whereClauses.push(propertyNames.length > 1
8927
+ ? drizzleOrm.or(...propertyNames.map((n) => drizzleOrm.eq(metadata$1.propertyName, n)))
8928
+ : drizzleOrm.eq(metadata$1.propertyName, propertyNames[0]));
8929
+ // Draft rows often have only seed_local_id populated; on-chain rows may have uid.
8930
+ // Requiring both with AND misses valid metadata when only one column is set.
8931
+ if (seedUid && seedLocalId) {
8932
+ whereClauses.push(drizzleOrm.or(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId), drizzleOrm.eq(metadata$1.seedUid, seedUid)));
8933
+ }
8934
+ else if (seedUid) {
8935
+ whereClauses.push(drizzleOrm.eq(metadata$1.seedUid, seedUid));
8936
+ }
8937
+ else if (seedLocalId) {
8938
+ whereClauses.push(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId));
8939
+ }
8940
+ const rows = await appDb
8941
+ .select()
8942
+ .from(metadata$1)
8943
+ .where(drizzleOrm.and(...whereClauses))
8944
+ .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
8945
+ if (!rows || !rows.length) {
8946
+ return;
8947
+ }
8948
+ const firstRow = rows[0];
8949
+ const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
8950
+ let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
8951
+ let propertyValueProcessed = propertyValueFromDb;
8952
+ let renderValue = refResolvedDisplayValue ?? undefined;
8953
+ // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
8954
+ if (isImageDynamic) {
8955
+ let dir = localStorageDir;
8956
+ if (!dir && isImageDynamic) {
8957
+ dir = 'images';
8958
+ }
8959
+ dir = dir.replace(/^\//, '');
8960
+ if (propertyValueFromDb &&
8961
+ propertyValueFromDb.length === 66) {
8962
+ // Here the storageTransactionId is stored on a different record and
8963
+ // we want to add it as the refResolvedValue
8964
+ const storageTransactionQuery = await appDb
8965
+ .select({
8966
+ propertyValue: metadata$1.propertyValue,
8967
+ })
8968
+ .from(metadata$1)
8969
+ .where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, propertyValueFromDb), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))));
8970
+ if (storageTransactionQuery && storageTransactionQuery.length > 0) {
8971
+ const row = storageTransactionQuery[0];
8972
+ refResolvedValue = row.propertyValue;
8973
+ await updateMetadata({
8974
+ localId,
8975
+ refResolvedValue,
8976
+ localStorageDir: '/images',
8977
+ });
8978
+ }
8979
+ }
8980
+ const resolveMatchingFilePath = async (dir, needle) => {
8981
+ const dirPath = BaseFileManager.getFilesPath(dir);
8982
+ const dirExists = await BaseFileManager.pathExists(dirPath);
8983
+ if (!dirExists)
8984
+ return undefined;
8985
+ const fs = await BaseFileManager.getFs();
8986
+ const path = BaseFileManager.getPathModule();
8987
+ const files = await fs.promises.readdir(dirPath);
8988
+ const matchingFiles = files.filter((file) => {
8989
+ return path.basename(file).includes(needle);
8990
+ });
8991
+ if (!matchingFiles?.length)
8992
+ return undefined;
8993
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
8994
+ };
8995
+ if (refResolvedValue) {
8996
+ try {
8997
+ let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
8998
+ if (!filePath) {
8999
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9000
+ filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9001
+ }
9002
+ localStorageDir = `/${dir}`;
9003
+ if (filePath) {
9004
+ const file = await BaseFileManager.readFile(filePath);
9005
+ refResolvedDisplayValue = URL.createObjectURL(file);
9006
+ renderValue = refResolvedDisplayValue;
9007
+ // Do not persist blob URL - it is session-scoped
9008
+ }
9009
+ }
9010
+ catch (e) {
9011
+ logger$k('[hydrateFromDb] Image file resolution error', e);
9012
+ }
9013
+ }
9014
+ }
9015
+ if (isFileDynamic && refResolvedValue) {
9016
+ try {
9017
+ const dir = (localStorageDir ?? '/files').replace(/^\//, '');
9018
+ const resolveMatchingFilePath = async (needle) => {
9019
+ const dirPath = BaseFileManager.getFilesPath(dir);
9020
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9021
+ if (!dirExists)
9022
+ return undefined;
9023
+ const fs = await BaseFileManager.getFs();
9024
+ const path = BaseFileManager.getPathModule();
9025
+ const files = await fs.promises.readdir(dirPath);
9026
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9027
+ if (!matchingFiles?.length)
9028
+ return undefined;
9029
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9030
+ };
9031
+ let filePath = await resolveMatchingFilePath(refResolvedValue);
9032
+ if (!filePath) {
9033
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9034
+ filePath = await resolveMatchingFilePath(refResolvedValue);
9035
+ }
9036
+ if (filePath) {
9037
+ localStorageDir = `/${dir}`;
9038
+ renderValue = await BaseFileManager.readFileAsString(filePath);
9039
+ }
9040
+ }
9041
+ catch (e) {
9042
+ logger$k('[hydrateFromDb] File resolution error', e);
9043
+ }
9044
+ }
9045
+ if (propertyRecordSchema &&
9046
+ normalizedDataType === ModelPropertyDataTypes.List &&
9047
+ typeof propertyValueFromDb === 'string') {
9048
+ propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
9049
+ }
9050
+ sendBack({
9051
+ type: 'updateContext',
9052
+ localId,
9053
+ uid,
9054
+ propertyValue: propertyValueProcessed,
9055
+ seedLocalId: seedLocalIdFromDb,
9056
+ seedUid: seedUidFromDb,
9057
+ versionLocalId: versionLocalIdFromDb,
9058
+ versionUid: versionUidFromDb,
9059
+ schemaUid: schemaUidFromDb,
9060
+ refValueType,
9061
+ localStorageDir,
9062
+ refResolvedValue,
9063
+ refResolvedDisplayValue,
9064
+ renderValue,
9065
+ populatedFromDb: true,
9066
+ });
9067
+ if (propertyRecordSchema &&
9068
+ propertyRecordSchema.storageType &&
9069
+ propertyRecordSchema.storageType === 'ItemStorage') {
9070
+ const itemMod = await Promise.resolve().then(function () { return Item$1; });
9071
+ const { Item } = itemMod;
9072
+ const item = await Item.find({
9073
+ seedLocalId: seedLocalId ?? undefined,
9074
+ modelName,
9075
+ });
9076
+ if (item) {
9077
+ const dir = localStorageDir?.replace(/^\//, '') || 'files';
9078
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9079
+ const exists = await BaseFileManager.pathExists(filePath);
9080
+ if (!exists) {
9081
+ return;
9082
+ }
9083
+ const renderValue = await BaseFileManager.readFileAsString(filePath);
9084
+ const property = item.properties.find(p => p.propertyName === propertyName);
8170
9085
  if (property) {
8171
9086
  property.getService().send({ type: 'updateContext', renderValue });
8172
9087
  }
8173
9088
  return;
8174
9089
  }
8175
9090
  }
8176
- // Html: read file content for renderValue (blob URLs from DB are invalid after reload)
8177
- // Fallback: when localStorageDir is null (e.g. EAS sync, legacy records) use '/html'
8178
- const htmlLocalStorageDir = isHtmlDynamic && refResolvedValue && !localStorageDir ? '/html' : localStorageDir;
8179
- if (isHtmlDynamic && refResolvedValue && htmlLocalStorageDir) {
8180
- const dir = htmlLocalStorageDir.replace(/^\//, '');
8181
- const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
8182
- const exists = await BaseFileManager.pathExists(filePath);
8183
- if (exists) {
8184
- const htmlContent = await BaseFileManager.readFileAsString(filePath);
9091
+ // Html: read file content for renderValue (blob URLs from DB are invalid after reload).
9092
+ // When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
9093
+ if (isHtmlDynamic) {
9094
+ const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
9095
+ let htmlContent;
9096
+ let outRef = refResolvedValue;
9097
+ let outDir = htmlLocalStorageDir;
9098
+ if (refResolvedValue && htmlLocalStorageDir) {
9099
+ const dir = htmlLocalStorageDir.replace(/^\//, '');
9100
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9101
+ let exists = await BaseFileManager.pathExists(filePath);
9102
+ if (!exists) {
9103
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9104
+ exists = await BaseFileManager.pathExists(filePath);
9105
+ }
9106
+ if (exists) {
9107
+ htmlContent = await BaseFileManager.readFileAsString(filePath);
9108
+ }
9109
+ }
9110
+ if (!htmlContent && propertyValueFromDb) {
9111
+ htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
9112
+ const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
9113
+ if (lid) {
9114
+ outRef = `${lid}.html`;
9115
+ outDir = '/html';
9116
+ }
9117
+ }
9118
+ if (htmlContent) {
8185
9119
  sendBack({
8186
9120
  type: 'updateContext',
8187
9121
  localId,
@@ -8193,8 +9127,8 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
8193
9127
  versionUid: versionUidFromDb,
8194
9128
  schemaUid: schemaUidFromDb,
8195
9129
  refValueType,
8196
- localStorageDir: htmlLocalStorageDir,
8197
- refResolvedValue,
9130
+ localStorageDir: outDir,
9131
+ refResolvedValue: outRef ?? refResolvedValue,
8198
9132
  refResolvedDisplayValue,
8199
9133
  renderValue: htmlContent,
8200
9134
  populatedFromDb: true,
@@ -8208,11 +9142,11 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
8208
9142
  });
8209
9143
  });
8210
9144
 
8211
- const logger$k = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
9145
+ const logger$j = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
8212
9146
  const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context } }) => {
8213
9147
  const _loadOrCreateProperty = async () => {
8214
9148
  const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
8215
- logger$k(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
9149
+ logger$j(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
8216
9150
  if (!seedLocalId && !seedUid) {
8217
9151
  throw new Error('seedLocalId or seedUid is required');
8218
9152
  }
@@ -8258,15 +9192,15 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8258
9192
  const schemas = modelPropertiesToObject(model$1.properties);
8259
9193
  propertyRecordSchema = schemas[propertyName];
8260
9194
  if (propertyRecordSchema) {
8261
- logger$k(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9195
+ logger$j(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8262
9196
  }
8263
9197
  }
8264
9198
  }
8265
9199
  catch (error) {
8266
- logger$k(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
9200
+ logger$j(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
8267
9201
  }
8268
9202
  }
8269
- logger$k(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
9203
+ logger$j(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
8270
9204
  sendBack({
8271
9205
  type: 'loadOrCreatePropertySuccess',
8272
9206
  property: {
@@ -8332,7 +9266,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8332
9266
  };
8333
9267
  // Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
8334
9268
  try {
8335
- const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-BQokoaRe.js'); });
9269
+ const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-2D7P6a2q.js'); });
8336
9270
  let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
8337
9271
  if (!schemaFromFile?.validation) {
8338
9272
  // Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
@@ -8370,7 +9304,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8370
9304
  }
8371
9305
  }
8372
9306
  catch (error) {
8373
- logger$k(`Error loading propertyRecordSchema from database: ${error}`);
9307
+ logger$j(`Error loading propertyRecordSchema from database: ${error}`);
8374
9308
  // Continue without propertyRecordSchema
8375
9309
  }
8376
9310
  }
@@ -8388,22 +9322,27 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8388
9322
  const schemas = modelPropertiesToObject(model$1.properties);
8389
9323
  propertyRecordSchema = schemas[propertyName];
8390
9324
  if (propertyRecordSchema) {
8391
- logger$k(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9325
+ logger$j(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8392
9326
  }
8393
9327
  }
8394
9328
  }
8395
9329
  catch (error) {
8396
- logger$k(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
9330
+ logger$j(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
8397
9331
  }
8398
9332
  }
8399
9333
  // For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
8400
9334
  let renderValue = metadataRecord.propertyValue || undefined;
8401
9335
  const refSeedType = metadataRecord.refSeedType;
8402
- const isHtml = refSeedType === 'html' || propertyRecordSchema?.dataType === 'Html';
8403
- // Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data)
9336
+ const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
9337
+ const isHtml = refSeedType === 'html' || normalizedHtmlDt === exports.ModelPropertyDataTypes.Html;
9338
+ // Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
9339
+ // After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
8404
9340
  if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
8405
- metadataRecord.refResolvedValue = `${metadataRecord.propertyValue}.html`;
8406
- metadataRecord.localStorageDir = '/html';
9341
+ const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
9342
+ if (lid) {
9343
+ metadataRecord.refResolvedValue = `${lid}.html`;
9344
+ metadataRecord.localStorageDir = '/html';
9345
+ }
8407
9346
  }
8408
9347
  // Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
8409
9348
  if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
@@ -8413,13 +9352,34 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8413
9352
  try {
8414
9353
  const dir = metadataRecord.localStorageDir.replace(/^\//, '');
8415
9354
  const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
8416
- const exists = await BaseFileManager.pathExists(filePath);
9355
+ let exists = await BaseFileManager.pathExists(filePath);
9356
+ if (!exists) {
9357
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9358
+ exists = await BaseFileManager.pathExists(filePath);
9359
+ }
8417
9360
  if (exists) {
8418
9361
  renderValue = await BaseFileManager.readFileAsString(filePath);
8419
9362
  }
9363
+ else {
9364
+ const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9365
+ if (viaSeedPointer) {
9366
+ renderValue = viaSeedPointer;
9367
+ }
9368
+ }
8420
9369
  }
8421
9370
  catch (e) {
8422
- logger$k(`Failed to read Html file for ${propertyName}: ${e}`);
9371
+ logger$j(`Failed to read Html file for ${propertyName}: ${e}`);
9372
+ }
9373
+ }
9374
+ // Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
9375
+ if (isHtml && metadataRecord.propertyValue) {
9376
+ const pv = String(metadataRecord.propertyValue).trim();
9377
+ const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
9378
+ if (!rv || rv === pv) {
9379
+ const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9380
+ if (recovered) {
9381
+ renderValue = recovered;
9382
+ }
8423
9383
  }
8424
9384
  }
8425
9385
  // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
@@ -8429,28 +9389,83 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8429
9389
  const isImage = refSeedType === 'image' ||
8430
9390
  normalizedDataType === 'Image' ||
8431
9391
  normalizedRefValueType === 'Image';
9392
+ const resolveMatchingFilePath = async (dir, needle) => {
9393
+ const dirPath = BaseFileManager.getFilesPath(dir);
9394
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9395
+ if (!dirExists)
9396
+ return undefined;
9397
+ const fs = await BaseFileManager.getFs();
9398
+ const path = BaseFileManager.getPathModule();
9399
+ const files = await fs.promises.readdir(dirPath);
9400
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9401
+ if (!matchingFiles?.length)
9402
+ return undefined;
9403
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9404
+ };
9405
+ // EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
9406
+ // hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
9407
+ if (isImage &&
9408
+ !metadataRecord.refResolvedValue &&
9409
+ typeof metadataRecord.propertyValue === 'string' &&
9410
+ metadataRecord.propertyValue.length === 66) {
9411
+ const storageTxRows = await db
9412
+ .select({ propertyValue: metadata$1.propertyValue })
9413
+ .from(metadata$1)
9414
+ .where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, metadataRecord.propertyValue), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))))
9415
+ .limit(1);
9416
+ const derivedTxId = storageTxRows[0]?.propertyValue;
9417
+ if (derivedTxId) {
9418
+ metadataRecord.refResolvedValue = derivedTxId;
9419
+ metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
9420
+ if (metadataRecord.localId) {
9421
+ try {
9422
+ await updateMetadata({
9423
+ localId: metadataRecord.localId,
9424
+ refResolvedValue: derivedTxId,
9425
+ localStorageDir: '/images',
9426
+ });
9427
+ }
9428
+ catch (e) {
9429
+ logger$j(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
9430
+ }
9431
+ }
9432
+ }
9433
+ }
8432
9434
  if (isImage && metadataRecord.refResolvedValue) {
8433
9435
  try {
8434
9436
  const dir = (metadataRecord.localStorageDir ?? '/images').replace(/^\//, '');
8435
- const dirPath = BaseFileManager.getFilesPath(dir);
8436
- const dirExists = await BaseFileManager.pathExists(dirPath);
8437
- if (dirExists) {
8438
- const fs = await BaseFileManager.getFs();
8439
- const path = BaseFileManager.getPathModule();
8440
- const files = await fs.promises.readdir(dirPath);
8441
- const matchingFiles = files.filter((file) => path.basename(file).includes(metadataRecord.refResolvedValue));
8442
- if (matchingFiles?.length > 0) {
8443
- const filename = matchingFiles[0];
8444
- const filePath = BaseFileManager.getFilesPath(dir, filename);
8445
- const file = await BaseFileManager.readFile(filePath);
8446
- const freshBlobUrl = URL.createObjectURL(file);
8447
- renderValue = freshBlobUrl;
8448
- refResolvedDisplayValue = freshBlobUrl;
8449
- }
9437
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9438
+ if (!filePath) {
9439
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9440
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9441
+ }
9442
+ if (filePath) {
9443
+ const file = await BaseFileManager.readFile(filePath);
9444
+ const freshBlobUrl = URL.createObjectURL(file);
9445
+ renderValue = freshBlobUrl;
9446
+ refResolvedDisplayValue = freshBlobUrl;
9447
+ }
9448
+ }
9449
+ catch (e) {
9450
+ logger$j(`Failed to resolve Image file for ${propertyName}: ${e}`);
9451
+ }
9452
+ }
9453
+ const isFile = refSeedType === 'file' ||
9454
+ normalizedDataType === 'File';
9455
+ if (isFile && metadataRecord.refResolvedValue) {
9456
+ try {
9457
+ const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
9458
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9459
+ if (!filePath) {
9460
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9461
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9462
+ }
9463
+ if (filePath) {
9464
+ renderValue = await BaseFileManager.readFileAsString(filePath);
8450
9465
  }
8451
9466
  }
8452
9467
  catch (e) {
8453
- logger$k(`Failed to resolve Image file for ${propertyName}: ${e}`);
9468
+ logger$j(`Failed to resolve File for ${propertyName}: ${e}`);
8454
9469
  }
8455
9470
  }
8456
9471
  let propertyValueOut = metadataRecord.propertyValue || undefined;
@@ -8482,7 +9497,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8482
9497
  });
8483
9498
  };
8484
9499
  _loadOrCreateProperty().catch((error) => {
8485
- logger$k(`Error in loadOrCreateProperty: ${error}`);
9500
+ logger$j(`Error in loadOrCreateProperty: ${error}`);
8486
9501
  sendBack({
8487
9502
  type: 'loadOrCreatePropertyError',
8488
9503
  error: error instanceof Error ? error.message : String(error),
@@ -8512,10 +9527,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
8512
9527
  return queryRows[0];
8513
9528
  };
8514
9529
 
8515
- const logger$j = debug('seedSdk:write:updateItemPropertyValue');
9530
+ const logger$i = debug('seedSdk:write:updateItemPropertyValue');
8516
9531
  const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
8517
9532
  if (!localIdParam && !seedLocalId) {
8518
- logger$j(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
9533
+ logger$i(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
8519
9534
  return;
8520
9535
  }
8521
9536
  let safeNewValue = newValue;
@@ -8543,7 +9558,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8543
9558
  .select()
8544
9559
  .from(metadata$1)
8545
9560
  .where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
8546
- .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9561
+ .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8547
9562
  }
8548
9563
  }
8549
9564
  else if (localIdParam) {
@@ -8563,7 +9578,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8563
9578
  .select()
8564
9579
  .from(metadata$1)
8565
9580
  .where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
8566
- .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9581
+ .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8567
9582
  }
8568
9583
  // const mostRecentRecordStatement = `SELECT local_id,
8569
9584
  // uid,
@@ -8579,7 +9594,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8579
9594
  // FROM metadata
8580
9595
  // WHERE property_name = '${propertyName}'
8581
9596
  // AND seed_local_id = '${seedLocalId}'
8582
- // ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
9597
+ // ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
8583
9598
  //
8584
9599
  // const { rows } = await runQueryForStatement(mostRecentRecordStatement)
8585
9600
  if (rows && rows.length > 0) {
@@ -8588,7 +9603,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8588
9603
  modelType === modelName?.toLowerCase() &&
8589
9604
  refSeedTypeFromDb === refSeedType &&
8590
9605
  refResolvedValueFromDb === refResolvedValue) {
8591
- logger$j(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
9606
+ logger$i(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
8592
9607
  return;
8593
9608
  }
8594
9609
  // This means we already have a local-only record so we should just update that one
@@ -8716,9 +9731,9 @@ const analyzeInput = xstate.fromCallback(({ sendBack, input: { context, event }
8716
9731
  }
8717
9732
  const _analyzeInput = async () => {
8718
9733
  // Use dynamic import to break circular dependency
8719
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
9734
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
8720
9735
  const { ModelPropertyDataTypes } = schemaMod;
8721
- const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
9736
+ const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
8722
9737
  let propertyName = propertyNameRaw;
8723
9738
  if (!propertyName) {
8724
9739
  throw new Error('propertyName is required');
@@ -8916,7 +9931,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8916
9931
  propertyRecordSchema?.validation &&
8917
9932
  metadataValues.propertyValue != null &&
8918
9933
  metadataValues.propertyValue !== '') {
8919
- const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
9934
+ const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
8920
9935
  const validationService = new SchemaValidationService();
8921
9936
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
8922
9937
  if (!validationResult.isValid && validationResult.errors.length > 0) {
@@ -8994,8 +10009,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8994
10009
  return inserted[0];
8995
10010
  };
8996
10011
 
8997
- const eventEmitter = new EventEmitter();
8998
-
8999
10012
  const readFileAsArrayBuffer$1 = async (file) => {
9000
10013
  return new Promise((resolve) => {
9001
10014
  const reader = new FileReader();
@@ -9142,6 +10155,12 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
9142
10155
  }
9143
10156
  const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
9144
10157
  let newLocalId;
10158
+ const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
10159
+ ? schemaUid
10160
+ : (await getEasSchemaForItemProperty({
10161
+ propertyName,
10162
+ easDataType: 'bytes32',
10163
+ }))?.id;
9145
10164
  if (!localId) {
9146
10165
  const result = await createMetadata({
9147
10166
  propertyName,
@@ -9151,7 +10170,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
9151
10170
  versionLocalId,
9152
10171
  versionUid,
9153
10172
  modelName,
9154
- schemaUid: imageSchemaUid,
10173
+ schemaUid: resolvedPropertySchemaUid,
9155
10174
  refSeedType: 'image',
9156
10175
  refModelUid: imageSchemaUid,
9157
10176
  refResolvedValue: fileName,
@@ -9170,7 +10189,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
9170
10189
  seedLocalId,
9171
10190
  versionLocalId,
9172
10191
  modelName,
9173
- schemaUid,
10192
+ schemaUid: resolvedPropertySchemaUid,
9174
10193
  refSeedType: 'image',
9175
10194
  refResolvedValue: fileName,
9176
10195
  localStorageDir: '/images',
@@ -9503,7 +10522,7 @@ const saveRelation = xstate.fromCallback(({ sendBack, input: { context, event }
9503
10522
  }
9504
10523
  const _saveRelation = async () => {
9505
10524
  // Use dynamic import to break circular dependency
9506
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
10525
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
9507
10526
  const { ModelPropertyDataTypes } = schemaMod;
9508
10527
  if (!propertyNameRaw) {
9509
10528
  throw new Error('propertyName is required');
@@ -9712,6 +10731,10 @@ const propertyMachine = xstate.setup({
9712
10731
  context: {},
9713
10732
  input: {},
9714
10733
  },
10734
+ guards: {
10735
+ // stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
10736
+ propertyMachineIsIdle: xstate.stateIn('idle'),
10737
+ },
9715
10738
  // actions: {
9716
10739
  // updateContext: updateMachineContext,
9717
10740
  // },
@@ -9734,7 +10757,11 @@ const propertyMachine = xstate.setup({
9734
10757
  initial: 'waitingForDb',
9735
10758
  context: ({ input }) => input,
9736
10759
  on: {
9737
- // reload: '.hydratingFromDb',
10760
+ /** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
10761
+ rehydrateFromDb: {
10762
+ guard: 'propertyMachineIsIdle',
10763
+ target: '.hydratingFromDb',
10764
+ },
9738
10765
  save: {
9739
10766
  actions: xstate.assign({
9740
10767
  isSaving: true,
@@ -10333,6 +11360,8 @@ function createReactiveProxy(config) {
10333
11360
  return proxy;
10334
11361
  }
10335
11362
 
11363
+ /** Parent Html property `propertyValue` after publish (66-char seed uid). */
11364
+ const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
10336
11365
  // Start loading Model at module load time (non-blocking)
10337
11366
  Promise.resolve().then(function () { return Model$1; }).then(module => {
10338
11367
  module.Model;
@@ -10432,7 +11461,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
10432
11461
  };
10433
11462
  /** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
10434
11463
  const modelTypeToModelName = (modelType) => modelType ? lodashEs.upperFirst(lodashEs.camelCase(modelType)) : '';
10435
- const logger$i = debug('seedSdk:property:class');
11464
+ const logger$h = debug('seedSdk:property:class');
10436
11465
  // Define tracked properties for the Proxy
10437
11466
  // These properties will be read from/written to the actor context
10438
11467
  const TRACKED_PROPERTIES$2 = [
@@ -10514,7 +11543,7 @@ class ItemProperty {
10514
11543
  serviceInput.propertyValue = JSON.parse(propertyValue);
10515
11544
  }
10516
11545
  catch (e) {
10517
- logger$i('List property value is not JSON', e);
11546
+ logger$h('List property value is not JSON', e);
10518
11547
  }
10519
11548
  }
10520
11549
  }
@@ -10537,7 +11566,7 @@ class ItemProperty {
10537
11566
  return;
10538
11567
  }
10539
11568
  // Use dynamic import to break circular dependency
10540
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
11569
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
10541
11570
  const { ModelPropertyDataTypes } = schemaMod;
10542
11571
  const { context } = snapshot;
10543
11572
  const { propertyRecordSchema } = context;
@@ -10560,7 +11589,8 @@ class ItemProperty {
10560
11589
  propertyRecordSchema.storageType === 'ItemStorage' &&
10561
11590
  context.refResolvedValue &&
10562
11591
  context.localStorageDir;
10563
- const isHtml = (context.refSeedType === 'html' || (propertyRecordSchema?.dataType === ModelPropertyDataTypes.Html)) &&
11592
+ const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
11593
+ const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
10564
11594
  context.refResolvedValue;
10565
11595
  // Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
10566
11596
  // so the UI can display the filename and preview immediately (these update again when save completes)
@@ -10596,7 +11626,11 @@ class ItemProperty {
10596
11626
  const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
10597
11627
  const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
10598
11628
  try {
10599
- const exists = await BaseFileManager.pathExists(filePath);
11629
+ let exists = await BaseFileManager.pathExists(filePath);
11630
+ if (!exists && isHtml) {
11631
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
11632
+ exists = await BaseFileManager.pathExists(filePath);
11633
+ }
10600
11634
  if (exists && (isItemStorage || isHtml)) {
10601
11635
  renderValue = await BaseFileManager.readFileAsString(filePath);
10602
11636
  }
@@ -10616,8 +11650,8 @@ class ItemProperty {
10616
11650
  if (isFile && isFileValue) {
10617
11651
  renderValue = pv.name;
10618
11652
  }
10619
- else if (isImage) {
10620
- // FS race / path not visible yet: do not clobber a hydrated blob URL with "No file found"
11653
+ else if (isImage || isHtml) {
11654
+ // FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
10621
11655
  renderValue = undefined;
10622
11656
  }
10623
11657
  else {
@@ -10626,13 +11660,21 @@ class ItemProperty {
10626
11660
  }
10627
11661
  }
10628
11662
  catch (e) {
10629
- logger$i(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
10630
- renderValue = 'No file found';
11663
+ logger$h(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
11664
+ renderValue = isHtml ? undefined : 'No file found';
10631
11665
  }
10632
11666
  }
10633
11667
  if (!renderValue) {
10634
11668
  renderValue = context.renderValue || context.propertyValue;
10635
11669
  }
11670
+ const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
11671
+ if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
11672
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
11673
+ renderValue === pvStr &&
11674
+ typeof context.renderValue === 'string' &&
11675
+ context.renderValue.length > pvStr.length) {
11676
+ renderValue = context.renderValue;
11677
+ }
10636
11678
  let transformedPropertyName = propertyName;
10637
11679
  const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
10638
11680
  if (!skipTransform && transformedPropertyName.endsWith('Id')) {
@@ -11045,6 +12087,35 @@ class ItemProperty {
11045
12087
  instance._service.send({ type: 'updateContext', ...updates });
11046
12088
  }
11047
12089
  }
12090
+ // After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
12091
+ // paths would hydrate. Re-run DB hydration without clobbering propertyValue.
12092
+ const svc = instance._service;
12093
+ const snap = svc.getSnapshot();
12094
+ if (snap.status === 'active' && snap.value === 'idle') {
12095
+ const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
12096
+ const dt = normalizeDataType(schema?.dataType);
12097
+ const isHtmlProp = props.refSeedType === 'html' ||
12098
+ ctx.refSeedType === 'html' ||
12099
+ dt === exports.ModelPropertyDataTypes.Html;
12100
+ const isListProp = dt === exports.ModelPropertyDataTypes.List;
12101
+ const isRelationProp = dt === exports.ModelPropertyDataTypes.Relation;
12102
+ const pv = ctx.propertyValue;
12103
+ const pvStr = typeof pv === 'string' ? pv.trim() : '';
12104
+ const renderVal = ctx.renderValue;
12105
+ const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
12106
+ const htmlStuckOnUid = isHtmlProp &&
12107
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
12108
+ (renderMissing || renderVal === pv);
12109
+ const pvPresent = pv != null &&
12110
+ (Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
12111
+ const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
12112
+ const versionChanged = props.versionLocalId != null &&
12113
+ ctx.versionLocalId != null &&
12114
+ props.versionLocalId !== ctx.versionLocalId;
12115
+ if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
12116
+ svc.send({ type: 'rehydrateFromDb' });
12117
+ }
12118
+ }
11048
12119
  // On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
11049
12120
  if (!waitForReady)
11050
12121
  return instance;
@@ -11394,7 +12465,7 @@ class ItemProperty {
11394
12465
  }
11395
12466
  async save() {
11396
12467
  const ctx = this._getSnapshotContext();
11397
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
12468
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
11398
12469
  await assertItemOwned({
11399
12470
  seedLocalId: ctx?.seedLocalId ?? undefined,
11400
12471
  seedUid: ctx?.seedUid ?? undefined,
@@ -11733,7 +12804,7 @@ class Item {
11733
12804
  });
11734
12805
  };
11735
12806
  this.unpublish = async () => {
11736
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
12807
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
11737
12808
  const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
11738
12809
  await assertItemOwned(this);
11739
12810
  const seedUid = this.seedUid;
@@ -11757,7 +12828,7 @@ class Item {
11757
12828
  this._service.send({ type: 'updateContext', revokedAt });
11758
12829
  };
11759
12830
  this.publish = async () => {
11760
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
12831
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
11761
12832
  await assertItemOwned(this);
11762
12833
  this._service.send({ type: 'startPublish' });
11763
12834
  return new Promise((resolve, reject) => {
@@ -11793,12 +12864,12 @@ class Item {
11793
12864
  };
11794
12865
  this.getPublishUploads = async (options) => {
11795
12866
  // Use dynamic import to break circular dependency
11796
- const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-DdVy-5fK.js'); });
12867
+ const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-BljRx4o4.js'); });
11797
12868
  const { getPublishUploads } = getPublishUploadsMod;
11798
12869
  return await getPublishUploads(this, [], undefined, options);
11799
12870
  };
11800
12871
  this.getPublishPayload = async (uploadedTransactions, options) => {
11801
- const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-DP2fm4q8.js'); });
12872
+ const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-ddl-1x6R.js'); });
11802
12873
  const { getPublishPayload } = getPublishPayloadMod;
11803
12874
  return await getPublishPayload(this, uploadedTransactions, options);
11804
12875
  };
@@ -11915,6 +12986,8 @@ class Item {
11915
12986
  'schemaUid',
11916
12987
  'latestVersionLocalId',
11917
12988
  'latestVersionUid',
12989
+ 'publishedVersionUid',
12990
+ 'publishedVersionLocalId',
11918
12991
  ];
11919
12992
  const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
11920
12993
  const schemaNameForModel = initialValues.schemaName;
@@ -11958,6 +13031,128 @@ class Item {
11958
13031
  });
11959
13032
  }
11960
13033
  }
13034
+ /** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
13035
+ static findItemInstanceCacheEntryByProps(props) {
13036
+ const l = props.seedLocalId;
13037
+ const u = props.seedUid;
13038
+ if (typeof l === 'string' && l.length > 0) {
13039
+ const e = this.instanceCache.get(l);
13040
+ if (e)
13041
+ return e;
13042
+ }
13043
+ if (typeof u === 'string' && u.length > 0) {
13044
+ const e = this.instanceCache.get(u);
13045
+ if (e)
13046
+ return e;
13047
+ }
13048
+ return undefined;
13049
+ }
13050
+ static findItemInstanceCacheEntryById(id) {
13051
+ const direct = this.instanceCache.get(id);
13052
+ if (direct)
13053
+ return direct;
13054
+ for (const [, entry] of this.instanceCache) {
13055
+ const ctx = entry.instance._getSnapshotContext();
13056
+ if (ctx.seedLocalId === id || ctx.seedUid === id)
13057
+ return entry;
13058
+ }
13059
+ return undefined;
13060
+ }
13061
+ static collectInstanceCacheKeysForInstance(instance) {
13062
+ const keys = [];
13063
+ for (const [k, v] of this.instanceCache) {
13064
+ if (v.instance === instance)
13065
+ keys.push(k);
13066
+ }
13067
+ return keys;
13068
+ }
13069
+ static registerItemInInstanceCache(instance) {
13070
+ const ctx = instance._getSnapshotContext();
13071
+ const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
13072
+ ? ctx.seedLocalId
13073
+ : undefined;
13074
+ const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
13075
+ const entry = { instance, refCount: 1 };
13076
+ if (lid)
13077
+ this.instanceCache.set(lid, entry);
13078
+ if (uid && uid !== lid)
13079
+ this.instanceCache.set(uid, entry);
13080
+ if (!lid && !uid) {
13081
+ throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
13082
+ }
13083
+ }
13084
+ static releaseItemInstanceCacheHold(instance) {
13085
+ const keys = this.collectInstanceCacheKeysForInstance(instance);
13086
+ if (keys.length === 0)
13087
+ return;
13088
+ const entry = this.instanceCache.get(keys[0]);
13089
+ entry.refCount -= 1;
13090
+ if (entry.refCount <= 0) {
13091
+ for (const k of keys) {
13092
+ this.instanceCache.delete(k);
13093
+ }
13094
+ }
13095
+ }
13096
+ /**
13097
+ * Item machine can reach `idle` before `propertyInstances` is merged (race) or while
13098
+ * child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
13099
+ */
13100
+ static async waitForItemInstanceReadyForRead(item, readyTimeout) {
13101
+ await waitForEntityIdle(item, { timeout: readyTimeout });
13102
+ const svc = item.getService();
13103
+ try {
13104
+ await xstate.waitFor(svc, (snap) => {
13105
+ if ('value' in snap && snap.value === 'error') {
13106
+ throw new Error('Entity failed to load');
13107
+ }
13108
+ if (!('value' in snap) || snap.value !== 'idle') {
13109
+ return false;
13110
+ }
13111
+ const ctx = snap.context || {};
13112
+ const versionsCount = ctx.versionsCount ?? 0;
13113
+ const hasHeadVersion = !!ctx.latestVersionLocalId;
13114
+ if (versionsCount === 0 && !hasHeadVersion) {
13115
+ return true;
13116
+ }
13117
+ return (ctx.propertyInstances?.size ?? 0) > 0;
13118
+ }, { timeout: readyTimeout });
13119
+ }
13120
+ catch (e) {
13121
+ if (e?.message === 'Entity failed to load') {
13122
+ throw e;
13123
+ }
13124
+ const msg = typeof e?.message === 'string' ? e.message : '';
13125
+ const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
13126
+ if (!isWaitForTimeout) {
13127
+ throw e;
13128
+ }
13129
+ }
13130
+ const snap = svc.getSnapshot();
13131
+ const pis = snap.context?.propertyInstances;
13132
+ if (!pis || pis.size === 0) {
13133
+ return;
13134
+ }
13135
+ await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
13136
+ timeout: readyTimeout,
13137
+ throwOnError: false,
13138
+ })));
13139
+ }
13140
+ static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
13141
+ const snap = instance.getService().getSnapshot();
13142
+ if (snap.value !== 'idle')
13143
+ return false;
13144
+ const mapSize = snap.context.propertyInstances?.size ?? 0;
13145
+ if (mapSize > 0)
13146
+ return false;
13147
+ const ctx = snap.context;
13148
+ const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
13149
+ const hasVersionHead = versionsCount > 0 ||
13150
+ !!props.latestVersionLocalId ||
13151
+ !!ctx.latestVersionLocalId ||
13152
+ !!props.latestVersionUid ||
13153
+ !!ctx.latestVersionUid;
13154
+ return hasVersionHead;
13155
+ }
11961
13156
  static async create(props, options) {
11962
13157
  const waitForReady = options?.waitForReady !== false;
11963
13158
  const readyTimeout = options?.readyTimeout ?? 5000;
@@ -11965,45 +13160,66 @@ class Item {
11965
13160
  props.modelName = lodashEs.startCase(props.type);
11966
13161
  }
11967
13162
  if (props.seedUid || props.seedLocalId) {
11968
- const seedId = (props.seedUid || props.seedLocalId);
11969
- if (this.instanceCache.has(seedId)) {
11970
- const { instance, refCount } = this.instanceCache.get(seedId);
11971
- this.instanceCache.set(seedId, {
11972
- instance,
11973
- refCount: refCount + 1,
11974
- });
11975
- for (const [propertyName, propertyValue] of Object.entries(props)) {
11976
- const snapshot = instance.getService().getSnapshot();
11977
- const propertyInstances = snapshot.context.propertyInstances;
11978
- if (!propertyInstances || !propertyInstances.has(propertyName)) {
11979
- continue;
11980
- }
11981
- const propertyInstance = propertyInstances.get(propertyName);
11982
- if (!propertyInstance) {
11983
- continue;
13163
+ cacheReuse: {
13164
+ const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
13165
+ if (cachedEntry) {
13166
+ const instance = cachedEntry.instance;
13167
+ cachedEntry.refCount += 1;
13168
+ for (const [propertyName, propertyValue] of Object.entries(props)) {
13169
+ const snapshot = instance.getService().getSnapshot();
13170
+ const propertyInstances = snapshot.context.propertyInstances;
13171
+ if (!propertyInstances || !propertyInstances.has(propertyName)) {
13172
+ continue;
13173
+ }
13174
+ const propertyInstance = propertyInstances.get(propertyName);
13175
+ if (!propertyInstance) {
13176
+ continue;
13177
+ }
13178
+ propertyInstance.getService().send({
13179
+ type: 'updateContext',
13180
+ propertyValue,
13181
+ });
11984
13182
  }
11985
- propertyInstance.getService().send({
11986
- type: 'updateContext',
11987
- propertyValue,
11988
- });
11989
- }
11990
- if (!waitForReady)
11991
- return instance;
11992
- try {
11993
- await waitForEntityIdle(instance, { timeout: readyTimeout });
11994
- }
11995
- catch (err) {
13183
+ if (!waitForReady)
13184
+ return instance;
11996
13185
  try {
11997
- instance.unload();
13186
+ await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
11998
13187
  }
11999
- catch {
12000
- /* best-effort cache cleanup */
13188
+ catch (err) {
13189
+ try {
13190
+ instance.unload();
13191
+ }
13192
+ catch {
13193
+ /* best-effort cache cleanup */
13194
+ }
13195
+ throw err;
12001
13196
  }
12002
- throw err;
13197
+ if (waitForReady &&
13198
+ this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
13199
+ forceRemoveFromCaches(instance, {
13200
+ getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
13201
+ caches: [Item.instanceCache],
13202
+ });
13203
+ try {
13204
+ unloadEntity(instance, {
13205
+ getCacheKeys: () => [],
13206
+ caches: [],
13207
+ instanceState: itemInstanceState,
13208
+ getService: (inst) => inst._service,
13209
+ onUnload: (inst) => {
13210
+ inst._subscription?.unsubscribe();
13211
+ },
13212
+ });
13213
+ }
13214
+ catch {
13215
+ /* best-effort teardown for stale cached shell */
13216
+ }
13217
+ break cacheReuse;
13218
+ }
13219
+ return instance;
12003
13220
  }
12004
- return instance;
12005
13221
  }
12006
- if (!this.instanceCache.has(seedId)) {
13222
+ if (!this.findItemInstanceCacheEntryByProps(props)) {
12007
13223
  // Item no longer needs modelInstance - it loads properties from database independently
12008
13224
  // Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
12009
13225
  const { latestVersionUid, ...propsWithoutVersionUid } = props;
@@ -12092,14 +13308,11 @@ class Item {
12092
13308
  return Reflect.getOwnPropertyDescriptor(target, prop);
12093
13309
  },
12094
13310
  });
12095
- this.instanceCache.set(seedId, {
12096
- instance: proxiedInstance,
12097
- refCount: 1,
12098
- });
13311
+ this.registerItemInInstanceCache(proxiedInstance);
12099
13312
  if (!waitForReady)
12100
13313
  return proxiedInstance;
12101
13314
  try {
12102
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13315
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12103
13316
  }
12104
13317
  catch (err) {
12105
13318
  try {
@@ -12275,14 +13488,11 @@ class Item {
12275
13488
  return Reflect.getOwnPropertyDescriptor(target, prop);
12276
13489
  },
12277
13490
  });
12278
- this.instanceCache.set((proxiedInstance.seedUid || proxiedInstance.seedLocalId), {
12279
- instance: proxiedInstance,
12280
- refCount: 1,
12281
- });
13491
+ this.registerItemInInstanceCache(proxiedInstance);
12282
13492
  if (!waitForReady)
12283
13493
  return proxiedInstance;
12284
13494
  try {
12285
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13495
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12286
13496
  }
12287
13497
  catch (err) {
12288
13498
  try {
@@ -12305,14 +13515,10 @@ class Item {
12305
13515
  if (!id) {
12306
13516
  return null;
12307
13517
  }
12308
- // Check cache - the cache key is seedUid || seedLocalId
12309
- if (this.instanceCache.has(id)) {
12310
- const { instance, refCount } = this.instanceCache.get(id);
12311
- this.instanceCache.set(id, {
12312
- instance,
12313
- refCount: refCount + 1,
12314
- });
12315
- return instance;
13518
+ const entry = this.findItemInstanceCacheEntryById(id);
13519
+ if (entry) {
13520
+ entry.refCount += 1;
13521
+ return entry.instance;
12316
13522
  }
12317
13523
  return null;
12318
13524
  }
@@ -12358,8 +13564,8 @@ class Item {
12358
13564
  if (!seedLocalId && !seedUid) {
12359
13565
  return undefined;
12360
13566
  }
12361
- // Use seedUid as primary ID if available, otherwise use seedLocalId
12362
- const id = seedUid || seedLocalId;
13567
+ // Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
13568
+ const id = seedLocalId || seedUid;
12363
13569
  if (!id) {
12364
13570
  return undefined;
12365
13571
  }
@@ -12390,10 +13596,127 @@ class Item {
12390
13596
  }));
12391
13597
  }
12392
13598
  if (waitForReady && itemInstances.length > 0) {
12393
- await Promise.all(itemInstances.map((item) => waitForEntityIdle(item, { timeout: readyTimeout })));
13599
+ await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
12394
13600
  }
12395
13601
  return lodashEs.orderBy(itemInstances, ['createdAt'], ['desc']);
12396
13602
  }
13603
+ /**
13604
+ * After EAS sync writes metadata for the latest version, merge new property instances and
13605
+ * re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
13606
+ * and useItems may not invalidate when the seed set is unchanged.
13607
+ */
13608
+ static async rehydrateCachedItemsFromDbAfterEasSync() {
13609
+ const appDb = BaseDb.getAppDb();
13610
+ if (!appDb || Item.instanceCache.size === 0) {
13611
+ return;
13612
+ }
13613
+ const { metadata } = await Promise.resolve().then(function () { return schema$1; });
13614
+ const { eq, and } = await import('drizzle-orm');
13615
+ const dedupedInstances = new Map();
13616
+ for (const entry of Item.instanceCache.values()) {
13617
+ dedupedInstances.set(entry.instance, entry);
13618
+ }
13619
+ const entries = [...dedupedInstances.values()];
13620
+ await Promise.all(entries.map(async ({ instance }) => {
13621
+ try {
13622
+ const svc = instance.getService();
13623
+ if (svc.getSnapshot().status !== 'active') {
13624
+ return;
13625
+ }
13626
+ const ctx = svc.getSnapshot().context;
13627
+ const seedLocalId = ctx.seedLocalId;
13628
+ const seedUid = ctx.seedUid;
13629
+ const versionLocalId = ctx.latestVersionLocalId;
13630
+ const itemModelName = ctx.modelName;
13631
+ const schemaNameForModel = ctx.schemaName;
13632
+ if (!seedLocalId || !versionLocalId || !itemModelName) {
13633
+ return;
13634
+ }
13635
+ const metadataRows = await appDb
13636
+ .select()
13637
+ .from(metadata)
13638
+ .where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
13639
+ let propertySchemas = {};
13640
+ try {
13641
+ const M = getModel();
13642
+ const model = schemaNameForModel !== undefined
13643
+ ? M?.getByName(itemModelName, schemaNameForModel)
13644
+ : M?.getByName(itemModelName);
13645
+ if (model?.properties?.length) {
13646
+ propertySchemas = modelPropertiesToObject(model.properties);
13647
+ }
13648
+ }
13649
+ catch {
13650
+ /* Model optional */
13651
+ }
13652
+ const sendToItemMachine = (event) => {
13653
+ if (svc.getSnapshot().status !== 'active') {
13654
+ return;
13655
+ }
13656
+ svc.send(event);
13657
+ };
13658
+ for (const metaRow of metadataRows) {
13659
+ try {
13660
+ let propertyName = metaRow.propertyName;
13661
+ const listSchemaKey = propertyName &&
13662
+ Object.keys(propertySchemas).length > 0 &&
13663
+ resolveStorageNameToSchemaName(propertySchemas, propertyName);
13664
+ if (listSchemaKey) {
13665
+ propertyName = listSchemaKey;
13666
+ }
13667
+ else {
13668
+ const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
13669
+ const refSeedType = metaRow.refSeedType;
13670
+ const isRefTypeFromMeta = refSeedType === 'file' ||
13671
+ refSeedType === 'image' ||
13672
+ refSeedType === 'relation' ||
13673
+ refSeedType === 'html';
13674
+ if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
13675
+ propertyName = baseName;
13676
+ }
13677
+ }
13678
+ if (!propertyName) {
13679
+ continue;
13680
+ }
13681
+ const property = await ItemProperty.find({
13682
+ propertyName,
13683
+ seedLocalId,
13684
+ seedUid,
13685
+ modelName: itemModelName,
13686
+ });
13687
+ if (property) {
13688
+ sendToItemMachine({
13689
+ type: 'addPropertyInstance',
13690
+ propertyName,
13691
+ propertyInstance: property,
13692
+ });
13693
+ }
13694
+ }
13695
+ catch {
13696
+ /* row skipped */
13697
+ }
13698
+ }
13699
+ const instances = svc.getSnapshot().context.propertyInstances;
13700
+ if (!instances) {
13701
+ return;
13702
+ }
13703
+ for (const propertyInstance of instances.values()) {
13704
+ try {
13705
+ const propertySnap = propertyInstance.getService().getSnapshot();
13706
+ if (xstate.isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
13707
+ propertyInstance.getService().send({ type: 'rehydrateFromDb' });
13708
+ }
13709
+ }
13710
+ catch {
13711
+ /* best-effort */
13712
+ }
13713
+ }
13714
+ }
13715
+ catch (e) {
13716
+ itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
13717
+ }
13718
+ }));
13719
+ }
12397
13720
  _createPropertyInstance(props) {
12398
13721
  if (this._storageTransactionId) {
12399
13722
  props.storageTransactionId = this._storageTransactionId;
@@ -13008,15 +14331,10 @@ class Item {
13008
14331
  }
13009
14332
  unload() {
13010
14333
  try {
13011
- const context = this._getSnapshotContext();
13012
- const cacheKey = context.seedUid || context.seedLocalId;
13013
- const cacheKeys = [];
13014
- if (cacheKey) {
13015
- cacheKeys.push(cacheKey);
13016
- }
14334
+ Item.releaseItemInstanceCacheHold(this);
13017
14335
  unloadEntity(this, {
13018
- getCacheKeys: () => cacheKeys,
13019
- caches: [Item.instanceCache],
14336
+ getCacheKeys: () => [],
14337
+ caches: [],
13020
14338
  instanceState: itemInstanceState,
13021
14339
  getService: (instance) => instance._service,
13022
14340
  onUnload: (instance) => {
@@ -13045,11 +14363,10 @@ class Item {
13045
14363
  * Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
13046
14364
  */
13047
14365
  async destroy() {
13048
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
14366
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
13049
14367
  await assertItemOwned(this);
13050
14368
  const context = this._getSnapshotContext();
13051
- const cacheKey = context.seedUid || context.seedLocalId;
13052
- const cacheKeys = cacheKey ? [cacheKey] : [];
14369
+ const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
13053
14370
  clearDestroySubscriptions(this, {
13054
14371
  instanceState: itemInstanceState,
13055
14372
  onUnload: (instance) => instance._subscription?.unsubscribe(),
@@ -13106,600 +14423,331 @@ function normalizeAddressConfig(addresses) {
13106
14423
  };
13107
14424
  }
13108
14425
 
13109
- // Dynamic import to break circular dependency: Model -> BaseItem -> ... -> getModelSchemas -> Model
13110
- // import { Model } from '@/Model/Model'
13111
- const schemaStringToModelRecord = new Map();
13112
- const getModelSchemas = async () => {
13113
- // Dynamic import to break circular dependency
13114
- const modelMod = await Promise.resolve().then(function () { return Model$1; });
13115
- const { Model } = modelMod;
13116
- const allModels = await Model.all();
13117
- const modelRecords = [];
13118
- const appDb = BaseDb.getAppDb();
13119
- for (const model of allModels) {
13120
- const modelName = model.modelName;
13121
- if (!modelName)
13122
- continue;
13123
- const foundModelQuery = await appDb
13124
- .select({
13125
- id: models$1.id,
13126
- name: models$1.name,
13127
- uid: modelUids.uid,
14426
+ let writeTail = Promise.resolve();
14427
+ function enqueueEasSyncDbWrite(fn) {
14428
+ const next = writeTail.then(fn);
14429
+ writeTail = next.catch(() => { });
14430
+ return next;
14431
+ }
14432
+ const MAX_ERROR_MESSAGE_LENGTH = 500;
14433
+ const MAX_ERROR_DETAILS_LENGTH = 2000;
14434
+ async function insertEasSyncProcessRow(params) {
14435
+ return enqueueEasSyncDbWrite(async () => {
14436
+ const db = BaseDb.getAppDb();
14437
+ if (!db) {
14438
+ throw new Error('[easSyncProcess] App DB not available');
14439
+ }
14440
+ const now = Date.now();
14441
+ const [row] = await db
14442
+ .insert(easSyncProcesses)
14443
+ .values({
14444
+ status: 'in_progress',
14445
+ startedAt: now,
14446
+ requestPayload: JSON.stringify(params.requestPayload),
14447
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14448
+ createdAt: now,
14449
+ updatedAt: now,
13128
14450
  })
13129
- .from(models$1)
13130
- .leftJoin(modelUids, drizzleOrm.eq(models$1.id, modelUids.modelId))
13131
- .where(drizzleOrm.eq(models$1.name, modelName))
13132
- .limit(1);
13133
- if (!foundModelQuery[0]) {
13134
- console.error(`[item/events] [syncDbWithEas] model ${modelName} not found in SDK DB`);
13135
- continue;
13136
- }
13137
- const foundModel = {
13138
- id: foundModelQuery[0].id,
13139
- name: foundModelQuery[0].name,
13140
- uid: foundModelQuery[0].uid,
13141
- tableName: pluralize(foundModelQuery[0].name).toLowerCase(),
13142
- };
13143
- modelRecords.push(foundModel);
13144
- if (modelName === 'Seed') {
13145
- continue;
13146
- }
13147
- const schemaString = `bytes32 ${toSnakeCase(modelName)}`;
13148
- schemaStringToModelRecord.set(schemaString, foundModel);
13149
- }
13150
- return {
13151
- schemaStringToModelRecord,
13152
- modelRecords,
13153
- };
13154
- };
13155
-
13156
- const createSeeds = async (newSeeds) => {
13157
- const appDb = BaseDb.getAppDb();
13158
- const results = await appDb
13159
- .insert(seeds)
13160
- .values(newSeeds)
13161
- .returning({ uid: seeds.uid });
13162
- const newUids = results.reduce((acc, result) => {
13163
- if (result.uid) {
13164
- acc.push(result.uid);
14451
+ .returning({ id: easSyncProcesses.id });
14452
+ return row.id;
14453
+ });
14454
+ }
14455
+ async function finalizeEasSyncProcessRow(id, params) {
14456
+ return enqueueEasSyncDbWrite(async () => {
14457
+ const db = BaseDb.getAppDb();
14458
+ if (!db) {
14459
+ return;
13165
14460
  }
13166
- return acc;
13167
- }, []);
13168
- return newUids;
13169
- };
14461
+ const now = Date.now();
14462
+ await db
14463
+ .update(easSyncProcesses)
14464
+ .set({
14465
+ status: params.status,
14466
+ completedAt: now,
14467
+ updatedAt: now,
14468
+ errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
14469
+ errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
14470
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14471
+ })
14472
+ .where(drizzleOrm.eq(easSyncProcesses.id, id));
14473
+ });
14474
+ }
13170
14475
 
13171
14476
  /**
13172
- * Sets revokedAt timestamp on a seed record after attestations have been revoked on EAS.
14477
+ * Merge multiple EAS sync intents: full sync (no concrete address list) wins;
14478
+ * otherwise union addresses (first-seen casing).
13173
14479
  */
13174
- const updateSeedRevokedAt = async ({ seedLocalId, revokedAt, }) => {
13175
- if (!seedLocalId) {
13176
- return;
14480
+ function mergeEasSyncRequestIntents(parts) {
14481
+ const norm = parts.filter((p) => p != null);
14482
+ if (norm.length === 0) {
14483
+ return {};
13177
14484
  }
13178
- const appDb = BaseDb.getAppDb();
13179
- await appDb
13180
- .update(seeds)
13181
- .set({
13182
- revokedAt,
13183
- updatedAt: Date.now(),
13184
- })
13185
- .where(drizzleOrm.eq(seeds.localId, seedLocalId));
13186
- };
13187
-
13188
- const relationValuesToExclude = [
13189
- '0x0000000000000000000000000000000000000000000000000000000000000020',
13190
- ];
13191
- const seedUidToLocalId = new Map();
13192
- const seedUidToModelType = new Map();
13193
- const relatedSeedUids = new Set();
13194
- const versionUidToLocalId = new Map();
13195
- const versionUidToSeedUid = new Map();
13196
- const propertyUidToLocalId = new Map();
13197
- const saveEasSeedsToDb = async ({ itemSeeds }) => {
13198
- const appDb = BaseDb.getAppDb();
13199
- const seedUids = itemSeeds.map((seed) => seed.id);
13200
- const existingSeedRecordsRows = await appDb
13201
- .select()
13202
- .from(seeds)
13203
- .where(drizzleOrm.inArray(seeds.uid, seedUids));
13204
- const existingSeedUids = new Set();
13205
- if (existingSeedRecordsRows && existingSeedRecordsRows.length > 0) {
13206
- for (const row of existingSeedRecordsRows) {
13207
- if (row.uid) {
13208
- existingSeedUids.add(row.uid);
13209
- if (row.localId) {
13210
- seedUidToLocalId.set(row.uid, row.localId);
13211
- }
13212
- if (row.type) {
13213
- seedUidToModelType.set(row.uid, row.type);
13214
- }
14485
+ let full = false;
14486
+ const addressMap = new Map();
14487
+ for (const p of norm) {
14488
+ if (!('addresses' in p) || p.addresses === undefined) {
14489
+ full = true;
14490
+ break;
14491
+ }
14492
+ for (const addr of p.addresses) {
14493
+ const k = addr.toLowerCase();
14494
+ if (!addressMap.has(k)) {
14495
+ addressMap.set(k, addr);
13215
14496
  }
13216
14497
  }
13217
14498
  }
13218
- const newSeeds = itemSeeds.filter((seed) => !existingSeedUids.has(seed.id));
13219
- // Update existing seeds when attestations are revoked on EAS
13220
- const seedByUid = new Map(itemSeeds.map((s) => [s.id, s]));
13221
- for (const row of existingSeedRecordsRows) {
13222
- if (!row.uid || !row.localId)
13223
- continue;
13224
- const attestation = seedByUid.get(row.uid);
13225
- if (!attestation?.revoked)
13226
- continue;
13227
- if (row.revokedAt != null)
13228
- continue;
13229
- const revokedAt = attestation.revocationTime > 0
13230
- ? attestation.revocationTime
13231
- : Math.floor(Date.now() / 1000);
13232
- await updateSeedRevokedAt({ seedLocalId: row.localId, revokedAt });
13233
- }
13234
- if (newSeeds.length === 0) {
13235
- return { seedUidToLocalId, seedUids };
13236
- }
13237
- const newSeedsData = [];
13238
- for (let i = 0; i < newSeeds.length; i++) {
13239
- const seed = newSeeds[i];
13240
- seedUidToModelType.set(seed.id, seed.schema.schemaNames[0].name);
13241
- const seedLocalId = generateId();
13242
- seedUidToLocalId.set(seed.id, seedLocalId);
13243
- const attestationRaw = escapeSqliteString(JSON.stringify(seed));
13244
- const revokedAt = seed.revoked && seed.revocationTime != null && seed.revocationTime > 0
13245
- ? seed.revocationTime
13246
- : seed.revoked
13247
- ? Math.floor(Date.now() / 1000)
13248
- : undefined;
13249
- newSeedsData.push({
13250
- localId: seedLocalId,
13251
- uid: seed.id,
13252
- schemaUid: seed.schemaId,
13253
- type: seed.schema.schemaNames[0].name,
13254
- publisher: seed.attester,
13255
- createdAt: Date.now(),
13256
- attestationCreatedAt: seed.timeCreated * 1000,
13257
- attestationRaw,
13258
- ...(revokedAt !== undefined && { revokedAt }),
13259
- });
13260
- seedUidToLocalId.set(seed.id, seedLocalId);
14499
+ if (full) {
14500
+ return {};
13261
14501
  }
13262
- const newSeedUids = await createSeeds(newSeedsData);
13263
- return { seedUids: newSeedUids };
13264
- };
13265
- const saveEasVersionsToDb = async ({ itemVersions }) => {
13266
- const versionUids = itemVersions.map((version) => version.id);
13267
- const appDb = BaseDb.getAppDb();
13268
- const existingVersionRecordsRows = await appDb
13269
- .select()
13270
- .from(versions)
13271
- .where(drizzleOrm.inArray(versions.uid, versionUids));
13272
- const existingVersionUids = new Set();
13273
- if (existingVersionRecordsRows && existingVersionRecordsRows.length > 0) {
13274
- for (const row of existingVersionRecordsRows) {
13275
- if (row.uid) {
13276
- existingVersionUids.add(row.uid);
13277
- if (row.localId) {
13278
- versionUidToLocalId.set(row.uid, row.localId);
13279
- }
13280
- if (row.seedUid) {
13281
- versionUidToSeedUid.set(row.uid, row.seedUid);
13282
- }
13283
- }
13284
- }
13285
- }
13286
- const newVersions = itemVersions.filter((version) => !existingVersionUids.has(version.id));
13287
- if (newVersions.length === 0) {
13288
- return { versionUidToLocalId, versionUids };
13289
- }
13290
- let insertVersionsQuery = `INSERT INTO versions (local_id, uid, seed_uid, seed_local_id, seed_type, created_at,
13291
- attestation_created_at,
13292
- attestation_raw, publisher)
13293
- VALUES `;
13294
- for (let i = 0; i < newVersions.length; i++) {
13295
- const version = newVersions[i];
13296
- versionUidToSeedUid.set(version.id, version.refUID);
13297
- const versionLocalId = generateId();
13298
- versionUidToLocalId.set(version.id, versionLocalId);
13299
- const seedUid = versionUidToSeedUid.get(version.id);
13300
- const seedLocalId = seedUidToLocalId.get(seedUid);
13301
- const seedType = seedUidToModelType.get(seedUid);
13302
- const attestationRaw = escapeSqliteString(JSON.stringify(version));
13303
- const publisher = escapeSqliteString(version.attester ?? '');
13304
- const valuesString = `('${versionLocalId}', '${version.id}', '${seedUid}', '${seedLocalId}', '${seedType}', ${Date.now()}, ${version.timeCreated * 1000}, '${attestationRaw}', '${publisher}')`;
13305
- if (i < newVersions.length - 1) {
13306
- insertVersionsQuery += valuesString + ', ';
13307
- }
13308
- if (i === newVersions.length - 1) {
13309
- insertVersionsQuery += valuesString + ';';
13310
- }
13311
- versionUidToLocalId.set(version.id, versionLocalId);
13312
- }
13313
- await appDb.run(drizzleOrm.sql.raw(insertVersionsQuery));
13314
- return { versionUids };
13315
- };
13316
- const createMetadataRecordsForStorageTransactionId = async (storageTransactionIdProperty, modelSchema) => {
13317
- // Early return if modelSchema is not provided
13318
- if (!modelSchema) {
13319
- console.warn('[item/events] [syncDbWithEas] modelSchema is undefined for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
13320
- return;
14502
+ if (addressMap.size === 0) {
14503
+ return { addresses: [] };
13321
14504
  }
13322
- // Validate and parse decodedDataJson
13323
- if (!storageTransactionIdProperty.decodedDataJson || storageTransactionIdProperty.decodedDataJson.trim() === '') {
13324
- console.warn('[item/events] [syncDbWithEas] empty decodedDataJson for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
13325
- return;
14505
+ return { addresses: [...addressMap.values()] };
14506
+ }
14507
+
14508
+ const log = debug('seedSdk:events:easSyncManager');
14509
+ function toRunSyncArg(options) {
14510
+ if (options &&
14511
+ 'addresses' in options &&
14512
+ options.addresses !== undefined) {
14513
+ return options;
13326
14514
  }
13327
- let parsedData;
14515
+ return undefined;
14516
+ }
14517
+ const runEasSync = xstate.fromPromise(async ({ input, }) => {
14518
+ const rowId = await insertEasSyncProcessRow({
14519
+ requestPayload: input.requestPayload,
14520
+ persistedSnapshot: input.runningSnapshot,
14521
+ });
14522
+ const { runSyncFromEas } = await Promise.resolve().then(function () { return require('./syncDbWithEas-DcKL-_Pb.js'); });
13328
14523
  try {
13329
- parsedData = JSON.parse(storageTransactionIdProperty.decodedDataJson);
13330
- }
13331
- catch (error) {
13332
- console.warn('[item/events] [syncDbWithEas] failed to parse decodedDataJson for storageTransactionIdProperty: ', storageTransactionIdProperty.id, error);
13333
- return;
13334
- }
13335
- if (!Array.isArray(parsedData) || parsedData.length === 0 || !parsedData[0]?.value) {
13336
- console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
13337
- return;
13338
- }
13339
- const attestationData = parsedData[0].value;
13340
- lodashEs.camelCase(attestationData.name);
13341
- const propertyValue = attestationData.value;
13342
- const itemStorageProperties = new Map();
13343
- for (const [_propertyName, propertyDef] of Object.entries(modelSchema)) {
13344
- if (propertyDef?.storageType && propertyDef.storageType === 'ItemStorage') {
13345
- itemStorageProperties.set(_propertyName, propertyDef);
13346
- }
13347
- }
13348
- if (itemStorageProperties.size === 0) {
13349
- return;
13350
- }
13351
- const appDb = BaseDb.getAppDb();
13352
- for (const [_propertyName, propertyDef] of itemStorageProperties.entries()) {
13353
- const existingMetadataRecordRows = await appDb
13354
- .select()
13355
- .from(metadata$1)
13356
- .where(drizzleOrm.and(drizzleOrm.eq(metadata$1.propertyName, _propertyName), drizzleOrm.eq(metadata$1.propertyValue, propertyValue), drizzleOrm.eq(metadata$1.versionUid, storageTransactionIdProperty.refUID)));
13357
- if (existingMetadataRecordRows && existingMetadataRecordRows.length > 0) {
13358
- continue;
13359
- }
13360
- const seedUid = versionUidToSeedUid.get(storageTransactionIdProperty.refUID);
13361
- const seedLocalId = seedUidToLocalId.get(seedUid);
13362
- const versionUid = storageTransactionIdProperty.refUID;
13363
- const versionLocalId = versionUidToLocalId.get(versionUid);
13364
- const modelType = seedUidToModelType.get(seedUid);
13365
- const propertyId = modelType != null
13366
- ? await getPropertyIdForModelAndName(modelType, _propertyName)
13367
- : null;
13368
- const propertyLocalId = generateId();
13369
- await appDb.insert(metadata$1).values({
13370
- localId: propertyLocalId,
13371
- propertyId: propertyId ?? undefined,
13372
- propertyName: _propertyName,
13373
- propertyValue,
13374
- localStorageDir: propertyDef.localStorageDir,
13375
- seedLocalId,
13376
- seedUid,
13377
- versionLocalId,
13378
- versionUid,
13379
- refValueType: 'file',
13380
- refResolvedValue: `${propertyValue}${propertyDef.filenameSuffix}`,
13381
- modelType: seedUidToModelType.get(seedUid),
13382
- createdAt: Date.now(),
13383
- updatedAt: Date.now(),
14524
+ await runSyncFromEas(toRunSyncArg(input.options));
14525
+ await finalizeEasSyncProcessRow(rowId, {
14526
+ status: 'completed',
14527
+ persistedSnapshot: {
14528
+ phase: 'completed',
14529
+ correlationIds: input.requestPayload.correlationIds,
14530
+ },
13384
14531
  });
13385
14532
  }
13386
- };
13387
- let isSavingToDb = false;
13388
- const saveEasPropertiesToDb = async ({ itemProperties, itemSeeds, }) => {
13389
- if (isSavingToDb) {
13390
- return { propertyUids: [] };
13391
- }
13392
- isSavingToDb = true;
13393
- const propertyUids = itemProperties.map((property) => property.id);
13394
- // Dynamic import to break circular dependency
13395
- const modelMod = await Promise.resolve().then(function () { return Model$1; });
13396
- const { Model } = modelMod;
13397
- const allModels = await Model.all();
13398
- const models = Object.fromEntries(allModels.map(m => [m.modelName, m]));
13399
- const appDb = BaseDb.getAppDb();
13400
- const existingMetadataRecordsRows = await appDb
13401
- .select()
13402
- .from(metadata$1)
13403
- .where(drizzleOrm.inArray(metadata$1.uid, propertyUids));
13404
- const existingPropertyRecordsUids = new Set();
13405
- if (existingMetadataRecordsRows && existingMetadataRecordsRows.length > 0) {
13406
- for (const row of existingMetadataRecordsRows) {
13407
- if (row.uid) {
13408
- existingPropertyRecordsUids.add(row.uid);
13409
- if (row.localId) {
13410
- propertyUidToLocalId.set(row.uid, row.localId);
13411
- }
13412
- }
13413
- }
13414
- }
13415
- const newProperties = itemProperties.filter((property) => !existingPropertyRecordsUids.has(property.id));
13416
- if (newProperties.length === 0) {
13417
- return { propertyUidToLocalId, propertyUids };
13418
- }
13419
- let insertPropertiesQuery = `INSERT INTO metadata (local_id, uid, schema_uid, property_id, property_name, property_value,
13420
- eas_data_type, version_uid, version_local_id, seed_uid,
13421
- seed_local_id, model_type, ref_value_type, ref_seed_type,
13422
- ref_schema_uid,
13423
- created_at, attestation_created_at, attestation_raw,
13424
- local_storage_dir, ref_resolved_value, publisher)
13425
- VALUES `;
13426
- for (let i = 0; i < newProperties.length; i++) {
13427
- const property = newProperties[i];
13428
- const propertyLocalId = generateId();
13429
- // Validate and parse decodedDataJson
13430
- if (!property.decodedDataJson || property.decodedDataJson.trim() === '') {
13431
- console.warn('[item/events] [syncDbWithEas] empty decodedDataJson for property: ', property.id);
13432
- continue;
13433
- }
13434
- let parsedData;
13435
- try {
13436
- parsedData = JSON.parse(property.decodedDataJson);
13437
- }
13438
- catch (error) {
13439
- console.warn('[item/events] [syncDbWithEas] failed to parse decodedDataJson for property: ', property.id, error);
13440
- continue;
13441
- }
13442
- if (!Array.isArray(parsedData) || parsedData.length === 0 || !parsedData[0]?.value) {
13443
- console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for property: ', property.id);
13444
- continue;
13445
- }
13446
- const metadata = parsedData[0].value;
13447
- let propertyNameSnake = metadata.name;
13448
- if (!propertyNameSnake) {
13449
- console.warn('[item/events] [syncDbWithEas] no propertyName found for property: ', property);
13450
- continue;
13451
- }
13452
- let isRelation = false;
13453
- let refValueType;
13454
- let refSeedType;
13455
- let refSchemaUid;
13456
- let isList = false;
13457
- const schemaUid = property.schemaId;
13458
- setSchemaUidForSchemaDefinition({
13459
- text: propertyNameSnake,
13460
- schemaUid,
14533
+ catch (err) {
14534
+ const message = err instanceof Error ? err.message : String(err);
14535
+ const details = err instanceof Error && err.stack
14536
+ ? err.stack.slice(0, 2000)
14537
+ : undefined;
14538
+ await finalizeEasSyncProcessRow(rowId, {
14539
+ status: 'failed',
14540
+ errorMessage: message,
14541
+ errorDetails: details,
14542
+ persistedSnapshot: {
14543
+ phase: 'failed',
14544
+ correlationIds: input.requestPayload.correlationIds,
14545
+ },
13461
14546
  });
13462
- if ((propertyNameSnake.endsWith('_id') ||
13463
- propertyNameSnake.endsWith('_ids')) &&
13464
- propertyNameSnake !== 'storage_transaction_id' &&
13465
- propertyNameSnake !== 'storage_provider_transaction_id') {
13466
- isRelation = true;
13467
- if (Array.isArray(metadata.value)) {
13468
- isList = true;
13469
- refValueType = 'list';
13470
- const result = parseEasRelationPropertyName(propertyNameSnake);
13471
- if (result) {
13472
- propertyNameSnake = result.propertyName;
13473
- refSeedType = result.modelName;
13474
- }
13475
- metadata.value.forEach((value) => {
13476
- relatedSeedUids.add(value);
13477
- });
13478
- }
13479
- if (!isList) {
13480
- if (relationValuesToExclude.includes(metadata.value)) {
13481
- continue;
13482
- }
13483
- relatedSeedUids.add(metadata.value);
13484
- }
13485
- }
13486
- let propertyValue = metadata.value;
13487
- if (typeof propertyValue !== 'string') {
13488
- propertyValue = JSON.stringify(propertyValue);
13489
- }
13490
- if (isRelation && !isList) {
13491
- const relatedSeed = itemSeeds.find((seed) => seed.id === metadata.value);
13492
- if (relatedSeed && relatedSeed.schema && relatedSeed.schema.schemaNames) {
13493
- refSeedType = relatedSeed.schema.schemaNames[0].name;
13494
- refSchemaUid = relatedSeed.schemaId;
13495
- }
13496
- }
13497
- if (isRelation && isList) {
13498
- const relatedSeeds = itemSeeds.filter((seed) => metadata.value.includes(seed.id));
13499
- if (relatedSeeds && relatedSeeds.length > 0) {
13500
- refSeedType = relatedSeeds[0].schema.schemaNames[0].name;
13501
- refSchemaUid = relatedSeeds[0].schemaId;
13502
- }
13503
- }
13504
- const propertyName = lodashEs.camelCase(propertyNameSnake);
13505
- propertyValue = escapeSqliteString(propertyValue);
13506
- const easDataType = metadata.type;
13507
- const versionUid = property.refUID;
13508
- const versionLocalId = versionUidToLocalId.get(versionUid);
13509
- const attestationCreatedAt = property.timeCreated * 1000;
13510
- const attestationRaw = escapeSqliteString(JSON.stringify(property));
13511
- const seedUid = versionUidToSeedUid.get(versionUid);
13512
- const seedLocalId = seedUidToLocalId.get(seedUid);
13513
- const modelType = seedUidToModelType.get(seedUid);
13514
- const modelName = lodashEs.startCase(modelType);
13515
- const model = models[modelName];
13516
- const modelSchema = model?.properties ? modelPropertiesToObject(model.properties) : undefined;
13517
- if (propertyNameSnake === 'storage_transaction_id') {
13518
- await createMetadataRecordsForStorageTransactionId(property, modelSchema);
13519
- }
13520
- const propertyId = modelType != null
13521
- ? await getPropertyIdForModelAndName(modelType, propertyName)
13522
- : null;
13523
- const propertyIdSql = propertyId != null ? String(propertyId) : 'NULL';
13524
- const publisher = escapeSqliteString(property.attester ?? '');
13525
- const valuesString = `('${propertyLocalId}', '${property.id}',
13526
- '${property.schemaId}', ${propertyIdSql}, '${propertyName}',
13527
- '${propertyValue}', '${easDataType}', '${versionUid}',
13528
- '${versionLocalId}', '${seedUid}', '${seedLocalId}',
13529
- '${modelType}', ${refValueType ? `'${refValueType}'` : 'NULL'},
13530
- ${refSeedType ? `'${refSeedType}'` : 'NULL'},
13531
- ${refSchemaUid ? `'${refSchemaUid}'` : 'NULL'},
13532
- ${Date.now()}, ${attestationCreatedAt}, '${attestationRaw}',
13533
- ${'NULL'},
13534
- ${'NULL'},
13535
- '${publisher}')`;
13536
- if (i < newProperties.length - 1) {
13537
- insertPropertiesQuery += valuesString + ', ';
13538
- }
13539
- if (i === newProperties.length - 1) {
13540
- insertPropertiesQuery += valuesString + ';';
13541
- }
13542
- propertyUidToLocalId.set(property.id, propertyLocalId);
13543
- }
13544
- if (insertPropertiesQuery.endsWith('VALUES ')) {
13545
- return { propertyUids };
13546
- }
13547
- if (insertPropertiesQuery.endsWith(', ')) {
13548
- insertPropertiesQuery = insertPropertiesQuery.slice(0, -2) + ';';
13549
- }
13550
- await appDb.run(drizzleOrm.sql.raw(insertPropertiesQuery));
13551
- isSavingToDb = false;
13552
- return { propertyUids };
14547
+ throw err;
14548
+ }
14549
+ });
14550
+ const initialContext = {
14551
+ runOptions: {},
14552
+ activeCorrelationIds: [],
14553
+ activePrimarySource: 'event_bus',
14554
+ pendingMergedOptions: undefined,
14555
+ pendingCorrelationIds: [],
14556
+ pendingPrimarySource: null,
14557
+ lastFinishedCorrelationIds: null,
14558
+ lastFinishedStatus: null,
14559
+ lastFinishedError: null,
13553
14560
  };
13554
- const getRelatedSeedsAndVersions = async () => {
13555
- BaseQueryClient.getQueryClient();
13556
- const easClient = BaseEasClient.getEasClient();
13557
- const { itemSeeds } = await easClient.request(GET_SEEDS, {
13558
- where: {
13559
- id: {
13560
- in: Array.from(relatedSeedUids),
14561
+ const easSyncMachine = xstate.setup({
14562
+ types: {
14563
+ context: {},
14564
+ events: {},
14565
+ },
14566
+ actors: {
14567
+ runEasSync,
14568
+ },
14569
+ }).createMachine({
14570
+ id: MachineIds.EAS_SYNC_MANAGER,
14571
+ initial: 'idle',
14572
+ context: initialContext,
14573
+ states: {
14574
+ idle: {
14575
+ on: {
14576
+ REQUEST: {
14577
+ target: 'running',
14578
+ actions: xstate.assign({
14579
+ runOptions: ({ event }) => event.options === undefined
14580
+ ? {}
14581
+ : mergeEasSyncRequestIntents([event.options]),
14582
+ activeCorrelationIds: ({ event }) => [event.correlationId],
14583
+ activePrimarySource: ({ event }) => event.source,
14584
+ }),
14585
+ },
14586
+ },
14587
+ },
14588
+ running: {
14589
+ on: {
14590
+ REQUEST: {
14591
+ actions: xstate.assign({
14592
+ pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
14593
+ context.runOptions,
14594
+ context.pendingMergedOptions,
14595
+ event.options === undefined ? {} : event.options,
14596
+ ].filter((x) => x != null)),
14597
+ pendingCorrelationIds: ({ context, event }) => [
14598
+ ...context.pendingCorrelationIds,
14599
+ event.correlationId,
14600
+ ],
14601
+ pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
14602
+ }),
14603
+ },
13561
14604
  },
13562
- },
13563
- });
13564
- await saveEasSeedsToDb({ itemSeeds });
13565
- const { itemVersions } = await easClient.request(GET_VERSIONS, {
13566
- where: {
13567
- refUID: {
13568
- in: Array.from(relatedSeedUids),
14605
+ invoke: {
14606
+ src: 'runEasSync',
14607
+ input: ({ context }) => ({
14608
+ options: context.runOptions,
14609
+ requestPayload: {
14610
+ source: context.activePrimarySource,
14611
+ correlationIds: context.activeCorrelationIds,
14612
+ options: context.runOptions,
14613
+ },
14614
+ runningSnapshot: {
14615
+ phase: 'running',
14616
+ correlationIds: context.activeCorrelationIds,
14617
+ },
14618
+ }),
14619
+ onDone: {
14620
+ target: 'afterRun',
14621
+ actions: xstate.assign({
14622
+ lastFinishedCorrelationIds: ({ context }) => [
14623
+ ...context.activeCorrelationIds,
14624
+ ],
14625
+ lastFinishedStatus: () => 'success',
14626
+ lastFinishedError: () => null,
14627
+ activeCorrelationIds: () => [],
14628
+ runOptions: () => ({}),
14629
+ }),
14630
+ },
14631
+ onError: {
14632
+ target: 'afterRun',
14633
+ actions: [
14634
+ xstate.assign({
14635
+ lastFinishedCorrelationIds: ({ context }) => [
14636
+ ...context.activeCorrelationIds,
14637
+ ],
14638
+ lastFinishedStatus: () => 'failed',
14639
+ lastFinishedError: ({ event }) => {
14640
+ const e = event.error;
14641
+ if (e instanceof Error) {
14642
+ return e.message;
14643
+ }
14644
+ return e != null ? String(e) : 'EAS sync failed';
14645
+ },
14646
+ activeCorrelationIds: () => [],
14647
+ runOptions: () => ({}),
14648
+ }),
14649
+ ({ event }) => {
14650
+ log('runEasSync error', event.error);
14651
+ },
14652
+ ],
14653
+ },
13569
14654
  },
13570
14655
  },
13571
- });
13572
- await saveEasVersionsToDb({ itemVersions });
13573
- const relatedVersionUids = itemVersions.map((v) => v.id);
13574
- const { itemProperties } = await easClient.request(GET_PROPERTIES, {
13575
- where: {
13576
- refUID: {
13577
- in: relatedVersionUids,
13578
- },
14656
+ afterRun: {
14657
+ always: [
14658
+ {
14659
+ guard: ({ context }) => context.pendingCorrelationIds.length > 0,
14660
+ target: 'running',
14661
+ actions: xstate.assign({
14662
+ runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
14663
+ activeCorrelationIds: ({ context }) => [
14664
+ ...context.pendingCorrelationIds,
14665
+ ],
14666
+ activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
14667
+ pendingMergedOptions: () => undefined,
14668
+ pendingCorrelationIds: () => [],
14669
+ pendingPrimarySource: () => null,
14670
+ }),
14671
+ },
14672
+ { target: 'idle' },
14673
+ ],
13579
14674
  },
13580
- });
13581
- await saveEasPropertiesToDb({
13582
- itemProperties,
13583
- itemSeeds,
13584
- });
13585
- };
13586
- /**
13587
- * Core sync logic: fetches item attestations from EAS for configured models and given addresses,
13588
- * then saves seeds, versions, and properties to the local DB.
13589
- * Uses owned + watched addresses from DB when addresses are not provided.
13590
- */
13591
- const runSyncFromEas = async (options) => {
13592
- let addresses = options?.addresses ?? (await getAllAddressesFromDb());
13593
- const additionalGetter = getGetAdditionalSyncAddresses();
13594
- if (additionalGetter) {
13595
- const additional = await additionalGetter();
13596
- if (additional?.length) {
13597
- const seen = new Set(addresses.map((a) => a.toLowerCase()));
13598
- for (const addr of additional) {
13599
- if (addr && !seen.has(addr.toLowerCase())) {
13600
- seen.add(addr.toLowerCase());
13601
- addresses = [...addresses, addr];
13602
- }
13603
- }
13604
- }
13605
- }
13606
- if (!addresses || addresses.length === 0) {
14675
+ },
14676
+ });
14677
+ const easSyncActor = xstate.createActor(easSyncMachine);
14678
+ let easSyncActorStarted = false;
14679
+ function startEasSyncActor() {
14680
+ if (easSyncActorStarted) {
13607
14681
  return;
13608
14682
  }
13609
- const appDb = BaseDb.getAppDb();
13610
- const { schemaStringToModelRecord } = await getModelSchemas();
13611
- const modelSchemas = await getModelSchemasFromEas();
13612
- const schemaUids = [];
13613
- for (const modelSchema of modelSchemas) {
13614
- const foundModel = schemaStringToModelRecord.get(modelSchema.schema);
13615
- if (!foundModel) {
13616
- // Skip schemas that don't have a corresponding model in the user's config
13617
- // This can happen with "bytes32 image" if there's no Image model defined
13618
- console.warn(`[item/events] [syncDbWithEas] Model not found for schema ${modelSchema.schema}, skipping`);
13619
- continue;
13620
- }
13621
- try {
13622
- await appDb
13623
- .insert(modelUids)
13624
- .values({
13625
- modelId: foundModel.id,
13626
- uid: modelSchema.id,
13627
- })
13628
- .onConflictDoNothing();
13629
- }
13630
- catch (err) {
13631
- // Model may have been deleted by test teardown or another process; skip to avoid unhandled rejection
13632
- const e = err;
13633
- const code = e?.code ?? e?.rawCode ?? e?.cause?.code ?? e?.cause?.rawCode;
13634
- if (code === 'SQLITE_CONSTRAINT_FOREIGNKEY' || code === 787) {
13635
- continue;
13636
- }
13637
- throw err;
13638
- }
13639
- schemaUids.push(modelSchema.id);
13640
- }
13641
- // If no schemas were found, skip the rest of the sync process
13642
- // This can happen when models exist but don't have schemas registered in EAS yet
13643
- if (schemaUids.length === 0) {
13644
- return;
14683
+ easSyncActorStarted = true;
14684
+ easSyncActor.start();
14685
+ }
14686
+ function newCorrelationId() {
14687
+ const c = globalThis.crypto;
14688
+ if (c?.randomUUID) {
14689
+ return c.randomUUID();
13645
14690
  }
13646
- const itemSeeds = await getSeedsFromSchemaUids({
13647
- schemaUids,
13648
- addresses,
13649
- excludeRevoked: false,
13650
- });
13651
- const { seedUids } = await saveEasSeedsToDb({
13652
- itemSeeds,
13653
- });
13654
- const itemVersions = await getItemVersionsFromEas({
13655
- seedUids,
13656
- excludeRevoked: false,
14691
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
14692
+ }
14693
+ function requestEasSyncFromEventBus() {
14694
+ startEasSyncActor();
14695
+ easSyncActor.send({
14696
+ type: 'REQUEST',
14697
+ correlationId: newCorrelationId(),
14698
+ source: 'event_bus',
13657
14699
  });
13658
- const { versionUids } = await saveEasVersionsToDb({
13659
- itemVersions,
14700
+ }
14701
+ function requestEasSyncFromAddressChange(addresses) {
14702
+ startEasSyncActor();
14703
+ easSyncActor.send({
14704
+ type: 'REQUEST',
14705
+ correlationId: newCorrelationId(),
14706
+ options: { addresses },
14707
+ source: 'address_change',
13660
14708
  });
13661
- const rawProperties = await getItemPropertiesFromEas({
13662
- versionUids,
13663
- excludeRevoked: false,
14709
+ }
14710
+ function requestEasSyncFromModelsInit() {
14711
+ startEasSyncActor();
14712
+ easSyncActor.send({
14713
+ type: 'REQUEST',
14714
+ correlationId: newCorrelationId(),
14715
+ source: 'models_init',
13664
14716
  });
13665
- const itemProperties = pickLatestPropertyAttestationsByRefAndSchema(rawProperties);
13666
- await saveEasPropertiesToDb({
13667
- itemProperties,
13668
- itemSeeds,
14717
+ }
14718
+ function sendEasSyncClientRequest(correlationId, options) {
14719
+ startEasSyncActor();
14720
+ easSyncActor.send({
14721
+ type: 'REQUEST',
14722
+ correlationId,
14723
+ options,
14724
+ source: 'client_api',
13669
14725
  });
13670
- await getRelatedSeedsAndVersions();
13671
- };
13672
- const syncDbWithEasHandler = lodashEs.throttle(async (_) => {
13673
- await runSyncFromEas();
13674
- }, 30000, {
13675
- leading: true,
13676
- trailing: false,
13677
- });
14726
+ }
13678
14727
 
13679
- const isNode = () => {
13680
- return (typeof process !== 'undefined' &&
13681
- process.versions != null &&
13682
- process.versions.node != null);
13683
- };
13684
- const isBrowser = () => {
13685
- return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
13686
- };
13687
- const isElectron = () => {
13688
- return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
13689
- };
14728
+ var easSyncManager = /*#__PURE__*/Object.freeze({
14729
+ __proto__: null,
14730
+ easSyncActor: easSyncActor,
14731
+ easSyncMachine: easSyncMachine,
14732
+ requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
14733
+ requestEasSyncFromEventBus: requestEasSyncFromEventBus,
14734
+ requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
14735
+ sendEasSyncClientRequest: sendEasSyncClientRequest,
14736
+ startEasSyncActor: startEasSyncActor
14737
+ });
13690
14738
 
13691
14739
  /**
13692
14740
  * @deprecated Use BaseArweaveClient.setHost() instead.
13693
14741
  * This function is kept for backward compatibility but will be removed in a future version.
13694
14742
  */
13695
14743
  const setArweaveDomain = (newDomain) => {
13696
- BaseArweaveClient.setHost(newDomain);
14744
+ BaseArweaveClient.setPreferredReadGateway(newDomain);
13697
14745
  };
13698
14746
 
13699
- const logger$h = debug('seedSdk:services:events');
14747
+ const logger$g = debug('seedSdk:services:events');
13700
14748
  const handleServiceSaveState = (event) => {
13701
14749
  const { state, serviceId } = event;
13702
- logger$h(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
14750
+ logger$g(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
13703
14751
  // TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
13704
14752
  // localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
13705
14753
  };
@@ -13708,7 +14756,8 @@ const setupServicesEventHandlers = () => {
13708
14756
  };
13709
14757
 
13710
14758
  const setupAllItemsEventHandlers = () => {
13711
- eventEmitter.addListener('syncDbWithEas', syncDbWithEasHandler);
14759
+ startEasSyncActor();
14760
+ eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
13712
14761
  };
13713
14762
  // Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
13714
14763
 
@@ -13742,9 +14791,9 @@ class BasePathResolver {
13742
14791
  }
13743
14792
  }
13744
14793
 
13745
- const logger$g = debug('seedSdk:ClientManager:initialize');
14794
+ const logger$f = debug('seedSdk:ClientManager:initialize');
13746
14795
  const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, event } }) => {
13747
- logger$g('initialize from ClientManager');
14796
+ logger$f('initialize from ClientManager');
13748
14797
  const { isInitialized } = context;
13749
14798
  if (!event || !('options' in event)) {
13750
14799
  throw new Error('Initialize event must include options');
@@ -13867,11 +14916,14 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
13867
14916
  dbConfig,
13868
14917
  schemaFile,
13869
14918
  schema,
13870
- syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? false,
14919
+ syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
13871
14920
  } });
13872
14921
  if (arweaveDomain) {
13873
14922
  setArweaveDomain(arweaveDomain);
13874
14923
  }
14924
+ void ensureReadGatewaySelected().catch(() => {
14925
+ /* non-blocking warm-up for read gateway probe */
14926
+ });
13875
14927
  // Models are now Model instances, no registration needed
13876
14928
  // They should be created via Model.create() and are accessible via Model static methods
13877
14929
  setupAllItemsEventHandlers();
@@ -13907,15 +14959,15 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
13907
14959
  };
13908
14960
  });
13909
14961
 
13910
- const logger$f = debug('seedSdk:client:writeToDb');
13911
- const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } }) => {
14962
+ const logger$e = debug('seedSdk:client:writeToDb');
14963
+ const saveAppState = xstate.fromCallback(({ sendBack, input: { key, value } }) => {
13912
14964
  const _saveAppState = async () => {
13913
14965
  try {
13914
14966
  const appDb = BaseDb.getAppDb();
13915
14967
  if (!appDb) {
13916
14968
  // In test environments, continue anyway
13917
14969
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13918
- logger$f('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
14970
+ logger$e('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
13919
14971
  return;
13920
14972
  }
13921
14973
  throw new Error('App DB not found');
@@ -13931,13 +14983,13 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
13931
14983
  value: JSON.stringify(value),
13932
14984
  },
13933
14985
  });
13934
- logger$f('result', result);
14986
+ logger$e('result', result);
13935
14987
  }
13936
14988
  catch (error) {
13937
- logger$f('[client/actors] [saveAppState] Error saving app state:', error);
14989
+ logger$e('[client/actors] [saveAppState] Error saving app state:', error);
13938
14990
  // In test environments, continue anyway
13939
14991
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13940
- logger$f('[client/actors] [saveAppState] Continuing despite error in test environment');
14992
+ logger$e('[client/actors] [saveAppState] Continuing despite error in test environment');
13941
14993
  return;
13942
14994
  }
13943
14995
  throw error;
@@ -13952,10 +15004,10 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
13952
15004
  });
13953
15005
  })
13954
15006
  .catch((error) => {
13955
- logger$f('[client/actors] [saveAppState] Error in promise chain:', error);
15007
+ logger$e('[client/actors] [saveAppState] Error in promise chain:', error);
13956
15008
  // In test environments, still send success to allow state machine to progress
13957
15009
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13958
- logger$f('[client/actors] [saveAppState] Sending success despite error in test environment');
15010
+ logger$e('[client/actors] [saveAppState] Sending success despite error in test environment');
13959
15011
  sendBack({
13960
15012
  type: 'saveAppStateSuccess',
13961
15013
  key,
@@ -13968,222 +15020,6 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
13968
15020
  });
13969
15021
  });
13970
15022
 
13971
- const GET_FILES_METADATA = graphql(/* GraphQL */ `
13972
- query GetFilesMetadata($where: AttestationWhereInput!) {
13973
- filesMetadata: attestations(
13974
- where: $where
13975
- orderBy: [{ timeCreated: desc }]
13976
- ) {
13977
- ...attestationFields
13978
- }
13979
- }
13980
- `);
13981
-
13982
- const getMetadata = async (props) => {
13983
- const appDb = BaseDb.getAppDb();
13984
- let storageTransactionId;
13985
- if (props) {
13986
- storageTransactionId = props.storageTransactionId;
13987
- }
13988
- const whereClauses = [];
13989
- if (storageTransactionId) {
13990
- whereClauses.push(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'));
13991
- whereClauses.push(drizzleOrm.eq(metadata$1.propertyValue, storageTransactionId));
13992
- }
13993
- const metadataRows = await appDb
13994
- .select()
13995
- .from(metadata$1)
13996
- .where(drizzleOrm.and(...whereClauses));
13997
- if (!metadataRows || metadataRows.length === 0) {
13998
- return;
13999
- }
14000
- return metadataRows[0];
14001
- };
14002
-
14003
- const saveMetadata = async (metadataRecord, metadataValues) => {
14004
- if (!metadataRecord.localId) {
14005
- return;
14006
- }
14007
- const appDb = BaseDb.getAppDb();
14008
- await appDb
14009
- .update(metadata$1)
14010
- .set({
14011
- ...metadataValues,
14012
- updatedAt: Date.now(),
14013
- })
14014
- .where(drizzleOrm.eq(metadata$1.localId, metadataRecord.localId));
14015
- };
14016
-
14017
- const saveAppState = async (key, value) => {
14018
- const appDb = BaseDb.getAppDb();
14019
- await appDb
14020
- .insert(appState)
14021
- .values({
14022
- key,
14023
- value,
14024
- })
14025
- .onConflictDoUpdate({
14026
- target: appState.key,
14027
- set: {
14028
- value,
14029
- },
14030
- });
14031
- };
14032
-
14033
- const logger$e = debug('seedSdk:files:download');
14034
- // syncDbFiles helper - internal service removed, functionality moved here
14035
- const syncDbFiles = async (endpoints) => {
14036
- // TODO: Implement syncDbFiles functionality if needed
14037
- // This was previously in @/services/internal/helpers
14038
- logger$e('[download] syncDbFiles called but not yet implemented');
14039
- return Promise.resolve();
14040
- };
14041
- const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
14042
- if (!isBrowser()) {
14043
- return;
14044
- }
14045
- await syncDbFiles();
14046
- eventEmitter.emit('fs.downloadAll.success', { eventId });
14047
- eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
14048
- };
14049
- const downloadAllFilesBinaryRequestHandler = async () => {
14050
- let addresses;
14051
- if (BaseDb.isAppDbReady()) {
14052
- addresses = await getAllAddressesFromDb();
14053
- }
14054
- if (!BaseDb.isAppDbReady()) {
14055
- // Wait for ClientManager to be ready (DB_INIT state or later)
14056
- const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
14057
- const { getClient } = clientManagerMod;
14058
- const clientManager = getClient();
14059
- const clientService = clientManager.getService();
14060
- await xstate.waitFor(clientService, (snapshot) => {
14061
- const state = snapshot.value;
14062
- return state === 'dbInit' ||
14063
- state === 'saveConfig' ||
14064
- state === 'processSchemaFiles' ||
14065
- state === 'addModelsToStore' ||
14066
- state === 'addModelsToDb' ||
14067
- state === 'idle';
14068
- }, { timeout: 30000 });
14069
- addresses = await getAllAddressesFromDb();
14070
- }
14071
- if (!addresses || addresses.length === 0) {
14072
- return;
14073
- }
14074
- const queryClient = BaseQueryClient.getQueryClient();
14075
- const easClient = BaseEasClient.getEasClient();
14076
- const { filesMetadata } = await queryClient.fetchQuery({
14077
- queryKey: ['getFilesMetadata', ...addresses],
14078
- queryFn: async () => easClient.request(GET_FILES_METADATA, {
14079
- where: {
14080
- attester: {
14081
- in: addresses,
14082
- },
14083
- schema: {
14084
- is: {
14085
- id: {
14086
- equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
14087
- },
14088
- },
14089
- },
14090
- },
14091
- }),
14092
- });
14093
- const filesRoot = BaseFileManager.getWorkingDir();
14094
- await BaseFileManager.createDirIfNotExists(filesRoot);
14095
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
14096
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
14097
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
14098
- const appDb = BaseDb.getAppDb();
14099
- if (!appDb) {
14100
- console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available');
14101
- return [];
14102
- }
14103
- const excludedTransactionsQuery = await appDb
14104
- .select()
14105
- .from(appState)
14106
- .where(drizzleOrm.eq(appState.key, 'excludedTransactions'));
14107
- let excludedTransactions = new Set();
14108
- if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
14109
- const valueString = excludedTransactionsQuery[0].value;
14110
- if (valueString) {
14111
- const excludedTransactionsArray = JSON.parse(valueString);
14112
- excludedTransactions = new Set(excludedTransactionsArray);
14113
- }
14114
- }
14115
- const transactionIds = [];
14116
- for (const fileMetadata of filesMetadata) {
14117
- // Validate and parse decodedDataJson
14118
- if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
14119
- console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
14120
- continue;
14121
- }
14122
- let json;
14123
- try {
14124
- json = JSON.parse(fileMetadata.decodedDataJson);
14125
- }
14126
- catch (error) {
14127
- console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
14128
- continue;
14129
- }
14130
- if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
14131
- console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
14132
- continue;
14133
- }
14134
- const transactionId = json[0].value.value;
14135
- if (excludedTransactions.has(transactionId)) {
14136
- continue;
14137
- }
14138
- transactionIds.push(transactionId);
14139
- }
14140
- const transactionIdsToDownload = [];
14141
- for (const transactionId of transactionIds) {
14142
- try {
14143
- // Use BaseArweaveClient for transaction status check
14144
- const status = await BaseArweaveClient.getTransactionStatus(transactionId);
14145
- if (status.status !== 200) {
14146
- logger$e(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`);
14147
- excludedTransactions.add(transactionId);
14148
- await saveAppState('excludedTransactions', JSON.stringify(Array.from(excludedTransactions)));
14149
- continue;
14150
- }
14151
- // Use BaseArweaveClient for getting transaction tags
14152
- const tags = await queryClient.fetchQuery({
14153
- queryKey: ['getTransactionTags', transactionId],
14154
- queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
14155
- });
14156
- if (tags && tags.length > 0) {
14157
- for (const { name, value } of tags) {
14158
- if (name === 'Content-SHA-256') {
14159
- const metadataRecord = await getMetadata({
14160
- storageTransactionId: transactionId,
14161
- });
14162
- if (metadataRecord) {
14163
- await saveMetadata(metadataRecord, {
14164
- contentHash: value,
14165
- });
14166
- }
14167
- }
14168
- }
14169
- }
14170
- transactionIdsToDownload.push(transactionId);
14171
- }
14172
- catch (error) {
14173
- logger$e(error);
14174
- }
14175
- }
14176
- await BaseFileManager.downloadAllFiles({
14177
- transactionIds: transactionIdsToDownload,
14178
- arweaveHost: BaseArweaveClient.getHost(),
14179
- excludedTransactions,
14180
- });
14181
- await BaseFileManager.resizeAllImages({
14182
- width: 480,
14183
- height: 480,
14184
- });
14185
- };
14186
-
14187
15023
  let isInitialized = false;
14188
15024
  const fsInitHandler = async () => {
14189
15025
  if (isInitialized) {
@@ -14349,7 +15185,7 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
14349
15185
  }
14350
15186
  const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
14351
15187
  // Fetch schemas from EAS in background - do not block init. EAS can be slow (10s+);
14352
- // modelUids will be populated async and syncDbWithEas will run when done.
15188
+ // modelUids will be populated async and EAS sync orchestrator runs when done.
14353
15189
  const fetchEasAndPopulateModelUids = async () => {
14354
15190
  try {
14355
15191
  const queryClient = BaseQueryClient.getQueryClient();
@@ -14382,7 +15218,8 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
14382
15218
  }
14383
15219
  }
14384
15220
  }
14385
- eventEmitter.emit('syncDbWithEas');
15221
+ const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
15222
+ requestEasSyncFromModelsInit();
14386
15223
  }
14387
15224
  else {
14388
15225
  logger$b('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
@@ -16724,16 +17561,19 @@ function addressesFromPersistedAddressValue(value) {
16724
17561
  return out;
16725
17562
  }
16726
17563
  function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
17564
+ const merged = addressesFromPersistedAddressValue(event.value);
16727
17565
  if (!context.syncFromEasOnAddressChange)
16728
17566
  return;
16729
17567
  if (event.key !== "addresses")
16730
17568
  return;
16731
- const merged = addressesFromPersistedAddressValue(event.value);
16732
17569
  if (merged.length === 0)
16733
17570
  return;
16734
- void runSyncFromEas({ addresses: merged }).catch((err) => {
16735
- logSyncAfterAddressSave("runSyncFromEas after address save failed", err);
16736
- });
17571
+ try {
17572
+ requestEasSyncFromAddressChange(merged);
17573
+ }
17574
+ catch (err) {
17575
+ logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
17576
+ }
16737
17577
  }
16738
17578
  function emitAddressesPersistedIfAddressesKey(event) {
16739
17579
  if (event.key !== "addresses")
@@ -16751,7 +17591,7 @@ const clientManagerMachine = xstate.setup({
16751
17591
  fileSystemInit,
16752
17592
  dbInit,
16753
17593
  saveConfig,
16754
- saveAppState: saveAppState$1,
17594
+ saveAppState,
16755
17595
  addModelsToStore,
16756
17596
  addModelsToDb,
16757
17597
  processSchemaFiles,
@@ -17075,7 +17915,16 @@ const clientInstance = {
17075
17915
  */
17076
17916
  syncFromEas: async (options) => {
17077
17917
  ensureInitialized();
17078
- await runSyncFromEas(options);
17918
+ startEasSyncActor();
17919
+ const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
17920
+ ? globalThis.crypto.randomUUID()
17921
+ : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
17922
+ sendEasSyncClientRequest(correlationId, options);
17923
+ await xstate.waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
17924
+ const snap = easSyncActor.getSnapshot();
17925
+ if (snap.context.lastFinishedStatus === 'failed') {
17926
+ throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
17927
+ }
17079
17928
  },
17080
17929
  addModel: async (modelDef) => {
17081
17930
  const db = await BaseDb.getAppDb();
@@ -17285,7 +18134,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
17285
18134
  // Lazy import cache for ModelProperty to avoid circular dependency
17286
18135
  // Eagerly start loading to minimize delay on first access
17287
18136
  let ModelPropertyClass = null;
17288
- const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); })
18137
+ const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); })
17289
18138
  .then(module => {
17290
18139
  ModelPropertyClass = module.ModelProperty;
17291
18140
  return ModelPropertyClass;
@@ -17302,7 +18151,7 @@ function getModelProperty() {
17302
18151
  }
17303
18152
  // Lazy import cache for Schema to avoid circular dependency
17304
18153
  let SchemaClass = null;
17305
- const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); })
18154
+ const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); })
17306
18155
  .then(module => {
17307
18156
  SchemaClass = module.Schema;
17308
18157
  return SchemaClass;
@@ -19256,7 +20105,7 @@ class Db extends BaseDb {
19256
20105
  // You can inspect what will happen before applying
19257
20106
  await apply();
19258
20107
  this.db = db;
19259
- const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-DhAXAuSf.js'); });
20108
+ const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-D1nLJAhB.js'); });
19260
20109
  await backfillMetadataPropertyIds();
19261
20110
  return this.db;
19262
20111
  }
@@ -19903,7 +20752,7 @@ const getTsImport = async (filePath) => {
19903
20752
 
19904
20753
  // Get the directory of this file to resolve relative paths
19905
20754
  // @ts-ignore - rollup plugin-typescript doesn't recognize import.meta with module: "preserve"
19906
- const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cjs/index-D1qR8xnb.js', document.baseURI).href)));
20755
+ const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cjs/index-C6rrqy3z.js', document.baseURI).href)));
19907
20756
  path.dirname(__filename$1);
19908
20757
  const commandExists = (command) => {
19909
20758
  try {
@@ -20151,6 +21000,7 @@ QueryClient.getQueryClient = () => {
20151
21000
  reject(new Error('Not implemented'));
20152
21001
  });
20153
21002
  },
21003
+ removeQueries: async () => { },
20154
21004
  };
20155
21005
  };
20156
21006
  BaseQueryClient.setPlatformClass(QueryClient);
@@ -20365,23 +21215,30 @@ immer.enableMapSet();
20365
21215
 
20366
21216
  exports.BaseArweaveClient = BaseArweaveClient;
20367
21217
  exports.BaseDb = BaseDb;
21218
+ exports.BaseEasClient = BaseEasClient;
20368
21219
  exports.BaseFileManager = BaseFileManager;
20369
21220
  exports.BaseFileManager$1 = BaseFileManager$1;
20370
21221
  exports.BasePathResolver = BasePathResolver;
21222
+ exports.BaseQueryClient = BaseQueryClient;
20371
21223
  exports.Boolean = Boolean$1;
20372
21224
  exports.ClientManager = ClientManager;
20373
21225
  exports.ConflictError = ConflictError;
20374
21226
  exports.DEFAULT_TEXT_MAX_LENGTH = DEFAULT_TEXT_MAX_LENGTH;
20375
21227
  exports.Date = Date$1;
20376
21228
  exports.Db = Db;
21229
+ exports.EAS_SEED_DATA_SYNCED_TO_DB_EVENT = EAS_SEED_DATA_SYNCED_TO_DB_EVENT;
20377
21230
  exports.File = File$1;
20378
21231
  exports.FileManager = FileManager;
21232
+ exports.GET_PROPERTIES = GET_PROPERTIES;
21233
+ exports.GET_SEEDS = GET_SEEDS;
21234
+ exports.GET_VERSIONS = GET_VERSIONS;
20379
21235
  exports.Html = Html;
20380
21236
  exports.INIT_SCRIPT_SUCCESS_MESSAGE = INIT_SCRIPT_SUCCESS_MESSAGE;
20381
21237
  exports.INTERNAL_DATA_TYPES = INTERNAL_DATA_TYPES;
20382
21238
  exports.INTERNAL_PROPERTY_NAMES = INTERNAL_PROPERTY_NAMES;
20383
21239
  exports.Image = Image;
20384
21240
  exports.Item = Item;
21241
+ exports.Item$1 = Item$1;
20385
21242
  exports.ItemProperty = ItemProperty;
20386
21243
  exports.Json = Json;
20387
21244
  exports.List = List;
@@ -20422,12 +21279,14 @@ exports.createReactiveProxy = createReactiveProxy;
20422
21279
  exports.db = db;
20423
21280
  exports.defaultAttestationData = defaultAttestationData;
20424
21281
  exports.eas = eas;
21282
+ exports.escapeSqliteString = escapeSqliteString;
20425
21283
  exports.eventEmitter = eventEmitter;
20426
21284
  exports.findEntity = findEntity;
20427
21285
  exports.findSeedBinary = findSeedBinary;
20428
21286
  exports.forceRemoveFromCaches = forceRemoveFromCaches;
20429
21287
  exports.generateId = generateId;
20430
21288
  exports.generateModelCode = generateModelCode;
21289
+ exports.getAllAddressesFromDb = getAllAddressesFromDb;
20431
21290
  exports.getClient = getClient;
20432
21291
  exports.getContentHash = getContentHash;
20433
21292
  exports.getCorrectId = getCorrectId;
@@ -20436,14 +21295,18 @@ exports.getEasSchemaUidForModel = getEasSchemaUidForModel;
20436
21295
  exports.getEasSchemaUidForSchemaDefinition = getEasSchemaUidForSchemaDefinition;
20437
21296
  exports.getGetAdditionalSyncAddresses = getGetAdditionalSyncAddresses;
20438
21297
  exports.getItemData = getItemData;
21298
+ exports.getItemPropertiesFromEas = getItemPropertiesFromEas;
21299
+ exports.getItemVersionsFromEas = getItemVersionsFromEas;
20439
21300
  exports.getLatestPublishedVersionRow = getLatestPublishedVersionRow;
20440
21301
  exports.getLatestSchemaVersion = getLatestSchemaVersion;
20441
21302
  exports.getModelId = getModelId;
20442
21303
  exports.getModelIdByFileId = getModelIdByFileId;
21304
+ exports.getModelSchemasFromEas = getModelSchemasFromEas;
20443
21305
  exports.getOwnedAddressesFromDb = getOwnedAddressesFromDb;
20444
21306
  exports.getPropertyData = getPropertyData$1;
20445
21307
  exports.getPropertyIdForModelAndName = getPropertyIdForModelAndName;
20446
21308
  exports.getRefValueType = getRefValueType;
21309
+ exports.getSeedsFromSchemaUids = getSeedsFromSchemaUids;
20447
21310
  exports.getTsImport = getTsImport;
20448
21311
  exports.htmlEmbeddedImageCoPublish = htmlEmbeddedImageCoPublish;
20449
21312
  exports.importJsonSchema = importJsonSchema;
@@ -20460,8 +21323,10 @@ exports.modelUids = modelUids;
20460
21323
  exports.models = models$1;
20461
21324
  exports.normalizeDataType = normalizeDataType;
20462
21325
  exports.normalizeRelationPropertyValue = normalizeRelationPropertyValue;
21326
+ exports.parseEasRelationPropertyName = parseEasRelationPropertyName;
20463
21327
  exports.parseListPropertyValueFromStorage = parseListPropertyValueFromStorage;
20464
21328
  exports.parseMarkdownFrontmatter = parseMarkdownFrontmatter;
21329
+ exports.pickLatestPropertyAttestationsByRefAndSchema = pickLatestPropertyAttestationsByRefAndSchema;
20465
21330
  exports.processSeedConfig = processSeedConfig;
20466
21331
  exports.properties = properties;
20467
21332
  exports.readJsonImportFile = readJsonImportFile;
@@ -20470,10 +21335,12 @@ exports.resolveStorageNameToSchemaName = resolveStorageNameToSchemaName;
20470
21335
  exports.runDestroyLifecycle = runDestroyLifecycle;
20471
21336
  exports.runSeedInit = runSeedInit;
20472
21337
  exports.saveModelsFromMarkdown = saveModelsFromMarkdown;
21338
+ exports.scheduleBulkFilesDownloadFromEasSync = scheduleBulkFilesDownloadFromEasSync;
20473
21339
  exports.schema = schema$1;
20474
21340
  exports.schema$1 = schema;
20475
21341
  exports.schemas = schemas;
20476
21342
  exports.seeds = seeds;
21343
+ exports.setSchemaUidForSchemaDefinition = setSchemaUidForSchemaDefinition;
20477
21344
  exports.setupEntityLiveQuery = setupEntityLiveQuery;
20478
21345
  exports.syncSchemaFromSource = syncSchemaFromSource;
20479
21346
  exports.toSnakeCase = toSnakeCase;
@@ -20483,4 +21350,4 @@ exports.versions = versions;
20483
21350
  exports.waitForEntityIdle = waitForEntityIdle;
20484
21351
  exports.withSeed = withSeed;
20485
21352
  exports.writeProcessMachine = writeProcessMachine;
20486
- //# sourceMappingURL=index-D1qR8xnb.js.map
21353
+ //# sourceMappingURL=index-C6rrqy3z.js.map