@seedprotocol/sdk 0.4.21 → 0.4.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/dist/{ArweaveClient-DxpJnJXU.js → ArweaveClient-B-vm2Xae.js} +3 -3
  2. package/dist/{ArweaveClient-DxpJnJXU.js.map → ArweaveClient-B-vm2Xae.js.map} +1 -1
  3. package/dist/{ArweaveClient-Cz9ZLiEV.js → ArweaveClient-C-eLH0zU.js} +3 -3
  4. package/dist/{ArweaveClient-Cz9ZLiEV.js.map → ArweaveClient-C-eLH0zU.js.map} +1 -1
  5. package/dist/{Db-CXwQVLZv.js → Db-B7whB3oJ.js} +107 -6
  6. package/dist/Db-B7whB3oJ.js.map +1 -0
  7. package/dist/{Db-DkTBncAM.js → Db-nir1xVHg.js} +4 -4
  8. package/dist/{Db-DkTBncAM.js.map → Db-nir1xVHg.js.map} +1 -1
  9. package/dist/{EasClient-DjpbHjU9.js → EasClient-BH_feMaX.js} +2 -2
  10. package/dist/{EasClient-JYkmHxu1.js.map → EasClient-BH_feMaX.js.map} +1 -1
  11. package/dist/{EasClient-JYkmHxu1.js → EasClient-CFguAKBp.js} +2 -2
  12. package/dist/{EasClient-DjpbHjU9.js.map → EasClient-CFguAKBp.js.map} +1 -1
  13. package/dist/{FileManager-CKyoLrBP.js → FileManager-BR3jtuSl.js} +2 -2
  14. package/dist/{FileManager-CKyoLrBP.js.map → FileManager-BR3jtuSl.js.map} +1 -1
  15. package/dist/{FileManager-DHnyb040.js → FileManager-C2uXql_C.js} +18 -2
  16. package/dist/FileManager-C2uXql_C.js.map +1 -0
  17. package/dist/{ModelProperty-DWtv9fQr.js → ModelProperty-CIeLasI4.js} +24 -24
  18. package/dist/{ModelProperty-DWtv9fQr.js.map → ModelProperty-CIeLasI4.js.map} +1 -1
  19. package/dist/{PathResolver-Ce4K9acQ.js → PathResolver-CZoSnHBU.js} +2 -2
  20. package/dist/{PathResolver-Ce4K9acQ.js.map → PathResolver-CZoSnHBU.js.map} +1 -1
  21. package/dist/{PathResolver-pmw--Ea2.js → PathResolver-DnrG1hUX.js} +2 -2
  22. package/dist/{PathResolver-pmw--Ea2.js.map → PathResolver-DnrG1hUX.js.map} +1 -1
  23. package/dist/{QueryClient-OUjfvY3g.js → QueryClient-DJOrJZRR.js} +3 -2
  24. package/dist/QueryClient-DJOrJZRR.js.map +1 -0
  25. package/dist/{QueryClient-unspcsWa.js → QueryClient-PqOg8mcw.js} +7 -3
  26. package/dist/QueryClient-PqOg8mcw.js.map +1 -0
  27. package/dist/{Schema-CqqcEexA.js → Schema-B3YQHTtu.js} +38 -38
  28. package/dist/{Schema-CqqcEexA.js.map → Schema-B3YQHTtu.js.map} +1 -1
  29. package/dist/{SchemaValidationService-Cb-b4kpD.js → SchemaValidationService-C4DIwn8Z.js} +2 -2
  30. package/dist/{SchemaValidationService-Cb-b4kpD.js.map → SchemaValidationService-C4DIwn8Z.js.map} +1 -1
  31. package/dist/{backfillMetadataPropertyIds-CRyRez3h.js → backfillMetadataPropertyIds-CBlRaU_M.js} +2 -2
  32. package/dist/{backfillMetadataPropertyIds-CRyRez3h.js.map → backfillMetadataPropertyIds-CBlRaU_M.js.map} +1 -1
  33. package/dist/cjs/{ModelProperty-sNx_ZQZX.js → ModelProperty-tfM38NL4.js} +17 -17
  34. package/dist/cjs/{ModelProperty-sNx_ZQZX.js.map → ModelProperty-tfM38NL4.js.map} +1 -1
  35. package/dist/cjs/{Schema-B4RRA-0g.js → Schema-44NqLqMV.js} +20 -20
  36. package/dist/cjs/{Schema-B4RRA-0g.js.map → Schema-44NqLqMV.js.map} +1 -1
  37. package/dist/cjs/{SchemaValidationService-DCflhpcI.js → SchemaValidationService-Cq_YBzFN.js} +2 -2
  38. package/dist/cjs/{SchemaValidationService-DCflhpcI.js.map → SchemaValidationService-Cq_YBzFN.js.map} +1 -1
  39. package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js → backfillMetadataPropertyIds-D1nLJAhB.js} +2 -2
  40. package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js.map → backfillMetadataPropertyIds-D1nLJAhB.js.map} +1 -1
  41. package/dist/cjs/{getItem-lyM2x5pT.js → getItem-BRoq91YU.js} +2 -2
  42. package/dist/cjs/{getItem-lyM2x5pT.js.map → getItem-BRoq91YU.js.map} +1 -1
  43. package/dist/cjs/{getPublishPayload-DP2fm4q8.js → getPublishPayload-ddl-1x6R.js} +11 -11
  44. package/dist/cjs/{getPublishPayload-DP2fm4q8.js.map → getPublishPayload-ddl-1x6R.js.map} +1 -1
  45. package/dist/cjs/{getPublishUploads-DdVy-5fK.js → getPublishUploads-BljRx4o4.js} +39 -6
  46. package/dist/cjs/getPublishUploads-BljRx4o4.js.map +1 -0
  47. package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js → getSegmentedItemProperties-iK5kepzl.js} +3 -3
  48. package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js.map → getSegmentedItemProperties-iK5kepzl.js.map} +1 -1
  49. package/dist/cjs/{index-D1qR8xnb.js → index-C6rrqy3z.js} +1980 -1113
  50. package/dist/cjs/index-C6rrqy3z.js.map +1 -0
  51. package/dist/cjs/{index-DTkoTvcq.js → index-DqSDhOp3.js} +3 -3
  52. package/dist/cjs/index-DqSDhOp3.js.map +1 -0
  53. package/dist/cjs/{ownership-DanM_n8E.js → ownership-CXlKAj4o.js} +2 -2
  54. package/dist/cjs/{ownership-DanM_n8E.js.map → ownership-CXlKAj4o.js.map} +1 -1
  55. package/dist/cjs/{property-BQokoaRe.js → property-2D7P6a2q.js} +4 -4
  56. package/dist/cjs/{property-BQokoaRe.js.map → property-2D7P6a2q.js.map} +1 -1
  57. package/dist/cjs/syncDbWithEas-DcKL-_Pb.js +610 -0
  58. package/dist/cjs/syncDbWithEas-DcKL-_Pb.js.map +1 -0
  59. package/dist/db/drizzle/drizzle/0013_eas_sync_processes.sql +12 -0
  60. package/dist/db/drizzle/drizzle/meta/0013_snapshot.json +1262 -0
  61. package/dist/db/drizzle/drizzle/meta/_journal.json +7 -0
  62. package/dist/{getItem-VI3QqdZH.js → getItem-CV3yTCRt.js} +2 -2
  63. package/dist/{getItem-VI3QqdZH.js.map → getItem-CV3yTCRt.js.map} +1 -1
  64. package/dist/{getPublishPayload-DpYwi-rd.js → getPublishPayload-Ddc_LGPs.js} +14 -14
  65. package/dist/{getPublishPayload-DpYwi-rd.js.map → getPublishPayload-Ddc_LGPs.js.map} +1 -1
  66. package/dist/{getPublishUploads-DS2dQ4Ho.js → getPublishUploads-Cf2J-5FR.js} +39 -6
  67. package/dist/getPublishUploads-Cf2J-5FR.js.map +1 -0
  68. package/dist/{getSegmentedItemProperties-Bz5B4DSA.js → getSegmentedItemProperties-B2mzArFD.js} +3 -3
  69. package/dist/{getSegmentedItemProperties-Bz5B4DSA.js.map → getSegmentedItemProperties-B2mzArFD.js.map} +1 -1
  70. package/dist/{index-Cqf_DxkJ.js → index-3Ekqb4QB.js} +3 -3
  71. package/dist/index-3Ekqb4QB.js.map +1 -0
  72. package/dist/{index-DdzhrbkF.js → index-BRo7D3s1.js} +3 -2
  73. package/dist/index-BRo7D3s1.js.map +1 -0
  74. package/dist/{index-BrD_NNaX.js → index-DUMXLKJr.js} +1991 -1125
  75. package/dist/index-DUMXLKJr.js.map +1 -0
  76. package/dist/main.cjs +1 -1
  77. package/dist/main.js +16 -41
  78. package/dist/main.js.map +1 -1
  79. package/dist/node.js +10 -10
  80. package/dist/{ownership-BK6suksO.js → ownership-TR-mIjJh.js} +2 -2
  81. package/dist/{ownership-BK6suksO.js.map → ownership-TR-mIjJh.js.map} +1 -1
  82. package/dist/{property-C63Ddzap.js → property-BSNWvgei.js} +6 -6
  83. package/dist/{property-C63Ddzap.js.map → property-BSNWvgei.js.map} +1 -1
  84. package/dist/{queries-BGuWjEqt.js → queries-0FZBThGQ.js} +2 -2
  85. package/dist/{queries-BGuWjEqt.js.map → queries-0FZBThGQ.js.map} +1 -1
  86. package/dist/seedSchema/EasSyncProcessSchema.ts +17 -0
  87. package/dist/seedSchema/index.ts +1 -0
  88. package/dist/src/Item/Item.d.ts +18 -0
  89. package/dist/src/Item/Item.d.ts.map +1 -1
  90. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  91. package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
  92. package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +1 -1
  93. package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts.map +1 -1
  94. package/dist/src/ItemProperty/service/propertyMachine.d.ts +4 -1
  95. package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
  96. package/dist/src/Model/service/modelMachine.d.ts +20 -20
  97. package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +2 -2
  98. package/dist/src/Schema/service/addModelsMachine.d.ts +1 -1
  99. package/dist/src/Schema/service/schemaMachine.d.ts +55 -55
  100. package/dist/src/browser/db/drizzleFiles.d.ts +3 -2
  101. package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
  102. package/dist/src/browser/helpers/QueryClient.d.ts.map +1 -1
  103. package/dist/src/client/ClientManager.d.ts.map +1 -1
  104. package/dist/src/client/actors/addModelsToDb.d.ts.map +1 -1
  105. package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
  106. package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
  107. package/dist/src/client/constants.d.ts +1 -0
  108. package/dist/src/client/constants.d.ts.map +1 -1
  109. package/dist/src/db/read/getPublishPendingDiff.d.ts.map +1 -1
  110. package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
  111. package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -1
  112. package/dist/src/db/write/easSyncProcess.d.ts +12 -0
  113. package/dist/src/db/write/easSyncProcess.d.ts.map +1 -0
  114. package/dist/src/db/write/updateItemPropertyValue.d.ts.map +1 -1
  115. package/dist/src/events/files/download.d.ts +5 -1
  116. package/dist/src/events/files/download.d.ts.map +1 -1
  117. package/dist/src/events/item/easSyncManager.d.ts +71 -0
  118. package/dist/src/events/item/easSyncManager.d.ts.map +1 -0
  119. package/dist/src/events/item/index.d.ts.map +1 -1
  120. package/dist/src/events/item/mergeEasSyncOptions.d.ts +7 -0
  121. package/dist/src/events/item/mergeEasSyncOptions.d.ts.map +1 -0
  122. package/dist/src/events/item/syncDbWithEas.d.ts +0 -3
  123. package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
  124. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts +17 -0
  125. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts.map +1 -1
  126. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts +6 -0
  127. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts.map +1 -1
  128. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts +16 -0
  129. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts.map +1 -0
  130. package/dist/src/helpers/FileManager/BaseFileManager.d.ts +1 -0
  131. package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
  132. package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts +16 -0
  133. package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts.map +1 -0
  134. package/dist/src/helpers/constants.d.ts +20 -5
  135. package/dist/src/helpers/constants.d.ts.map +1 -1
  136. package/dist/src/helpers/environment.d.ts +5 -0
  137. package/dist/src/helpers/environment.d.ts.map +1 -1
  138. package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -1
  139. package/dist/src/helpers/index.d.ts +1 -0
  140. package/dist/src/helpers/index.d.ts.map +1 -1
  141. package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts +8 -0
  142. package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts.map +1 -0
  143. package/dist/src/index.d.ts +7 -3
  144. package/dist/src/index.d.ts.map +1 -1
  145. package/dist/src/interfaces/IQueryClient.d.ts +4 -0
  146. package/dist/src/interfaces/IQueryClient.d.ts.map +1 -1
  147. package/dist/src/node/helpers/QueryClient.d.ts.map +1 -1
  148. package/dist/src/seedSchema/EasSyncProcessSchema.d.ts +190 -0
  149. package/dist/src/seedSchema/EasSyncProcessSchema.d.ts.map +1 -0
  150. package/dist/src/seedSchema/index.d.ts +1 -0
  151. package/dist/src/seedSchema/index.d.ts.map +1 -1
  152. package/dist/src/services/write/writeProcessMachine.d.ts +1 -1
  153. package/dist/src/types/fileManager.d.ts +5 -0
  154. package/dist/src/types/fileManager.d.ts.map +1 -1
  155. package/dist/src/types/index.d.ts +3 -2
  156. package/dist/src/types/index.d.ts.map +1 -1
  157. package/dist/src/types/machines.d.ts +1 -1
  158. package/dist/src/types/machines.d.ts.map +1 -1
  159. package/dist/syncDbWithEas-CaytdS8D.js +583 -0
  160. package/dist/syncDbWithEas-CaytdS8D.js.map +1 -0
  161. package/dist/updateSeedRevokedAt-CfUXirik.js +22 -0
  162. package/dist/updateSeedRevokedAt-CfUXirik.js.map +1 -0
  163. package/package.json +1 -1
  164. package/dist/Db-CXwQVLZv.js.map +0 -1
  165. package/dist/FileManager-DHnyb040.js.map +0 -1
  166. package/dist/QueryClient-OUjfvY3g.js.map +0 -1
  167. package/dist/QueryClient-unspcsWa.js.map +0 -1
  168. package/dist/cjs/getPublishUploads-DdVy-5fK.js.map +0 -1
  169. package/dist/cjs/index-D1qR8xnb.js.map +0 -1
  170. package/dist/cjs/index-DTkoTvcq.js.map +0 -1
  171. package/dist/getPublishUploads-DS2dQ4Ho.js.map +0 -1
  172. package/dist/index-BrD_NNaX.js.map +0 -1
  173. package/dist/index-Cqf_DxkJ.js.map +0 -1
  174. package/dist/index-DdzhrbkF.js.map +0 -1
@@ -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,7 +8,7 @@ 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
13
  import EventEmitter from 'eventemitter3';
14
14
  import 'arweave';
@@ -157,6 +157,13 @@ class BaseFileManager {
157
157
  static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
158
158
  return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
159
159
  }
160
+ static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
161
+ return this.PlatformClass.downloadAllFiles({
162
+ transactionIds: [transactionId],
163
+ arweaveHost,
164
+ excludedTransactions,
165
+ });
166
+ }
160
167
  static resizeImage({ filePath, width, height }) {
161
168
  return this.PlatformClass.resizeImage({ filePath, width, height });
162
169
  }
@@ -365,12 +372,71 @@ var SeedModels;
365
372
  // Internal SDK schema that should not be created in app's files directory
366
373
  const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
367
374
  const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
368
- /** Default Arweave gateway host used across all packages */
369
- const DEFAULT_ARWEAVE_HOST = 'arweave.net';
375
+ /** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
376
+ const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
370
377
  /** 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'];
378
+ const DEFAULT_ARWEAVE_GRAPHQL_URL = `https://${DEFAULT_ARWEAVE_HOST}/graphql`;
379
+ /**
380
+ * Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
381
+ * Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
382
+ */
383
+ const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
384
+ const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
385
+ /** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
386
+ function getDefaultArweaveReadGatewayHostsOrdered() {
387
+ if (typeof process === 'undefined' || !process.env) {
388
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
389
+ }
390
+ for (const key of READ_GATEWAYS_ENV_KEYS) {
391
+ const raw = process.env[key]?.trim();
392
+ if (raw) {
393
+ return raw.split(',').map((s) => s.trim()).filter(Boolean);
394
+ }
395
+ }
396
+ return [...DEFAULT_ARWEAVE_GATEWAYS];
397
+ }
398
+ /**
399
+ * Deduped host list: primary first, then each default not already present (case-insensitive).
400
+ */
401
+ function mergePrimaryHostWithDefaults(primary, defaults) {
402
+ const seen = new Set();
403
+ const out = [];
404
+ const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
405
+ const add = (h) => {
406
+ const t = h.trim().replace(/\/$/, '');
407
+ if (!t)
408
+ return;
409
+ const k = keyOf(t);
410
+ if (seen.has(k))
411
+ return;
412
+ seen.add(k);
413
+ out.push(t);
414
+ };
415
+ add(primary);
416
+ for (const d of defaults)
417
+ add(d);
418
+ return out;
419
+ }
420
+ /**
421
+ * True if `hostname` looks like a public Arweave gateway used in stored URLs (hydration / RSS).
422
+ */
423
+ function isKnownArweaveGatewayHostname(hostname) {
424
+ const h = hostname.trim().toLowerCase();
425
+ if (!h)
426
+ return false;
427
+ if (h.endsWith('arweave.net'))
428
+ return true;
429
+ if (h.endsWith('ar-io.net'))
430
+ return true;
431
+ for (const g of DEFAULT_ARWEAVE_GATEWAYS) {
432
+ const gl = g.toLowerCase();
433
+ if (h === gl || h.endsWith(`.${gl}`))
434
+ return true;
435
+ }
436
+ return false;
437
+ }
438
+ /** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
439
+ const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
374
440
  /**
375
441
  * Check if a schema is an internal SDK schema that should not be created in app files
376
442
  */
