@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
@@ -1,4 +1,4 @@
1
- import { waitFor, fromCallback, fromPromise, setup, assign, createActor } from 'xstate';
1
+ import { waitFor, fromCallback, fromPromise, setup, assign, stateIn, createActor, isMachineSnapshot } from 'xstate';
2
2
  import { sqliteTable, integer, text, unique, int, blob, uniqueIndex } from 'drizzle-orm/sqlite-core';
3
3
  import { relations, and, eq, isNull, isNotNull, not, or, max, count, getTableColumns, sql, desc, inArray, gt } from 'drizzle-orm';
4
4
  import { customAlphabet } from 'nanoid';
@@ -8,9 +8,8 @@ import { ZeroAddress, getAddress } from 'ethers';
8
8
  import pluralize from 'pluralize';
9
9
  import { Type } from '@sinclair/typebox';
10
10
  import { toSnakeCase as toSnakeCase$1 } from 'drizzle-orm/casing';
11
- import { upperFirst, camelCase, startCase, orderBy, throttle } from 'lodash-es';
11
+ import { upperFirst, camelCase, startCase, throttle, orderBy } from 'lodash-es';
12
12
  import { BehaviorSubject } from 'rxjs';
13
- import EventEmitter from 'eventemitter3';
14
13
  import 'arweave';
15
14
  import * as sha3 from 'js-sha3';
16
15
 
@@ -157,6 +156,13 @@ class BaseFileManager {
157
156
  static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
158
157
  return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
159
158
  }
159
+ static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
160
+ return this.PlatformClass.downloadAllFiles({
161
+ transactionIds: [transactionId],
162
+ arweaveHost,
163
+ excludedTransactions,
164
+ });
165
+ }
160
166
  static resizeImage({ filePath, width, height }) {
161
167
  return this.PlatformClass.resizeImage({ filePath, width, height });
162
168
  }
@@ -365,12 +371,71 @@ var SeedModels;
365
371
  // Internal SDK schema that should not be created in app's files directory
366
372
  const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
367
373
  const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
368
- /** Default Arweave gateway host used across all packages */
369
- const DEFAULT_ARWEAVE_HOST = 'arweave.net';
374
+ /** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
375
+ const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
370
376
  /** Default Arweave gateway GraphQL endpoint (transaction / block queries). */
371
- const DEFAULT_ARWEAVE_GRAPHQL_URL = 'https://arweave.net/graphql';
372
- /** Default Arweave gateways for fallback / metadata fetching (ordered by preference) */
373
- const DEFAULT_ARWEAVE_GATEWAYS = ['arweave.net', 'ar-io.net'];
377
+ const DEFAULT_ARWEAVE_GRAPHQL_URL = `https://${DEFAULT_ARWEAVE_HOST}/graphql`;
378
+ /**
379
+ * Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
380
+ * Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
381
+ */
382
+ const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
383
+ const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
384
+ /** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
385
+ function getDefaultArweaveReadGatewayHostsOrdered() {
386
+ if (typeof process === 'undefined' || !process.env) {
387
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
388
+ }
389
+ for (const key of READ_GATEWAYS_ENV_KEYS) {
390
+ const raw = process.env[key]?.trim();
391
+ if (raw) {
392
+ return raw.split(',').map((s) => s.trim()).filter(Boolean);
393
+ }
394
+ }
395
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
396
+ }
397
+ /**
398
+ * Deduped host list: primary first, then each default not already present (case-insensitive).
399
+ */
400
+ function mergePrimaryHostWithDefaults(primary, defaults) {
401
+ const seen = new Set();
402
+ const out = [];
403
+ const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
404
+ const add = (h) => {
405
+ const t = h.trim().replace(/\/$/, '');
406
+ if (!t)
407
+ return;
408
+ const k = keyOf(t);
409
+ if (seen.has(k))
410
+ return;
411
+ seen.add(k);
412
+ out.push(t);
413
+ };
414
+ add(primary);
415
+ for (const d of defaults)
416
+ add(d);
417
+ return out;
418
+ }
419
+ /**
420
+ * True if `hostname` looks like a public Arweave gateway used in stored URLs (hydration / RSS).
421
+ */
422
+ function isKnownArweaveGatewayHostname(hostname) {
423
+ const h = hostname.trim().toLowerCase();
424
+ if (!h)
425
+ return false;
426
+ if (h.endsWith('arweave.net'))
427
+ return true;
428
+ if (h.endsWith('ar-io.net'))
429
+ return true;
430
+ for (const g of DEFAULT_ARWEAVE_GATEWAYS) {
431
+ const gl = g.toLowerCase();
432
+ if (h === gl || h.endsWith(`.${gl}`))
433
+ return true;
434
+ }
435
+ return false;
436
+ }
437
+ /** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
438
+ const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
374
439
  /**
375
440
  * Check if a schema is an internal SDK schema that should not be created in app files
376
441
  */
@@ -385,6 +450,7 @@ var constants = /*#__PURE__*/Object.freeze({
385
450
  DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
386
451
  DEFAULT_ARWEAVE_GRAPHQL_URL: DEFAULT_ARWEAVE_GRAPHQL_URL,
387
452
  DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
453
+ EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
388
454
  INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
389
455
  INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
390
456
  INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
@@ -402,7 +468,10 @@ var constants = /*#__PURE__*/Object.freeze({
402
468
  ZERO_BYTES: ZERO_BYTES,
403
469
  ZERO_BYTES32: ZERO_BYTES32,
404
470
  defaultAttestationData: defaultAttestationData,
405
- isInternalSchema: isInternalSchema
471
+ getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
472
+ isInternalSchema: isInternalSchema,
473
+ isKnownArweaveGatewayHostname: isKnownArweaveGatewayHostname,
474
+ mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
406
475
  });
407
476
 
408
477
  function parseGateway(input) {
@@ -419,6 +488,8 @@ function parseGateway(input) {
419
488
  let _host = DEFAULT_ARWEAVE_HOST;
420
489
  let _protocol = 'https';
421
490
  let _hostExplicitlySet = false;
491
+ /** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
492
+ let _suppressEnvGatewayOverride = false;
422
493
  class BaseArweaveClient {
423
494
  static setPlatformClass(platformClass) {
424
495
  this.PlatformClass = platformClass;
@@ -431,7 +502,7 @@ class BaseArweaveClient {
431
502
  const envHost = typeof process !== 'undefined' && process.env
432
503
  ? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
433
504
  : undefined;
434
- if (envHost && !_hostExplicitlySet) {
505
+ if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
435
506
  return parseGateway(envHost);
436
507
  }
437
508
  }
@@ -469,6 +540,39 @@ class BaseArweaveClient {
469
540
  _host = parsed.host;
470
541
  _protocol = parsed.protocol;
471
542
  _hostExplicitlySet = true;
543
+ _suppressEnvGatewayOverride = false;
544
+ }
545
+ /**
546
+ * When true, read-path gateway probing does not change the host ({@link setHost}).
547
+ */
548
+ static isReadGatewayLocked() {
549
+ return _hostExplicitlySet;
550
+ }
551
+ /**
552
+ * @internal Clears env override suppression after probing (for test isolation).
553
+ */
554
+ static resetReadGatewaySelectionStateForTests() {
555
+ _suppressEnvGatewayOverride = false;
556
+ }
557
+ /**
558
+ * Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
559
+ * Used for seed `arweaveDomain`.
560
+ */
561
+ static setPreferredReadGateway(host) {
562
+ const parsed = parseGateway(host);
563
+ _host = parsed.host;
564
+ _protocol = parsed.protocol;
565
+ _hostExplicitlySet = false;
566
+ }
567
+ /**
568
+ * Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
569
+ */
570
+ static applyProbedReadGateway(host) {
571
+ const parsed = parseGateway(host);
572
+ _host = parsed.host;
573
+ _protocol = parsed.protocol;
574
+ _hostExplicitlySet = false;
575
+ _suppressEnvGatewayOverride = true;
472
576
  }
473
577
  /**
474
578
  * Get the GraphQL endpoint URL
@@ -552,6 +656,11 @@ class BaseArweaveClient {
552
656
  }
553
657
  }
554
658
 
659
+ var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
660
+ __proto__: null,
661
+ BaseArweaveClient: BaseArweaveClient
662
+ });
663
+
555
664
  /**
556
665
  * Trim and strip a trailing slash from an upload API base URL.
557
666
  */
@@ -603,6 +712,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
603
712
  }
604
713
  }
605
714
 
715
+ const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
716
+ const PROBE_TIMEOUT_MS = 5000;
717
+ let readGatewayCache = null;
718
+ let ensureInFlight = null;
719
+ /** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
720
+ function invalidateReadGatewayCache() {
721
+ readGatewayCache = null;
722
+ ensureInFlight = null;
723
+ }
724
+ /** Clears probe cache, env override suppression, and preferred host (for tests). */
725
+ function resetArweaveReadGatewayForTests() {
726
+ invalidateReadGatewayCache();
727
+ BaseArweaveClient.resetReadGatewaySelectionStateForTests();
728
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
729
+ BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
730
+ }
731
+ }
732
+ /**
733
+ * GET /info with timeout. Treat 2xx + JSON object as healthy.
734
+ */
735
+ async function probeGateway(baseUrl, signal) {
736
+ const url = `${baseUrl.replace(/\/$/, '')}/info`;
737
+ let timer;
738
+ const controller = new AbortController();
739
+ const effectiveSignal = signal ?? controller.signal;
740
+ if (!signal) {
741
+ timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
742
+ }
743
+ try {
744
+ const response = await fetch(url, {
745
+ method: 'GET',
746
+ signal: effectiveSignal,
747
+ headers: { Accept: 'application/json' },
748
+ });
749
+ if (!response.ok)
750
+ return false;
751
+ const text = await response.text();
752
+ if (!text.trim())
753
+ return false;
754
+ try {
755
+ const json = JSON.parse(text);
756
+ return typeof json === 'object' && json !== null;
757
+ }
758
+ catch {
759
+ return false;
760
+ }
761
+ }
762
+ catch {
763
+ return false;
764
+ }
765
+ finally {
766
+ if (timer)
767
+ clearTimeout(timer);
768
+ }
769
+ }
770
+ async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
771
+ for (const host of hosts) {
772
+ const h = host.trim().replace(/\/$/, '');
773
+ if (!h)
774
+ continue;
775
+ const baseUrl = `${protocol}://${h}`;
776
+ if (await probeGateway(baseUrl, signal)) {
777
+ return h;
778
+ }
779
+ }
780
+ return null;
781
+ }
782
+ function buildOrderedHostsForProbe() {
783
+ const primary = BaseArweaveClient.getHost();
784
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
785
+ return mergePrimaryHostWithDefaults(primary, defaults);
786
+ }
787
+ /**
788
+ * Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
789
+ * No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
790
+ * Uses a short TTL cache to avoid probing on every read.
791
+ */
792
+ async function ensureReadGatewaySelected(signal) {
793
+ if (BaseArweaveClient.isReadGatewayLocked()) {
794
+ return BaseArweaveClient.getHost();
795
+ }
796
+ const now = Date.now();
797
+ if (readGatewayCache && now < readGatewayCache.expiresAt) {
798
+ return readGatewayCache.host;
799
+ }
800
+ if (ensureInFlight) {
801
+ return ensureInFlight;
802
+ }
803
+ ensureInFlight = (async () => {
804
+ const ordered = buildOrderedHostsForProbe();
805
+ const protocol = BaseArweaveClient.getProtocol();
806
+ const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
807
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
808
+ if (picked) {
809
+ BaseArweaveClient.applyProbedReadGateway(picked);
810
+ }
811
+ }
812
+ readGatewayCache = {
813
+ host: BaseArweaveClient.getHost(),
814
+ expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
815
+ };
816
+ return readGatewayCache.host;
817
+ })();
818
+ try {
819
+ return await ensureInFlight;
820
+ }
821
+ finally {
822
+ ensureInFlight = null;
823
+ }
824
+ }
825
+
826
+ var selectReadGateway = /*#__PURE__*/Object.freeze({
827
+ __proto__: null,
828
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
829
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
830
+ probeGateway: probeGateway,
831
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
832
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
833
+ });
834
+
606
835
  const GATEWAY_TX_QUERY = `
607
836
  query ArweaveGatewayTransaction($id: String!) {
608
837
  transaction(id: $id) {
@@ -699,6 +928,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
699
928
  return null;
700
929
  }
701
930
  }
931
+ /**
932
+ * Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
933
+ * {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
934
+ * {@link getDefaultArweaveReadGatewayHostsOrdered}.
935
+ */
936
+ async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
937
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
938
+ const trimmed = graphqlUrl?.trim();
939
+ let protocol = 'https';
940
+ let preferredHost = null;
941
+ if (trimmed) {
942
+ try {
943
+ const u = new URL(trimmed);
944
+ protocol = u.protocol === 'http:' ? 'http' : 'https';
945
+ preferredHost = u.hostname || null;
946
+ }
947
+ catch {
948
+ preferredHost = null;
949
+ }
950
+ }
951
+ const ordered = preferredHost && preferredHost.length > 0
952
+ ? mergePrimaryHostWithDefaults(preferredHost, defaults)
953
+ : [...defaults];
954
+ const signal = init?.signal;
955
+ for (const host of ordered) {
956
+ const base = `${protocol}://${host}`;
957
+ if (!(await probeGateway(base, signal ?? undefined)))
958
+ continue;
959
+ const gqlUrl = `${protocol}://${host}/graphql`;
960
+ const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
961
+ if (result !== null) {
962
+ return result;
963
+ }
964
+ }
965
+ return null;
966
+ }
702
967
 
