@seedprotocol/sdk 0.4.21 → 0.4.23

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 (186) hide show
  1. package/dist/{ArweaveClient-DxpJnJXU.js → ArweaveClient-DoBABTLW.js} +3 -4
  2. package/dist/{ArweaveClient-DxpJnJXU.js.map → ArweaveClient-DoBABTLW.js.map} +1 -1
  3. package/dist/{ArweaveClient-Cz9ZLiEV.js → ArweaveClient-KF_T3NSr.js} +3 -4
  4. package/dist/{ArweaveClient-Cz9ZLiEV.js.map → ArweaveClient-KF_T3NSr.js.map} +1 -1
  5. package/dist/{Db-DkTBncAM.js → Db-Cg7Q5gIc.js} +4 -5
  6. package/dist/{Db-DkTBncAM.js.map → Db-Cg7Q5gIc.js.map} +1 -1
  7. package/dist/{Db-CXwQVLZv.js → Db-DA_e7Jcc.js} +107 -7
  8. package/dist/Db-DA_e7Jcc.js.map +1 -0
  9. package/dist/{EasClient-DjpbHjU9.js → EasClient-B4VivHxM.js} +2 -3
  10. package/dist/{EasClient-JYkmHxu1.js.map → EasClient-B4VivHxM.js.map} +1 -1
  11. package/dist/{EasClient-JYkmHxu1.js → EasClient-CVPHYGNP.js} +2 -3
  12. package/dist/{EasClient-DjpbHjU9.js.map → EasClient-CVPHYGNP.js.map} +1 -1
  13. package/dist/{FileManager-DHnyb040.js → FileManager-BOxbzROS.js} +18 -3
  14. package/dist/FileManager-BOxbzROS.js.map +1 -0
  15. package/dist/{FileManager-CKyoLrBP.js → FileManager-Ba5BCbCL.js} +2 -3
  16. package/dist/{FileManager-CKyoLrBP.js.map → FileManager-Ba5BCbCL.js.map} +1 -1
  17. package/dist/{ModelProperty-DWtv9fQr.js → ModelProperty-D6JLRqQW.js} +24 -25
  18. package/dist/ModelProperty-D6JLRqQW.js.map +1 -0
  19. package/dist/{PathResolver-Ce4K9acQ.js → PathResolver-D7WqjJCo.js} +2 -3
  20. package/dist/{PathResolver-Ce4K9acQ.js.map → PathResolver-D7WqjJCo.js.map} +1 -1
  21. package/dist/{PathResolver-pmw--Ea2.js → PathResolver-DHTAlCzo.js} +2 -3
  22. package/dist/{PathResolver-pmw--Ea2.js.map → PathResolver-DHTAlCzo.js.map} +1 -1
  23. package/dist/{QueryClient-unspcsWa.js → QueryClient-B12y2daD.js} +7 -4
  24. package/dist/QueryClient-B12y2daD.js.map +1 -0
  25. package/dist/{QueryClient-OUjfvY3g.js → QueryClient-BCxuWg7f.js} +3 -3
  26. package/dist/QueryClient-BCxuWg7f.js.map +1 -0
  27. package/dist/{Schema-CqqcEexA.js → Schema-B5_B8nM5.js} +38 -38
  28. package/dist/{Schema-CqqcEexA.js.map → Schema-B5_B8nM5.js.map} +1 -1
  29. package/dist/{SchemaValidationService-Cb-b4kpD.js → SchemaValidationService-DXYRdSYa.js} +2 -3
  30. package/dist/{SchemaValidationService-Cb-b4kpD.js.map → SchemaValidationService-DXYRdSYa.js.map} +1 -1
  31. package/dist/{backfillMetadataPropertyIds-CRyRez3h.js → backfillMetadataPropertyIds-BWEhAJPS.js} +2 -3
  32. package/dist/{backfillMetadataPropertyIds-CRyRez3h.js.map → backfillMetadataPropertyIds-BWEhAJPS.js.map} +1 -1
  33. package/dist/cjs/{ModelProperty-sNx_ZQZX.js → ModelProperty-Ov1_YL9l.js} +17 -18
  34. package/dist/cjs/{ModelProperty-sNx_ZQZX.js.map → ModelProperty-Ov1_YL9l.js.map} +1 -1
  35. package/dist/cjs/{Schema-B4RRA-0g.js → Schema-CeG5iRX_.js} +20 -21
  36. package/dist/cjs/{Schema-B4RRA-0g.js.map → Schema-CeG5iRX_.js.map} +1 -1
  37. package/dist/cjs/{SchemaValidationService-DCflhpcI.js → SchemaValidationService-C8mdrNnp.js} +2 -3
  38. package/dist/cjs/{SchemaValidationService-DCflhpcI.js.map → SchemaValidationService-C8mdrNnp.js.map} +1 -1
  39. package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js → backfillMetadataPropertyIds-LDYghZxU.js} +2 -3
  40. package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js.map → backfillMetadataPropertyIds-LDYghZxU.js.map} +1 -1
  41. package/dist/cjs/{getItem-lyM2x5pT.js → getItem-CW3BFytl.js} +2 -3
  42. package/dist/cjs/{getItem-lyM2x5pT.js.map → getItem-CW3BFytl.js.map} +1 -1
  43. package/dist/cjs/{getPublishPayload-DP2fm4q8.js → getPublishPayload-C0hWIYCX.js} +11 -12
  44. package/dist/cjs/{getPublishPayload-DP2fm4q8.js.map → getPublishPayload-C0hWIYCX.js.map} +1 -1
  45. package/dist/cjs/{getPublishUploads-DdVy-5fK.js → getPublishUploads-CMpPR2JJ.js} +39 -7
  46. package/dist/cjs/getPublishUploads-CMpPR2JJ.js.map +1 -0
  47. package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js → getSegmentedItemProperties-B4ao_B1Q.js} +3 -3
  48. package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js.map → getSegmentedItemProperties-B4ao_B1Q.js.map} +1 -1
  49. package/dist/cjs/{index-DTkoTvcq.js → index-Dty7eE10.js} +3 -4
  50. package/dist/cjs/index-Dty7eE10.js.map +1 -0
  51. package/dist/cjs/{index-D1qR8xnb.js → index-Far6-WGM.js} +2034 -1118
  52. package/dist/cjs/index-Far6-WGM.js.map +1 -0
  53. package/dist/cjs/{ownership-DanM_n8E.js → ownership-TCXiKRY_.js} +2 -3
  54. package/dist/cjs/{ownership-DanM_n8E.js.map → ownership-TCXiKRY_.js.map} +1 -1
  55. package/dist/cjs/{property-BQokoaRe.js → property-BT7i8Tl-.js} +4 -5
  56. package/dist/cjs/{property-BQokoaRe.js.map → property-BT7i8Tl-.js.map} +1 -1
  57. package/dist/cjs/syncDbWithEas-DUi78csI.js +609 -0
  58. package/dist/cjs/syncDbWithEas-DUi78csI.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-D5_bPYyC.js} +2 -3
  63. package/dist/{getItem-VI3QqdZH.js.map → getItem-D5_bPYyC.js.map} +1 -1
  64. package/dist/{getPublishPayload-DpYwi-rd.js → getPublishPayload-DEdHgrgC.js} +14 -15
  65. package/dist/getPublishPayload-DEdHgrgC.js.map +1 -0
  66. package/dist/{getPublishUploads-DS2dQ4Ho.js → getPublishUploads-CH72lAID.js} +39 -7
  67. package/dist/getPublishUploads-CH72lAID.js.map +1 -0
  68. package/dist/{getSegmentedItemProperties-Bz5B4DSA.js → getSegmentedItemProperties-Cp92QUHQ.js} +3 -3
  69. package/dist/{getSegmentedItemProperties-Bz5B4DSA.js.map → getSegmentedItemProperties-Cp92QUHQ.js.map} +1 -1
  70. package/dist/{index-BrD_NNaX.js → index-18lln0cM.js} +2045 -1130
  71. package/dist/index-18lln0cM.js.map +1 -0
  72. package/dist/{index-DdzhrbkF.js → index-Bp0ChnQr.js} +3 -2
  73. package/dist/index-Bp0ChnQr.js.map +1 -0
  74. package/dist/{index-Cqf_DxkJ.js → index-DB3nZ0lK.js} +3 -4
  75. package/dist/index-DB3nZ0lK.js.map +1 -0
  76. package/dist/main.cjs +1 -2
  77. package/dist/main.cjs.map +1 -1
  78. package/dist/main.js +16 -42
  79. package/dist/main.js.map +1 -1
  80. package/dist/node.js +10 -11
  81. package/dist/node.js.map +1 -1
  82. package/dist/{ownership-BK6suksO.js → ownership-D-KsIkxM.js} +2 -3
  83. package/dist/{ownership-BK6suksO.js.map → ownership-D-KsIkxM.js.map} +1 -1
  84. package/dist/{property-C63Ddzap.js → property-DViA9nga.js} +6 -7
  85. package/dist/property-DViA9nga.js.map +1 -0
  86. package/dist/{queries-BGuWjEqt.js → queries-ANFHy2e0.js} +2 -2
  87. package/dist/{queries-BGuWjEqt.js.map → queries-ANFHy2e0.js.map} +1 -1
  88. package/dist/seedSchema/EasSyncProcessSchema.ts +17 -0
  89. package/dist/seedSchema/index.ts +1 -0
  90. package/dist/src/Item/Item.d.ts +18 -0
  91. package/dist/src/Item/Item.d.ts.map +1 -1
  92. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  93. package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
  94. package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +1 -1
  95. package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts.map +1 -1
  96. package/dist/src/ItemProperty/service/propertyMachine.d.ts +4 -1
  97. package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
  98. package/dist/src/Model/service/modelMachine.d.ts +20 -20
  99. package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +2 -2
  100. package/dist/src/Schema/service/addModelsMachine.d.ts +1 -1
  101. package/dist/src/Schema/service/schemaMachine.d.ts +55 -55
  102. package/dist/src/browser/db/drizzleFiles.d.ts +3 -2
  103. package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
  104. package/dist/src/browser/helpers/QueryClient.d.ts.map +1 -1
  105. package/dist/src/client/ClientManager.d.ts.map +1 -1
  106. package/dist/src/client/actors/addModelsToDb.d.ts.map +1 -1
  107. package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
  108. package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
  109. package/dist/src/client/constants.d.ts +1 -0
  110. package/dist/src/client/constants.d.ts.map +1 -1
  111. package/dist/src/db/read/getPublishPendingDiff.d.ts.map +1 -1
  112. package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
  113. package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -1
  114. package/dist/src/db/write/easSyncProcess.d.ts +12 -0
  115. package/dist/src/db/write/easSyncProcess.d.ts.map +1 -0
  116. package/dist/src/db/write/updateItemPropertyValue.d.ts.map +1 -1
  117. package/dist/src/eventBus.d.ts +13 -2
  118. package/dist/src/eventBus.d.ts.map +1 -1
  119. package/dist/src/events/files/download.d.ts +5 -1
  120. package/dist/src/events/files/download.d.ts.map +1 -1
  121. package/dist/src/events/item/easSyncManager.d.ts +71 -0
  122. package/dist/src/events/item/easSyncManager.d.ts.map +1 -0
  123. package/dist/src/events/item/index.d.ts.map +1 -1
  124. package/dist/src/events/item/mergeEasSyncOptions.d.ts +7 -0
  125. package/dist/src/events/item/mergeEasSyncOptions.d.ts.map +1 -0
  126. package/dist/src/events/item/syncDbWithEas.d.ts +0 -3
  127. package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
  128. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts +17 -0
  129. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts.map +1 -1
  130. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts +6 -0
  131. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts.map +1 -1
  132. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts +16 -0
  133. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts.map +1 -0
  134. package/dist/src/helpers/FileManager/BaseFileManager.d.ts +1 -0
  135. package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
  136. package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts +16 -0
  137. package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts.map +1 -0
  138. package/dist/src/helpers/constants.d.ts +20 -5
  139. package/dist/src/helpers/constants.d.ts.map +1 -1
  140. package/dist/src/helpers/environment.d.ts +5 -0
  141. package/dist/src/helpers/environment.d.ts.map +1 -1
  142. package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -1
  143. package/dist/src/helpers/index.d.ts +1 -0
  144. package/dist/src/helpers/index.d.ts.map +1 -1
  145. package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts +8 -0
  146. package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts.map +1 -0
  147. package/dist/src/index.d.ts +7 -3
  148. package/dist/src/index.d.ts.map +1 -1
  149. package/dist/src/interfaces/IQueryClient.d.ts +4 -0
  150. package/dist/src/interfaces/IQueryClient.d.ts.map +1 -1
  151. package/dist/src/node/helpers/QueryClient.d.ts.map +1 -1
  152. package/dist/src/seedSchema/EasSyncProcessSchema.d.ts +190 -0
  153. package/dist/src/seedSchema/EasSyncProcessSchema.d.ts.map +1 -0
  154. package/dist/src/seedSchema/index.d.ts +1 -0
  155. package/dist/src/seedSchema/index.d.ts.map +1 -1
  156. package/dist/src/services/write/writeProcessMachine.d.ts +1 -1
  157. package/dist/src/types/fileManager.d.ts +5 -0
  158. package/dist/src/types/fileManager.d.ts.map +1 -1
  159. package/dist/src/types/index.d.ts +3 -2
  160. package/dist/src/types/index.d.ts.map +1 -1
  161. package/dist/src/types/machines.d.ts +1 -1
  162. package/dist/src/types/machines.d.ts.map +1 -1
  163. package/dist/src/vite/index.d.ts.map +1 -1
  164. package/dist/syncDbWithEas-m-_3Ds7d.js +582 -0
  165. package/dist/syncDbWithEas-m-_3Ds7d.js.map +1 -0
  166. package/dist/updateSeedRevokedAt-BvAK-Rfh.js +22 -0
  167. package/dist/updateSeedRevokedAt-BvAK-Rfh.js.map +1 -0
  168. package/dist/vite.cjs +100 -26
  169. package/dist/vite.cjs.map +1 -1
  170. package/dist/vite.js +100 -26
  171. package/dist/vite.js.map +1 -1
  172. package/package.json +1 -1
  173. package/dist/Db-CXwQVLZv.js.map +0 -1
  174. package/dist/FileManager-DHnyb040.js.map +0 -1
  175. package/dist/ModelProperty-DWtv9fQr.js.map +0 -1
  176. package/dist/QueryClient-OUjfvY3g.js.map +0 -1
  177. package/dist/QueryClient-unspcsWa.js.map +0 -1
  178. package/dist/cjs/getPublishUploads-DdVy-5fK.js.map +0 -1
  179. package/dist/cjs/index-D1qR8xnb.js.map +0 -1
  180. package/dist/cjs/index-DTkoTvcq.js.map +0 -1
  181. package/dist/getPublishPayload-DpYwi-rd.js.map +0 -1
  182. package/dist/getPublishUploads-DS2dQ4Ho.js.map +0 -1
  183. package/dist/index-BrD_NNaX.js.map +0 -1
  184. package/dist/index-Cqf_DxkJ.js.map +0 -1
  185. package/dist/index-DdzhrbkF.js.map +0 -1
  186. package/dist/property-C63Ddzap.js.map +0 -1
@@ -14,7 +14,6 @@ var typebox = require('@sinclair/typebox');
14
14
  var casing = require('drizzle-orm/casing');
15
15
  var lodashEs = require('lodash-es');
16
16
  var rxjs = require('rxjs');
17
- var EventEmitter = require('eventemitter3');
18
17
  var Arweave = require('arweave');
19
18
  var sha3 = require('js-sha3');
20
19
  var fsAsync = require('fs/promises');
@@ -198,6 +197,13 @@ class BaseFileManager {
198
197
  static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
199
198
  return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
200
199
  }
200
+ static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
201
+ return this.PlatformClass.downloadAllFiles({
202
+ transactionIds: [transactionId],
203
+ arweaveHost,
204
+ excludedTransactions,
205
+ });
206
+ }
201
207
  static resizeImage({ filePath, width, height }) {
202
208
  return this.PlatformClass.resizeImage({ filePath, width, height });
203
209
  }
@@ -406,8 +412,51 @@ var SeedModels;
406
412
  // Internal SDK schema that should not be created in app's files directory
407
413
  const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
408
414
  const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
409
- /** Default Arweave gateway host used across all packages */
410
- const DEFAULT_ARWEAVE_HOST = 'arweave.net';
415
+ /** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
416
+ const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
417
+ /**
418
+ * Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
419
+ * Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
420
+ */
421
+ const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
422
+ const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
423
+ /** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
424
+ function getDefaultArweaveReadGatewayHostsOrdered() {
425
+ if (typeof process === 'undefined' || !process.env) {
426
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
427
+ }
428
+ for (const key of READ_GATEWAYS_ENV_KEYS) {
429
+ const raw = process.env[key]?.trim();
430
+ if (raw) {
431
+ return raw.split(',').map((s) => s.trim()).filter(Boolean);
432
+ }
433
+ }
434
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
435
+ }
436
+ /**
437
+ * Deduped host list: primary first, then each default not already present (case-insensitive).
438
+ */
439
+ function mergePrimaryHostWithDefaults(primary, defaults) {
440
+ const seen = new Set();
441
+ const out = [];
442
+ const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
443
+ const add = (h) => {
444
+ const t = h.trim().replace(/\/$/, '');
445
+ if (!t)
446
+ return;
447
+ const k = keyOf(t);
448
+ if (seen.has(k))
449
+ return;
450
+ seen.add(k);
451
+ out.push(t);
452
+ };
453
+ add(primary);
454
+ for (const d of defaults)
455
+ add(d);
456
+ return out;
457
+ }
458
+ /** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
459
+ const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
411
460
  /**
412
461
  * Check if a schema is an internal SDK schema that should not be created in app files
413
462
  */