@@ -385,6 +451,7 @@ var constants = /*#__PURE__*/Object.freeze({
385
451
  DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
386
452
  DEFAULT_ARWEAVE_GRAPHQL_URL: DEFAULT_ARWEAVE_GRAPHQL_URL,
387
453
  DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
454
+ EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
388
455
  INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
389
456
  INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
390
457
  INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
@@ -402,7 +469,10 @@ var constants = /*#__PURE__*/Object.freeze({
402
469
  ZERO_BYTES: ZERO_BYTES,
403
470
  ZERO_BYTES32: ZERO_BYTES32,
404
471
  defaultAttestationData: defaultAttestationData,
405
- isInternalSchema: isInternalSchema
472
+ getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
473
+ isInternalSchema: isInternalSchema,
474
+ isKnownArweaveGatewayHostname: isKnownArweaveGatewayHostname,
475
+ mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
406
476
  });
407
477
 
408
478
  function parseGateway(input) {
@@ -419,6 +489,8 @@ function parseGateway(input) {
419
489
  let _host = DEFAULT_ARWEAVE_HOST;
420
490
  let _protocol = 'https';
421
491
  let _hostExplicitlySet = false;
492
+ /** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
493
+ let _suppressEnvGatewayOverride = false;
422
494
  class BaseArweaveClient {
423
495
  static setPlatformClass(platformClass) {
424
496
  this.PlatformClass = platformClass;
@@ -431,7 +503,7 @@ class BaseArweaveClient {
431
503
  const envHost = typeof process !== 'undefined' && process.env
432
504
  ? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
433
505
  : undefined;
434
- if (envHost && !_hostExplicitlySet) {
506
+ if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
435
507
  return parseGateway(envHost);
436
508
  }
437
509
  }
@@ -469,6 +541,39 @@ class BaseArweaveClient {
469
541
  _host = parsed.host;
470
542
  _protocol = parsed.protocol;
471
543
  _hostExplicitlySet = true;
544
+ _suppressEnvGatewayOverride = false;
545
+ }
546
+ /**
547
+ * When true, read-path gateway probing does not change the host ({@link setHost}).
548
+ */
549
+ static isReadGatewayLocked() {
550
+ return _hostExplicitlySet;
551
+ }
552
+ /**
553
+ * @internal Clears env override suppression after probing (for test isolation).
554
+ */
555
+ static resetReadGatewaySelectionStateForTests() {
556
+ _suppressEnvGatewayOverride = false;
557
+ }
558
+ /**
559
+ * Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
560
+ * Used for seed `arweaveDomain`.
561
+ */
562
+ static setPreferredReadGateway(host) {
563
+ const parsed = parseGateway(host);
564
+ _host = parsed.host;
565
+ _protocol = parsed.protocol;
566
+ _hostExplicitlySet = false;
567
+ }
568
+ /**
569
+ * Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
570
+ */
571
+ static applyProbedReadGateway(host) {
572
+ const parsed = parseGateway(host);
573
+ _host = parsed.host;
574
+ _protocol = parsed.protocol;
575
+ _hostExplicitlySet = false;
576
+ _suppressEnvGatewayOverride = true;
472
577
  }
473
578
  /**
474
579
  * Get the GraphQL endpoint URL
@@ -552,6 +657,11 @@ class BaseArweaveClient {
552
657
  }
553
658
  }
554
659
 
660
+ var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
661
+ __proto__: null,
662
+ BaseArweaveClient: BaseArweaveClient
663
+ });
664
+
555
665
  /**
556
666
  * Trim and strip a trailing slash from an upload API base URL.
557
667
  */
@@ -603,6 +713,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
603
713
  }
604
714
  }
605
715
 
716
+ const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
717
+ const PROBE_TIMEOUT_MS = 5000;
718
+ let readGatewayCache = null;
719
+ let ensureInFlight = null;
720
+ /** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
721
+ function invalidateReadGatewayCache() {
722
+ readGatewayCache = null;
723
+ ensureInFlight = null;
724
+ }
725
+ /** Clears probe cache, env override suppression, and preferred host (for tests). */
726
+ function resetArweaveReadGatewayForTests() {
727
+ invalidateReadGatewayCache();
728
+ BaseArweaveClient.resetReadGatewaySelectionStateForTests();
729
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
730
+ BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
731
+ }
732
+ }
733
+ /**
734
+ * GET /info with timeout. Treat 2xx + JSON object as healthy.
735
+ */
736
+ async function probeGateway(baseUrl, signal) {
737
+ const url = `${baseUrl.replace(/\/$/, '')}/info`;
738
+ let timer;
739
+ const controller = new AbortController();
740
+ const effectiveSignal = signal ?? controller.signal;
741
+ if (!signal) {
742
+ timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
743
+ }
744
+ try {
745
+ const response = await fetch(url, {
746
+ method: 'GET',
747
+ signal: effectiveSignal,
748
+ headers: { Accept: 'application/json' },
749
+ });
750
+ if (!response.ok)
751
+ return false;
752
+ const text = await response.text();
753
+ if (!text.trim())
754
+ return false;
755
+ try {
756
+ const json = JSON.parse(text);
757
+ return typeof json === 'object' && json !== null;
758
+ }
759
+ catch {
760
+ return false;
761
+ }
762
+ }
763
+ catch {
764
+ return false;
765
+ }
766
+ finally {
767
+ if (timer)
768
+ clearTimeout(timer);
769
+ }
770
+ }
771
+ async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
772
+ for (const host of hosts) {
773
+ const h = host.trim().replace(/\/$/, '');
774
+ if (!h)
775
+ continue;
776
+ const baseUrl = `${protocol}://${h}`;
777
+ if (await probeGateway(baseUrl, signal)) {
778
+ return h;
779
+ }
780
+ }
781
+ return null;
782
+ }
783
+ function buildOrderedHostsForProbe() {
784
+ const primary = BaseArweaveClient.getHost();
785
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
786
+ return mergePrimaryHostWithDefaults(primary, defaults);
787
+ }
788
+ /**
789
+ * Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
790
+ * No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
791
+ * Uses a short TTL cache to avoid probing on every read.
792
+ */
793
+ async function ensureReadGatewaySelected(signal) {
794
+ if (BaseArweaveClient.isReadGatewayLocked()) {
795
+ return BaseArweaveClient.getHost();
796
+ }
797
+ const now = Date.now();
798
+ if (readGatewayCache && now < readGatewayCache.expiresAt) {
799
+ return readGatewayCache.host;
800
+ }
801
+ if (ensureInFlight) {
802
+ return ensureInFlight;
803
+ }
804
+ ensureInFlight = (async () => {
805
+ const ordered = buildOrderedHostsForProbe();
806
+ const protocol = BaseArweaveClient.getProtocol();
807
+ const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
808
+ if (!BaseArweaveClient.isReadGatewayLocked()) {
809
+ if (picked) {
810
+ BaseArweaveClient.applyProbedReadGateway(picked);
811
+ }
812
+ }
813
+ readGatewayCache = {
814
+ host: BaseArweaveClient.getHost(),
815
+ expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
816
+ };
817
+ return readGatewayCache.host;
818
+ })();
819
+ try {
820
+ return await ensureInFlight;
821
+ }
822
+ finally {
823
+ ensureInFlight = null;
824
+ }
825
+ }
826
+
827
+ var selectReadGateway = /*#__PURE__*/Object.freeze({
828
+ __proto__: null,
829
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
830
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
831
+ probeGateway: probeGateway,
832
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
833
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
834
+ });
835
+
606
836
  const GATEWAY_TX_QUERY = `
607
837
  query ArweaveGatewayTransaction($id: String!) {
608
838
  transaction(id: $id) {
@@ -699,6 +929,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
699
929
  return null;
700
930
  }
701
931
  }
932
+ /**
933
+ * Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
934
+ * {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
935
+ * {@link getDefaultArweaveReadGatewayHostsOrdered}.
936
+ */
937
+ async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
938
+ const defaults = getDefaultArweaveReadGatewayHostsOrdered();
939
+ const trimmed = graphqlUrl?.trim();
940
+ let protocol = 'https';
941
+ let preferredHost = null;
942
+ if (trimmed) {
943
+ try {
944
+ const u = new URL(trimmed);
945
+ protocol = u.protocol === 'http:' ? 'http' : 'https';
946
+ preferredHost = u.hostname || null;
947
+ }
948
+ catch {
949
+ preferredHost = null;
950
+ }
951
+ }
952
+ const ordered = preferredHost && preferredHost.length > 0
953
+ ? mergePrimaryHostWithDefaults(preferredHost, defaults)
954
+ : [...defaults];
955
+ const signal = init?.signal;
956
+ for (const host of ordered) {
957
+ const base = `${protocol}://${host}`;
958
+ if (!(await probeGateway(base, signal ?? undefined)))
959
+ continue;
960
+ const gqlUrl = `${protocol}://${host}/graphql`;
961
+ const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
962
+ if (result !== null) {
963
+ return result;
964
+ }
965
+ }
966
+ return null;
967
+ }
702
968
 