703
968
  class BaseEasClient {
704
969
  static setPlatformClass(platformClass) {
@@ -1374,6 +1639,19 @@ const arweaveL1FinalizeJobs = sqliteTable('arweave_l1_finalize_jobs', {
1374
1639
  dataItemIdUnique: uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
1375
1640
  }));
1376
1641
 
1642
+ const easSyncProcesses = sqliteTable('eas_sync_processes', {
1643
+ id: int('id').primaryKey({ autoIncrement: true }),
1644
+ status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
1645
+ startedAt: int('started_at').notNull(),
1646
+ completedAt: int('completed_at'),
1647
+ requestPayload: text('request_payload').notNull(),
1648
+ errorMessage: text('error_message'),
1649
+ errorDetails: text('error_details'),
1650
+ persistedSnapshot: text('persisted_snapshot').notNull(),
1651
+ createdAt: int('created_at'),
1652
+ updatedAt: int('updated_at'),
1653
+ });
1654
+
1377
1655
  /**
1378
1656
  * Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
1379
1657
  * Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
@@ -1864,6 +2142,7 @@ var index = /*#__PURE__*/Object.freeze({
1864
2142
  capitalizeFirstLetter: capitalizeFirstLetter,
1865
2143
  classifyMediaRef: classifyMediaRef,
1866
2144
  convertTxIdToImage: convertTxIdToImage,
2145
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
1867
2146
  generateId: generateId,
1868
2147
  getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
1869
2148
  getArweaveUploadStatus: getArweaveUploadStatus,
@@ -1883,6 +2162,7 @@ var index = /*#__PURE__*/Object.freeze({
1883
2162
  getUploadExecutor: getUploadExecutor,
1884
2163
  getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
1885
2164
  identifyString: identifyString,
2165
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
1886
2166
  isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
1887
2167
  isBinary: isBinary,
1888
2168
  isPlaceholderUid: isPlaceholderUid,
@@ -1895,11 +2175,15 @@ var index = /*#__PURE__*/Object.freeze({
1895
2175
  normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
1896
2176
  parseEasRelationPropertyName: parseEasRelationPropertyName,
1897
2177
  pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
2178
+ probeGateway: probeGateway,
1898
2179
  queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
2180
+ queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
2181
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
1899
2182
  resolveMediaRef: resolveMediaRef,
1900
2183
  resolveMetadataRecord: resolveMetadataRecord,
1901
2184
  resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
1902
2185
  resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
2186
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
1903
2187
  setAdditionalSyncAddresses: setAdditionalSyncAddresses,
1904
2188
  setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
1905
2189
  setRevokeExecutor: setRevokeExecutor,
@@ -1922,7 +2206,7 @@ const createPropertyInstances = async (propertyFileIds) => {
1922
2206
  return;
1923
2207
  }
1924
2208
  try {
1925
- const mod = await import('./ModelProperty-DWtv9fQr.js');
2209
+ const mod = await import('./ModelProperty-D6JLRqQW.js');
1926
2210
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
1927
2211
  if (!ModelProperty) {
1928
2212
  logger$t('createPropertyInstances: ModelProperty not available from dynamic import');
@@ -2106,7 +2390,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
2106
2390
  // Step 2: Fallback to Schema context (only if database doesn't have the model)
2107
2391
  // This handles the case where model exists in schema file but not yet in database
2108
2392
  try {
2109
- const _mod_0 = await import('./Schema-CqqcEexA.js');
2393
+ const _mod_0 = await import('./Schema-B5_B8nM5.js');
2110
2394
  const _ns_0 = _mod_0.b;
2111
2395
  const schemaMod = _ns_0;
2112
2396
  const { Schema } = schemaMod;
@@ -2352,7 +2636,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
2352
2636
  }
2353
2637
  // Mark schema as draft when a new model is created so saveNewVersion() can persist it
2354
2638
  try {
2355
- const _mod_1 = await import('./Schema-CqqcEexA.js');
2639
+ const _mod_1 = await import('./Schema-B5_B8nM5.js');
2356
2640
  const _ns_1 = _mod_1.b;
2357
2641
  const schemaMod = _ns_1;
2358
2642
  const { Schema } = schemaMod;
@@ -2398,10 +2682,10 @@ const validateModel = fromCallback(({ sendBack, input: { context } }) => {
2398
2682
  const _validateModel = async () => {
2399
2683
  try {
2400
2684
  // Use dynamic imports to break circular dependencies
2401
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2685
+ const validationServiceMod = await import('./SchemaValidationService-DXYRdSYa.js');
2402
2686
  const { SchemaValidationService } = validationServiceMod;
2403
2687
  const validationService = new SchemaValidationService();
2404
- const _mod_2 = await import('./Schema-CqqcEexA.js');
2688
+ const _mod_2 = await import('./Schema-B5_B8nM5.js');
2405
2689
  const _ns_2 = _mod_2.b;
2406
2690
  const schemaMod = _ns_2;
2407
2691
  const { Schema } = schemaMod;
@@ -2513,7 +2797,7 @@ const createModelProperties = fromCallback(({ sendBack, input }) => {
2513
2797
  return;
2514
2798
  }
2515
2799
  logger$r(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
2516
- const mod = await import('./ModelProperty-DWtv9fQr.js');
2800
+ const mod = await import('./ModelProperty-D6JLRqQW.js');
2517
2801
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
2518
2802
  if (!ModelProperty) {
2519
2803
  logger$r('ModelProperty not available from dynamic import');
@@ -2617,7 +2901,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2617
2901
  const structureMsg = `[validateEntity] Validating model structure`;
2618
2902
  logger$q(structureMsg);
2619
2903
  // Use existing Model validation
2620
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2904
+ const validationServiceMod = await import('./SchemaValidationService-DXYRdSYa.js');
2621
2905
  const { SchemaValidationService } = validationServiceMod;
2622
2906
  const validationService = new SchemaValidationService();
2623
2907
  // Validate model structure
@@ -2635,7 +2919,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2635
2919
  if (entityInput.entityData.schemaName) {
2636
2920
  try {
2637
2921
  logger$q(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
2638
- const _mod_3 = await import('./Schema-CqqcEexA.js');
2922
+ const _mod_3 = await import('./Schema-B5_B8nM5.js');
2639
2923
  const _ns_3 = _mod_3.b;
2640
2924
  const schemaMod = _ns_3;
2641
2925
  const { Schema } = schemaMod;
@@ -2673,7 +2957,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2673
2957
  }
2674
2958
  else if (entityInput.entityType === 'modelProperty') {
2675
2959
  // Use existing ModelProperty validation
2676
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2960
+ const validationServiceMod = await import('./SchemaValidationService-DXYRdSYa.js');
2677
2961
  const { SchemaValidationService } = validationServiceMod;
2678
2962
  const validationService = new SchemaValidationService();
2679
2963
  // Validate property structure
@@ -2688,7 +2972,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2688
2972
  // If schema name and model name provided, validate against schema
2689
2973
  if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
2690
2974
  try {
2691
- const _mod_4 = await import('./Schema-CqqcEexA.js');
2975
+ const _mod_4 = await import('./Schema-B5_B8nM5.js');
2692
2976
  const _ns_4 = _mod_4.b;
2693
2977
  const schemaMod = _ns_4;
2694
2978
  const { Schema } = schemaMod;
@@ -2719,7 +3003,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2719
3003
  }
2720
3004
  else if (entityInput.entityType === 'schema') {
2721
3005
  // Schema validation - use existing validation
2722
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
3006
+ const validationServiceMod = await import('./SchemaValidationService-DXYRdSYa.js');
2723
3007
  const { SchemaValidationService } = validationServiceMod;
2724
3008
  const validationService = new SchemaValidationService();
2725
3009
  const schemaResult = validationService.validateSchema(entityInput.entityData);
@@ -4671,7 +4955,7 @@ const writeToDatabase = fromCallback(({ sendBack, input }) => {
4671
4955
  // initial write completes is not overwritten by the stale requestWrite payload.
4672
4956
  let dataToWrite = input.entityData;
4673
4957
  try {
4674
- const mod = await import('./ModelProperty-DWtv9fQr.js');
4958
+ const mod = await import('./ModelProperty-D6JLRqQW.js');
4675
4959
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
4676
4960
  if (ModelProperty && typeof ModelProperty.getById === 'function') {
4677
4961
  const instance = ModelProperty.getById(input.entityId);
@@ -5051,7 +5335,7 @@ const modelMachine = setup({
5051
5335
  // Create ModelProperty instances for any new property IDs
5052
5336
  if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
5053
5337
  // Import and create instances asynchronously (fire-and-forget)
5054
- import('./ModelProperty-DWtv9fQr.js').then(({ ModelProperty }) => {
5338
+ import('./ModelProperty-D6JLRqQW.js').then(({ ModelProperty }) => {
5055
5339
  const createPromises = newPropertyIds.map(async (propertyFileId) => {
5056
5340
  try {
5057
5341
  const property = await ModelProperty.createById(propertyFileId);
@@ -5354,6 +5638,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
5354
5638
  var MachineIds;
5355
5639
  (function (MachineIds) {
5356
5640
  MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
5641
+ MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
5357
5642
  MachineIds["GLOBAL"] = "@seedSdk/global";
5358
5643
  MachineIds["INTERNAL"] = "@seedSdk/internal";
5359
5644
  MachineIds["EAS"] = "@seedSdk/eas";
@@ -5426,7 +5711,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
5426
5711
  * This constant is kept for backward compatibility but will be removed in a future version.
5427
5712
  * Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
5428
5713
  */
5429
- ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'arweave.net';
5714
+ ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
5430
5715
 
5431
5716
  debug('seedSdk:item:service:actors:waitForDb');
5432
5717
  const waitForDb$1 = fromCallback(({ sendBack }) => {
@@ -6347,7 +6632,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
6347
6632
  rowNum: sql.raw(`
6348
6633
  ROW_NUMBER() OVER (
6349
6634
  PARTITION BY property_name
6350
- ORDER BY COALESCE(attestation_created_at, created_at) DESC
6635
+ ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
6351
6636
  )
6352
6637
  `).as('rowNum')
6353
6638
  })
@@ -6360,6 +6645,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
6360
6645
  getMetadataLatest: getMetadataLatest
6361
6646
  });
6362
6647
 
6648
+ /**
6649
+ * Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
6650
+ * `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
6651
+ */
6652
+ function metadataLatestFirstSortKey(row) {
6653
+ return {
6654
+ t: row.attestationCreatedAt ?? row.createdAt ?? 0,
6655
+ localId: String(row.localId ?? ''),
6656
+ };
6657
+ }
6658
+ /** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
6659
+ function compareMetadataRowsLatestFirst(a, b) {
6660
+ const ka = metadataLatestFirstSortKey(a);
6661
+ const kb = metadataLatestFirstSortKey(b);
6662
+ if (kb.t !== ka.t)
6663
+ return kb.t - ka.t;
6664
+ return kb.localId.localeCompare(ka.localId);
6665
+ }
6666
+
6363
6667
  const logger$l = debug('seedSdk:item:actors:loadOrCreateItem');
6364
6668
  /**
6365
6669
  * Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
@@ -6401,9 +6705,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
6401
6705
  return b;
6402
6706
  if (sa !== sb)
6403
6707
  return sa > sb ? a : b;
6404
- const ta = a.attestationCreatedAt ?? a.createdAt ?? 0;
6405
- const tb = b.attestationCreatedAt ?? b.createdAt ?? 0;
6406
- return ta >= tb ? a : b;
6708
+ const cmp = compareMetadataRowsLatestFirst(a, b);
6709
+ return cmp < 0 ? a : b;
6407
6710
  }
6408
6711
  function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
6409
6712
  const byKey = new Map();
@@ -6451,7 +6754,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6451
6754
  const schemaNameToTry = model$1?.schemaName;
6452
6755
  if (schemaNameToTry) {
6453
6756
  try {
6454
- const _mod_5 = await import('./Schema-CqqcEexA.js');
6757
+ const _mod_5 = await import('./Schema-B5_B8nM5.js');
6455
6758
  const _ns_5 = _mod_5.b;
6456
6759
  const { Schema } = _ns_5;
6457
6760
  const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
@@ -6502,7 +6805,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6502
6805
  }
6503
6806
  }
6504
6807
  if (Object.keys(propertySchemas).length === 0) {
6505
- const schemaMod = await import('./index-Cqf_DxkJ.js');
6808
+ const schemaMod = await import('./index-DB3nZ0lK.js');
6506
6809
  const { ModelPropertyDataTypes } = schemaMod;
6507
6810
  const KNOWN_MODEL_FALLBACKS = {
6508
6811
  Post: {
@@ -6549,7 +6852,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6549
6852
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
6550
6853
  let propSchema = propertySchemas[propertyName];
6551
6854
  if (!propSchema && isRefTypeFromMeta) {
6552
- const schemaMod = await import('./index-Cqf_DxkJ.js');
6855
+ const schemaMod = await import('./index-DB3nZ0lK.js');
6553
6856
  const { ModelPropertyDataTypes } = schemaMod;
6554
6857
  propSchema = {
6555
6858
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -6806,9 +7109,9 @@ const runPublish = fromCallback(({ sendBack, input: { context } }) => {
6806
7109
  sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
6807
7110
  return;
6808
7111
  }
6809
- const getPublishUploadsMod = await import('./getPublishUploads-DS2dQ4Ho.js');
7112
+ const getPublishUploadsMod = await import('./getPublishUploads-CH72lAID.js');
6810
7113
  const { getPublishUploads } = getPublishUploadsMod;
6811
- const getPublishPayloadMod = await import('./getPublishPayload-DpYwi-rd.js');
7114
+ const getPublishPayloadMod = await import('./getPublishPayload-DEdHgrgC.js');
6812
7115
  const { getPublishPayload } = getPublishPayloadMod;
6813
7116
  const uploads = await getPublishUploads(item);
6814
7117
  let uploadedTransactions = [];
@@ -7154,6 +7457,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
7154
7457
  return rows[0];
7155
7458
  };
7156
7459
 
7460
+ var getSeedData$1 = /*#__PURE__*/Object.freeze({
7461
+ __proto__: null,
7462
+ getSeedData: getSeedData
7463
+ });
7464
+
7157
7465
  /**
7158
7466
  * Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
7159
7467
  * Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
@@ -7643,7 +7951,7 @@ const resolveRelatedValue = fromCallback(({ sendBack, input: { context } }) => {
7643
7951
  const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
7644
7952
  const _resolveRelatedValue = async () => {
7645
7953
  // Use dynamic import to break circular dependency
7646
- const schemaMod = await import('./index-Cqf_DxkJ.js');
7954
+ const schemaMod = await import('./index-DB3nZ0lK.js');
7647
7955
  const { ModelPropertyDataTypes } = schemaMod;
7648
7956
  if (!propertyValue || !isRelation || populatedFromDb) {
7649
7957
  return;
@@ -8006,155 +8314,826 @@ function parseListPropertyValueFromStorage(raw) {
8006
8314
  return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
8007
8315
  }
8008
8316
 
8009
- // Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
8010
- // import { ModelPropertyDataTypes } from '@/schema'
8011
- const logger$g = debug('seedSdk:property:actors:hydrateFromDb');
8012
- const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8013
- const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
8014
- if (!propertyNameRaw) {
8015
- throw new Error('propertyName is required');
8317
+ class SeedEventEmitter {
8318
+ constructor() {
8319
+ this.listeners = new Map();
8016
8320
  }
8017
- let propertyName = propertyNameRaw;
8018
- // Note: isRelation, isImage, isFile checks moved inside async function
8019
- // to use dynamically imported ModelPropertyDataTypes
8020
- const _hydrateFromDb = async () => {
8021
- // Use dynamic import to break circular dependency
8022
- const schemaMod = await import('./index-Cqf_DxkJ.js');
8023
- const { ModelPropertyDataTypes } = schemaMod;
8024
- const appDb = BaseDb.getAppDb();
8025
- const whereClauses = [];
8026
- // Re-check types with dynamically imported ModelPropertyDataTypes
8027
- // Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
8028
- const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
8029
- const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
8030
- propertyRecordSchema &&
8031
- propertyRecordSchema.ref &&
8032
- normalizedDataType === ModelPropertyDataTypes.Relation;
8033
- const isImageDynamic = propertyRecordSchema &&
8034
- (normalizedDataType === ModelPropertyDataTypes.Image ||
8035
- normalizedRefValueType === ModelPropertyDataTypes.Image);
8036
- propertyRecordSchema &&
8037
- normalizedDataType === ModelPropertyDataTypes.File;
8038
- const isHtmlDynamic = propertyRecordSchema &&
8039
- normalizedDataType === ModelPropertyDataTypes.Html;
8040
- // Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
8041
- const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
8042
- whereClauses.push(propertyNames.length > 1
8043
- ? or(...propertyNames.map((n) => eq(metadata$1.propertyName, n)))
8044
- : eq(metadata$1.propertyName, propertyNames[0]));
8045
- if (seedUid) {
8046
- whereClauses.push(eq(metadata$1.seedUid, seedUid));
8047
- }
8048
- if (seedLocalId) {
8049
- whereClauses.push(eq(metadata$1.seedLocalId, seedLocalId));
8050
- }
8051
- const rows = await appDb
8052
- .select()
8053
- .from(metadata$1)
8054
- .where(and(...whereClauses))
8055
- .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
8056
- if (!rows || !rows.length) {
8057
- return;
8058
- }
8059
- const firstRow = rows[0];
8060
- const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
8061
- let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
8062
- let propertyValueProcessed = propertyValueFromDb;
8063
- // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
8064
- if (isImageDynamic) {
8065
- let dir = localStorageDir;
8066
- if (!dir && isImageDynamic) {
8067
- dir = 'images';
8068
- }
8069
- dir = dir.replace(/^\//, '');
8070
- if (propertyValueFromDb &&
8071
- propertyValueFromDb.length === 66) {
8072
- // Here the storageTransactionId is stored on a different record and
8073
- // we want to add it as the refResolvedValue
8074
- const storageTransactionQuery = await appDb
8075
- .select({
8076
- propertyValue: metadata$1.propertyValue,
8077
- })
8078
- .from(metadata$1)
8079
- .where(and(eq(metadata$1.seedUid, propertyValueFromDb), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))));
8080
- if (storageTransactionQuery && storageTransactionQuery.length > 0) {
8081
- const row = storageTransactionQuery[0];
8082
- refResolvedValue = row.propertyValue;
8083
- await updateMetadata({
8084
- localId,
8085
- refResolvedValue,
8086
- localStorageDir: '/images',
8087
- });
8088
- }
8089
- }
8090
- if (refResolvedValue) {
8091
- try {
8092
- const dirPath = BaseFileManager.getFilesPath(dir);
8093
- const dirExists = await BaseFileManager.pathExists(dirPath);
8094
- if (dirExists) {
8095
- const fs = await BaseFileManager.getFs();
8096
- const path = BaseFileManager.getPathModule();
8097
- const files = await fs.promises.readdir(dirPath);
8098
- const matchingFiles = files.filter((file) => {
8099
- return path.basename(file).includes(refResolvedValue);
8100
- });
8101
- let fileExists = false;
8102
- let filename;
8103
- let filePath;
8104
- if (matchingFiles && matchingFiles.length > 0) {
8105
- fileExists = true;
8106
- filename = matchingFiles[0];
8107
- filePath = BaseFileManager.getFilesPath(dir, filename);
8108
- }
8109
- localStorageDir = `/${dir}`;
8110
- if (fileExists && filename && filePath) {
8111
- const file = await BaseFileManager.readFile(filePath);
8112
- refResolvedDisplayValue = URL.createObjectURL(file);
8113
- // Do not persist blob URL - it is session-scoped
8114
- }
8115
- }
8116
- }
8117
- catch (e) {
8118
- logger$g('[hydrateFromDb] Image file resolution error', e);
8119
- }
8120
- }
8121
- }
8122
- if (propertyRecordSchema &&
8123
- normalizedDataType === ModelPropertyDataTypes.List &&
8124
- typeof propertyValueFromDb === 'string') {
8125
- propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
8321
+ on(event, listener) {
8322
+ const set = this.listeners.get(event) ?? new Set();
8323
+ set.add(listener);
8324
+ this.listeners.set(event, set);
8325
+ return this;
8326
+ }
8327
+ addListener(event, listener) {
8328
+ return this.on(event, listener);
8329
+ }
8330
+ once(event, listener) {
8331
+ const wrapped = (...args) => {
8332
+ this.off(event, wrapped);
8333
+ listener(...args);
8334
+ };
8335
+ return this.on(event, wrapped);
8336
+ }
8337
+ off(event, listener) {
8338
+ const set = this.listeners.get(event);
8339
+ if (!set)
8340
+ return this;
8341
+ set.delete(listener);
8342
+ if (set.size === 0)
8343
+ this.listeners.delete(event);
8344
+ return this;
8345
+ }
8346
+ removeListener(event, listener) {
8347
+ return this.off(event, listener);
8348
+ }
8349
+ removeAllListeners(event) {
8350
+ if (typeof event === 'undefined') {
8351
+ this.listeners.clear();
8352
+ return this;
8353
+ }
8354
+ this.listeners.delete(event);
8355
+ return this;
8356
+ }
8357
+ emit(event, ...args) {
8358
+ const set = this.listeners.get(event);
8359
+ if (!set || set.size === 0)
8360
+ return false;
8361
+ for (const listener of [...set]) {
8362
+ listener(...args);
8126
8363
  }
8127
- sendBack({
8128
- type: 'updateContext',
8129
- localId,
8130
- uid,
8131
- propertyValue: propertyValueProcessed,
8132
- seedLocalId: seedLocalIdFromDb,
8133
- seedUid: seedUidFromDb,
8134
- versionLocalId: versionLocalIdFromDb,
8135
- versionUid: versionUidFromDb,
8136
- schemaUid: schemaUidFromDb,
8137
- refValueType,
8138
- localStorageDir,
8139
- refResolvedValue,
8140
- refResolvedDisplayValue,
8141
- renderValue: refResolvedDisplayValue,
8142
- populatedFromDb: true,
8143
- });
8144
- if (propertyRecordSchema &&
8145
- propertyRecordSchema.storageType &&
8146
- propertyRecordSchema.storageType === 'ItemStorage') {
8147
- const itemMod = await Promise.resolve().then(function () { return Item$1; });
8148
- const { Item } = itemMod;
8149
- const item = await Item.find({
8150
- seedLocalId: seedLocalId ?? undefined,
8151
- modelName,
8152
- });
8153
- if (item) {
8154
- const dir = localStorageDir?.replace(/^\//, '') || 'files';
8155
- const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
8156
- const exists = await BaseFileManager.pathExists(filePath);
8157
- if (!exists) {
8364
+ return true;
8365
+ }
8366
+ }
8367
+ const eventEmitter = new SeedEventEmitter();
8368
+
8369
+ const GET_FILES_METADATA = graphql(/* GraphQL */ `
8370
+ query GetFilesMetadata($where: AttestationWhereInput!) {
8371
+ filesMetadata: attestations(
8372
+ where: $where
8373
+ orderBy: [{ timeCreated: desc }]
8374
+ ) {
8375
+ ...attestationFields
8376
+ }
8377
+ }
8378
+ `);
8379
+
8380
+ const getMetadata = async (props) => {
8381
+ const appDb = BaseDb.getAppDb();
8382
+ let storageTransactionId;
8383
+ if (props) {
8384
+ storageTransactionId = props.storageTransactionId;
8385
+ }
8386
+ const whereClauses = [];
8387
+ if (storageTransactionId) {
8388
+ whereClauses.push(eq(metadata$1.propertyName, 'storageTransactionId'));
8389
+ whereClauses.push(eq(metadata$1.propertyValue, storageTransactionId));
8390
+ }
8391
+ const metadataRows = await appDb
8392
+ .select()
8393
+ .from(metadata$1)
8394
+ .where(and(...whereClauses));
8395
+ if (!metadataRows || metadataRows.length === 0) {
8396
+ return;
8397
+ }
8398
+ return metadataRows[0];
8399
+ };
8400
+
8401
+ const saveMetadata = async (metadataRecord, metadataValues) => {
8402
+ if (!metadataRecord.localId) {
8403
+ return;
8404
+ }
8405
+ const appDb = BaseDb.getAppDb();
8406
+ await appDb
8407
+ .update(metadata$1)
8408
+ .set({
8409
+ ...metadataValues,
8410
+ updatedAt: Date.now(),
8411
+ })
8412
+ .where(eq(metadata$1.localId, metadataRecord.localId));
8413
+ };
8414
+
8415
+ const isNode = () => {
8416
+ return (typeof process !== 'undefined' &&
8417
+ process.versions != null &&
8418
+ process.versions.node != null);
8419
+ };
8420
+ const isBrowser = () => {
8421
+ return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
8422
+ };
8423
+ const isElectron = () => {
8424
+ return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
8425
+ };
8426
+ /**
8427
+ * Detects if code is running in an Electron renderer process.
8428
+ *
8429
+ * Uses multiple detection methods for robustness:
8430
+ * 1. Checks process.type === 'renderer' (most reliable)
8431
+ * 2. Falls back to checking if Electron is present and window/document exist
8432
+ *
8433
+ * @returns true if running in Electron renderer process, false otherwise
8434
+ */
8435
+ const isElectronRenderer = () => {
8436
+ // Method 1: Check process.type (most reliable - official Electron API)
8437
+ if (typeof process !== 'undefined' &&
8438
+ process.type === 'renderer') {
8439
+ return true;
8440
+ }
8441
+ // Method 2: Fallback - Electron + browser-like environment
8442
+ // Renderer processes have window/document, main process doesn't (in modern Electron)
8443
+ if (isElectron() &&
8444
+ typeof window !== 'undefined' &&
8445
+ typeof document !== 'undefined') {
8446
+ return true;
8447
+ }
8448
+ return false;
8449
+ };
8450
+ /**
8451
+ * True where OPFS-backed Arweave file downloads should run: normal browsers and
8452
+ * Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
8453
+ */
8454
+ const supportsOpfsFileDownloads = () => {
8455
+ return isBrowser() || isElectronRenderer();
8456
+ };
8457
+
8458
+ const logger$g = debug('seedSdk:files:download');
8459
+ const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
8460
+ /** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
8461
+ const GET_FILES_METADATA_STALE_MS = 120000;
8462
+ let bulkDownloadInFlight = null;
8463
+ const lazyDownloadInFlightByTransactionId = new Map();
8464
+ // syncDbFiles helper - internal service removed, functionality moved here
8465
+ const syncDbFiles = async (endpoints) => {
8466
+ // TODO: Implement syncDbFiles functionality if needed
8467
+ // This was previously in @/services/internal/helpers
8468
+ logger$g('[download] syncDbFiles called but not yet implemented');
8469
+ return Promise.resolve();
8470
+ };
8471
+ const getAppDbReady = async () => {
8472
+ if (!BaseDb.isAppDbReady()) {
8473
+ // Wait for ClientManager to be ready (DB_INIT state or later)
8474
+ const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
8475
+ const { getClient } = clientManagerMod;
8476
+ const clientManager = getClient();
8477
+ const clientService = clientManager.getService();
8478
+ await waitFor(clientService, (snapshot) => {
8479
+ const state = snapshot.value;
8480
+ return state === 'dbInit' ||
8481
+ state === 'saveConfig' ||
8482
+ state === 'processSchemaFiles' ||
8483
+ state === 'addModelsToStore' ||
8484
+ state === 'addModelsToDb' ||
8485
+ state === 'idle';
8486
+ }, { timeout: 30000 });
8487
+ }
8488
+ return BaseDb.getAppDb();
8489
+ };
8490
+ const getExcludedTransactions = async () => {
8491
+ const appDb = await getAppDbReady();
8492
+ if (!appDb) {
8493
+ return new Set();
8494
+ }
8495
+ const excludedTransactionsQuery = await appDb
8496
+ .select()
8497
+ .from(appState)
8498
+ .where(eq(appState.key, 'excludedTransactions'));
8499
+ const excludedTransactions = new Set();
8500
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
8501
+ const valueString = excludedTransactionsQuery[0].value;
8502
+ if (valueString) {
8503
+ const excludedTransactionsArray = JSON.parse(valueString);
8504
+ for (const txId of excludedTransactionsArray) {
8505
+ excludedTransactions.add(txId);
8506
+ }
8507
+ }
8508
+ }
8509
+ return excludedTransactions;
8510
+ };
8511
+ /** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
8512
+ const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
8513
+ const normalizeArweaveTxId = (raw) => {
8514
+ if (raw == null || raw === '')
8515
+ return undefined;
8516
+ const t = String(raw).trim();
8517
+ if (ARWEAVE_TX_ID_RE.test(t))
8518
+ return t;
8519
+ const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
8520
+ if (m)
8521
+ return m[1];
8522
+ // Values may be full gateway URLs or paths; scan for the embedded tx id.
8523
+ const embedded = t.match(/[a-z0-9_-]{43}/gi);
8524
+ if (embedded) {
8525
+ for (const candidate of embedded) {
8526
+ if (ARWEAVE_TX_ID_RE.test(candidate))
8527
+ return candidate;
8528
+ }
8529
+ }
8530
+ return undefined;
8531
+ };
8532
+ const mergeAddressLists = (a, b) => {
8533
+ const seen = new Set();
8534
+ const out = [];
8535
+ for (const addr of [...(a ?? []), ...(b ?? [])]) {
8536
+ if (!addr || !addr.trim())
8537
+ continue;
8538
+ const k = addr.toLowerCase();
8539
+ if (seen.has(k))
8540
+ continue;
8541
+ seen.add(k);
8542
+ out.push(addr);
8543
+ }
8544
+ return out;
8545
+ };
8546
+ const collectTransactionIdsFromLocalMetadata = async () => {
8547
+ const appDb = await getAppDbReady();
8548
+ if (!appDb) {
8549
+ return [];
8550
+ }
8551
+ const nameOr = or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'storage_transaction_id'), eq(metadata$1.propertyName, 'transactionId'));
8552
+ const propRows = await appDb
8553
+ .select({ propertyValue: metadata$1.propertyValue })
8554
+ .from(metadata$1)
8555
+ .where(and(nameOr, isNotNull(metadata$1.propertyValue)));
8556
+ const refRows = await appDb
8557
+ .select({ refResolvedValue: metadata$1.refResolvedValue })
8558
+ .from(metadata$1)
8559
+ .where(isNotNull(metadata$1.refResolvedValue));
8560
+ const ids = new Set();
8561
+ for (const row of propRows) {
8562
+ const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
8563
+ if (id)
8564
+ ids.add(id);
8565
+ }
8566
+ for (const row of refRows) {
8567
+ const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
8568
+ if (id)
8569
+ ids.add(id);
8570
+ }
8571
+ return Array.from(ids);
8572
+ };
8573
+ const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
8574
+ const transactionIds = [];
8575
+ for (const fileMetadata of filesMetadata) {
8576
+ // Validate and parse decodedDataJson
8577
+ if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
8578
+ console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
8579
+ continue;
8580
+ }
8581
+ let json;
8582
+ try {
8583
+ json = JSON.parse(fileMetadata.decodedDataJson);
8584
+ }
8585
+ catch (error) {
8586
+ console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
8587
+ continue;
8588
+ }
8589
+ if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
8590
+ console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
8591
+ continue;
8592
+ }
8593
+ const rawTx = json[0].value.value;
8594
+ if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
8595
+ continue;
8596
+ }
8597
+ const transactionId = normalizeArweaveTxId(rawTx.trim());
8598
+ if (!transactionId) {
8599
+ continue;
8600
+ }
8601
+ if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
8602
+ continue;
8603
+ }
8604
+ transactionIds.push(transactionId);
8605
+ }
8606
+ return transactionIds;
8607
+ };
8608
+ const downloadTransactionIds = async (rawTransactionIds, options) => {
8609
+ if (!supportsOpfsFileDownloads()) {
8610
+ return false;
8611
+ }
8612
+ const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
8613
+ if (transactionIds.length === 0) {
8614
+ return false;
8615
+ }
8616
+ const excludedTransactions = await getExcludedTransactions();
8617
+ const queryClient = BaseQueryClient.getQueryClient();
8618
+ const transactionIdsToDownload = [];
8619
+ await ensureReadGatewaySelected();
8620
+ for (const transactionId of transactionIds) {
8621
+ if (excludedTransactions.has(transactionId)) {
8622
+ continue;
8623
+ }
8624
+ try {
8625
+ // Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
8626
+ // CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
8627
+ let tags = [];
8628
+ try {
8629
+ tags = await queryClient.fetchQuery({
8630
+ queryKey: ['getTransactionTags', transactionId],
8631
+ queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
8632
+ });
8633
+ }
8634
+ catch {
8635
+ tags = [];
8636
+ }
8637
+ if (tags && tags.length > 0) {
8638
+ for (const { name, value } of tags) {
8639
+ if (name !== 'Content-SHA-256')
8640
+ continue;
8641
+ const metadataRecord = await getMetadata({
8642
+ storageTransactionId: transactionId,
8643
+ });
8644
+ if (metadataRecord) {
8645
+ await saveMetadata(metadataRecord, {
8646
+ contentHash: value,
8647
+ });
8648
+ }
8649
+ }
8650
+ }
8651
+ transactionIdsToDownload.push(transactionId);
8652
+ }
8653
+ catch (error) {
8654
+ logger$g(error);
8655
+ }
8656
+ }
8657
+ if (transactionIdsToDownload.length === 0) {
8658
+ return false;
8659
+ }
8660
+ if (transactionIdsToDownload.length === 1) {
8661
+ await BaseFileManager.downloadFileByTransactionId({
8662
+ transactionId: transactionIdsToDownload[0],
8663
+ arweaveHost: BaseArweaveClient.getHost(),
8664
+ excludedTransactions,
8665
+ });
8666
+ }
8667
+ else {
8668
+ await BaseFileManager.downloadAllFiles({
8669
+ transactionIds: transactionIdsToDownload,
8670
+ arweaveHost: BaseArweaveClient.getHost(),
8671
+ excludedTransactions,
8672
+ });
8673
+ }
8674
+ if (options?.resizeAllImages !== false) {
8675
+ await BaseFileManager.resizeAllImages({
8676
+ width: 480,
8677
+ height: 480,
8678
+ });
8679
+ }
8680
+ return true;
8681
+ };
8682
+ const runBulkDownloadWithDedupe = async (transactionIds) => {
8683
+ if (bulkDownloadInFlight) {
8684
+ return bulkDownloadInFlight;
8685
+ }
8686
+ bulkDownloadInFlight = (async () => {
8687
+ try {
8688
+ await downloadTransactionIds(transactionIds, { resizeAllImages: true });
8689
+ }
8690
+ finally {
8691
+ bulkDownloadInFlight = null;
8692
+ }
8693
+ })();
8694
+ return bulkDownloadInFlight;
8695
+ };
8696
+ const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
8697
+ if (!supportsOpfsFileDownloads()) {
8698
+ return;
8699
+ }
8700
+ await syncDbFiles();
8701
+ eventEmitter.emit('fs.downloadAll.success', { eventId });
8702
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
8703
+ };
8704
+ const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
8705
+ if (!supportsOpfsFileDownloads()) {
8706
+ return;
8707
+ }
8708
+ const addressesHint = Array.isArray(addressesHintOrPayload)
8709
+ ? addressesHintOrPayload
8710
+ : undefined;
8711
+ let fromDb = [];
8712
+ if (BaseDb.isAppDbReady()) {
8713
+ fromDb = await getAllAddressesFromDb();
8714
+ }
8715
+ if (!BaseDb.isAppDbReady()) {
8716
+ await getAppDbReady();
8717
+ fromDb = await getAllAddressesFromDb();
8718
+ }
8719
+ const addresses = mergeAddressLists(addressesHint, fromDb);
8720
+ if (!addresses || addresses.length === 0) {
8721
+ return;
8722
+ }
8723
+ const queryClient = BaseQueryClient.getQueryClient();
8724
+ const easClient = BaseEasClient.getEasClient();
8725
+ const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
8726
+ const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
8727
+ where: {
8728
+ attester: {
8729
+ in: addresses,
8730
+ },
8731
+ schema: {
8732
+ is: {
8733
+ id: {
8734
+ equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
8735
+ },
8736
+ },
8737
+ },
8738
+ },
8739
+ });
8740
+ let { filesMetadata } = await queryClient.fetchQuery({
8741
+ queryKey: filesMetadataQueryKey,
8742
+ queryFn: fetchFilesMetadata,
8743
+ staleTime: GET_FILES_METADATA_STALE_MS,
8744
+ });
8745
+ if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
8746
+ await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
8747
+ ({ filesMetadata } = await queryClient.fetchQuery({
8748
+ queryKey: filesMetadataQueryKey,
8749
+ queryFn: fetchFilesMetadata,
8750
+ staleTime: GET_FILES_METADATA_STALE_MS,
8751
+ }));
8752
+ }
8753
+ const filesRoot = BaseFileManager.getWorkingDir();
8754
+ await BaseFileManager.createDirIfNotExists(filesRoot);
8755
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
8756
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
8757
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
8758
+ const excludedTransactions = await getExcludedTransactions();
8759
+ const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
8760
+ const fromLocal = await collectTransactionIdsFromLocalMetadata();
8761
+ const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
8762
+ await runBulkDownloadWithDedupe(transactionIds);
8763
+ };
8764
+ const downloadTransactionIdWithDedupe = async (transactionId) => {
8765
+ if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
8766
+ return false;
8767
+ }
8768
+ const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
8769
+ const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
8770
+ if (existing) {
8771
+ return existing;
8772
+ }
8773
+ const inFlight = (async () => {
8774
+ try {
8775
+ const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
8776
+ return ok;
8777
+ }
8778
+ finally {
8779
+ lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
8780
+ }
8781
+ })();
8782
+ lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
8783
+ return inFlight;
8784
+ };
8785
+ const scheduleBulkFilesDownloadFromEasSyncThrottled = throttle((addressesHint) => {
8786
+ void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
8787
+ logger$g('[scheduleBulkFilesDownloadFromEasSync] failed', error);
8788
+ });
8789
+ }, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
8790
+ const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
8791
+ if (!supportsOpfsFileDownloads()) {
8792
+ return;
8793
+ }
8794
+ scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
8795
+ };
8796
+
8797
+ var download = /*#__PURE__*/Object.freeze({
8798
+ __proto__: null,
8799
+ downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
8800
+ downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
8801
+ downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
8802
+ scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
8803
+ });
8804
+
8805
+ /** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
8806
+ const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
8807
+ /** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
8808
+ const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
8809
+ function extractArweaveTransactionId(raw) {
8810
+ const t = raw.trim();
8811
+ const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
8812
+ if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
8813
+ return embedded[0];
8814
+ }
8815
+ return t;
8816
+ }
8817
+ /**
8818
+ * GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
8819
+ * arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
8820
+ */
8821
+ async function fetchHtmlViaRawAcrossGateways(txId) {
8822
+ const id = extractArweaveTransactionId(txId);
8823
+ if (!id || SEED_UID_HEX_RE.test(id))
8824
+ return undefined;
8825
+ try {
8826
+ const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
8827
+ await ensureReadGatewaySelected().catch(() => { });
8828
+ }
8829
+ catch {
8830
+ /* optional */
8831
+ }
8832
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8833
+ const protocol = BaseArweaveClient.getProtocol();
8834
+ const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
8835
+ for (const host of hosts) {
8836
+ const h = host.trim().replace(/\/$/, '');
8837
+ if (!h)
8838
+ continue;
8839
+ const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
8840
+ try {
8841
+ const res = await fetch(url, { method: 'GET', credentials: 'omit' });
8842
+ if (!res.ok)
8843
+ continue;
8844
+ const text = await res.text();
8845
+ if (typeof text === 'string' && text.length > 0) {
8846
+ return text;
8847
+ }
8848
+ }
8849
+ catch {
8850
+ /* next gateway */
8851
+ }
8852
+ }
8853
+ return undefined;
8854
+ }
8855
+ /**
8856
+ * Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
8857
+ * `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
8858
+ */
8859
+ async function resolveHtmlStorageSeedLocalId(propertyValue) {
8860
+ const pv = String(propertyValue ?? '').trim();
8861
+ if (!pv)
8862
+ return undefined;
8863
+ if (SEED_UID_HEX_RE.test(pv)) {
8864
+ const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
8865
+ return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
8866
+ }
8867
+ return pv;
8868
+ }
8869
+ /**
8870
+ * When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
8871
+ * Html storage seed's published Arweave transaction id on that child seed.
8872
+ */
8873
+ async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
8874
+ const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
8875
+ const pickTx = async (name) => {
8876
+ const row = await getPropertyData({ propertyName: name, seedLocalId });
8877
+ const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
8878
+ return v || undefined;
8879
+ };
8880
+ const txId = (await pickTx('storageTransactionId')) ??
8881
+ (await pickTx('transactionId')) ??
8882
+ (await pickTx('storage_transaction_id'));
8883
+ if (!txId || SEED_UID_HEX_RE.test(txId)) {
8884
+ return { txIdLen: 0, gatewayStringLen: 0 };
8885
+ }
8886
+ const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
8887
+ if (rawHtml && rawHtml.length > 0) {
8888
+ return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
8889
+ }
8890
+ try {
8891
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8892
+ const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
8893
+ string: true,
8894
+ });
8895
+ if (typeof data === 'string' && data.length > 0) {
8896
+ return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
8897
+ }
8898
+ }
8899
+ catch {
8900
+ /* offline / bad tx id */
8901
+ }
8902
+ try {
8903
+ const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
8904
+ await downloadTransactionIdWithDedupe(txId);
8905
+ const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
8906
+ if (await BaseFileManager.pathExists(retryFp)) {
8907
+ const s = await BaseFileManager.readFileAsString(retryFp);
8908
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8909
+ }
8910
+ const dirPath = BaseFileManager.getFilesPath('html');
8911
+ if (await BaseFileManager.pathExists(dirPath)) {
8912
+ const fs = await BaseFileManager.getFs();
8913
+ const pathMod = BaseFileManager.getPathModule();
8914
+ const files = await fs.promises.readdir(dirPath);
8915
+ const needle = txId.replace(/\.[^/.]+$/, '');
8916
+ const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
8917
+ if (match) {
8918
+ const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
8919
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8920
+ }
8921
+ }
8922
+ }
8923
+ catch {
8924
+ /* OPFS unsupported or download failed */
8925
+ }
8926
+ return { txIdLen: txId.length, gatewayStringLen: 0 };
8927
+ }
8928
+ /** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
8929
+ async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
8930
+ const pv = String(propertyValue ?? '').trim();
8931
+ if (!pv)
8932
+ return undefined;
8933
+ const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
8934
+ const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
8935
+ let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
8936
+ // OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
8937
+ if (!fileExists && fp) {
8938
+ await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
8939
+ fileExists = await BaseFileManager.pathExists(fp);
8940
+ }
8941
+ let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
8942
+ if (!body && localId) {
8943
+ const ar = await readHtmlBodyFromChildStorageArweave(localId);
8944
+ body = ar.body;
8945
+ }
8946
+ return body;
8947
+ }
8948
+
8949
+ // Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
8950
+ // import { ModelPropertyDataTypes } from '@/schema'
8951
+ const logger$f = debug('seedSdk:property:actors:hydrateFromDb');
8952
+ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8953
+ const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
8954
+ if (!propertyNameRaw) {
8955
+ throw new Error('propertyName is required');
8956
+ }
8957
+ let propertyName = propertyNameRaw;
8958
+ // Note: isRelation, isImage, isFile checks moved inside async function
8959
+ // to use dynamically imported ModelPropertyDataTypes
8960
+ const _hydrateFromDb = async () => {
8961
+ // Use dynamic import to break circular dependency
8962
+ const schemaMod = await import('./index-DB3nZ0lK.js');
8963
+ const { ModelPropertyDataTypes } = schemaMod;
8964
+ const appDb = BaseDb.getAppDb();
8965
+ const whereClauses = [];
8966
+ // Re-check types with dynamically imported ModelPropertyDataTypes
8967
+ // Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
8968
+ const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
8969
+ const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
8970
+ propertyRecordSchema &&
8971
+ propertyRecordSchema.ref &&
8972
+ normalizedDataType === ModelPropertyDataTypes.Relation;
8973
+ const isImageDynamic = propertyRecordSchema &&
8974
+ (normalizedDataType === ModelPropertyDataTypes.Image ||
8975
+ normalizedRefValueType === ModelPropertyDataTypes.Image);
8976
+ const isFileDynamic = propertyRecordSchema &&
8977
+ normalizedDataType === ModelPropertyDataTypes.File;
8978
+ const isHtmlDynamic = propertyRecordSchema &&
8979
+ normalizedDataType === ModelPropertyDataTypes.Html;
8980
+ // Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
8981
+ const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
8982
+ whereClauses.push(propertyNames.length > 1
8983
+ ? or(...propertyNames.map((n) => eq(metadata$1.propertyName, n)))
8984
+ : eq(metadata$1.propertyName, propertyNames[0]));
8985
+ // Draft rows often have only seed_local_id populated; on-chain rows may have uid.
8986
+ // Requiring both with AND misses valid metadata when only one column is set.
8987
+ if (seedUid && seedLocalId) {
8988
+ whereClauses.push(or(eq(metadata$1.seedLocalId, seedLocalId), eq(metadata$1.seedUid, seedUid)));
8989
+ }
8990
+ else if (seedUid) {
8991
+ whereClauses.push(eq(metadata$1.seedUid, seedUid));
8992
+ }
8993
+ else if (seedLocalId) {
8994
+ whereClauses.push(eq(metadata$1.seedLocalId, seedLocalId));
8995
+ }
8996
+ const rows = await appDb
8997
+ .select()
8998
+ .from(metadata$1)
8999
+ .where(and(...whereClauses))
9000
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
9001
+ if (!rows || !rows.length) {
9002
+ return;
9003
+ }
9004
+ const firstRow = rows[0];
9005
+ const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
9006
+ let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
9007
+ let propertyValueProcessed = propertyValueFromDb;
9008
+ let renderValue = refResolvedDisplayValue ?? undefined;
9009
+ // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
9010
+ if (isImageDynamic) {
9011
+ let dir = localStorageDir;
9012
+ if (!dir && isImageDynamic) {
9013
+ dir = 'images';
9014
+ }
9015
+ dir = dir.replace(/^\//, '');
9016
+ if (propertyValueFromDb &&
9017
+ propertyValueFromDb.length === 66) {
9018
+ // Here the storageTransactionId is stored on a different record and
9019
+ // we want to add it as the refResolvedValue
9020
+ const storageTransactionQuery = await appDb
9021
+ .select({
9022
+ propertyValue: metadata$1.propertyValue,
9023
+ })
9024
+ .from(metadata$1)
9025
+ .where(and(eq(metadata$1.seedUid, propertyValueFromDb), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))));
9026
+ if (storageTransactionQuery && storageTransactionQuery.length > 0) {
9027
+ const row = storageTransactionQuery[0];
9028
+ refResolvedValue = row.propertyValue;
9029
+ await updateMetadata({
9030
+ localId,
9031
+ refResolvedValue,
9032
+ localStorageDir: '/images',
9033
+ });
9034
+ }
9035
+ }
9036
+ const resolveMatchingFilePath = async (dir, needle) => {
9037
+ const dirPath = BaseFileManager.getFilesPath(dir);
9038
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9039
+ if (!dirExists)
9040
+ return undefined;
9041
+ const fs = await BaseFileManager.getFs();
9042
+ const path = BaseFileManager.getPathModule();
9043
+ const files = await fs.promises.readdir(dirPath);
9044
+ const matchingFiles = files.filter((file) => {
9045
+ return path.basename(file).includes(needle);
9046
+ });
9047
+ if (!matchingFiles?.length)
9048
+ return undefined;
9049
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9050
+ };
9051
+ if (refResolvedValue) {
9052
+ try {
9053
+ let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9054
+ if (!filePath) {
9055
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9056
+ filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9057
+ }
9058
+ localStorageDir = `/${dir}`;
9059
+ if (filePath) {
9060
+ const file = await BaseFileManager.readFile(filePath);
9061
+ refResolvedDisplayValue = URL.createObjectURL(file);
9062
+ renderValue = refResolvedDisplayValue;
9063
+ // Do not persist blob URL - it is session-scoped
9064
+ }
9065
+ }
9066
+ catch (e) {
9067
+ logger$f('[hydrateFromDb] Image file resolution error', e);
9068
+ }
9069
+ }
9070
+ }
9071
+ if (isFileDynamic && refResolvedValue) {
9072
+ try {
9073
+ const dir = (localStorageDir ?? '/files').replace(/^\//, '');
9074
+ const resolveMatchingFilePath = async (needle) => {
9075
+ const dirPath = BaseFileManager.getFilesPath(dir);
9076
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9077
+ if (!dirExists)
9078
+ return undefined;
9079
+ const fs = await BaseFileManager.getFs();
9080
+ const path = BaseFileManager.getPathModule();
9081
+ const files = await fs.promises.readdir(dirPath);
9082
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9083
+ if (!matchingFiles?.length)
9084
+ return undefined;
9085
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9086
+ };
9087
+ let filePath = await resolveMatchingFilePath(refResolvedValue);
9088
+ if (!filePath) {
9089
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9090
+ filePath = await resolveMatchingFilePath(refResolvedValue);
9091
+ }
9092
+ if (filePath) {
9093
+ localStorageDir = `/${dir}`;
9094
+ renderValue = await BaseFileManager.readFileAsString(filePath);
9095
+ }
9096
+ }
9097
+ catch (e) {
9098
+ logger$f('[hydrateFromDb] File resolution error', e);
9099
+ }
9100
+ }
9101
+ if (propertyRecordSchema &&
9102
+ normalizedDataType === ModelPropertyDataTypes.List &&
9103
+ typeof propertyValueFromDb === 'string') {
9104
+ propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
9105
+ }
9106
+ sendBack({
9107
+ type: 'updateContext',
9108
+ localId,
9109
+ uid,
9110
+ propertyValue: propertyValueProcessed,
9111
+ seedLocalId: seedLocalIdFromDb,
9112
+ seedUid: seedUidFromDb,
9113
+ versionLocalId: versionLocalIdFromDb,
9114
+ versionUid: versionUidFromDb,
9115
+ schemaUid: schemaUidFromDb,
9116
+ refValueType,
9117
+ localStorageDir,
9118
+ refResolvedValue,
9119
+ refResolvedDisplayValue,
9120
+ renderValue,
9121
+ populatedFromDb: true,
9122
+ });
9123
+ if (propertyRecordSchema &&
9124
+ propertyRecordSchema.storageType &&
9125
+ propertyRecordSchema.storageType === 'ItemStorage') {
9126
+ const itemMod = await Promise.resolve().then(function () { return Item$1; });
9127
+ const { Item } = itemMod;
9128
+ const item = await Item.find({
9129
+ seedLocalId: seedLocalId ?? undefined,
9130
+ modelName,
9131
+ });
9132
+ if (item) {
9133
+ const dir = localStorageDir?.replace(/^\//, '') || 'files';
9134
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9135
+ const exists = await BaseFileManager.pathExists(filePath);
9136
+ if (!exists) {
8158
9137
  return;
8159
9138
  }
8160
9139
  const renderValue = await BaseFileManager.readFileAsString(filePath);
@@ -8165,15 +9144,34 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8165
9144
  return;
8166
9145
  }
8167
9146
  }
8168
- // Html: read file content for renderValue (blob URLs from DB are invalid after reload)
8169
- // Fallback: when localStorageDir is null (e.g. EAS sync, legacy records) use '/html'
8170
- const htmlLocalStorageDir = isHtmlDynamic && refResolvedValue && !localStorageDir ? '/html' : localStorageDir;
8171
- if (isHtmlDynamic && refResolvedValue && htmlLocalStorageDir) {
8172
- const dir = htmlLocalStorageDir.replace(/^\//, '');
8173
- const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
8174
- const exists = await BaseFileManager.pathExists(filePath);
8175
- if (exists) {
8176
- const htmlContent = await BaseFileManager.readFileAsString(filePath);
9147
+ // Html: read file content for renderValue (blob URLs from DB are invalid after reload).
9148
+ // When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
9149
+ if (isHtmlDynamic) {
9150
+ const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
9151
+ let htmlContent;
9152
+ let outRef = refResolvedValue;
9153
+ let outDir = htmlLocalStorageDir;
9154
+ if (refResolvedValue && htmlLocalStorageDir) {
9155
+ const dir = htmlLocalStorageDir.replace(/^\//, '');
9156
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9157
+ let exists = await BaseFileManager.pathExists(filePath);
9158
+ if (!exists) {
9159
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9160
+ exists = await BaseFileManager.pathExists(filePath);
9161
+ }
9162
+ if (exists) {
9163
+ htmlContent = await BaseFileManager.readFileAsString(filePath);
9164
+ }
9165
+ }
9166
+ if (!htmlContent && propertyValueFromDb) {
9167
+ htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
9168
+ const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
9169
+ if (lid) {
9170
+ outRef = `${lid}.html`;
9171
+ outDir = '/html';
9172
+ }
9173
+ }
9174
+ if (htmlContent) {
8177
9175
  sendBack({
8178
9176
  type: 'updateContext',
8179
9177
  localId,
@@ -8185,8 +9183,8 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8185
9183
  versionUid: versionUidFromDb,
8186
9184
  schemaUid: schemaUidFromDb,
8187
9185
  refValueType,
8188
- localStorageDir: htmlLocalStorageDir,
8189
- refResolvedValue,
9186
+ localStorageDir: outDir,
9187
+ refResolvedValue: outRef ?? refResolvedValue,
8190
9188
  refResolvedDisplayValue,
8191
9189
  renderValue: htmlContent,
8192
9190
  populatedFromDb: true,
@@ -8200,11 +9198,11 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8200
9198
  });
8201
9199
  });
8202
9200
 
8203
- const logger$f = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
9201
+ const logger$e = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
8204
9202
  const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) => {
8205
9203
  const _loadOrCreateProperty = async () => {
8206
9204
  const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
8207
- logger$f(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
9205
+ logger$e(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
8208
9206
  if (!seedLocalId && !seedUid) {
8209
9207
  throw new Error('seedLocalId or seedUid is required');
8210
9208
  }
@@ -8250,15 +9248,15 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8250
9248
  const schemas = modelPropertiesToObject(model$1.properties);
8251
9249
  propertyRecordSchema = schemas[propertyName];
8252
9250
  if (propertyRecordSchema) {
8253
- logger$f(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9251
+ logger$e(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8254
9252
  }
8255
9253
  }
8256
9254
  }
8257
9255
  catch (error) {
8258
- logger$f(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
9256
+ logger$e(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
8259
9257
  }
8260
9258
  }
8261
- logger$f(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
9259
+ logger$e(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
8262
9260
  sendBack({
8263
9261
  type: 'loadOrCreatePropertySuccess',
8264
9262
  property: {
@@ -8324,7 +9322,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8324
9322
  };
8325
9323
  // Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
8326
9324
  try {
8327
- const { getPropertySchema } = await import('./property-C63Ddzap.js');
9325
+ const { getPropertySchema } = await import('./property-DViA9nga.js');
8328
9326
  let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
8329
9327
  if (!schemaFromFile?.validation) {
8330
9328
  // Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
@@ -8362,7 +9360,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8362
9360
  }
8363
9361
  }
8364
9362
  catch (error) {
8365
- logger$f(`Error loading propertyRecordSchema from database: ${error}`);
9363
+ logger$e(`Error loading propertyRecordSchema from database: ${error}`);
8366
9364
  // Continue without propertyRecordSchema
8367
9365
  }
8368
9366
  }
@@ -8380,22 +9378,27 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8380
9378
  const schemas = modelPropertiesToObject(model$1.properties);
8381
9379
  propertyRecordSchema = schemas[propertyName];
8382
9380
  if (propertyRecordSchema) {
8383
- logger$f(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9381
+ logger$e(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8384
9382
  }
8385
9383
  }
8386
9384
  }
8387
9385
  catch (error) {
8388
- logger$f(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
9386
+ logger$e(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
8389
9387
  }
8390
9388
  }
8391
9389
  // For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
8392
9390
  let renderValue = metadataRecord.propertyValue || undefined;
8393
9391
  const refSeedType = metadataRecord.refSeedType;
8394
- const isHtml = refSeedType === 'html' || propertyRecordSchema?.dataType === 'Html';
8395
- // Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data)
9392
+ const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
9393
+ const isHtml = refSeedType === 'html' || normalizedHtmlDt === ModelPropertyDataTypes.Html;
9394
+ // Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
9395
+ // After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
8396
9396
  if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
8397
- metadataRecord.refResolvedValue = `${metadataRecord.propertyValue}.html`;
8398
- metadataRecord.localStorageDir = '/html';
9397
+ const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
9398
+ if (lid) {
9399
+ metadataRecord.refResolvedValue = `${lid}.html`;
9400
+ metadataRecord.localStorageDir = '/html';
9401
+ }
8399
9402
  }
8400
9403
  // Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
8401
9404
  if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
@@ -8405,13 +9408,34 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8405
9408
  try {
8406
9409
  const dir = metadataRecord.localStorageDir.replace(/^\//, '');
8407
9410
  const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
8408
- const exists = await BaseFileManager.pathExists(filePath);
9411
+ let exists = await BaseFileManager.pathExists(filePath);
9412
+ if (!exists) {
9413
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9414
+ exists = await BaseFileManager.pathExists(filePath);
9415
+ }
8409
9416
  if (exists) {
8410
9417
  renderValue = await BaseFileManager.readFileAsString(filePath);
8411
9418
  }
9419
+ else {
9420
+ const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9421
+ if (viaSeedPointer) {
9422
+ renderValue = viaSeedPointer;
9423
+ }
9424
+ }
8412
9425
  }
8413
9426
  catch (e) {
8414
- logger$f(`Failed to read Html file for ${propertyName}: ${e}`);
9427
+ logger$e(`Failed to read Html file for ${propertyName}: ${e}`);
9428
+ }
9429
+ }
9430
+ // Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
9431
+ if (isHtml && metadataRecord.propertyValue) {
9432
+ const pv = String(metadataRecord.propertyValue).trim();
9433
+ const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
9434
+ if (!rv || rv === pv) {
9435
+ const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9436
+ if (recovered) {
9437
+ renderValue = recovered;
9438
+ }
8415
9439
  }
8416
9440
  }
8417
9441
  // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
@@ -8421,28 +9445,83 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8421
9445
  const isImage = refSeedType === 'image' ||
8422
9446
  normalizedDataType === 'Image' ||
8423
9447
  normalizedRefValueType === 'Image';
9448
+ const resolveMatchingFilePath = async (dir, needle) => {
9449
+ const dirPath = BaseFileManager.getFilesPath(dir);
9450
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9451
+ if (!dirExists)
9452
+ return undefined;
9453
+ const fs = await BaseFileManager.getFs();
9454
+ const path = BaseFileManager.getPathModule();
9455
+ const files = await fs.promises.readdir(dirPath);
9456
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9457
+ if (!matchingFiles?.length)
9458
+ return undefined;
9459
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9460
+ };
9461
+ // EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
9462
+ // hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
9463
+ if (isImage &&
9464
+ !metadataRecord.refResolvedValue &&
9465
+ typeof metadataRecord.propertyValue === 'string' &&
9466
+ metadataRecord.propertyValue.length === 66) {
9467
+ const storageTxRows = await db
9468
+ .select({ propertyValue: metadata$1.propertyValue })
9469
+ .from(metadata$1)
9470
+ .where(and(eq(metadata$1.seedUid, metadataRecord.propertyValue), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))))
9471
+ .limit(1);
9472
+ const derivedTxId = storageTxRows[0]?.propertyValue;
9473
+ if (derivedTxId) {
9474
+ metadataRecord.refResolvedValue = derivedTxId;
9475
+ metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
9476
+ if (metadataRecord.localId) {
9477
+ try {
9478
+ await updateMetadata({
9479
+ localId: metadataRecord.localId,
9480
+ refResolvedValue: derivedTxId,
9481
+ localStorageDir: '/images',
9482
+ });
9483
+ }
9484
+ catch (e) {
9485
+ logger$e(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
9486
+ }
9487
+ }
9488
+ }
9489
+ }
8424
9490
  if (isImage && metadataRecord.refResolvedValue) {
8425
9491
  try {
8426
9492
  const dir = (metadataRecord.localStorageDir ?? '/images').replace(/^\//, '');
8427
- const dirPath = BaseFileManager.getFilesPath(dir);
8428
- const dirExists = await BaseFileManager.pathExists(dirPath);
8429
- if (dirExists) {
8430
- const fs = await BaseFileManager.getFs();
8431
- const path = BaseFileManager.getPathModule();
8432
- const files = await fs.promises.readdir(dirPath);
8433
- const matchingFiles = files.filter((file) => path.basename(file).includes(metadataRecord.refResolvedValue));
8434
- if (matchingFiles?.length > 0) {
8435
- const filename = matchingFiles[0];
8436
- const filePath = BaseFileManager.getFilesPath(dir, filename);
8437
- const file = await BaseFileManager.readFile(filePath);
8438
- const freshBlobUrl = URL.createObjectURL(file);
8439
- renderValue = freshBlobUrl;
8440
- refResolvedDisplayValue = freshBlobUrl;
8441
- }
9493
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9494
+ if (!filePath) {
9495
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9496
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9497
+ }
9498
+ if (filePath) {
9499
+ const file = await BaseFileManager.readFile(filePath);
9500
+ const freshBlobUrl = URL.createObjectURL(file);
9501
+ renderValue = freshBlobUrl;
9502
+ refResolvedDisplayValue = freshBlobUrl;
9503
+ }
9504
+ }
9505
+ catch (e) {
9506
+ logger$e(`Failed to resolve Image file for ${propertyName}: ${e}`);
9507
+ }
9508
+ }
9509
+ const isFile = refSeedType === 'file' ||
9510
+ normalizedDataType === 'File';
9511
+ if (isFile && metadataRecord.refResolvedValue) {
9512
+ try {
9513
+ const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
9514
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9515
+ if (!filePath) {
9516
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9517
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9518
+ }
9519
+ if (filePath) {
9520
+ renderValue = await BaseFileManager.readFileAsString(filePath);
8442
9521
  }
8443
9522
  }
8444
9523
  catch (e) {
8445
- logger$f(`Failed to resolve Image file for ${propertyName}: ${e}`);
9524
+ logger$e(`Failed to resolve File for ${propertyName}: ${e}`);
8446
9525
  }
8447
9526
  }
8448
9527
  let propertyValueOut = metadataRecord.propertyValue || undefined;
@@ -8474,7 +9553,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8474
9553
  });
8475
9554
  };
8476
9555
  _loadOrCreateProperty().catch((error) => {
8477
- logger$f(`Error in loadOrCreateProperty: ${error}`);
9556
+ logger$e(`Error in loadOrCreateProperty: ${error}`);
8478
9557
  sendBack({
8479
9558
  type: 'loadOrCreatePropertyError',
8480
9559
  error: error instanceof Error ? error.message : String(error),
@@ -8504,10 +9583,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
8504
9583
  return queryRows[0];
8505
9584
  };
8506
9585
 
8507
- const logger$e = debug('seedSdk:write:updateItemPropertyValue');
9586
+ const logger$d = debug('seedSdk:write:updateItemPropertyValue');
8508
9587
  const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
8509
9588
  if (!localIdParam && !seedLocalId) {
8510
- logger$e(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
9589
+ logger$d(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
8511
9590
  return;
8512
9591
  }
8513
9592
  let safeNewValue = newValue;
@@ -8535,7 +9614,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8535
9614
  .select()
8536
9615
  .from(metadata$1)
8537
9616
  .where(and(propertyNameWhere, eq(metadata$1.seedLocalId, seedLocalId)))
8538
- .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9617
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8539
9618
  }
8540
9619
  }
8541
9620
  else if (localIdParam) {
@@ -8555,7 +9634,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8555
9634
  .select()
8556
9635
  .from(metadata$1)
8557
9636
  .where(and(propertyNameWhere, eq(metadata$1.seedLocalId, seedLocalId)))
8558
- .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9637
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8559
9638
  }
8560
9639
  // const mostRecentRecordStatement = `SELECT local_id,
8561
9640
  // uid,
@@ -8571,7 +9650,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8571
9650
  // FROM metadata
8572
9651
  // WHERE property_name = '${propertyName}'
8573
9652
  // AND seed_local_id = '${seedLocalId}'
8574
- // ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
9653
+ // ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
8575
9654
  //
8576
9655
  // const { rows } = await runQueryForStatement(mostRecentRecordStatement)
8577
9656
  if (rows && rows.length > 0) {
@@ -8580,7 +9659,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8580
9659
  modelType === modelName?.toLowerCase() &&
8581
9660
  refSeedTypeFromDb === refSeedType &&
8582
9661
  refResolvedValueFromDb === refResolvedValue) {
8583
- logger$e(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
9662
+ logger$d(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
8584
9663
  return;
8585
9664
  }
8586
9665
  // This means we already have a local-only record so we should just update that one
@@ -8708,9 +9787,9 @@ const analyzeInput = fromCallback(({ sendBack, input: { context, event } }) => {
8708
9787
  }
8709
9788
  const _analyzeInput = async () => {
8710
9789
  // Use dynamic import to break circular dependency
8711
- const schemaMod = await import('./index-Cqf_DxkJ.js');
9790
+ const schemaMod = await import('./index-DB3nZ0lK.js');
8712
9791
  const { ModelPropertyDataTypes } = schemaMod;
8713
- const { SchemaValidationService } = await import('./SchemaValidationService-Cb-b4kpD.js');
9792
+ const { SchemaValidationService } = await import('./SchemaValidationService-DXYRdSYa.js');
8714
9793
  let propertyName = propertyNameRaw;
8715
9794
  if (!propertyName) {
8716
9795
  throw new Error('propertyName is required');
@@ -8908,7 +9987,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8908
9987
  propertyRecordSchema?.validation &&
8909
9988
  metadataValues.propertyValue != null &&
8910
9989
  metadataValues.propertyValue !== '') {
8911
- const { SchemaValidationService } = await import('./SchemaValidationService-Cb-b4kpD.js');
9990
+ const { SchemaValidationService } = await import('./SchemaValidationService-DXYRdSYa.js');
8912
9991
  const validationService = new SchemaValidationService();
8913
9992
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
8914
9993
  if (!validationResult.isValid && validationResult.errors.length > 0) {
@@ -8986,8 +10065,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8986
10065
  return inserted[0];
8987
10066
  };
8988
10067
 
8989
- const eventEmitter = new EventEmitter();
8990
-
8991
10068
  const readFileAsArrayBuffer$1 = async (file) => {
8992
10069
  return new Promise((resolve) => {
8993
10070
  const reader = new FileReader();
@@ -9134,6 +10211,12 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
9134
10211
  }
9135
10212
  const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
9136
10213
  let newLocalId;
10214
+ const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
10215
+ ? schemaUid
10216
+ : (await getEasSchemaForItemProperty({
10217
+ propertyName,
10218
+ easDataType: 'bytes32',
10219
+ }))?.id;
9137
10220
  if (!localId) {
9138
10221
  const result = await createMetadata({
9139
10222
  propertyName,
@@ -9143,7 +10226,7 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
9143
10226
  versionLocalId,
9144
10227
  versionUid,
9145
10228
  modelName,
9146
- schemaUid: imageSchemaUid,
10229
+ schemaUid: resolvedPropertySchemaUid,
9147
10230
  refSeedType: 'image',
9148
10231
  refModelUid: imageSchemaUid,
9149
10232
  refResolvedValue: fileName,
@@ -9162,7 +10245,7 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
9162
10245
  seedLocalId,
9163
10246
  versionLocalId,
9164
10247
  modelName,
9165
- schemaUid,
10248
+ schemaUid: resolvedPropertySchemaUid,
9166
10249
  refSeedType: 'image',
9167
10250
  refResolvedValue: fileName,
9168
10251
  localStorageDir: '/images',
@@ -9495,7 +10578,7 @@ const saveRelation = fromCallback(({ sendBack, input: { context, event } }) => {
9495
10578
  }
9496
10579
  const _saveRelation = async () => {
9497
10580
  // Use dynamic import to break circular dependency
9498
- const schemaMod = await import('./index-Cqf_DxkJ.js');
10581
+ const schemaMod = await import('./index-DB3nZ0lK.js');
9499
10582
  const { ModelPropertyDataTypes } = schemaMod;
9500
10583
  if (!propertyNameRaw) {
9501
10584
  throw new Error('propertyName is required');
@@ -9704,6 +10787,10 @@ const propertyMachine = setup({
9704
10787
  context: {},
9705
10788
  input: {},
9706
10789
  },
10790
+ guards: {
10791
+ // stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
10792
+ propertyMachineIsIdle: stateIn('idle'),
10793
+ },
9707
10794
  // actions: {
9708
10795
  // updateContext: updateMachineContext,
9709
10796
  // },
@@ -9726,7 +10813,11 @@ const propertyMachine = setup({
9726
10813
  initial: 'waitingForDb',
9727
10814
  context: ({ input }) => input,
9728
10815
  on: {
9729
- // reload: '.hydratingFromDb',
10816
+ /** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
10817
+ rehydrateFromDb: {
10818
+ guard: 'propertyMachineIsIdle',
10819
+ target: '.hydratingFromDb',
10820
+ },
9730
10821
  save: {
9731
10822
  actions: assign({
9732
10823
  isSaving: true,
@@ -10325,6 +11416,8 @@ function createReactiveProxy(config) {
10325
11416
  return proxy;
10326
11417
  }
10327
11418
 
11419
+ /** Parent Html property `propertyValue` after publish (66-char seed uid). */
11420
+ const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
10328
11421
  // Start loading Model at module load time (non-blocking)
10329
11422
  Promise.resolve().then(function () { return Model$1; }).then(module => {
10330
11423
  module.Model;
@@ -10424,7 +11517,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
10424
11517
  };
10425
11518
  /** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
10426
11519
  const modelTypeToModelName = (modelType) => modelType ? upperFirst(camelCase(modelType)) : '';
10427
- const logger$d = debug('seedSdk:property:class');
11520
+ const logger$c = debug('seedSdk:property:class');
10428
11521
  // Define tracked properties for the Proxy
10429
11522
  // These properties will be read from/written to the actor context
10430
11523
  const TRACKED_PROPERTIES$2 = [
@@ -10506,7 +11599,7 @@ class ItemProperty {
10506
11599
  serviceInput.propertyValue = JSON.parse(propertyValue);
10507
11600
  }
10508
11601
  catch (e) {
10509
- logger$d('List property value is not JSON', e);
11602
+ logger$c('List property value is not JSON', e);
10510
11603
  }
10511
11604
  }
10512
11605
  }
@@ -10529,7 +11622,7 @@ class ItemProperty {
10529
11622
  return;
10530
11623
  }
10531
11624
  // Use dynamic import to break circular dependency
10532
- const schemaMod = await import('./index-Cqf_DxkJ.js');
11625
+ const schemaMod = await import('./index-DB3nZ0lK.js');
10533
11626
  const { ModelPropertyDataTypes } = schemaMod;
10534
11627
  const { context } = snapshot;
10535
11628
  const { propertyRecordSchema } = context;
@@ -10552,7 +11645,8 @@ class ItemProperty {
10552
11645
  propertyRecordSchema.storageType === 'ItemStorage' &&
10553
11646
  context.refResolvedValue &&
10554
11647
  context.localStorageDir;
10555
- const isHtml = (context.refSeedType === 'html' || (propertyRecordSchema?.dataType === ModelPropertyDataTypes.Html)) &&
11648
+ const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
11649
+ const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
10556
11650
  context.refResolvedValue;
10557
11651
  // Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
10558
11652
  // so the UI can display the filename and preview immediately (these update again when save completes)
@@ -10588,7 +11682,11 @@ class ItemProperty {
10588
11682
  const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
10589
11683
  const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
10590
11684
  try {
10591
- const exists = await BaseFileManager.pathExists(filePath);
11685
+ let exists = await BaseFileManager.pathExists(filePath);
11686
+ if (!exists && isHtml) {
11687
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
11688
+ exists = await BaseFileManager.pathExists(filePath);
11689
+ }
10592
11690
  if (exists && (isItemStorage || isHtml)) {
10593
11691
  renderValue = await BaseFileManager.readFileAsString(filePath);
10594
11692
  }
@@ -10608,8 +11706,8 @@ class ItemProperty {
10608
11706
  if (isFile && isFileValue) {
10609
11707
  renderValue = pv.name;
10610
11708
  }
10611
- else if (isImage) {
10612
- // FS race / path not visible yet: do not clobber a hydrated blob URL with "No file found"
11709
+ else if (isImage || isHtml) {
11710
+ // FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
10613
11711
  renderValue = undefined;
10614
11712
  }
10615
11713
  else {
@@ -10618,13 +11716,21 @@ class ItemProperty {
10618
11716
  }
10619
11717
  }
10620
11718
  catch (e) {
10621
- logger$d(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
10622
- renderValue = 'No file found';
11719
+ logger$c(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
11720
+ renderValue = isHtml ? undefined : 'No file found';
10623
11721
  }
10624
11722
  }
10625
11723
  if (!renderValue) {
10626
11724
  renderValue = context.renderValue || context.propertyValue;
10627
11725
  }
11726
+ const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
11727
+ if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
11728
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
11729
+ renderValue === pvStr &&
11730
+ typeof context.renderValue === 'string' &&
11731
+ context.renderValue.length > pvStr.length) {
11732
+ renderValue = context.renderValue;
11733
+ }
10628
11734
  let transformedPropertyName = propertyName;
10629
11735
  const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
10630
11736
  if (!skipTransform && transformedPropertyName.endsWith('Id')) {
@@ -10687,7 +11793,7 @@ class ItemProperty {
10687
11793
  const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
10688
11794
  const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
10689
11795
  const propertyNameVariant = propertyNames.length > 1 ? propertyNames[1] : undefined;
10690
- const _mod_6 = await import('./index-DdzhrbkF.js');
11796
+ const _mod_6 = await import('./index-Bp0ChnQr.js');
10691
11797
  const _ns_6 = _mod_6.s;
10692
11798
  const seedSchemaMod = _ns_6;
10693
11799
  const { metadata } = seedSchemaMod;
@@ -11039,6 +12145,35 @@ class ItemProperty {
11039
12145
  instance._service.send({ type: 'updateContext', ...updates });
11040
12146
  }
11041
12147
  }
12148
+ // After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
12149
+ // paths would hydrate. Re-run DB hydration without clobbering propertyValue.
12150
+ const svc = instance._service;
12151
+ const snap = svc.getSnapshot();
12152
+ if (snap.status === 'active' && snap.value === 'idle') {
12153
+ const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
12154
+ const dt = normalizeDataType(schema?.dataType);
12155
+ const isHtmlProp = props.refSeedType === 'html' ||
12156
+ ctx.refSeedType === 'html' ||
12157
+ dt === ModelPropertyDataTypes.Html;
12158
+ const isListProp = dt === ModelPropertyDataTypes.List;
12159
+ const isRelationProp = dt === ModelPropertyDataTypes.Relation;
12160
+ const pv = ctx.propertyValue;
12161
+ const pvStr = typeof pv === 'string' ? pv.trim() : '';
12162
+ const renderVal = ctx.renderValue;
12163
+ const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
12164
+ const htmlStuckOnUid = isHtmlProp &&
12165
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
12166
+ (renderMissing || renderVal === pv);
12167
+ const pvPresent = pv != null &&
12168
+ (Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
12169
+ const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
12170
+ const versionChanged = props.versionLocalId != null &&
12171
+ ctx.versionLocalId != null &&
12172
+ props.versionLocalId !== ctx.versionLocalId;
12173
+ if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
12174
+ svc.send({ type: 'rehydrateFromDb' });
12175
+ }
12176
+ }
11042
12177
  // On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
11043
12178
  if (!waitForReady)
11044
12179
  return instance;
@@ -11388,7 +12523,7 @@ class ItemProperty {
11388
12523
  }
11389
12524
  async save() {
11390
12525
  const ctx = this._getSnapshotContext();
11391
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12526
+ const { assertItemOwned } = await import('./ownership-D-KsIkxM.js');
11392
12527
  await assertItemOwned({
11393
12528
  seedLocalId: ctx?.seedLocalId ?? undefined,
11394
12529
  seedUid: ctx?.seedUid ?? undefined,
@@ -11481,7 +12616,7 @@ class ItemProperty {
11481
12616
  if (!propertyName || (!seedLocalId && !seedUid))
11482
12617
  return;
11483
12618
  if (db) {
11484
- const _mod_7 = await import('./index-DdzhrbkF.js');
12619
+ const _mod_7 = await import('./index-Bp0ChnQr.js');
11485
12620
  const _ns_7 = _mod_7.s;
11486
12621
  const seedSchemaMod = _ns_7;
11487
12622
  const { metadata } = seedSchemaMod;
@@ -11729,7 +12864,7 @@ class Item {
11729
12864
  });
11730
12865
  };
11731
12866
  this.unpublish = async () => {
11732
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12867
+ const { assertItemOwned } = await import('./ownership-D-KsIkxM.js');
11733
12868
  const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
11734
12869
  await assertItemOwned(this);
11735
12870
  const seedUid = this.seedUid;
@@ -11753,7 +12888,7 @@ class Item {
11753
12888
  this._service.send({ type: 'updateContext', revokedAt });
11754
12889
  };
11755
12890
  this.publish = async () => {
11756
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12891
+ const { assertItemOwned } = await import('./ownership-D-KsIkxM.js');
11757
12892
  await assertItemOwned(this);
11758
12893
  this._service.send({ type: 'startPublish' });
11759
12894
  return new Promise((resolve, reject) => {
@@ -11789,12 +12924,12 @@ class Item {
11789
12924
  };
11790
12925
  this.getPublishUploads = async (options) => {
11791
12926
  // Use dynamic import to break circular dependency
11792
- const getPublishUploadsMod = await import('./getPublishUploads-DS2dQ4Ho.js');
12927
+ const getPublishUploadsMod = await import('./getPublishUploads-CH72lAID.js');
11793
12928
  const { getPublishUploads } = getPublishUploadsMod;
11794
12929
  return await getPublishUploads(this, [], undefined, options);
11795
12930
  };
11796
12931
  this.getPublishPayload = async (uploadedTransactions, options) => {
11797
- const getPublishPayloadMod = await import('./getPublishPayload-DpYwi-rd.js');
12932
+ const getPublishPayloadMod = await import('./getPublishPayload-DEdHgrgC.js');
11798
12933
  const { getPublishPayload } = getPublishPayloadMod;
11799
12934
  return await getPublishPayload(this, uploadedTransactions, options);
11800
12935
  };
@@ -11911,6 +13046,8 @@ class Item {
11911
13046
  'schemaUid',
11912
13047
  'latestVersionLocalId',
11913
13048
  'latestVersionUid',
13049
+ 'publishedVersionUid',
13050
+ 'publishedVersionLocalId',
11914
13051
  ];
11915
13052
  const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
11916
13053
  const schemaNameForModel = initialValues.schemaName;
@@ -11954,6 +13091,128 @@ class Item {
11954
13091
  });
11955
13092
  }
11956
13093
  }
13094
+ /** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
13095
+ static findItemInstanceCacheEntryByProps(props) {
13096
+ const l = props.seedLocalId;
13097
+ const u = props.seedUid;
13098
+ if (typeof l === 'string' && l.length > 0) {
13099
+ const e = this.instanceCache.get(l);
13100
+ if (e)
13101
+ return e;
13102
+ }
13103
+ if (typeof u === 'string' && u.length > 0) {
13104
+ const e = this.instanceCache.get(u);
13105
+ if (e)
13106
+ return e;
13107
+ }
13108
+ return undefined;
13109
+ }
13110
+ static findItemInstanceCacheEntryById(id) {
13111
+ const direct = this.instanceCache.get(id);
13112
+ if (direct)
13113
+ return direct;
13114
+ for (const [, entry] of this.instanceCache) {
13115
+ const ctx = entry.instance._getSnapshotContext();
13116
+ if (ctx.seedLocalId === id || ctx.seedUid === id)
13117
+ return entry;
13118
+ }
13119
+ return undefined;
13120
+ }
13121
+ static collectInstanceCacheKeysForInstance(instance) {
13122
+ const keys = [];
13123
+ for (const [k, v] of this.instanceCache) {
13124
+ if (v.instance === instance)
13125
+ keys.push(k);
13126
+ }
13127
+ return keys;
13128
+ }
13129
+ static registerItemInInstanceCache(instance) {
13130
+ const ctx = instance._getSnapshotContext();
13131
+ const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
13132
+ ? ctx.seedLocalId
13133
+ : undefined;
13134
+ const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
13135
+ const entry = { instance, refCount: 1 };
13136
+ if (lid)
13137
+ this.instanceCache.set(lid, entry);
13138
+ if (uid && uid !== lid)
13139
+ this.instanceCache.set(uid, entry);
13140
+ if (!lid && !uid) {
13141
+ throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
13142
+ }
13143
+ }
13144
+ static releaseItemInstanceCacheHold(instance) {
13145
+ const keys = this.collectInstanceCacheKeysForInstance(instance);
13146
+ if (keys.length === 0)
13147
+ return;
13148
+ const entry = this.instanceCache.get(keys[0]);
13149
+ entry.refCount -= 1;
13150
+ if (entry.refCount <= 0) {
13151
+ for (const k of keys) {
13152
+ this.instanceCache.delete(k);
13153
+ }
13154
+ }
13155
+ }
13156
+ /**
13157
+ * Item machine can reach `idle` before `propertyInstances` is merged (race) or while
13158
+ * child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
13159
+ */
13160
+ static async waitForItemInstanceReadyForRead(item, readyTimeout) {
13161
+ await waitForEntityIdle(item, { timeout: readyTimeout });
13162
+ const svc = item.getService();
13163
+ try {
13164
+ await waitFor(svc, (snap) => {
13165
+ if ('value' in snap && snap.value === 'error') {
13166
+ throw new Error('Entity failed to load');
13167
+ }
13168
+ if (!('value' in snap) || snap.value !== 'idle') {
13169
+ return false;
13170
+ }
13171
+ const ctx = snap.context || {};
13172
+ const versionsCount = ctx.versionsCount ?? 0;
13173
+ const hasHeadVersion = !!ctx.latestVersionLocalId;
13174
+ if (versionsCount === 0 && !hasHeadVersion) {
13175
+ return true;
13176
+ }
13177
+ return (ctx.propertyInstances?.size ?? 0) > 0;
13178
+ }, { timeout: readyTimeout });
13179
+ }
13180
+ catch (e) {
13181
+ if (e?.message === 'Entity failed to load') {
13182
+ throw e;
13183
+ }
13184
+ const msg = typeof e?.message === 'string' ? e.message : '';
13185
+ const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
13186
+ if (!isWaitForTimeout) {
13187
+ throw e;
13188
+ }
13189
+ }
13190
+ const snap = svc.getSnapshot();
13191
+ const pis = snap.context?.propertyInstances;
13192
+ if (!pis || pis.size === 0) {
13193
+ return;
13194
+ }
13195
+ await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
13196
+ timeout: readyTimeout,
13197
+ throwOnError: false,
13198
+ })));
13199
+ }
13200
+ static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
13201
+ const snap = instance.getService().getSnapshot();
13202
+ if (snap.value !== 'idle')
13203
+ return false;
13204
+ const mapSize = snap.context.propertyInstances?.size ?? 0;
13205
+ if (mapSize > 0)
13206
+ return false;
13207
+ const ctx = snap.context;
13208
+ const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
13209
+ const hasVersionHead = versionsCount > 0 ||
13210
+ !!props.latestVersionLocalId ||
13211
+ !!ctx.latestVersionLocalId ||
13212
+ !!props.latestVersionUid ||
13213
+ !!ctx.latestVersionUid;
13214
+ return hasVersionHead;
13215
+ }
11957
13216
  static async create(props, options) {
11958
13217
  const waitForReady = options?.waitForReady !== false;
11959
13218
  const readyTimeout = options?.readyTimeout ?? 5000;
@@ -11961,45 +13220,66 @@ class Item {
11961
13220
  props.modelName = startCase(props.type);
11962
13221
  }
11963
13222
  if (props.seedUid || props.seedLocalId) {
11964
- const seedId = (props.seedUid || props.seedLocalId);
11965
- if (this.instanceCache.has(seedId)) {
11966
- const { instance, refCount } = this.instanceCache.get(seedId);
11967
- this.instanceCache.set(seedId, {
11968
- instance,
11969
- refCount: refCount + 1,
11970
- });
11971
- for (const [propertyName, propertyValue] of Object.entries(props)) {
11972
- const snapshot = instance.getService().getSnapshot();
11973
- const propertyInstances = snapshot.context.propertyInstances;
11974
- if (!propertyInstances || !propertyInstances.has(propertyName)) {
11975
- continue;
11976
- }
11977
- const propertyInstance = propertyInstances.get(propertyName);
11978
- if (!propertyInstance) {
11979
- continue;
13223
+ cacheReuse: {
13224
+ const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
13225
+ if (cachedEntry) {
13226
+ const instance = cachedEntry.instance;
13227
+ cachedEntry.refCount += 1;
13228
+ for (const [propertyName, propertyValue] of Object.entries(props)) {
13229
+ const snapshot = instance.getService().getSnapshot();
13230
+ const propertyInstances = snapshot.context.propertyInstances;
13231
+ if (!propertyInstances || !propertyInstances.has(propertyName)) {
13232
+ continue;
13233
+ }
13234
+ const propertyInstance = propertyInstances.get(propertyName);
13235
+ if (!propertyInstance) {
13236
+ continue;
13237
+ }
13238
+ propertyInstance.getService().send({
13239
+ type: 'updateContext',
13240
+ propertyValue,
13241
+ });
11980
13242
  }
11981
- propertyInstance.getService().send({
11982
- type: 'updateContext',
11983
- propertyValue,
11984
- });
11985
- }
11986
- if (!waitForReady)
11987
- return instance;
11988
- try {
11989
- await waitForEntityIdle(instance, { timeout: readyTimeout });
11990
- }
11991
- catch (err) {
13243
+ if (!waitForReady)
13244
+ return instance;
11992
13245
  try {
11993
- instance.unload();
13246
+ await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
11994
13247
  }
11995
- catch {
11996
- /* best-effort cache cleanup */
13248
+ catch (err) {
13249
+ try {
13250
+ instance.unload();
13251
+ }
13252
+ catch {
13253
+ /* best-effort cache cleanup */
13254
+ }
13255
+ throw err;
11997
13256
  }
11998
- throw err;
13257
+ if (waitForReady &&
13258
+ this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
13259
+ forceRemoveFromCaches(instance, {
13260
+ getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
13261
+ caches: [Item.instanceCache],
13262
+ });
13263
+ try {
13264
+ unloadEntity(instance, {
13265
+ getCacheKeys: () => [],
13266
+ caches: [],
13267
+ instanceState: itemInstanceState,
13268
+ getService: (inst) => inst._service,
13269
+ onUnload: (inst) => {
13270
+ inst._subscription?.unsubscribe();
13271
+ },
13272
+ });
13273
+ }
13274
+ catch {
13275
+ /* best-effort teardown for stale cached shell */
13276
+ }
13277
+ break cacheReuse;
13278
+ }
13279
+ return instance;
11999
13280
  }
12000
- return instance;
12001
13281
  }
12002
- if (!this.instanceCache.has(seedId)) {
13282
+ if (!this.findItemInstanceCacheEntryByProps(props)) {
12003
13283
  // Item no longer needs modelInstance - it loads properties from database independently
12004
13284
  // Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
12005
13285
  const { latestVersionUid, ...propsWithoutVersionUid } = props;
@@ -12088,14 +13368,11 @@ class Item {
12088
13368
  return Reflect.getOwnPropertyDescriptor(target, prop);
12089
13369
  },
12090
13370
  });
12091
- this.instanceCache.set(seedId, {
12092
- instance: proxiedInstance,
12093
- refCount: 1,
12094
- });
13371
+ this.registerItemInInstanceCache(proxiedInstance);
12095
13372
  if (!waitForReady)
12096
13373
  return proxiedInstance;
12097
13374
  try {
12098
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13375
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12099
13376
  }
12100
13377
  catch (err) {
12101
13378
  try {
@@ -12271,14 +13548,11 @@ class Item {
12271
13548
  return Reflect.getOwnPropertyDescriptor(target, prop);
12272
13549
  },
12273
13550
  });
12274
- this.instanceCache.set((proxiedInstance.seedUid || proxiedInstance.seedLocalId), {
12275
- instance: proxiedInstance,
12276
- refCount: 1,
12277
- });
13551
+ this.registerItemInInstanceCache(proxiedInstance);
12278
13552
  if (!waitForReady)
12279
13553
  return proxiedInstance;
12280
13554
  try {
12281
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13555
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12282
13556
  }
12283
13557
  catch (err) {
12284
13558
  try {
@@ -12301,14 +13575,10 @@ class Item {
12301
13575
  if (!id) {
12302
13576
  return null;
12303
13577
  }
12304
- // Check cache - the cache key is seedUid || seedLocalId
12305
- if (this.instanceCache.has(id)) {
12306
- const { instance, refCount } = this.instanceCache.get(id);
12307
- this.instanceCache.set(id, {
12308
- instance,
12309
- refCount: refCount + 1,
12310
- });
12311
- return instance;
13578
+ const entry = this.findItemInstanceCacheEntryById(id);
13579
+ if (entry) {
13580
+ entry.refCount += 1;
13581
+ return entry.instance;
12312
13582
  }
12313
13583
  return null;
12314
13584
  }
@@ -12354,8 +13624,8 @@ class Item {
12354
13624
  if (!seedLocalId && !seedUid) {
12355
13625
  return undefined;
12356
13626
  }
12357
- // Use seedUid as primary ID if available, otherwise use seedLocalId
12358
- const id = seedUid || seedLocalId;
13627
+ // Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
13628
+ const id = seedLocalId || seedUid;
12359
13629
  if (!id) {
12360
13630
  return undefined;
12361
13631
  }
@@ -12386,10 +13656,129 @@ class Item {
12386
13656
  }));
12387
13657
  }
12388
13658
  if (waitForReady && itemInstances.length > 0) {
12389
- await Promise.all(itemInstances.map((item) => waitForEntityIdle(item, { timeout: readyTimeout })));
13659
+ await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
12390
13660
  }
12391
13661
  return orderBy(itemInstances, ['createdAt'], ['desc']);
12392
13662
  }
13663
+ /**
13664
+ * After EAS sync writes metadata for the latest version, merge new property instances and
13665
+ * re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
13666
+ * and useItems may not invalidate when the seed set is unchanged.
13667
+ */
13668
+ static async rehydrateCachedItemsFromDbAfterEasSync() {
13669
+ const appDb = BaseDb.getAppDb();
13670
+ if (!appDb || Item.instanceCache.size === 0) {
13671
+ return;
13672
+ }
13673
+ const _mod_8 = await import('./index-Bp0ChnQr.js');
13674
+ const _ns_8 = _mod_8.s;
13675
+ const { metadata } = _ns_8;
13676
+ const { eq, and } = await import('drizzle-orm');
13677
+ const dedupedInstances = new Map();
13678
+ for (const entry of Item.instanceCache.values()) {
13679
+ dedupedInstances.set(entry.instance, entry);
13680
+ }
13681
+ const entries = [...dedupedInstances.values()];
13682
+ await Promise.all(entries.map(async ({ instance }) => {
13683
+ try {
13684
+ const svc = instance.getService();
13685
+ if (svc.getSnapshot().status !== 'active') {
13686
+ return;
13687
+ }
13688
+ const ctx = svc.getSnapshot().context;
13689
+ const seedLocalId = ctx.seedLocalId;
13690
+ const seedUid = ctx.seedUid;
13691
+ const versionLocalId = ctx.latestVersionLocalId;
13692
+ const itemModelName = ctx.modelName;
13693
+ const schemaNameForModel = ctx.schemaName;
13694
+ if (!seedLocalId || !versionLocalId || !itemModelName) {
13695
+ return;
13696
+ }
13697
+ const metadataRows = await appDb
13698
+ .select()
13699
+ .from(metadata)
13700
+ .where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
13701
+ let propertySchemas = {};
13702
+ try {
13703
+ const M = getModel();
13704
+ const model = schemaNameForModel !== undefined
13705
+ ? M?.getByName(itemModelName, schemaNameForModel)
13706
+ : M?.getByName(itemModelName);
13707
+ if (model?.properties?.length) {
13708
+ propertySchemas = modelPropertiesToObject(model.properties);
13709
+ }
13710
+ }
13711
+ catch {
13712
+ /* Model optional */
13713
+ }
13714
+ const sendToItemMachine = (event) => {
13715
+ if (svc.getSnapshot().status !== 'active') {
13716
+ return;
13717
+ }
13718
+ svc.send(event);
13719
+ };
13720
+ for (const metaRow of metadataRows) {
13721
+ try {
13722
+ let propertyName = metaRow.propertyName;
13723
+ const listSchemaKey = propertyName &&
13724
+ Object.keys(propertySchemas).length > 0 &&
13725
+ resolveStorageNameToSchemaName(propertySchemas, propertyName);
13726
+ if (listSchemaKey) {
13727
+ propertyName = listSchemaKey;
13728
+ }
13729
+ else {
13730
+ const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
13731
+ const refSeedType = metaRow.refSeedType;
13732
+ const isRefTypeFromMeta = refSeedType === 'file' ||
13733
+ refSeedType === 'image' ||
13734
+ refSeedType === 'relation' ||
13735
+ refSeedType === 'html';
13736
+ if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
13737
+ propertyName = baseName;
13738
+ }
13739
+ }
13740
+ if (!propertyName) {
13741
+ continue;
13742
+ }
13743
+ const property = await ItemProperty.find({
13744
+ propertyName,
13745
+ seedLocalId,
13746
+ seedUid,
13747
+ modelName: itemModelName,
13748
+ });
13749
+ if (property) {
13750
+ sendToItemMachine({
13751
+ type: 'addPropertyInstance',
13752
+ propertyName,
13753
+ propertyInstance: property,
13754
+ });
13755
+ }
13756
+ }
13757
+ catch {
13758
+ /* row skipped */
13759
+ }
13760
+ }
13761
+ const instances = svc.getSnapshot().context.propertyInstances;
13762
+ if (!instances) {
13763
+ return;
13764
+ }
13765
+ for (const propertyInstance of instances.values()) {
13766
+ try {
13767
+ const propertySnap = propertyInstance.getService().getSnapshot();
13768
+ if (isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
13769
+ propertyInstance.getService().send({ type: 'rehydrateFromDb' });
13770
+ }
13771
+ }
13772
+ catch {
13773
+ /* best-effort */
13774
+ }
13775
+ }
13776
+ }
13777
+ catch (e) {
13778
+ itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
13779
+ }
13780
+ }));
13781
+ }
12393
13782
  _createPropertyInstance(props) {
12394
13783
  if (this._storageTransactionId) {
12395
13784
  props.storageTransactionId = this._storageTransactionId;
@@ -12732,9 +14121,9 @@ class Item {
12732
14121
  itemActor.send(event);
12733
14122
  };
12734
14123
  try {
12735
- const _mod_8 = await import('./index-DdzhrbkF.js');
12736
- const _ns_8 = _mod_8.s;
12737
- const seedSchemaMod = _ns_8;
14124
+ const _mod_9 = await import('./index-Bp0ChnQr.js');
14125
+ const _ns_9 = _mod_9.s;
14126
+ const seedSchemaMod = _ns_9;
12738
14127
  const { seeds, versions, metadata } = seedSchemaMod;
12739
14128
  const drizzleMod = await import('drizzle-orm');
12740
14129
  const { eq, and } = drizzleMod;
@@ -13006,15 +14395,10 @@ class Item {
13006
14395
  }
13007
14396
  unload() {
13008
14397
  try {
13009
- const context = this._getSnapshotContext();
13010
- const cacheKey = context.seedUid || context.seedLocalId;
13011
- const cacheKeys = [];
13012
- if (cacheKey) {
13013
- cacheKeys.push(cacheKey);
13014
- }
14398
+ Item.releaseItemInstanceCacheHold(this);
13015
14399
  unloadEntity(this, {
13016
- getCacheKeys: () => cacheKeys,
13017
- caches: [Item.instanceCache],
14400
+ getCacheKeys: () => [],
14401
+ caches: [],
13018
14402
  instanceState: itemInstanceState,
13019
14403
  getService: (instance) => instance._service,
13020
14404
  onUnload: (instance) => {
@@ -13043,11 +14427,10 @@ class Item {
13043
14427
  * Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
13044
14428
  */
13045
14429
  async destroy() {
13046
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
14430
+ const { assertItemOwned } = await import('./ownership-D-KsIkxM.js');
13047
14431
  await assertItemOwned(this);
13048
14432
  const context = this._getSnapshotContext();
13049
- const cacheKey = context.seedUid || context.seedLocalId;
13050
- const cacheKeys = cacheKey ? [cacheKey] : [];
14433
+ const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
13051
14434
  clearDestroySubscriptions(this, {
13052
14435
  instanceState: itemInstanceState,
13053
14436
  onUnload: (instance) => instance._subscription?.unsubscribe(),
@@ -13104,600 +14487,331 @@ function normalizeAddressConfig(addresses) {
13104
14487
  };
13105
14488
  }
13106
14489
 
13107
- // Dynamic import to break circular dependency: Model -> BaseItem -> ... -> getModelSchemas -> Model
13108
- // import { Model } from '@/Model/Model'
13109
- const schemaStringToModelRecord = new Map();
13110
- const getModelSchemas = async () => {
13111
- // Dynamic import to break circular dependency
13112
- const modelMod = await Promise.resolve().then(function () { return Model$1; });
13113
- const { Model } = modelMod;
13114
- const allModels = await Model.all();
13115
- const modelRecords = [];
13116
- const appDb = BaseDb.getAppDb();
13117
- for (const model of allModels) {
13118
- const modelName = model.modelName;
13119
- if (!modelName)
13120
- continue;
13121
- const foundModelQuery = await appDb
13122
- .select({
13123
- id: models$1.id,
13124
- name: models$1.name,
13125
- uid: modelUids.uid,
14490
+ let writeTail = Promise.resolve();
14491
+ function enqueueEasSyncDbWrite(fn) {
14492
+ const next = writeTail.then(fn);
14493
+ writeTail = next.catch(() => { });
14494
+ return next;
14495
+ }
14496
+ const MAX_ERROR_MESSAGE_LENGTH = 500;
14497
+ const MAX_ERROR_DETAILS_LENGTH = 2000;
14498
+ async function insertEasSyncProcessRow(params) {
14499
+ return enqueueEasSyncDbWrite(async () => {
14500
+ const db = BaseDb.getAppDb();
14501
+ if (!db) {
14502
+ throw new Error('[easSyncProcess] App DB not available');
14503
+ }
14504
+ const now = Date.now();
14505
+ const [row] = await db
14506
+ .insert(easSyncProcesses)
14507
+ .values({
14508
+ status: 'in_progress',
14509
+ startedAt: now,
14510
+ requestPayload: JSON.stringify(params.requestPayload),
14511
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14512
+ createdAt: now,
14513
+ updatedAt: now,
13126
14514
  })
13127
- .from(models$1)
13128
- .leftJoin(modelUids, eq(models$1.id, modelUids.modelId))
13129
- .where(eq(models$1.name, modelName))
13130
- .limit(1);
13131
- if (!foundModelQuery[0]) {
13132
- console.error(`[item/events] [syncDbWithEas] model ${modelName} not found in SDK DB`);
13133
- continue;
13134
- }
13135
- const foundModel = {
13136
- id: foundModelQuery[0].id,
13137
- name: foundModelQuery[0].name,
13138
- uid: foundModelQuery[0].uid,
13139
- tableName: pluralize(foundModelQuery[0].name).toLowerCase(),
13140
- };
13141
- modelRecords.push(foundModel);
13142
- if (modelName === 'Seed') {
13143
- continue;
13144
- }
13145
- const schemaString = `bytes32 ${toSnakeCase(modelName)}`;
13146
- schemaStringToModelRecord.set(schemaString, foundModel);
13147
- }
13148
- return {
13149
- schemaStringToModelRecord,
13150
- modelRecords,
13151
- };
13152
- };
13153
-
13154
- const createSeeds = async (newSeeds) => {
13155
- const appDb = BaseDb.getAppDb();
13156
- const results = await appDb
13157
- .insert(seeds)
13158
- .values(newSeeds)
13159
- .returning({ uid: seeds.uid });
13160
- const newUids = results.reduce((acc, result) => {
13161
- if (result.uid) {
13162
- acc.push(result.uid);
14515
+ .returning({ id: easSyncProcesses.id });
14516
+ return row.id;
14517
+ });
14518
+ }
14519
+ async function finalizeEasSyncProcessRow(id, params) {
14520
+ return enqueueEasSyncDbWrite(async () => {
14521
+ const db = BaseDb.getAppDb();
14522
+ if (!db) {
14523
+ return;
13163
14524
  }
13164
- return acc;
13165
- }, []);
13166
- return newUids;
13167
- };
14525
+ const now = Date.now();
14526
+ await db
14527
+ .update(easSyncProcesses)
14528
+ .set({
14529
+ status: params.status,
14530
+ completedAt: now,
14531
+ updatedAt: now,
14532
+ errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
14533
+ errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
14534
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14535
+ })
14536
+ .where(eq(easSyncProcesses.id, id));
14537
+ });
14538
+ }
13168
14539
 
13169
14540
  /**
13170
- * Sets revokedAt timestamp on a seed record after attestations have been revoked on EAS.
14541
+ * Merge multiple EAS sync intents: full sync (no concrete address list) wins;
14542
+ * otherwise union addresses (first-seen casing).
13171
14543
  */
13172
- const updateSeedRevokedAt = async ({ seedLocalId, revokedAt, }) => {
13173
- if (!seedLocalId) {
13174
- return;
14544
+ function mergeEasSyncRequestIntents(parts) {
14545
+ const norm = parts.filter((p) => p != null);
14546
+ if (norm.length === 0) {
14547
+ return {};
13175
14548
  }
13176
- const appDb = BaseDb.getAppDb();
13177
- await appDb
13178
- .update(seeds)
13179
- .set({
13180
- revokedAt,
13181
- updatedAt: Date.now(),
13182
- })
13183
- .where(eq(seeds.localId, seedLocalId));
13184
- };
13185
-
13186
- const relationValuesToExclude = [
13187
- '0x0000000000000000000000000000000000000000000000000000000000000020',
13188
- ];
13189
- const seedUidToLocalId = new Map();
13190
- const seedUidToModelType = new Map();
13191
- const relatedSeedUids = new Set();
13192
- const versionUidToLocalId = new Map();
13193
- const versionUidToSeedUid = new Map();
13194
- const propertyUidToLocalId = new Map();
13195
- const saveEasSeedsToDb = async ({ itemSeeds }) => {
13196
- const appDb = BaseDb.getAppDb();
13197
- const seedUids = itemSeeds.map((seed) => seed.id);
13198
- const existingSeedRecordsRows = await appDb
13199
- .select()
13200
- .from(seeds)
13201
- .where(inArray(seeds.uid, seedUids));
13202
- const existingSeedUids = new Set();
13203
- if (existingSeedRecordsRows && existingSeedRecordsRows.length > 0) {
13204
- for (const row of existingSeedRecordsRows) {
13205
- if (row.uid) {
13206
- existingSeedUids.add(row.uid);
13207
- if (row.localId) {
13208
- seedUidToLocalId.set(row.uid, row.localId);
13209
- }
13210
- if (row.type) {
13211
- seedUidToModelType.set(row.uid, row.type);
13212
- }
14549
+ let full = false;
14550
+ const addressMap = new Map();
14551
+ for (const p of norm) {
14552
+ if (!('addresses' in p) || p.addresses === undefined) {
14553
+ full = true;
14554
+ break;
14555
+ }
14556
+ for (const addr of p.addresses) {
14557
+ const k = addr.toLowerCase();
14558
+ if (!addressMap.has(k)) {
14559
+ addressMap.set(k, addr);
13213
14560
  }
13214
14561
  }
13215
14562
  }
13216
- const newSeeds = itemSeeds.filter((seed) => !existingSeedUids.has(seed.id));
13217
- // Update existing seeds when attestations are revoked on EAS
13218
- const seedByUid = new Map(itemSeeds.map((s) => [s.id, s]));
13219
- for (const row of existingSeedRecordsRows) {
13220
- if (!row.uid || !row.localId)
13221
- continue;
13222
- const attestation = seedByUid.get(row.uid);
13223
- if (!attestation?.revoked)
13224
- continue;
13225
- if (row.revokedAt != null)
13226
- continue;
13227
- const revokedAt = attestation.revocationTime > 0
13228
- ? attestation.revocationTime
13229
- : Math.floor(Date.now() / 1000);
13230
- await updateSeedRevokedAt({ seedLocalId: row.localId, revokedAt });
13231
- }
13232
- if (newSeeds.length === 0) {
13233
- return { seedUidToLocalId, seedUids };
13234
- }
13235
- const newSeedsData = [];
13236
- for (let i = 0; i < newSeeds.length; i++) {
13237
- const seed = newSeeds[i];
13238
- seedUidToModelType.set(seed.id, seed.schema.schemaNames[0].name);
13239
- const seedLocalId = generateId();
13240
- seedUidToLocalId.set(seed.id, seedLocalId);
13241
- const attestationRaw = escapeSqliteString(JSON.stringify(seed));
13242
- const revokedAt = seed.revoked && seed.revocationTime != null && seed.revocationTime > 0
13243
- ? seed.revocationTime
13244
- : seed.revoked
13245
- ? Math.floor(Date.now() / 1000)
13246
- : undefined;
13247
- newSeedsData.push({
13248
- localId: seedLocalId,
13249
- uid: seed.id,
13250
- schemaUid: seed.schemaId,
13251
- type: seed.schema.schemaNames[0].name,
13252
- publisher: seed.attester,
13253
- createdAt: Date.now(),
13254
- attestationCreatedAt: seed.timeCreated * 1000,
13255
- attestationRaw,
13256
- ...(revokedAt !== undefined && { revokedAt }),
13257
- });
13258
- seedUidToLocalId.set(seed.id, seedLocalId);
14563
+ if (full) {
14564
+ return {};
13259
14565
  }
13260
- const newSeedUids = await createSeeds(newSeedsData);
13261
- return { seedUids: newSeedUids };
13262
- };
13263
- const saveEasVersionsToDb = async ({ itemVersions }) => {
13264
- const versionUids = itemVersions.map((version) => version.id);
13265
- const appDb = BaseDb.getAppDb();
13266
- const existingVersionRecordsRows = await appDb
13267
- .select()
13268
- .from(versions)
13269
- .where(inArray(versions.uid, versionUids));
13270
- const existingVersionUids = new Set();
13271
- if (existingVersionRecordsRows && existingVersionRecordsRows.length > 0) {
13272
- for (const row of existingVersionRecordsRows) {
13273
- if (row.uid) {
13274
- existingVersionUids.add(row.uid);
13275
- if (row.localId) {
13276
- versionUidToLocalId.set(row.uid, row.localId);
13277
- }
13278
- if (row.seedUid) {
13279
- versionUidToSeedUid.set(row.uid, row.seedUid);
13280
- }
13281
- }
13282
- }
13283
- }
13284
- const newVersions = itemVersions.filter((version) => !existingVersionUids.has(version.id));
13285
- if (newVersions.length === 0) {
13286
- return { versionUidToLocalId, versionUids };
13287
- }
13288
- let insertVersionsQuery = `INSERT INTO versions (local_id, uid, seed_uid, seed_local_id, seed_type, created_at,
13289
- attestation_created_at,
13290
- attestation_raw, publisher)
13291
- VALUES `;
13292
- for (let i = 0; i < newVersions.length; i++) {
13293
- const version = newVersions[i];
13294
- versionUidToSeedUid.set(version.id, version.refUID);
13295
- const versionLocalId = generateId();
13296
- versionUidToLocalId.set(version.id, versionLocalId);
13297
- const seedUid = versionUidToSeedUid.get(version.id);
13298
- const seedLocalId = seedUidToLocalId.get(seedUid);
13299
- const seedType = seedUidToModelType.get(seedUid);
13300
- const attestationRaw = escapeSqliteString(JSON.stringify(version));
13301
- const publisher = escapeSqliteString(version.attester ?? '');
13302
- const valuesString = `('${versionLocalId}', '${version.id}', '${seedUid}', '${seedLocalId}', '${seedType}', ${Date.now()}, ${version.timeCreated * 1000}, '${attestationRaw}', '${publisher}')`;
13303
- if (i < newVersions.length - 1) {
13304
- insertVersionsQuery += valuesString + ', ';
13305
- }
13306
- if (i === newVersions.length - 1) {
13307
- insertVersionsQuery += valuesString + ';';
13308
- }
13309
- versionUidToLocalId.set(version.id, versionLocalId);
13310
- }
13311
- await appDb.run(sql.raw(insertVersionsQuery));
13312
- return { versionUids };
13313
- };
13314
- const createMetadataRecordsForStorageTransactionId = async (storageTransactionIdProperty, modelSchema) => {
13315
- // Early return if modelSchema is not provided
13316
- if (!modelSchema) {
13317
- console.warn('[item/events] [syncDbWithEas] modelSchema is undefined for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
13318
- return;
14566
+ if (addressMap.size === 0) {
14567
+ return { addresses: [] };
13319
14568
  }
13320
- // Validate and parse decodedDataJson
13321
- if (!storageTransactionIdProperty.decodedDataJson || storageTransactionIdProperty.decodedDataJson.trim() === '') {
13322
- console.warn('[item/events] [syncDbWithEas] empty decodedDataJson for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
13323
- return;
14569
+ return { addresses: [...addressMap.values()] };
14570
+ }
14571
+
14572
+ const log = debug('seedSdk:events:easSyncManager');
14573
+ function toRunSyncArg(options) {
14574
+ if (options &&
14575
+ 'addresses' in options &&
14576
+ options.addresses !== undefined) {
14577
+ return options;
13324
14578
  }
13325
- let parsedData;
14579
+ return undefined;
14580
+ }
14581
+ const runEasSync = fromPromise(async ({ input, }) => {
14582
+ const rowId = await insertEasSyncProcessRow({
14583
+ requestPayload: input.requestPayload,
14584
+ persistedSnapshot: input.runningSnapshot,
14585
+ });
14586
+ const { runSyncFromEas } = await import('./syncDbWithEas-m-_3Ds7d.js');
13326
14587
  try {
13327
- parsedData = JSON.parse(storageTransactionIdProperty.decodedDataJson);
13328
- }
13329
- catch (error) {
13330
- console.warn('[item/events] [syncDbWithEas] failed to parse decodedDataJson for storageTransactionIdProperty: ', storageTransactionIdProperty.id, error);
13331
- return;
13332
- }
13333
- if (!Array.isArray(parsedData) || parsedData.length === 0 || !parsedData[0]?.value) {
13334
- console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
13335
- return;
13336
- }
13337
- const attestationData = parsedData[0].value;
13338
- camelCase(attestationData.name);
13339
- const propertyValue = attestationData.value;
13340
- const itemStorageProperties = new Map();
13341
- for (const [_propertyName, propertyDef] of Object.entries(modelSchema)) {
13342
- if (propertyDef?.storageType && propertyDef.storageType === 'ItemStorage') {
13343
- itemStorageProperties.set(_propertyName, propertyDef);
13344
- }
13345
- }
13346
- if (itemStorageProperties.size === 0) {
13347
- return;
13348
- }
13349
- const appDb = BaseDb.getAppDb();
13350
- for (const [_propertyName, propertyDef] of itemStorageProperties.entries()) {
13351
- const existingMetadataRecordRows = await appDb
13352
- .select()
13353
- .from(metadata$1)
13354
- .where(and(eq(metadata$1.propertyName, _propertyName), eq(metadata$1.propertyValue, propertyValue), eq(metadata$1.versionUid, storageTransactionIdProperty.refUID)));
13355
- if (existingMetadataRecordRows && existingMetadataRecordRows.length > 0) {
13356
- continue;
13357
- }
13358
- const seedUid = versionUidToSeedUid.get(storageTransactionIdProperty.refUID);
13359
- const seedLocalId = seedUidToLocalId.get(seedUid);
13360
- const versionUid = storageTransactionIdProperty.refUID;
13361
- const versionLocalId = versionUidToLocalId.get(versionUid);
13362
- const modelType = seedUidToModelType.get(seedUid);
13363
- const propertyId = modelType != null
13364
- ? await getPropertyIdForModelAndName(modelType, _propertyName)
13365
- : null;
13366
- const propertyLocalId = generateId();
13367
- await appDb.insert(metadata$1).values({
13368
- localId: propertyLocalId,
13369
- propertyId: propertyId ?? undefined,
13370
- propertyName: _propertyName,
13371
- propertyValue,
13372
- localStorageDir: propertyDef.localStorageDir,
13373
- seedLocalId,
13374
- seedUid,
13375
- versionLocalId,
13376
- versionUid,
13377
- refValueType: 'file',
13378
- refResolvedValue: `${propertyValue}${propertyDef.filenameSuffix}`,
13379
- modelType: seedUidToModelType.get(seedUid),
13380
- createdAt: Date.now(),
13381
- updatedAt: Date.now(),
14588
+ await runSyncFromEas(toRunSyncArg(input.options));
14589
+ await finalizeEasSyncProcessRow(rowId, {
14590
+ status: 'completed',
14591
+ persistedSnapshot: {
14592
+ phase: 'completed',
14593
+ correlationIds: input.requestPayload.correlationIds,
14594
+ },
13382
14595
  });
13383
14596
  }
13384
- };
13385
- let isSavingToDb = false;
13386
- const saveEasPropertiesToDb = async ({ itemProperties, itemSeeds, }) => {
13387
- if (isSavingToDb) {
13388
- return { propertyUids: [] };
13389
- }
13390
- isSavingToDb = true;
13391
- const propertyUids = itemProperties.map((property) => property.id);
13392
- // Dynamic import to break circular dependency
13393
- const modelMod = await Promise.resolve().then(function () { return Model$1; });
13394
- const { Model } = modelMod;
13395
- const allModels = await Model.all();
13396
- const models = Object.fromEntries(allModels.map(m => [m.modelName, m]));
13397
- const appDb = BaseDb.getAppDb();
13398
- const existingMetadataRecordsRows = await appDb
13399
- .select()
13400
- .from(metadata$1)
13401
- .where(inArray(metadata$1.uid, propertyUids));
13402
- const existingPropertyRecordsUids = new Set();
13403
- if (existingMetadataRecordsRows && existingMetadataRecordsRows.length > 0) {
13404
- for (const row of existingMetadataRecordsRows) {
13405
- if (row.uid) {
13406
- existingPropertyRecordsUids.add(row.uid);
13407
- if (row.localId) {
13408
- propertyUidToLocalId.set(row.uid, row.localId);
13409
- }
13410
- }
13411
- }
13412
- }
13413
- const newProperties = itemProperties.filter((property) => !existingPropertyRecordsUids.has(property.id));
13414
- if (newProperties.length === 0) {
13415
- return { propertyUidToLocalId, propertyUids };
13416
- }
13417
- let insertPropertiesQuery = `INSERT INTO metadata (local_id, uid, schema_uid, property_id, property_name, property_value,
13418
- eas_data_type, version_uid, version_local_id, seed_uid,
13419
- seed_local_id, model_type, ref_value_type, ref_seed_type,
13420
- ref_schema_uid,
13421
- created_at, attestation_created_at, attestation_raw,
13422
- local_storage_dir, ref_resolved_value, publisher)
13423
- VALUES `;
13424
- for (let i = 0; i < newProperties.length; i++) {
13425
- const property = newProperties[i];
13426
- const propertyLocalId = generateId();
13427
- // Validate and parse decodedDataJson
13428
- if (!property.decodedDataJson || property.decodedDataJson.trim() === '') {
13429
- console.warn('[item/events] [syncDbWithEas] empty decodedDataJson for property: ', property.id);
13430
- continue;
13431
- }
13432
- let parsedData;
13433
- try {
13434
- parsedData = JSON.parse(property.decodedDataJson);
13435
- }
13436
- catch (error) {
13437
- console.warn('[item/events] [syncDbWithEas] failed to parse decodedDataJson for property: ', property.id, error);
13438
- continue;
13439
- }
13440
- if (!Array.isArray(parsedData) || parsedData.length === 0 || !parsedData[0]?.value) {
13441
- console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for property: ', property.id);
13442
- continue;
13443
- }
13444
- const metadata = parsedData[0].value;
13445
- let propertyNameSnake = metadata.name;
13446
- if (!propertyNameSnake) {
13447
- console.warn('[item/events] [syncDbWithEas] no propertyName found for property: ', property);
13448
- continue;
13449
- }
13450
- let isRelation = false;
13451
- let refValueType;
13452
- let refSeedType;
13453
- let refSchemaUid;
13454
- let isList = false;
13455
- const schemaUid = property.schemaId;
13456
- setSchemaUidForSchemaDefinition({
13457
- text: propertyNameSnake,
13458
- schemaUid,
14597
+ catch (err) {
14598
+ const message = err instanceof Error ? err.message : String(err);
14599
+ const details = err instanceof Error && err.stack
14600
+ ? err.stack.slice(0, 2000)
14601
+ : undefined;
14602
+ await finalizeEasSyncProcessRow(rowId, {
14603
+ status: 'failed',
14604
+ errorMessage: message,
14605
+ errorDetails: details,
14606
+ persistedSnapshot: {
14607
+ phase: 'failed',
14608
+ correlationIds: input.requestPayload.correlationIds,
14609
+ },
13459
14610
  });
13460
- if ((propertyNameSnake.endsWith('_id') ||
13461
- propertyNameSnake.endsWith('_ids')) &&
13462
- propertyNameSnake !== 'storage_transaction_id' &&
13463
- propertyNameSnake !== 'storage_provider_transaction_id') {
13464
- isRelation = true;
13465
- if (Array.isArray(metadata.value)) {
13466
- isList = true;
13467
- refValueType = 'list';
13468
- const result = parseEasRelationPropertyName(propertyNameSnake);
13469
- if (result) {
13470
- propertyNameSnake = result.propertyName;
13471
- refSeedType = result.modelName;
13472
- }
13473
- metadata.value.forEach((value) => {
13474
- relatedSeedUids.add(value);
13475
- });
13476
- }
13477
- if (!isList) {
13478
- if (relationValuesToExclude.includes(metadata.value)) {
13479
- continue;
13480
- }
13481
- relatedSeedUids.add(metadata.value);
13482
- }
13483
- }
13484
- let propertyValue = metadata.value;
13485
- if (typeof propertyValue !== 'string') {
13486
- propertyValue = JSON.stringify(propertyValue);
13487
- }
13488
- if (isRelation && !isList) {
13489
- const relatedSeed = itemSeeds.find((seed) => seed.id === metadata.value);
13490
- if (relatedSeed && relatedSeed.schema && relatedSeed.schema.schemaNames) {
13491
- refSeedType = relatedSeed.schema.schemaNames[0].name;
13492
- refSchemaUid = relatedSeed.schemaId;
13493
- }
13494
- }
13495
- if (isRelation && isList) {
13496
- const relatedSeeds = itemSeeds.filter((seed) => metadata.value.includes(seed.id));
13497
- if (relatedSeeds && relatedSeeds.length > 0) {
13498
- refSeedType = relatedSeeds[0].schema.schemaNames[0].name;
13499
- refSchemaUid = relatedSeeds[0].schemaId;
13500
- }
13501
- }
13502
- const propertyName = camelCase(propertyNameSnake);
13503
- propertyValue = escapeSqliteString(propertyValue);
13504
- const easDataType = metadata.type;
13505
- const versionUid = property.refUID;
13506
- const versionLocalId = versionUidToLocalId.get(versionUid);
13507
- const attestationCreatedAt = property.timeCreated * 1000;
13508
- const attestationRaw = escapeSqliteString(JSON.stringify(property));
13509
- const seedUid = versionUidToSeedUid.get(versionUid);
13510
- const seedLocalId = seedUidToLocalId.get(seedUid);
13511
- const modelType = seedUidToModelType.get(seedUid);
13512
- const modelName = startCase(modelType);
13513
- const model = models[modelName];
13514
- const modelSchema = model?.properties ? modelPropertiesToObject(model.properties) : undefined;
13515
- if (propertyNameSnake === 'storage_transaction_id') {
13516
- await createMetadataRecordsForStorageTransactionId(property, modelSchema);
13517
- }
13518
- const propertyId = modelType != null
13519
- ? await getPropertyIdForModelAndName(modelType, propertyName)
13520
- : null;
13521
- const propertyIdSql = propertyId != null ? String(propertyId) : 'NULL';
13522
- const publisher = escapeSqliteString(property.attester ?? '');
13523
- const valuesString = `('${propertyLocalId}', '${property.id}',
13524
- '${property.schemaId}', ${propertyIdSql}, '${propertyName}',
13525
- '${propertyValue}', '${easDataType}', '${versionUid}',
13526
- '${versionLocalId}', '${seedUid}', '${seedLocalId}',
13527
- '${modelType}', ${refValueType ? `'${refValueType}'` : 'NULL'},
13528
- ${refSeedType ? `'${refSeedType}'` : 'NULL'},
13529
- ${refSchemaUid ? `'${refSchemaUid}'` : 'NULL'},
13530
- ${Date.now()}, ${attestationCreatedAt}, '${attestationRaw}',
13531
- ${'NULL'},
13532
- ${'NULL'},
13533
- '${publisher}')`;
13534
- if (i < newProperties.length - 1) {
13535
- insertPropertiesQuery += valuesString + ', ';
13536
- }
13537
- if (i === newProperties.length - 1) {
13538
- insertPropertiesQuery += valuesString + ';';
13539
- }
13540
- propertyUidToLocalId.set(property.id, propertyLocalId);
13541
- }
13542
- if (insertPropertiesQuery.endsWith('VALUES ')) {
13543
- return { propertyUids };
13544
- }
13545
- if (insertPropertiesQuery.endsWith(', ')) {
13546
- insertPropertiesQuery = insertPropertiesQuery.slice(0, -2) + ';';
13547
- }
13548
- await appDb.run(sql.raw(insertPropertiesQuery));
13549
- isSavingToDb = false;
13550
- return { propertyUids };
14611
+ throw err;
14612
+ }
14613
+ });
14614
+ const initialContext = {
14615
+ runOptions: {},
14616
+ activeCorrelationIds: [],
14617
+ activePrimarySource: 'event_bus',
14618
+ pendingMergedOptions: undefined,
14619
+ pendingCorrelationIds: [],
14620
+ pendingPrimarySource: null,
14621
+ lastFinishedCorrelationIds: null,
14622
+ lastFinishedStatus: null,
14623
+ lastFinishedError: null,
13551
14624
  };
13552
- const getRelatedSeedsAndVersions = async () => {
13553
- BaseQueryClient.getQueryClient();
13554
- const easClient = BaseEasClient.getEasClient();
13555
- const { itemSeeds } = await easClient.request(GET_SEEDS, {
13556
- where: {
13557
- id: {
13558
- in: Array.from(relatedSeedUids),
14625
+ const easSyncMachine = setup({
14626
+ types: {
14627
+ context: {},
14628
+ events: {},
14629
+ },
14630
+ actors: {
14631
+ runEasSync,
14632
+ },
14633
+ }).createMachine({
14634
+ id: MachineIds.EAS_SYNC_MANAGER,
14635
+ initial: 'idle',
14636
+ context: initialContext,
14637
+ states: {
14638
+ idle: {
14639
+ on: {
14640
+ REQUEST: {
14641
+ target: 'running',
14642
+ actions: assign({
14643
+ runOptions: ({ event }) => event.options === undefined
14644
+ ? {}
14645
+ : mergeEasSyncRequestIntents([event.options]),
14646
+ activeCorrelationIds: ({ event }) => [event.correlationId],
14647
+ activePrimarySource: ({ event }) => event.source,
14648
+ }),
14649
+ },
14650
+ },
14651
+ },
14652
+ running: {
14653
+ on: {
14654
+ REQUEST: {
14655
+ actions: assign({
14656
+ pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
14657
+ context.runOptions,
14658
+ context.pendingMergedOptions,
14659
+ event.options === undefined ? {} : event.options,
14660
+ ].filter((x) => x != null)),
14661
+ pendingCorrelationIds: ({ context, event }) => [
14662
+ ...context.pendingCorrelationIds,
14663
+ event.correlationId,
14664
+ ],
14665
+ pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
14666
+ }),
14667
+ },
13559
14668
  },
13560
- },
13561
- });
13562
- await saveEasSeedsToDb({ itemSeeds });
13563
- const { itemVersions } = await easClient.request(GET_VERSIONS, {
13564
- where: {
13565
- refUID: {
13566
- in: Array.from(relatedSeedUids),
14669
+ invoke: {
14670
+ src: 'runEasSync',
14671
+ input: ({ context }) => ({
14672
+ options: context.runOptions,
14673
+ requestPayload: {
14674
+ source: context.activePrimarySource,
14675
+ correlationIds: context.activeCorrelationIds,
14676
+ options: context.runOptions,
14677
+ },
14678
+ runningSnapshot: {
14679
+ phase: 'running',
14680
+ correlationIds: context.activeCorrelationIds,
14681
+ },
14682
+ }),
14683
+ onDone: {
14684
+ target: 'afterRun',
14685
+ actions: assign({
14686
+ lastFinishedCorrelationIds: ({ context }) => [
14687
+ ...context.activeCorrelationIds,
14688
+ ],
14689
+ lastFinishedStatus: () => 'success',
14690
+ lastFinishedError: () => null,
14691
+ activeCorrelationIds: () => [],
14692
+ runOptions: () => ({}),
14693
+ }),
14694
+ },
14695
+ onError: {
14696
+ target: 'afterRun',
14697
+ actions: [
14698
+ assign({
14699
+ lastFinishedCorrelationIds: ({ context }) => [
14700
+ ...context.activeCorrelationIds,
14701
+ ],
14702
+ lastFinishedStatus: () => 'failed',
14703
+ lastFinishedError: ({ event }) => {
14704
+ const e = event.error;
14705
+ if (e instanceof Error) {
14706
+ return e.message;
14707
+ }
14708
+ return e != null ? String(e) : 'EAS sync failed';
14709
+ },
14710
+ activeCorrelationIds: () => [],
14711
+ runOptions: () => ({}),
14712
+ }),
14713
+ ({ event }) => {
14714
+ log('runEasSync error', event.error);
14715
+ },
14716
+ ],
14717
+ },
13567
14718
  },
13568
14719
  },
13569
- });
13570
- await saveEasVersionsToDb({ itemVersions });
13571
- const relatedVersionUids = itemVersions.map((v) => v.id);
13572
- const { itemProperties } = await easClient.request(GET_PROPERTIES, {
13573
- where: {
13574
- refUID: {
13575
- in: relatedVersionUids,
13576
- },
14720
+ afterRun: {
14721
+ always: [
14722
+ {
14723
+ guard: ({ context }) => context.pendingCorrelationIds.length > 0,
14724
+ target: 'running',
14725
+ actions: assign({
14726
+ runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
14727
+ activeCorrelationIds: ({ context }) => [
14728
+ ...context.pendingCorrelationIds,
14729
+ ],
14730
+ activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
14731
+ pendingMergedOptions: () => undefined,
14732
+ pendingCorrelationIds: () => [],
14733
+ pendingPrimarySource: () => null,
14734
+ }),
14735
+ },
14736
+ { target: 'idle' },
14737
+ ],
13577
14738
  },
13578
- });
13579
- await saveEasPropertiesToDb({
13580
- itemProperties,
13581
- itemSeeds,
13582
- });
13583
- };
13584
- /**
13585
- * Core sync logic: fetches item attestations from EAS for configured models and given addresses,
13586
- * then saves seeds, versions, and properties to the local DB.
13587
- * Uses owned + watched addresses from DB when addresses are not provided.
13588
- */
13589
- const runSyncFromEas = async (options) => {
13590
- let addresses = options?.addresses ?? (await getAllAddressesFromDb());
13591
- const additionalGetter = getGetAdditionalSyncAddresses();
13592
- if (additionalGetter) {
13593
- const additional = await additionalGetter();
13594
- if (additional?.length) {
13595
- const seen = new Set(addresses.map((a) => a.toLowerCase()));
13596
- for (const addr of additional) {
13597
- if (addr && !seen.has(addr.toLowerCase())) {
13598
- seen.add(addr.toLowerCase());
13599
- addresses = [...addresses, addr];
13600
- }
13601
- }
13602
- }
13603
- }
13604
- if (!addresses || addresses.length === 0) {
14739
+ },
14740
+ });
14741
+ const easSyncActor = createActor(easSyncMachine);
14742
+ let easSyncActorStarted = false;
14743
+ function startEasSyncActor() {
14744
+ if (easSyncActorStarted) {
13605
14745
  return;
13606
14746
  }
13607
- const appDb = BaseDb.getAppDb();
13608
- const { schemaStringToModelRecord } = await getModelSchemas();
13609
- const modelSchemas = await getModelSchemasFromEas();
13610
- const schemaUids = [];
13611
- for (const modelSchema of modelSchemas) {
13612
- const foundModel = schemaStringToModelRecord.get(modelSchema.schema);
13613
- if (!foundModel) {
13614
- // Skip schemas that don't have a corresponding model in the user's config
13615
- // This can happen with "bytes32 image" if there's no Image model defined
13616
- console.warn(`[item/events] [syncDbWithEas] Model not found for schema ${modelSchema.schema}, skipping`);
13617
- continue;
13618
- }
13619
- try {
13620
- await appDb
13621
- .insert(modelUids)
13622
- .values({
13623
- modelId: foundModel.id,
13624
- uid: modelSchema.id,
13625
- })
13626
- .onConflictDoNothing();
13627
- }
13628
- catch (err) {
13629
- // Model may have been deleted by test teardown or another process; skip to avoid unhandled rejection
13630
- const e = err;
13631
- const code = e?.code ?? e?.rawCode ?? e?.cause?.code ?? e?.cause?.rawCode;
13632
- if (code === 'SQLITE_CONSTRAINT_FOREIGNKEY' || code === 787) {
13633
- continue;
13634
- }
13635
- throw err;
13636
- }
13637
- schemaUids.push(modelSchema.id);
13638
- }
13639
- // If no schemas were found, skip the rest of the sync process
13640
- // This can happen when models exist but don't have schemas registered in EAS yet
13641
- if (schemaUids.length === 0) {
13642
- return;
14747
+ easSyncActorStarted = true;
14748
+ easSyncActor.start();
14749
+ }
14750
+ function newCorrelationId() {
14751
+ const c = globalThis.crypto;
14752
+ if (c?.randomUUID) {
14753
+ return c.randomUUID();
13643
14754
  }
13644
- const itemSeeds = await getSeedsFromSchemaUids({
13645
- schemaUids,
13646
- addresses,
13647
- excludeRevoked: false,
13648
- });
13649
- const { seedUids } = await saveEasSeedsToDb({
13650
- itemSeeds,
13651
- });
13652
- const itemVersions = await getItemVersionsFromEas({
13653
- seedUids,
13654
- excludeRevoked: false,
14755
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
14756
+ }
14757
+ function requestEasSyncFromEventBus() {
14758
+ startEasSyncActor();
14759
+ easSyncActor.send({
14760
+ type: 'REQUEST',
14761
+ correlationId: newCorrelationId(),
14762
+ source: 'event_bus',
13655
14763
  });
13656
- const { versionUids } = await saveEasVersionsToDb({
13657
- itemVersions,
14764
+ }
14765
+ function requestEasSyncFromAddressChange(addresses) {
14766
+ startEasSyncActor();
14767
+ easSyncActor.send({
14768
+ type: 'REQUEST',
14769
+ correlationId: newCorrelationId(),
14770
+ options: { addresses },
14771
+ source: 'address_change',
13658
14772
  });
13659
- const rawProperties = await getItemPropertiesFromEas({
13660
- versionUids,
13661
- excludeRevoked: false,
14773
+ }
14774
+ function requestEasSyncFromModelsInit() {
14775
+ startEasSyncActor();
14776
+ easSyncActor.send({
14777
+ type: 'REQUEST',
14778
+ correlationId: newCorrelationId(),
14779
+ source: 'models_init',
13662
14780
  });
13663
- const itemProperties = pickLatestPropertyAttestationsByRefAndSchema(rawProperties);
13664
- await saveEasPropertiesToDb({
13665
- itemProperties,
13666
- itemSeeds,
14781
+ }
14782
+ function sendEasSyncClientRequest(correlationId, options) {
14783
+ startEasSyncActor();
14784
+ easSyncActor.send({
14785
+ type: 'REQUEST',
14786
+ correlationId,
14787
+ options,
14788
+ source: 'client_api',
13667
14789
  });
13668
- await getRelatedSeedsAndVersions();
13669
- };
13670
- const syncDbWithEasHandler = throttle(async (_) => {
13671
- await runSyncFromEas();
13672
- }, 30000, {
13673
- leading: true,
13674
- trailing: false,
13675
- });
14790
+ }
13676
14791
 
13677
- const isNode = () => {
13678
- return (typeof process !== 'undefined' &&
13679
- process.versions != null &&
13680
- process.versions.node != null);
13681
- };
13682
- const isBrowser = () => {
13683
- return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
13684
- };
13685
- const isElectron = () => {
13686
- return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
13687
- };
14792
+ var easSyncManager = /*#__PURE__*/Object.freeze({
14793
+ __proto__: null,
14794
+ easSyncActor: easSyncActor,
14795
+ easSyncMachine: easSyncMachine,
14796
+ requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
14797
+ requestEasSyncFromEventBus: requestEasSyncFromEventBus,
14798
+ requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
14799
+ sendEasSyncClientRequest: sendEasSyncClientRequest,
14800
+ startEasSyncActor: startEasSyncActor
14801
+ });
13688
14802
 
13689
14803
  /**
13690
14804
  * @deprecated Use BaseArweaveClient.setHost() instead.
13691
14805
  * This function is kept for backward compatibility but will be removed in a future version.
13692
14806
  */
13693
14807
  const setArweaveDomain = (newDomain) => {
13694
- BaseArweaveClient.setHost(newDomain);
14808
+ BaseArweaveClient.setPreferredReadGateway(newDomain);
13695
14809
  };
13696
14810
 
13697
- const logger$c = debug('seedSdk:services:events');
14811
+ const logger$b = debug('seedSdk:services:events');
13698
14812
  const handleServiceSaveState = (event) => {
13699
14813
  const { state, serviceId } = event;
13700
- logger$c(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
14814
+ logger$b(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
13701
14815
  // TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
13702
14816
  // localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
13703
14817
  };
@@ -13706,7 +14820,8 @@ const setupServicesEventHandlers = () => {
13706
14820
  };
13707
14821
 
13708
14822
  const setupAllItemsEventHandlers = () => {
13709
- eventEmitter.addListener('syncDbWithEas', syncDbWithEasHandler);
14823
+ startEasSyncActor();
14824
+ eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
13710
14825
  };
13711
14826
  // Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
13712
14827
 
@@ -13740,9 +14855,9 @@ class BasePathResolver {
13740
14855
  }
13741
14856
  }
13742
14857
 
13743
- const logger$b = debug('seedSdk:ClientManager:initialize');
14858
+ const logger$a = debug('seedSdk:ClientManager:initialize');
13744
14859
  const platformClassesInit = fromCallback(({ sendBack, input: { context, event } }) => {
13745
- logger$b('initialize from ClientManager');
14860
+ logger$a('initialize from ClientManager');
13746
14861
  const { isInitialized } = context;
13747
14862
  if (!event || !('options' in event)) {
13748
14863
  throw new Error('Initialize event must include options');
@@ -13778,20 +14893,20 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13778
14893
  let PathResolver;
13779
14894
  let EasClient;
13780
14895
  if (isBrowser()) {
13781
- FileManager = (await import('./FileManager-DHnyb040.js')).FileManager;
13782
- Db = (await import('./Db-CXwQVLZv.js')).Db;
13783
- QueryClient = (await import('./QueryClient-unspcsWa.js')).QueryClient;
13784
- ArweaveClient = (await import('./ArweaveClient-Cz9ZLiEV.js')).ArweaveClient;
13785
- PathResolver = (await import('./PathResolver-pmw--Ea2.js')).PathResolver;
13786
- EasClient = (await import('./EasClient-DjpbHjU9.js')).EasClient;
14896
+ FileManager = (await import('./FileManager-BOxbzROS.js')).FileManager;
14897
+ Db = (await import('./Db-DA_e7Jcc.js')).Db;
14898
+ QueryClient = (await import('./QueryClient-B12y2daD.js')).QueryClient;
14899
+ ArweaveClient = (await import('./ArweaveClient-KF_T3NSr.js')).ArweaveClient;
14900
+ PathResolver = (await import('./PathResolver-DHTAlCzo.js')).PathResolver;
14901
+ EasClient = (await import('./EasClient-CVPHYGNP.js')).EasClient;
13787
14902
  }
13788
14903
  else if (isNode()) {
13789
- FileManager = (await import('./FileManager-CKyoLrBP.js')).FileManager;
13790
- Db = (await import('./Db-DkTBncAM.js')).Db;
13791
- QueryClient = (await import('./QueryClient-OUjfvY3g.js')).QueryClient;
13792
- ArweaveClient = (await import('./ArweaveClient-DxpJnJXU.js')).ArweaveClient;
13793
- PathResolver = (await import('./PathResolver-Ce4K9acQ.js')).PathResolver;
13794
- EasClient = (await import('./EasClient-JYkmHxu1.js')).EasClient;
14904
+ FileManager = (await import('./FileManager-Ba5BCbCL.js')).FileManager;
14905
+ Db = (await import('./Db-Cg7Q5gIc.js')).Db;
14906
+ QueryClient = (await import('./QueryClient-BCxuWg7f.js')).QueryClient;
14907
+ ArweaveClient = (await import('./ArweaveClient-DoBABTLW.js')).ArweaveClient;
14908
+ PathResolver = (await import('./PathResolver-D7WqjJCo.js')).PathResolver;
14909
+ EasClient = (await import('./EasClient-B4VivHxM.js')).EasClient;
13795
14910
  }
13796
14911
  else {
13797
14912
  throw new Error(`Unable to determine environment. isBrowser()=${isBrowser()}, isNode()=${isNode()}. Platform-specific implementations could not be loaded.`);
@@ -13865,11 +14980,14 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13865
14980
  dbConfig,
13866
14981
  schemaFile,
13867
14982
  schema,
13868
- syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? false,
14983
+ syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
13869
14984
  } });
13870
14985
  if (arweaveDomain) {
13871
14986
  setArweaveDomain(arweaveDomain);
13872
14987
  }
14988
+ void ensureReadGatewaySelected().catch(() => {
14989
+ /* non-blocking warm-up for read gateway probe */
14990
+ });
13873
14991
  // Models are now Model instances, no registration needed
13874
14992
  // They should be created via Model.create() and are accessible via Model static methods
13875
14993
  setupAllItemsEventHandlers();
@@ -13905,15 +15023,15 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13905
15023
  };
13906
15024
  });
13907
15025
 
13908
- const logger$a = debug('seedSdk:client:writeToDb');
13909
- const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
15026
+ const logger$9 = debug('seedSdk:client:writeToDb');
15027
+ const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
13910
15028
  const _saveAppState = async () => {
13911
15029
  try {
13912
15030
  const appDb = BaseDb.getAppDb();
13913
15031
  if (!appDb) {
13914
15032
  // In test environments, continue anyway
13915
15033
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13916
- logger$a('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
15034
+ logger$9('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
13917
15035
  return;
13918
15036
  }
13919
15037
  throw new Error('App DB not found');
@@ -13929,13 +15047,13 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
13929
15047
  value: JSON.stringify(value),
13930
15048
  },
13931
15049
  });
13932
- logger$a('result', result);
15050
+ logger$9('result', result);
13933
15051
  }
13934
15052
  catch (error) {
13935
- logger$a('[client/actors] [saveAppState] Error saving app state:', error);
15053
+ logger$9('[client/actors] [saveAppState] Error saving app state:', error);
13936
15054
  // In test environments, continue anyway
13937
15055
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13938
- logger$a('[client/actors] [saveAppState] Continuing despite error in test environment');
15056
+ logger$9('[client/actors] [saveAppState] Continuing despite error in test environment');
13939
15057
  return;
13940
15058
  }
13941
15059
  throw error;
@@ -13950,10 +15068,10 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
13950
15068
  });
13951
15069
  })
13952
15070
  .catch((error) => {
13953
- logger$a('[client/actors] [saveAppState] Error in promise chain:', error);
15071
+ logger$9('[client/actors] [saveAppState] Error in promise chain:', error);
13954
15072
  // In test environments, still send success to allow state machine to progress
13955
15073
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13956
- logger$a('[client/actors] [saveAppState] Sending success despite error in test environment');
15074
+ logger$9('[client/actors] [saveAppState] Sending success despite error in test environment');
13957
15075
  sendBack({
13958
15076
  type: 'saveAppStateSuccess',
13959
15077
  key,
@@ -13966,222 +15084,6 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
13966
15084
  });
13967
15085
  });
13968
15086
 
13969
- const GET_FILES_METADATA = graphql(/* GraphQL */ `
13970
- query GetFilesMetadata($where: AttestationWhereInput!) {
13971
- filesMetadata: attestations(
13972
- where: $where
13973
- orderBy: [{ timeCreated: desc }]
13974
- ) {
13975
- ...attestationFields
13976
- }
13977
- }
13978
- `);
13979
-
13980
- const getMetadata = async (props) => {
13981
- const appDb = BaseDb.getAppDb();
13982
- let storageTransactionId;
13983
- if (props) {
13984
- storageTransactionId = props.storageTransactionId;
13985
- }
13986
- const whereClauses = [];
13987
- if (storageTransactionId) {
13988
- whereClauses.push(eq(metadata$1.propertyName, 'storageTransactionId'));
13989
- whereClauses.push(eq(metadata$1.propertyValue, storageTransactionId));
13990
- }
13991
- const metadataRows = await appDb
13992
- .select()
13993
- .from(metadata$1)
13994
- .where(and(...whereClauses));
13995
- if (!metadataRows || metadataRows.length === 0) {
13996
- return;
13997
- }
13998
- return metadataRows[0];
13999
- };
14000
-
14001
- const saveMetadata = async (metadataRecord, metadataValues) => {
14002
- if (!metadataRecord.localId) {
14003
- return;
14004
- }
14005
- const appDb = BaseDb.getAppDb();
14006
- await appDb
14007
- .update(metadata$1)
14008
- .set({
14009
- ...metadataValues,
14010
- updatedAt: Date.now(),
14011
- })
14012
- .where(eq(metadata$1.localId, metadataRecord.localId));
14013
- };
14014
-
14015
- const saveAppState = async (key, value) => {
14016
- const appDb = BaseDb.getAppDb();
14017
- await appDb
14018
- .insert(appState)
14019
- .values({
14020
- key,
14021
- value,
14022
- })
14023
- .onConflictDoUpdate({
14024
- target: appState.key,
14025
- set: {
14026
- value,
14027
- },
14028
- });
14029
- };
14030
-
14031
- const logger$9 = debug('seedSdk:files:download');
14032
- // syncDbFiles helper - internal service removed, functionality moved here
14033
- const syncDbFiles = async (endpoints) => {
14034
- // TODO: Implement syncDbFiles functionality if needed
14035
- // This was previously in @/services/internal/helpers
14036
- logger$9('[download] syncDbFiles called but not yet implemented');
14037
- return Promise.resolve();
14038
- };
14039
- const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
14040
- if (!isBrowser()) {
14041
- return;
14042
- }
14043
- await syncDbFiles();
14044
- eventEmitter.emit('fs.downloadAll.success', { eventId });
14045
- eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
14046
- };
14047
- const downloadAllFilesBinaryRequestHandler = async () => {
14048
- let addresses;
14049
- if (BaseDb.isAppDbReady()) {
14050
- addresses = await getAllAddressesFromDb();
14051
- }
14052
- if (!BaseDb.isAppDbReady()) {
14053
- // Wait for ClientManager to be ready (DB_INIT state or later)
14054
- const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
14055
- const { getClient } = clientManagerMod;
14056
- const clientManager = getClient();
14057
- const clientService = clientManager.getService();
14058
- await waitFor(clientService, (snapshot) => {
14059
- const state = snapshot.value;
14060
- return state === 'dbInit' ||
14061
- state === 'saveConfig' ||
14062
- state === 'processSchemaFiles' ||
14063
- state === 'addModelsToStore' ||
14064
- state === 'addModelsToDb' ||
14065
- state === 'idle';
14066
- }, { timeout: 30000 });
14067
- addresses = await getAllAddressesFromDb();
14068
- }
14069
- if (!addresses || addresses.length === 0) {
14070
- return;
14071
- }
14072
- const queryClient = BaseQueryClient.getQueryClient();
14073
- const easClient = BaseEasClient.getEasClient();
14074
- const { filesMetadata } = await queryClient.fetchQuery({
14075
- queryKey: ['getFilesMetadata', ...addresses],
14076
- queryFn: async () => easClient.request(GET_FILES_METADATA, {
14077
- where: {
14078
- attester: {
14079
- in: addresses,
14080
- },
14081
- schema: {
14082
- is: {
14083
- id: {
14084
- equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
14085
- },
14086
- },
14087
- },
14088
- },
14089
- }),
14090
- });
14091
- const filesRoot = BaseFileManager.getWorkingDir();
14092
- await BaseFileManager.createDirIfNotExists(filesRoot);
14093
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
14094
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
14095
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
14096
- const appDb = BaseDb.getAppDb();
14097
- if (!appDb) {
14098
- console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available');
14099
- return [];
14100
- }
14101
- const excludedTransactionsQuery = await appDb
14102
- .select()
14103
- .from(appState)
14104
- .where(eq(appState.key, 'excludedTransactions'));
14105
- let excludedTransactions = new Set();
14106
- if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
14107
- const valueString = excludedTransactionsQuery[0].value;
14108
- if (valueString) {
14109
- const excludedTransactionsArray = JSON.parse(valueString);
14110
- excludedTransactions = new Set(excludedTransactionsArray);
14111
- }
14112
- }
14113
- const transactionIds = [];
14114
- for (const fileMetadata of filesMetadata) {
14115
- // Validate and parse decodedDataJson
14116
- if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
14117
- console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
14118
- continue;
14119
- }
14120
- let json;
14121
- try {
14122
- json = JSON.parse(fileMetadata.decodedDataJson);
14123
- }
14124
- catch (error) {
14125
- console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
14126
- continue;
14127
- }
14128
- if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
14129
- console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
14130
- continue;
14131
- }
14132
- const transactionId = json[0].value.value;
14133
- if (excludedTransactions.has(transactionId)) {
14134
- continue;
14135
- }
14136
- transactionIds.push(transactionId);
14137
- }
14138
- const transactionIdsToDownload = [];
14139
- for (const transactionId of transactionIds) {
14140
- try {
14141
- // Use BaseArweaveClient for transaction status check
14142
- const status = await BaseArweaveClient.getTransactionStatus(transactionId);
14143
- if (status.status !== 200) {
14144
- logger$9(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`);
14145
- excludedTransactions.add(transactionId);
14146
- await saveAppState('excludedTransactions', JSON.stringify(Array.from(excludedTransactions)));
14147
- continue;
14148
- }
14149
- // Use BaseArweaveClient for getting transaction tags
14150
- const tags = await queryClient.fetchQuery({
14151
- queryKey: ['getTransactionTags', transactionId],
14152
- queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
14153
- });
14154
- if (tags && tags.length > 0) {
14155
- for (const { name, value } of tags) {
14156
- if (name === 'Content-SHA-256') {
14157
- const metadataRecord = await getMetadata({
14158
- storageTransactionId: transactionId,
14159
- });
14160
- if (metadataRecord) {
14161
- await saveMetadata(metadataRecord, {
14162
- contentHash: value,
14163
- });
14164
- }
14165
- }
14166
- }
14167
- }
14168
- transactionIdsToDownload.push(transactionId);
14169
- }
14170
- catch (error) {
14171
- logger$9(error);
14172
- }
14173
- }
14174
- await BaseFileManager.downloadAllFiles({
14175
- transactionIds: transactionIdsToDownload,
14176
- arweaveHost: BaseArweaveClient.getHost(),
14177
- excludedTransactions,
14178
- });
14179
- await BaseFileManager.resizeAllImages({
14180
- width: 480,
14181
- height: 480,
14182
- });
14183
- };
14184
-
14185
15087
  let isInitialized = false;
14186
15088
  const fsInitHandler = async () => {
14187
15089
  if (isInitialized) {
@@ -14347,7 +15249,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
14347
15249
  }
14348
15250
  const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
14349
15251
  // Fetch schemas from EAS in background - do not block init. EAS can be slow (10s+);
14350
- // modelUids will be populated async and syncDbWithEas will run when done.
15252
+ // modelUids will be populated async and EAS sync orchestrator runs when done.
14351
15253
  const fetchEasAndPopulateModelUids = async () => {
14352
15254
  try {
14353
15255
  const queryClient = BaseQueryClient.getQueryClient();
@@ -14380,7 +15282,8 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
14380
15282
  }
14381
15283
  }
14382
15284
  }
14383
- eventEmitter.emit('syncDbWithEas');
15285
+ const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
15286
+ requestEasSyncFromModelsInit();
14384
15287
  }
14385
15288
  else {
14386
15289
  logger$6('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
@@ -16830,16 +17733,19 @@ function addressesFromPersistedAddressValue(value) {
16830
17733
  return out;
16831
17734
  }
16832
17735
  function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
17736
+ const merged = addressesFromPersistedAddressValue(event.value);
16833
17737
  if (!context.syncFromEasOnAddressChange)
16834
17738
  return;
16835
17739
  if (event.key !== "addresses")
16836
17740
  return;
16837
- const merged = addressesFromPersistedAddressValue(event.value);
16838
17741
  if (merged.length === 0)
16839
17742
  return;
16840
- void runSyncFromEas({ addresses: merged }).catch((err) => {
16841
- logSyncAfterAddressSave("runSyncFromEas after address save failed", err);
16842
- });
17743
+ try {
17744
+ requestEasSyncFromAddressChange(merged);
17745
+ }
17746
+ catch (err) {
17747
+ logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
17748
+ }
16843
17749
  }
16844
17750
  function emitAddressesPersistedIfAddressesKey(event) {
16845
17751
  if (event.key !== "addresses")
@@ -16857,7 +17763,7 @@ const clientManagerMachine = setup({
16857
17763
  fileSystemInit,
16858
17764
  dbInit,
16859
17765
  saveConfig,
16860
- saveAppState: saveAppState$1,
17766
+ saveAppState,
16861
17767
  addModelsToStore,
16862
17768
  addModelsToDb,
16863
17769
  processSchemaFiles,
@@ -17181,7 +18087,16 @@ const clientInstance = {
17181
18087
  */
17182
18088
  syncFromEas: async (options) => {
17183
18089
  ensureInitialized();
17184
- await runSyncFromEas(options);
18090
+ startEasSyncActor();
18091
+ const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
18092
+ ? globalThis.crypto.randomUUID()
18093
+ : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
18094
+ sendEasSyncClientRequest(correlationId, options);
18095
+ await waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
18096
+ const snap = easSyncActor.getSnapshot();
18097
+ if (snap.context.lastFinishedStatus === 'failed') {
18098
+ throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
18099
+ }
17185
18100
  },
17186
18101
  addModel: async (modelDef) => {
17187
18102
  const db = await BaseDb.getAppDb();
@@ -17391,7 +18306,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
17391
18306
  // Lazy import cache for ModelProperty to avoid circular dependency
17392
18307
  // Eagerly start loading to minimize delay on first access
17393
18308
  let ModelPropertyClass = null;
17394
- const modelPropertyImportPromise = import('./ModelProperty-DWtv9fQr.js')
18309
+ const modelPropertyImportPromise = import('./ModelProperty-D6JLRqQW.js')
17395
18310
  .then(module => {
17396
18311
  ModelPropertyClass = module.ModelProperty;
17397
18312
  return ModelPropertyClass;
@@ -17408,7 +18323,7 @@ function getModelProperty() {
17408
18323
  }
17409
18324
  // Lazy import cache for Schema to avoid circular dependency
17410
18325
  let SchemaClass = null;
17411
- const schemaImportPromise = (async () => { const _mod_9 = await import('./Schema-CqqcEexA.js'); return _mod_9.b; })()
18326
+ const schemaImportPromise = (async () => { const _mod_10 = await import('./Schema-B5_B8nM5.js'); return _mod_10.b; })()
17412
18327
  .then(module => {
17413
18328
  SchemaClass = module.Schema;
17414
18329
  return SchemaClass;
@@ -19148,5 +20063,5 @@ var Model$1 = /*#__PURE__*/Object.freeze({
19148
20063
  const TModelValues = Type.Record(Type.String(), Type.Any());
19149
20064
  const TModelSchema = Type.Record(Type.String(), TProperty);
19150
20065
 
19151
- export { getItemData as $, models$1 as A, Boolean$1 as B, properties as C, Date$1 as D, isValidEasAttestationUid as E, File$1 as F, getLatestPublishedVersionRow as G, Html as H, Image as I, Json as J, modelPropertiesToObject as K, List as L, Model as M, Number$1 as N, parseListPropertyValueFromStorage as O, Property as P, getCorrectId as Q, Relation as R, INTERNAL_PROPERTY_NAMES as S, TModelValues as T, defaultAttestationData as U, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as V, INTERNAL_DATA_TYPES as W, toSnakeCase as X, getEasSchemaUidForSchemaDefinition as Y, ZERO_BYTES32 as Z, getEasSchemaForItemProperty as _, TModelSchema as a, setSchemaUidForModel as a$, resolveStorageNameToSchemaName as a0, appState as a1, BasePathResolver as a2, SEED_CONFIG_FILE as a3, SEED_CONFIG_FALLBACKS as a4, BaseEasClient as a5, EAS_ENDPOINT as a6, BaseQueryClient as a7, arweaveL1FinalizeJobs as a8, config as a9, syncSchemaFromSource as aA, transformImportToSchemaFile as aB, writeProcessMachine as aC, getModelIdByFileId as aD, generateId as aE, waitForEntityIdle as aF, createReactiveProxy as aG, findEntity as aH, forceRemoveFromCaches as aI, runDestroyLifecycle as aJ, getModelId as aK, isPlaceholderUid as aL, normalizeBytes32Hex as aM, getArweaveUrlForTransaction as aN, ADDRESSES_PERSISTED_EVENT as aO, parseAddressesPersistedPayload as aP, getClient as aQ, ClientManagerState as aR, MachineIds as aS, createNewItem as aT, getVersionData$1 as aU, getMetadataLatest as aV, loadAllSchemasFromDb as aW, propertyMachine as aX, SEED_PROTOCOL_SCHEMA_NAME as aY, ImageSize as aZ, setSchemaUidForSchemaDefinition as a_, metadata$1 as aa, modelRelations as ab, modelSchemas as ac, modelUids as ad, modelsRelations as ae, propertiesRelations as af, propertyUidRelations as ag, propertyUids as ah, publishProcesses as ai, schemas as aj, uploadProcesses as ak, versions as al, graphql as am, getPropertyIdForModelAndName as an, saveAppState as ao, addModelsToDb$1 as ap, SCHEMA_NJK as aq, ItemProperty as ar, eventEmitter as as, ClientManager as at, INIT_SCRIPT_SUCCESS_MESSAGE as au, SCHEMA_TS as av, getRefValueType as aw, importJsonSchema as ax, loadSchemaFromFile as ay, readJsonImportFile as az, ModelPropertyDataTypes as b, getModelSchemasFromEas as b0, getItemVersionsFromEas as b1, getItemPropertiesFromEas as b2, getCanonicalItemPropertiesFromEas as b3, getEasSchemaUidBySchemaName as b4, getSeedsFromSchemaUids as b5, getSeedsBySchemaName as b6, withExcludeRevokedFilter as b7, classifyMediaRef as b8, resolveMediaRef as b9, getSchemaNameFromId as bA, addSchemaToDb as bB, createModelsFromJson as bC, loadModelsFromDbForSchema as bD, getLatestSchemaVersion as bE, isInternalSchema as bF, createModelFromJson as bG, ConflictError as bH, unloadEntity as bI, clearDestroySubscriptions as bJ, setupEntityLiveQuery as bK, ModelSchema as bL, BaseFileManager$1 as bM, db as bN, eas as bO, getPropertyData$1 as bP, schema as bQ, SEEDPROTOCOL_Seed_Protocol_v1 as bR, Model$1 as bS, normalizeFeedItemFields as ba, getFeedItemStringField as bb, pickLatestPropertyAttestationsByRefAndSchema as bc, SeedModels as bd, DEFAULT_ARWEAVE_HOST as be, DEFAULT_ARWEAVE_GATEWAYS as bf, DEFAULT_ARWEAVE_GRAPHQL_URL as bg, updateSeedRevokedAt as bh, getAddressesForItemsFilter as bi, normalizeUploadApiBaseUrl as bj, getUploadApiArweaveDataUrl as bk, getUploadPipelineTransactionStatus as bl, getUploadApiArweaveStatusUrl as bm, getArweaveUploadStatus as bn, isArweaveL1AnchoringComplete as bo, queryArweaveGatewayTransaction as bp, setUploadExecutor as bq, getUploadExecutor as br, setGetPublisherForNewSeeds as bs, getGetPublisherForNewSeeds as bt, setRevokeExecutor as bu, getRevokeExecutor as bv, setAdditionalSyncAddresses as bw, createSchema as bx, readSchema as by, listCompleteSchemaFiles as bz, TPropertyDataType as c, TStorageType as d, THtmlEmbeddedDataUriPolicy as e, TProperty as f, TPropertyConstructor as g, TPropertyDefs as h, PropertyMetadataKey as i, PropertyConstructor as j, Text as k, DEFAULT_TEXT_MAX_LENGTH as l, TValidationRules as m, normalizeDataType as n, getOwnedAddressesFromDb as o, BaseDb as p, getGetAdditionalSyncAddresses as q, resolveSeedIdsFromRefString as r, seeds as s, normalizeRelationPropertyValue as t, Item as u, BaseFileManager as v, getContentHash as w, htmlEmbeddedImageCoPublish as x, BaseArweaveClient as y, getEasSchemaUidForModel as z };
19152
- //# sourceMappingURL=index-BrD_NNaX.js.map
20066
+ export { getItemData as $, models$1 as A, Boolean$1 as B, properties as C, Date$1 as D, isValidEasAttestationUid as E, File$1 as F, getLatestPublishedVersionRow as G, Html as H, Image as I, Json as J, modelPropertiesToObject as K, List as L, Model as M, Number$1 as N, parseListPropertyValueFromStorage as O, Property as P, getCorrectId as Q, Relation as R, INTERNAL_PROPERTY_NAMES as S, TModelValues as T, defaultAttestationData as U, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as V, INTERNAL_DATA_TYPES as W, toSnakeCase as X, getEasSchemaUidForSchemaDefinition as Y, ZERO_BYTES32 as Z, getEasSchemaForItemProperty as _, TModelSchema as a, compareMetadataRowsLatestFirst as a$, resolveStorageNameToSchemaName as a0, appState as a1, BasePathResolver as a2, SEED_CONFIG_FILE as a3, SEED_CONFIG_FALLBACKS as a4, BaseEasClient as a5, EAS_ENDPOINT as a6, BaseQueryClient as a7, arweaveL1FinalizeJobs as a8, config as a9, GET_SEEDS as aA, GET_VERSIONS as aB, GET_PROPERTIES as aC, setSchemaUidForSchemaDefinition as aD, parseEasRelationPropertyName as aE, addModelsToDb$1 as aF, SCHEMA_NJK as aG, ItemProperty as aH, ClientManager as aI, INIT_SCRIPT_SUCCESS_MESSAGE as aJ, SCHEMA_TS as aK, getRefValueType as aL, importJsonSchema as aM, loadSchemaFromFile as aN, readJsonImportFile as aO, syncSchemaFromSource as aP, transformImportToSchemaFile as aQ, writeProcessMachine as aR, getModelIdByFileId as aS, waitForEntityIdle as aT, createReactiveProxy as aU, findEntity as aV, forceRemoveFromCaches as aW, runDestroyLifecycle as aX, getModelId as aY, isPlaceholderUid as aZ, normalizeBytes32Hex as a_, easSyncProcesses as aa, metadata$1 as ab, modelRelations as ac, modelSchemas as ad, modelUids as ae, modelsRelations as af, propertiesRelations as ag, propertyUidRelations as ah, propertyUids as ai, publishProcesses as aj, schemas as ak, uploadProcesses as al, versions as am, graphql as an, getPropertyIdForModelAndName as ao, getAllAddressesFromDb as ap, getModelSchemasFromEas as aq, getSeedsFromSchemaUids as ar, getItemVersionsFromEas as as, getItemPropertiesFromEas as at, pickLatestPropertyAttestationsByRefAndSchema as au, scheduleBulkFilesDownloadFromEasSync as av, eventEmitter as aw, EAS_SEED_DATA_SYNCED_TO_DB_EVENT as ax, generateId as ay, escapeSqliteString as az, ModelPropertyDataTypes as b, isInternalSchema as b$, getArweaveUrlForTransaction as b0, ADDRESSES_PERSISTED_EVENT as b1, parseAddressesPersistedPayload as b2, getClient as b3, ClientManagerState as b4, MachineIds as b5, createNewItem as b6, getVersionData$1 as b7, getMetadataLatest as b8, loadAllSchemasFromDb as b9, queryArweaveGatewayTransaction as bA, queryArweaveGatewayTransactionWithFallback as bB, ensureReadGatewaySelected as bC, invalidateReadGatewayCache as bD, resetArweaveReadGatewayForTests as bE, setUploadExecutor as bF, getUploadExecutor as bG, setGetPublisherForNewSeeds as bH, getGetPublisherForNewSeeds as bI, setRevokeExecutor as bJ, getRevokeExecutor as bK, setAdditionalSyncAddresses as bL, createSchema as bM, readSchema as bN, listCompleteSchemaFiles as bO, getSchemaNameFromId as bP, easSyncActor as bQ, startEasSyncActor as bR, sendEasSyncClientRequest as bS, requestEasSyncFromAddressChange as bT, requestEasSyncFromEventBus as bU, requestEasSyncFromModelsInit as bV, mergeEasSyncRequestIntents as bW, addSchemaToDb as bX, createModelsFromJson as bY, loadModelsFromDbForSchema as bZ, getLatestSchemaVersion as b_, propertyMachine as ba, SEED_PROTOCOL_SCHEMA_NAME as bb, ImageSize as bc, setSchemaUidForModel as bd, getCanonicalItemPropertiesFromEas as be, getEasSchemaUidBySchemaName as bf, getSeedsBySchemaName as bg, withExcludeRevokedFilter as bh, classifyMediaRef as bi, resolveMediaRef as bj, normalizeFeedItemFields as bk, getFeedItemStringField as bl, SeedModels as bm, DEFAULT_ARWEAVE_HOST as bn, DEFAULT_ARWEAVE_GATEWAYS as bo, DEFAULT_ARWEAVE_GRAPHQL_URL as bp, getDefaultArweaveReadGatewayHostsOrdered as bq, mergePrimaryHostWithDefaults as br, isKnownArweaveGatewayHostname as bs, getAddressesForItemsFilter as bt, normalizeUploadApiBaseUrl as bu, getUploadApiArweaveDataUrl as bv, getUploadPipelineTransactionStatus as bw, getUploadApiArweaveStatusUrl as bx, getArweaveUploadStatus as by, isArweaveL1AnchoringComplete as bz, TPropertyDataType as c, createModelFromJson as c0, ConflictError as c1, unloadEntity as c2, clearDestroySubscriptions as c3, setupEntityLiveQuery as c4, ModelSchema as c5, BaseFileManager$1 as c6, db as c7, eas as c8, getPropertyData$1 as c9, Item$1 as ca, schema as cb, SEEDPROTOCOL_Seed_Protocol_v1 as cc, Model$1 as cd, TStorageType as d, THtmlEmbeddedDataUriPolicy as e, TProperty as f, TPropertyConstructor as g, TPropertyDefs as h, PropertyMetadataKey as i, PropertyConstructor as j, Text as k, DEFAULT_TEXT_MAX_LENGTH as l, TValidationRules as m, normalizeDataType as n, getOwnedAddressesFromDb as o, BaseDb as p, getGetAdditionalSyncAddresses as q, resolveSeedIdsFromRefString as r, seeds as s, normalizeRelationPropertyValue as t, Item as u, BaseFileManager as v, getContentHash as w, htmlEmbeddedImageCoPublish as x, BaseArweaveClient as y, getEasSchemaUidForModel as z };
20067
+ //# sourceMappingURL=index-18lln0cM.js.map