@@ -419,7 +468,9 @@ function isInternalSchema(schemaName, schemaId) {
419
468
  var constants = /*#__PURE__*/Object.freeze({
420
469
  __proto__: null,
421
470
  CLIENT_NOT_INITIALIZED: CLIENT_NOT_INITIALIZED,
471
+ DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
422
472
  DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
473
+ EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
423
474
  INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
424
475
  INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
425
476
  INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
@@ -437,7 +488,9 @@ var constants = /*#__PURE__*/Object.freeze({
437
488
  ZERO_BYTES: ZERO_BYTES,
438
489
  ZERO_BYTES32: ZERO_BYTES32,
439
490
  defaultAttestationData: defaultAttestationData,
440
- isInternalSchema: isInternalSchema
491
+ getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
492
+ isInternalSchema: isInternalSchema,
493
+ mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
441
494
  });
442
495
 
443
496
  function parseGateway(input) {
@@ -454,6 +507,8 @@ function parseGateway(input) {
454
507
  let _host = DEFAULT_ARWEAVE_HOST;
455
508
  let _protocol = 'https';
456
509
  let _hostExplicitlySet = false;
510
+ /** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
511
+ let _suppressEnvGatewayOverride = false;
457
512
  class BaseArweaveClient {
458
513
  static setPlatformClass(platformClass) {
459
514
  this.PlatformClass = platformClass;
@@ -466,7 +521,7 @@ class BaseArweaveClient {
466
521
  const envHost = typeof process !== 'undefined' && process.env
467
522
  ? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
468
523
  : undefined;
469
- if (envHost && !_hostExplicitlySet) {
524
+ if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
470
525
  return parseGateway(envHost);
471
526
  }
472
527
  }
@@ -504,6 +559,39 @@ class BaseArweaveClient {
504
559
  _host = parsed.host;
505
560
  _protocol = parsed.protocol;
506
561
  _hostExplicitlySet = true;
562
+ _suppressEnvGatewayOverride = false;
563
+ }
564
+ /**
565
+ * When true, read-path gateway probing does not change the host ({@link setHost}).
566
+ */
567
+ static isReadGatewayLocked() {
568
+ return _hostExplicitlySet;
569
+ }
570
+ /**
571
+ * @internal Clears env override suppression after probing (for test isolation).
572
+ */
573
+ static resetReadGatewaySelectionStateForTests() {
574
+ _suppressEnvGatewayOverride = false;
575
+ }
576
+ /**
577
+ * Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
578
+ * Used for seed `arweaveDomain`.
579
+ */
580
+ static setPreferredReadGateway(host) {
581
+ const parsed = parseGateway(host);
582
+ _host = parsed.host;
583
+ _protocol = parsed.protocol;
584
+ _hostExplicitlySet = false;
585
+ }
586
+ /**
587
+ * Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
588
+ */
589
+ static applyProbedReadGateway(host) {
590
+ const parsed = parseGateway(host);
591
+ _host = parsed.host;
592
+ _protocol = parsed.protocol;
593
+ _hostExplicitlySet = false;
594
+ _suppressEnvGatewayOverride = true;
507
595
  }
508
596
  /**
509
597
  * Get the GraphQL endpoint URL
@@ -587,6 +675,11 @@ class BaseArweaveClient {
587
675
  }
588
676
  }
589
677
 
678
+ var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
679
+ __proto__: null,
680
+ BaseArweaveClient: BaseArweaveClient
681
+ });
682
+
590
683
  /**
591
684
  * Trim and strip a trailing slash from an upload API base URL.
592
685
  */
@@ -638,6 +731,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
638
731
  }
639
732
  }
640
733
 
734
+ const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
735
+ const PROBE_TIMEOUT_MS = 5000;
736
+ let readGatewayCache = null;
737
+ let ensureInFlight = null;
738
+ /** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
739
+ function invalidateReadGatewayCache() {
740
+ readGatewayCache = null;
741
+ ensureInFlight = null;
742
+ }
743
+ /** Clears probe cache, env override suppression, and preferred host (for tests). */
744
+ function resetArweaveReadGatewayForTests() {
745
+ invalidateReadGatewayCache();
746
+ BaseArweaveClient.resetReadGatewaySelectionStateForTests();
747
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
748
+ BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
749
+ }
750
+ }
751
+ /**
752
+ * GET /info with timeout. Treat 2xx + JSON object as healthy.
753
+ */
754
+ async function probeGateway(baseUrl, signal) {
755
+ const url = `${baseUrl.replace(/\/$/, '')}/info`;
756
+ let timer;
757
+ const controller = new AbortController();
758
+ const effectiveSignal = signal ?? controller.signal;
759
+ if (!signal) {
760
+ timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
761
+ }
762
+ try {
763
+ const response = await fetch(url, {
764
+ method: 'GET',
765
+ signal: effectiveSignal,
766
+ headers: { Accept: 'application/json' },
767
+ });
768
+ if (!response.ok)
769
+ return false;
770
+ const text = await response.text();
771
+ if (!text.trim())
772
+ return false;
773
+ try {
774
+ const json = JSON.parse(text);
775
+ return typeof json === 'object' && json !== null;
776
+ }
777
+ catch {
778
+ return false;
779
+ }
780
+ }
781
+ catch {
782
+ return false;
783
+ }
784
+ finally {
785
+ if (timer)
786
+ clearTimeout(timer);
787
+ }
788
+ }
789
+ async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
790
+ for (const host of hosts) {
791
+ const h = host.trim().replace(/\/$/, '');
792
+ if (!h)
793
+ continue;
794
+ const baseUrl = `${protocol}://${h}`;
795
+ if (await probeGateway(baseUrl, signal)) {
796
+ return h;
797
+ }
798
+ }
799
+ return null;
800
+ }
801
+ function buildOrderedHostsForProbe() {
802
+ const primary = BaseArweaveClient.getHost();
803
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
804
+ return mergePrimaryHostWithDefaults(primary, defaults);
805
+ }
806
+ /**
807
+ * Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
808
+ * No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
809
+ * Uses a short TTL cache to avoid probing on every read.
810
+ */
811
+ async function ensureReadGatewaySelected(signal) {
812
+ if (BaseArweaveClient.isReadGatewayLocked()) {
813
+ return BaseArweaveClient.getHost();
814
+ }
815
+ const now = Date.now();
816
+ if (readGatewayCache && now < readGatewayCache.expiresAt) {
817
+ return readGatewayCache.host;
818
+ }
819
+ if (ensureInFlight) {
820
+ return ensureInFlight;
821
+ }
822
+ ensureInFlight = (async () => {
823
+ const ordered = buildOrderedHostsForProbe();
824
+ const protocol = BaseArweaveClient.getProtocol();
825
+ const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
826
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
827
+ if (picked) {
828
+ BaseArweaveClient.applyProbedReadGateway(picked);
829
+ }
830
+ }
831
+ readGatewayCache = {
832
+ host: BaseArweaveClient.getHost(),
833
+ expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
834
+ };
835
+ return readGatewayCache.host;
836
+ })();
837
+ try {
838
+ return await ensureInFlight;
839
+ }
840
+ finally {
841
+ ensureInFlight = null;
842
+ }
843
+ }
844
+
845
+ var selectReadGateway = /*#__PURE__*/Object.freeze({
846
+ __proto__: null,
847
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
848
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
849
+ probeGateway: probeGateway,
850
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
851
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
852
+ });
853
+
641
854
  const GATEWAY_TX_QUERY = `
642
855
  query ArweaveGatewayTransaction($id: String!) {
643
856
  transaction(id: $id) {
@@ -734,6 +947,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
734
947
  return null;
735
948
  }
736
949
  }
950
+ /**
951
+ * Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
952
+ * {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
953
+ * {@link getDefaultArweaveReadGatewayHostsOrdered}.
954
+ */
955
+ async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
956
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
957
+ const trimmed = graphqlUrl?.trim();
958
+ let protocol = 'https';
959
+ let preferredHost = null;
960
+ if (trimmed) {
961
+ try {
962
+ const u = new URL(trimmed);
963
+ protocol = u.protocol === 'http:' ? 'http' : 'https';
964
+ preferredHost = u.hostname || null;
965
+ }
966
+ catch {
967
+ preferredHost = null;
968
+ }
969
+ }
970
+ const ordered = preferredHost && preferredHost.length > 0
971
+ ? mergePrimaryHostWithDefaults(preferredHost, defaults)
972
+ : [...defaults];
973
+ const signal = init?.signal;
974
+ for (const host of ordered) {
975
+ const base = `${protocol}://${host}`;
976
+ if (!(await probeGateway(base, signal ?? undefined)))
977
+ continue;
978
+ const gqlUrl = `${protocol}://${host}/graphql`;
979
+ const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
980
+ if (result !== null) {
981
+ return result;
982
+ }
983
+ }
984
+ return null;
985
+ }
737
986
 
738
987
  class BaseEasClient {
739
988
  static setPlatformClass(platformClass) {
@@ -1409,6 +1658,19 @@ const arweaveL1FinalizeJobs = sqliteCore.sqliteTable('arweave_l1_finalize_jobs',
1409
1658
  dataItemIdUnique: sqliteCore.uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
1410
1659
  }));
1411
1660
 