703
969
  class BaseEasClient {
704
970
  static setPlatformClass(platformClass) {
@@ -1374,6 +1640,19 @@ const arweaveL1FinalizeJobs = sqliteTable('arweave_l1_finalize_jobs', {
1374
1640
  dataItemIdUnique: uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
1375
1641
  }));
1376
1642
 
1643
+ const easSyncProcesses = sqliteTable('eas_sync_processes', {
1644
+ id: int('id').primaryKey({ autoIncrement: true }),
1645
+ status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
1646
+ startedAt: int('started_at').notNull(),
1647
+ completedAt: int('completed_at'),
1648
+ requestPayload: text('request_payload').notNull(),
1649
+ errorMessage: text('error_message'),
1650
+ errorDetails: text('error_details'),
1651
+ persistedSnapshot: text('persisted_snapshot').notNull(),
1652
+ createdAt: int('created_at'),
1653
+ updatedAt: int('updated_at'),
1654
+ });
1655
+
1377
1656
  /**
1378
1657
  * Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
1379
1658
  * Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
@@ -1864,6 +2143,7 @@ var index = /*#__PURE__*/Object.freeze({
1864
2143
  capitalizeFirstLetter: capitalizeFirstLetter,
1865
2144
  classifyMediaRef: classifyMediaRef,
1866
2145
  convertTxIdToImage: convertTxIdToImage,
2146
+ ensureReadGatewaySelected: ensureReadGatewaySelected,
1867
2147
  generateId: generateId,
1868
2148
  getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
1869
2149
  getArweaveUploadStatus: getArweaveUploadStatus,
@@ -1883,6 +2163,7 @@ var index = /*#__PURE__*/Object.freeze({
1883
2163
  getUploadExecutor: getUploadExecutor,
1884
2164
  getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
1885
2165
  identifyString: identifyString,
2166
+ invalidateReadGatewayCache: invalidateReadGatewayCache,
1886
2167
  isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
1887
2168
  isBinary: isBinary,
1888
2169
  isPlaceholderUid: isPlaceholderUid,
@@ -1895,11 +2176,15 @@ var index = /*#__PURE__*/Object.freeze({
1895
2176
  normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
1896
2177
  parseEasRelationPropertyName: parseEasRelationPropertyName,
1897
2178
  pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
2179
+ probeGateway: probeGateway,
1898
2180
  queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
2181
+ queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
2182
+ resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
1899
2183
  resolveMediaRef: resolveMediaRef,
1900
2184
  resolveMetadataRecord: resolveMetadataRecord,
1901
2185
  resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
1902
2186
  resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
2187
+ selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
1903
2188
  setAdditionalSyncAddresses: setAdditionalSyncAddresses,
1904
2189
  setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
1905
2190
  setRevokeExecutor: setRevokeExecutor,
@@ -1922,7 +2207,7 @@ const createPropertyInstances = async (propertyFileIds) => {
1922
2207
  return;
1923
2208
  }
1924
2209
  try {
1925
- const mod = await import('./ModelProperty-DWtv9fQr.js');
2210
+ const mod = await import('./ModelProperty-CIeLasI4.js');
1926
2211
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
1927
2212
  if (!ModelProperty) {
1928
2213
  logger$t('createPropertyInstances: ModelProperty not available from dynamic import');
@@ -2106,7 +2391,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
2106
2391
  // Step 2: Fallback to Schema context (only if database doesn't have the model)
2107
2392
  // This handles the case where model exists in schema file but not yet in database
2108
2393
  try {
2109
- const _mod_0 = await import('./Schema-CqqcEexA.js');
2394
+ const _mod_0 = await import('./Schema-B3YQHTtu.js');
2110
2395
  const _ns_0 = _mod_0.b;
2111
2396
  const schemaMod = _ns_0;
2112
2397
  const { Schema } = schemaMod;
@@ -2352,7 +2637,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
2352
2637
  }
2353
2638
  // Mark schema as draft when a new model is created so saveNewVersion() can persist it
2354
2639
  try {
2355
- const _mod_1 = await import('./Schema-CqqcEexA.js');
2640
+ const _mod_1 = await import('./Schema-B3YQHTtu.js');
2356
2641
  const _ns_1 = _mod_1.b;
2357
2642
  const schemaMod = _ns_1;
2358
2643
  const { Schema } = schemaMod;
@@ -2398,10 +2683,10 @@ const validateModel = fromCallback(({ sendBack, input: { context } }) => {
2398
2683
  const _validateModel = async () => {
2399
2684
  try {
2400
2685
  // Use dynamic imports to break circular dependencies
2401
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2686
+ const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
2402
2687
  const { SchemaValidationService } = validationServiceMod;
2403
2688
  const validationService = new SchemaValidationService();
2404
- const _mod_2 = await import('./Schema-CqqcEexA.js');
2689
+ const _mod_2 = await import('./Schema-B3YQHTtu.js');
2405
2690
  const _ns_2 = _mod_2.b;
2406
2691
  const schemaMod = _ns_2;
2407
2692
  const { Schema } = schemaMod;
@@ -2513,7 +2798,7 @@ const createModelProperties = fromCallback(({ sendBack, input }) => {
2513
2798
  return;
2514
2799
  }
2515
2800
  logger$r(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
2516
- const mod = await import('./ModelProperty-DWtv9fQr.js');
2801
+ const mod = await import('./ModelProperty-CIeLasI4.js');
2517
2802
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
2518
2803
  if (!ModelProperty) {
2519
2804
  logger$r('ModelProperty not available from dynamic import');
@@ -2617,7 +2902,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2617
2902
  const structureMsg = `[validateEntity] Validating model structure`;
2618
2903
  logger$q(structureMsg);
2619
2904
  // Use existing Model validation
2620
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2905
+ const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
2621
2906
  const { SchemaValidationService } = validationServiceMod;
2622
2907
  const validationService = new SchemaValidationService();
2623
2908
  // Validate model structure
@@ -2635,7 +2920,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2635
2920
  if (entityInput.entityData.schemaName) {
2636
2921
  try {
2637
2922
  logger$q(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
2638
- const _mod_3 = await import('./Schema-CqqcEexA.js');
2923
+ const _mod_3 = await import('./Schema-B3YQHTtu.js');
2639
2924
  const _ns_3 = _mod_3.b;
2640
2925
  const schemaMod = _ns_3;
2641
2926
  const { Schema } = schemaMod;
@@ -2673,7 +2958,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2673
2958
  }
2674
2959
  else if (entityInput.entityType === 'modelProperty') {
2675
2960
  // Use existing ModelProperty validation
2676
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
2961
+ const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
2677
2962
  const { SchemaValidationService } = validationServiceMod;
2678
2963
  const validationService = new SchemaValidationService();
2679
2964
  // Validate property structure
@@ -2688,7 +2973,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2688
2973
  // If schema name and model name provided, validate against schema
2689
2974
  if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
2690
2975
  try {
2691
- const _mod_4 = await import('./Schema-CqqcEexA.js');
2976
+ const _mod_4 = await import('./Schema-B3YQHTtu.js');
2692
2977
  const _ns_4 = _mod_4.b;
2693
2978
  const schemaMod = _ns_4;
2694
2979
  const { Schema } = schemaMod;
@@ -2719,7 +3004,7 @@ const validateEntity = fromPromise(async ({ input }) => {
2719
3004
  }
2720
3005
  else if (entityInput.entityType === 'schema') {
2721
3006
  // Schema validation - use existing validation
2722
- const validationServiceMod = await import('./SchemaValidationService-Cb-b4kpD.js');
3007
+ const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
2723
3008
  const { SchemaValidationService } = validationServiceMod;
2724
3009
  const validationService = new SchemaValidationService();
2725
3010
  const schemaResult = validationService.validateSchema(entityInput.entityData);
@@ -4671,7 +4956,7 @@ const writeToDatabase = fromCallback(({ sendBack, input }) => {
4671
4956
  // initial write completes is not overwritten by the stale requestWrite payload.
4672
4957
  let dataToWrite = input.entityData;
4673
4958
  try {
4674
- const mod = await import('./ModelProperty-DWtv9fQr.js');
4959
+ const mod = await import('./ModelProperty-CIeLasI4.js');
4675
4960
  const ModelProperty = mod?.ModelProperty ?? mod?.default;
4676
4961
  if (ModelProperty && typeof ModelProperty.getById === 'function') {
4677
4962
  const instance = ModelProperty.getById(input.entityId);
@@ -5051,7 +5336,7 @@ const modelMachine = setup({
5051
5336
  // Create ModelProperty instances for any new property IDs
5052
5337
  if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
5053
5338
  // Import and create instances asynchronously (fire-and-forget)
5054
- import('./ModelProperty-DWtv9fQr.js').then(({ ModelProperty }) => {
5339
+ import('./ModelProperty-CIeLasI4.js').then(({ ModelProperty }) => {
5055
5340
  const createPromises = newPropertyIds.map(async (propertyFileId) => {
5056
5341
  try {
5057
5342
  const property = await ModelProperty.createById(propertyFileId);
@@ -5354,6 +5639,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
5354
5639
  var MachineIds;
5355
5640
  (function (MachineIds) {
5356
5641
  MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
5642
+ MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
5357
5643
  MachineIds["GLOBAL"] = "@seedSdk/global";
5358
5644
  MachineIds["INTERNAL"] = "@seedSdk/internal";
5359
5645
  MachineIds["EAS"] = "@seedSdk/eas";
@@ -5426,7 +5712,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
5426
5712
  * This constant is kept for backward compatibility but will be removed in a future version.
5427
5713
  * Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
5428
5714
  */
5429
- ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'arweave.net';
5715
+ ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
5430
5716
 
5431
5717
  debug('seedSdk:item:service:actors:waitForDb');
5432
5718
  const waitForDb$1 = fromCallback(({ sendBack }) => {
@@ -6347,7 +6633,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
6347
6633
  rowNum: sql.raw(`
6348
6634
  ROW_NUMBER() OVER (
6349
6635
  PARTITION BY property_name
6350
- ORDER BY COALESCE(attestation_created_at, created_at) DESC
6636
+ ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
6351
6637
  )
6352
6638
  `).as('rowNum')
6353
6639
  })
@@ -6360,6 +6646,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
6360
6646
  getMetadataLatest: getMetadataLatest
6361
6647
  });
6362
6648
 
6649
+ /**
6650
+ * Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
6651
+ * `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
6652
+ */
6653
+ function metadataLatestFirstSortKey(row) {
6654
+ return {
6655
+ t: row.attestationCreatedAt ?? row.createdAt ?? 0,
6656
+ localId: String(row.localId ?? ''),
6657
+ };
6658
+ }
6659
+ /** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
6660
+ function compareMetadataRowsLatestFirst(a, b) {
6661
+ const ka = metadataLatestFirstSortKey(a);
6662
+ const kb = metadataLatestFirstSortKey(b);
6663
+ if (kb.t !== ka.t)
6664
+ return kb.t - ka.t;
6665
+ return kb.localId.localeCompare(ka.localId);
6666
+ }
6667
+
6363
6668
  const logger$l = debug('seedSdk:item:actors:loadOrCreateItem');
6364
6669
  /**
6365
6670
  * Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
@@ -6401,9 +6706,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
6401
6706
  return b;
6402
6707
  if (sa !== sb)
6403
6708
  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;
6709
+ const cmp = compareMetadataRowsLatestFirst(a, b);
6710
+ return cmp < 0 ? a : b;
6407
6711
  }
6408
6712
  function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
6409
6713
  const byKey = new Map();
@@ -6451,7 +6755,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6451
6755
  const schemaNameToTry = model$1?.schemaName;
6452
6756
  if (schemaNameToTry) {
6453
6757
  try {
6454
- const _mod_5 = await import('./Schema-CqqcEexA.js');
6758
+ const _mod_5 = await import('./Schema-B3YQHTtu.js');
6455
6759
  const _ns_5 = _mod_5.b;
6456
6760
  const { Schema } = _ns_5;
6457
6761
  const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
@@ -6502,7 +6806,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6502
6806
  }
6503
6807
  }
6504
6808
  if (Object.keys(propertySchemas).length === 0) {
6505
- const schemaMod = await import('./index-Cqf_DxkJ.js');
6809
+ const schemaMod = await import('./index-3Ekqb4QB.js');
6506
6810
  const { ModelPropertyDataTypes } = schemaMod;
6507
6811
  const KNOWN_MODEL_FALLBACKS = {
6508
6812
  Post: {
@@ -6549,7 +6853,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6549
6853
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
6550
6854
  let propSchema = propertySchemas[propertyName];
6551
6855
  if (!propSchema && isRefTypeFromMeta) {
6552
- const schemaMod = await import('./index-Cqf_DxkJ.js');
6856
+ const schemaMod = await import('./index-3Ekqb4QB.js');
6553
6857
  const { ModelPropertyDataTypes } = schemaMod;
6554
6858
  propSchema = {
6555
6859
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -6806,9 +7110,9 @@ const runPublish = fromCallback(({ sendBack, input: { context } }) => {
6806
7110
  sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
6807
7111
  return;
6808
7112
  }
6809
- const getPublishUploadsMod = await import('./getPublishUploads-DS2dQ4Ho.js');
7113
+ const getPublishUploadsMod = await import('./getPublishUploads-Cf2J-5FR.js');
6810
7114
  const { getPublishUploads } = getPublishUploadsMod;
6811
- const getPublishPayloadMod = await import('./getPublishPayload-DpYwi-rd.js');
7115
+ const getPublishPayloadMod = await import('./getPublishPayload-Ddc_LGPs.js');
6812
7116
  const { getPublishPayload } = getPublishPayloadMod;
6813
7117
  const uploads = await getPublishUploads(item);
6814
7118
  let uploadedTransactions = [];
@@ -7154,6 +7458,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
7154
7458
  return rows[0];
7155
7459
  };
7156
7460
 
7461
+ var getSeedData$1 = /*#__PURE__*/Object.freeze({
7462
+ __proto__: null,
7463
+ getSeedData: getSeedData
7464
+ });
7465
+
7157
7466
  /**
7158
7467
  * Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
7159
7468
  * Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
@@ -7643,7 +7952,7 @@ const resolveRelatedValue = fromCallback(({ sendBack, input: { context } }) => {
7643
7952
  const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
7644
7953
  const _resolveRelatedValue = async () => {
7645
7954
  // Use dynamic import to break circular dependency
7646
- const schemaMod = await import('./index-Cqf_DxkJ.js');
7955
+ const schemaMod = await import('./index-3Ekqb4QB.js');
7647
7956
  const { ModelPropertyDataTypes } = schemaMod;
7648
7957
  if (!propertyValue || !isRelation || populatedFromDb) {
7649
7958
  return;
@@ -8006,150 +8315,771 @@ function parseListPropertyValueFromStorage(raw) {
8006
8315
  return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
8007
8316
  }
8008
8317
 
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');
8318
+ const eventEmitter = new EventEmitter();
8319
+
8320
+ const GET_FILES_METADATA = graphql(/* GraphQL */ `
8321
+ query GetFilesMetadata($where: AttestationWhereInput!) {
8322
+ filesMetadata: attestations(
8323
+ where: $where
8324
+ orderBy: [{ timeCreated: desc }]
8325
+ ) {
8326
+ ...attestationFields
8016
8327
  }
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);
8126
- }
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
- });
8328
+ }
8329
+ `);
8330
+
8331
+ const getMetadata = async (props) => {
8332
+ const appDb = BaseDb.getAppDb();
8333
+ let storageTransactionId;
8334
+ if (props) {
8335
+ storageTransactionId = props.storageTransactionId;
8336
+ }
8337
+ const whereClauses = [];
8338
+ if (storageTransactionId) {
8339
+ whereClauses.push(eq(metadata$1.propertyName, 'storageTransactionId'));
8340
+ whereClauses.push(eq(metadata$1.propertyValue, storageTransactionId));
8341
+ }
8342
+ const metadataRows = await appDb
8343
+ .select()
8344
+ .from(metadata$1)
8345
+ .where(and(...whereClauses));
8346
+ if (!metadataRows || metadataRows.length === 0) {
8347
+ return;
8348
+ }
8349
+ return metadataRows[0];
8350
+ };
8351
+
8352
+ const saveMetadata = async (metadataRecord, metadataValues) => {
8353
+ if (!metadataRecord.localId) {
8354
+ return;
8355
+ }
8356
+ const appDb = BaseDb.getAppDb();
8357
+ await appDb
8358
+ .update(metadata$1)
8359
+ .set({
8360
+ ...metadataValues,
8361
+ updatedAt: Date.now(),
8362
+ })
8363
+ .where(eq(metadata$1.localId, metadataRecord.localId));
8364
+ };
8365
+
8366
+ const isNode = () => {
8367
+ return (typeof process !== 'undefined' &&
8368
+ process.versions != null &&
8369
+ process.versions.node != null);
8370
+ };
8371
+ const isBrowser = () => {
8372
+ return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
8373
+ };
8374
+ const isElectron = () => {
8375
+ return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
8376
+ };
8377
+ /**
8378
+ * Detects if code is running in an Electron renderer process.
8379
+ *
8380
+ * Uses multiple detection methods for robustness:
8381
+ * 1. Checks process.type === 'renderer' (most reliable)
8382
+ * 2. Falls back to checking if Electron is present and window/document exist
8383
+ *
8384
+ * @returns true if running in Electron renderer process, false otherwise
8385
+ */
8386
+ const isElectronRenderer = () => {
8387
+ // Method 1: Check process.type (most reliable - official Electron API)
8388
+ if (typeof process !== 'undefined' &&
8389
+ process.type === 'renderer') {
8390
+ return true;
8391
+ }
8392
+ // Method 2: Fallback - Electron + browser-like environment
8393
+ // Renderer processes have window/document, main process doesn't (in modern Electron)
8394
+ if (isElectron() &&
8395
+ typeof window !== 'undefined' &&
8396
+ typeof document !== 'undefined') {
8397
+ return true;
8398
+ }
8399
+ return false;
8400
+ };
8401
+ /**
8402
+ * True where OPFS-backed Arweave file downloads should run: normal browsers and
8403
+ * Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
8404
+ */
8405
+ const supportsOpfsFileDownloads = () => {
8406
+ return isBrowser() || isElectronRenderer();
8407
+ };
8408
+
8409
+ const logger$g = debug('seedSdk:files:download');
8410
+ const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
8411
+ /** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
8412
+ const GET_FILES_METADATA_STALE_MS = 120000;
8413
+ let bulkDownloadInFlight = null;
8414
+ const lazyDownloadInFlightByTransactionId = new Map();
8415
+ // syncDbFiles helper - internal service removed, functionality moved here
8416
+ const syncDbFiles = async (endpoints) => {
8417
+ // TODO: Implement syncDbFiles functionality if needed
8418
+ // This was previously in @/services/internal/helpers
8419
+ logger$g('[download] syncDbFiles called but not yet implemented');
8420
+ return Promise.resolve();
8421
+ };
8422
+ const getAppDbReady = async () => {
8423
+ if (!BaseDb.isAppDbReady()) {
8424
+ // Wait for ClientManager to be ready (DB_INIT state or later)
8425
+ const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
8426
+ const { getClient } = clientManagerMod;
8427
+ const clientManager = getClient();
8428
+ const clientService = clientManager.getService();
8429
+ await waitFor(clientService, (snapshot) => {
8430
+ const state = snapshot.value;
8431
+ return state === 'dbInit' ||
8432
+ state === 'saveConfig' ||
8433
+ state === 'processSchemaFiles' ||
8434
+ state === 'addModelsToStore' ||
8435
+ state === 'addModelsToDb' ||
8436
+ state === 'idle';
8437
+ }, { timeout: 30000 });
8438
+ }
8439
+ return BaseDb.getAppDb();
8440
+ };
8441
+ const getExcludedTransactions = async () => {
8442
+ const appDb = await getAppDbReady();
8443
+ if (!appDb) {
8444
+ return new Set();
8445
+ }
8446
+ const excludedTransactionsQuery = await appDb
8447
+ .select()
8448
+ .from(appState)
8449
+ .where(eq(appState.key, 'excludedTransactions'));
8450
+ const excludedTransactions = new Set();
8451
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
8452
+ const valueString = excludedTransactionsQuery[0].value;
8453
+ if (valueString) {
8454
+ const excludedTransactionsArray = JSON.parse(valueString);
8455
+ for (const txId of excludedTransactionsArray) {
8456
+ excludedTransactions.add(txId);
8457
+ }
8458
+ }
8459
+ }
8460
+ return excludedTransactions;
8461
+ };
8462
+ /** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
8463
+ const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
8464
+ const normalizeArweaveTxId = (raw) => {
8465
+ if (raw == null || raw === '')
8466
+ return undefined;
8467
+ const t = String(raw).trim();
8468
+ if (ARWEAVE_TX_ID_RE.test(t))
8469
+ return t;
8470
+ const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
8471
+ if (m)
8472
+ return m[1];
8473
+ // Values may be full gateway URLs or paths; scan for the embedded tx id.
8474
+ const embedded = t.match(/[a-z0-9_-]{43}/gi);
8475
+ if (embedded) {
8476
+ for (const candidate of embedded) {
8477
+ if (ARWEAVE_TX_ID_RE.test(candidate))
8478
+ return candidate;
8479
+ }
8480
+ }
8481
+ return undefined;
8482
+ };
8483
+ const mergeAddressLists = (a, b) => {
8484
+ const seen = new Set();
8485
+ const out = [];
8486
+ for (const addr of [...(a ?? []), ...(b ?? [])]) {
8487
+ if (!addr || !addr.trim())
8488
+ continue;
8489
+ const k = addr.toLowerCase();
8490
+ if (seen.has(k))
8491
+ continue;
8492
+ seen.add(k);
8493
+ out.push(addr);
8494
+ }
8495
+ return out;
8496
+ };
8497
+ const collectTransactionIdsFromLocalMetadata = async () => {
8498
+ const appDb = await getAppDbReady();
8499
+ if (!appDb) {
8500
+ return [];
8501
+ }
8502
+ const nameOr = or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'storage_transaction_id'), eq(metadata$1.propertyName, 'transactionId'));
8503
+ const propRows = await appDb
8504
+ .select({ propertyValue: metadata$1.propertyValue })
8505
+ .from(metadata$1)
8506
+ .where(and(nameOr, isNotNull(metadata$1.propertyValue)));
8507
+ const refRows = await appDb
8508
+ .select({ refResolvedValue: metadata$1.refResolvedValue })
8509
+ .from(metadata$1)
8510
+ .where(isNotNull(metadata$1.refResolvedValue));
8511
+ const ids = new Set();
8512
+ for (const row of propRows) {
8513
+ const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
8514
+ if (id)
8515
+ ids.add(id);
8516
+ }
8517
+ for (const row of refRows) {
8518
+ const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
8519
+ if (id)
8520
+ ids.add(id);
8521
+ }
8522
+ return Array.from(ids);
8523
+ };
8524
+ const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
8525
+ const transactionIds = [];
8526
+ for (const fileMetadata of filesMetadata) {
8527
+ // Validate and parse decodedDataJson
8528
+ if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
8529
+ console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
8530
+ continue;
8531
+ }
8532
+ let json;
8533
+ try {
8534
+ json = JSON.parse(fileMetadata.decodedDataJson);
8535
+ }
8536
+ catch (error) {
8537
+ console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
8538
+ continue;
8539
+ }
8540
+ if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
8541
+ console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
8542
+ continue;
8543
+ }
8544
+ const rawTx = json[0].value.value;
8545
+ if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
8546
+ continue;
8547
+ }
8548
+ const transactionId = normalizeArweaveTxId(rawTx.trim());
8549
+ if (!transactionId) {
8550
+ continue;
8551
+ }
8552
+ if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
8553
+ continue;
8554
+ }
8555
+ transactionIds.push(transactionId);
8556
+ }
8557
+ return transactionIds;
8558
+ };
8559
+ const downloadTransactionIds = async (rawTransactionIds, options) => {
8560
+ if (!supportsOpfsFileDownloads()) {
8561
+ return false;
8562
+ }
8563
+ const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
8564
+ if (transactionIds.length === 0) {
8565
+ return false;
8566
+ }
8567
+ const excludedTransactions = await getExcludedTransactions();
8568
+ const queryClient = BaseQueryClient.getQueryClient();
8569
+ const transactionIdsToDownload = [];
8570
+ await ensureReadGatewaySelected();
8571
+ for (const transactionId of transactionIds) {
8572
+ if (excludedTransactions.has(transactionId)) {
8573
+ continue;
8574
+ }
8575
+ try {
8576
+ // Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
8577
+ // CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
8578
+ let tags = [];
8579
+ try {
8580
+ tags = await queryClient.fetchQuery({
8581
+ queryKey: ['getTransactionTags', transactionId],
8582
+ queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
8583
+ });
8584
+ }
8585
+ catch {
8586
+ tags = [];
8587
+ }
8588
+ if (tags && tags.length > 0) {
8589
+ for (const { name, value } of tags) {
8590
+ if (name !== 'Content-SHA-256')
8591
+ continue;
8592
+ const metadataRecord = await getMetadata({
8593
+ storageTransactionId: transactionId,
8594
+ });
8595
+ if (metadataRecord) {
8596
+ await saveMetadata(metadataRecord, {
8597
+ contentHash: value,
8598
+ });
8599
+ }
8600
+ }
8601
+ }
8602
+ transactionIdsToDownload.push(transactionId);
8603
+ }
8604
+ catch (error) {
8605
+ logger$g(error);
8606
+ }
8607
+ }
8608
+ if (transactionIdsToDownload.length === 0) {
8609
+ return false;
8610
+ }
8611
+ if (transactionIdsToDownload.length === 1) {
8612
+ await BaseFileManager.downloadFileByTransactionId({
8613
+ transactionId: transactionIdsToDownload[0],
8614
+ arweaveHost: BaseArweaveClient.getHost(),
8615
+ excludedTransactions,
8616
+ });
8617
+ }
8618
+ else {
8619
+ await BaseFileManager.downloadAllFiles({
8620
+ transactionIds: transactionIdsToDownload,
8621
+ arweaveHost: BaseArweaveClient.getHost(),
8622
+ excludedTransactions,
8623
+ });
8624
+ }
8625
+ if (options?.resizeAllImages !== false) {
8626
+ await BaseFileManager.resizeAllImages({
8627
+ width: 480,
8628
+ height: 480,
8629
+ });
8630
+ }
8631
+ return true;
8632
+ };
8633
+ const runBulkDownloadWithDedupe = async (transactionIds) => {
8634
+ if (bulkDownloadInFlight) {
8635
+ return bulkDownloadInFlight;
8636
+ }
8637
+ bulkDownloadInFlight = (async () => {
8638
+ try {
8639
+ await downloadTransactionIds(transactionIds, { resizeAllImages: true });
8640
+ }
8641
+ finally {
8642
+ bulkDownloadInFlight = null;
8643
+ }
8644
+ })();
8645
+ return bulkDownloadInFlight;
8646
+ };
8647
+ const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
8648
+ if (!supportsOpfsFileDownloads()) {
8649
+ return;
8650
+ }
8651
+ await syncDbFiles();
8652
+ eventEmitter.emit('fs.downloadAll.success', { eventId });
8653
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
8654
+ };
8655
+ const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
8656
+ if (!supportsOpfsFileDownloads()) {
8657
+ return;
8658
+ }
8659
+ const addressesHint = Array.isArray(addressesHintOrPayload)
8660
+ ? addressesHintOrPayload
8661
+ : undefined;
8662
+ let fromDb = [];
8663
+ if (BaseDb.isAppDbReady()) {
8664
+ fromDb = await getAllAddressesFromDb();
8665
+ }
8666
+ if (!BaseDb.isAppDbReady()) {
8667
+ await getAppDbReady();
8668
+ fromDb = await getAllAddressesFromDb();
8669
+ }
8670
+ const addresses = mergeAddressLists(addressesHint, fromDb);
8671
+ if (!addresses || addresses.length === 0) {
8672
+ return;
8673
+ }
8674
+ const queryClient = BaseQueryClient.getQueryClient();
8675
+ const easClient = BaseEasClient.getEasClient();
8676
+ const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
8677
+ const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
8678
+ where: {
8679
+ attester: {
8680
+ in: addresses,
8681
+ },
8682
+ schema: {
8683
+ is: {
8684
+ id: {
8685
+ equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
8686
+ },
8687
+ },
8688
+ },
8689
+ },
8690
+ });
8691
+ let { filesMetadata } = await queryClient.fetchQuery({
8692
+ queryKey: filesMetadataQueryKey,
8693
+ queryFn: fetchFilesMetadata,
8694
+ staleTime: GET_FILES_METADATA_STALE_MS,
8695
+ });
8696
+ if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
8697
+ await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
8698
+ ({ filesMetadata } = await queryClient.fetchQuery({
8699
+ queryKey: filesMetadataQueryKey,
8700
+ queryFn: fetchFilesMetadata,
8701
+ staleTime: GET_FILES_METADATA_STALE_MS,
8702
+ }));
8703
+ }
8704
+ const filesRoot = BaseFileManager.getWorkingDir();
8705
+ await BaseFileManager.createDirIfNotExists(filesRoot);
8706
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
8707
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
8708
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
8709
+ const excludedTransactions = await getExcludedTransactions();
8710
+ const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
8711
+ const fromLocal = await collectTransactionIdsFromLocalMetadata();
8712
+ const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
8713
+ await runBulkDownloadWithDedupe(transactionIds);
8714
+ };
8715
+ const downloadTransactionIdWithDedupe = async (transactionId) => {
8716
+ if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
8717
+ return false;
8718
+ }
8719
+ const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
8720
+ const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
8721
+ if (existing) {
8722
+ return existing;
8723
+ }
8724
+ const inFlight = (async () => {
8725
+ try {
8726
+ const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
8727
+ return ok;
8728
+ }
8729
+ finally {
8730
+ lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
8731
+ }
8732
+ })();
8733
+ lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
8734
+ return inFlight;
8735
+ };
8736
+ const scheduleBulkFilesDownloadFromEasSyncThrottled = throttle((addressesHint) => {
8737
+ void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
8738
+ logger$g('[scheduleBulkFilesDownloadFromEasSync] failed', error);
8739
+ });
8740
+ }, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
8741
+ const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
8742
+ if (!supportsOpfsFileDownloads()) {
8743
+ return;
8744
+ }
8745
+ scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
8746
+ };
8747
+
8748
+ var download = /*#__PURE__*/Object.freeze({
8749
+ __proto__: null,
8750
+ downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
8751
+ downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
8752
+ downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
8753
+ scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
8754
+ });
8755
+
8756
+ /** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
8757
+ const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
8758
+ /** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
8759
+ const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
8760
+ function extractArweaveTransactionId(raw) {
8761
+ const t = raw.trim();
8762
+ const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
8763
+ if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
8764
+ return embedded[0];
8765
+ }
8766
+ return t;
8767
+ }
8768
+ /**
8769
+ * GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
8770
+ * arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
8771
+ */
8772
+ async function fetchHtmlViaRawAcrossGateways(txId) {
8773
+ const id = extractArweaveTransactionId(txId);
8774
+ if (!id || SEED_UID_HEX_RE.test(id))
8775
+ return undefined;
8776
+ try {
8777
+ const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
8778
+ await ensureReadGatewaySelected().catch(() => { });
8779
+ }
8780
+ catch {
8781
+ /* optional */
8782
+ }
8783
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8784
+ const protocol = BaseArweaveClient.getProtocol();
8785
+ const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
8786
+ for (const host of hosts) {
8787
+ const h = host.trim().replace(/\/$/, '');
8788
+ if (!h)
8789
+ continue;
8790
+ const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
8791
+ try {
8792
+ const res = await fetch(url, { method: 'GET', credentials: 'omit' });
8793
+ if (!res.ok)
8794
+ continue;
8795
+ const text = await res.text();
8796
+ if (typeof text === 'string' && text.length > 0) {
8797
+ return text;
8798
+ }
8799
+ }
8800
+ catch {
8801
+ /* next gateway */
8802
+ }
8803
+ }
8804
+ return undefined;
8805
+ }
8806
+ /**
8807
+ * Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
8808
+ * `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
8809
+ */
8810
+ async function resolveHtmlStorageSeedLocalId(propertyValue) {
8811
+ const pv = String(propertyValue ?? '').trim();
8812
+ if (!pv)
8813
+ return undefined;
8814
+ if (SEED_UID_HEX_RE.test(pv)) {
8815
+ const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
8816
+ return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
8817
+ }
8818
+ return pv;
8819
+ }
8820
+ /**
8821
+ * When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
8822
+ * Html storage seed's published Arweave transaction id on that child seed.
8823
+ */
8824
+ async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
8825
+ const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
8826
+ const pickTx = async (name) => {
8827
+ const row = await getPropertyData({ propertyName: name, seedLocalId });
8828
+ const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
8829
+ return v || undefined;
8830
+ };
8831
+ const txId = (await pickTx('storageTransactionId')) ??
8832
+ (await pickTx('transactionId')) ??
8833
+ (await pickTx('storage_transaction_id'));
8834
+ if (!txId || SEED_UID_HEX_RE.test(txId)) {
8835
+ return { txIdLen: 0, gatewayStringLen: 0 };
8836
+ }
8837
+ const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
8838
+ if (rawHtml && rawHtml.length > 0) {
8839
+ return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
8840
+ }
8841
+ try {
8842
+ const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
8843
+ const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
8844
+ string: true,
8845
+ });
8846
+ if (typeof data === 'string' && data.length > 0) {
8847
+ return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
8848
+ }
8849
+ }
8850
+ catch {
8851
+ /* offline / bad tx id */
8852
+ }
8853
+ try {
8854
+ const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
8855
+ await downloadTransactionIdWithDedupe(txId);
8856
+ const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
8857
+ if (await BaseFileManager.pathExists(retryFp)) {
8858
+ const s = await BaseFileManager.readFileAsString(retryFp);
8859
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8860
+ }
8861
+ const dirPath = BaseFileManager.getFilesPath('html');
8862
+ if (await BaseFileManager.pathExists(dirPath)) {
8863
+ const fs = await BaseFileManager.getFs();
8864
+ const pathMod = BaseFileManager.getPathModule();
8865
+ const files = await fs.promises.readdir(dirPath);
8866
+ const needle = txId.replace(/\.[^/.]+$/, '');
8867
+ const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
8868
+ if (match) {
8869
+ const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
8870
+ return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
8871
+ }
8872
+ }
8873
+ }
8874
+ catch {
8875
+ /* OPFS unsupported or download failed */
8876
+ }
8877
+ return { txIdLen: txId.length, gatewayStringLen: 0 };
8878
+ }
8879
+ /** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
8880
+ async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
8881
+ const pv = String(propertyValue ?? '').trim();
8882
+ if (!pv)
8883
+ return undefined;
8884
+ const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
8885
+ const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
8886
+ let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
8887
+ // OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
8888
+ if (!fileExists && fp) {
8889
+ await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
8890
+ fileExists = await BaseFileManager.pathExists(fp);
8891
+ }
8892
+ let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
8893
+ if (!body && localId) {
8894
+ const ar = await readHtmlBodyFromChildStorageArweave(localId);
8895
+ body = ar.body;
8896
+ }
8897
+ return body;
8898
+ }
8899
+
8900
+ // Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
8901
+ // import { ModelPropertyDataTypes } from '@/schema'
8902
+ const logger$f = debug('seedSdk:property:actors:hydrateFromDb');
8903
+ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8904
+ const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
8905
+ if (!propertyNameRaw) {
8906
+ throw new Error('propertyName is required');
8907
+ }
8908
+ let propertyName = propertyNameRaw;
8909
+ // Note: isRelation, isImage, isFile checks moved inside async function
8910
+ // to use dynamically imported ModelPropertyDataTypes
8911
+ const _hydrateFromDb = async () => {
8912
+ // Use dynamic import to break circular dependency
8913
+ const schemaMod = await import('./index-3Ekqb4QB.js');
8914
+ const { ModelPropertyDataTypes } = schemaMod;
8915
+ const appDb = BaseDb.getAppDb();
8916
+ const whereClauses = [];
8917
+ // Re-check types with dynamically imported ModelPropertyDataTypes
8918
+ // Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
8919
+ const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
8920
+ const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
8921
+ propertyRecordSchema &&
8922
+ propertyRecordSchema.ref &&
8923
+ normalizedDataType === ModelPropertyDataTypes.Relation;
8924
+ const isImageDynamic = propertyRecordSchema &&
8925
+ (normalizedDataType === ModelPropertyDataTypes.Image ||
8926
+ normalizedRefValueType === ModelPropertyDataTypes.Image);
8927
+ const isFileDynamic = propertyRecordSchema &&
8928
+ normalizedDataType === ModelPropertyDataTypes.File;
8929
+ const isHtmlDynamic = propertyRecordSchema &&
8930
+ normalizedDataType === ModelPropertyDataTypes.Html;
8931
+ // Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
8932
+ const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
8933
+ whereClauses.push(propertyNames.length > 1
8934
+ ? or(...propertyNames.map((n) => eq(metadata$1.propertyName, n)))
8935
+ : eq(metadata$1.propertyName, propertyNames[0]));
8936
+ // Draft rows often have only seed_local_id populated; on-chain rows may have uid.
8937
+ // Requiring both with AND misses valid metadata when only one column is set.
8938
+ if (seedUid && seedLocalId) {
8939
+ whereClauses.push(or(eq(metadata$1.seedLocalId, seedLocalId), eq(metadata$1.seedUid, seedUid)));
8940
+ }
8941
+ else if (seedUid) {
8942
+ whereClauses.push(eq(metadata$1.seedUid, seedUid));
8943
+ }
8944
+ else if (seedLocalId) {
8945
+ whereClauses.push(eq(metadata$1.seedLocalId, seedLocalId));
8946
+ }
8947
+ const rows = await appDb
8948
+ .select()
8949
+ .from(metadata$1)
8950
+ .where(and(...whereClauses))
8951
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
8952
+ if (!rows || !rows.length) {
8953
+ return;
8954
+ }
8955
+ const firstRow = rows[0];
8956
+ const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
8957
+ let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
8958
+ let propertyValueProcessed = propertyValueFromDb;
8959
+ let renderValue = refResolvedDisplayValue ?? undefined;
8960
+ // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
8961
+ if (isImageDynamic) {
8962
+ let dir = localStorageDir;
8963
+ if (!dir && isImageDynamic) {
8964
+ dir = 'images';
8965
+ }
8966
+ dir = dir.replace(/^\//, '');
8967
+ if (propertyValueFromDb &&
8968
+ propertyValueFromDb.length === 66) {
8969
+ // Here the storageTransactionId is stored on a different record and
8970
+ // we want to add it as the refResolvedValue
8971
+ const storageTransactionQuery = await appDb
8972
+ .select({
8973
+ propertyValue: metadata$1.propertyValue,
8974
+ })
8975
+ .from(metadata$1)
8976
+ .where(and(eq(metadata$1.seedUid, propertyValueFromDb), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))));
8977
+ if (storageTransactionQuery && storageTransactionQuery.length > 0) {
8978
+ const row = storageTransactionQuery[0];
8979
+ refResolvedValue = row.propertyValue;
8980
+ await updateMetadata({
8981
+ localId,
8982
+ refResolvedValue,
8983
+ localStorageDir: '/images',
8984
+ });
8985
+ }
8986
+ }
8987
+ const resolveMatchingFilePath = async (dir, needle) => {
8988
+ const dirPath = BaseFileManager.getFilesPath(dir);
8989
+ const dirExists = await BaseFileManager.pathExists(dirPath);
8990
+ if (!dirExists)
8991
+ return undefined;
8992
+ const fs = await BaseFileManager.getFs();
8993
+ const path = BaseFileManager.getPathModule();
8994
+ const files = await fs.promises.readdir(dirPath);
8995
+ const matchingFiles = files.filter((file) => {
8996
+ return path.basename(file).includes(needle);
8997
+ });
8998
+ if (!matchingFiles?.length)
8999
+ return undefined;
9000
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9001
+ };
9002
+ if (refResolvedValue) {
9003
+ try {
9004
+ let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9005
+ if (!filePath) {
9006
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9007
+ filePath = await resolveMatchingFilePath(dir, refResolvedValue);
9008
+ }
9009
+ localStorageDir = `/${dir}`;
9010
+ if (filePath) {
9011
+ const file = await BaseFileManager.readFile(filePath);
9012
+ refResolvedDisplayValue = URL.createObjectURL(file);
9013
+ renderValue = refResolvedDisplayValue;
9014
+ // Do not persist blob URL - it is session-scoped
9015
+ }
9016
+ }
9017
+ catch (e) {
9018
+ logger$f('[hydrateFromDb] Image file resolution error', e);
9019
+ }
9020
+ }
9021
+ }
9022
+ if (isFileDynamic && refResolvedValue) {
9023
+ try {
9024
+ const dir = (localStorageDir ?? '/files').replace(/^\//, '');
9025
+ const resolveMatchingFilePath = async (needle) => {
9026
+ const dirPath = BaseFileManager.getFilesPath(dir);
9027
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9028
+ if (!dirExists)
9029
+ return undefined;
9030
+ const fs = await BaseFileManager.getFs();
9031
+ const path = BaseFileManager.getPathModule();
9032
+ const files = await fs.promises.readdir(dirPath);
9033
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9034
+ if (!matchingFiles?.length)
9035
+ return undefined;
9036
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9037
+ };
9038
+ let filePath = await resolveMatchingFilePath(refResolvedValue);
9039
+ if (!filePath) {
9040
+ await downloadTransactionIdWithDedupe(refResolvedValue);
9041
+ filePath = await resolveMatchingFilePath(refResolvedValue);
9042
+ }
9043
+ if (filePath) {
9044
+ localStorageDir = `/${dir}`;
9045
+ renderValue = await BaseFileManager.readFileAsString(filePath);
9046
+ }
9047
+ }
9048
+ catch (e) {
9049
+ logger$f('[hydrateFromDb] File resolution error', e);
9050
+ }
9051
+ }
9052
+ if (propertyRecordSchema &&
9053
+ normalizedDataType === ModelPropertyDataTypes.List &&
9054
+ typeof propertyValueFromDb === 'string') {
9055
+ propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
9056
+ }
9057
+ sendBack({
9058
+ type: 'updateContext',
9059
+ localId,
9060
+ uid,
9061
+ propertyValue: propertyValueProcessed,
9062
+ seedLocalId: seedLocalIdFromDb,
9063
+ seedUid: seedUidFromDb,
9064
+ versionLocalId: versionLocalIdFromDb,
9065
+ versionUid: versionUidFromDb,
9066
+ schemaUid: schemaUidFromDb,
9067
+ refValueType,
9068
+ localStorageDir,
9069
+ refResolvedValue,
9070
+ refResolvedDisplayValue,
9071
+ renderValue,
9072
+ populatedFromDb: true,
9073
+ });
9074
+ if (propertyRecordSchema &&
9075
+ propertyRecordSchema.storageType &&
9076
+ propertyRecordSchema.storageType === 'ItemStorage') {
9077
+ const itemMod = await Promise.resolve().then(function () { return Item$1; });
9078
+ const { Item } = itemMod;
9079
+ const item = await Item.find({
9080
+ seedLocalId: seedLocalId ?? undefined,
9081
+ modelName,
9082
+ });
8153
9083
  if (item) {
8154
9084
  const dir = localStorageDir?.replace(/^\//, '') || 'files';
8155
9085
  const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
@@ -8165,15 +9095,34 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8165
9095
  return;
8166
9096
  }
8167
9097
  }
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);
9098
+ // Html: read file content for renderValue (blob URLs from DB are invalid after reload).
9099
+ // When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
9100
+ if (isHtmlDynamic) {
9101
+ const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
9102
+ let htmlContent;
9103
+ let outRef = refResolvedValue;
9104
+ let outDir = htmlLocalStorageDir;
9105
+ if (refResolvedValue && htmlLocalStorageDir) {
9106
+ const dir = htmlLocalStorageDir.replace(/^\//, '');
9107
+ const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
9108
+ let exists = await BaseFileManager.pathExists(filePath);
9109
+ if (!exists) {
9110
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9111
+ exists = await BaseFileManager.pathExists(filePath);
9112
+ }
9113
+ if (exists) {
9114
+ htmlContent = await BaseFileManager.readFileAsString(filePath);
9115
+ }
9116
+ }
9117
+ if (!htmlContent && propertyValueFromDb) {
9118
+ htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
9119
+ const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
9120
+ if (lid) {
9121
+ outRef = `${lid}.html`;
9122
+ outDir = '/html';
9123
+ }
9124
+ }
9125
+ if (htmlContent) {
8177
9126
  sendBack({
8178
9127
  type: 'updateContext',
8179
9128
  localId,
@@ -8185,8 +9134,8 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8185
9134
  versionUid: versionUidFromDb,
8186
9135
  schemaUid: schemaUidFromDb,
8187
9136
  refValueType,
8188
- localStorageDir: htmlLocalStorageDir,
8189
- refResolvedValue,
9137
+ localStorageDir: outDir,
9138
+ refResolvedValue: outRef ?? refResolvedValue,
8190
9139
  refResolvedDisplayValue,
8191
9140
  renderValue: htmlContent,
8192
9141
  populatedFromDb: true,
@@ -8200,11 +9149,11 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
8200
9149
  });
8201
9150
  });
8202
9151
 
8203
- const logger$f = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
9152
+ const logger$e = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
8204
9153
  const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) => {
8205
9154
  const _loadOrCreateProperty = async () => {
8206
9155
  const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
8207
- logger$f(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
9156
+ logger$e(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
8208
9157
  if (!seedLocalId && !seedUid) {
8209
9158
  throw new Error('seedLocalId or seedUid is required');
8210
9159
  }
@@ -8250,15 +9199,15 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8250
9199
  const schemas = modelPropertiesToObject(model$1.properties);
8251
9200
  propertyRecordSchema = schemas[propertyName];
8252
9201
  if (propertyRecordSchema) {
8253
- logger$f(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9202
+ logger$e(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8254
9203
  }
8255
9204
  }
8256
9205
  }
8257
9206
  catch (error) {
8258
- logger$f(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
9207
+ logger$e(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
8259
9208
  }
8260
9209
  }
8261
- logger$f(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
9210
+ logger$e(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
8262
9211
  sendBack({
8263
9212
  type: 'loadOrCreatePropertySuccess',
8264
9213
  property: {
@@ -8324,7 +9273,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8324
9273
  };
8325
9274
  // Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
8326
9275
  try {
8327
- const { getPropertySchema } = await import('./property-C63Ddzap.js');
9276
+ const { getPropertySchema } = await import('./property-BSNWvgei.js');
8328
9277
  let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
8329
9278
  if (!schemaFromFile?.validation) {
8330
9279
  // Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
@@ -8362,7 +9311,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8362
9311
  }
8363
9312
  }
8364
9313
  catch (error) {
8365
- logger$f(`Error loading propertyRecordSchema from database: ${error}`);
9314
+ logger$e(`Error loading propertyRecordSchema from database: ${error}`);
8366
9315
  // Continue without propertyRecordSchema
8367
9316
  }
8368
9317
  }
@@ -8380,22 +9329,27 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8380
9329
  const schemas = modelPropertiesToObject(model$1.properties);
8381
9330
  propertyRecordSchema = schemas[propertyName];
8382
9331
  if (propertyRecordSchema) {
8383
- logger$f(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
9332
+ logger$e(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
8384
9333
  }
8385
9334
  }
8386
9335
  }
8387
9336
  catch (error) {
8388
- logger$f(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
9337
+ logger$e(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
8389
9338
  }
8390
9339
  }
8391
9340
  // For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
8392
9341
  let renderValue = metadataRecord.propertyValue || undefined;
8393
9342
  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)
9343
+ const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
9344
+ const isHtml = refSeedType === 'html' || normalizedHtmlDt === ModelPropertyDataTypes.Html;
9345
+ // Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
9346
+ // After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
8396
9347
  if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
8397
- metadataRecord.refResolvedValue = `${metadataRecord.propertyValue}.html`;
8398
- metadataRecord.localStorageDir = '/html';
9348
+ const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
9349
+ if (lid) {
9350
+ metadataRecord.refResolvedValue = `${lid}.html`;
9351
+ metadataRecord.localStorageDir = '/html';
9352
+ }
8399
9353
  }
8400
9354
  // Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
8401
9355
  if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
@@ -8405,13 +9359,34 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8405
9359
  try {
8406
9360
  const dir = metadataRecord.localStorageDir.replace(/^\//, '');
8407
9361
  const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
8408
- const exists = await BaseFileManager.pathExists(filePath);
9362
+ let exists = await BaseFileManager.pathExists(filePath);
9363
+ if (!exists) {
9364
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
9365
+ exists = await BaseFileManager.pathExists(filePath);
9366
+ }
8409
9367
  if (exists) {
8410
9368
  renderValue = await BaseFileManager.readFileAsString(filePath);
8411
9369
  }
9370
+ else {
9371
+ const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9372
+ if (viaSeedPointer) {
9373
+ renderValue = viaSeedPointer;
9374
+ }
9375
+ }
8412
9376
  }
8413
9377
  catch (e) {
8414
- logger$f(`Failed to read Html file for ${propertyName}: ${e}`);
9378
+ logger$e(`Failed to read Html file for ${propertyName}: ${e}`);
9379
+ }
9380
+ }
9381
+ // Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
9382
+ if (isHtml && metadataRecord.propertyValue) {
9383
+ const pv = String(metadataRecord.propertyValue).trim();
9384
+ const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
9385
+ if (!rv || rv === pv) {
9386
+ const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
9387
+ if (recovered) {
9388
+ renderValue = recovered;
9389
+ }
8415
9390
  }
8416
9391
  }
8417
9392
  // Image: always resolve display value from file (blob URLs in DB are invalid after reload)
@@ -8421,28 +9396,83 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8421
9396
  const isImage = refSeedType === 'image' ||
8422
9397
  normalizedDataType === 'Image' ||
8423
9398
  normalizedRefValueType === 'Image';
9399
+ const resolveMatchingFilePath = async (dir, needle) => {
9400
+ const dirPath = BaseFileManager.getFilesPath(dir);
9401
+ const dirExists = await BaseFileManager.pathExists(dirPath);
9402
+ if (!dirExists)
9403
+ return undefined;
9404
+ const fs = await BaseFileManager.getFs();
9405
+ const path = BaseFileManager.getPathModule();
9406
+ const files = await fs.promises.readdir(dirPath);
9407
+ const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
9408
+ if (!matchingFiles?.length)
9409
+ return undefined;
9410
+ return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
9411
+ };
9412
+ // EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
9413
+ // hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
9414
+ if (isImage &&
9415
+ !metadataRecord.refResolvedValue &&
9416
+ typeof metadataRecord.propertyValue === 'string' &&
9417
+ metadataRecord.propertyValue.length === 66) {
9418
+ const storageTxRows = await db
9419
+ .select({ propertyValue: metadata$1.propertyValue })
9420
+ .from(metadata$1)
9421
+ .where(and(eq(metadata$1.seedUid, metadataRecord.propertyValue), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))))
9422
+ .limit(1);
9423
+ const derivedTxId = storageTxRows[0]?.propertyValue;
9424
+ if (derivedTxId) {
9425
+ metadataRecord.refResolvedValue = derivedTxId;
9426
+ metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
9427
+ if (metadataRecord.localId) {
9428
+ try {
9429
+ await updateMetadata({
9430
+ localId: metadataRecord.localId,
9431
+ refResolvedValue: derivedTxId,
9432
+ localStorageDir: '/images',
9433
+ });
9434
+ }
9435
+ catch (e) {
9436
+ logger$e(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
9437
+ }
9438
+ }
9439
+ }
9440
+ }
8424
9441
  if (isImage && metadataRecord.refResolvedValue) {
8425
9442
  try {
8426
9443
  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
- }
9444
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9445
+ if (!filePath) {
9446
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9447
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9448
+ }
9449
+ if (filePath) {
9450
+ const file = await BaseFileManager.readFile(filePath);
9451
+ const freshBlobUrl = URL.createObjectURL(file);
9452
+ renderValue = freshBlobUrl;
9453
+ refResolvedDisplayValue = freshBlobUrl;
9454
+ }
9455
+ }
9456
+ catch (e) {
9457
+ logger$e(`Failed to resolve Image file for ${propertyName}: ${e}`);
9458
+ }
9459
+ }
9460
+ const isFile = refSeedType === 'file' ||
9461
+ normalizedDataType === 'File';
9462
+ if (isFile && metadataRecord.refResolvedValue) {
9463
+ try {
9464
+ const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
9465
+ let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9466
+ if (!filePath) {
9467
+ await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
9468
+ filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
9469
+ }
9470
+ if (filePath) {
9471
+ renderValue = await BaseFileManager.readFileAsString(filePath);
8442
9472
  }
8443
9473
  }
8444
9474
  catch (e) {
8445
- logger$f(`Failed to resolve Image file for ${propertyName}: ${e}`);
9475
+ logger$e(`Failed to resolve File for ${propertyName}: ${e}`);
8446
9476
  }
8447
9477
  }
8448
9478
  let propertyValueOut = metadataRecord.propertyValue || undefined;
@@ -8474,7 +9504,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
8474
9504
  });
8475
9505
  };
8476
9506
  _loadOrCreateProperty().catch((error) => {
8477
- logger$f(`Error in loadOrCreateProperty: ${error}`);
9507
+ logger$e(`Error in loadOrCreateProperty: ${error}`);
8478
9508
  sendBack({
8479
9509
  type: 'loadOrCreatePropertyError',
8480
9510
  error: error instanceof Error ? error.message : String(error),
@@ -8504,10 +9534,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
8504
9534
  return queryRows[0];
8505
9535
  };
8506
9536
 
8507
- const logger$e = debug('seedSdk:write:updateItemPropertyValue');
9537
+ const logger$d = debug('seedSdk:write:updateItemPropertyValue');
8508
9538
  const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
8509
9539
  if (!localIdParam && !seedLocalId) {
8510
- logger$e(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
9540
+ logger$d(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
8511
9541
  return;
8512
9542
  }
8513
9543
  let safeNewValue = newValue;
@@ -8535,7 +9565,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8535
9565
  .select()
8536
9566
  .from(metadata$1)
8537
9567
  .where(and(propertyNameWhere, eq(metadata$1.seedLocalId, seedLocalId)))
8538
- .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9568
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8539
9569
  }
8540
9570
  }
8541
9571
  else if (localIdParam) {
@@ -8555,7 +9585,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8555
9585
  .select()
8556
9586
  .from(metadata$1)
8557
9587
  .where(and(propertyNameWhere, eq(metadata$1.seedLocalId, seedLocalId)))
8558
- .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
9588
+ .orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
8559
9589
  }
8560
9590
  // const mostRecentRecordStatement = `SELECT local_id,
8561
9591
  // uid,
@@ -8571,7 +9601,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8571
9601
  // FROM metadata
8572
9602
  // WHERE property_name = '${propertyName}'
8573
9603
  // AND seed_local_id = '${seedLocalId}'
8574
- // ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
9604
+ // ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
8575
9605
  //
8576
9606
  // const { rows } = await runQueryForStatement(mostRecentRecordStatement)
8577
9607
  if (rows && rows.length > 0) {
@@ -8580,7 +9610,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
8580
9610
  modelType === modelName?.toLowerCase() &&
8581
9611
  refSeedTypeFromDb === refSeedType &&
8582
9612
  refResolvedValueFromDb === refResolvedValue) {
8583
- logger$e(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
9613
+ logger$d(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
8584
9614
  return;
8585
9615
  }
8586
9616
  // This means we already have a local-only record so we should just update that one
@@ -8708,9 +9738,9 @@ const analyzeInput = fromCallback(({ sendBack, input: { context, event } }) => {
8708
9738
  }
8709
9739
  const _analyzeInput = async () => {
8710
9740
  // Use dynamic import to break circular dependency
8711
- const schemaMod = await import('./index-Cqf_DxkJ.js');
9741
+ const schemaMod = await import('./index-3Ekqb4QB.js');
8712
9742
  const { ModelPropertyDataTypes } = schemaMod;
8713
- const { SchemaValidationService } = await import('./SchemaValidationService-Cb-b4kpD.js');
9743
+ const { SchemaValidationService } = await import('./SchemaValidationService-C4DIwn8Z.js');
8714
9744
  let propertyName = propertyNameRaw;
8715
9745
  if (!propertyName) {
8716
9746
  throw new Error('propertyName is required');
@@ -8908,7 +9938,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8908
9938
  propertyRecordSchema?.validation &&
8909
9939
  metadataValues.propertyValue != null &&
8910
9940
  metadataValues.propertyValue !== '') {
8911
- const { SchemaValidationService } = await import('./SchemaValidationService-Cb-b4kpD.js');
9941
+ const { SchemaValidationService } = await import('./SchemaValidationService-C4DIwn8Z.js');
8912
9942
  const validationService = new SchemaValidationService();
8913
9943
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
8914
9944
  if (!validationResult.isValid && validationResult.errors.length > 0) {
@@ -8986,8 +10016,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
8986
10016
  return inserted[0];
8987
10017
  };
8988
10018
 
8989
- const eventEmitter = new EventEmitter();
8990
-
8991
10019
  const readFileAsArrayBuffer$1 = async (file) => {
8992
10020
  return new Promise((resolve) => {
8993
10021
  const reader = new FileReader();
@@ -9134,6 +10162,12 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
9134
10162
  }
9135
10163
  const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
9136
10164
  let newLocalId;
10165
+ const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
10166
+ ? schemaUid
10167
+ : (await getEasSchemaForItemProperty({
10168
+ propertyName,
10169
+ easDataType: 'bytes32',
10170
+ }))?.id;
9137
10171
  if (!localId) {
9138
10172
  const result = await createMetadata({
9139
10173
  propertyName,
@@ -9143,7 +10177,7 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
9143
10177
  versionLocalId,
9144
10178
  versionUid,
9145
10179
  modelName,
9146
- schemaUid: imageSchemaUid,
10180
+ schemaUid: resolvedPropertySchemaUid,
9147
10181
  refSeedType: 'image',
9148
10182
  refModelUid: imageSchemaUid,
9149
10183
  refResolvedValue: fileName,
@@ -9162,7 +10196,7 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
9162
10196
  seedLocalId,
9163
10197
  versionLocalId,
9164
10198
  modelName,
9165
- schemaUid,
10199
+ schemaUid: resolvedPropertySchemaUid,
9166
10200
  refSeedType: 'image',
9167
10201
  refResolvedValue: fileName,
9168
10202
  localStorageDir: '/images',
@@ -9495,7 +10529,7 @@ const saveRelation = fromCallback(({ sendBack, input: { context, event } }) => {
9495
10529
  }
9496
10530
  const _saveRelation = async () => {
9497
10531
  // Use dynamic import to break circular dependency
9498
- const schemaMod = await import('./index-Cqf_DxkJ.js');
10532
+ const schemaMod = await import('./index-3Ekqb4QB.js');
9499
10533
  const { ModelPropertyDataTypes } = schemaMod;
9500
10534
  if (!propertyNameRaw) {
9501
10535
  throw new Error('propertyName is required');
@@ -9704,6 +10738,10 @@ const propertyMachine = setup({
9704
10738
  context: {},
9705
10739
  input: {},
9706
10740
  },
10741
+ guards: {
10742
+ // stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
10743
+ propertyMachineIsIdle: stateIn('idle'),
10744
+ },
9707
10745
  // actions: {
9708
10746
  // updateContext: updateMachineContext,
9709
10747
  // },
@@ -9726,7 +10764,11 @@ const propertyMachine = setup({
9726
10764
  initial: 'waitingForDb',
9727
10765
  context: ({ input }) => input,
9728
10766
  on: {
9729
- // reload: '.hydratingFromDb',
10767
+ /** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
10768
+ rehydrateFromDb: {
10769
+ guard: 'propertyMachineIsIdle',
10770
+ target: '.hydratingFromDb',
10771
+ },
9730
10772
  save: {
9731
10773
  actions: assign({
9732
10774
  isSaving: true,
@@ -10325,6 +11367,8 @@ function createReactiveProxy(config) {
10325
11367
  return proxy;
10326
11368
  }
10327
11369
 
11370
+ /** Parent Html property `propertyValue` after publish (66-char seed uid). */
11371
+ const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
10328
11372
  // Start loading Model at module load time (non-blocking)
10329
11373
  Promise.resolve().then(function () { return Model$1; }).then(module => {
10330
11374
  module.Model;
@@ -10424,7 +11468,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
10424
11468
  };
10425
11469
  /** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
10426
11470
  const modelTypeToModelName = (modelType) => modelType ? upperFirst(camelCase(modelType)) : '';
10427
- const logger$d = debug('seedSdk:property:class');
11471
+ const logger$c = debug('seedSdk:property:class');
10428
11472
  // Define tracked properties for the Proxy
10429
11473
  // These properties will be read from/written to the actor context
10430
11474
  const TRACKED_PROPERTIES$2 = [
@@ -10506,7 +11550,7 @@ class ItemProperty {
10506
11550
  serviceInput.propertyValue = JSON.parse(propertyValue);
10507
11551
  }
10508
11552
  catch (e) {
10509
- logger$d('List property value is not JSON', e);
11553
+ logger$c('List property value is not JSON', e);
10510
11554
  }
10511
11555
  }
10512
11556
  }
@@ -10529,7 +11573,7 @@ class ItemProperty {
10529
11573
  return;
10530
11574
  }
10531
11575
  // Use dynamic import to break circular dependency
10532
- const schemaMod = await import('./index-Cqf_DxkJ.js');
11576
+ const schemaMod = await import('./index-3Ekqb4QB.js');
10533
11577
  const { ModelPropertyDataTypes } = schemaMod;
10534
11578
  const { context } = snapshot;
10535
11579
  const { propertyRecordSchema } = context;
@@ -10552,7 +11596,8 @@ class ItemProperty {
10552
11596
  propertyRecordSchema.storageType === 'ItemStorage' &&
10553
11597
  context.refResolvedValue &&
10554
11598
  context.localStorageDir;
10555
- const isHtml = (context.refSeedType === 'html' || (propertyRecordSchema?.dataType === ModelPropertyDataTypes.Html)) &&
11599
+ const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
11600
+ const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
10556
11601
  context.refResolvedValue;
10557
11602
  // Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
10558
11603
  // so the UI can display the filename and preview immediately (these update again when save completes)
@@ -10588,7 +11633,11 @@ class ItemProperty {
10588
11633
  const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
10589
11634
  const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
10590
11635
  try {
10591
- const exists = await BaseFileManager.pathExists(filePath);
11636
+ let exists = await BaseFileManager.pathExists(filePath);
11637
+ if (!exists && isHtml) {
11638
+ await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
11639
+ exists = await BaseFileManager.pathExists(filePath);
11640
+ }
10592
11641
  if (exists && (isItemStorage || isHtml)) {
10593
11642
  renderValue = await BaseFileManager.readFileAsString(filePath);
10594
11643
  }
@@ -10608,8 +11657,8 @@ class ItemProperty {
10608
11657
  if (isFile && isFileValue) {
10609
11658
  renderValue = pv.name;
10610
11659
  }
10611
- else if (isImage) {
10612
- // FS race / path not visible yet: do not clobber a hydrated blob URL with "No file found"
11660
+ else if (isImage || isHtml) {
11661
+ // FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
10613
11662
  renderValue = undefined;
10614
11663
  }
10615
11664
  else {
@@ -10618,13 +11667,21 @@ class ItemProperty {
10618
11667
  }
10619
11668
  }
10620
11669
  catch (e) {
10621
- logger$d(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
10622
- renderValue = 'No file found';
11670
+ logger$c(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
11671
+ renderValue = isHtml ? undefined : 'No file found';
10623
11672
  }
10624
11673
  }
10625
11674
  if (!renderValue) {
10626
11675
  renderValue = context.renderValue || context.propertyValue;
10627
11676
  }
11677
+ const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
11678
+ if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
11679
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
11680
+ renderValue === pvStr &&
11681
+ typeof context.renderValue === 'string' &&
11682
+ context.renderValue.length > pvStr.length) {
11683
+ renderValue = context.renderValue;
11684
+ }
10628
11685
  let transformedPropertyName = propertyName;
10629
11686
  const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
10630
11687
  if (!skipTransform && transformedPropertyName.endsWith('Id')) {
@@ -10687,7 +11744,7 @@ class ItemProperty {
10687
11744
  const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
10688
11745
  const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
10689
11746
  const propertyNameVariant = propertyNames.length > 1 ? propertyNames[1] : undefined;
10690
- const _mod_6 = await import('./index-DdzhrbkF.js');
11747
+ const _mod_6 = await import('./index-BRo7D3s1.js');
10691
11748
  const _ns_6 = _mod_6.s;
10692
11749
  const seedSchemaMod = _ns_6;
10693
11750
  const { metadata } = seedSchemaMod;
@@ -11039,6 +12096,35 @@ class ItemProperty {
11039
12096
  instance._service.send({ type: 'updateContext', ...updates });
11040
12097
  }
11041
12098
  }
12099
+ // After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
12100
+ // paths would hydrate. Re-run DB hydration without clobbering propertyValue.
12101
+ const svc = instance._service;
12102
+ const snap = svc.getSnapshot();
12103
+ if (snap.status === 'active' && snap.value === 'idle') {
12104
+ const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
12105
+ const dt = normalizeDataType(schema?.dataType);
12106
+ const isHtmlProp = props.refSeedType === 'html' ||
12107
+ ctx.refSeedType === 'html' ||
12108
+ dt === ModelPropertyDataTypes.Html;
12109
+ const isListProp = dt === ModelPropertyDataTypes.List;
12110
+ const isRelationProp = dt === ModelPropertyDataTypes.Relation;
12111
+ const pv = ctx.propertyValue;
12112
+ const pvStr = typeof pv === 'string' ? pv.trim() : '';
12113
+ const renderVal = ctx.renderValue;
12114
+ const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
12115
+ const htmlStuckOnUid = isHtmlProp &&
12116
+ HTML_PROP_SEED_UID_RE.test(pvStr) &&
12117
+ (renderMissing || renderVal === pv);
12118
+ const pvPresent = pv != null &&
12119
+ (Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
12120
+ const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
12121
+ const versionChanged = props.versionLocalId != null &&
12122
+ ctx.versionLocalId != null &&
12123
+ props.versionLocalId !== ctx.versionLocalId;
12124
+ if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
12125
+ svc.send({ type: 'rehydrateFromDb' });
12126
+ }
12127
+ }
11042
12128
  // On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
11043
12129
  if (!waitForReady)
11044
12130
  return instance;
@@ -11388,7 +12474,7 @@ class ItemProperty {
11388
12474
  }
11389
12475
  async save() {
11390
12476
  const ctx = this._getSnapshotContext();
11391
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12477
+ const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
11392
12478
  await assertItemOwned({
11393
12479
  seedLocalId: ctx?.seedLocalId ?? undefined,
11394
12480
  seedUid: ctx?.seedUid ?? undefined,
@@ -11481,7 +12567,7 @@ class ItemProperty {
11481
12567
  if (!propertyName || (!seedLocalId && !seedUid))
11482
12568
  return;
11483
12569
  if (db) {
11484
- const _mod_7 = await import('./index-DdzhrbkF.js');
12570
+ const _mod_7 = await import('./index-BRo7D3s1.js');
11485
12571
  const _ns_7 = _mod_7.s;
11486
12572
  const seedSchemaMod = _ns_7;
11487
12573
  const { metadata } = seedSchemaMod;
@@ -11729,7 +12815,7 @@ class Item {
11729
12815
  });
11730
12816
  };
11731
12817
  this.unpublish = async () => {
11732
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12818
+ const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
11733
12819
  const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
11734
12820
  await assertItemOwned(this);
11735
12821
  const seedUid = this.seedUid;
@@ -11753,7 +12839,7 @@ class Item {
11753
12839
  this._service.send({ type: 'updateContext', revokedAt });
11754
12840
  };
11755
12841
  this.publish = async () => {
11756
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
12842
+ const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
11757
12843
  await assertItemOwned(this);
11758
12844
  this._service.send({ type: 'startPublish' });
11759
12845
  return new Promise((resolve, reject) => {
@@ -11789,12 +12875,12 @@ class Item {
11789
12875
  };
11790
12876
  this.getPublishUploads = async (options) => {
11791
12877
  // Use dynamic import to break circular dependency
11792
- const getPublishUploadsMod = await import('./getPublishUploads-DS2dQ4Ho.js');
12878
+ const getPublishUploadsMod = await import('./getPublishUploads-Cf2J-5FR.js');
11793
12879
  const { getPublishUploads } = getPublishUploadsMod;
11794
12880
  return await getPublishUploads(this, [], undefined, options);
11795
12881
  };
11796
12882
  this.getPublishPayload = async (uploadedTransactions, options) => {
11797
- const getPublishPayloadMod = await import('./getPublishPayload-DpYwi-rd.js');
12883
+ const getPublishPayloadMod = await import('./getPublishPayload-Ddc_LGPs.js');
11798
12884
  const { getPublishPayload } = getPublishPayloadMod;
11799
12885
  return await getPublishPayload(this, uploadedTransactions, options);
11800
12886
  };
@@ -11911,6 +12997,8 @@ class Item {
11911
12997
  'schemaUid',
11912
12998
  'latestVersionLocalId',
11913
12999
  'latestVersionUid',
13000
+ 'publishedVersionUid',
13001
+ 'publishedVersionLocalId',
11914
13002
  ];
11915
13003
  const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
11916
13004
  const schemaNameForModel = initialValues.schemaName;
@@ -11954,6 +13042,128 @@ class Item {
11954
13042
  });
11955
13043
  }
11956
13044
  }
13045
+ /** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
13046
+ static findItemInstanceCacheEntryByProps(props) {
13047
+ const l = props.seedLocalId;
13048
+ const u = props.seedUid;
13049
+ if (typeof l === 'string' && l.length > 0) {
13050
+ const e = this.instanceCache.get(l);
13051
+ if (e)
13052
+ return e;
13053
+ }
13054
+ if (typeof u === 'string' && u.length > 0) {
13055
+ const e = this.instanceCache.get(u);
13056
+ if (e)
13057
+ return e;
13058
+ }
13059
+ return undefined;
13060
+ }
13061
+ static findItemInstanceCacheEntryById(id) {
13062
+ const direct = this.instanceCache.get(id);
13063
+ if (direct)
13064
+ return direct;
13065
+ for (const [, entry] of this.instanceCache) {
13066
+ const ctx = entry.instance._getSnapshotContext();
13067
+ if (ctx.seedLocalId === id || ctx.seedUid === id)
13068
+ return entry;
13069
+ }
13070
+ return undefined;
13071
+ }
13072
+ static collectInstanceCacheKeysForInstance(instance) {
13073
+ const keys = [];
13074
+ for (const [k, v] of this.instanceCache) {
13075
+ if (v.instance === instance)
13076
+ keys.push(k);
13077
+ }
13078
+ return keys;
13079
+ }
13080
+ static registerItemInInstanceCache(instance) {
13081
+ const ctx = instance._getSnapshotContext();
13082
+ const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
13083
+ ? ctx.seedLocalId
13084
+ : undefined;
13085
+ const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
13086
+ const entry = { instance, refCount: 1 };
13087
+ if (lid)
13088
+ this.instanceCache.set(lid, entry);
13089
+ if (uid && uid !== lid)
13090
+ this.instanceCache.set(uid, entry);
13091
+ if (!lid && !uid) {
13092
+ throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
13093
+ }
13094
+ }
13095
+ static releaseItemInstanceCacheHold(instance) {
13096
+ const keys = this.collectInstanceCacheKeysForInstance(instance);
13097
+ if (keys.length === 0)
13098
+ return;
13099
+ const entry = this.instanceCache.get(keys[0]);
13100
+ entry.refCount -= 1;
13101
+ if (entry.refCount <= 0) {
13102
+ for (const k of keys) {
13103
+ this.instanceCache.delete(k);
13104
+ }
13105
+ }
13106
+ }
13107
+ /**
13108
+ * Item machine can reach `idle` before `propertyInstances` is merged (race) or while
13109
+ * child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
13110
+ */
13111
+ static async waitForItemInstanceReadyForRead(item, readyTimeout) {
13112
+ await waitForEntityIdle(item, { timeout: readyTimeout });
13113
+ const svc = item.getService();
13114
+ try {
13115
+ await waitFor(svc, (snap) => {
13116
+ if ('value' in snap && snap.value === 'error') {
13117
+ throw new Error('Entity failed to load');
13118
+ }
13119
+ if (!('value' in snap) || snap.value !== 'idle') {
13120
+ return false;
13121
+ }
13122
+ const ctx = snap.context || {};
13123
+ const versionsCount = ctx.versionsCount ?? 0;
13124
+ const hasHeadVersion = !!ctx.latestVersionLocalId;
13125
+ if (versionsCount === 0 && !hasHeadVersion) {
13126
+ return true;
13127
+ }
13128
+ return (ctx.propertyInstances?.size ?? 0) > 0;
13129
+ }, { timeout: readyTimeout });
13130
+ }
13131
+ catch (e) {
13132
+ if (e?.message === 'Entity failed to load') {
13133
+ throw e;
13134
+ }
13135
+ const msg = typeof e?.message === 'string' ? e.message : '';
13136
+ const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
13137
+ if (!isWaitForTimeout) {
13138
+ throw e;
13139
+ }
13140
+ }
13141
+ const snap = svc.getSnapshot();
13142
+ const pis = snap.context?.propertyInstances;
13143
+ if (!pis || pis.size === 0) {
13144
+ return;
13145
+ }
13146
+ await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
13147
+ timeout: readyTimeout,
13148
+ throwOnError: false,
13149
+ })));
13150
+ }
13151
+ static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
13152
+ const snap = instance.getService().getSnapshot();
13153
+ if (snap.value !== 'idle')
13154
+ return false;
13155
+ const mapSize = snap.context.propertyInstances?.size ?? 0;
13156
+ if (mapSize > 0)
13157
+ return false;
13158
+ const ctx = snap.context;
13159
+ const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
13160
+ const hasVersionHead = versionsCount > 0 ||
13161
+ !!props.latestVersionLocalId ||
13162
+ !!ctx.latestVersionLocalId ||
13163
+ !!props.latestVersionUid ||
13164
+ !!ctx.latestVersionUid;
13165
+ return hasVersionHead;
13166
+ }
11957
13167
  static async create(props, options) {
11958
13168
  const waitForReady = options?.waitForReady !== false;
11959
13169
  const readyTimeout = options?.readyTimeout ?? 5000;
@@ -11961,45 +13171,66 @@ class Item {
11961
13171
  props.modelName = startCase(props.type);
11962
13172
  }
11963
13173
  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;
13174
+ cacheReuse: {
13175
+ const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
13176
+ if (cachedEntry) {
13177
+ const instance = cachedEntry.instance;
13178
+ cachedEntry.refCount += 1;
13179
+ for (const [propertyName, propertyValue] of Object.entries(props)) {
13180
+ const snapshot = instance.getService().getSnapshot();
13181
+ const propertyInstances = snapshot.context.propertyInstances;
13182
+ if (!propertyInstances || !propertyInstances.has(propertyName)) {
13183
+ continue;
13184
+ }
13185
+ const propertyInstance = propertyInstances.get(propertyName);
13186
+ if (!propertyInstance) {
13187
+ continue;
13188
+ }
13189
+ propertyInstance.getService().send({
13190
+ type: 'updateContext',
13191
+ propertyValue,
13192
+ });
11980
13193
  }
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) {
13194
+ if (!waitForReady)
13195
+ return instance;
11992
13196
  try {
11993
- instance.unload();
13197
+ await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
11994
13198
  }
11995
- catch {
11996
- /* best-effort cache cleanup */
13199
+ catch (err) {
13200
+ try {
13201
+ instance.unload();
13202
+ }
13203
+ catch {
13204
+ /* best-effort cache cleanup */
13205
+ }
13206
+ throw err;
11997
13207
  }
11998
- throw err;
13208
+ if (waitForReady &&
13209
+ this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
13210
+ forceRemoveFromCaches(instance, {
13211
+ getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
13212
+ caches: [Item.instanceCache],
13213
+ });
13214
+ try {
13215
+ unloadEntity(instance, {
13216
+ getCacheKeys: () => [],
13217
+ caches: [],
13218
+ instanceState: itemInstanceState,
13219
+ getService: (inst) => inst._service,
13220
+ onUnload: (inst) => {
13221
+ inst._subscription?.unsubscribe();
13222
+ },
13223
+ });
13224
+ }
13225
+ catch {
13226
+ /* best-effort teardown for stale cached shell */
13227
+ }
13228
+ break cacheReuse;
13229
+ }
13230
+ return instance;
11999
13231
  }
12000
- return instance;
12001
13232
  }
12002
- if (!this.instanceCache.has(seedId)) {
13233
+ if (!this.findItemInstanceCacheEntryByProps(props)) {
12003
13234
  // Item no longer needs modelInstance - it loads properties from database independently
12004
13235
  // Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
12005
13236
  const { latestVersionUid, ...propsWithoutVersionUid } = props;
@@ -12088,14 +13319,11 @@ class Item {
12088
13319
  return Reflect.getOwnPropertyDescriptor(target, prop);
12089
13320
  },
12090
13321
  });
12091
- this.instanceCache.set(seedId, {
12092
- instance: proxiedInstance,
12093
- refCount: 1,
12094
- });
13322
+ this.registerItemInInstanceCache(proxiedInstance);
12095
13323
  if (!waitForReady)
12096
13324
  return proxiedInstance;
12097
13325
  try {
12098
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13326
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12099
13327
  }
12100
13328
  catch (err) {
12101
13329
  try {
@@ -12271,14 +13499,11 @@ class Item {
12271
13499
  return Reflect.getOwnPropertyDescriptor(target, prop);
12272
13500
  },
12273
13501
  });
12274
- this.instanceCache.set((proxiedInstance.seedUid || proxiedInstance.seedLocalId), {
12275
- instance: proxiedInstance,
12276
- refCount: 1,
12277
- });
13502
+ this.registerItemInInstanceCache(proxiedInstance);
12278
13503
  if (!waitForReady)
12279
13504
  return proxiedInstance;
12280
13505
  try {
12281
- await waitForEntityIdle(proxiedInstance, { timeout: readyTimeout });
13506
+ await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
12282
13507
  }
12283
13508
  catch (err) {
12284
13509
  try {
@@ -12301,14 +13526,10 @@ class Item {
12301
13526
  if (!id) {
12302
13527
  return null;
12303
13528
  }
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;
13529
+ const entry = this.findItemInstanceCacheEntryById(id);
13530
+ if (entry) {
13531
+ entry.refCount += 1;
13532
+ return entry.instance;
12312
13533
  }
12313
13534
  return null;
12314
13535
  }
@@ -12354,8 +13575,8 @@ class Item {
12354
13575
  if (!seedLocalId && !seedUid) {
12355
13576
  return undefined;
12356
13577
  }
12357
- // Use seedUid as primary ID if available, otherwise use seedLocalId
12358
- const id = seedUid || seedLocalId;
13578
+ // Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
13579
+ const id = seedLocalId || seedUid;
12359
13580
  if (!id) {
12360
13581
  return undefined;
12361
13582
  }
@@ -12386,10 +13607,129 @@ class Item {
12386
13607
  }));
12387
13608
  }
12388
13609
  if (waitForReady && itemInstances.length > 0) {
12389
- await Promise.all(itemInstances.map((item) => waitForEntityIdle(item, { timeout: readyTimeout })));
13610
+ await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
12390
13611
  }
12391
13612
  return orderBy(itemInstances, ['createdAt'], ['desc']);
12392
13613
  }
13614
+ /**
13615
+ * After EAS sync writes metadata for the latest version, merge new property instances and
13616
+ * re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
13617
+ * and useItems may not invalidate when the seed set is unchanged.
13618
+ */
13619
+ static async rehydrateCachedItemsFromDbAfterEasSync() {
13620
+ const appDb = BaseDb.getAppDb();
13621
+ if (!appDb || Item.instanceCache.size === 0) {
13622
+ return;
13623
+ }
13624
+ const _mod_8 = await import('./index-BRo7D3s1.js');
13625
+ const _ns_8 = _mod_8.s;
13626
+ const { metadata } = _ns_8;
13627
+ const { eq, and } = await import('drizzle-orm');
13628
+ const dedupedInstances = new Map();
13629
+ for (const entry of Item.instanceCache.values()) {
13630
+ dedupedInstances.set(entry.instance, entry);
13631
+ }
13632
+ const entries = [...dedupedInstances.values()];
13633
+ await Promise.all(entries.map(async ({ instance }) => {
13634
+ try {
13635
+ const svc = instance.getService();
13636
+ if (svc.getSnapshot().status !== 'active') {
13637
+ return;
13638
+ }
13639
+ const ctx = svc.getSnapshot().context;
13640
+ const seedLocalId = ctx.seedLocalId;
13641
+ const seedUid = ctx.seedUid;
13642
+ const versionLocalId = ctx.latestVersionLocalId;
13643
+ const itemModelName = ctx.modelName;
13644
+ const schemaNameForModel = ctx.schemaName;
13645
+ if (!seedLocalId || !versionLocalId || !itemModelName) {
13646
+ return;
13647
+ }
13648
+ const metadataRows = await appDb
13649
+ .select()
13650
+ .from(metadata)
13651
+ .where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
13652
+ let propertySchemas = {};
13653
+ try {
13654
+ const M = getModel();
13655
+ const model = schemaNameForModel !== undefined
13656
+ ? M?.getByName(itemModelName, schemaNameForModel)
13657
+ : M?.getByName(itemModelName);
13658
+ if (model?.properties?.length) {
13659
+ propertySchemas = modelPropertiesToObject(model.properties);
13660
+ }
13661
+ }
13662
+ catch {
13663
+ /* Model optional */
13664
+ }
13665
+ const sendToItemMachine = (event) => {
13666
+ if (svc.getSnapshot().status !== 'active') {
13667
+ return;
13668
+ }
13669
+ svc.send(event);
13670
+ };
13671
+ for (const metaRow of metadataRows) {
13672
+ try {
13673
+ let propertyName = metaRow.propertyName;
13674
+ const listSchemaKey = propertyName &&
13675
+ Object.keys(propertySchemas).length > 0 &&
13676
+ resolveStorageNameToSchemaName(propertySchemas, propertyName);
13677
+ if (listSchemaKey) {
13678
+ propertyName = listSchemaKey;
13679
+ }
13680
+ else {
13681
+ const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
13682
+ const refSeedType = metaRow.refSeedType;
13683
+ const isRefTypeFromMeta = refSeedType === 'file' ||
13684
+ refSeedType === 'image' ||
13685
+ refSeedType === 'relation' ||
13686
+ refSeedType === 'html';
13687
+ if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
13688
+ propertyName = baseName;
13689
+ }
13690
+ }
13691
+ if (!propertyName) {
13692
+ continue;
13693
+ }
13694
+ const property = await ItemProperty.find({
13695
+ propertyName,
13696
+ seedLocalId,
13697
+ seedUid,
13698
+ modelName: itemModelName,
13699
+ });
13700
+ if (property) {
13701
+ sendToItemMachine({
13702
+ type: 'addPropertyInstance',
13703
+ propertyName,
13704
+ propertyInstance: property,
13705
+ });
13706
+ }
13707
+ }
13708
+ catch {
13709
+ /* row skipped */
13710
+ }
13711
+ }
13712
+ const instances = svc.getSnapshot().context.propertyInstances;
13713
+ if (!instances) {
13714
+ return;
13715
+ }
13716
+ for (const propertyInstance of instances.values()) {
13717
+ try {
13718
+ const propertySnap = propertyInstance.getService().getSnapshot();
13719
+ if (isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
13720
+ propertyInstance.getService().send({ type: 'rehydrateFromDb' });
13721
+ }
13722
+ }
13723
+ catch {
13724
+ /* best-effort */
13725
+ }
13726
+ }
13727
+ }
13728
+ catch (e) {
13729
+ itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
13730
+ }
13731
+ }));
13732
+ }
12393
13733
  _createPropertyInstance(props) {
12394
13734
  if (this._storageTransactionId) {
12395
13735
  props.storageTransactionId = this._storageTransactionId;
@@ -12732,9 +14072,9 @@ class Item {
12732
14072
  itemActor.send(event);
12733
14073
  };
12734
14074
  try {
12735
- const _mod_8 = await import('./index-DdzhrbkF.js');
12736
- const _ns_8 = _mod_8.s;
12737
- const seedSchemaMod = _ns_8;
14075
+ const _mod_9 = await import('./index-BRo7D3s1.js');
14076
+ const _ns_9 = _mod_9.s;
14077
+ const seedSchemaMod = _ns_9;
12738
14078
  const { seeds, versions, metadata } = seedSchemaMod;
12739
14079
  const drizzleMod = await import('drizzle-orm');
12740
14080
  const { eq, and } = drizzleMod;
@@ -13006,15 +14346,10 @@ class Item {
13006
14346
  }
13007
14347
  unload() {
13008
14348
  try {
13009
- const context = this._getSnapshotContext();
13010
- const cacheKey = context.seedUid || context.seedLocalId;
13011
- const cacheKeys = [];
13012
- if (cacheKey) {
13013
- cacheKeys.push(cacheKey);
13014
- }
14349
+ Item.releaseItemInstanceCacheHold(this);
13015
14350
  unloadEntity(this, {
13016
- getCacheKeys: () => cacheKeys,
13017
- caches: [Item.instanceCache],
14351
+ getCacheKeys: () => [],
14352
+ caches: [],
13018
14353
  instanceState: itemInstanceState,
13019
14354
  getService: (instance) => instance._service,
13020
14355
  onUnload: (instance) => {
@@ -13043,11 +14378,10 @@ class Item {
13043
14378
  * Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
13044
14379
  */
13045
14380
  async destroy() {
13046
- const { assertItemOwned } = await import('./ownership-BK6suksO.js');
14381
+ const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
13047
14382
  await assertItemOwned(this);
13048
14383
  const context = this._getSnapshotContext();
13049
- const cacheKey = context.seedUid || context.seedLocalId;
13050
- const cacheKeys = cacheKey ? [cacheKey] : [];
14384
+ const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
13051
14385
  clearDestroySubscriptions(this, {
13052
14386
  instanceState: itemInstanceState,
13053
14387
  onUnload: (instance) => instance._subscription?.unsubscribe(),
@@ -13104,600 +14438,331 @@ function normalizeAddressConfig(addresses) {
13104
14438
  };
13105
14439
  }
13106
14440
 
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,
14441
+ let writeTail = Promise.resolve();
14442
+ function enqueueEasSyncDbWrite(fn) {
14443
+ const next = writeTail.then(fn);
14444
+ writeTail = next.catch(() => { });
14445
+ return next;
14446
+ }
14447
+ const MAX_ERROR_MESSAGE_LENGTH = 500;
14448
+ const MAX_ERROR_DETAILS_LENGTH = 2000;
14449
+ async function insertEasSyncProcessRow(params) {
14450
+ return enqueueEasSyncDbWrite(async () => {
14451
+ const db = BaseDb.getAppDb();
14452
+ if (!db) {
14453
+ throw new Error('[easSyncProcess] App DB not available');
14454
+ }
14455
+ const now = Date.now();
14456
+ const [row] = await db
14457
+ .insert(easSyncProcesses)
14458
+ .values({
14459
+ status: 'in_progress',
14460
+ startedAt: now,
14461
+ requestPayload: JSON.stringify(params.requestPayload),
14462
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14463
+ createdAt: now,
14464
+ updatedAt: now,
13126
14465
  })
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);
14466
+ .returning({ id: easSyncProcesses.id });
14467
+ return row.id;
14468
+ });
14469
+ }
14470
+ async function finalizeEasSyncProcessRow(id, params) {
14471
+ return enqueueEasSyncDbWrite(async () => {
14472
+ const db = BaseDb.getAppDb();
14473
+ if (!db) {
14474
+ return;
13163
14475
  }
13164
- return acc;
13165
- }, []);
13166
- return newUids;
13167
- };
14476
+ const now = Date.now();
14477
+ await db
14478
+ .update(easSyncProcesses)
14479
+ .set({
14480
+ status: params.status,
14481
+ completedAt: now,
14482
+ updatedAt: now,
14483
+ errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
14484
+ errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
14485
+ persistedSnapshot: JSON.stringify(params.persistedSnapshot),
14486
+ })
14487
+ .where(eq(easSyncProcesses.id, id));
14488
+ });
14489
+ }
13168
14490
 
13169
14491
  /**
13170
- * Sets revokedAt timestamp on a seed record after attestations have been revoked on EAS.
14492
+ * Merge multiple EAS sync intents: full sync (no concrete address list) wins;
14493
+ * otherwise union addresses (first-seen casing).
13171
14494
  */
13172
- const updateSeedRevokedAt = async ({ seedLocalId, revokedAt, }) => {
13173
- if (!seedLocalId) {
13174
- return;
14495
+ function mergeEasSyncRequestIntents(parts) {
14496
+ const norm = parts.filter((p) => p != null);
14497
+ if (norm.length === 0) {
14498
+ return {};
13175
14499
  }
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
- }
14500
+ let full = false;
14501
+ const addressMap = new Map();
14502
+ for (const p of norm) {
14503
+ if (!('addresses' in p) || p.addresses === undefined) {
14504
+ full = true;
14505
+ break;
14506
+ }
14507
+ for (const addr of p.addresses) {
14508
+ const k = addr.toLowerCase();
14509
+ if (!addressMap.has(k)) {
14510
+ addressMap.set(k, addr);
13213
14511
  }
13214
14512
  }
13215
14513
  }
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);
14514
+ if (full) {
14515
+ return {};
13259
14516
  }
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;
14517
+ if (addressMap.size === 0) {
14518
+ return { addresses: [] };
13319
14519
  }
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;
14520
+ return { addresses: [...addressMap.values()] };
14521
+ }
14522
+
14523
+ const log = debug('seedSdk:events:easSyncManager');
14524
+ function toRunSyncArg(options) {
14525
+ if (options &&
14526
+ 'addresses' in options &&
14527
+ options.addresses !== undefined) {
14528
+ return options;
13324
14529
  }
13325
- let parsedData;
14530
+ return undefined;
14531
+ }
14532
+ const runEasSync = fromPromise(async ({ input, }) => {
14533
+ const rowId = await insertEasSyncProcessRow({
14534
+ requestPayload: input.requestPayload,
14535
+ persistedSnapshot: input.runningSnapshot,
14536
+ });
14537
+ const { runSyncFromEas } = await import('./syncDbWithEas-CaytdS8D.js');
13326
14538
  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(),
14539
+ await runSyncFromEas(toRunSyncArg(input.options));
14540
+ await finalizeEasSyncProcessRow(rowId, {
14541
+ status: 'completed',
14542
+ persistedSnapshot: {
14543
+ phase: 'completed',
14544
+ correlationIds: input.requestPayload.correlationIds,
14545
+ },
13382
14546
  });
13383
14547
  }
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,
14548
+ catch (err) {
14549
+ const message = err instanceof Error ? err.message : String(err);
14550
+ const details = err instanceof Error && err.stack
14551
+ ? err.stack.slice(0, 2000)
14552
+ : undefined;
14553
+ await finalizeEasSyncProcessRow(rowId, {
14554
+ status: 'failed',
14555
+ errorMessage: message,
14556
+ errorDetails: details,
14557
+ persistedSnapshot: {
14558
+ phase: 'failed',
14559
+ correlationIds: input.requestPayload.correlationIds,
14560
+ },
13459
14561
  });
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 };
14562
+ throw err;
14563
+ }
14564
+ });
14565
+ const initialContext = {
14566
+ runOptions: {},
14567
+ activeCorrelationIds: [],
14568
+ activePrimarySource: 'event_bus',
14569
+ pendingMergedOptions: undefined,
14570
+ pendingCorrelationIds: [],
14571
+ pendingPrimarySource: null,
14572
+ lastFinishedCorrelationIds: null,
14573
+ lastFinishedStatus: null,
14574
+ lastFinishedError: null,
13551
14575
  };
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),
14576
+ const easSyncMachine = setup({
14577
+ types: {
14578
+ context: {},
14579
+ events: {},
14580
+ },
14581
+ actors: {
14582
+ runEasSync,
14583
+ },
14584
+ }).createMachine({
14585
+ id: MachineIds.EAS_SYNC_MANAGER,
14586
+ initial: 'idle',
14587
+ context: initialContext,
14588
+ states: {
14589
+ idle: {
14590
+ on: {
14591
+ REQUEST: {
14592
+ target: 'running',
14593
+ actions: assign({
14594
+ runOptions: ({ event }) => event.options === undefined
14595
+ ? {}
14596
+ : mergeEasSyncRequestIntents([event.options]),
14597
+ activeCorrelationIds: ({ event }) => [event.correlationId],
14598
+ activePrimarySource: ({ event }) => event.source,
14599
+ }),
14600
+ },
14601
+ },
14602
+ },
14603
+ running: {
14604
+ on: {
14605
+ REQUEST: {
14606
+ actions: assign({
14607
+ pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
14608
+ context.runOptions,
14609
+ context.pendingMergedOptions,
14610
+ event.options === undefined ? {} : event.options,
14611
+ ].filter((x) => x != null)),
14612
+ pendingCorrelationIds: ({ context, event }) => [
14613
+ ...context.pendingCorrelationIds,
14614
+ event.correlationId,
14615
+ ],
14616
+ pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
14617
+ }),
14618
+ },
13559
14619
  },
13560
- },
13561
- });
13562
- await saveEasSeedsToDb({ itemSeeds });
13563
- const { itemVersions } = await easClient.request(GET_VERSIONS, {
13564
- where: {
13565
- refUID: {
13566
- in: Array.from(relatedSeedUids),
14620
+ invoke: {
14621
+ src: 'runEasSync',
14622
+ input: ({ context }) => ({
14623
+ options: context.runOptions,
14624
+ requestPayload: {
14625
+ source: context.activePrimarySource,
14626
+ correlationIds: context.activeCorrelationIds,
14627
+ options: context.runOptions,
14628
+ },
14629
+ runningSnapshot: {
14630
+ phase: 'running',
14631
+ correlationIds: context.activeCorrelationIds,
14632
+ },
14633
+ }),
14634
+ onDone: {
14635
+ target: 'afterRun',
14636
+ actions: assign({
14637
+ lastFinishedCorrelationIds: ({ context }) => [
14638
+ ...context.activeCorrelationIds,
14639
+ ],
14640
+ lastFinishedStatus: () => 'success',
14641
+ lastFinishedError: () => null,
14642
+ activeCorrelationIds: () => [],
14643
+ runOptions: () => ({}),
14644
+ }),
14645
+ },
14646
+ onError: {
14647
+ target: 'afterRun',
14648
+ actions: [
14649
+ assign({
14650
+ lastFinishedCorrelationIds: ({ context }) => [
14651
+ ...context.activeCorrelationIds,
14652
+ ],
14653
+ lastFinishedStatus: () => 'failed',
14654
+ lastFinishedError: ({ event }) => {
14655
+ const e = event.error;
14656
+ if (e instanceof Error) {
14657
+ return e.message;
14658
+ }
14659
+ return e != null ? String(e) : 'EAS sync failed';
14660
+ },
14661
+ activeCorrelationIds: () => [],
14662
+ runOptions: () => ({}),
14663
+ }),
14664
+ ({ event }) => {
14665
+ log('runEasSync error', event.error);
14666
+ },
14667
+ ],
14668
+ },
13567
14669
  },
13568
14670
  },
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
- },
14671
+ afterRun: {
14672
+ always: [
14673
+ {
14674
+ guard: ({ context }) => context.pendingCorrelationIds.length > 0,
14675
+ target: 'running',
14676
+ actions: assign({
14677
+ runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
14678
+ activeCorrelationIds: ({ context }) => [
14679
+ ...context.pendingCorrelationIds,
14680
+ ],
14681
+ activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
14682
+ pendingMergedOptions: () => undefined,
14683
+ pendingCorrelationIds: () => [],
14684
+ pendingPrimarySource: () => null,
14685
+ }),
14686
+ },
14687
+ { target: 'idle' },
14688
+ ],
13577
14689
  },
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) {
14690
+ },
14691
+ });
14692
+ const easSyncActor = createActor(easSyncMachine);
14693
+ let easSyncActorStarted = false;
14694
+ function startEasSyncActor() {
14695
+ if (easSyncActorStarted) {
13605
14696
  return;
13606
14697
  }
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;
14698
+ easSyncActorStarted = true;
14699
+ easSyncActor.start();
14700
+ }
14701
+ function newCorrelationId() {
14702
+ const c = globalThis.crypto;
14703
+ if (c?.randomUUID) {
14704
+ return c.randomUUID();
13643
14705
  }
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,
14706
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
14707
+ }
14708
+ function requestEasSyncFromEventBus() {
14709
+ startEasSyncActor();
14710
+ easSyncActor.send({
14711
+ type: 'REQUEST',
14712
+ correlationId: newCorrelationId(),
14713
+ source: 'event_bus',
13655
14714
  });
13656
- const { versionUids } = await saveEasVersionsToDb({
13657
- itemVersions,
14715
+ }
14716
+ function requestEasSyncFromAddressChange(addresses) {
14717
+ startEasSyncActor();
14718
+ easSyncActor.send({
14719
+ type: 'REQUEST',
14720
+ correlationId: newCorrelationId(),
14721
+ options: { addresses },
14722
+ source: 'address_change',
13658
14723
  });
13659
- const rawProperties = await getItemPropertiesFromEas({
13660
- versionUids,
13661
- excludeRevoked: false,
14724
+ }
14725
+ function requestEasSyncFromModelsInit() {
14726
+ startEasSyncActor();
14727
+ easSyncActor.send({
14728
+ type: 'REQUEST',
14729
+ correlationId: newCorrelationId(),
14730
+ source: 'models_init',
13662
14731
  });
13663
- const itemProperties = pickLatestPropertyAttestationsByRefAndSchema(rawProperties);
13664
- await saveEasPropertiesToDb({
13665
- itemProperties,
13666
- itemSeeds,
14732
+ }
14733
+ function sendEasSyncClientRequest(correlationId, options) {
14734
+ startEasSyncActor();
14735
+ easSyncActor.send({
14736
+ type: 'REQUEST',
14737
+ correlationId,
14738
+ options,
14739
+ source: 'client_api',
13667
14740
  });
13668
- await getRelatedSeedsAndVersions();
13669
- };
13670
- const syncDbWithEasHandler = throttle(async (_) => {
13671
- await runSyncFromEas();
13672
- }, 30000, {
13673
- leading: true,
13674
- trailing: false,
13675
- });
14741
+ }
13676
14742
 
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
- };
14743
+ var easSyncManager = /*#__PURE__*/Object.freeze({
14744
+ __proto__: null,
14745
+ easSyncActor: easSyncActor,
14746
+ easSyncMachine: easSyncMachine,
14747
+ requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
14748
+ requestEasSyncFromEventBus: requestEasSyncFromEventBus,
14749
+ requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
14750
+ sendEasSyncClientRequest: sendEasSyncClientRequest,
14751
+ startEasSyncActor: startEasSyncActor
14752
+ });
13688
14753
 
13689
14754
  /**
13690
14755
  * @deprecated Use BaseArweaveClient.setHost() instead.
13691
14756
  * This function is kept for backward compatibility but will be removed in a future version.
13692
14757
  */
13693
14758
  const setArweaveDomain = (newDomain) => {
13694
- BaseArweaveClient.setHost(newDomain);
14759
+ BaseArweaveClient.setPreferredReadGateway(newDomain);
13695
14760
  };
13696
14761
 
13697
- const logger$c = debug('seedSdk:services:events');
14762
+ const logger$b = debug('seedSdk:services:events');
13698
14763
  const handleServiceSaveState = (event) => {
13699
14764
  const { state, serviceId } = event;
13700
- logger$c(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
14765
+ logger$b(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
13701
14766
  // TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
13702
14767
  // localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
13703
14768
  };
@@ -13706,7 +14771,8 @@ const setupServicesEventHandlers = () => {
13706
14771
  };
13707
14772
 
13708
14773
  const setupAllItemsEventHandlers = () => {
13709
- eventEmitter.addListener('syncDbWithEas', syncDbWithEasHandler);
14774
+ startEasSyncActor();
14775
+ eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
13710
14776
  };
13711
14777
  // Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
13712
14778
 
@@ -13740,9 +14806,9 @@ class BasePathResolver {
13740
14806
  }
13741
14807
  }
13742
14808
 
13743
- const logger$b = debug('seedSdk:ClientManager:initialize');
14809
+ const logger$a = debug('seedSdk:ClientManager:initialize');
13744
14810
  const platformClassesInit = fromCallback(({ sendBack, input: { context, event } }) => {
13745
- logger$b('initialize from ClientManager');
14811
+ logger$a('initialize from ClientManager');
13746
14812
  const { isInitialized } = context;
13747
14813
  if (!event || !('options' in event)) {
13748
14814
  throw new Error('Initialize event must include options');
@@ -13778,20 +14844,20 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13778
14844
  let PathResolver;
13779
14845
  let EasClient;
13780
14846
  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;
14847
+ FileManager = (await import('./FileManager-C2uXql_C.js')).FileManager;
14848
+ Db = (await import('./Db-B7whB3oJ.js')).Db;
14849
+ QueryClient = (await import('./QueryClient-PqOg8mcw.js')).QueryClient;
14850
+ ArweaveClient = (await import('./ArweaveClient-C-eLH0zU.js')).ArweaveClient;
14851
+ PathResolver = (await import('./PathResolver-DnrG1hUX.js')).PathResolver;
14852
+ EasClient = (await import('./EasClient-CFguAKBp.js')).EasClient;
13787
14853
  }
13788
14854
  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;
14855
+ FileManager = (await import('./FileManager-BR3jtuSl.js')).FileManager;
14856
+ Db = (await import('./Db-nir1xVHg.js')).Db;
14857
+ QueryClient = (await import('./QueryClient-DJOrJZRR.js')).QueryClient;
14858
+ ArweaveClient = (await import('./ArweaveClient-B-vm2Xae.js')).ArweaveClient;
14859
+ PathResolver = (await import('./PathResolver-CZoSnHBU.js')).PathResolver;
14860
+ EasClient = (await import('./EasClient-BH_feMaX.js')).EasClient;
13795
14861
  }
13796
14862
  else {
13797
14863
  throw new Error(`Unable to determine environment. isBrowser()=${isBrowser()}, isNode()=${isNode()}. Platform-specific implementations could not be loaded.`);
@@ -13865,11 +14931,14 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13865
14931
  dbConfig,
13866
14932
  schemaFile,
13867
14933
  schema,
13868
- syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? false,
14934
+ syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
13869
14935
  } });
13870
14936
  if (arweaveDomain) {
13871
14937
  setArweaveDomain(arweaveDomain);
13872
14938
  }
14939
+ void ensureReadGatewaySelected().catch(() => {
14940
+ /* non-blocking warm-up for read gateway probe */
14941
+ });
13873
14942
  // Models are now Model instances, no registration needed
13874
14943
  // They should be created via Model.create() and are accessible via Model static methods
13875
14944
  setupAllItemsEventHandlers();
@@ -13905,15 +14974,15 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
13905
14974
  };
13906
14975
  });
13907
14976
 
13908
- const logger$a = debug('seedSdk:client:writeToDb');
13909
- const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
14977
+ const logger$9 = debug('seedSdk:client:writeToDb');
14978
+ const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
13910
14979
  const _saveAppState = async () => {
13911
14980
  try {
13912
14981
  const appDb = BaseDb.getAppDb();
13913
14982
  if (!appDb) {
13914
14983
  // In test environments, continue anyway
13915
14984
  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');
14985
+ logger$9('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
13917
14986
  return;
13918
14987
  }
13919
14988
  throw new Error('App DB not found');
@@ -13929,13 +14998,13 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
13929
14998
  value: JSON.stringify(value),
13930
14999
  },
13931
15000
  });
13932
- logger$a('result', result);
15001
+ logger$9('result', result);
13933
15002
  }
13934
15003
  catch (error) {
13935
- logger$a('[client/actors] [saveAppState] Error saving app state:', error);
15004
+ logger$9('[client/actors] [saveAppState] Error saving app state:', error);
13936
15005
  // In test environments, continue anyway
13937
15006
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13938
- logger$a('[client/actors] [saveAppState] Continuing despite error in test environment');
15007
+ logger$9('[client/actors] [saveAppState] Continuing despite error in test environment');
13939
15008
  return;
13940
15009
  }
13941
15010
  throw error;
@@ -13950,10 +15019,10 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
13950
15019
  });
13951
15020
  })
13952
15021
  .catch((error) => {
13953
- logger$a('[client/actors] [saveAppState] Error in promise chain:', error);
15022
+ logger$9('[client/actors] [saveAppState] Error in promise chain:', error);
13954
15023
  // In test environments, still send success to allow state machine to progress
13955
15024
  if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
13956
- logger$a('[client/actors] [saveAppState] Sending success despite error in test environment');
15025
+ logger$9('[client/actors] [saveAppState] Sending success despite error in test environment');
13957
15026
  sendBack({
13958
15027
  type: 'saveAppStateSuccess',
13959
15028
  key,
@@ -13966,222 +15035,6 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
13966
15035
  });
13967
15036
  });
13968
15037
 
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
15038
  let isInitialized = false;
14186
15039
  const fsInitHandler = async () => {
14187
15040
  if (isInitialized) {
@@ -14347,7 +15200,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
14347
15200
  }
14348
15201
  const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
14349
15202
  // 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.
15203
+ // modelUids will be populated async and EAS sync orchestrator runs when done.
14351
15204
  const fetchEasAndPopulateModelUids = async () => {
14352
15205
  try {
14353
15206
  const queryClient = BaseQueryClient.getQueryClient();
@@ -14380,7 +15233,8 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
14380
15233
  }
14381
15234
  }
14382
15235
  }
14383
- eventEmitter.emit('syncDbWithEas');
15236
+ const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
15237
+ requestEasSyncFromModelsInit();
14384
15238
  }
14385
15239
  else {
14386
15240
  logger$6('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
@@ -16830,16 +17684,19 @@ function addressesFromPersistedAddressValue(value) {
16830
17684
  return out;
16831
17685
  }
16832
17686
  function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
17687
+ const merged = addressesFromPersistedAddressValue(event.value);
16833
17688
  if (!context.syncFromEasOnAddressChange)
16834
17689
  return;
16835
17690
  if (event.key !== "addresses")
16836
17691
  return;
16837
- const merged = addressesFromPersistedAddressValue(event.value);
16838
17692
  if (merged.length === 0)
16839
17693
  return;
16840
- void runSyncFromEas({ addresses: merged }).catch((err) => {
16841
- logSyncAfterAddressSave("runSyncFromEas after address save failed", err);
16842
- });
17694
+ try {
17695
+ requestEasSyncFromAddressChange(merged);
17696
+ }
17697
+ catch (err) {
17698
+ logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
17699
+ }
16843
17700
  }
16844
17701
  function emitAddressesPersistedIfAddressesKey(event) {
16845
17702
  if (event.key !== "addresses")
@@ -16857,7 +17714,7 @@ const clientManagerMachine = setup({
16857
17714
  fileSystemInit,
16858
17715
  dbInit,
16859
17716
  saveConfig,
16860
- saveAppState: saveAppState$1,
17717
+ saveAppState,
16861
17718
  addModelsToStore,
16862
17719
  addModelsToDb,
16863
17720
  processSchemaFiles,
@@ -17181,7 +18038,16 @@ const clientInstance = {
17181
18038
  */
17182
18039
  syncFromEas: async (options) => {
17183
18040
  ensureInitialized();
17184
- await runSyncFromEas(options);
18041
+ startEasSyncActor();
18042
+ const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
18043
+ ? globalThis.crypto.randomUUID()
18044
+ : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
18045
+ sendEasSyncClientRequest(correlationId, options);
18046
+ await waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
18047
+ const snap = easSyncActor.getSnapshot();
18048
+ if (snap.context.lastFinishedStatus === 'failed') {
18049
+ throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
18050
+ }
17185
18051
  },
17186
18052
  addModel: async (modelDef) => {
17187
18053
  const db = await BaseDb.getAppDb();
@@ -17391,7 +18257,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
17391
18257
  // Lazy import cache for ModelProperty to avoid circular dependency
17392
18258
  // Eagerly start loading to minimize delay on first access
17393
18259
  let ModelPropertyClass = null;
17394
- const modelPropertyImportPromise = import('./ModelProperty-DWtv9fQr.js')
18260
+ const modelPropertyImportPromise = import('./ModelProperty-CIeLasI4.js')
17395
18261
  .then(module => {
17396
18262
  ModelPropertyClass = module.ModelProperty;
17397
18263
  return ModelPropertyClass;
@@ -17408,7 +18274,7 @@ function getModelProperty() {
17408
18274
  }
17409
18275
  // Lazy import cache for Schema to avoid circular dependency
17410
18276
  let SchemaClass = null;
17411
- const schemaImportPromise = (async () => { const _mod_9 = await import('./Schema-CqqcEexA.js'); return _mod_9.b; })()
18277
+ const schemaImportPromise = (async () => { const _mod_10 = await import('./Schema-B3YQHTtu.js'); return _mod_10.b; })()
17412
18278
  .then(module => {
17413
18279
  SchemaClass = module.Schema;
17414
18280
  return SchemaClass;
@@ -19148,5 +20014,5 @@ var Model$1 = /*#__PURE__*/Object.freeze({
19148
20014
  const TModelValues = Type.Record(Type.String(), Type.Any());
19149
20015
  const TModelSchema = Type.Record(Type.String(), TProperty);
19150
20016
 
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
20017
+ 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 };
20018
+ //# sourceMappingURL=index-DUMXLKJr.js.map