1661
+ const easSyncProcesses = sqliteCore.sqliteTable('eas_sync_processes', {
1662
+ id: sqliteCore.int('id').primaryKey({ autoIncrement: true }),
1663
+ status: sqliteCore.text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
1664
+ startedAt: sqliteCore.int('started_at').notNull(),
1665
+ completedAt: sqliteCore.int('completed_at'),
1666
+ requestPayload: sqliteCore.text('request_payload').notNull(),
1667
+ errorMessage: sqliteCore.text('error_message'),
1668
+ errorDetails: sqliteCore.text('error_details'),
1669
+ persistedSnapshot: sqliteCore.text('persisted_snapshot').notNull(),
1670
+ createdAt: sqliteCore.int('created_at'),
1671
+ updatedAt: sqliteCore.int('updated_at'),
1672
+ });
1673
+
1412
1674
  /**
1413
1675
  * Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
1414
1676
  * Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
@@ -1430,6 +1692,7 @@ var schema$1 = /*#__PURE__*/Object.freeze({
1430
1692
  appState: appState,
1431
1693
  arweaveL1FinalizeJobs: arweaveL1FinalizeJobs,
1432
1694
  config: config,
1695
+ easSyncProcesses: easSyncProcesses,
1433
1696
  htmlEmbeddedImageCoPublish: htmlEmbeddedImageCoPublish,
1434
1697
  metadata: metadata$1,
1435
1698
  modelRelations: modelRelations,
@@ -1922,6 +2185,7 @@ var index = /*#__PURE__*/Object.freeze({
1922
2185
  capitalizeFirstLetter: capitalizeFirstLetter,
1923
2186
  classifyMediaRef: classifyMediaRef,
1924
2187
  convertTxIdToImage: convertTxIdToImage,
2188
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
1925
2189
  generateId: generateId,
1926
2190
  getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
1927
2191
  getArweaveUploadStatus: getArweaveUploadStatus,
@@ -1941,6 +2205,7 @@ var index = /*#__PURE__*/Object.freeze({
1941
2205
  getUploadExecutor: getUploadExecutor,
1942
2206
  getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
1943
2207
  identifyString: identifyString,
2208
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
1944
2209
  isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
1945
2210
  isBinary: isBinary,
1946
2211
  isPlaceholderUid: isPlaceholderUid,
@@ -1953,11 +2218,15 @@ var index = /*#__PURE__*/Object.freeze({
1953
2218
  normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
1954
2219
  parseEasRelationPropertyName: parseEasRelationPropertyName,
1955
2220
  pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
2221
+ probeGateway: probeGateway,
1956
2222
  queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
2223
+ queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
2224
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
1957
2225
  resolveMediaRef: resolveMediaRef,
1958
2226
  resolveMetadataRecord: resolveMetadataRecord,
1959
2227
  resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
1960
2228
  resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
2229
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
1961
2230
  setAdditionalSyncAddresses: setAdditionalSyncAddresses,
1962
2231
  setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
1963
2232
  setRevokeExecutor: setRevokeExecutor,
@@ -1980,7 +2249,7 @@ const createPropertyInstances = async (propertyFileIds) => {
1980
2249
  return;
1981
2250
  }
1982
2251
  try {
1983
- const mod = await Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); });
2252
+ const mod = await Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); });
1984
2253
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
1985
2254
  if (!ModelProperty) {
1986
2255
  logger$y('createPropertyInstances: ModelProperty not available from dynamic import');
@@ -2164,7 +2433,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
2164
2433
  // Step 2: Fallback to Schema context (only if database doesn't have the model)
2165
2434
  // This handles the case where model exists in schema file but not yet in database
2166
2435
  try {
2167
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2436
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
2168
2437
  const { Schema } = schemaMod;
2169
2438
  const schema = Schema.create(schemaName, { waitForReady: false });
2170
2439
  const schemaSnapshot = schema.getService().getSnapshot();
@@ -2408,7 +2677,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
2408
2677
  }
2409
2678
  // Mark schema as draft when a new model is created so saveNewVersion() can persist it
2410
2679
  try {
2411
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2680
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
2412
2681
  const { Schema } = schemaMod;
2413
2682
  const schema = Schema.create(schemaName, { waitForReady: false });
2414
2683
  schema.getService().send({ type: 'markAsDraft', propertyKey: 'schema:models' });
@@ -2452,10 +2721,10 @@ const validateModel = xstate.fromCallback(({ sendBack, input: { context } }) =>
2452
2721
  const _validateModel = async () => {
2453
2722
  try {
2454
2723
  // Use dynamic imports to break circular dependencies
2455
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
2724
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
2456
2725
  const { SchemaValidationService } = validationServiceMod;
2457
2726
  const validationService = new SchemaValidationService();
2458
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2727
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
2459
2728
  const { Schema } = schemaMod;
2460
2729
  // Validate model structure
2461
2730
  const structureResult = validationService.validateModelStructure(context);
@@ -2565,7 +2834,7 @@ const createModelProperties = xstate.fromCallback(({ sendBack, input }) => {
2565
2834
  return;
2566
2835
  }
2567
2836
  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'); });
2837
+ const mod = await Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); });
2569
2838
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
2570
2839
  if (!ModelProperty) {
2571
2840
  logger$w('ModelProperty not available from dynamic import');
@@ -2669,7 +2938,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2669
2938
  const structureMsg = `[validateEntity] Validating model structure`;
2670
2939
  logger$v(structureMsg);
2671
2940
  // Use existing Model validation
2672
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
2941
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
2673
2942
  const { SchemaValidationService } = validationServiceMod;
2674
2943
  const validationService = new SchemaValidationService();
2675
2944
  // Validate model structure
@@ -2687,7 +2956,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2687
2956
  if (entityInput.entityData.schemaName) {
2688
2957
  try {
2689
2958
  logger$v(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
2690
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
2959
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
2691
2960
  const { Schema } = schemaMod;
2692
2961
  const schema = Schema.create(entityInput.entityData.schemaName, {
2693
2962
  waitForReady: false,
@@ -2723,7 +2992,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2723
2992
  }
2724
2993
  else if (entityInput.entityType === 'modelProperty') {
2725
2994
  // Use existing ModelProperty validation
2726
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
2995
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
2727
2996
  const { SchemaValidationService } = validationServiceMod;
2728
2997
  const validationService = new SchemaValidationService();
2729
2998
  // Validate property structure
@@ -2738,7 +3007,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2738
3007
  // If schema name and model name provided, validate against schema
2739
3008
  if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
2740
3009
  try {
2741
- const schemaMod = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
3010
+ const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
2742
3011
  const { Schema } = schemaMod;
2743
3012
  const schema = Schema.create(entityInput.entityData._schemaName, {
2744
3013
  waitForReady: false,
@@ -2767,7 +3036,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
2767
3036
  }
2768
3037
  else if (entityInput.entityType === 'schema') {
2769
3038
  // Schema validation - use existing validation
2770
- const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
3039
+ const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
2771
3040
  const { SchemaValidationService } = validationServiceMod;
2772
3041
  const validationService = new SchemaValidationService();
2773
3042
  const schemaResult = validationService.validateSchema(entityInput.entityData);
@@ -4719,7 +4988,7 @@ const writeToDatabase = xstate.fromCallback(({ sendBack, input }) => {
4719
4988
  // initial write completes is not overwritten by the stale requestWrite payload.
4720
4989
  let dataToWrite = input.entityData;
4721
4990
  try {
4722
- const mod = await Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); });
4991
+ const mod = await Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); });
4723
4992
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
4724
4993
  if (ModelProperty && typeof ModelProperty.getById === 'function') {
4725
4994
  const instance = ModelProperty.getById(input.entityId);
@@ -5099,7 +5368,7 @@ const modelMachine = xstate.setup({
5099
5368
  // Create ModelProperty instances for any new property IDs
5100
5369
  if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
5101
5370
  // Import and create instances asynchronously (fire-and-forget)
5102
- Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); }).then(({ ModelProperty }) => {
5371
+ Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); }).then(({ ModelProperty }) => {
5103
5372
  const createPromises = newPropertyIds.map(async (propertyFileId) => {
5104
5373
  try {
5105
5374
  const property = await ModelProperty.createById(propertyFileId);
@@ -5402,6 +5671,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
5402
5671
  var MachineIds;
5403
5672
  (function (MachineIds) {
5404
5673
  MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
5674
+ MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
5405
5675
  MachineIds["GLOBAL"] = "@seedSdk/global";
5406
5676
  MachineIds["INTERNAL"] = "@seedSdk/internal";
5407
5677
  MachineIds["EAS"] = "@seedSdk/eas";
@@ -5474,7 +5744,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
5474
5744
  * This constant is kept for backward compatibility but will be removed in a future version.
5475
5745
  * Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
5476
5746
  */
5477
- ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'arweave.net';
5747
+ ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
5478
5748
 
5479
5749
  debug('seedSdk:item:service:actors:waitForDb');
5480
5750
  const waitForDb$1 = xstate.fromCallback(({ sendBack }) => {
@@ -6357,7 +6627,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
6357
6627
  rowNum: drizzleOrm.sql.raw(`
6358
6628
  ROW_NUMBER() OVER (
6359
6629
  PARTITION BY property_name
6360
- ORDER BY COALESCE(attestation_created_at, created_at) DESC
6630
+ ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
6361
6631
  )
6362
6632
  `).as('rowNum')
6363
6633
  })
@@ -6370,6 +6640,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
6370
6640
  getMetadataLatest: getMetadataLatest
6371
6641
  });
6372
6642
 
6643
+ /**
6644
+ * Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
6645
+ * `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
6646
+ */
6647
+ function metadataLatestFirstSortKey(row) {
6648
+ return {
6649
+ t: row.attestationCreatedAt ?? row.createdAt ?? 0,
6650
+ localId: String(row.localId ?? ''),
6651
+ };
6652
+ }
6653
+ /** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
6654
+ function compareMetadataRowsLatestFirst(a, b) {
6655
+ const ka = metadataLatestFirstSortKey(a);
6656
+ const kb = metadataLatestFirstSortKey(b);
6657
+ if (kb.t !== ka.t)
6658
+ return kb.t - ka.t;
6659
+ return kb.localId.localeCompare(ka.localId);
6660
+ }
6661
+
6373
6662
  const logger$q = debug('seedSdk:item:actors:loadOrCreateItem');
6374
6663
  /**
6375
6664
  * Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
@@ -6411,9 +6700,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
6411
6700
  return b;
6412
6701
  if (sa !== sb)
6413
6702
  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;
6703
+ const cmp = compareMetadataRowsLatestFirst(a, b);
6704
+ return cmp < 0 ? a : b;
6417
6705
  }
6418
6706
  function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
6419
6707
  const byKey = new Map();
@@ -6461,7 +6749,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6461
6749
  const schemaNameToTry = model$1?.schemaName;
6462
6750
  if (schemaNameToTry) {
6463
6751
  try {
6464
- const { Schema } = await Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); });
6752
+ const { Schema } = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
6465
6753
  const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
6466
6754
  const schemaContext = schemaInstance.getService().getSnapshot().context;
6467
6755
  if (schemaContext.models?.[modelName]?.properties) {
@@ -6510,7 +6798,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6510
6798
  }
6511
6799
  }
6512
6800
  if (Object.keys(propertySchemas).length === 0) {
6513
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
6801
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
6514
6802
  const { ModelPropertyDataTypes } = schemaMod;
6515
6803
  const KNOWN_MODEL_FALLBACKS = {
6516
6804
  Post: {
@@ -6557,7 +6845,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6557
6845
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
6558
6846
  let propSchema = propertySchemas[propertyName];
6559
6847
  if (!propSchema && isRefTypeFromMeta) {
6560
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
6848
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
6561
6849
  const { ModelPropertyDataTypes } = schemaMod;
6562
6850
  propSchema = {
6563
6851
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -6814,9 +7102,9 @@ const runPublish = xstate.fromCallback(({ sendBack, input: { context } }) => {
6814
7102
  sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
6815
7103
  return;
6816
7104
  }
6817
- const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-DdVy-5fK.js'); });
7105
+ const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-CMpPR2JJ.js'); });
6818
7106
  const { getPublishUploads } = getPublishUploadsMod;
6819
- const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-DP2fm4q8.js'); });
7107
+ const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-C0hWIYCX.js'); });
6820
7108
  const { getPublishPayload } = getPublishPayloadMod;
6821
7109
  const uploads = await getPublishUploads(item);
6822
7110
  let uploadedTransactions = [];
@@ -7162,6 +7450,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
7162
7450
  return rows[0];
7163
7451
  };
7164
7452
 
7453
+ var getSeedData$1 = /*#__PURE__*/Object.freeze({
7454
+ __proto__: null,
7455
+ getSeedData: getSeedData
7456
+ });
7457
+
7165
7458
  /**
7166
7459
  * Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
7167
7460
  * Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
@@ -7651,7 +7944,7 @@ const resolveRelatedValue = xstate.fromCallback(({ sendBack, input: { context }
7651
7944
  const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
7652
7945
  const _resolveRelatedValue = async () => {
7653
7946
  // Use dynamic import to break circular dependency
7654
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
7947
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
7655
7948
  const { ModelPropertyDataTypes } = schemaMod;
7656
7949
  if (!propertyValue || !isRelation || populatedFromDb) {
7657
7950
  return;
@@ -8014,174 +8307,864 @@ function parseListPropertyValueFromStorage(raw) {
8014
8307
  return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
8015
8308
  }
8016
8309
 
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');
8310
+ class SeedEventEmitter {
8311
+ constructor() {
8312
+ this.listeners = new Map();
8024
8313
  }
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);
8314
+ on(event, listener) {
8315
+ const set = this.listeners.get(event) ?? new Set();
8316
+ set.add(listener);
8317
+ this.listeners.set(event, set);
8318
+ return this;
8319
+ }
8320
+ addListener(event, listener) {
8321
+ return this.on(event, listener);
8322
+ }
8323
+ once(event, listener) {
8324
+ const wrapped = (...args) => {
8325
+ this.off(event, wrapped);
8326
+ listener(...args);
8327
+ };
8328
+ return this.on(event, wrapped);
8329
+ }
8330
+ off(event, listener) {
8331
+ const set = this.listeners.get(event);
8332
+ if (!set)
8333
+ return this;
8334
+ set.delete(listener);
8335
+ if (set.size === 0)
8336
+ this.listeners.delete(event);
8337
+ return this;
8338
+ }
8339
+ removeListener(event, listener) {
8340
+ return this.off(event, listener);
8341
+ }
8342
+ removeAllListeners(event) {
8343
+ if (typeof event === 'undefined') {
8344
+ this.listeners.clear();
8345
+ return this;
8346
+ }
8347
+ this.listeners.delete(event);
8348
+ return this;
8349
+ }
8350
+ emit(event, ...args) {
8351
+ const set = this.listeners.get(event);
8352
+ if (!set || set.size === 0)
8353
+ return false;
8354
+ for (const listener of [...set]) {
8355
+ listener(...args);
8134
8356
  }
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);
8170
- if (property) {
8171
- property.getService().send({ type: 'updateContext', renderValue });
8172
- }
8173
- return;
8174
- }
8357
+ return true;
8358
+ }
8359
+ }
8360
+ const eventEmitter = new SeedEventEmitter();
8361
+
8362
+ const GET_FILES_METADATA = graphql(/* GraphQL */ `
8363
+ query GetFilesMetadata($where: AttestationWhereInput!) {
8364
+ filesMetadata: attestations(
8365
+ where: $where
8366
+ orderBy: [{ timeCreated: desc }]
8367
+ ) {
8368
+ ...attestationFields
8369
+ }
8370
+ }
8371
+ `);
8372
+
8373
+ const getMetadata = async (props) => {
8374
+ const appDb = BaseDb.getAppDb();
8375
+ let storageTransactionId;
8376
+ if (props) {
8377
+ storageTransactionId = props.storageTransactionId;
8378
+ }
8379
+ const whereClauses = [];
8380
+ if (storageTransactionId) {
8381
+ whereClauses.push(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'));
8382
+ whereClauses.push(drizzleOrm.eq(metadata$1.propertyValue, storageTransactionId));
8383
+ }
8384
+ const metadataRows = await appDb
8385
+ .select()
8386
+ .from(metadata$1)
8387
+ .where(drizzleOrm.and(...whereClauses));
8388
+ if (!metadataRows || metadataRows.length === 0) {
8389
+ return;
8390
+ }
8391
+ return metadataRows[0];
8392
+ };
8393
+
8394
+ const saveMetadata = async (metadataRecord, metadataValues) => {
8395
+ if (!metadataRecord.localId) {
8396
+ return;
8397
+ }
8398
+ const appDb = BaseDb.getAppDb();
8399
+ await appDb
8400
+ .update(metadata$1)
8401
+ .set({
8402
+ ...metadataValues,
8403
+ updatedAt: Date.now(),
8404
+ })
8405
+ .where(drizzleOrm.eq(metadata$1.localId, metadataRecord.localId));
8406
+ };
8407
+
8408
+ const isNode = () => {
8409
+ return (typeof process !== 'undefined' &&
8410
+ process.versions != null &&
8411
+ process.versions.node != null);
8412
+ };
8413
+ const isBrowser = () => {
8414
+ return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
8415
+ };
8416
+ const isElectron = () => {
8417
+ return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
8418
+ };
8419
+ /**
8420
+ * Detects if code is running in an Electron renderer process.
8421
+ *
8422
+ * Uses multiple detection methods for robustness:
8423
+ * 1. Checks process.type === 'renderer' (most reliable)
8424
+ * 2. Falls back to checking if Electron is present and window/document exist
8425
+ *
8426
+ * @returns true if running in Electron renderer process, false otherwise
8427
+ */
8428
+ const isElectronRenderer = () => {
8429
+ // Method 1: Check process.type (most reliable - official Electron API)
8430
+ if (typeof process !== 'undefined' &&
8431
+ process.type === 'renderer') {
8432
+ return true;
8433
+ }
8434
+ // Method 2: Fallback - Electron + browser-like environment
8435
+ // Renderer processes have window/document, main process doesn't (in modern Electron)
8436
+ if (isElectron() &&
8437
+ typeof window !== 'undefined' &&
8438
+ typeof document !== 'undefined') {
8439
+ return true;
8440
+ }
8441
+ return false;
8442
+ };
8443
+ /**
8444
+ * True where OPFS-backed Arweave file downloads should run: normal browsers and
8445
+ * Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
8446
+ */
8447
+ const supportsOpfsFileDownloads = () => {
8448
+ return isBrowser() || isElectronRenderer();
8449
+ };
8450
+
8451
+ const logger$l = debug('seedSdk:files:download');
8452
+ const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
8453
+ /** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
8454
+ const GET_FILES_METADATA_STALE_MS = 120000;
8455
+ let bulkDownloadInFlight = null;
8456
+ const lazyDownloadInFlightByTransactionId = new Map();
8457
+ // syncDbFiles helper - internal service removed, functionality moved here
8458
+ const syncDbFiles = async (endpoints) => {
8459
+ // TODO: Implement syncDbFiles functionality if needed
8460
+ // This was previously in @/services/internal/helpers
8461
+ logger$l('[download] syncDbFiles called but not yet implemented');
8462
+ return Promise.resolve();
8463
+ };
8464
+ const getAppDbReady = async () => {
8465
+ if (!BaseDb.isAppDbReady()) {
8466
+ // Wait for ClientManager to be ready (DB_INIT state or later)
8467
+ const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
8468
+ const { getClient } = clientManagerMod;
8469
+ const clientManager = getClient();
8470
+ const clientService = clientManager.getService();
8471
+ await xstate.waitFor(clientService, (snapshot) => {
8472
+ const state = snapshot.value;
8473
+ return state === 'dbInit' ||
8474
+ state === 'saveConfig' ||
8475
+ state === 'processSchemaFiles' ||
8476
+ state === 'addModelsToStore' ||
8477
+ state === 'addModelsToDb' ||
8478
+ state === 'idle';
8479
+ }, { timeout: 30000 });
8480
+ }
8481
+ return BaseDb.getAppDb();
8482
+ };
8483
+ const getExcludedTransactions = async () => {
8484
+ const appDb = await getAppDbReady();
8485
+ if (!appDb) {
8486
+ return new Set();
8487
+ }
8488
+ const excludedTransactionsQuery = await appDb
8489
+ .select()
8490
+ .from(appState)
8491
+ .where(drizzleOrm.eq(appState.key, 'excludedTransactions'));
8492
+ const excludedTransactions = new Set();
8493
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
8494
+ const valueString = excludedTransactionsQuery[0].value;
8495
+ if (valueString) {
8496
+ const excludedTransactionsArray = JSON.parse(valueString);
8497
+ for (const txId of excludedTransactionsArray) {
8498
+ excludedTransactions.add(txId);
8499
+ }
8500
+ }
8501
+ }
8502
+ return excludedTransactions;
8503
+ };
8504
+ /** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
8505
+ const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
8506
+ const normalizeArweaveTxId = (raw) => {
8507
+ if (raw == null || raw === '')
8508
+ return undefined;
8509
+ const t = String(raw).trim();
8510
+ if (ARWEAVE_TX_ID_RE.test(t))
8511
+ return t;
8512
+ const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
8513
+ if (m)
8514
+ return m[1];
8515
+ // Values may be full gateway URLs or paths; scan for the embedded tx id.
8516
+ const embedded = t.match(/[a-z0-9_-]{43}/gi);
8517
+ if (embedded) {
8518
+ for (const candidate of embedded) {
8519
+ if (ARWEAVE_TX_ID_RE.test(candidate))
8520
+ return candidate;
8521
+ }
8522
+ }
8523
+ return undefined;
8524
+ };
8525
+ const mergeAddressLists = (a, b) => {
8526
+ const seen = new Set();
8527
+ const out = [];
8528
+ for (const addr of [...(a ?? []), ...(b ?? [])]) {
8529
+ if (!addr || !addr.trim())
8530
+ continue;
8531
+ const k = addr.toLowerCase();
8532
+ if (seen.has(k))
8533
+ continue;
8534
+ seen.add(k);
8535
+ out.push(addr);
8536
+ }
8537
+ return out;
8538
+ };
8539
+ const collectTransactionIdsFromLocalMetadata = async () => {
8540
+ const appDb = await getAppDbReady();
8541
+ if (!appDb) {
8542
+ return [];
8543
+ }
8544
+ const nameOr = drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'storage_transaction_id'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'));
8545
+ const propRows = await appDb
8546
+ .select({ propertyValue: metadata$1.propertyValue })
8547
+ .from(metadata$1)
8548
+ .where(drizzleOrm.and(nameOr, drizzleOrm.isNotNull(metadata$1.propertyValue)));
8549
+ const refRows = await appDb
8550
+ .select({ refResolvedValue: metadata$1.refResolvedValue })
8551
+ .from(metadata$1)
8552
+ .where(drizzleOrm.isNotNull(metadata$1.refResolvedValue));
8553
+ const ids = new Set();
8554
+ for (const row of propRows) {
8555
+ const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
8556
+ if (id)
8557
+ ids.add(id);
8558
+ }
8559
+ for (const row of refRows) {
8560
+ const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
8561
+ if (id)
8562
+ ids.add(id);
8563
+ }
8564
+ return Array.from(ids);
8565
+ };
8566
+ const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
8567
+ const transactionIds = [];
8568
+ for (const fileMetadata of filesMetadata) {
8569
+ // Validate and parse decodedDataJson
8570
+ if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
8571
+ console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
8572
+ continue;
8573
+ }
8574
+ let json;
8575
+ try {
8576
+ json = JSON.parse(fileMetadata.decodedDataJson);
8577
+ }
8578
+ catch (error) {
8579
+ console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
8580
+ continue;
8581
+ }
8582
+ if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
8583
+ console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
8584
+ continue;
8585
+ }
8586
+ const rawTx = json[0].value.value;
8587
+ if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
8588
+ continue;
8589
+ }
8590
+ const transactionId = normalizeArweaveTxId(rawTx.trim());
8591
+ if (!transactionId) {
8592
+ continue;
8593
+ }
8594
+ if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
8595
+ continue;
8596
+ }
8597
+ transactionIds.push(transactionId);
8598
+ }
8599
+ return transactionIds;
8600
+ };
8601
+ const downloadTransactionIds = async (rawTransactionIds, options) => {
8602
+ if (!supportsOpfsFileDownloads()) {
8603
+ return false;
8604
+ }
8605
+ const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
8606
+ if (transactionIds.length === 0) {
8607
+ return false;
8608
+ }
8609
+ const excludedTransactions = await getExcludedTransactions();
8610
+ const queryClient = BaseQueryClient.getQueryClient();
8611
+ const transactionIdsToDownload = [];
8612
+ await ensureReadGatewaySelected();
8613
+ for (const transactionId of transactionIds) {
8614
+ if (excludedTransactions.has(transactionId)) {
8615
+ continue;
8616
+ }
8617
+ try {
8618
+ // Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
8619
+ // CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
8620
+ let tags = [];
8621
+ try {
8622
+ tags = await queryClient.fetchQuery({
8623
+ queryKey: ['getTransactionTags', transactionId],
8624
+ queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
8625
+ });
8626
+ }
8627
+ catch {
8628
+ tags = [];
8629
+ }
8630
+ if (tags && tags.length > 0) {
8631
+ for (const { name, value } of tags) {
8632
+ if (name !== 'Content-SHA-256')
8633
+ continue;
8634
+ const metadataRecord = await getMetadata({
8635
+ storageTransactionId: transactionId,
8636
+ });
8637
+ if (metadataRecord) {
8638
+ await saveMetadata(metadataRecord, {
8639
+ contentHash: value,
8640
+ });
8641
+ }
8642
+ }
8643
+ }
8644
+ transactionIdsToDownload.push(transactionId);
8645
+ }
8646
+ catch (error) {
8647
+ logger$l(error);
8648
+ }
8649
+ }
8650
+ if (transactionIdsToDownload.length === 0) {
8651
+ return false;
8652
+ }
8653
+ if (transactionIdsToDownload.length === 1) {
8654
+ await BaseFileManager.downloadFileByTransactionId({
8655
+ transactionId: transactionIdsToDownload[0],
8656
+ arweaveHost: BaseArweaveClient.getHost(),
8657
+ excludedTransactions,
8658
+ });
8659
+ }
8660
+ else {
8661
+ await BaseFileManager.downloadAllFiles({
8662
+ transactionIds: transactionIdsToDownload,
8663
+ arweaveHost: BaseArweaveClient.getHost(),
8664
+ excludedTransactions,
8665
+ });
8666
+ }
8667
+ if (options?.resizeAllImages !== false) {
8668
+ await BaseFileManager.resizeAllImages({
8669
+ width: 480,
8670
+ height: 480,
8671
+ });
8672
+ }
8673
+ return true;
8674
+ };
8675
+ const runBulkDownloadWithDedupe = async (transactionIds) => {
8676
+ if (bulkDownloadInFlight) {
8677
+ return bulkDownloadInFlight;
8678
+ }
8679
+ bulkDownloadInFlight = (async () => {
8680
+ try {
8681
+ await downloadTransactionIds(transactionIds, { resizeAllImages: true });
8682
+ }
8683
+ finally {
8684
+ bulkDownloadInFlight = null;
8685
+ }
8686
+ })();
8687
+ return bulkDownloadInFlight;
8688
+ };
8689
+ const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
8690
+ if (!supportsOpfsFileDownloads()) {
8691
+ return;
8692
+ }
8693
+ await syncDbFiles();
8694
+ eventEmitter.emit('fs.downloadAll.success', { eventId });
8695
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
8696
+ };
8697
+ const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
8698
+ if (!supportsOpfsFileDownloads()) {
8699
+ return;
8700
+ }
8701
+ const addressesHint = Array.isArray(addressesHintOrPayload)
8702
+ ? addressesHintOrPayload
8703
+ : undefined;
8704
+ let fromDb = [];
8705
+ if (BaseDb.isAppDbReady()) {
8706
+ fromDb = await getAllAddressesFromDb();
8707
+ }
8708
+ if (!BaseDb.isAppDbReady()) {
8709
+ await getAppDbReady();
8710
+ fromDb = await getAllAddressesFromDb();
8711
+ }
8712
+ const addresses = mergeAddressLists(addressesHint, fromDb);
8713
+ if (!addresses || addresses.length === 0) {
8714
+ return;
8715
+ }
8716
+ const queryClient = BaseQueryClient.getQueryClient();
8717
+ const easClient = BaseEasClient.getEasClient();
8718
+ const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
8719
+ const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
8720
+ where: {
8721
+ attester: {
8722
+ in: addresses,
8723
+ },
8724
+ schema: {
8725
+ is: {
8726
+ id: {
8727
+ equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
8728
+ },
8729
+ },
8730
+ },
8731
+ },
8732
+ });
8733
+ let { filesMetadata } = await queryClient.fetchQuery({
8734
+ queryKey: filesMetadataQueryKey,
8735
+ queryFn: fetchFilesMetadata,
8736
+ staleTime: GET_FILES_METADATA_STALE_MS,
8737
+ });
8738
+ if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
8739
+ await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
8740
+ ({ filesMetadata } = await queryClient.fetchQuery({
8741
+ queryKey: filesMetadataQueryKey,
8742
+ queryFn: fetchFilesMetadata,
8743
+ staleTime: GET_FILES_METADATA_STALE_MS,
8744
+ }));
8745
+ }
8746
+ const filesRoot = BaseFileManager.getWorkingDir();
8747
+ await BaseFileManager.createDirIfNotExists(filesRoot);
8748
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
8749
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
8750
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
8751
+ const excludedTransactions = await getExcludedTransactions();
8752
+ const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
8753
+ const fromLocal = await collectTransactionIdsFromLocalMetadata();
8754
+ const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
8755
+ await runBulkDownloadWithDedupe(transactionIds);
8756
+ };
8757
+ const downloadTransactionIdWithDedupe = async (transactionId) => {
8758
+ if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
8759
+ return false;
8760
+ }
8761
+ const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
8762
+ const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
8763
+ if (existing) {
8764
+ return existing;
8765
+ }
8766
+ const inFlight = (async () => {
8767
+ try {
8768
+ const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
8769
+ return ok;
8770
+ }
8771
+ finally {
8772
+ lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
8773
+ }
8774
+ })();
8775
+ lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
8776
+ return inFlight;
8777
+ };
8778
+ const scheduleBulkFilesDownloadFromEasSyncThrottled = lodashEs.throttle((addressesHint) => {
8779
+ void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
8780
+ logger$l('[scheduleBulkFilesDownloadFromEasSync] failed', error);
8781
+ });
8782
+ }, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
8783
+ const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
8784
+ if (!supportsOpfsFileDownloads()) {
8785
+ return;
8786
+ }
8787
+ scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
8788
+ };
8789
+
8790
+ var download = /*#__PURE__*/Object.freeze({
8791
+ __proto__: null,
8792
+ downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
8793
+ downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
8794
+ downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
8795
+ scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
8796
+ });
8797
+
8798
+ /** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
8799
+ const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
8800
+ /** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
8801
+ const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
8802
+ function extractArweaveTransactionId(raw) {
8803
+ const t = raw.trim();
8804
+ const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
8805
+ if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
8806
+ return embedded[0];
8807
+ }
8808
+ return t;
8809
+ }
8810
+ /**
8811
+ * GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
8812
+ * arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
8813
+ */
8814
+ async function fetchHtmlViaRawAcrossGateways(txId) {
8815
+ const id = extractArweaveTransactionId(txId);
8816
+ if (!id || SEED_UID_HEX_RE.test(id))
8817
+ return undefined;
8818
+ try {
8819
+ const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
8820
+ await ensureReadGatewaySelected().catch(() => { });
8821
+ }
8822
+ catch {
8823
+ /* optional */
8824
+ }
8825
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8826
+ const protocol = BaseArweaveClient.getProtocol();
8827
+ const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
8828
+ for (const host of hosts) {
8829
+ const h = host.trim().replace(/\/$/, '');
8830
+ if (!h)
8831
+ continue;
8832
+ const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
8833
+ try {
8834
+ const res = await fetch(url, { method: 'GET', credentials: 'omit' });
8835
+ if (!res.ok)
8836
+ continue;
8837
+ const text = await res.text();
8838
+ if (typeof text === 'string' && text.length > 0) {
8839
+ return text;
8840
+ }
8841
+ }
8842
+ catch {
8843
+ /* next gateway */
8844
+ }
8845
+ }
8846
+ return undefined;
8847
+ }
8848
+ /**
8849
+ * Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
8850
+ * `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
8851
+ */
8852
+ async function resolveHtmlStorageSeedLocalId(propertyValue) {
8853
+ const pv = String(propertyValue ?? '').trim();
8854
+ if (!pv)
8855
+ return undefined;
8856
+ if (SEED_UID_HEX_RE.test(pv)) {
8857
+ const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
8858
+ return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
8859
+ }
8860
+ return pv;
8861
+ }
8862
+ /**
8863
+ * When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
8864
+ * Html storage seed's published Arweave transaction id on that child seed.
8865
+ */
8866
+ async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
8867
+ const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
8868
+ const pickTx = async (name) => {
8869
+ const row = await getPropertyData({ propertyName: name, seedLocalId });
8870
+ const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
8871
+ return v || undefined;
8872
+ };
8873
+ const txId = (await pickTx('storageTransactionId')) ??
8874
+ (await pickTx('transactionId')) ??
8875
+ (await pickTx('storage_transaction_id'));
8876
+ if (!txId || SEED_UID_HEX_RE.test(txId)) {
8877
+ return { txIdLen: 0, gatewayStringLen: 0 };
8878
+ }
8879
+ const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
8880
+ if (rawHtml && rawHtml.length > 0) {
8881
+ return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
8882
+ }
8883
+ try {
8884
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8885
+ const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
8886
+ string: true,
8887
+ });
8888
+ if (typeof data === 'string' && data.length > 0) {
8889
+ return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
8890
+ }
8891
+ }
8892
+ catch {
8893
+ /* offline / bad tx id */
8894
+ }
8895
+ try {
8896
+ const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
8897
+ await downloadTransactionIdWithDedupe(txId);
8898
+ const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
8899
+ if (await BaseFileManager.pathExists(retryFp)) {
8900
+ const s = await BaseFileManager.readFileAsString(retryFp);
8901
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8902
+ }
8903
+ const dirPath = BaseFileManager.getFilesPath('html');
8904
+ if (await BaseFileManager.pathExists(dirPath)) {
8905
+ const fs = await BaseFileManager.getFs();
8906
+ const pathMod = BaseFileManager.getPathModule();
8907
+ const files = await fs.promises.readdir(dirPath);
8908
+ const needle = txId.replace(/\.[^/.]+$/, '');
8909
+ const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
8910
+ if (match) {
8911
+ const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
8912
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8913
+ }
8914
+ }
8915
+ }
8916
+ catch {
8917
+ /* OPFS unsupported or download failed */
8918
+ }
8919
+ return { txIdLen: txId.length, gatewayStringLen: 0 };
8920
+ }
8921
+ /** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
8922
+ async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
8923
+ const pv = String(propertyValue ?? '').trim();
8924
+ if (!pv)
8925
+ return undefined;
8926
+ const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
8927
+ const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
8928
+ let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
8929
+ // OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
8930
+ if (!fileExists && fp) {
8931
+ await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
8932
+ fileExists = await BaseFileManager.pathExists(fp);
8933
+ }
8934
+ let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
8935
+ if (!body && localId) {
8936
+ const ar = await readHtmlBodyFromChildStorageArweave(localId);
8937
+ body = ar.body;
8938
+ }
8939
+ return body;
8940
+ }
8941
+
8942
+ // Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
8943
+ // import { ModelPropertyDataTypes } from '@/schema'
8944
+ const logger$k = debug('seedSdk:property:actors:hydrateFromDb');
8945
+ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) => {
8946
+ const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
8947
+ if (!propertyNameRaw) {
8948
+ throw new Error('propertyName is required');
8949
+ }
8950
+ let propertyName = propertyNameRaw;
8951
+ // Note: isRelation, isImage, isFile checks moved inside async function
8952
+ // to use dynamically imported ModelPropertyDataTypes
8953
+ const _hydrateFromDb = async () => {
8954
+ // Use dynamic import to break circular dependency
8955
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
8956
+ const { ModelPropertyDataTypes } = schemaMod;
8957
+ const appDb = BaseDb.getAppDb();
8958
+ const whereClauses = [];
8959
+ // Re-check types with dynamically imported ModelPropertyDataTypes
8960
+ // Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
8961
+ const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
8962
+ const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
8963
+ propertyRecordSchema &&
8964
+ propertyRecordSchema.ref &&
8965
+ normalizedDataType === ModelPropertyDataTypes.Relation;
8966
+ const isImageDynamic = propertyRecordSchema &&
8967
+ (normalizedDataType === ModelPropertyDataTypes.Image ||
8968
+ normalizedRefValueType === ModelPropertyDataTypes.Image);
8969
+ const isFileDynamic = propertyRecordSchema &&
8970
+ normalizedDataType === ModelPropertyDataTypes.File;
8971
+ const isHtmlDynamic = propertyRecordSchema &&
8972
+ normalizedDataType === ModelPropertyDataTypes.Html;
8973
+ // Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
8974
+ const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
8975
+ whereClauses.push(propertyNames.length > 1
8976
+ ? drizzleOrm.or(...propertyNames.map((n) => drizzleOrm.eq(metadata$1.propertyName, n)))
8977
+ : drizzleOrm.eq(metadata$1.propertyName, propertyNames[0]));
8978
+ // Draft rows often have only seed_local_id populated; on-chain rows may have uid.
8979
+ // Requiring both with AND misses valid metadata when only one column is set.
8980
+ if (seedUid && seedLocalId) {
8981
+ whereClauses.push(drizzleOrm.or(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId), drizzleOrm.eq(metadata$1.seedUid, seedUid)));
8982
+ }
8983
+ else if (seedUid) {
8984
+ whereClauses.push(drizzleOrm.eq(metadata$1.seedUid, seedUid));
8985
+ }
8986
+ else if (seedLocalId) {
8987
+ whereClauses.push(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId));
8988
+ }
8989
+ const rows = await appDb
8990
+ .select()
8991
+ .from(metadata$1)
8992
+ .where(drizzleOrm.and(...whereClauses))
8993
+ .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
8994
+ if (!rows || !rows.length) {
8995
+ return;
8996
+ }
8997
+ const firstRow = rows[0];
8998
+ const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
8999
+ let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
9000
+ let propertyValueProcessed = propertyValueFromDb;
9001
+ let renderValue = refResolvedDisplayValue ?? undefined;
9002
+ // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
9003
+ if (isImageDynamic) {
9004
+ let dir = localStorageDir;
9005
+ if (!dir && isImageDynamic) {
9006
+ dir = 'images';
9007
+ }
9008
+ dir = dir.replace(/^\//, '');
9009
+ if (propertyValueFromDb &&
9010
+ propertyValueFromDb.length === 66) {
9011
+ // Here the storageTransactionId is stored on a different record and
9012
+ // we want to add it as the refResolvedValue
9013
+ const storageTransactionQuery = await appDb
9014
+ .select({
9015
+ propertyValue: metadata$1.propertyValue,
9016
+ })
9017
+ .from(metadata$1)
9018
+ .where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, propertyValueFromDb), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))));
9019
+ if (storageTransactionQuery && storageTransactionQuery.length > 0) {
9020
+ const row = storageTransactionQuery[0];
9021
+ refResolvedValue = row.propertyValue;
9022
+ await updateMetadata({
9023
+ localId,
9024
+ refResolvedValue,
9025
+ localStorageDir: '/images',
9026
+ });
9027
+ }
9028
+ }
9029
+ const resolveMatchingFilePath = async (dir, needle) => {
9030
+ const dirPath = BaseFileManager.getFilesPath(dir);
9031
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9032
+ if (!dirExists)
9033
+ return undefined;
9034
+ const fs = await BaseFileManager.getFs();
9035
+ const path = BaseFileManager.getPathModule();
9036
+ const files = await fs.promises.readdir(dirPath);
9037
+ const matchingFiles = files.filter((file) => {
9038
+ return path.basename(file).includes(needle);
9039
+ });
9040
+ if (!matchingFiles?.length)
9041
+ return undefined;
9042
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9043
+ };
9044
+ if (refResolvedValue) {
9045
+ try {
9046
+ let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9047
+ if (!filePath) {
9048
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9049
+ filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9050
+ }
9051
+ localStorageDir = `/${dir}`;
9052
+ if (filePath) {
9053
+ const file = await BaseFileManager.readFile(filePath);
9054
+ refResolvedDisplayValue = URL.createObjectURL(file);
9055
+ renderValue = refResolvedDisplayValue;
9056
+ // Do not persist blob URL - it is session-scoped
9057
+ }
9058
+ }
9059
+ catch (e) {
9060
+ logger$k('[hydrateFromDb] Image file resolution error', e);
9061
+ }
9062
+ }
9063
+ }
9064
+ if (isFileDynamic && refResolvedValue) {
9065
+ try {
9066
+ const dir = (localStorageDir ?? '/files').replace(/^\//, '');
9067
+ const resolveMatchingFilePath = async (needle) => {
9068
+ const dirPath = BaseFileManager.getFilesPath(dir);
9069
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9070
+ if (!dirExists)
9071
+ return undefined;
9072
+ const fs = await BaseFileManager.getFs();
9073
+ const path = BaseFileManager.getPathModule();
9074
+ const files = await fs.promises.readdir(dirPath);
9075
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9076
+ if (!matchingFiles?.length)
9077
+ return undefined;
9078
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9079
+ };
9080
+ let filePath = await resolveMatchingFilePath(refResolvedValue);
9081
+ if (!filePath) {
9082
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9083
+ filePath = await resolveMatchingFilePath(refResolvedValue);
9084
+ }
9085
+ if (filePath) {
9086
+ localStorageDir = `/${dir}`;
9087
+ renderValue = await BaseFileManager.readFileAsString(filePath);
9088
+ }
9089
+ }
9090
+ catch (e) {
9091
+ logger$k('[hydrateFromDb] File resolution error', e);
9092
+ }
9093
+ }
9094
+ if (propertyRecordSchema &&
9095
+ normalizedDataType === ModelPropertyDataTypes.List &&
9096
+ typeof propertyValueFromDb === 'string') {
9097
+ propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
9098
+ }
9099
+ sendBack({
9100
+ type: 'updateContext',
9101
+ localId,
9102
+ uid,
9103
+ propertyValue: propertyValueProcessed,
9104
+ seedLocalId: seedLocalIdFromDb,
9105
+ seedUid: seedUidFromDb,
9106
+ versionLocalId: versionLocalIdFromDb,
9107
+ versionUid: versionUidFromDb,
9108
+ schemaUid: schemaUidFromDb,
9109
+ refValueType,
9110
+ localStorageDir,
9111
+ refResolvedValue,
9112
+ refResolvedDisplayValue,
9113
+ renderValue,
9114
+ populatedFromDb: true,
9115
+ });
9116
+ if (propertyRecordSchema &&
9117
+ propertyRecordSchema.storageType &&
9118
+ propertyRecordSchema.storageType === 'ItemStorage') {
9119
+ const itemMod = await Promise.resolve().then(function () { return Item$1; });
9120
+ const { Item } = itemMod;
9121
+ const item = await Item.find({
9122
+ seedLocalId: seedLocalId ?? undefined,
9123
+ modelName,
9124
+ });
9125
+ if (item) {
9126
+ const dir = localStorageDir?.replace(/^\//, '') || 'files';
9127
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9128
+ const exists = await BaseFileManager.pathExists(filePath);
9129
+ if (!exists) {
9130
+ return;
9131
+ }
9132
+ const renderValue = await BaseFileManager.readFileAsString(filePath);
9133
+ const property = item.properties.find(p => p.propertyName === propertyName);
9134
+ if (property) {
9135
+ property.getService().send({ type: 'updateContext', renderValue });
9136
+ }
9137
+ return;
9138
+ }
8175
9139
  }
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);
9140
+ // Html: read file content for renderValue (blob URLs from DB are invalid after reload).
9141
+ // When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
9142
+ if (isHtmlDynamic) {
9143
+ const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
9144
+ let htmlContent;
9145
+ let outRef = refResolvedValue;
9146
+ let outDir = htmlLocalStorageDir;
9147
+ if (refResolvedValue && htmlLocalStorageDir) {
9148
+ const dir = htmlLocalStorageDir.replace(/^\//, '');
9149
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9150
+ let exists = await BaseFileManager.pathExists(filePath);
9151
+ if (!exists) {
9152
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9153
+ exists = await BaseFileManager.pathExists(filePath);
9154
+ }
9155
+ if (exists) {
9156
+ htmlContent = await BaseFileManager.readFileAsString(filePath);
9157
+ }
9158
+ }
9159
+ if (!htmlContent && propertyValueFromDb) {
9160
+ htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
9161
+ const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
9162
+ if (lid) {
9163
+ outRef = `${lid}.html`;
9164
+ outDir = '/html';
9165
+ }
9166
+ }
9167
+ if (htmlContent) {
8185
9168
  sendBack({
8186
9169
  type: 'updateContext',
8187
9170
  localId,
@@ -8193,8 +9176,8 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
8193
9176
  versionUid: versionUidFromDb,
8194
9177
  schemaUid: schemaUidFromDb,
8195
9178
  refValueType,
8196
- localStorageDir: htmlLocalStorageDir,
8197
- refResolvedValue,
9179
+ localStorageDir: outDir,
9180
+ refResolvedValue: outRef ?? refResolvedValue,
8198
9181
  refResolvedDisplayValue,
8199
9182
  renderValue: htmlContent,
8200
9183
  populatedFromDb: true,
@@ -8208,11 +9191,11 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
8208
9191
  });
8209
9192
  });
8210
9193
 
8211
- const logger$k = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
9194
+ const logger$j = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
8212
9195
  const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context } }) => {
8213
9196
  const _loadOrCreateProperty = async () => {
8214
9197
  const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
8215
- logger$k(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
9198
+ logger$j(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
8216
9199
  if (!seedLocalId && !seedUid) {
8217
9200
  throw new Error('seedLocalId or seedUid is required');
8218
9201
  }
@@ -8258,15 +9241,15 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8258
9241
  const schemas = modelPropertiesToObject(model$1.properties);
8259
9242
  propertyRecordSchema = schemas[propertyName];
8260
9243
  if (propertyRecordSchema) {
8261
- logger$k(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9244
+ logger$j(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8262
9245
  }
8263
9246
  }
8264
9247
  }
8265
9248
  catch (error) {
8266
- logger$k(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
9249
+ logger$j(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
8267
9250
  }
8268
9251
  }
8269
- logger$k(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
9252
+ logger$j(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
8270
9253
  sendBack({
8271
9254
  type: 'loadOrCreatePropertySuccess',
8272
9255
  property: {
@@ -8332,7 +9315,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8332
9315
  };
8333
9316
  // Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
8334
9317
  try {
8335
- const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-BQokoaRe.js'); });
9318
+ const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-BT7i8Tl-.js'); });
8336
9319
  let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
8337
9320
  if (!schemaFromFile?.validation) {
8338
9321
  // Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
@@ -8370,7 +9353,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8370
9353
  }
8371
9354
  }
8372
9355
  catch (error) {
8373
- logger$k(`Error loading propertyRecordSchema from database: ${error}`);
9356
+ logger$j(`Error loading propertyRecordSchema from database: ${error}`);
8374
9357
  // Continue without propertyRecordSchema
8375
9358
  }
8376
9359
  }
@@ -8388,22 +9371,27 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8388
9371
  const schemas = modelPropertiesToObject(model$1.properties);
8389
9372
  propertyRecordSchema = schemas[propertyName];
8390
9373
  if (propertyRecordSchema) {
8391
- logger$k(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9374
+ logger$j(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8392
9375
  }
8393
9376
  }
8394
9377
  }
8395
9378
  catch (error) {
8396
- logger$k(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
9379
+ logger$j(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
8397
9380
  }
8398
9381
  }
8399
9382
  // For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
8400
9383
  let renderValue = metadataRecord.propertyValue || undefined;
8401
9384
  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)
9385
+ const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
9386
+ const isHtml = refSeedType === 'html' || normalizedHtmlDt === exports.ModelPropertyDataTypes.Html;
9387
+ // Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
9388
+ // After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
8404
9389
  if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
8405
- metadataRecord.refResolvedValue = `${metadataRecord.propertyValue}.html`;
8406
- metadataRecord.localStorageDir = '/html';
9390
+ const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
9391
+ if (lid) {
9392
+ metadataRecord.refResolvedValue = `${lid}.html`;
9393
+ metadataRecord.localStorageDir = '/html';
9394
+ }
8407
9395
  }
8408
9396
  // Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
8409
9397
  if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
@@ -8413,13 +9401,34 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8413
9401
  try {
8414
9402
  const dir = metadataRecord.localStorageDir.replace(/^\//, '');
8415
9403
  const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
8416
- const exists = await BaseFileManager.pathExists(filePath);
9404
+ let exists = await BaseFileManager.pathExists(filePath);
9405
+ if (!exists) {
9406
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9407
+ exists = await BaseFileManager.pathExists(filePath);
9408
+ }
8417
9409
  if (exists) {
8418
9410
  renderValue = await BaseFileManager.readFileAsString(filePath);
8419
9411
  }
9412
+ else {
9413
+ const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9414
+ if (viaSeedPointer) {
9415
+ renderValue = viaSeedPointer;
9416
+ }
9417
+ }
8420
9418
  }
8421
9419
  catch (e) {
8422
- logger$k(`Failed to read Html file for ${propertyName}: ${e}`);
9420
+ logger$j(`Failed to read Html file for ${propertyName}: ${e}`);
9421
+ }
9422
+ }
9423
+ // Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
9424
+ if (isHtml && metadataRecord.propertyValue) {
9425
+ const pv = String(metadataRecord.propertyValue).trim();
9426
+ const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
9427
+ if (!rv || rv === pv) {
9428
+ const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9429
+ if (recovered) {
9430
+ renderValue = recovered;
9431
+ }
8423
9432
  }
8424
9433
  }
8425
9434
  // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
@@ -8429,28 +9438,83 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8429
9438
  const isImage = refSeedType === 'image' ||
8430
9439
  normalizedDataType === 'Image' ||
8431
9440
  normalizedRefValueType === 'Image';
9441
+ const resolveMatchingFilePath = async (dir, needle) => {
9442
+ const dirPath = BaseFileManager.getFilesPath(dir);
9443
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9444
+ if (!dirExists)
9445
+ return undefined;
9446
+ const fs = await BaseFileManager.getFs();
9447
+ const path = BaseFileManager.getPathModule();
9448
+ const files = await fs.promises.readdir(dirPath);
9449
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9450
+ if (!matchingFiles?.length)
9451
+ return undefined;
9452
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9453
+ };
9454
+ // EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
9455
+ // hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
9456
+ if (isImage &&
9457
+ !metadataRecord.refResolvedValue &&
9458
+ typeof metadataRecord.propertyValue === 'string' &&
9459
+ metadataRecord.propertyValue.length === 66) {
9460
+ const storageTxRows = await db
9461
+ .select({ propertyValue: metadata$1.propertyValue })
9462
+ .from(metadata$1)
9463
+ .where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, metadataRecord.propertyValue), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))))
9464
+ .limit(1);
9465
+ const derivedTxId = storageTxRows[0]?.propertyValue;
9466
+ if (derivedTxId) {
9467
+ metadataRecord.refResolvedValue = derivedTxId;
9468
+ metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
9469
+ if (metadataRecord.localId) {
9470
+ try {
9471
+ await updateMetadata({
9472
+ localId: metadataRecord.localId,
9473
+ refResolvedValue: derivedTxId,
9474
+ localStorageDir: '/images',
9475
+ });
9476
+ }
9477
+ catch (e) {
9478
+ logger$j(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
9479
+ }
9480
+ }
9481
+ }
9482
+ }
8432
9483
  if (isImage && metadataRecord.refResolvedValue) {
8433
9484
  try {
8434
9485
  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
- }
9486
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9487
+ if (!filePath) {
9488
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9489
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9490
+ }
9491
+ if (filePath) {
9492
+ const file = await BaseFileManager.readFile(filePath);
9493
+ const freshBlobUrl = URL.createObjectURL(file);
9494
+ renderValue = freshBlobUrl;
9495
+ refResolvedDisplayValue = freshBlobUrl;
9496
+ }
9497
+ }
9498
+ catch (e) {
9499
+ logger$j(`Failed to resolve Image file for ${propertyName}: ${e}`);
9500
+ }
9501
+ }
9502
+ const isFile = refSeedType === 'file' ||
9503
+ normalizedDataType === 'File';
9504
+ if (isFile && metadataRecord.refResolvedValue) {
9505
+ try {
9506
+ const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
9507
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9508
+ if (!filePath) {
9509
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9510
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9511
+ }
9512
+ if (filePath) {
9513
+ renderValue = await BaseFileManager.readFileAsString(filePath);
8450
9514
  }
8451
9515
  }
8452
9516
  catch (e) {
8453
- logger$k(`Failed to resolve Image file for ${propertyName}: ${e}`);
9517
+ logger$j(`Failed to resolve File for ${propertyName}: ${e}`);
8454
9518
  }
8455
9519
  }
8456
9520
  let propertyValueOut = metadataRecord.propertyValue || undefined;
@@ -8482,7 +9546,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
8482
9546
  });
8483
9547
  };
8484
9548
  _loadOrCreateProperty().catch((error) => {
8485
- logger$k(`Error in loadOrCreateProperty: ${error}`);
9549
+ logger$j(`Error in loadOrCreateProperty: ${error}`);
8486
9550
  sendBack({
8487
9551
  type: 'loadOrCreatePropertyError',
8488
9552
  error: error instanceof Error ? error.message : String(error),
@@ -8512,10 +9576,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
8512
9576
  return queryRows[0];
8513
9577
  };
8514
9578
 
8515
- const logger$j = debug('seedSdk:write:updateItemPropertyValue');
9579
+ const logger$i = debug('seedSdk:write:updateItemPropertyValue');
8516
9580
  const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
8517
9581
  if (!localIdParam && !seedLocalId) {
8518
- logger$j(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
9582
+ logger$i(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
8519
9583
  return;
8520
9584
  }
8521
9585
  let safeNewValue = newValue;
@@ -8543,7 +9607,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8543
9607
  .select()
8544
9608
  .from(metadata$1)
8545
9609
  .where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
8546
- .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9610
+ .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8547
9611
  }
8548
9612
  }
8549
9613
  else if (localIdParam) {
@@ -8563,7 +9627,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8563
9627
  .select()
8564
9628
  .from(metadata$1)
8565
9629
  .where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
8566
- .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9630
+ .orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8567
9631
  }
8568
9632
  // const mostRecentRecordStatement = `SELECT local_id,
8569
9633
  // uid,
@@ -8579,7 +9643,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8579
9643
  // FROM metadata
8580
9644
  // WHERE property_name = '${propertyName}'
8581
9645
  // AND seed_local_id = '${seedLocalId}'
8582
- // ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
9646
+ // ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
8583
9647
  //
8584
9648
  // const { rows } = await runQueryForStatement(mostRecentRecordStatement)
8585
9649
  if (rows && rows.length > 0) {
@@ -8588,7 +9652,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8588
9652
  modelType === modelName?.toLowerCase() &&
8589
9653
  refSeedTypeFromDb === refSeedType &&
8590
9654
  refResolvedValueFromDb === refResolvedValue) {
8591
- logger$j(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
9655
+ logger$i(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
8592
9656
  return;
8593
9657
  }
8594
9658
  // This means we already have a local-only record so we should just update that one
@@ -8716,9 +9780,9 @@ const analyzeInput = xstate.fromCallback(({ sendBack, input: { context, event }
8716
9780
  }
8717
9781
  const _analyzeInput = async () => {
8718
9782
  // Use dynamic import to break circular dependency
8719
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
9783
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
8720
9784
  const { ModelPropertyDataTypes } = schemaMod;
8721
- const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
9785
+ const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
8722
9786
  let propertyName = propertyNameRaw;
8723
9787
  if (!propertyName) {
8724
9788
  throw new Error('propertyName is required');
@@ -8916,7 +9980,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8916
9980
  propertyRecordSchema?.validation &&
8917
9981
  metadataValues.propertyValue != null &&
8918
9982
  metadataValues.propertyValue !== '') {
8919
- const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-DCflhpcI.js'); });
9983
+ const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
8920
9984
  const validationService = new SchemaValidationService();
8921
9985
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
8922
9986
  if (!validationResult.isValid && validationResult.errors.length > 0) {
@@ -8994,8 +10058,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8994
10058
  return inserted[0];
8995
10059
  };
8996
10060
 
8997
- const eventEmitter = new EventEmitter();
8998
-
8999
10061
  const readFileAsArrayBuffer$1 = async (file) => {
9000
10062
  return new Promise((resolve) => {
9001
10063
  const reader = new FileReader();
@@ -9142,6 +10204,12 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
9142
10204
  }
9143
10205
  const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
9144
10206
  let newLocalId;
10207
+ const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
10208
+ ? schemaUid
10209
+ : (await getEasSchemaForItemProperty({
10210
+ propertyName,
10211
+ easDataType: 'bytes32',
10212
+ }))?.id;
9145
10213
  if (!localId) {
9146
10214
  const result = await createMetadata({
9147
10215
  propertyName,
@@ -9151,7 +10219,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
9151
10219
  versionLocalId,
9152
10220
  versionUid,
9153
10221
  modelName,
9154
- schemaUid: imageSchemaUid,
10222
+ schemaUid: resolvedPropertySchemaUid,
9155
10223
  refSeedType: 'image',
9156
10224
  refModelUid: imageSchemaUid,
9157
10225
  refResolvedValue: fileName,
@@ -9170,7 +10238,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
9170
10238
  seedLocalId,
9171
10239
  versionLocalId,
9172
10240
  modelName,
9173
- schemaUid,
10241
+ schemaUid: resolvedPropertySchemaUid,
9174
10242
  refSeedType: 'image',
9175
10243
  refResolvedValue: fileName,
9176
10244
  localStorageDir: '/images',
@@ -9503,7 +10571,7 @@ const saveRelation = xstate.fromCallback(({ sendBack, input: { context, event }
9503
10571
  }
9504
10572
  const _saveRelation = async () => {
9505
10573
  // Use dynamic import to break circular dependency
9506
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
10574
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
9507
10575
  const { ModelPropertyDataTypes } = schemaMod;
9508
10576
  if (!propertyNameRaw) {
9509
10577
  throw new Error('propertyName is required');
@@ -9712,6 +10780,10 @@ const propertyMachine = xstate.setup({
9712
10780
  context: {},
9713
10781
  input: {},
9714
10782
  },
10783
+ guards: {
10784
+ // stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
10785
+ propertyMachineIsIdle: xstate.stateIn('idle'),
10786
+ },
9715
10787
  // actions: {
9716
10788
  // updateContext: updateMachineContext,
9717
10789
  // },
@@ -9734,7 +10806,11 @@ const propertyMachine = xstate.setup({
9734
10806
  initial: 'waitingForDb',
9735
10807
  context: ({ input }) => input,
9736
10808
  on: {
9737
- // reload: '.hydratingFromDb',
10809
+ /** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
10810
+ rehydrateFromDb: {
10811
+ guard: 'propertyMachineIsIdle',
10812
+ target: '.hydratingFromDb',
10813
+ },
9738
10814
  save: {
9739
10815
  actions: xstate.assign({
9740
10816
  isSaving: true,
@@ -10333,6 +11409,8 @@ function createReactiveProxy(config) {
10333
11409
  return proxy;
10334
11410
  }
10335
11411
 
11412
+ /** Parent Html property `propertyValue` after publish (66-char seed uid). */
11413
+ const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
10336
11414
  // Start loading Model at module load time (non-blocking)
10337
11415
  Promise.resolve().then(function () { return Model$1; }).then(module => {
10338
11416
  module.Model;
@@ -10432,7 +11510,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
10432
11510
  };
10433
11511
  /** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
10434
11512
  const modelTypeToModelName = (modelType) => modelType ? lodashEs.upperFirst(lodashEs.camelCase(modelType)) : '';
10435
- const logger$i = debug('seedSdk:property:class');
11513
+ const logger$h = debug('seedSdk:property:class');
10436
11514
  // Define tracked properties for the Proxy
10437
11515
  // These properties will be read from/written to the actor context
10438
11516
  const TRACKED_PROPERTIES$2 = [
@@ -10514,7 +11592,7 @@ class ItemProperty {
10514
11592
  serviceInput.propertyValue = JSON.parse(propertyValue);
10515
11593
  }
10516
11594
  catch (e) {
10517
- logger$i('List property value is not JSON', e);
11595
+ logger$h('List property value is not JSON', e);
10518
11596
  }
10519
11597
  }
10520
11598
  }
@@ -10537,7 +11615,7 @@ class ItemProperty {
10537
11615
  return;
10538
11616
  }
10539
11617
  // Use dynamic import to break circular dependency
10540
- const schemaMod = await Promise.resolve().then(function () { return require('./index-DTkoTvcq.js'); });
11618
+ const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
10541
11619
  const { ModelPropertyDataTypes } = schemaMod;
10542
11620
  const { context } = snapshot;
10543
11621
  const { propertyRecordSchema } = context;
@@ -10560,7 +11638,8 @@ class ItemProperty {
10560
11638
  propertyRecordSchema.storageType === 'ItemStorage' &&
10561
11639
  context.refResolvedValue &&
10562
11640
  context.localStorageDir;
10563
- const isHtml = (context.refSeedType === 'html' || (propertyRecordSchema?.dataType === ModelPropertyDataTypes.Html)) &&
11641
+ const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
11642
+ const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
10564
11643
  context.refResolvedValue;
10565
11644
  // Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
10566
11645
  // so the UI can display the filename and preview immediately (these update again when save completes)
@@ -10596,7 +11675,11 @@ class ItemProperty {
10596
11675
  const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
10597
11676
  const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
10598
11677
  try {
10599
- const exists = await BaseFileManager.pathExists(filePath);
11678
+ let exists = await BaseFileManager.pathExists(filePath);
11679
+ if (!exists && isHtml) {
11680
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
11681
+ exists = await BaseFileManager.pathExists(filePath);
11682
+ }
10600
11683
  if (exists && (isItemStorage || isHtml)) {
10601
11684
  renderValue = await BaseFileManager.readFileAsString(filePath);
10602
11685
  }
@@ -10616,8 +11699,8 @@ class ItemProperty {
10616
11699
  if (isFile && isFileValue) {
10617
11700
  renderValue = pv.name;
10618
11701
  }
10619
- else if (isImage) {
10620
- // FS race / path not visible yet: do not clobber a hydrated blob URL with "No file found"
11702
+ else if (isImage || isHtml) {
11703
+ // FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
10621
11704
  renderValue = undefined;
10622
11705
  }
10623
11706
  else {
@@ -10626,13 +11709,21 @@ class ItemProperty {
10626
11709
  }
10627
11710
  }
10628
11711
  catch (e) {
10629
- logger$i(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
10630
- renderValue = 'No file found';
11712
+ logger$h(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
11713
+ renderValue = isHtml ? undefined : 'No file found';
10631
11714
  }
10632
11715
  }
10633
11716
  if (!renderValue) {
10634
11717
  renderValue = context.renderValue || context.propertyValue;
10635
11718
  }
11719
+ const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
11720
+ if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
11721
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
11722
+ renderValue === pvStr &&
11723
+ typeof context.renderValue === 'string' &&
11724
+ context.renderValue.length > pvStr.length) {
11725
+ renderValue = context.renderValue;
11726
+ }
10636
11727
  let transformedPropertyName = propertyName;
10637
11728
  const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
10638
11729
  if (!skipTransform && transformedPropertyName.endsWith('Id')) {
@@ -11045,6 +12136,35 @@ class ItemProperty {
11045
12136
  instance._service.send({ type: 'updateContext', ...updates });
11046
12137
  }
11047
12138
  }
12139
+ // After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
12140
+ // paths would hydrate. Re-run DB hydration without clobbering propertyValue.
12141
+ const svc = instance._service;
12142
+ const snap = svc.getSnapshot();
12143
+ if (snap.status === 'active' && snap.value === 'idle') {
12144
+ const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
12145
+ const dt = normalizeDataType(schema?.dataType);
12146
+ const isHtmlProp = props.refSeedType === 'html' ||
12147
+ ctx.refSeedType === 'html' ||
12148
+ dt === exports.ModelPropertyDataTypes.Html;
12149
+ const isListProp = dt === exports.ModelPropertyDataTypes.List;
12150
+ const isRelationProp = dt === exports.ModelPropertyDataTypes.Relation;
12151
+ const pv = ctx.propertyValue;
12152
+ const pvStr = typeof pv === 'string' ? pv.trim() : '';
12153
+ const renderVal = ctx.renderValue;
12154
+ const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
12155
+ const htmlStuckOnUid = isHtmlProp &&
12156
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
12157
+ (renderMissing || renderVal === pv);
12158
+ const pvPresent = pv != null &&
12159
+ (Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
12160
+ const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
12161
+ const versionChanged = props.versionLocalId != null &&
12162
+ ctx.versionLocalId != null &&
12163
+ props.versionLocalId !== ctx.versionLocalId;
12164
+ if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
12165
+ svc.send({ type: 'rehydrateFromDb' });
12166
+ }
12167
+ }
11048
12168
  // On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
11049
12169
  if (!waitForReady)
11050
12170
  return instance;
@@ -11394,7 +12514,7 @@ class ItemProperty {
11394
12514
  }
11395
12515
  async save() {
11396
12516
  const ctx = this._getSnapshotContext();
11397
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
12517
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
11398
12518
  await assertItemOwned({
11399
12519
  seedLocalId: ctx?.seedLocalId ?? undefined,
11400
12520
  seedUid: ctx?.seedUid ?? undefined,
@@ -11733,7 +12853,7 @@ class Item {
11733
12853
  });
11734
12854
  };
11735
12855
  this.unpublish = async () => {
11736
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
12856
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
11737
12857
  const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
11738
12858
  await assertItemOwned(this);
11739
12859
  const seedUid = this.seedUid;
@@ -11757,7 +12877,7 @@ class Item {
11757
12877
  this._service.send({ type: 'updateContext', revokedAt });
11758
12878
  };
11759
12879
  this.publish = async () => {
11760
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
12880
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
11761
12881
  await assertItemOwned(this);
11762
12882
  this._service.send({ type: 'startPublish' });
11763
12883
  return new Promise((resolve, reject) => {
@@ -11793,12 +12913,12 @@ class Item {
11793
12913
  };
11794
12914
  this.getPublishUploads = async (options) => {
11795
12915
  // Use dynamic import to break circular dependency
11796
- const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-DdVy-5fK.js'); });
12916
+ const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-CMpPR2JJ.js'); });
11797
12917
  const { getPublishUploads } = getPublishUploadsMod;
11798
12918
  return await getPublishUploads(this, [], undefined, options);
11799
12919
  };
11800
12920
  this.getPublishPayload = async (uploadedTransactions, options) => {
11801
- const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-DP2fm4q8.js'); });
12921
+ const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-C0hWIYCX.js'); });
11802
12922
  const { getPublishPayload } = getPublishPayloadMod;
11803
12923
  return await getPublishPayload(this, uploadedTransactions, options);
11804
12924
  };
@@ -11915,6 +13035,8 @@ class Item {
11915
13035
  'schemaUid',
11916
13036
  'latestVersionLocalId',
11917
13037
  'latestVersionUid',
13038
+ 'publishedVersionUid',
13039
+ 'publishedVersionLocalId',
11918
13040
  ];
11919
13041
  const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
11920
13042
  const schemaNameForModel = initialValues.schemaName;
@@ -11958,6 +13080,128 @@ class Item {
11958
13080
  });
11959
13081
  }
11960
13082
  }
13083
+ /** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
13084
+ static findItemInstanceCacheEntryByProps(props) {
13085
+ const l = props.seedLocalId;
13086
+ const u = props.seedUid;
13087
+ if (typeof l === 'string' && l.length > 0) {
13088
+ const e = this.instanceCache.get(l);
13089
+ if (e)
13090
+ return e;
13091
+ }
13092
+ if (typeof u === 'string' && u.length > 0) {
13093
+ const e = this.instanceCache.get(u);
13094
+ if (e)
13095
+ return e;
13096
+ }
13097
+ return undefined;
13098
+ }
13099
+ static findItemInstanceCacheEntryById(id) {
13100
+ const direct = this.instanceCache.get(id);
13101
+ if (direct)
13102
+ return direct;
13103
+ for (const [, entry] of this.instanceCache) {
13104
+ const ctx = entry.instance._getSnapshotContext();
13105
+ if (ctx.seedLocalId === id || ctx.seedUid === id)
13106
+ return entry;
13107
+ }
13108
+ return undefined;
13109
+ }
13110
+ static collectInstanceCacheKeysForInstance(instance) {
13111
+ const keys = [];
13112
+ for (const [k, v] of this.instanceCache) {
13113
+ if (v.instance === instance)
13114
+ keys.push(k);
13115
+ }
13116
+ return keys;
13117
+ }
13118
+ static registerItemInInstanceCache(instance) {
13119
+ const ctx = instance._getSnapshotContext();
13120
+ const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
13121
+ ? ctx.seedLocalId
13122
+ : undefined;
13123
+ const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
13124
+ const entry = { instance, refCount: 1 };
13125
+ if (lid)
13126
+ this.instanceCache.set(lid, entry);
13127
+ if (uid && uid !== lid)
13128
+ this.instanceCache.set(uid, entry);
13129
+ if (!lid && !uid) {
13130
+ throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
13131
+ }
13132
+ }
13133
+ static releaseItemInstanceCacheHold(instance) {
13134
+ const keys = this.collectInstanceCacheKeysForInstance(instance);
13135
+ if (keys.length === 0)
13136
+ return;
13137
+ const entry = this.instanceCache.get(keys[0]);
13138
+ entry.refCount -= 1;
13139
+ if (entry.refCount <= 0) {
13140
+ for (const k of keys) {
13141
+ this.instanceCache.delete(k);
13142
+ }
13143
+ }
13144
+ }
13145
+ /**
13146
+ * Item machine can reach `idle` before `propertyInstances` is merged (race) or while
13147
+ * child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
13148
+ */
13149
+ static async waitForItemInstanceReadyForRead(item, readyTimeout) {
13150
+ await waitForEntityIdle(item, { timeout: readyTimeout });
13151
+ const svc = item.getService();
13152
+ try {
13153
+ await xstate.waitFor(svc, (snap) => {
13154
+ if ('value' in snap && snap.value === 'error') {
13155
+ throw new Error('Entity failed to load');
13156
+ }
13157
+ if (!('value' in snap) || snap.value !== 'idle') {
13158
+ return false;
13159
+ }
13160
+ const ctx = snap.context || {};
13161
+ const versionsCount = ctx.versionsCount ?? 0;
13162
+ const hasHeadVersion = !!ctx.latestVersionLocalId;
13163
+ if (versionsCount === 0 && !hasHeadVersion) {
13164
+ return true;
13165
+ }
13166
+ return (ctx.propertyInstances?.size ?? 0) > 0;
13167
+ }, { timeout: readyTimeout });
13168
+ }
13169
+ catch (e) {
13170
+ if (e?.message === 'Entity failed to load') {
13171
+ throw e;
13172
+ }
13173
+ const msg = typeof e?.message === 'string' ? e.message : '';
13174
+ const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
13175
+ if (!isWaitForTimeout) {
13176
+ throw e;
13177
+ }
13178
+ }
13179
+ const snap = svc.getSnapshot();
13180
+ const pis = snap.context?.propertyInstances;
13181
+ if (!pis || pis.size === 0) {
13182
+ return;
13183
+ }
13184
+ await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
13185
+ timeout: readyTimeout,
13186
+ throwOnError: false,
13187
+ })));
13188
+ }
13189
+ static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
13190
+ const snap = instance.getService().getSnapshot();
13191
+ if (snap.value !== 'idle')
13192
+ return false;
13193
+ const mapSize = snap.context.propertyInstances?.size ?? 0;
13194
+ if (mapSize > 0)
13195
+ return false;
13196
+ const ctx = snap.context;
13197
+ const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
13198
+ const hasVersionHead = versionsCount > 0 ||
13199
+ !!props.latestVersionLocalId ||
13200
+ !!ctx.latestVersionLocalId ||
13201
+ !!props.latestVersionUid ||
13202
+ !!ctx.latestVersionUid;
13203
+ return hasVersionHead;
13204
+ }
11961
13205
  static async create(props, options) {
11962
13206
  const waitForReady = options?.waitForReady !== false;
11963
13207
  const readyTimeout = options?.readyTimeout ?? 5000;
@@ -11965,45 +13209,66 @@ class Item {
11965
13209
  props.modelName = lodashEs.startCase(props.type);
11966
13210
  }
11967
13211
  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;
13212
+ cacheReuse: {
13213
+ const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
13214
+ if (cachedEntry) {
13215
+ const instance = cachedEntry.instance;
13216
+ cachedEntry.refCount += 1;
13217
+ for (const [propertyName, propertyValue] of Object.entries(props)) {
13218
+ const snapshot = instance.getService().getSnapshot();
13219
+ const propertyInstances = snapshot.context.propertyInstances;
13220
+ if (!propertyInstances || !propertyInstances.has(propertyName)) {
13221
+ continue;
13222
+ }
13223
+ const propertyInstance = propertyInstances.get(propertyName);
13224
+ if (!propertyInstance) {
13225
+ continue;
13226
+ }
13227
+ propertyInstance.getService().send({
13228
+ type: 'updateContext',
13229
+ propertyValue,
13230
+ });
11984
13231
  }
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) {
13232
+ if (!waitForReady)
13233
+ return instance;
11996
13234
  try {
11997
- instance.unload();
13235
+ await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
11998
13236
  }
11999
- catch {
12000
- /* best-effort cache cleanup */
13237
+ catch (err) {
13238
+ try {
13239
+ instance.unload();
13240
+ }
13241
+ catch {
13242
+ /* best-effort cache cleanup */
13243
+ }
13244
+ throw err;
12001
13245
  }
12002
- throw err;
13246
+ if (waitForReady &&
13247
+ this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
13248
+ forceRemoveFromCaches(instance, {
13249
+ getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
13250
+ caches: [Item.instanceCache],
13251
+ });
13252
+ try {
13253
+ unloadEntity(instance, {
13254
+ getCacheKeys: () => [],
13255
+ caches: [],
13256
+ instanceState: itemInstanceState,
13257
+ getService: (inst) => inst._service,
13258
+ onUnload: (inst) => {
13259
+ inst._subscription?.unsubscribe();
13260
+ },
13261
+ });
13262
+ }
13263
+ catch {
13264
+ /* best-effort teardown for stale cached shell */
13265
+ }
13266
+ break cacheReuse;
13267
+ }
13268
+ return instance;
12003
13269
  }
12004
- return instance;
12005
13270
  }
12006
- if (!this.instanceCache.has(seedId)) {
13271
+ if (!this.findItemInstanceCacheEntryByProps(props)) {
12007
13272
  // Item no longer needs modelInstance - it loads properties from database independently
12008
13273
  // Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
12009
13274
  const { latestVersionUid, ...propsWithoutVersionUid } = props;
@@ -12092,14 +13357,11 @@ class Item {
12092
13357
  return Reflect.getOwnPropertyDescriptor(target, prop);
12093
13358
  },
12094
13359
  });
12095
- this.instanceCache.set(seedId, {
12096
- instance: proxiedInstance,
12097
- refCount: 1,
12098
- });
13360
+ this.registerItemInInstanceCache(proxiedInstance);
12099
13361
  if (!waitForReady)
12100
13362
  return proxiedInstance;
12101
13363
  try {
12102
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13364
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12103
13365
  }
12104
13366
  catch (err) {
12105
13367
  try {
@@ -12275,14 +13537,11 @@ class Item {
12275
13537
  return Reflect.getOwnPropertyDescriptor(target, prop);
12276
13538
  },
12277
13539
  });
12278
- this.instanceCache.set((proxiedInstance.seedUid || proxiedInstance.seedLocalId), {
12279
- instance: proxiedInstance,
12280
- refCount: 1,
12281
- });
13540
+ this.registerItemInInstanceCache(proxiedInstance);
12282
13541
  if (!waitForReady)
12283
13542
  return proxiedInstance;
12284
13543
  try {
12285
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13544
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12286
13545
  }
12287
13546
  catch (err) {
12288
13547
  try {
@@ -12305,14 +13564,10 @@ class Item {
12305
13564
  if (!id) {
12306
13565
  return null;
12307
13566
  }
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;
13567
+ const entry = this.findItemInstanceCacheEntryById(id);
13568
+ if (entry) {
13569
+ entry.refCount += 1;
13570
+ return entry.instance;
12316
13571
  }
12317
13572
  return null;
12318
13573
  }
@@ -12358,8 +13613,8 @@ class Item {
12358
13613
  if (!seedLocalId && !seedUid) {
12359
13614
  return undefined;
12360
13615
  }
12361
- // Use seedUid as primary ID if available, otherwise use seedLocalId
12362
- const id = seedUid || seedLocalId;
13616
+ // Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
13617
+ const id = seedLocalId || seedUid;
12363
13618
  if (!id) {
12364
13619
  return undefined;
12365
13620
  }
@@ -12390,10 +13645,127 @@ class Item {
12390
13645
  }));
12391
13646
  }
12392
13647
  if (waitForReady && itemInstances.length > 0) {
12393
- await Promise.all(itemInstances.map((item) => waitForEntityIdle(item, { timeout: readyTimeout })));
13648
+ await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
12394
13649
  }
12395
13650
  return lodashEs.orderBy(itemInstances, ['createdAt'], ['desc']);
12396
13651
  }
13652
+ /**
13653
+ * After EAS sync writes metadata for the latest version, merge new property instances and
13654
+ * re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
13655
+ * and useItems may not invalidate when the seed set is unchanged.
13656
+ */
13657
+ static async rehydrateCachedItemsFromDbAfterEasSync() {
13658
+ const appDb = BaseDb.getAppDb();
13659
+ if (!appDb || Item.instanceCache.size === 0) {
13660
+ return;
13661
+ }
13662
+ const { metadata } = await Promise.resolve().then(function () { return schema$1; });
13663
+ const { eq, and } = await import('drizzle-orm');
13664
+ const dedupedInstances = new Map();
13665
+ for (const entry of Item.instanceCache.values()) {
13666
+ dedupedInstances.set(entry.instance, entry);
13667
+ }
13668
+ const entries = [...dedupedInstances.values()];
13669
+ await Promise.all(entries.map(async ({ instance }) => {
13670
+ try {
13671
+ const svc = instance.getService();
13672
+ if (svc.getSnapshot().status !== 'active') {
13673
+ return;
13674
+ }
13675
+ const ctx = svc.getSnapshot().context;
13676
+ const seedLocalId = ctx.seedLocalId;
13677
+ const seedUid = ctx.seedUid;
13678
+ const versionLocalId = ctx.latestVersionLocalId;
13679
+ const itemModelName = ctx.modelName;
13680
+ const schemaNameForModel = ctx.schemaName;
13681
+ if (!seedLocalId || !versionLocalId || !itemModelName) {
13682
+ return;
13683
+ }
13684
+ const metadataRows = await appDb
13685
+ .select()
13686
+ .from(metadata)
13687
+ .where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
13688
+ let propertySchemas = {};
13689
+ try {
13690
+ const M = getModel();
13691
+ const model = schemaNameForModel !== undefined
13692
+ ? M?.getByName(itemModelName, schemaNameForModel)
13693
+ : M?.getByName(itemModelName);
13694
+ if (model?.properties?.length) {
13695
+ propertySchemas = modelPropertiesToObject(model.properties);
13696
+ }
13697
+ }
13698
+ catch {
13699
+ /* Model optional */
13700
+ }
13701
+ const sendToItemMachine = (event) => {
13702
+ if (svc.getSnapshot().status !== 'active') {
13703
+ return;
13704
+ }
13705
+ svc.send(event);
13706
+ };
13707
+ for (const metaRow of metadataRows) {
13708
+ try {
13709
+ let propertyName = metaRow.propertyName;
13710
+ const listSchemaKey = propertyName &&
13711
+ Object.keys(propertySchemas).length > 0 &&
13712
+ resolveStorageNameToSchemaName(propertySchemas, propertyName);
13713
+ if (listSchemaKey) {
13714
+ propertyName = listSchemaKey;
13715
+ }
13716
+ else {
13717
+ const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
13718
+ const refSeedType = metaRow.refSeedType;
13719
+ const isRefTypeFromMeta = refSeedType === 'file' ||
13720
+ refSeedType === 'image' ||
13721
+ refSeedType === 'relation' ||
13722
+ refSeedType === 'html';
13723
+ if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
13724
+ propertyName = baseName;
13725
+ }
13726
+ }
13727
+ if (!propertyName) {
13728
+ continue;
13729
+ }
13730
+ const property = await ItemProperty.find({
13731
+ propertyName,
13732
+ seedLocalId,
13733
+ seedUid,
13734
+ modelName: itemModelName,
13735
+ });
13736
+ if (property) {
13737
+ sendToItemMachine({
13738
+ type: 'addPropertyInstance',
13739
+ propertyName,
13740
+ propertyInstance: property,
13741
+ });
13742
+ }
13743
+ }
13744
+ catch {
13745
+ /* row skipped */
13746
+ }
13747
+ }
13748
+ const instances = svc.getSnapshot().context.propertyInstances;
13749
+ if (!instances) {
13750
+ return;
13751
+ }
13752
+ for (const propertyInstance of instances.values()) {
13753
+ try {
13754
+ const propertySnap = propertyInstance.getService().getSnapshot();
13755
+ if (xstate.isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
13756
+ propertyInstance.getService().send({ type: 'rehydrateFromDb' });
13757
+ }
13758
+ }
13759
+ catch {
13760
+ /* best-effort */
13761
+ }
13762
+ }
13763
+ }
13764
+ catch (e) {
13765
+ itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
13766
+ }
13767
+ }));
13768
+ }
12397
13769
  _createPropertyInstance(props) {
12398
13770
  if (this._storageTransactionId) {
12399
13771
  props.storageTransactionId = this._storageTransactionId;
@@ -13008,15 +14380,10 @@ class Item {
13008
14380
  }
13009
14381
  unload() {
13010
14382
  try {
13011
- const context = this._getSnapshotContext();
13012
- const cacheKey = context.seedUid || context.seedLocalId;
13013
- const cacheKeys = [];
13014
- if (cacheKey) {
13015
- cacheKeys.push(cacheKey);
13016
- }
14383
+ Item.releaseItemInstanceCacheHold(this);
13017
14384
  unloadEntity(this, {
13018
- getCacheKeys: () => cacheKeys,
13019
- caches: [Item.instanceCache],
14385
+ getCacheKeys: () => [],
14386
+ caches: [],
13020
14387
  instanceState: itemInstanceState,
13021
14388
  getService: (instance) => instance._service,
13022
14389
  onUnload: (instance) => {
@@ -13045,11 +14412,10 @@ class Item {
13045
14412
  * Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
13046
14413
  */
13047
14414
  async destroy() {
13048
- const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-DanM_n8E.js'); });
14415
+ const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
13049
14416
  await assertItemOwned(this);
13050
14417
  const context = this._getSnapshotContext();
13051
- const cacheKey = context.seedUid || context.seedLocalId;
13052
- const cacheKeys = cacheKey ? [cacheKey] : [];
14418
+ const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
13053
14419
  clearDestroySubscriptions(this, {
13054
14420
  instanceState: itemInstanceState,
13055
14421
  onUnload: (instance) => instance._subscription?.unsubscribe(),
@@ -13106,600 +14472,331 @@ function normalizeAddressConfig(addresses) {
13106
14472
  };
13107
14473
  }
13108
14474
 
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,
14475
+ let writeTail = Promise.resolve();
14476
+ function enqueueEasSyncDbWrite(fn) {
14477
+ const next = writeTail.then(fn);
14478
+ writeTail = next.catch(() => { });
14479
+ return next;
14480
+ }
14481
+ const MAX_ERROR_MESSAGE_LENGTH = 500;
14482
+ const MAX_ERROR_DETAILS_LENGTH = 2000;
14483
+ async function insertEasSyncProcessRow(params) {
14484
+ return enqueueEasSyncDbWrite(async () => {
14485
+ const db = BaseDb.getAppDb();
14486
+ if (!db) {
14487
+ throw new Error('[easSyncProcess] App DB not available');
14488
+ }
14489
+ const now = Date.now();
14490
+ const [row] = await db
14491
+ .insert(easSyncProcesses)
14492
+ .values({
14493
+ status: 'in_progress',
14494
+ startedAt: now,
14495
+ requestPayload: JSON.stringify(params.requestPayload),
14496
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14497
+ createdAt: now,
14498
+ updatedAt: now,
13128
14499
  })
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);
14500
+ .returning({ id: easSyncProcesses.id });
14501
+ return row.id;
14502
+ });
14503
+ }
14504
+ async function finalizeEasSyncProcessRow(id, params) {
14505
+ return enqueueEasSyncDbWrite(async () => {
14506
+ const db = BaseDb.getAppDb();
14507
+ if (!db) {
14508
+ return;
13165
14509
  }
13166
- return acc;
13167
- }, []);
13168
- return newUids;
13169
- };
14510
+ const now = Date.now();
14511
+ await db
14512
+ .update(easSyncProcesses)
14513
+ .set({
14514
+ status: params.status,
14515
+ completedAt: now,
14516
+ updatedAt: now,
14517
+ errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
14518
+ errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
14519
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14520
+ })
14521
+ .where(drizzleOrm.eq(easSyncProcesses.id, id));
14522
+ });
14523
+ }
13170
14524
 
13171
14525
  /**
13172
- * Sets revokedAt timestamp on a seed record after attestations have been revoked on EAS.
14526
+ * Merge multiple EAS sync intents: full sync (no concrete address list) wins;
14527
+ * otherwise union addresses (first-seen casing).
13173
14528
  */
13174
- const updateSeedRevokedAt = async ({ seedLocalId, revokedAt, }) => {
13175
- if (!seedLocalId) {
13176
- return;
14529
+ function mergeEasSyncRequestIntents(parts) {
14530
+ const norm = parts.filter((p) => p != null);
14531
+ if (norm.length === 0) {
14532
+ return {};
13177
14533
  }
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
- }
14534
+ let full = false;
14535
+ const addressMap = new Map();
14536
+ for (const p of norm) {
14537
+ if (!('addresses' in p) || p.addresses === undefined) {
14538
+ full = true;
14539
+ break;
14540
+ }
14541
+ for (const addr of p.addresses) {
14542
+ const k = addr.toLowerCase();
14543
+ if (!addressMap.has(k)) {
14544
+ addressMap.set(k, addr);
13215
14545
  }
13216
14546
  }
13217
14547
  }
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);
14548
+ if (full) {
14549
+ return {};
13261
14550
  }
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;
14551
+ if (addressMap.size === 0) {
14552
+ return { addresses: [] };
13321
14553
  }
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;
14554
+ return { addresses: [...addressMap.values()] };
14555
+ }
14556
+
14557
+ const log = debug('seedSdk:events:easSyncManager');
14558
+ function toRunSyncArg(options) {
14559
+ if (options &&
14560
+ 'addresses' in options &&
14561
+ options.addresses !== undefined) {
14562
+ return options;
13326
14563
  }
13327
- let parsedData;
14564
+ return undefined;
14565
+ }
14566
+ const runEasSync = xstate.fromPromise(async ({ input, }) => {
14567
+ const rowId = await insertEasSyncProcessRow({
14568
+ requestPayload: input.requestPayload,
14569
+ persistedSnapshot: input.runningSnapshot,
14570
+ });
14571
+ const { runSyncFromEas } = await Promise.resolve().then(function () { return require('./syncDbWithEas-DUi78csI.js'); });
13328
14572
  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(),
14573
+ await runSyncFromEas(toRunSyncArg(input.options));
14574
+ await finalizeEasSyncProcessRow(rowId, {
14575
+ status: 'completed',
14576
+ persistedSnapshot: {
14577
+ phase: 'completed',
14578
+ correlationIds: input.requestPayload.correlationIds,
14579
+ },
13384
14580
  });
13385
14581
  }
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,
14582
+ catch (err) {
14583
+ const message = err instanceof Error ? err.message : String(err);
14584
+ const details = err instanceof Error && err.stack
14585
+ ? err.stack.slice(0, 2000)
14586
+ : undefined;
14587
+ await finalizeEasSyncProcessRow(rowId, {
14588
+ status: 'failed',
14589
+ errorMessage: message,
14590
+ errorDetails: details,
14591
+ persistedSnapshot: {
14592
+ phase: 'failed',
14593
+ correlationIds: input.requestPayload.correlationIds,
14594
+ },
13461
14595
  });
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 };
14596
+ throw err;
14597
+ }
14598
+ });
14599
+ const initialContext = {
14600
+ runOptions: {},
14601
+ activeCorrelationIds: [],
14602
+ activePrimarySource: 'event_bus',
14603
+ pendingMergedOptions: undefined,
14604
+ pendingCorrelationIds: [],
14605
+ pendingPrimarySource: null,
14606
+ lastFinishedCorrelationIds: null,
14607
+ lastFinishedStatus: null,
14608
+ lastFinishedError: null,
13553
14609
  };
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),
14610
+ const easSyncMachine = xstate.setup({
14611
+ types: {
14612
+ context: {},
14613
+ events: {},
14614
+ },
14615
+ actors: {
14616
+ runEasSync,
14617
+ },
14618
+ }).createMachine({
14619
+ id: MachineIds.EAS_SYNC_MANAGER,
14620
+ initial: 'idle',
14621
+ context: initialContext,
14622
+ states: {
14623
+ idle: {
14624
+ on: {
14625
+ REQUEST: {
14626
+ target: 'running',
14627
+ actions: xstate.assign({
14628
+ runOptions: ({ event }) => event.options === undefined
14629
+ ? {}
14630
+ : mergeEasSyncRequestIntents([event.options]),
14631
+ activeCorrelationIds: ({ event }) => [event.correlationId],
14632
+ activePrimarySource: ({ event }) => event.source,
14633
+ }),
14634
+ },
14635
+ },
14636
+ },
14637
+ running: {
14638
+ on: {
14639
+ REQUEST: {
14640
+ actions: xstate.assign({
14641
+ pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
14642
+ context.runOptions,
14643
+ context.pendingMergedOptions,
14644
+ event.options === undefined ? {} : event.options,
14645
+ ].filter((x) => x != null)),
14646
+ pendingCorrelationIds: ({ context, event }) => [
14647
+ ...context.pendingCorrelationIds,
14648
+ event.correlationId,
14649
+ ],
14650
+ pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
14651
+ }),
14652
+ },
13561
14653
  },
13562
- },
13563
- });
13564
- await saveEasSeedsToDb({ itemSeeds });
13565
- const { itemVersions } = await easClient.request(GET_VERSIONS, {
13566
- where: {
13567
- refUID: {
13568
- in: Array.from(relatedSeedUids),
14654
+ invoke: {
14655
+ src: 'runEasSync',
14656
+ input: ({ context }) => ({
14657
+ options: context.runOptions,
14658
+ requestPayload: {
14659
+ source: context.activePrimarySource,
14660
+ correlationIds: context.activeCorrelationIds,
14661
+ options: context.runOptions,
14662
+ },
14663
+ runningSnapshot: {
14664
+ phase: 'running',
14665
+ correlationIds: context.activeCorrelationIds,
14666
+ },
14667
+ }),
14668
+ onDone: {
14669
+ target: 'afterRun',
14670
+ actions: xstate.assign({
14671
+ lastFinishedCorrelationIds: ({ context }) => [
14672
+ ...context.activeCorrelationIds,
14673
+ ],
14674
+ lastFinishedStatus: () => 'success',
14675
+ lastFinishedError: () => null,
14676
+ activeCorrelationIds: () => [],
14677
+ runOptions: () => ({}),
14678
+ }),
14679
+ },
14680
+ onError: {
14681
+ target: 'afterRun',
14682
+ actions: [
14683
+ xstate.assign({
14684
+ lastFinishedCorrelationIds: ({ context }) => [
14685
+ ...context.activeCorrelationIds,
14686
+ ],
14687
+ lastFinishedStatus: () => 'failed',
14688
+ lastFinishedError: ({ event }) => {
14689
+ const e = event.error;
14690
+ if (e instanceof Error) {
14691
+ return e.message;
14692
+ }
14693
+ return e != null ? String(e) : 'EAS sync failed';
14694
+ },
14695
+ activeCorrelationIds: () => [],
14696
+ runOptions: () => ({}),
14697
+ }),
14698
+ ({ event }) => {
14699
+ log('runEasSync error', event.error);
14700
+ },
14701
+ ],
14702
+ },
13569
14703
  },
13570
14704
  },
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
- },
14705
+ afterRun: {
14706
+ always: [
14707
+ {
14708
+ guard: ({ context }) => context.pendingCorrelationIds.length > 0,
14709
+ target: 'running',
14710
+ actions: xstate.assign({
14711
+ runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
14712
+ activeCorrelationIds: ({ context }) => [
14713
+ ...context.pendingCorrelationIds,
14714
+ ],
14715
+ activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
14716
+ pendingMergedOptions: () => undefined,
14717
+ pendingCorrelationIds: () => [],
14718
+ pendingPrimarySource: () => null,
14719
+ }),
14720
+ },
14721
+ { target: 'idle' },
14722
+ ],
13579
14723
  },
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) {
14724
+ },
14725
+ });
14726
+ const easSyncActor = xstate.createActor(easSyncMachine);
14727
+ let easSyncActorStarted = false;
14728
+ function startEasSyncActor() {
14729
+ if (easSyncActorStarted) {
13607
14730
  return;
13608
14731
  }
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;
14732
+ easSyncActorStarted = true;
14733
+ easSyncActor.start();
14734
+ }
14735
+ function newCorrelationId() {
14736
+ const c = globalThis.crypto;
14737
+ if (c?.randomUUID) {
14738
+ return c.randomUUID();
13645
14739
  }
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,
14740
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
14741
+ }
14742
+ function requestEasSyncFromEventBus() {
14743
+ startEasSyncActor();
14744
+ easSyncActor.send({
14745
+ type: 'REQUEST',
14746
+ correlationId: newCorrelationId(),
14747
+ source: 'event_bus',
13657
14748
  });
13658
- const { versionUids } = await saveEasVersionsToDb({
13659
- itemVersions,
14749
+ }
14750
+ function requestEasSyncFromAddressChange(addresses) {
14751
+ startEasSyncActor();
14752
+ easSyncActor.send({
14753
+ type: 'REQUEST',
14754
+ correlationId: newCorrelationId(),
14755
+ options: { addresses },
14756
+ source: 'address_change',
13660
14757
  });
13661
- const rawProperties = await getItemPropertiesFromEas({
13662
- versionUids,
13663
- excludeRevoked: false,
14758
+ }
14759
+ function requestEasSyncFromModelsInit() {
14760
+ startEasSyncActor();
14761
+ easSyncActor.send({
14762
+ type: 'REQUEST',
14763
+ correlationId: newCorrelationId(),
14764
+ source: 'models_init',
13664
14765
  });
13665
- const itemProperties = pickLatestPropertyAttestationsByRefAndSchema(rawProperties);
13666
- await saveEasPropertiesToDb({
13667
- itemProperties,
13668
- itemSeeds,
14766
+ }
14767
+ function sendEasSyncClientRequest(correlationId, options) {
14768
+ startEasSyncActor();
14769
+ easSyncActor.send({
14770
+ type: 'REQUEST',
14771
+ correlationId,
14772
+ options,
14773
+ source: 'client_api',
13669
14774
  });
13670
- await getRelatedSeedsAndVersions();
13671
- };
13672
- const syncDbWithEasHandler = lodashEs.throttle(async (_) => {
13673
- await runSyncFromEas();
13674
- }, 30000, {
13675
- leading: true,
13676
- trailing: false,
13677
- });
14775
+ }
13678
14776
 
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
- };
14777
+ var easSyncManager = /*#__PURE__*/Object.freeze({
14778
+ __proto__: null,
14779
+ easSyncActor: easSyncActor,
14780
+ easSyncMachine: easSyncMachine,
14781
+ requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
14782
+ requestEasSyncFromEventBus: requestEasSyncFromEventBus,
14783
+ requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
14784
+ sendEasSyncClientRequest: sendEasSyncClientRequest,
14785
+ startEasSyncActor: startEasSyncActor
14786
+ });
13690
14787
 
13691
14788
  /**
13692
14789
  * @deprecated Use BaseArweaveClient.setHost() instead.
13693
14790
  * This function is kept for backward compatibility but will be removed in a future version.
13694
14791
  */
13695
14792
  const setArweaveDomain = (newDomain) => {
13696
- BaseArweaveClient.setHost(newDomain);
14793
+ BaseArweaveClient.setPreferredReadGateway(newDomain);
13697
14794
  };
13698
14795
 
13699
- const logger$h = debug('seedSdk:services:events');
14796
+ const logger$g = debug('seedSdk:services:events');
13700
14797
  const handleServiceSaveState = (event) => {
13701
14798
  const { state, serviceId } = event;
13702
- logger$h(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
14799
+ logger$g(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
13703
14800
  // TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
13704
14801
  // localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
13705
14802
  };
@@ -13708,7 +14805,8 @@ const setupServicesEventHandlers = () => {
13708
14805
  };
13709
14806
 
13710
14807
  const setupAllItemsEventHandlers = () => {
13711
- eventEmitter.addListener('syncDbWithEas', syncDbWithEasHandler);
14808
+ startEasSyncActor();
14809
+ eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
13712
14810
  };
13713
14811
  // Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
13714
14812
 
@@ -13742,9 +14840,9 @@ class BasePathResolver {
13742
14840
  }
13743
14841
  }
13744
14842
 
13745
- const logger$g = debug('seedSdk:ClientManager:initialize');
14843
+ const logger$f = debug('seedSdk:ClientManager:initialize');
13746
14844
  const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, event } }) => {
13747
- logger$g('initialize from ClientManager');
14845
+ logger$f('initialize from ClientManager');
13748
14846
  const { isInitialized } = context;
13749
14847
  if (!event || !('options' in event)) {
13750
14848
  throw new Error('Initialize event must include options');
@@ -13867,11 +14965,14 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
13867
14965
  dbConfig,
13868
14966
  schemaFile,
13869
14967
  schema,
13870
- syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? false,
14968
+ syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
13871
14969
  } });
13872
14970
  if (arweaveDomain) {
13873
14971
  setArweaveDomain(arweaveDomain);
13874
14972
  }
14973
+ void ensureReadGatewaySelected().catch(() => {
14974
+ /* non-blocking warm-up for read gateway probe */
14975
+ });
13875
14976
  // Models are now Model instances, no registration needed
13876
14977
  // They should be created via Model.create() and are accessible via Model static methods
13877
14978
  setupAllItemsEventHandlers();
@@ -13907,15 +15008,15 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
13907
15008
  };
13908
15009
  });
13909
15010
 
13910
- const logger$f = debug('seedSdk:client:writeToDb');
13911
- const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } }) => {
15011
+ const logger$e = debug('seedSdk:client:writeToDb');
15012
+ const saveAppState = xstate.fromCallback(({ sendBack, input: { key, value } }) => {
13912
15013
  const _saveAppState = async () => {
13913
15014
  try {
13914
15015
  const appDb = BaseDb.getAppDb();
13915
15016
  if (!appDb) {
13916
15017
  // In test environments, continue anyway
13917
15018
  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');
15019
+ logger$e('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
13919
15020
  return;
13920
15021
  }
13921
15022
  throw new Error('App DB not found');
@@ -13931,13 +15032,13 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
13931
15032
  value: JSON.stringify(value),
13932
15033
  },
13933
15034
  });
13934
- logger$f('result', result);
15035
+ logger$e('result', result);
13935
15036
  }
13936
15037
  catch (error) {
13937
- logger$f('[client/actors] [saveAppState] Error saving app state:', error);
15038
+ logger$e('[client/actors] [saveAppState] Error saving app state:', error);
13938
15039
  // In test environments, continue anyway
13939
15040
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13940
- logger$f('[client/actors] [saveAppState] Continuing despite error in test environment');
15041
+ logger$e('[client/actors] [saveAppState] Continuing despite error in test environment');
13941
15042
  return;
13942
15043
  }
13943
15044
  throw error;
@@ -13952,10 +15053,10 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
13952
15053
  });
13953
15054
  })
13954
15055
  .catch((error) => {
13955
- logger$f('[client/actors] [saveAppState] Error in promise chain:', error);
15056
+ logger$e('[client/actors] [saveAppState] Error in promise chain:', error);
13956
15057
  // In test environments, still send success to allow state machine to progress
13957
15058
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13958
- logger$f('[client/actors] [saveAppState] Sending success despite error in test environment');
15059
+ logger$e('[client/actors] [saveAppState] Sending success despite error in test environment');
13959
15060
  sendBack({
13960
15061
  type: 'saveAppStateSuccess',
13961
15062
  key,
@@ -13968,222 +15069,6 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
13968
15069
  });
13969
15070
  });
13970
15071
 
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
15072
  let isInitialized = false;
14188
15073
  const fsInitHandler = async () => {
14189
15074
  if (isInitialized) {
@@ -14349,7 +15234,7 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
14349
15234
  }
14350
15235
  const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
14351
15236
  // 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.
15237
+ // modelUids will be populated async and EAS sync orchestrator runs when done.
14353
15238
  const fetchEasAndPopulateModelUids = async () => {
14354
15239
  try {
14355
15240
  const queryClient = BaseQueryClient.getQueryClient();
@@ -14382,7 +15267,8 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
14382
15267
  }
14383
15268
  }
14384
15269
  }
14385
- eventEmitter.emit('syncDbWithEas');
15270
+ const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
15271
+ requestEasSyncFromModelsInit();
14386
15272
  }
14387
15273
  else {
14388
15274
  logger$b('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
@@ -16724,16 +17610,19 @@ function addressesFromPersistedAddressValue(value) {
16724
17610
  return out;
16725
17611
  }
16726
17612
  function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
17613
+ const merged = addressesFromPersistedAddressValue(event.value);
16727
17614
  if (!context.syncFromEasOnAddressChange)
16728
17615
  return;
16729
17616
  if (event.key !== "addresses")
16730
17617
  return;
16731
- const merged = addressesFromPersistedAddressValue(event.value);
16732
17618
  if (merged.length === 0)
16733
17619
  return;
16734
- void runSyncFromEas({ addresses: merged }).catch((err) => {
16735
- logSyncAfterAddressSave("runSyncFromEas after address save failed", err);
16736
- });
17620
+ try {
17621
+ requestEasSyncFromAddressChange(merged);
17622
+ }
17623
+ catch (err) {
17624
+ logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
17625
+ }
16737
17626
  }
16738
17627
  function emitAddressesPersistedIfAddressesKey(event) {
16739
17628
  if (event.key !== "addresses")
@@ -16751,7 +17640,7 @@ const clientManagerMachine = xstate.setup({
16751
17640
  fileSystemInit,
16752
17641
  dbInit,
16753
17642
  saveConfig,
16754
- saveAppState: saveAppState$1,
17643
+ saveAppState,
16755
17644
  addModelsToStore,
16756
17645
  addModelsToDb,
16757
17646
  processSchemaFiles,
@@ -17075,7 +17964,16 @@ const clientInstance = {
17075
17964
  */
17076
17965
  syncFromEas: async (options) => {
17077
17966
  ensureInitialized();
17078
- await runSyncFromEas(options);
17967
+ startEasSyncActor();
17968
+ const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
17969
+ ? globalThis.crypto.randomUUID()
17970
+ : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
17971
+ sendEasSyncClientRequest(correlationId, options);
17972
+ await xstate.waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
17973
+ const snap = easSyncActor.getSnapshot();
17974
+ if (snap.context.lastFinishedStatus === 'failed') {
17975
+ throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
17976
+ }
17079
17977
  },
17080
17978
  addModel: async (modelDef) => {
17081
17979
  const db = await BaseDb.getAppDb();
@@ -17285,7 +18183,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
17285
18183
  // Lazy import cache for ModelProperty to avoid circular dependency
17286
18184
  // Eagerly start loading to minimize delay on first access
17287
18185
  let ModelPropertyClass = null;
17288
- const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-sNx_ZQZX.js'); })
18186
+ const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); })
17289
18187
  .then(module => {
17290
18188
  ModelPropertyClass = module.ModelProperty;
17291
18189
  return ModelPropertyClass;
@@ -17302,7 +18200,7 @@ function getModelProperty() {
17302
18200
  }
17303
18201
  // Lazy import cache for Schema to avoid circular dependency
17304
18202
  let SchemaClass = null;
17305
- const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-B4RRA-0g.js'); })
18203
+ const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); })
17306
18204
  .then(module => {
17307
18205
  SchemaClass = module.Schema;
17308
18206
  return SchemaClass;
@@ -19256,7 +20154,7 @@ class Db extends BaseDb {
19256
20154
  // You can inspect what will happen before applying
19257
20155
  await apply();
19258
20156
  this.db = db;
19259
- const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-DhAXAuSf.js'); });
20157
+ const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-LDYghZxU.js'); });
19260
20158
  await backfillMetadataPropertyIds();
19261
20159
  return this.db;
19262
20160
  }
@@ -19903,7 +20801,7 @@ const getTsImport = async (filePath) => {
19903
20801
 
19904
20802
  // Get the directory of this file to resolve relative paths
19905
20803
  // @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)));
20804
+ 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-Far6-WGM.js', document.baseURI).href)));
19907
20805
  path.dirname(__filename$1);
19908
20806
  const commandExists = (command) => {
19909
20807
  try {
@@ -20151,6 +21049,7 @@ QueryClient.getQueryClient = () => {
20151
21049
  reject(new Error('Not implemented'));
20152
21050
  });
20153
21051
  },
21052
+ removeQueries: async () => { },
20154
21053
  };
20155
21054
  };
20156
21055
  BaseQueryClient.setPlatformClass(QueryClient);
@@ -20365,23 +21264,30 @@ immer.enableMapSet();
20365
21264
 
20366
21265
  exports.BaseArweaveClient = BaseArweaveClient;
20367
21266
  exports.BaseDb = BaseDb;
21267
+ exports.BaseEasClient = BaseEasClient;
20368
21268
  exports.BaseFileManager = BaseFileManager;
20369
21269
  exports.BaseFileManager$1 = BaseFileManager$1;
20370
21270
  exports.BasePathResolver = BasePathResolver;
21271
+ exports.BaseQueryClient = BaseQueryClient;
20371
21272
  exports.Boolean = Boolean$1;
20372
21273
  exports.ClientManager = ClientManager;
20373
21274
  exports.ConflictError = ConflictError;
20374
21275
  exports.DEFAULT_TEXT_MAX_LENGTH = DEFAULT_TEXT_MAX_LENGTH;
20375
21276
  exports.Date = Date$1;
20376
21277
  exports.Db = Db;
21278
+ exports.EAS_SEED_DATA_SYNCED_TO_DB_EVENT = EAS_SEED_DATA_SYNCED_TO_DB_EVENT;
20377
21279
  exports.File = File$1;
20378
21280
  exports.FileManager = FileManager;
21281
+ exports.GET_PROPERTIES = GET_PROPERTIES;
21282
+ exports.GET_SEEDS = GET_SEEDS;
21283
+ exports.GET_VERSIONS = GET_VERSIONS;
20379
21284
  exports.Html = Html;
20380
21285
  exports.INIT_SCRIPT_SUCCESS_MESSAGE = INIT_SCRIPT_SUCCESS_MESSAGE;
20381
21286
  exports.INTERNAL_DATA_TYPES = INTERNAL_DATA_TYPES;
20382
21287
  exports.INTERNAL_PROPERTY_NAMES = INTERNAL_PROPERTY_NAMES;
20383
21288
  exports.Image = Image;
20384
21289
  exports.Item = Item;
21290
+ exports.Item$1 = Item$1;
20385
21291
  exports.ItemProperty = ItemProperty;
20386
21292
  exports.Json = Json;
20387
21293
  exports.List = List;
@@ -20422,12 +21328,14 @@ exports.createReactiveProxy = createReactiveProxy;
20422
21328
  exports.db = db;
20423
21329
  exports.defaultAttestationData = defaultAttestationData;
20424
21330
  exports.eas = eas;
21331
+ exports.escapeSqliteString = escapeSqliteString;
20425
21332
  exports.eventEmitter = eventEmitter;
20426
21333
  exports.findEntity = findEntity;
20427
21334
  exports.findSeedBinary = findSeedBinary;
20428
21335
  exports.forceRemoveFromCaches = forceRemoveFromCaches;
20429
21336
  exports.generateId = generateId;
20430
21337
  exports.generateModelCode = generateModelCode;
21338
+ exports.getAllAddressesFromDb = getAllAddressesFromDb;
20431
21339
  exports.getClient = getClient;
20432
21340
  exports.getContentHash = getContentHash;
20433
21341
  exports.getCorrectId = getCorrectId;
@@ -20436,14 +21344,18 @@ exports.getEasSchemaUidForModel = getEasSchemaUidForModel;
20436
21344
  exports.getEasSchemaUidForSchemaDefinition = getEasSchemaUidForSchemaDefinition;
20437
21345
  exports.getGetAdditionalSyncAddresses = getGetAdditionalSyncAddresses;
20438
21346
  exports.getItemData = getItemData;
21347
+ exports.getItemPropertiesFromEas = getItemPropertiesFromEas;
21348
+ exports.getItemVersionsFromEas = getItemVersionsFromEas;
20439
21349
  exports.getLatestPublishedVersionRow = getLatestPublishedVersionRow;
20440
21350
  exports.getLatestSchemaVersion = getLatestSchemaVersion;
20441
21351
  exports.getModelId = getModelId;
20442
21352
  exports.getModelIdByFileId = getModelIdByFileId;
21353
+ exports.getModelSchemasFromEas = getModelSchemasFromEas;
20443
21354
  exports.getOwnedAddressesFromDb = getOwnedAddressesFromDb;
20444
21355
  exports.getPropertyData = getPropertyData$1;
20445
21356
  exports.getPropertyIdForModelAndName = getPropertyIdForModelAndName;
20446
21357
  exports.getRefValueType = getRefValueType;
21358
+ exports.getSeedsFromSchemaUids = getSeedsFromSchemaUids;
20447
21359
  exports.getTsImport = getTsImport;
20448
21360
  exports.htmlEmbeddedImageCoPublish = htmlEmbeddedImageCoPublish;
20449
21361
  exports.importJsonSchema = importJsonSchema;
@@ -20460,8 +21372,10 @@ exports.modelUids = modelUids;
20460
21372
  exports.models = models$1;
20461
21373
  exports.normalizeDataType = normalizeDataType;
20462
21374
  exports.normalizeRelationPropertyValue = normalizeRelationPropertyValue;
21375
+ exports.parseEasRelationPropertyName = parseEasRelationPropertyName;
20463
21376
  exports.parseListPropertyValueFromStorage = parseListPropertyValueFromStorage;
20464
21377
  exports.parseMarkdownFrontmatter = parseMarkdownFrontmatter;
21378
+ exports.pickLatestPropertyAttestationsByRefAndSchema = pickLatestPropertyAttestationsByRefAndSchema;
20465
21379
  exports.processSeedConfig = processSeedConfig;
20466
21380
  exports.properties = properties;
20467
21381
  exports.readJsonImportFile = readJsonImportFile;
@@ -20470,10 +21384,12 @@ exports.resolveStorageNameToSchemaName = resolveStorageNameToSchemaName;
20470
21384
  exports.runDestroyLifecycle = runDestroyLifecycle;
20471
21385
  exports.runSeedInit = runSeedInit;
20472
21386
  exports.saveModelsFromMarkdown = saveModelsFromMarkdown;
21387
+ exports.scheduleBulkFilesDownloadFromEasSync = scheduleBulkFilesDownloadFromEasSync;
20473
21388
  exports.schema = schema$1;
20474
21389
  exports.schema$1 = schema;
20475
21390
  exports.schemas = schemas;
20476
21391
  exports.seeds = seeds;
21392
+ exports.setSchemaUidForSchemaDefinition = setSchemaUidForSchemaDefinition;
20477
21393
  exports.setupEntityLiveQuery = setupEntityLiveQuery;
20478
21394
  exports.syncSchemaFromSource = syncSchemaFromSource;
20479
21395
  exports.toSnakeCase = toSnakeCase;
@@ -20483,4 +21399,4 @@ exports.versions = versions;
20483
21399
  exports.waitForEntityIdle = waitForEntityIdle;
20484
21400
  exports.withSeed = withSeed;
20485
21401
  exports.writeProcessMachine = writeProcessMachine;
20486
- //# sourceMappingURL=index-D1qR8xnb.js.map
21402
+ //# sourceMappingURL=index-Far6-WGM.js.map