@seedprotocol/sdk 0.7.3-next.654.g52217f6 → 0.7.3

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 (187) hide show
  1. package/dist/{db-D9K_f5cF.js → BasePathResolver-Cm4apKRb.js} +2041 -127
  2. package/dist/BasePathResolver-Cm4apKRb.js.map +1 -0
  3. package/dist/{ClientManager-C-QXqUK9.js → ClientManager-i3nJASkg.js} +249 -147
  4. package/dist/ClientManager-i3nJASkg.js.map +1 -0
  5. package/dist/{Item-C7sUUu2B.js → Item-DBFchXpC.js} +259 -169
  6. package/dist/Item-DBFchXpC.js.map +1 -0
  7. package/dist/{ModelProperty-DJxeOOrc.js → ModelProperty-BS49g01Y.js} +166 -47
  8. package/dist/ModelProperty-BS49g01Y.js.map +1 -0
  9. package/dist/{Schema-fXtvd-yL.js → Schema-CpMNEnUO.js} +53 -42
  10. package/dist/Schema-CpMNEnUO.js.map +1 -0
  11. package/dist/{SchemaValidationService-CvRS2HSO.js → SchemaValidationService-DieV4KL-.js} +15 -17
  12. package/dist/{SchemaValidationService-CvRS2HSO.js.map → SchemaValidationService-DieV4KL-.js.map} +1 -1
  13. package/dist/{backfillMetadataPropertyIds-SXW-8C64.js → backfillMetadataPropertyIds-DSoOoTnX.js} +14 -7
  14. package/dist/{backfillMetadataPropertyIds-SXW-8C64.js.map → backfillMetadataPropertyIds-DSoOoTnX.js.map} +1 -1
  15. package/dist/{configurePlatform-BRw2j0ZN.js → configurePlatform-D0lQGAMQ.js} +5 -7
  16. package/dist/{configurePlatform-BRw2j0ZN.js.map → configurePlatform-D0lQGAMQ.js.map} +1 -1
  17. package/dist/detachRowsBeforeDelete-S0q-DJPT.js +50 -0
  18. package/dist/detachRowsBeforeDelete-S0q-DJPT.js.map +1 -0
  19. package/dist/{eas-DHxfswCt.js → eas-6pjU-OuX.js} +6 -8
  20. package/dist/eas-6pjU-OuX.js.map +1 -0
  21. package/dist/{getItem-d6N_aM6S.js → getItem-CxBNZ-WL.js} +10 -11
  22. package/dist/{getItem-d6N_aM6S.js.map → getItem-CxBNZ-WL.js.map} +1 -1
  23. package/dist/{getPublishPayload-BHrxVtzY.js → getPublishPayload-CTCvRUoU.js} +50 -18
  24. package/dist/getPublishPayload-CTCvRUoU.js.map +1 -0
  25. package/dist/{getPublishUploads-BEqRiKIS.js → getPublishUploads-SFHCbf_y.js} +13 -22
  26. package/dist/{getPublishUploads-BEqRiKIS.js.map → getPublishUploads-SFHCbf_y.js.map} +1 -1
  27. package/dist/{index-s15q14rm.js → index-8O3Uow-Y.js} +125 -57
  28. package/dist/index-8O3Uow-Y.js.map +1 -0
  29. package/dist/{index-DglvthOk.js → index-AVFTVp1m.js} +2 -2
  30. package/dist/index-AVFTVp1m.js.map +1 -0
  31. package/dist/index-Cvt5UBz4.js +30 -0
  32. package/dist/index-Cvt5UBz4.js.map +1 -0
  33. package/dist/{index.browser-Cm06tP4X.js → index.browser-DBhxRoe8.js} +11 -10
  34. package/dist/{index.browser-Cm06tP4X.js.map → index.browser-DBhxRoe8.js.map} +1 -1
  35. package/dist/{index.node-C30dmFgn.js → index.node-CJhlcNHM.js} +25 -13
  36. package/dist/index.node-CJhlcNHM.js.map +1 -0
  37. package/dist/main.js +27 -32
  38. package/dist/main.js.map +1 -1
  39. package/dist/node.js +19 -22
  40. package/dist/node.js.map +1 -1
  41. package/dist/platform.browser.js +9 -9
  42. package/dist/platform.node.js +18 -5
  43. package/dist/platform.node.js.map +1 -1
  44. package/dist/{property-DhmmYAvQ.js → property-DwPD283A.js} +11 -12
  45. package/dist/property-DwPD283A.js.map +1 -0
  46. package/dist/{publishDraftGraph-yYP74WRt.js → publishDraftGraph-BOn3_Occ.js} +6 -9
  47. package/dist/{publishDraftGraph-yYP74WRt.js.map → publishDraftGraph-BOn3_Occ.js.map} +1 -1
  48. package/dist/{resetAmbiguousLegacyItemData-Bk0QyDW8.js → resetAmbiguousLegacyItemData-BkYmBeJc.js} +14 -3
  49. package/dist/{resetAmbiguousLegacyItemData-Bk0QyDW8.js.map → resetAmbiguousLegacyItemData-BkYmBeJc.js.map} +1 -1
  50. package/dist/{resolveModelForSyncedSeed-8cAzvUFd.js → resolveModelForSyncedSeed-BL24nLa7.js} +2 -2
  51. package/dist/{resolveModelForSyncedSeed-8cAzvUFd.js.map → resolveModelForSyncedSeed-BL24nLa7.js.map} +1 -1
  52. package/dist/src/Item/Item.d.ts +20 -2
  53. package/dist/src/Item/Item.d.ts.map +1 -1
  54. package/dist/src/Item/service/actors/runPublish.d.ts +11 -2
  55. package/dist/src/Item/service/actors/runPublish.d.ts.map +1 -1
  56. package/dist/src/Item/service/itemMachineSingle.d.ts +12 -2
  57. package/dist/src/Item/service/itemMachineSingle.d.ts.map +1 -1
  58. package/dist/src/ItemProperty/ItemProperty.d.ts +5 -3
  59. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  60. package/dist/src/ItemProperty/service/actors/saveValueToDb/analyzeInput.d.ts.map +1 -1
  61. package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
  62. package/dist/src/Model/Model.d.ts +10 -4
  63. package/dist/src/Model/Model.d.ts.map +1 -1
  64. package/dist/src/Model/index.d.ts +2 -2
  65. package/dist/src/ModelProperty/ModelProperty.d.ts +10 -2
  66. package/dist/src/ModelProperty/ModelProperty.d.ts.map +1 -1
  67. package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +3 -0
  68. package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts.map +1 -1
  69. package/dist/src/Schema/Schema.d.ts +2 -2
  70. package/dist/src/Schema/Schema.d.ts.map +1 -1
  71. package/dist/src/Schema/index.d.ts +0 -1
  72. package/dist/src/Schema/index.d.ts.map +1 -1
  73. package/dist/src/client/ClientManager.d.ts +30 -11
  74. package/dist/src/client/ClientManager.d.ts.map +1 -1
  75. package/dist/src/client/actors/platformClassesInit.d.ts +6 -0
  76. package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
  77. package/dist/src/client/actors/processSchemaFiles.d.ts.map +1 -1
  78. package/dist/src/client/actors/saveConfig.d.ts +13 -6
  79. package/dist/src/client/actors/saveConfig.d.ts.map +1 -1
  80. package/dist/src/db/read/getPublishPayload.d.ts +1 -1
  81. package/dist/src/db/read/getPublishPayload.d.ts.map +1 -1
  82. package/dist/src/db/write/claimUnpublishedDrafts.d.ts +2 -0
  83. package/dist/src/db/write/claimUnpublishedDrafts.d.ts.map +1 -1
  84. package/dist/src/eventBus.d.ts +5 -0
  85. package/dist/src/eventBus.d.ts.map +1 -1
  86. package/dist/src/helpers/cachedPropertyRefresh.d.ts +12 -0
  87. package/dist/src/helpers/cachedPropertyRefresh.d.ts.map +1 -0
  88. package/dist/src/helpers/db.d.ts +3 -0
  89. package/dist/src/helpers/db.d.ts.map +1 -1
  90. package/dist/src/helpers/easSdk.d.ts +16 -0
  91. package/dist/src/helpers/easSdk.d.ts.map +1 -0
  92. package/dist/src/helpers/entity/detachRowsBeforeDelete.d.ts +16 -0
  93. package/dist/src/helpers/entity/detachRowsBeforeDelete.d.ts.map +1 -0
  94. package/dist/src/helpers/entity/entityDestroy.d.ts +2 -0
  95. package/dist/src/helpers/entity/entityDestroy.d.ts.map +1 -1
  96. package/dist/src/helpers/ownership.d.ts +9 -1
  97. package/dist/src/helpers/ownership.d.ts.map +1 -1
  98. package/dist/src/helpers/property/index.d.ts +37 -51
  99. package/dist/src/helpers/property/index.d.ts.map +1 -1
  100. package/dist/src/helpers/publishConfig.d.ts +27 -8
  101. package/dist/src/helpers/publishConfig.d.ts.map +1 -1
  102. package/dist/src/helpers/updateSchema.d.ts +5 -0
  103. package/dist/src/helpers/updateSchema.d.ts.map +1 -1
  104. package/dist/src/helpers/waitForEntityIdle.d.ts +5 -0
  105. package/dist/src/helpers/waitForEntityIdle.d.ts.map +1 -1
  106. package/dist/src/imports/json.d.ts +9 -0
  107. package/dist/src/imports/json.d.ts.map +1 -1
  108. package/dist/src/index.d.ts +6 -4
  109. package/dist/src/index.d.ts.map +1 -1
  110. package/dist/src/interfaces/IItem.d.ts +7 -1
  111. package/dist/src/interfaces/IItem.d.ts.map +1 -1
  112. package/dist/src/node/db/Db.d.ts.map +1 -1
  113. package/dist/src/node/helpers/PathResolver.d.ts.map +1 -1
  114. package/dist/src/node/index.d.ts +8 -1
  115. package/dist/src/node/index.d.ts.map +1 -1
  116. package/dist/src/platform/index.browser.d.ts +2 -0
  117. package/dist/src/platform/index.browser.d.ts.map +1 -1
  118. package/dist/src/platform/index.node.d.ts +2 -0
  119. package/dist/src/platform/index.node.d.ts.map +1 -1
  120. package/dist/src/types/index.d.ts +12 -1
  121. package/dist/src/types/index.d.ts.map +1 -1
  122. package/dist/src/types/machines.d.ts +2 -0
  123. package/dist/src/types/machines.d.ts.map +1 -1
  124. package/dist/src/types/property.d.ts +8 -0
  125. package/dist/src/types/property.d.ts.map +1 -1
  126. package/dist/{syncDbWithEas--HUA9WNb.js → syncDbWithEas-Bv2Fe38J.js} +15 -16
  127. package/dist/syncDbWithEas-Bv2Fe38J.js.map +1 -0
  128. package/dist/tabEvents-9s2WCYw-.js +335 -0
  129. package/dist/tabEvents-9s2WCYw-.js.map +1 -0
  130. package/dist/{tolerantWebAccess-BZYWt09Y.js → tolerantWebAccess-iUu80pAP.js} +9 -9
  131. package/dist/{tolerantWebAccess-BZYWt09Y.js.map → tolerantWebAccess-iUu80pAP.js.map} +1 -1
  132. package/dist/{updateSeedRevokedAt-D_EG-q3b.js → updateSeedRevokedAt-zBfi931j.js} +3 -3
  133. package/dist/{updateSeedRevokedAt-D_EG-q3b.js.map → updateSeedRevokedAt-zBfi931j.js.map} +1 -1
  134. package/package.json +11 -12
  135. package/src/node/easLodashRegister.js +4 -0
  136. package/dist/BasePathResolver-CfSfMW5_.js +0 -676
  137. package/dist/BasePathResolver-CfSfMW5_.js.map +0 -1
  138. package/dist/ClientManager-C-QXqUK9.js.map +0 -1
  139. package/dist/Item-C7sUUu2B.js.map +0 -1
  140. package/dist/ModelProperty-DJxeOOrc.js.map +0 -1
  141. package/dist/Schema-fXtvd-yL.js.map +0 -1
  142. package/dist/cjs/ModelProperty-DXZ39Wyv.js +0 -1978
  143. package/dist/cjs/ModelProperty-DXZ39Wyv.js.map +0 -1
  144. package/dist/cjs/Schema-DdP109QD.js +0 -5257
  145. package/dist/cjs/Schema-DdP109QD.js.map +0 -1
  146. package/dist/cjs/SchemaValidationService-CSXxx7sQ.js +0 -779
  147. package/dist/cjs/SchemaValidationService-CSXxx7sQ.js.map +0 -1
  148. package/dist/cjs/backfillMetadataPropertyIds-CPYoaMl4.js +0 -90
  149. package/dist/cjs/backfillMetadataPropertyIds-CPYoaMl4.js.map +0 -1
  150. package/dist/cjs/eas-B2YDQssV.js +0 -139
  151. package/dist/cjs/eas-B2YDQssV.js.map +0 -1
  152. package/dist/cjs/getItem-DgnaQzbE.js +0 -59
  153. package/dist/cjs/getItem-DgnaQzbE.js.map +0 -1
  154. package/dist/cjs/getPublishPayload-CqlqRdot.js +0 -1604
  155. package/dist/cjs/getPublishPayload-CqlqRdot.js.map +0 -1
  156. package/dist/cjs/getPublishUploads-DsXY9S4U.js +0 -872
  157. package/dist/cjs/getPublishUploads-DsXY9S4U.js.map +0 -1
  158. package/dist/cjs/index-BHaWOwNF.js +0 -71
  159. package/dist/cjs/index-BHaWOwNF.js.map +0 -1
  160. package/dist/cjs/index-C4XlgCJ4.js +0 -22801
  161. package/dist/cjs/index-C4XlgCJ4.js.map +0 -1
  162. package/dist/cjs/index.browser-BSf8HpnU.js +0 -22
  163. package/dist/cjs/index.browser-BSf8HpnU.js.map +0 -1
  164. package/dist/cjs/property-fa0iju0J.js +0 -328
  165. package/dist/cjs/property-fa0iju0J.js.map +0 -1
  166. package/dist/cjs/publishDraftGraph-3ASwAlD7.js +0 -403
  167. package/dist/cjs/publishDraftGraph-3ASwAlD7.js.map +0 -1
  168. package/dist/cjs/resetAmbiguousLegacyItemData-Bu_MBBYt.js +0 -117
  169. package/dist/cjs/resetAmbiguousLegacyItemData-Bu_MBBYt.js.map +0 -1
  170. package/dist/cjs/resolveModelForSyncedSeed-BANIiuFU.js +0 -49
  171. package/dist/cjs/resolveModelForSyncedSeed-BANIiuFU.js.map +0 -1
  172. package/dist/cjs/syncDbWithEas-CrmxxmUW.js +0 -887
  173. package/dist/cjs/syncDbWithEas-CrmxxmUW.js.map +0 -1
  174. package/dist/db-D9K_f5cF.js.map +0 -1
  175. package/dist/eas-DHxfswCt.js.map +0 -1
  176. package/dist/getPublishPayload-BHrxVtzY.js.map +0 -1
  177. package/dist/index-CiMEoGu3.js +0 -32
  178. package/dist/index-CiMEoGu3.js.map +0 -1
  179. package/dist/index-DglvthOk.js.map +0 -1
  180. package/dist/index-s15q14rm.js.map +0 -1
  181. package/dist/index.node-C30dmFgn.js.map +0 -1
  182. package/dist/main.cjs +0 -85
  183. package/dist/main.cjs.map +0 -1
  184. package/dist/property-DhmmYAvQ.js.map +0 -1
  185. package/dist/syncDbWithEas--HUA9WNb.js.map +0 -1
  186. package/dist/tabEvents-DguZpCCv.js +0 -1580
  187. package/dist/tabEvents-DguZpCCv.js.map +0 -1
@@ -1,10 +1,272 @@
1
- import { i as models, f as modelSchemas, s as schemas, B as BaseDb, q as seeds, p as properties, a as appState, m as metadata } from './BasePathResolver-CfSfMW5_.js';
2
- import { toSnakeCase } from 'drizzle-orm/casing';
3
- import { eq, and, inArray, desc, isNull } from 'drizzle-orm';
4
1
  import debug from 'debug';
5
- import { upperFirst, camelCase } from 'lodash-es';
2
+ import { isEasAttestationExplorerUrl, BaseArweaveClient, ensureReadGatewaySelected, getArweaveReadBaseUrls, getTransactionTagsByIds } from '@seedprotocol/arweave';
3
+ import { BaseQueryClient, BaseEasClient, GET_FILES_METADATA } from '@seedprotocol/eas';
4
+ import { waitFor } from 'xstate';
6
5
  import 'pluralize';
7
6
  import { Type } from '@sinclair/typebox';
7
+ import { sqliteTable, integer, text, unique, int, blob, uniqueIndex } from 'drizzle-orm/sqlite-core';
8
+ import { relations, and, eq, inArray, desc, isNull, isNotNull, or } from 'drizzle-orm';
9
+ import { toSnakeCase as toSnakeCase$1 } from 'drizzle-orm/casing';
10
+ import { upperFirst, camelCase, throttle } from 'lodash-es';
11
+ import { customAlphabet } from 'nanoid';
12
+ import { alphanumeric } from 'nanoid-dictionary';
13
+ import '@seedprotocol/query';
14
+ import { sha256 } from '@noble/hashes/sha256';
15
+ import { sha3_256 } from '@noble/hashes/sha3';
16
+ import { bytesToHex } from '@noble/hashes/utils';
17
+
18
+ class BaseDb {
19
+ static configure(impl) {
20
+ if (!impl) {
21
+ throw new Error('Cannot configure Db with undefined or null. Ensure the platform-specific Db is properly created.');
22
+ }
23
+ BaseDb._impl = impl;
24
+ }
25
+ static requireImpl() {
26
+ if (!BaseDb._impl) {
27
+ throw new Error('Db not configured. Call BaseDb.configure() during platform init.');
28
+ }
29
+ return BaseDb._impl;
30
+ }
31
+ static getAppDb() {
32
+ return BaseDb.requireImpl().getAppDb();
33
+ }
34
+ static prepareDb(filesDir, config) {
35
+ return BaseDb.requireImpl().prepareDb(filesDir, config);
36
+ }
37
+ static isAppDbReady() {
38
+ if (!BaseDb._impl) {
39
+ return false;
40
+ }
41
+ return BaseDb._impl.isAppDbReady();
42
+ }
43
+ static connectToDb(pathToDir) {
44
+ return BaseDb.requireImpl().connectToDb(pathToDir);
45
+ }
46
+ static async migrate(pathToDbDir, dbName, dbId) {
47
+ return BaseDb.requireImpl().migrate(pathToDbDir, dbName, dbId);
48
+ }
49
+ /**
50
+ * Execute a reactive query that emits new results whenever the underlying data changes.
51
+ *
52
+ * Supports two usage patterns:
53
+ * 1. SQL tag function: liveQuery((sql) => sql`SELECT * FROM models`)
54
+ * 2. Drizzle query builder (browser only): liveQuery(db.select().from(models))
55
+ */
56
+ static liveQuery(query) {
57
+ return BaseDb.requireImpl().liveQuery(query);
58
+ }
59
+ }
60
+ BaseDb._impl = null;
61
+
62
+ const models = sqliteTable('models', {
63
+ id: integer('id').primaryKey({ autoIncrement: true }),
64
+ name: text('name').notNull(),
65
+ schemaFileId: text('schema_file_id'), // ID from JSON file for change tracking - must be unique
66
+ isEdited: integer('is_edited', { mode: 'boolean' }), // true if model has been edited locally, false if matches schema file
67
+ }, (table) => {
68
+ return {
69
+ uniqueSchemaFileId: unique('unique_schema_file_id').on(table.schemaFileId),
70
+ };
71
+ });
72
+ const modelsRelations = relations(models, ({ many }) => ({
73
+ properties: many(properties),
74
+ }));
75
+ const properties = sqliteTable('properties', {
76
+ id: integer('id').primaryKey({ autoIncrement: true }),
77
+ name: text('name').notNull(),
78
+ dataType: text('data_type').notNull(),
79
+ modelId: integer('model_id')
80
+ .notNull()
81
+ .references(() => models.id),
82
+ refModelId: integer('ref_model_id').references(() => models.id),
83
+ refValueType: text('ref_value_type'),
84
+ schemaFileId: text('schema_file_id'), // ID from JSON file for change tracking
85
+ isEdited: integer('is_edited', { mode: 'boolean' }), // true if property has been edited locally, false if matches schema file
86
+ required: integer('required', { mode: 'boolean' }), // true if relation/image property is required (publish fails when related item not found)
87
+ // Storage settings from the schema file's `storage: { type, path, extension }`, in the internal
88
+ // shape ModelProperty uses. Null when the property has no storage config.
89
+ storageType: text('storage_type'), // 'ItemStorage' | 'PropertyStorage'
90
+ localStorageDir: text('local_storage_dir'), // storage.path, e.g. '/html'
91
+ filenameSuffix: text('filename_suffix'), // storage.extension, e.g. '.html'
92
+ }, (table) => {
93
+ return {
94
+ uniqueNameModelId: unique('unique_name_model_id').on(table.name, table.modelId),
95
+ uniqueSchemaFileId: unique('unique_property_schema_file_id').on(table.schemaFileId),
96
+ };
97
+ });
98
+ const propertiesRelations = relations(properties, ({ one }) => ({
99
+ model: one(models),
100
+ refModel: one(models),
101
+ }));
102
+
103
+ var ModelSchema = /*#__PURE__*/Object.freeze({
104
+ __proto__: null,
105
+ models: models,
106
+ modelsRelations: modelsRelations,
107
+ properties: properties,
108
+ propertiesRelations: propertiesRelations
109
+ });
110
+
111
+ class BaseFileManager {
112
+ static configure(impl) {
113
+ if (!impl) {
114
+ throw new Error('Cannot configure FileManager with undefined or null. Ensure the platform-specific FileManager is properly created.');
115
+ }
116
+ BaseFileManager._impl = impl;
117
+ }
118
+ static requireImpl() {
119
+ if (!BaseFileManager._impl) {
120
+ throw new Error('FileManager not configured. Call BaseFileManager.configure() during platform init.');
121
+ }
122
+ return BaseFileManager._impl;
123
+ }
124
+ /**
125
+ * Clears FS init flags so a later call can retry. Used after a failed init
126
+ * and by tests. Does not unmount or delete any files.
127
+ */
128
+ static resetInitializationState() {
129
+ this.fileSystemInitialized = false;
130
+ this.initializing = false;
131
+ this.initializePromise = null;
132
+ this.workingDir = undefined;
133
+ }
134
+ static initializeFileSystem(workingDir) {
135
+ if (this.fileSystemInitialized) {
136
+ return Promise.resolve();
137
+ }
138
+ if (this.initializePromise) {
139
+ return this.initializePromise;
140
+ }
141
+ this.initializing = true;
142
+ const pending = this.runInitializeFileSystem(workingDir).finally(() => {
143
+ this.initializing = false;
144
+ if (this.initializePromise === pending) {
145
+ this.initializePromise = null;
146
+ }
147
+ });
148
+ this.initializePromise = pending;
149
+ return pending;
150
+ }
151
+ static async runInitializeFileSystem(workingDir) {
152
+ await BaseFileManager.requireImpl().initializeFileSystem(workingDir);
153
+ this.fileSystemInitialized = true;
154
+ this.workingDir = workingDir;
155
+ }
156
+ static getWorkingDir() {
157
+ if (!this.workingDir) {
158
+ throw new Error('Working directory is not set');
159
+ }
160
+ return this.workingDir;
161
+ }
162
+ /**
163
+ * Build a path under the configured files root (e.g. /app-files).
164
+ * Use this instead of hardcoding /files/ for images, html, json, etc.
165
+ * @param subpaths - path segments to join (e.g. 'images', fileName)
166
+ * @returns full path like /app-files/images/egg.jpg
167
+ */
168
+ static getFilesPath(...subpaths) {
169
+ const root = this.getWorkingDir().replace(/\/$/, '');
170
+ const parts = [root, ...subpaths].filter(Boolean);
171
+ return parts.join('/').replace(/\/+/g, '/');
172
+ }
173
+ static getContentUrlFromPath(path) {
174
+ return BaseFileManager.requireImpl().getContentUrlFromPath(path);
175
+ }
176
+ static downloadAllFiles(params) {
177
+ return BaseFileManager.requireImpl().downloadAllFiles(params);
178
+ }
179
+ static downloadFileByTransactionId({ transactionId, arweaveHost, arweaveBaseUrls, excludedTransactions, expectedContentHash, compositeChildPaths, }) {
180
+ return BaseFileManager.requireImpl().downloadAllFiles({
181
+ transactionIds: [transactionId],
182
+ arweaveHost,
183
+ arweaveBaseUrls,
184
+ excludedTransactions,
185
+ expectedContentHashes: expectedContentHash ? { [transactionId]: expectedContentHash } : undefined,
186
+ compositeChildPaths: compositeChildPaths ? { [transactionId]: compositeChildPaths } : undefined,
187
+ });
188
+ }
189
+ static resizeImage({ filePath, width, height }) {
190
+ return BaseFileManager.requireImpl().resizeImage({ filePath, width, height });
191
+ }
192
+ static resizeAllImages({ width, height }) {
193
+ return BaseFileManager.requireImpl().resizeAllImages({ width, height });
194
+ }
195
+ static pathExists(filePath) {
196
+ return BaseFileManager.requireImpl().pathExists(filePath);
197
+ }
198
+ static invalidateCachedPaths(filePaths) {
199
+ return BaseFileManager.requireImpl().invalidateCachedPaths(filePaths);
200
+ }
201
+ /** File size in bytes, or null if the path does not exist / cannot be stated. */
202
+ static getFileSize(filePath) {
203
+ return BaseFileManager.requireImpl().getFileSize(filePath);
204
+ }
205
+ /**
206
+ * Returns a list of filenames in the given directory (e.g. 'images', 'files').
207
+ */
208
+ static listFiles(dir) {
209
+ return BaseFileManager.requireImpl().listFiles(dir);
210
+ }
211
+ /**
212
+ * Returns a list of image filenames in the images folder (originals only, excludes size subdirs).
213
+ * Use this to get all stored images without traversing 480/760/1024/1440/1920 subdirectories.
214
+ */
215
+ static listImageFiles() {
216
+ return this.listFiles('images');
217
+ }
218
+ static createDirIfNotExists(filePath) {
219
+ return BaseFileManager.requireImpl().createDirIfNotExists(filePath);
220
+ }
221
+ static async waitForFile(filePath) {
222
+ return BaseFileManager.requireImpl().waitForFile(filePath);
223
+ }
224
+ static async waitForFileWithContent(filePath, interval, timeout) {
225
+ return BaseFileManager.requireImpl().waitForFileWithContent(filePath, interval, timeout);
226
+ }
227
+ static async saveFile(filePath, content) {
228
+ return BaseFileManager.requireImpl().saveFile(filePath, content);
229
+ }
230
+ static saveFileSync(filePath, content) {
231
+ return BaseFileManager.requireImpl().saveFileSync(filePath, content);
232
+ }
233
+ static async readFile(filePath) {
234
+ return BaseFileManager.requireImpl().readFile(filePath);
235
+ }
236
+ static readFileSync(filePath) {
237
+ return BaseFileManager.requireImpl().readFileSync(filePath);
238
+ }
239
+ static async readFileAsBuffer(filePath) {
240
+ return BaseFileManager.requireImpl().readFileAsBuffer(filePath);
241
+ }
242
+ static async readFileAsString(filePath) {
243
+ return BaseFileManager.requireImpl().readFileAsString(filePath);
244
+ }
245
+ static async getFs() {
246
+ return BaseFileManager.requireImpl().getFs();
247
+ }
248
+ static getFsSync() {
249
+ return BaseFileManager.requireImpl().getFsSync();
250
+ }
251
+ static getPathModule() {
252
+ return BaseFileManager.requireImpl().getPathModule();
253
+ }
254
+ static getParentDirPath(filePath) {
255
+ return BaseFileManager.requireImpl().getParentDirPath(filePath);
256
+ }
257
+ static getFilenameFromPath(filePath) {
258
+ return BaseFileManager.requireImpl().getFilenameFromPath(filePath);
259
+ }
260
+ }
261
+ BaseFileManager.fileSystemInitialized = false;
262
+ BaseFileManager.initializing = false;
263
+ BaseFileManager._impl = null;
264
+ BaseFileManager.initializePromise = null;
265
+
266
+ var BaseFileManager$1 = /*#__PURE__*/Object.freeze({
267
+ __proto__: null,
268
+ BaseFileManager: BaseFileManager
269
+ });
8
270
 
9
271
  /** Default maximum length for Text properties when not explicitly set. Html holds arbitrary-length content and does not use this limit. */
10
272
  const DEFAULT_TEXT_MAX_LENGTH = 255;
@@ -105,17 +367,19 @@ function normalizePropertyRecordSchema(def) {
105
367
  }
106
368
  return out;
107
369
  }
370
+ // String literals, not enum members: PropertyDataType must accept plain strings
371
+ // such as `{ dataType: 'Text' }`. ModelPropertyDataTypes members still fit.
108
372
  const TPropertyDataType = Type.Union([
109
- Type.Literal(ModelPropertyDataTypes.Text),
110
- Type.Literal(ModelPropertyDataTypes.Number),
111
- Type.Literal(ModelPropertyDataTypes.List),
112
- Type.Literal(ModelPropertyDataTypes.Relation),
113
- Type.Literal(ModelPropertyDataTypes.Image),
114
- Type.Literal(ModelPropertyDataTypes.Json),
115
- Type.Literal(ModelPropertyDataTypes.File),
116
- Type.Literal(ModelPropertyDataTypes.Boolean),
117
- Type.Literal(ModelPropertyDataTypes.Date),
118
- Type.Literal(ModelPropertyDataTypes.Html),
373
+ Type.Literal('Text'),
374
+ Type.Literal('Number'),
375
+ Type.Literal('List'),
376
+ Type.Literal('Relation'),
377
+ Type.Literal('Image'),
378
+ Type.Literal('Json'),
379
+ Type.Literal('File'),
380
+ Type.Literal('Boolean'),
381
+ Type.Literal('Date'),
382
+ Type.Literal('Html'),
119
383
  ]);
120
384
  const TStorageType = Type.Union([
121
385
  Type.Literal('ItemStorage'), // Looks for a storageTransactionId property on the item
@@ -195,24 +459,547 @@ const Property = {
195
459
  Html: htmlPropertyFactory,
196
460
  /** `Html` opts are not representable in `TPropertyConstructor`; keep runtime shape via double assert. */
197
461
  };
198
- const PropertyMetadataKey = Symbol('property');
199
- const PropertyConstructor = (propertyType) => {
200
- return function (parentClassPrototype, propertyKey) {
201
- const existingProperties = Reflect.getMetadata(PropertyMetadataKey, parentClassPrototype) || [];
202
- existingProperties.push({ propertyKey, propertyType });
203
- Reflect.defineMetadata(PropertyMetadataKey, existingProperties, parentClassPrototype);
462
+
463
+ /** Same rules as getCorrectId in helpers/index (avoid barrel circular import). */
464
+ function parseLocalIdOrUid(localIdOrUid) {
465
+ const id = { localId: undefined, uid: undefined };
466
+ if (!localIdOrUid)
467
+ return id;
468
+ if (localIdOrUid.length === 10) {
469
+ id.localId = localIdOrUid;
470
+ }
471
+ if (localIdOrUid.startsWith('0x') && localIdOrUid.length === 66) {
472
+ id.uid = localIdOrUid;
473
+ }
474
+ return id;
475
+ }
476
+ /** Relation/image refs may be string ids or `{ seedLocalId?, seedUid? }`. */
477
+ function normalizeRelationPropertyValue(value) {
478
+ if (value == null)
479
+ return undefined;
480
+ if (typeof value === 'string') {
481
+ const t = value.trim();
482
+ return t !== '' ? t : undefined;
483
+ }
484
+ if (typeof value === 'object' && value !== null) {
485
+ const o = value;
486
+ if (typeof o.seedLocalId === 'string' && o.seedLocalId.trim() !== '') {
487
+ return o.seedLocalId.trim();
488
+ }
489
+ if (typeof o.seedUid === 'string' && o.seedUid.trim() !== '') {
490
+ return o.seedUid.trim();
491
+ }
492
+ }
493
+ return undefined;
494
+ }
495
+ /** getCorrectId only accepts 10-char local ids and 0x66 uids; local seed refs can be up to 21 chars. */
496
+ const LOCAL_SEED_REF = /^[a-zA-Z0-9_-]{10,21}$/;
497
+ /** Resolve seed ids from a single string (context propertyValue or DB row). */
498
+ function resolveSeedIdsFromRefString(s) {
499
+ const fromCorrect = parseLocalIdOrUid(s);
500
+ if (fromCorrect.localId || fromCorrect.uid) {
501
+ return { seedLocalId: fromCorrect.localId, seedUid: fromCorrect.uid };
502
+ }
503
+ if (LOCAL_SEED_REF.test(s) && !s.startsWith('0x')) {
504
+ return { seedLocalId: s };
505
+ }
506
+ return {};
507
+ }
508
+ /**
509
+ * True when a relation ref is an attested seed uid (0x…) rather than a local id. A uid only exists once
510
+ * the seed is on EAS, so publish can attest the uid as-is when no local copy exists (e.g. a server
511
+ * publishing on someone's behalf that only holds the uids it was given). Callers must not walk into it.
512
+ */
513
+ function isPublishedSeedRef(value) {
514
+ const ref = normalizeRelationPropertyValue(value);
515
+ if (!ref)
516
+ return false;
517
+ const { seedLocalId, seedUid } = resolveSeedIdsFromRefString(ref);
518
+ return !!seedUid && !seedLocalId;
519
+ }
520
+ /**
521
+ * Storage seed local id (nanoid) or 0x uid. Stricter than resolveSeedIdsFromRefString, which accepts
522
+ * any 10-char string (so a 10-char html snippet like "<p>raw</p>" would pass as a local id).
523
+ */
524
+ const STORAGE_SEED_REF = /^(?:[A-Za-z0-9_-]{10,21}|0x[0-9a-fA-F]{64})$/;
525
+ /** True when a File/Image/Html value is already a storage seed reference rather than raw content. */
526
+ function isStorageSeedRef(value) {
527
+ return typeof value === 'string' && STORAGE_SEED_REF.test(value.trim());
528
+ }
529
+
530
+ const seeds = sqliteTable('seeds', {
531
+ localId: text('local_id').unique(),
532
+ uid: text('uid'),
533
+ schemaUid: text('schema_uid'),
534
+ type: text('type'),
535
+ // schemaFileId of the models row this item belongs to (= Model.id). Disambiguates items whose
536
+ // model name exists in more than one schema; null for legacy rows that couldn't be backfilled.
537
+ modelFileId: text('model_file_id'),
538
+ publisher: text('publisher'),
539
+ attestationRaw: text('attestation_raw'),
540
+ attestationCreatedAt: int('attestation_created_at'),
541
+ createdAt: int('created_at'),
542
+ updatedAt: int('updated_at'),
543
+ _markedForDeletion: int('_marked_for_deletion'),
544
+ revokedAt: int('revoked_at'),
545
+ });
546
+
547
+ const versions = sqliteTable('versions', {
548
+ localId: text('local_id').unique(),
549
+ uid: text('uid'),
550
+ seedLocalId: text('seed_local_id'),
551
+ seedUid: text('seed_uid'),
552
+ seedType: text('seed_type'),
553
+ note: text('note'),
554
+ createdAt: int('created_at'),
555
+ updatedAt: int('updated_at'),
556
+ attestationCreatedAt: int('attestation_created_at'),
557
+ attestationRaw: text('attestation_raw'),
558
+ publisher: text('publisher'),
559
+ /**
560
+ * When the version attestation was revoked, in Unix seconds (EAS `revocationTime`, or the local
561
+ * unpublish time until sync confirms it). Null while live or unpublished.
562
+ */
563
+ revokedAt: int('revoked_at'),
564
+ });
565
+
566
+ const metadata = sqliteTable('metadata', {
567
+ localId: text('local_id').unique(),
568
+ uid: text('uid'),
569
+ propertyId: integer('property_id').references(() => properties.id),
570
+ propertyName: text('property_name'),
571
+ propertyValue: text('property_value'),
572
+ schemaUid: text('schema_uid'),
573
+ modelType: text('model_type'),
574
+ seedLocalId: text('seed_local_id'),
575
+ seedUid: text('seed_uid'),
576
+ versionLocalId: text('version_local_id'),
577
+ versionUid: text('version_uid'),
578
+ easDataType: text('eas_data_type'),
579
+ refValueType: text('ref_value_type'),
580
+ refModelUid: text('ref_schema_uid'),
581
+ refSeedType: text('ref_seed_type'),
582
+ refResolvedValue: text('ref_resolved_value'),
583
+ refResolvedDisplayValue: text('ref_resolved_display_value'),
584
+ localStorageDir: text('local_storage_dir'),
585
+ attestationRaw: text('attestation_raw'),
586
+ attestationCreatedAt: int('attestation_created_at'),
587
+ contentHash: text('content_hash'),
588
+ createdAt: int('created_at'),
589
+ updatedAt: int('updated_at'),
590
+ publisher: text('publisher'),
591
+ // Unix seconds when this row's attestation was revoked on EAS; null while it's live (or for a
592
+ // local, unpublished row). EAS sync keeps only the canonical attestation per (version, property
593
+ // schema): the newest live one, or the newest revoked one when all are revoked. So a non-null
594
+ // value marks a property kept only for its last value, not one that is present on the version.
595
+ revokedAt: int('revoked_at'),
596
+ // For a row EAS sync derived for an ItemStorage property from a `storage_transaction_id`
597
+ // attestation (uid null, ref_value_type 'file', value = the transaction id): that attestation's
598
+ // uid. Null for every other row. Marks the row as published content, not a local draft.
599
+ derivedFromUid: text('derived_from_uid'),
600
+ });
601
+
602
+ const appState = sqliteTable('appState', {
603
+ key: text('key').unique(),
604
+ value: text('value'),
605
+ createdAt: int('created_at'),
606
+ updatedAt: int('updated_at'),
607
+ });
608
+
609
+ const modelUids = sqliteTable('model_uids', {
610
+ id: int('id').primaryKey({ autoIncrement: true }),
611
+ uid: text('uid').notNull(),
612
+ modelId: int('model_id')
613
+ .notNull()
614
+ .unique()
615
+ .references(() => models.id),
616
+ });
617
+ const modelRelations = relations(modelUids, ({ one }) => ({
618
+ model: one(models),
619
+ }));
620
+
621
+ const propertyUids = sqliteTable('property_uids', {
622
+ id: int('id').primaryKey({ autoIncrement: true }),
623
+ uid: text('uid').notNull(),
624
+ propertyId: int('property_id')
625
+ .notNull()
626
+ .unique()
627
+ .references(() => properties.id),
628
+ });
629
+ const propertyUidRelations = relations(propertyUids, ({ one }) => ({
630
+ property: one(properties),
631
+ }));
632
+
633
+ const config = sqliteTable('config', {
634
+ id: integer('id').primaryKey({ autoIncrement: true }),
635
+ key: text('key').notNull(),
636
+ text: text('text'),
637
+ json: text('json'),
638
+ blob: blob('blob'),
639
+ });
640
+
641
+ const schemas = sqliteTable('schemas', {
642
+ id: integer('id').primaryKey({ autoIncrement: true }),
643
+ name: text('name').notNull(),
644
+ version: integer('version').notNull(),
645
+ schemaFileId: text('schema_file_id'), // ID from JSON file for change tracking - must be unique
646
+ schemaData: text('schema_data'), // Full JSON schema content (SchemaFileFormat as JSON string)
647
+ isDraft: integer('is_draft', { mode: 'boolean' }), // true if schema is in draft/editing state, false if published to file
648
+ isEdited: integer('is_edited', { mode: 'boolean' }), // true if schema has been edited locally, false if matches schema file
649
+ createdAt: int('created_at'),
650
+ updatedAt: int('updated_at'),
651
+ }, (table) => {
652
+ return {
653
+ uniqueSchemaFileId: unique('unique_schema_schema_file_id').on(table.schemaFileId),
204
654
  };
655
+ });
656
+
657
+ var SchemaSchema = /*#__PURE__*/Object.freeze({
658
+ __proto__: null,
659
+ schemas: schemas
660
+ });
661
+
662
+ const modelSchemas = sqliteTable('model_schemas', {
663
+ id: integer('id').primaryKey({ autoIncrement: true }),
664
+ modelId: integer('model_id').references(() => models.id),
665
+ schemaId: integer('schema_id').references(() => schemas.id),
666
+ });
667
+
668
+ var ModelSchemaSchema = /*#__PURE__*/Object.freeze({
669
+ __proto__: null,
670
+ modelSchemas: modelSchemas
671
+ });
672
+
673
+ const publishProcesses = sqliteTable('publish_processes', {
674
+ id: int('id').primaryKey({ autoIncrement: true }),
675
+ seedLocalId: text('seed_local_id').notNull(),
676
+ modelName: text('model_name').notNull(),
677
+ schemaId: text('schema_id'),
678
+ status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed' | 'interrupted'
679
+ startedAt: int('started_at').notNull(),
680
+ completedAt: int('completed_at'),
681
+ errorMessage: text('error_message'),
682
+ errorStep: text('error_step'),
683
+ errorDetails: text('error_details'),
684
+ errorCode: text('error_code'), // e.g. ManagedAccountPublishError.code
685
+ persistedSnapshot: text('persisted_snapshot').notNull(),
686
+ seedId: text('seed_id'),
687
+ existingSeedUid: text('existing_seed_uid'),
688
+ createdAt: int('created_at'),
689
+ updatedAt: int('updated_at'),
690
+ });
691
+
692
+ const uploadProcesses = sqliteTable('upload_processes', {
693
+ id: int('id').primaryKey({ autoIncrement: true }),
694
+ reimbursementConfirmed: int('reimbursement_confirmed').notNull(), // 0 or 1 for boolean
695
+ reimbursementTransactionId: text('reimbursement_transaction_id'),
696
+ transactionKeys: text('transaction_keys'),
697
+ persistedSnapshot: text('persisted_snapshot').notNull(), // JSON string
698
+ createdAt: int('created_at'),
699
+ updatedAt: int('updated_at'),
700
+ });
701
+
702
+ /** Background job: resolve L1 tx id and wait for L1 confirmation after bundler publish. */
703
+ const arweaveL1FinalizeJobs = sqliteTable('arweave_l1_finalize_jobs', {
704
+ id: int('id').primaryKey({ autoIncrement: true }),
705
+ seedLocalId: text('seed_local_id').notNull(),
706
+ dataItemId: text('data_item_id').notNull(),
707
+ /** L1 bundle / anchor transaction id from gateway GraphQL `bundledIn.id`. */
708
+ l1TransactionId: text('l1_transaction_id'),
709
+ bundleId: text('bundle_id'),
710
+ versionLocalId: text('version_local_id'),
711
+ itemPropertyName: text('item_property_name'),
712
+ /** `pending_l1` | `confirmed` | `failed` */
713
+ phase: text('phase').notNull(),
714
+ statusJson: text('status_json'),
715
+ errorMessage: text('error_message'),
716
+ createdAt: int('created_at').notNull(),
717
+ updatedAt: int('updated_at').notNull(),
718
+ }, (table) => ({
719
+ dataItemIdUnique: uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
720
+ }));
721
+
722
+ const easSyncProcesses = sqliteTable('eas_sync_processes', {
723
+ id: int('id').primaryKey({ autoIncrement: true }),
724
+ status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
725
+ startedAt: int('started_at').notNull(),
726
+ completedAt: int('completed_at'),
727
+ requestPayload: text('request_payload').notNull(),
728
+ errorMessage: text('error_message'),
729
+ errorDetails: text('error_details'),
730
+ persistedSnapshot: text('persisted_snapshot').notNull(),
731
+ createdAt: int('created_at'),
732
+ updatedAt: int('updated_at'),
733
+ });
734
+
735
+ /**
736
+ * Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
737
+ * Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
738
+ */
739
+ const htmlEmbeddedImageCoPublish = sqliteTable('html_embedded_image_co_publish', {
740
+ id: int('id').primaryKey({ autoIncrement: true }),
741
+ parentSeedLocalId: text('parent_seed_local_id').notNull(),
742
+ htmlSeedLocalId: text('html_seed_local_id').notNull(),
743
+ imageSeedLocalId: text('image_seed_local_id').notNull(),
744
+ /** Stable dedup key (e.g. sha256 of data URI or normalized URI string). */
745
+ stableKey: text('stable_key').notNull(),
746
+ createdAt: int('created_at').notNull(),
747
+ }, (t) => [
748
+ uniqueIndex('html_embed_co_pub_parent_html_stable').on(t.parentSeedLocalId, t.htmlSeedLocalId, t.stableKey),
749
+ ]);
750
+
751
+ const seedUidToStorageTransactionId = new Map();
752
+ const getStorageTransactionIdForSeedUid = async (seedUid) => {
753
+ if (seedUidToStorageTransactionId.has(seedUid)) {
754
+ return seedUidToStorageTransactionId.get(seedUid);
755
+ }
756
+ const appDb = BaseDb.getAppDb();
757
+ const results = (await appDb
758
+ .select({
759
+ storageTransactionId: metadata.propertyValue,
760
+ })
761
+ .from(metadata)
762
+ .where(and(eq(metadata.seedUid, seedUid), eq(metadata.propertyName, 'storageTransactionId'))));
763
+ if (!results || results.length === 0) {
764
+ return;
765
+ }
766
+ seedUidToStorageTransactionId.set(seedUid, results[0].storageTransactionId);
767
+ return results[0].storageTransactionId;
205
768
  };
206
- const Text = (storageType, srcDir, filenameSuffix) => PropertyConstructor(Property.Text(storageType, srcDir, filenameSuffix));
207
- const Number$1 = () => PropertyConstructor(Property.Number());
208
- const Json = () => PropertyConstructor(Property.Json());
209
- const File = () => PropertyConstructor(Property.File());
210
- const Image = () => PropertyConstructor(Property.Image());
211
- const Relation = (ref, refValueType, required) => PropertyConstructor(Property.Relation(ref, refValueType, required)); // Adjust for actual relation type
212
- const List = (refValueType, ref) => PropertyConstructor(Property.List(refValueType, ref));
213
- const Boolean = () => PropertyConstructor(Property.Boolean());
214
- const Date$1 = () => PropertyConstructor(Property.Date());
215
- const Html = (opts) => PropertyConstructor(htmlPropertyFactory(opts));
769
+
770
+ const logger$4 = debug('seedSdk:helpers:mediaRef');
771
+ /** Typical Arweave transaction id: 43 URL-safe base64 characters. */
772
+ const ARWEAVE_TX_ID = /^[a-zA-Z0-9_-]{43}$/;
773
+ function trimOrEmpty(raw) {
774
+ if (raw == null)
775
+ return '';
776
+ return typeof raw === 'string' ? raw.trim() : String(raw).trim();
777
+ }
778
+ function coalesceStringField(item, key) {
779
+ const v = item[key];
780
+ if (v == null)
781
+ return '';
782
+ if (typeof v === 'string')
783
+ return v.trim();
784
+ if (typeof v === 'number' || typeof v === 'boolean')
785
+ return String(v);
786
+ return '';
787
+ }
788
+ /**
789
+ * Try JSON relation payloads and plain relation id strings.
790
+ */
791
+ function unwrapRelationString(raw) {
792
+ const t = raw.trim();
793
+ if (!t)
794
+ return t;
795
+ try {
796
+ const parsed = JSON.parse(t);
797
+ const fromObj = normalizeRelationPropertyValue(parsed);
798
+ if (fromObj)
799
+ return fromObj;
800
+ }
801
+ catch {
802
+ // not JSON
803
+ }
804
+ return t;
805
+ }
806
+ /**
807
+ * Pure, sync classification of a media-related string from feeds or XML.
808
+ */
809
+ function classifyMediaRef(raw, options) {
810
+ const s = trimOrEmpty(raw);
811
+ if (!s) {
812
+ return { kind: 'empty' };
813
+ }
814
+ const treatAs = options?.treatAs;
815
+ if (treatAs === 'url') {
816
+ return { kind: 'url', href: s };
817
+ }
818
+ if (treatAs === 'arweaveTx') {
819
+ return { kind: 'arweaveTxId', txId: s };
820
+ }
821
+ if (treatAs === 'seedUid') {
822
+ if (s.startsWith('0x') && s.length === 66) {
823
+ return { kind: 'seedUid', uid: s };
824
+ }
825
+ return { kind: 'unknown', raw: s };
826
+ }
827
+ if (s.startsWith('http://') || s.startsWith('https://') || s.startsWith('blob:') || s.startsWith('data:')) {
828
+ if (isEasAttestationExplorerUrl(s)) {
829
+ return { kind: 'nonMediaUrl', href: s };
830
+ }
831
+ return { kind: 'url', href: s };
832
+ }
833
+ const unwrapped = unwrapRelationString(s);
834
+ const ids = resolveSeedIdsFromRefString(unwrapped);
835
+ if (ids.seedUid) {
836
+ return { kind: 'seedUid', uid: ids.seedUid };
837
+ }
838
+ if (ids.seedLocalId) {
839
+ return { kind: 'seedLocalId', localId: ids.seedLocalId };
840
+ }
841
+ if (unwrapped.startsWith('0x') && unwrapped.length === 66) {
842
+ return { kind: 'seedUid', uid: unwrapped };
843
+ }
844
+ if (ARWEAVE_TX_ID.test(unwrapped) && !unwrapped.startsWith('0x')) {
845
+ return { kind: 'arweaveTxId', txId: unwrapped };
846
+ }
847
+ return { kind: 'unknown', raw: s };
848
+ }
849
+ /**
850
+ * Same as convertTxIdToImage but local to this module to avoid circular imports with helpers/index.
851
+ */
852
+ async function tryLocalBlobUrlFromTxId(txId) {
853
+ const imageFilePath = BaseFileManager.getFilesPath('images', txId);
854
+ const fileExists = await BaseFileManager.pathExists(imageFilePath);
855
+ if (!fileExists) {
856
+ logger$4(`[tryLocalBlobUrlFromTxId] ${imageFilePath} does not exist`);
857
+ return undefined;
858
+ }
859
+ const buffer = await BaseFileManager.readFileAsBuffer(imageFilePath);
860
+ let arrayBuffer;
861
+ if (buffer instanceof Blob) {
862
+ arrayBuffer = await buffer.arrayBuffer();
863
+ }
864
+ else if (buffer instanceof ArrayBuffer) {
865
+ arrayBuffer = buffer;
866
+ }
867
+ else {
868
+ const sliced = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
869
+ if (sliced instanceof SharedArrayBuffer) {
870
+ const uint8Array = new Uint8Array(sliced);
871
+ arrayBuffer = uint8Array.buffer.slice(0);
872
+ }
873
+ else {
874
+ arrayBuffer = sliced;
875
+ }
876
+ }
877
+ const uint = new Uint8Array(arrayBuffer);
878
+ const imageBlob = new Blob([uint]);
879
+ return URL.createObjectURL(imageBlob);
880
+ }
881
+ async function resolveTxId(txId) {
882
+ const local = await tryLocalBlobUrlFromTxId(txId);
883
+ if (local) {
884
+ return { status: 'ready', href: local, source: 'localBlob' };
885
+ }
886
+ return {
887
+ status: 'ready',
888
+ href: BaseArweaveClient.getRawUrl(txId),
889
+ source: 'gateway',
890
+ };
891
+ }
892
+ /**
893
+ * Resolve a classified media reference to a display URL (https/blob/data), using local files when present.
894
+ */
895
+ async function resolveMediaRef(raw, options) {
896
+ const classification = classifyMediaRef(raw, options);
897
+ switch (classification.kind) {
898
+ case 'empty':
899
+ return { status: 'empty' };
900
+ case 'url':
901
+ return {
902
+ status: 'ready',
903
+ href: classification.href,
904
+ source: 'direct',
905
+ };
906
+ case 'nonMediaUrl':
907
+ return {
908
+ status: 'unresolved',
909
+ reason: 'non_media_url',
910
+ classification,
911
+ };
912
+ case 'seedLocalId':
913
+ return {
914
+ status: 'unresolved',
915
+ reason: 'seed_local_id_not_portable',
916
+ classification,
917
+ };
918
+ case 'unknown':
919
+ return {
920
+ status: 'unresolved',
921
+ reason: 'unknown_ref',
922
+ classification,
923
+ };
924
+ case 'arweaveTxId':
925
+ return resolveTxId(classification.txId);
926
+ case 'seedUid': {
927
+ const appDb = BaseDb.getAppDb();
928
+ if (!appDb) {
929
+ return {
930
+ status: 'unresolved',
931
+ reason: 'seed_uid_requires_app_db',
932
+ classification,
933
+ };
934
+ }
935
+ const storageTransactionId = await getStorageTransactionIdForSeedUid(classification.uid);
936
+ if (!storageTransactionId) {
937
+ return {
938
+ status: 'unresolved',
939
+ reason: 'seed_uid_no_storage_transaction',
940
+ classification,
941
+ };
942
+ }
943
+ return resolveTxId(storageTransactionId);
944
+ }
945
+ default:
946
+ return {
947
+ status: 'unresolved',
948
+ reason: 'unknown_ref',
949
+ classification,
950
+ };
951
+ }
952
+ }
953
+ /**
954
+ * Read a string field from a parsed item, trying camelCase and snake_case keys.
955
+ */
956
+ function getFeedItemStringField(item, key) {
957
+ const direct = coalesceStringField(item, key);
958
+ if (direct)
959
+ return direct;
960
+ const snake = key.replace(/[A-Z]/g, (l) => `_${l.toLowerCase()}`);
961
+ if (snake !== key) {
962
+ const alt = coalesceStringField(item, snake);
963
+ if (alt)
964
+ return alt;
965
+ }
966
+ const parts = key.split('_');
967
+ if (parts.length > 1) {
968
+ const camel = parts[0] + parts.slice(1).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join('');
969
+ const alt2 = coalesceStringField(item, camel);
970
+ if (alt2)
971
+ return alt2;
972
+ }
973
+ return '';
974
+ }
975
+ /**
976
+ * Apply a field manifest to a plain feed item: classify media/file fields; pass through html/text.
977
+ */
978
+ function normalizeFeedItemFields(item, manifest) {
979
+ const out = {};
980
+ for (const [fieldKey, descriptor] of Object.entries(manifest)) {
981
+ const raw = getFeedItemStringField(item, fieldKey);
982
+ if (!raw) {
983
+ out[fieldKey] = undefined;
984
+ continue;
985
+ }
986
+ if (descriptor.role === 'html') {
987
+ out[fieldKey] = { role: 'html', raw };
988
+ continue;
989
+ }
990
+ if (descriptor.role === 'text') {
991
+ out[fieldKey] = { role: 'text', raw };
992
+ continue;
993
+ }
994
+ const classification = classifyMediaRef(raw, { treatAs: descriptor.treatAs });
995
+ out[fieldKey] = {
996
+ role: descriptor.role,
997
+ raw,
998
+ classification,
999
+ };
1000
+ }
1001
+ return out;
1002
+ }
216
1003
 
217
1004
  class SeedEventEmitter {
218
1005
  constructor() {
@@ -254,18 +1041,39 @@ class SeedEventEmitter {
254
1041
  this.listeners.delete(event);
255
1042
  return this;
256
1043
  }
1044
+ /**
1045
+ * Calls every listener. A listener that throws is logged and skipped: the others still
1046
+ * run, and the error never reaches the SDK code that emitted the event (which may be
1047
+ * midway through a save).
1048
+ */
257
1049
  emit(event, ...args) {
258
1050
  const set = this.listeners.get(event);
259
1051
  if (!set || set.size === 0)
260
1052
  return false;
261
1053
  for (const listener of [...set]) {
262
- listener(...args);
1054
+ try {
1055
+ listener(...args);
1056
+ }
1057
+ catch (error) {
1058
+ console.error(`[seed] listener for "${String(event)}" threw:`, error);
1059
+ }
263
1060
  }
264
1061
  return true;
265
1062
  }
266
1063
  }
267
1064
  const eventEmitter = new SeedEventEmitter();
268
1065
 
1066
+ let refresher;
1067
+ function setCachedPropertyRefresher(fn) {
1068
+ refresher = fn;
1069
+ }
1070
+ /** Give cached ModelProperty instances of these properties their rows' current values. */
1071
+ async function refreshCachedProperties(propertyFileIds) {
1072
+ if (!refresher || propertyFileIds.length === 0)
1073
+ return;
1074
+ await refresher(propertyFileIds);
1075
+ }
1076
+
269
1077
  /**
270
1078
  * Detect SQLite UNIQUE constraint failures across better-sqlite3 and drizzle/wasm wrappers.
271
1079
  * Drizzle often surfaces `Failed query: insert into...` without "UNIQUE constraint" on message,
@@ -406,7 +1214,7 @@ const modelNamesForNameOrType = async (nameOrType, db) => {
406
1214
  const rows = (await db.selectDistinct({ name: models.name }).from(models));
407
1215
  return rows
408
1216
  .map((r) => r.name)
409
- .filter((name) => name === nameOrType || name === pascal || toSnakeCase(name) === nameOrType);
1217
+ .filter((name) => name === nameOrType || name === pascal || toSnakeCase$1(name) === nameOrType);
410
1218
  };
411
1219
  /**
412
1220
  * resolveModelRecord for a model name **or** an EAS model type (snake_case model name, what sync
@@ -619,7 +1427,7 @@ function linkModelToSchema(db, modelId, schemaId) {
619
1427
  return current;
620
1428
  }
621
1429
 
622
- const logger = debug('seedSdk:helpers:db');
1430
+ const logger$3 = debug('seedSdk:helpers:db');
623
1431
  /**
624
1432
  * The `properties` storage columns for a property definition, in either the internal shape
625
1433
  * (`storageType`, `localStorageDir`, `filenameSuffix`) or the schema-file shape
@@ -725,7 +1533,7 @@ async function getItemStoragePropertiesForModel(modelNameOrType, scope = {}) {
725
1533
  async function migrateMetadataForPropertyRename(modelName, oldPropertyName, newPropertyName, propertySchemaFileId, scope = {}) {
726
1534
  const db = BaseDb.getAppDb();
727
1535
  if (!db) {
728
- logger('[migrateMetadataForPropertyRename] Database not available, skipping');
1536
+ logger$3('[migrateMetadataForPropertyRename] Database not available, skipping');
729
1537
  return 0;
730
1538
  }
731
1539
  // Find the property row by schemaFileId (preferred) or by name
@@ -737,7 +1545,7 @@ async function migrateMetadataForPropertyRename(modelName, oldPropertyName, newP
737
1545
  propertyId = await getPropertyIdForModelAndName(modelName, oldPropertyName, scope);
738
1546
  }
739
1547
  if (propertyId == null) {
740
- logger(`[migrateMetadataForPropertyRename] Property not found: ${modelName}.${oldPropertyName}, skipping`);
1548
+ logger$3(`[migrateMetadataForPropertyRename] Property not found: ${modelName}.${oldPropertyName}, skipping`);
741
1549
  return 0;
742
1550
  }
743
1551
  // Primary path: update metadata by propertyId
@@ -753,7 +1561,7 @@ async function migrateMetadataForPropertyRename(modelName, oldPropertyName, newP
753
1561
  .where(eq(metadata.propertyId, propertyId));
754
1562
  }
755
1563
  // Fallback: update metadata with null propertyId (legacy rows) by propertyName + modelType
756
- const modelType = toSnakeCase(modelName);
1564
+ const modelType = toSnakeCase$1(modelName);
757
1565
  const toUpdateByFallback = await db
758
1566
  .select({ localId: metadata.localId })
759
1567
  .from(metadata)
@@ -766,11 +1574,11 @@ async function migrateMetadataForPropertyRename(modelName, oldPropertyName, newP
766
1574
  .where(and(eq(metadata.propertyName, oldPropertyName), eq(metadata.modelType, modelType), isNull(metadata.propertyId)));
767
1575
  }
768
1576
  if (updatedByFallback > 0) {
769
- logger(`[migrateMetadataForPropertyRename] Fallback updated ${updatedByFallback} rows (propertyId was null)`);
1577
+ logger$3(`[migrateMetadataForPropertyRename] Fallback updated ${updatedByFallback} rows (propertyId was null)`);
770
1578
  }
771
1579
  const total = updatedByPropertyId + updatedByFallback;
772
1580
  if (total > 0) {
773
- logger(`[migrateMetadataForPropertyRename] Migrated ${total} metadata rows for ${modelName}.${oldPropertyName} -> ${newPropertyName}`);
1581
+ logger$3(`[migrateMetadataForPropertyRename] Migrated ${total} metadata rows for ${modelName}.${oldPropertyName} -> ${newPropertyName}`);
774
1582
  }
775
1583
  return total;
776
1584
  }
@@ -919,7 +1727,7 @@ const findOrCreateModelRecord = async (db, modelName, modelFileId, schemaId) =>
919
1727
  .set({ schemaFileId: modelFileId, isEdited: false })
920
1728
  .where(eq(models.id, chosen.id));
921
1729
  chosen = { ...chosen, schemaFileId: modelFileId, isEdited: false };
922
- logger(`Adopted existing model "${modelName}" (id: ${chosen.id}) with schemaFileId "${modelFileId}"`);
1730
+ logger$3(`Adopted existing model "${modelName}" (id: ${chosen.id}) with schemaFileId "${modelFileId}"`);
923
1731
  }
924
1732
  if (chosen) {
925
1733
  return chosen;
@@ -1190,7 +1998,7 @@ const addSchemaToDb = async (schema, schemaFileId, schemaData, isDraft, isEdited
1190
1998
  .limit(1);
1191
1999
  if (draftSchemas.length > 0) {
1192
2000
  // Found a draft - we'll update it to non-draft below
1193
- logger(`Found draft schema "${schema.name}" with schemaFileId "${draftSchemas[0].schemaFileId}", will update to non-draft with schemaFileId "${schemaFileId}"`);
2001
+ logger$3(`Found draft schema "${schema.name}" with schemaFileId "${draftSchemas[0].schemaFileId}", will update to non-draft with schemaFileId "${schemaFileId}"`);
1194
2002
  existingSchemas = draftSchemas;
1195
2003
  }
1196
2004
  }
@@ -1210,11 +2018,11 @@ const addSchemaToDb = async (schema, schemaFileId, schemaData, isDraft, isEdited
1210
2018
  !existingSchemas[0].schemaFileId ||
1211
2019
  (isDraft === false && existingSchemas[0].isDraft === true);
1212
2020
  if (shouldUpdate) {
1213
- logger(`Updating schemaFileId from "${existingSchemas[0].schemaFileId}" to "${schemaFileId}" for schema "${schema.name}"`);
2021
+ logger$3(`Updating schemaFileId from "${existingSchemas[0].schemaFileId}" to "${schemaFileId}" for schema "${schema.name}"`);
1214
2022
  updates.schemaFileId = schemaFileId;
1215
2023
  }
1216
2024
  else {
1217
- logger(`Preserving existing schemaFileId "${existingSchemas[0].schemaFileId}" for non-draft schema "${schema.name}" (new schemaFileId "${schemaFileId}" would overwrite it)`);
2025
+ logger$3(`Preserving existing schemaFileId "${existingSchemas[0].schemaFileId}" for non-draft schema "${schema.name}" (new schemaFileId "${schemaFileId}" would overwrite it)`);
1218
2026
  }
1219
2027
  }
1220
2028
  // Always update name if it's different (handles name changes)
@@ -1241,16 +2049,16 @@ const addSchemaToDb = async (schema, schemaFileId, schemaData, isDraft, isEdited
1241
2049
  updates.updatedAt = schema.updatedAt;
1242
2050
  }
1243
2051
  if (Object.keys(updates).length > 0) {
1244
- logger(`Applying updates to schema "${schema.name}" (id: ${existingSchemas[0].id}):`, Object.keys(updates));
2052
+ logger$3(`Applying updates to schema "${schema.name}" (id: ${existingSchemas[0].id}):`, Object.keys(updates));
1245
2053
  await db
1246
2054
  .update(schemas)
1247
2055
  .set(updates)
1248
2056
  .where(eq(schemas.id, existingSchemas[0].id));
1249
2057
  const updated = { ...existingSchemas[0], ...updates };
1250
- logger(`Schema "${schema.name}" updated. New schemaFileId: "${updated.schemaFileId}", isDraft: ${updated.isDraft}`);
2058
+ logger$3(`Schema "${schema.name}" updated. New schemaFileId: "${updated.schemaFileId}", isDraft: ${updated.isDraft}`);
1251
2059
  return updated;
1252
2060
  }
1253
- logger(`No updates needed for schema "${schema.name}" (id: ${existingSchemas[0].id})`);
2061
+ logger$3(`No updates needed for schema "${schema.name}" (id: ${existingSchemas[0].id})`);
1254
2062
  return existingSchemas[0];
1255
2063
  }
1256
2064
  const newSchema = await db.insert(schemas).values({
@@ -1286,9 +2094,7 @@ const renameModelInDb = async (oldName, newName, schemaNameOrId) => {
1286
2094
  if (!db) {
1287
2095
  throw new Error('Database not found');
1288
2096
  }
1289
- const _mod_0 = await import('./BasePathResolver-CfSfMW5_.js');
1290
- const _ns_0 = _mod_0.Q;
1291
- const { schemas: schemasTable } = _ns_0;
2097
+ const { schemas: schemasTable } = await Promise.resolve().then(function () { return SchemaSchema; });
1292
2098
  // Find the model by old name, optionally scoped by schema
1293
2099
  let existingModels;
1294
2100
  if (schemaNameOrId !== undefined) {
@@ -1435,7 +2241,7 @@ modelId) {
1435
2241
  // Compare database value with schema file value
1436
2242
  // If they differ, the property has been edited
1437
2243
  if (dbProperty.dataType !== schemaFileValue.dataType) {
1438
- logger(`Property ${modelName}:${propertyName} has been edited (dataType differs: DB=${dbProperty.dataType}, Schema=${schemaFileValue.dataType})`);
2244
+ logger$3(`Property ${modelName}:${propertyName} has been edited (dataType differs: DB=${dbProperty.dataType}, Schema=${schemaFileValue.dataType})`);
1439
2245
  return true;
1440
2246
  }
1441
2247
  // Check refModelId if it's a relation
@@ -1444,19 +2250,19 @@ modelId) {
1444
2250
  if (refModelRecord) {
1445
2251
  const expectedRefModelId = refModelRecord.id;
1446
2252
  if (dbProperty.refModelId !== expectedRefModelId) {
1447
- logger(`Property ${modelName}:${propertyName} has been edited (refModelId differs)`);
2253
+ logger$3(`Property ${modelName}:${propertyName} has been edited (refModelId differs)`);
1448
2254
  return true;
1449
2255
  }
1450
2256
  }
1451
2257
  }
1452
2258
  else if (dbProperty.refModelId !== null) {
1453
2259
  // Schema file has no ref, but DB has one
1454
- logger(`Property ${modelName}:${propertyName} has been edited (refModelId differs)`);
2260
+ logger$3(`Property ${modelName}:${propertyName} has been edited (refModelId differs)`);
1455
2261
  return true;
1456
2262
  }
1457
2263
  // Check refValueType
1458
2264
  if (dbProperty.refValueType !== (schemaFileValue.refValueType || null)) {
1459
- logger(`Property ${modelName}:${propertyName} has been edited (refValueType differs)`);
2265
+ logger$3(`Property ${modelName}:${propertyName} has been edited (refValueType differs)`);
1460
2266
  return true;
1461
2267
  }
1462
2268
  // Check required (for Relation/Image properties)
@@ -1464,7 +2270,7 @@ modelId) {
1464
2270
  const schemaRequired = !!schemaFileValue.required;
1465
2271
  const dbRequired = dbProperty.required === true;
1466
2272
  if (dbRequired !== schemaRequired) {
1467
- logger(`Property ${modelName}:${propertyName} has been edited (required differs: DB=${dbRequired}, Schema=${schemaRequired})`);
2273
+ logger$3(`Property ${modelName}:${propertyName} has been edited (required differs: DB=${dbRequired}, Schema=${schemaRequired})`);
1468
2274
  return true;
1469
2275
  }
1470
2276
  }
@@ -1480,7 +2286,7 @@ modelId) {
1480
2286
  if (dbStorage.storageType !== fileStorage.storageType ||
1481
2287
  dbStorage.localStorageDir !== fileStorage.localStorageDir ||
1482
2288
  dbStorage.filenameSuffix !== fileStorage.filenameSuffix) {
1483
- logger(`Property ${modelName}:${propertyName} has been edited (storage settings differ)`);
2289
+ logger$3(`Property ${modelName}:${propertyName} has been edited (storage settings differ)`);
1484
2290
  return true;
1485
2291
  }
1486
2292
  }
@@ -1492,7 +2298,7 @@ modelId) {
1492
2298
  }
1493
2299
  catch (error) {
1494
2300
  // If we can't check, assume it's not edited to be safe
1495
- logger('Error checking if property is edited:', error);
2301
+ logger$3('Error checking if property is edited:', error);
1496
2302
  return false;
1497
2303
  }
1498
2304
  }
@@ -1517,11 +2323,11 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1517
2323
  // SchemaType includes id, so check if it's set
1518
2324
  if (schema.id !== null && schema.id !== undefined) {
1519
2325
  schemaRecord = schema;
1520
- logger(`Using existing schema record with id: ${schemaRecord.id}`);
2326
+ logger$3(`Using existing schema record with id: ${schemaRecord.id}`);
1521
2327
  }
1522
2328
  else {
1523
2329
  schemaRecord = await addSchemaToDb(schema, schemaFileData?.schemaFileId);
1524
- logger(`Created/found schema record with id: ${schemaRecord.id}`);
2330
+ logger$3(`Created/found schema record with id: ${schemaRecord.id}`);
1525
2331
  }
1526
2332
  }
1527
2333
  // Handle model renames first if provided
@@ -1534,6 +2340,8 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1534
2340
  // Search for all models by schemaFileId (preferred) or name and create them if they don't exist
1535
2341
  const modelRecords = new Map();
1536
2342
  const modelProcessingErrors = [];
2343
+ // Property rows this call changed, so cached ModelProperty instances can be given the new values
2344
+ const updatedPropertyFileIds = [];
1537
2345
  for (const [modelName, modelClass] of Object.entries(models$1)) {
1538
2346
  try {
1539
2347
  const modelFileId = schemaFileData?.modelFileIds?.get(modelName);
@@ -1547,7 +2355,7 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1547
2355
  .where(eq(models.schemaFileId, modelFileId))
1548
2356
  .limit(1);
1549
2357
  if (existingWithFileId.length > 0 && existingWithFileId[0].id !== modelRecord.id) {
1550
- logger(`WARNING: Model "${modelName}" (id: ${modelRecord.id}) conflicts with existing model "${existingWithFileId[0].name}" (id: ${existingWithFileId[0].id}) both trying to use schemaFileId "${modelFileId}"`);
2358
+ logger$3(`WARNING: Model "${modelName}" (id: ${modelRecord.id}) conflicts with existing model "${existingWithFileId[0].name}" (id: ${existingWithFileId[0].id}) both trying to use schemaFileId "${modelFileId}"`);
1551
2359
  modelRecord = existingWithFileId[0];
1552
2360
  }
1553
2361
  else if (!modelRecord.schemaFileId) {
@@ -1575,8 +2383,14 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1575
2383
  const pendingProperties = modelContext._pendingPropertyDefinitions || {};
1576
2384
  // If context properties are empty, try modelClass.properties (for backward compatibility)
1577
2385
  // but convert ModelProperty instances to object format
2386
+ // Property definitions read from the schema file win: a cached Model keeps the properties it
2387
+ // was created with, so after a rename its context still has the old name.
2388
+ const filePropertyDefinitions = schemaFileData?.propertyDefinitions?.get(modelName);
1578
2389
  let schema = {};
1579
- if (Object.keys(contextProperties).length > 0) {
2390
+ if (filePropertyDefinitions) {
2391
+ schema = filePropertyDefinitions;
2392
+ }
2393
+ else if (Object.keys(contextProperties).length > 0) {
1580
2394
  schema = contextProperties;
1581
2395
  }
1582
2396
  else if (Object.keys(pendingProperties).length > 0) {
@@ -1600,14 +2414,13 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1600
2414
  }
1601
2415
  // Get property schemaFileId if available
1602
2416
  let propertyFileId = schemaFileData?.propertyFileIds?.get(modelName)?.get(propertyName);
2417
+ const propertyFileIdGenerated = !propertyFileId;
1603
2418
  // If no propertyFileId from map, generate a random ID
1604
2419
  // IDs should be generated in the import process before calling addModelsToDb
1605
2420
  if (!propertyFileId) {
1606
- const _mod_1 = await import('./tabEvents-DguZpCCv.js');
1607
- const _ns_1 = _mod_1.Z;
1608
- const { generateId } = _ns_1;
2421
+ const { generateId } = await Promise.resolve().then(function () { return generateId$1; });
1609
2422
  propertyFileId = generateId();
1610
- logger(`Generated propertyFileId "${propertyFileId}" for property "${modelName}:${propertyName}" (not found in propertyFileIds map)`);
2423
+ logger$3(`Generated propertyFileId "${propertyFileId}" for property "${modelName}:${propertyName}" (not found in propertyFileIds map)`);
1611
2424
  }
1612
2425
  // First, try to find by schemaFileId (preferred for change tracking)
1613
2426
  let existingProperty;
@@ -1674,7 +2487,7 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1674
2487
  if (potentialMatches.length > 0) {
1675
2488
  const matchedProperty = potentialMatches[0];
1676
2489
  existingProperty = matchedProperty;
1677
- logger(`Found renamed property: ${modelName}:${matchedProperty.name} -> ${propertyName} (matched by characteristics)`);
2490
+ logger$3(`Found renamed property: ${modelName}:${matchedProperty.name} -> ${propertyName} (matched by characteristics)`);
1678
2491
  }
1679
2492
  }
1680
2493
  if (existingProperty) {
@@ -1695,7 +2508,7 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1695
2508
  }, modelRecord.id);
1696
2509
  if (isPropertyEdited) {
1697
2510
  // Property has been locally edited - skip update to preserve local changes
1698
- logger(`Skipping update for property ${modelName}:${existingProperty.name} -> ${propertyName} - it has been locally edited and will be preserved`);
2511
+ logger$3(`Skipping update for property ${modelName}:${existingProperty.name} -> ${propertyName} - it has been locally edited and will be preserved`);
1699
2512
  continue;
1700
2513
  }
1701
2514
  // Property exists (possibly with different name) - update it with new values from schema file
@@ -1703,6 +2516,10 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1703
2516
  // Ensure schemaFileId is updated if we have it
1704
2517
  // Preserve existing isEdited value if it was true (local edits take precedence)
1705
2518
  const updateData = { ...propertyData };
2519
+ // A generated id must not replace the one the row already has from its schema file
2520
+ if (propertyFileIdGenerated && existingProperty.schemaFileId) {
2521
+ updateData.schemaFileId = existingProperty.schemaFileId;
2522
+ }
1706
2523
  if (existingProperty.isEdited === true) {
1707
2524
  // Preserve isEdited = true if property was locally edited
1708
2525
  delete updateData.isEdited;
@@ -1726,6 +2543,9 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1726
2543
  .update(properties)
1727
2544
  .set(updateData)
1728
2545
  .where(eq(properties.id, existingProperty.id));
2546
+ const updatedFileId = updateData.schemaFileId ?? existingProperty.schemaFileId;
2547
+ if (updatedFileId)
2548
+ updatedPropertyFileIds.push(updatedFileId);
1729
2549
  }
1730
2550
  }
1731
2551
  else {
@@ -1746,18 +2566,18 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1746
2566
  if (existingByFileId.length > 0) {
1747
2567
  const found = existingByFileId[0];
1748
2568
  matchedDbPropertyIds.add(found.id);
1749
- logger(`Property ${modelName}:${propertyName} already exists by schemaFileId "${propertyFileId}" (id: ${found.id}), skipping insert`);
2569
+ logger$3(`Property ${modelName}:${propertyName} already exists by schemaFileId "${propertyFileId}" (id: ${found.id}), skipping insert`);
1750
2570
  continue;
1751
2571
  }
1752
2572
  }
1753
- logger(`Creating new property ${modelName}:${propertyName} with schemaFileId: ${propertyData.schemaFileId}`);
2573
+ logger$3(`Creating new property ${modelName}:${propertyName} with schemaFileId: ${propertyData.schemaFileId}`);
1754
2574
  try {
1755
2575
  await db.insert(properties).values(propertyDataWithIsEdited);
1756
2576
  }
1757
2577
  catch (insertError) {
1758
2578
  // Treat UNIQUE constraint as success - property already exists (e.g. from concurrent addModelsToDb call)
1759
2579
  if (isSqliteUniqueConstraintError(insertError)) {
1760
- logger(`Property ${modelName}:${propertyName} already exists (UNIQUE constraint), treating as success`);
2580
+ logger$3(`Property ${modelName}:${propertyName} already exists (UNIQUE constraint), treating as success`);
1761
2581
  }
1762
2582
  else {
1763
2583
  throw insertError;
@@ -1768,14 +2588,14 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1768
2588
  }
1769
2589
  catch (error) {
1770
2590
  const errorMessage = error?.message || String(error);
1771
- logger(`Error processing model "${modelName}": ${errorMessage}`);
2591
+ logger$3(`Error processing model "${modelName}": ${errorMessage}`);
1772
2592
  modelProcessingErrors.push({ modelName, error: errorMessage });
1773
2593
  // Continue processing other models even if one fails
1774
2594
  }
1775
2595
  }
1776
2596
  if (modelProcessingErrors.length > 0) {
1777
2597
  console.warn(`[addModelsToDb] Errors occurred while processing ${modelProcessingErrors.length} model(s):`, modelProcessingErrors.map(e => `${e.modelName}: ${e.error}`).join('; '));
1778
- logger(`Errors processing models: ${modelProcessingErrors.map(e => e.modelName).join(', ')}`);
2598
+ logger$3(`Errors processing models: ${modelProcessingErrors.map(e => e.modelName).join(', ')}`);
1779
2599
  }
1780
2600
  // If schema was provided, create modelSchema join records to connect models to the schema
1781
2601
  if (schemaRecord && schemaRecord.id) {
@@ -1783,7 +2603,7 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1783
2603
  .filter(([, r]) => r.id)
1784
2604
  .map(([name, r]) => ({ modelName: name, modelId: r.id }));
1785
2605
  if (modelIds.length === 0) {
1786
- logger('No model IDs to link, skipping schema linking');
2606
+ logger$3('No model IDs to link, skipping schema linking');
1787
2607
  }
1788
2608
  else {
1789
2609
  // Single batch query: get all existing joins for this schema
@@ -1797,14 +2617,16 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1797
2617
  for (const { modelName, modelId } of toInsert) {
1798
2618
  if (!(await linkModelToSchema(db, modelId, schemaRecord.id)))
1799
2619
  continue;
1800
- logger(`Created join table entry for model ${modelName} (id: ${modelId}) to schema (id: ${schemaRecord.id})`);
2620
+ logger$3(`Created join table entry for model ${modelName} (id: ${modelId}) to schema (id: ${schemaRecord.id})`);
1801
2621
  }
1802
2622
  }
1803
2623
  }
1804
2624
  }
1805
2625
  else if (schemaRecord && !schemaRecord.id) {
1806
- logger(`Warning: schemaRecord provided but has no id, cannot create join table entries`);
2626
+ logger$3(`Warning: schemaRecord provided but has no id, cannot create join table entries`);
1807
2627
  }
2628
+ // A cached instance is otherwise never re-read from its row (createById returns it as is)
2629
+ await refreshCachedProperties(updatedPropertyFileIds);
1808
2630
  };
1809
2631
  /**
1810
2632
  * Loads models from the database for a given schema by querying the model_schemas join table.
@@ -1816,7 +2638,7 @@ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) =>
1816
2638
  const loadModelsFromDbForSchema = async (schemaId) => {
1817
2639
  const db = BaseDb.getAppDb();
1818
2640
  if (!db) {
1819
- logger('Database not found, cannot load models from DB');
2641
+ logger$3('Database not found, cannot load models from DB');
1820
2642
  return {};
1821
2643
  }
1822
2644
  try {
@@ -1885,11 +2707,11 @@ const loadModelsFromDbForSchema = async (schemaId) => {
1885
2707
  // or reconstructed from schemaData if available
1886
2708
  };
1887
2709
  }
1888
- logger(`Loaded ${Object.keys(models$1).length} models from database for schema ${schemaId}`);
2710
+ logger$3(`Loaded ${Object.keys(models$1).length} models from database for schema ${schemaId}`);
1889
2711
  return models$1;
1890
2712
  }
1891
2713
  catch (error) {
1892
- logger(`Error loading models from database for schema ${schemaId}:`, error);
2714
+ logger$3(`Error loading models from database for schema ${schemaId}:`, error);
1893
2715
  return {};
1894
2716
  }
1895
2717
  };
@@ -2006,34 +2828,34 @@ const savePropertyToDb = async (property) => {
2006
2828
  // Find existing property - try multiple strategies to handle name changes
2007
2829
  // 1. First try by schemaFileId (most reliable - doesn't change when name changes)
2008
2830
  let existingProperties = [];
2009
- logger(`[savePropertyToDb] Looking for property ${property.modelName}:${property.name} (schemaFileId: ${schemaFileId}, originalName: ${property._originalValues?.name})`);
2831
+ logger$3(`[savePropertyToDb] Looking for property ${property.modelName}:${property.name} (schemaFileId: ${schemaFileId}, originalName: ${property._originalValues?.name})`);
2010
2832
  if (schemaFileId) {
2011
2833
  existingProperties = await db
2012
2834
  .select()
2013
2835
  .from(properties)
2014
2836
  .where(and(eq(properties.schemaFileId, schemaFileId), eq(properties.modelId, modelRecord.id)))
2015
2837
  .limit(1);
2016
- logger(`[savePropertyToDb] Found ${existingProperties.length} properties by schemaFileId`);
2838
+ logger$3(`[savePropertyToDb] Found ${existingProperties.length} properties by schemaFileId`);
2017
2839
  }
2018
2840
  // 2. If not found by schemaFileId, try by original name (if name was changed)
2019
2841
  if (existingProperties.length === 0 && property._originalValues?.name && property._originalValues.name !== property.name) {
2020
- logger(`[savePropertyToDb] Trying to find by original name: ${property._originalValues.name}`);
2842
+ logger$3(`[savePropertyToDb] Trying to find by original name: ${property._originalValues.name}`);
2021
2843
  existingProperties = await db
2022
2844
  .select()
2023
2845
  .from(properties)
2024
2846
  .where(and(eq(properties.name, property._originalValues.name), eq(properties.modelId, modelRecord.id)))
2025
2847
  .limit(1);
2026
- logger(`[savePropertyToDb] Found ${existingProperties.length} properties by original name`);
2848
+ logger$3(`[savePropertyToDb] Found ${existingProperties.length} properties by original name`);
2027
2849
  }
2028
2850
  // 3. Fallback: try by current name
2029
2851
  if (existingProperties.length === 0) {
2030
- logger(`[savePropertyToDb] Trying to find by current name: ${property.name}`);
2852
+ logger$3(`[savePropertyToDb] Trying to find by current name: ${property.name}`);
2031
2853
  existingProperties = await db
2032
2854
  .select()
2033
2855
  .from(properties)
2034
2856
  .where(and(eq(properties.name, property.name), eq(properties.modelId, modelRecord.id)))
2035
2857
  .limit(1);
2036
- logger(`[savePropertyToDb] Found ${existingProperties.length} properties by current name`);
2858
+ logger$3(`[savePropertyToDb] Found ${existingProperties.length} properties by current name`);
2037
2859
  }
2038
2860
  // Prepare property data
2039
2861
  const propertyData = {
@@ -2082,7 +2904,7 @@ const savePropertyToDb = async (property) => {
2082
2904
  isEdited: true, // Mark as edited when saving changes
2083
2905
  })
2084
2906
  .where(eq(properties.id, existingProperty.id));
2085
- logger(`Updated property ${property.modelName}:${property._originalValues?.name || 'unknown'} -> ${property.name} in database`);
2907
+ logger$3(`Updated property ${property.modelName}:${property._originalValues?.name || 'unknown'} -> ${property.name} in database`);
2086
2908
  }
2087
2909
  else {
2088
2910
  // Property doesn't exist, create it
@@ -2092,12 +2914,12 @@ const savePropertyToDb = async (property) => {
2092
2914
  ...propertyData,
2093
2915
  isEdited: true, // Runtime-created properties are edited
2094
2916
  });
2095
- logger(`Created property ${property.modelName}:${property.name} in database`);
2917
+ logger$3(`Created property ${property.modelName}:${property.name} in database`);
2096
2918
  }
2097
2919
  catch (insertError) {
2098
2920
  // Treat UNIQUE constraint as success - property already exists (e.g. from concurrent addModelsToDb or race)
2099
2921
  if (isSqliteUniqueConstraintError(insertError)) {
2100
- logger(`Property ${property.modelName}:${property.name} already exists (UNIQUE constraint), treating as success`);
2922
+ logger$3(`Property ${property.modelName}:${property.name} already exists (UNIQUE constraint), treating as success`);
2101
2923
  }
2102
2924
  else {
2103
2925
  throw insertError;
@@ -2214,7 +3036,7 @@ async function writeModelToDb(modelFileId, data) {
2214
3036
  if (doubleCheck.length > 0) {
2215
3037
  // Another process created it, use existing
2216
3038
  modelId = doubleCheck[0].id;
2217
- logger(`Model with schemaFileId "${modelFileId}" was created by another process, using existing record (id: ${modelId})`);
3039
+ logger$3(`Model with schemaFileId "${modelFileId}" was created by another process, using existing record (id: ${modelId})`);
2218
3040
  }
2219
3041
  else {
2220
3042
  try {
@@ -2228,7 +3050,7 @@ async function writeModelToDb(modelFileId, data) {
2228
3050
  catch (error) {
2229
3051
  // Handle unique constraint violation
2230
3052
  if (isSqliteUniqueConstraintError(error)) {
2231
- logger(`Unique constraint violation for schemaFileId "${modelFileId}", attempting to find existing model`);
3053
+ logger$3(`Unique constraint violation for schemaFileId "${modelFileId}", attempting to find existing model`);
2232
3054
  const existing = await db
2233
3055
  .select()
2234
3056
  .from(models)
@@ -2236,7 +3058,7 @@ async function writeModelToDb(modelFileId, data) {
2236
3058
  .limit(1);
2237
3059
  if (existing.length > 0) {
2238
3060
  modelId = existing[0].id;
2239
- logger(`Found existing model with schemaFileId "${modelFileId}" (id: ${modelId}) after constraint violation`);
3061
+ logger$3(`Found existing model with schemaFileId "${modelFileId}" (id: ${modelId}) after constraint violation`);
2240
3062
  }
2241
3063
  else {
2242
3064
  throw error;
@@ -2292,9 +3114,7 @@ async function writeModelToDb(modelFileId, data) {
2292
3114
  throw new Error(`Model with id ${modelId} does not exist in database. Cannot create join record.`);
2293
3115
  }
2294
3116
  // Verify schemaId exists and get name/fileId for invalidation broadcast
2295
- const _mod_2 = await import('./BasePathResolver-CfSfMW5_.js');
2296
- const _ns_2 = _mod_2.Q;
2297
- const schemaSchemaMod = _ns_2;
3117
+ const schemaSchemaMod = await Promise.resolve().then(function () { return SchemaSchema; });
2298
3118
  const { schemas: schemasTable } = schemaSchemaMod;
2299
3119
  const schemaCheck = await db
2300
3120
  .select({
@@ -2308,7 +3128,7 @@ async function writeModelToDb(modelFileId, data) {
2308
3128
  if (schemaCheck.length === 0) {
2309
3129
  throw new Error(`Schema with id ${data.schemaId} does not exist in database. Cannot create join record.`);
2310
3130
  }
2311
- logger(`Creating join record: modelId=${modelId}, schemaId=${data.schemaId} (both verified to exist)`);
3131
+ logger$3(`Creating join record: modelId=${modelId}, schemaId=${data.schemaId} (both verified to exist)`);
2312
3132
  await linkModelToSchema(db, modelId, data.schemaId);
2313
3133
  // Notify React useModels so it can invalidate; live query over join often doesn't re-run when model_schemas is inserted.
2314
3134
  // Yield so the insert is visible to the refetch that will run when the broadcast is received.
@@ -2323,13 +3143,13 @@ async function writeModelToDb(modelFileId, data) {
2323
3143
  }
2324
3144
  catch (_) { }
2325
3145
  }
2326
- logger(`Successfully created join record for model ${data.modelName} (id: ${modelId}) to schema (id: ${data.schemaId})`);
3146
+ logger$3(`Successfully created join record for model ${data.modelName} (id: ${modelId}) to schema (id: ${data.schemaId})`);
2327
3147
  }
2328
3148
  catch (error) {
2329
3149
  if (error?.code === 'SQLITE_CONSTRAINT_FOREIGNKEY') {
2330
- logger(`FOREIGN KEY constraint failed when creating join record for model "${data.modelName}"`);
2331
- logger(`modelId: ${modelId}, schemaId: ${data.schemaId}`);
2332
- logger(`Error details:`, error);
3150
+ logger$3(`FOREIGN KEY constraint failed when creating join record for model "${data.modelName}"`);
3151
+ logger$3(`modelId: ${modelId}, schemaId: ${data.schemaId}`);
3152
+ logger$3(`Error details:`, error);
2333
3153
  // Re-throw with more context
2334
3154
  throw new Error(`FOREIGN KEY constraint failed when creating join record for model "${data.modelName}" (modelId: ${modelId}, schemaId: ${data.schemaId}). ${error.message}`);
2335
3155
  }
@@ -2349,7 +3169,7 @@ async function writeModelToDb(modelFileId, data) {
2349
3169
  if (existingProps.length > 0 && existingProps[0].schemaFileId) {
2350
3170
  // Use existing property's schemaFileId
2351
3171
  propertyFileId = existingProps[0].schemaFileId;
2352
- logger(`Using existing propertyFileId "${propertyFileId}" for property "${data.modelName}:${propName}"`);
3172
+ logger$3(`Using existing propertyFileId "${propertyFileId}" for property "${data.modelName}:${propName}"`);
2353
3173
  }
2354
3174
  else if (propData.id) {
2355
3175
  // Use provided ID
@@ -2358,11 +3178,9 @@ async function writeModelToDb(modelFileId, data) {
2358
3178
  else {
2359
3179
  // Generate random propertyFileId
2360
3180
  // IDs should be generated in the import process before calling writeModelToDb
2361
- const _mod_3 = await import('./tabEvents-DguZpCCv.js');
2362
- const _ns_3 = _mod_3.Z;
2363
- const { generateId } = _ns_3;
3181
+ const { generateId } = await Promise.resolve().then(function () { return generateId$1; });
2364
3182
  propertyFileId = generateId();
2365
- logger(`Generated propertyFileId "${propertyFileId}" for property "${data.modelName}:${propName}"`);
3183
+ logger$3(`Generated propertyFileId "${propertyFileId}" for property "${data.modelName}:${propName}"`);
2366
3184
  }
2367
3185
  await writePropertyToDb(propertyFileId, {
2368
3186
  modelId,
@@ -2371,7 +3189,7 @@ async function writeModelToDb(modelFileId, data) {
2371
3189
  });
2372
3190
  }
2373
3191
  }
2374
- logger(`Wrote model ${data.modelName} (${modelFileId}) to database`);
3192
+ logger$3(`Wrote model ${data.modelName} (${modelFileId}) to database`);
2375
3193
  }
2376
3194
  /**
2377
3195
  * Write property to database
@@ -2446,7 +3264,7 @@ async function writePropertyToDb(propertyFileId, data, isEdited = false) {
2446
3264
  .update(properties)
2447
3265
  .set(propertyData)
2448
3266
  .where(eq(properties.id, existing.id));
2449
- logger(`Updated property ${data.name} (${propertyFileId}) in database`);
3267
+ logger$3(`Updated property ${data.name} (${propertyFileId}) in database`);
2450
3268
  }
2451
3269
  else {
2452
3270
  // Property doesn't exist, create it
@@ -2462,17 +3280,17 @@ async function writePropertyToDb(propertyFileId, data, isEdited = false) {
2462
3280
  .update(properties)
2463
3281
  .set(propertyData)
2464
3282
  .where(eq(properties.id, doubleCheck[0].id));
2465
- logger(`Property with schemaFileId "${propertyFileId}" was created by another process, updated existing record`);
3283
+ logger$3(`Property with schemaFileId "${propertyFileId}" was created by another process, updated existing record`);
2466
3284
  }
2467
3285
  else {
2468
3286
  try {
2469
3287
  await db.insert(properties).values({ required: false, ...propertyData });
2470
- logger(`Created property ${data.name} (${propertyFileId}) in database`);
3288
+ logger$3(`Created property ${data.name} (${propertyFileId}) in database`);
2471
3289
  }
2472
3290
  catch (error) {
2473
3291
  // Handle unique constraint violation
2474
3292
  if (isSqliteUniqueConstraintError(error)) {
2475
- logger(`Unique constraint violation for property schemaFileId "${propertyFileId}", attempting to find existing property`);
3293
+ logger$3(`Unique constraint violation for property schemaFileId "${propertyFileId}", attempting to find existing property`);
2476
3294
  const existing = await db
2477
3295
  .select()
2478
3296
  .from(properties)
@@ -2483,7 +3301,7 @@ async function writePropertyToDb(propertyFileId, data, isEdited = false) {
2483
3301
  .update(properties)
2484
3302
  .set(propertyData)
2485
3303
  .where(eq(properties.id, existing[0].id));
2486
- logger(`Found existing property with schemaFileId "${propertyFileId}" (id: ${existing[0].id}) after constraint violation, updated it`);
3304
+ logger$3(`Found existing property with schemaFileId "${propertyFileId}" (id: ${existing[0].id}) after constraint violation, updated it`);
2487
3305
  }
2488
3306
  else {
2489
3307
  throw new Error(`Failed to create or find property "${data.name}" with schemaFileId "${propertyFileId}": ${error.message}`);
@@ -2507,9 +3325,7 @@ async function getSchemaId(schemaNameOrFileId) {
2507
3325
  if (!db) {
2508
3326
  throw new Error('Database not available');
2509
3327
  }
2510
- const _mod_4 = await import('./BasePathResolver-CfSfMW5_.js');
2511
- const _ns_4 = _mod_4.Q;
2512
- const schemaSchemaMod = _ns_4;
3328
+ const schemaSchemaMod = await Promise.resolve().then(function () { return SchemaSchema; });
2513
3329
  const { schemas: schemasTable } = schemaSchemaMod;
2514
3330
  const drizzleMod = await import('drizzle-orm');
2515
3331
  const { eq, desc } = drizzleMod;
@@ -2545,9 +3361,7 @@ async function getSchemaIdByFileId(schemaFileId) {
2545
3361
  if (!db) {
2546
3362
  throw new Error('Database not available');
2547
3363
  }
2548
- const _mod_5 = await import('./BasePathResolver-CfSfMW5_.js');
2549
- const _ns_5 = _mod_5.Q;
2550
- const schemaSchemaMod = _ns_5;
3364
+ const schemaSchemaMod = await Promise.resolve().then(function () { return SchemaSchema; });
2551
3365
  const { schemas: schemasTable } = schemaSchemaMod;
2552
3366
  const drizzleMod = await import('drizzle-orm');
2553
3367
  const { eq, desc } = drizzleMod;
@@ -2574,9 +3388,7 @@ async function getModelId(modelNameOrFileId, schemaNameOrId) {
2574
3388
  if (!db) {
2575
3389
  throw new Error('Database not available');
2576
3390
  }
2577
- const _mod_6 = await import('./BasePathResolver-CfSfMW5_.js');
2578
- const _ns_6 = _mod_6.N;
2579
- const modelSchemaMod = _ns_6;
3391
+ const modelSchemaMod = await Promise.resolve().then(function () { return ModelSchema; });
2580
3392
  const { models: modelsTable } = modelSchemaMod;
2581
3393
  const drizzleMod = await import('drizzle-orm');
2582
3394
  const { eq, and, or } = drizzleMod;
@@ -2591,13 +3403,9 @@ async function getModelId(modelNameOrFileId, schemaNameOrId) {
2591
3403
  [eq(modelsTable.name, modelNameOrFileId)];
2592
3404
  // If schema is provided, narrow the search
2593
3405
  if (schemaNameOrId !== undefined) {
2594
- const _mod_7 = await import('./BasePathResolver-CfSfMW5_.js');
2595
- const _ns_7 = _mod_7.R;
2596
- const modelSchemaSchemaMod = _ns_7;
3406
+ const modelSchemaSchemaMod = await Promise.resolve().then(function () { return ModelSchemaSchema; });
2597
3407
  const { modelSchemas } = modelSchemaSchemaMod;
2598
- const _mod_8 = await import('./BasePathResolver-CfSfMW5_.js');
2599
- const _ns_8 = _mod_8.Q;
2600
- const schemaSchemaMod = _ns_8;
3408
+ const schemaSchemaMod = await Promise.resolve().then(function () { return SchemaSchema; });
2601
3409
  const { schemas: schemasTable } = schemaSchemaMod;
2602
3410
  if (typeof schemaNameOrId === 'number') {
2603
3411
  // schemaNameOrId is schemaId
@@ -2642,9 +3450,7 @@ async function getModelIdByFileId(modelFileId) {
2642
3450
  if (!db) {
2643
3451
  throw new Error('Database not available');
2644
3452
  }
2645
- const _mod_9 = await import('./BasePathResolver-CfSfMW5_.js');
2646
- const _ns_9 = _mod_9.N;
2647
- const modelSchemaMod = _ns_9;
3453
+ const modelSchemaMod = await Promise.resolve().then(function () { return ModelSchema; });
2648
3454
  const { models: modelsTable } = modelSchemaMod;
2649
3455
  const drizzleMod = await import('drizzle-orm');
2650
3456
  const { eq } = drizzleMod;
@@ -2690,5 +3496,1113 @@ var db = /*#__PURE__*/Object.freeze({
2690
3496
  writePropertyToDb: writePropertyToDb
2691
3497
  });
2692
3498
 
2693
- export { AmbiguousModelError as A, Boolean as B, normalizeAddressConfig as C, DEFAULT_TEXT_MAX_LENGTH as D, normalizeAddressList as E, File as F, writeModelToDb as G, Html as H, Image as I, Json as J, writePropertyToDb as K, List as L, ModelPropertyDataTypes as M, Number$1 as N, addSchemaToDb as O, Property as P, renameModelInDb as Q, Relation as R, loadModelsFromDbForSchema as S, THtmlEmbeddedDataUriPolicy as T, linkModelToSchema as U, getWatchedAddressesFromDb as V, getOwnedAddressesFromDb as W, getPropertyIdForSchemaFileId as X, resolveModelRecord$1 as Y, db as Z, Date$1 as a, PropertyConstructor as b, PropertyMetadataKey as c, TProperty as d, TPropertyConstructor as e, TPropertyDataType as f, TPropertyDefs as g, TStorageType as h, TValidationRules as i, Text as j, isDataType as k, normalizePropertyRecordSchema as l, eventEmitter as m, normalizeDataType as n, getPropertyIdForModelAndName as o, resolveModelRecord as p, getItemModelScope as q, resolveItemModelFileId as r, normalizePublisher as s, getAllAddressesFromDb as t, normalizeHexAddress as u, getItemStoragePropertiesForModel as v, addModelsToDb as w, getModelIdByFileId as x, getModelId as y, getAddressesForItemsFilter as z };
2694
- //# sourceMappingURL=db-D9K_f5cF.js.map
3499
+ const getMetadata = async (props) => {
3500
+ const appDb = BaseDb.getAppDb();
3501
+ let storageTransactionId;
3502
+ if (props) {
3503
+ storageTransactionId = props.storageTransactionId;
3504
+ }
3505
+ const whereClauses = [];
3506
+ if (storageTransactionId) {
3507
+ whereClauses.push(eq(metadata.propertyName, 'storageTransactionId'));
3508
+ whereClauses.push(eq(metadata.propertyValue, storageTransactionId));
3509
+ }
3510
+ const metadataRows = await appDb
3511
+ .select()
3512
+ .from(metadata)
3513
+ .where(and(...whereClauses));
3514
+ if (!metadataRows || metadataRows.length === 0) {
3515
+ return;
3516
+ }
3517
+ return metadataRows[0];
3518
+ };
3519
+
3520
+ const saveMetadata = async (metadataRecord, metadataValues) => {
3521
+ if (!metadataRecord.localId) {
3522
+ return;
3523
+ }
3524
+ const appDb = BaseDb.getAppDb();
3525
+ await appDb
3526
+ .update(metadata)
3527
+ .set({
3528
+ ...metadataValues,
3529
+ updatedAt: Date.now(),
3530
+ })
3531
+ .where(eq(metadata.localId, metadataRecord.localId));
3532
+ };
3533
+
3534
+ const isNode = () => {
3535
+ return (typeof process !== 'undefined' &&
3536
+ process.versions != null &&
3537
+ process.versions.node != null);
3538
+ };
3539
+ const isBrowser = () => {
3540
+ return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
3541
+ };
3542
+ const isElectron = () => {
3543
+ return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
3544
+ };
3545
+ /**
3546
+ * Detects if code is running in an Electron renderer process.
3547
+ *
3548
+ * Uses multiple detection methods for robustness:
3549
+ * 1. Checks process.type === 'renderer' (most reliable)
3550
+ * 2. Falls back to checking if Electron is present and window/document exist
3551
+ *
3552
+ * @returns true if running in Electron renderer process, false otherwise
3553
+ */
3554
+ const isElectronRenderer = () => {
3555
+ // Method 1: Check process.type (most reliable - official Electron API)
3556
+ if (typeof process !== 'undefined' &&
3557
+ process.type === 'renderer') {
3558
+ return true;
3559
+ }
3560
+ // Method 2: Fallback - Electron + browser-like environment
3561
+ // Renderer processes have window/document, main process doesn't (in modern Electron)
3562
+ if (isElectron() &&
3563
+ typeof window !== 'undefined' &&
3564
+ typeof document !== 'undefined') {
3565
+ return true;
3566
+ }
3567
+ return false;
3568
+ };
3569
+ /**
3570
+ * True where OPFS-backed Arweave file downloads should run: normal browsers and
3571
+ * Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
3572
+ */
3573
+ const supportsOpfsFileDownloads = () => {
3574
+ return isBrowser() || isElectronRenderer();
3575
+ };
3576
+
3577
+ /**
3578
+ * Tag every Seed upload carries with the hex digest of its data. Producers: the SDK's
3579
+ * `getPublishUploadData` / `getPublishUploads` (and through them both the L1 transaction path and
3580
+ * the bundler / DataItem path in `@seedprotocol/publish`). Consumer: the files download
3581
+ * (`events/files/download.ts` and the download worker), which verifies downloaded bytes against it
3582
+ * and copies a verified value into `metadata.content_hash`.
3583
+ */
3584
+ const CONTENT_SHA256_TAG = 'Content-SHA-256';
3585
+ const CONTENT_TYPE_TAG = 'Content-Type';
3586
+ /**
3587
+ * Lowercase hex SHA-256 of `data`: the value of the {@link CONTENT_SHA256_TAG} tag.
3588
+ *
3589
+ * Uses @noble/hashes rather than WebCrypto so it also works outside secure contexts (WebCrypto's
3590
+ * `crypto.subtle` is missing on plain-http origins); the digest is the same.
3591
+ *
3592
+ * In SDK 0.7.2 and earlier the L1 transaction path (`getPublishUploads`) wrote SHA3-256 under this tag name
3593
+ * while the bundler path wrote SHA-256. Uploads from that path still carry SHA3-256 digests; use
3594
+ * {@link contentSha256TagMatches} to check a tag value against bytes.
3595
+ */
3596
+ const getContentSha256 = (data) => bytesToHex(sha256(data));
3597
+ /**
3598
+ * True when `tagValue` (a {@link CONTENT_SHA256_TAG} value read from Arweave) is the digest of
3599
+ * `data`. Accepts SHA-256 and, for uploads made by SDK 0.7.2 and earlier through the L1 transaction path,
3600
+ * SHA3-256.
3601
+ */
3602
+ const contentSha256TagMatches = (data, tagValue) => {
3603
+ const expected = tagValue.trim().toLowerCase();
3604
+ if (!expected)
3605
+ return false;
3606
+ return getContentSha256(data) === expected || bytesToHex(sha3_256(data)) === expected;
3607
+ };
3608
+ /**
3609
+ * Tags for one upload, in the order every upload uses: content hash, content type, then any
3610
+ * configured extra tags (e.g. App-Name from `arweaveUploadTags`).
3611
+ */
3612
+ const buildArweaveContentTags = (contentHash, contentType, extra) => {
3613
+ const tags = [];
3614
+ if (contentHash)
3615
+ tags.push({ name: CONTENT_SHA256_TAG, value: contentHash });
3616
+ if (contentType)
3617
+ tags.push({ name: CONTENT_TYPE_TAG, value: contentType });
3618
+ if (extra?.length)
3619
+ tags.push(...extra);
3620
+ return tags;
3621
+ };
3622
+
3623
+ /** Subdirectory of the files root that holds a storage seed's file, by its data type. */
3624
+ const getStorageSubdirForDataType = (dataType) => {
3625
+ switch (normalizeDataType(dataType ?? undefined)) {
3626
+ case 'Image':
3627
+ return 'images';
3628
+ case 'Html':
3629
+ return 'html';
3630
+ case 'Json':
3631
+ return 'json';
3632
+ case 'File':
3633
+ default:
3634
+ // Unknown types are generic files; `images/` is only for what the SDK knows is an image.
3635
+ return 'files';
3636
+ }
3637
+ };
3638
+ /** Absolute directory for a storage seed's file (`images/`, `files/`, `html/` or `json/` under the files root). */
3639
+ const getStorageDirForDataType = (dataType) => BaseFileManager.getFilesPath(getStorageSubdirForDataType(dataType));
3640
+ /**
3641
+ * Subdirectory (relative to the files root, no leading slash) for an ItemStorage property's file:
3642
+ * its model's `storage.path` (`localStorageDir`), else `files`.
3643
+ */
3644
+ const getItemStorageSubdir = (localStorageDir) => (localStorageDir ?? '').replace(/^\/+/, '').replace(/\/+$/, '') || 'files';
3645
+ /**
3646
+ * File name a local save gives an ItemStorage property: `<seedUid or seedLocalId><extension>`
3647
+ * (see saveItemStorage). Downloaded content is named after its transaction instead
3648
+ * (`<txId><extension>`, see syncDbWithEas), which is what the metadata row's refResolvedValue says.
3649
+ */
3650
+ const getItemStorageLocalFileName = (seedId, filenameSuffix) => `${seedId}${filenameSuffix ?? ''}`;
3651
+
3652
+ /** Rows per query: well under SQLite's bound-parameter limit. */
3653
+ const CHUNK_SIZE = 400;
3654
+ /**
3655
+ * Where the download worker saves each child of a composite upload, by transaction id then child
3656
+ * (property) name: a path relative to the files root.
3657
+ *
3658
+ * The paths come from the ItemStorage rows sync derives from a `storage_transaction_id`
3659
+ * attestation (see `createMetadataRecordsForStorageTransactionId`): property value = the
3660
+ * transaction id, `refResolvedValue` = `<txId><extension>`, `localStorageDir` = the model's storage
3661
+ * directory. Those rows are what hydration reads, so a child saved here is found as that property's
3662
+ * file. Transactions with no such rows are left out; the worker then falls back to the legacy
3663
+ * html / json layout.
3664
+ */
3665
+ const getCompositeChildPaths = async (transactionIds) => {
3666
+ const out = {};
3667
+ const appDb = BaseDb.getAppDb();
3668
+ if (!appDb || transactionIds.length === 0)
3669
+ return out;
3670
+ for (let i = 0; i < transactionIds.length; i += CHUNK_SIZE) {
3671
+ const chunk = transactionIds.slice(i, i + CHUNK_SIZE);
3672
+ const rows = await appDb
3673
+ .select({
3674
+ transactionId: metadata.propertyValue,
3675
+ propertyName: metadata.propertyName,
3676
+ refResolvedValue: metadata.refResolvedValue,
3677
+ localStorageDir: metadata.localStorageDir,
3678
+ })
3679
+ .from(metadata)
3680
+ .where(and(isNotNull(metadata.derivedFromUid), isNotNull(metadata.refResolvedValue), inArray(metadata.propertyValue, chunk)));
3681
+ for (const row of rows) {
3682
+ const { transactionId, propertyName, refResolvedValue } = row;
3683
+ if (!transactionId || !propertyName || !refResolvedValue)
3684
+ continue;
3685
+ // A file name, never a path: anything else is not where the SDK would look.
3686
+ if (refResolvedValue.includes('/') || refResolvedValue.includes('\\'))
3687
+ continue;
3688
+ const byName = (out[transactionId] ?? (out[transactionId] = {}));
3689
+ byName[propertyName] ?? (byName[propertyName] = `${getItemStorageSubdir(row.localStorageDir)}/${refResolvedValue}`);
3690
+ }
3691
+ }
3692
+ return out;
3693
+ };
3694
+
3695
+ const logger$2 = debug('seedSdk:files:download');
3696
+ const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
3697
+ /** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
3698
+ const GET_FILES_METADATA_STALE_MS = 120000;
3699
+ let bulkDownloadInFlight = null;
3700
+ const lazyDownloadInFlightByTransactionId = new Map();
3701
+ // syncDbFiles helper - internal service removed, functionality moved here
3702
+ const syncDbFiles = async (endpoints) => {
3703
+ // TODO: Implement syncDbFiles functionality if needed
3704
+ // This was previously in @/services/internal/helpers
3705
+ logger$2('[download] syncDbFiles called but not yet implemented');
3706
+ return Promise.resolve();
3707
+ };
3708
+ const getAppDbReady = async () => {
3709
+ if (!BaseDb.isAppDbReady()) {
3710
+ // Wait for ClientManager to be ready (DB_INIT state or later)
3711
+ const _mod_0 = await import('./ClientManager-i3nJASkg.js');
3712
+ const _ns_0 = _mod_0.L;
3713
+ const clientManagerMod = _ns_0;
3714
+ const { getClient } = clientManagerMod;
3715
+ const clientManager = getClient();
3716
+ const clientService = clientManager.getService();
3717
+ await waitFor(clientService, (snapshot) => {
3718
+ const state = snapshot.value;
3719
+ return state === 'dbInit' ||
3720
+ state === 'saveConfig' ||
3721
+ state === 'processSchemaFiles' ||
3722
+ state === 'addModelsToStore' ||
3723
+ state === 'addModelsToDb' ||
3724
+ state === 'idle';
3725
+ }, { timeout: 30000 });
3726
+ }
3727
+ return BaseDb.getAppDb();
3728
+ };
3729
+ const getExcludedTransactions = async () => {
3730
+ const appDb = await getAppDbReady();
3731
+ if (!appDb) {
3732
+ return new Set();
3733
+ }
3734
+ const excludedTransactionsQuery = await appDb
3735
+ .select()
3736
+ .from(appState)
3737
+ .where(eq(appState.key, 'excludedTransactions'));
3738
+ const excludedTransactions = new Set();
3739
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
3740
+ const valueString = excludedTransactionsQuery[0].value;
3741
+ if (valueString) {
3742
+ const excludedTransactionsArray = JSON.parse(valueString);
3743
+ for (const txId of excludedTransactionsArray) {
3744
+ excludedTransactions.add(txId);
3745
+ }
3746
+ }
3747
+ }
3748
+ return excludedTransactions;
3749
+ };
3750
+ /** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
3751
+ const ARWEAVE_TX_ID_RE$1 = /^[a-z0-9_-]{43}$/i;
3752
+ const normalizeArweaveTxId = (raw) => {
3753
+ if (raw == null || raw === '')
3754
+ return undefined;
3755
+ const t = String(raw).trim();
3756
+ if (ARWEAVE_TX_ID_RE$1.test(t))
3757
+ return t;
3758
+ const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
3759
+ if (m)
3760
+ return m[1];
3761
+ // Values may be full gateway URLs or paths; scan for the embedded tx id.
3762
+ const embedded = t.match(/[a-z0-9_-]{43}/gi);
3763
+ if (embedded) {
3764
+ for (const candidate of embedded) {
3765
+ if (ARWEAVE_TX_ID_RE$1.test(candidate))
3766
+ return candidate;
3767
+ }
3768
+ }
3769
+ return undefined;
3770
+ };
3771
+ const mergeAddressLists = (a, b) => {
3772
+ const seen = new Set();
3773
+ const out = [];
3774
+ for (const addr of [...(a ?? []), ...(b ?? [])]) {
3775
+ if (!addr || !addr.trim())
3776
+ continue;
3777
+ const k = addr.toLowerCase();
3778
+ if (seen.has(k))
3779
+ continue;
3780
+ seen.add(k);
3781
+ out.push(addr);
3782
+ }
3783
+ return out;
3784
+ };
3785
+ const collectTransactionIdsFromLocalMetadata = async () => {
3786
+ const appDb = await getAppDbReady();
3787
+ if (!appDb) {
3788
+ return [];
3789
+ }
3790
+ const nameOr = or(eq(metadata.propertyName, 'storageTransactionId'), eq(metadata.propertyName, 'storage_transaction_id'), eq(metadata.propertyName, 'transactionId'));
3791
+ const propRows = await appDb
3792
+ .select({ propertyValue: metadata.propertyValue })
3793
+ .from(metadata)
3794
+ .where(and(nameOr, isNotNull(metadata.propertyValue)));
3795
+ const refRows = await appDb
3796
+ .select({ refResolvedValue: metadata.refResolvedValue })
3797
+ .from(metadata)
3798
+ .where(isNotNull(metadata.refResolvedValue));
3799
+ const ids = new Set();
3800
+ for (const row of propRows) {
3801
+ const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
3802
+ if (id)
3803
+ ids.add(id);
3804
+ }
3805
+ for (const row of refRows) {
3806
+ const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
3807
+ if (id)
3808
+ ids.add(id);
3809
+ }
3810
+ return Array.from(ids);
3811
+ };
3812
+ const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
3813
+ const transactionIds = [];
3814
+ for (const fileMetadata of filesMetadata) {
3815
+ // Validate and parse decodedDataJson
3816
+ if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
3817
+ console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
3818
+ continue;
3819
+ }
3820
+ let json;
3821
+ try {
3822
+ json = JSON.parse(fileMetadata.decodedDataJson);
3823
+ }
3824
+ catch (error) {
3825
+ console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
3826
+ continue;
3827
+ }
3828
+ if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
3829
+ console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
3830
+ continue;
3831
+ }
3832
+ const rawTx = json[0].value.value;
3833
+ if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
3834
+ continue;
3835
+ }
3836
+ const transactionId = normalizeArweaveTxId(rawTx.trim());
3837
+ if (!transactionId) {
3838
+ continue;
3839
+ }
3840
+ if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
3841
+ continue;
3842
+ }
3843
+ transactionIds.push(transactionId);
3844
+ }
3845
+ return transactionIds;
3846
+ };
3847
+ /** Content-SHA-256 tag values for the transactions that have one, from one batched tag lookup (cached). */
3848
+ const getExpectedContentHashes = async (transactionIds) => {
3849
+ const queryClient = BaseQueryClient.getQueryClient();
3850
+ const tagsById = new Map();
3851
+ const toFetch = [];
3852
+ for (const transactionId of transactionIds) {
3853
+ // Tags never change once a transaction is indexed, so a cached lookup stays good.
3854
+ const cached = queryClient.getQueryData?.(['getTransactionTags', transactionId]);
3855
+ if (cached)
3856
+ tagsById.set(transactionId, cached);
3857
+ else
3858
+ toFetch.push(transactionId);
3859
+ }
3860
+ if (toFetch.length > 0) {
3861
+ try {
3862
+ const fetched = await getTransactionTagsByIds(toFetch, {
3863
+ client: BaseArweaveClient.getArweaveClient(),
3864
+ onError: (error) => logger$2('[download] transaction tags lookup failed', error),
3865
+ });
3866
+ for (const [transactionId, tags] of fetched) {
3867
+ tagsById.set(transactionId, tags);
3868
+ // Seed the per-transaction cache entry (the client interface has no setQueryData).
3869
+ void queryClient
3870
+ .fetchQuery({ queryKey: ['getTransactionTags', transactionId], queryFn: async () => tags })
3871
+ .catch(() => { });
3872
+ }
3873
+ }
3874
+ catch (error) {
3875
+ logger$2('[download] transaction tags lookup failed', error);
3876
+ }
3877
+ }
3878
+ const out = {};
3879
+ for (const [transactionId, tags] of tagsById) {
3880
+ const value = tags.find((tag) => tag.name === CONTENT_SHA256_TAG)?.value?.trim();
3881
+ if (value)
3882
+ out[transactionId] = value;
3883
+ }
3884
+ return out;
3885
+ };
3886
+ /** Store the (now verified) Content-SHA-256 of each downloaded transaction on its metadata row. */
3887
+ const recordVerifiedContentHashes = async (transactionIds, expectedContentHashes) => {
3888
+ for (const transactionId of transactionIds) {
3889
+ const contentHash = expectedContentHashes[transactionId];
3890
+ if (!contentHash)
3891
+ continue;
3892
+ try {
3893
+ const metadataRecord = await getMetadata({ storageTransactionId: transactionId });
3894
+ if (metadataRecord) {
3895
+ await saveMetadata(metadataRecord, { contentHash });
3896
+ }
3897
+ }
3898
+ catch (error) {
3899
+ logger$2(error);
3900
+ }
3901
+ }
3902
+ };
3903
+ const downloadTransactionIds = async (rawTransactionIds, options) => {
3904
+ if (!supportsOpfsFileDownloads()) {
3905
+ return false;
3906
+ }
3907
+ const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
3908
+ if (transactionIds.length === 0) {
3909
+ return false;
3910
+ }
3911
+ const excludedTransactions = await getExcludedTransactions();
3912
+ await ensureReadGatewaySelected();
3913
+ // Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
3914
+ // CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
3915
+ const transactionIdsToDownload = transactionIds.filter((id) => !excludedTransactions.has(id));
3916
+ if (transactionIdsToDownload.length === 0) {
3917
+ return false;
3918
+ }
3919
+ // One batched lookup for every upload's Content-SHA-256 tag; downloads are verified against it.
3920
+ // Missing tags (old uploads, or a just-published one not indexed yet) just mean no verification.
3921
+ const expectedContentHashes = await getExpectedContentHashes(transactionIdsToDownload);
3922
+ // Preferred gateways first: a just-published item is only on the gateway it was uploaded through.
3923
+ const arweaveBaseUrls = getArweaveReadBaseUrls();
3924
+ // Where each ItemStorage child of a composite goes (the worker cannot read the DB or the schema).
3925
+ const compositeChildPaths = await getCompositeChildPaths(transactionIdsToDownload).catch((error) => {
3926
+ logger$2('[download] composite child paths lookup failed', error);
3927
+ return {};
3928
+ });
3929
+ let result;
3930
+ if (transactionIdsToDownload.length === 1) {
3931
+ const transactionId = transactionIdsToDownload[0];
3932
+ result = await BaseFileManager.downloadFileByTransactionId({
3933
+ transactionId,
3934
+ arweaveHost: BaseArweaveClient.getBaseUrl(),
3935
+ arweaveBaseUrls,
3936
+ excludedTransactions,
3937
+ expectedContentHash: expectedContentHashes[transactionId],
3938
+ compositeChildPaths: compositeChildPaths[transactionId],
3939
+ });
3940
+ }
3941
+ else {
3942
+ result = await BaseFileManager.downloadAllFiles({
3943
+ transactionIds: transactionIdsToDownload,
3944
+ arweaveHost: BaseArweaveClient.getBaseUrl(),
3945
+ arweaveBaseUrls,
3946
+ excludedTransactions,
3947
+ expectedContentHashes,
3948
+ compositeChildPaths,
3949
+ });
3950
+ }
3951
+ if (result) {
3952
+ for (const transactionId of result.hashMismatchTransactionIds) {
3953
+ // Not saved by the worker; left for a later run (a gateway may serve the right bytes then).
3954
+ logger$2(`[download] ${transactionId}: downloaded bytes do not match Content-SHA-256; skipped`);
3955
+ }
3956
+ await recordVerifiedContentHashes(result.verifiedTransactionIds, expectedContentHashes);
3957
+ }
3958
+ if (options?.resizeAllImages !== false) {
3959
+ await BaseFileManager.resizeAllImages({
3960
+ width: 480,
3961
+ height: 480,
3962
+ });
3963
+ }
3964
+ return true;
3965
+ };
3966
+ const runBulkDownloadWithDedupe = async (transactionIds) => {
3967
+ if (bulkDownloadInFlight) {
3968
+ return bulkDownloadInFlight;
3969
+ }
3970
+ bulkDownloadInFlight = (async () => {
3971
+ try {
3972
+ await downloadTransactionIds(transactionIds, { resizeAllImages: true });
3973
+ }
3974
+ finally {
3975
+ bulkDownloadInFlight = null;
3976
+ }
3977
+ })();
3978
+ return bulkDownloadInFlight;
3979
+ };
3980
+ const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
3981
+ if (!supportsOpfsFileDownloads()) {
3982
+ return;
3983
+ }
3984
+ await syncDbFiles();
3985
+ eventEmitter.emit('fs.downloadAll.success', { eventId });
3986
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
3987
+ };
3988
+ const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
3989
+ if (!supportsOpfsFileDownloads()) {
3990
+ return;
3991
+ }
3992
+ const addressesHint = Array.isArray(addressesHintOrPayload)
3993
+ ? addressesHintOrPayload
3994
+ : undefined;
3995
+ let fromDb = [];
3996
+ if (BaseDb.isAppDbReady()) {
3997
+ fromDb = await getAllAddressesFromDb();
3998
+ }
3999
+ if (!BaseDb.isAppDbReady()) {
4000
+ await getAppDbReady();
4001
+ fromDb = await getAllAddressesFromDb();
4002
+ }
4003
+ const addresses = mergeAddressLists(addressesHint, fromDb);
4004
+ if (!addresses || addresses.length === 0) {
4005
+ return;
4006
+ }
4007
+ const queryClient = BaseQueryClient.getQueryClient();
4008
+ const easClient = BaseEasClient.getEasClient();
4009
+ const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
4010
+ const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
4011
+ where: {
4012
+ attester: {
4013
+ in: addresses,
4014
+ },
4015
+ schema: {
4016
+ is: {
4017
+ id: {
4018
+ equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
4019
+ },
4020
+ },
4021
+ },
4022
+ },
4023
+ });
4024
+ let { filesMetadata } = await queryClient.fetchQuery({
4025
+ queryKey: filesMetadataQueryKey,
4026
+ queryFn: fetchFilesMetadata,
4027
+ staleTime: GET_FILES_METADATA_STALE_MS,
4028
+ });
4029
+ if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
4030
+ await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
4031
+ ({ filesMetadata } = await queryClient.fetchQuery({
4032
+ queryKey: filesMetadataQueryKey,
4033
+ queryFn: fetchFilesMetadata,
4034
+ staleTime: GET_FILES_METADATA_STALE_MS,
4035
+ }));
4036
+ }
4037
+ const filesRoot = BaseFileManager.getWorkingDir();
4038
+ await BaseFileManager.createDirIfNotExists(filesRoot);
4039
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
4040
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
4041
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
4042
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('files'));
4043
+ const excludedTransactions = await getExcludedTransactions();
4044
+ const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
4045
+ const fromLocal = await collectTransactionIdsFromLocalMetadata();
4046
+ const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
4047
+ await runBulkDownloadWithDedupe(transactionIds);
4048
+ };
4049
+ const downloadTransactionIdWithDedupe = async (transactionId) => {
4050
+ if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
4051
+ return false;
4052
+ }
4053
+ const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
4054
+ const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
4055
+ if (existing) {
4056
+ return existing;
4057
+ }
4058
+ const inFlight = (async () => {
4059
+ try {
4060
+ const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
4061
+ return ok;
4062
+ }
4063
+ finally {
4064
+ lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
4065
+ }
4066
+ })();
4067
+ lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
4068
+ return inFlight;
4069
+ };
4070
+ const scheduleBulkFilesDownloadFromEasSyncThrottled = throttle((addressesHint) => {
4071
+ void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
4072
+ logger$2('[scheduleBulkFilesDownloadFromEasSync] failed', error);
4073
+ });
4074
+ }, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
4075
+ const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
4076
+ if (!supportsOpfsFileDownloads()) {
4077
+ return;
4078
+ }
4079
+ scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
4080
+ };
4081
+
4082
+ var download = /*#__PURE__*/Object.freeze({
4083
+ __proto__: null,
4084
+ downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
4085
+ downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
4086
+ downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
4087
+ scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
4088
+ });
4089
+
4090
+ // Top-level re-export (not mid-file import + export): Rollup with
4091
+ // external `@seedprotocol/arweave` otherwise emits a side-effect-only import
4092
+ // and an unbound Object.freeze namespace when this module is dynamically imported.
4093
+ // Define zero constants ourselves since they're not exported from eas-sdk in newer versions
4094
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
4095
+ const ZERO_BYTES = '0x';
4096
+ const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
4097
+ // Primary config file name for Seed Protocol SDK
4098
+ const SEED_CONFIG_FILE = 'seed.config.ts';
4099
+ // Fallback config file names (in order of preference)
4100
+ const SEED_CONFIG_FALLBACKS = ['seed.schema.ts', 'schema.ts'];
4101
+ // Legacy constant for backward compatibility
4102
+ const SCHEMA_TS = SEED_CONFIG_FILE;
4103
+ const INTERNAL_DATA_TYPES = {
4104
+ Text: {
4105
+ eas: 'string',
4106
+ },
4107
+ Number: {
4108
+ eas: 'uint8',
4109
+ },
4110
+ Image: {
4111
+ eas: 'bytes32',
4112
+ },
4113
+ Relation: {
4114
+ eas: 'bytes32',
4115
+ },
4116
+ List: {
4117
+ eas: 'bytes32[]',
4118
+ },
4119
+ File: {
4120
+ eas: 'bytes32',
4121
+ },
4122
+ Json: {
4123
+ eas: 'bytes32',
4124
+ },
4125
+ Blob: {
4126
+ eas: 'bytes32',
4127
+ },
4128
+ Boolean: {
4129
+ eas: 'bool',
4130
+ },
4131
+ Date: {
4132
+ eas: 'uint256',
4133
+ },
4134
+ Html: {
4135
+ eas: 'bytes32',
4136
+ },
4137
+ };
4138
+ /** Full property names ending in `Id` that must not be stripped to a “base” name for `allProperties` keys. */
4139
+ const PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP = new Set(['storageTransactionId']);
4140
+ const INTERNAL_PROPERTY_NAMES = [
4141
+ 'localId',
4142
+ 'uid',
4143
+ 'seedLocalId',
4144
+ 'seedUid',
4145
+ 'schemaUid',
4146
+ 'attestationCreatedAt',
4147
+ 'attestationRaw',
4148
+ 'createdAt',
4149
+ 'updatedAt',
4150
+ 'lastVersionPublishedAt',
4151
+ 'latestVersionLocalId',
4152
+ 'latestVersionUid',
4153
+ 'lastLocalUpdateAt',
4154
+ 'modelName',
4155
+ 'refSeedType',
4156
+ 'refValueType',
4157
+ 'refResolvedValue',
4158
+ 'refResolvedDisplayValue',
4159
+ 'type',
4160
+ // Image
4161
+ 'src',
4162
+ 'alt',
4163
+ //
4164
+ 'versionLocalId',
4165
+ 'versionsCount',
4166
+ 'versionUid',
4167
+ '_markedForDeletion',
4168
+ // SDK-internal: wallet address of attester; never publish as property attestation
4169
+ 'publisher',
4170
+ // SDK-internal: Unix timestamp when attestations were revoked; never a schema field
4171
+ 'revokedAt',
4172
+ ];
4173
+ /** Schema definition of the Version attestation (zero resolver, revocable). */
4174
+ const VERSION_SCHEMA_DEF = 'bytes32 version';
4175
+ /**
4176
+ * UID of {@link VERSION_SCHEMA_DEF}. Schema UIDs hash the definition, resolver and revocable flag,
4177
+ * so this is the same on every chain; the schema must still be registered on each one.
4178
+ */
4179
+ const VERSION_SCHEMA_UID = '0x13c0fd59d69dbce40501a41f8b37768d26dd2e2bb0cad64615334d84f7b9bdf6';
4180
+ /** @deprecated The UID is chain-independent. Use {@link VERSION_SCHEMA_UID}. */
4181
+ const VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA = VERSION_SCHEMA_UID;
4182
+ const defaultAttestationData = {
4183
+ recipient: ZERO_ADDRESS,
4184
+ revocable: true,
4185
+ value: BigInt(0),
4186
+ refUID: ZERO_BYTES32,
4187
+ expirationTime: BigInt(0),
4188
+ data: ZERO_BYTES,
4189
+ };
4190
+ var ImageSize;
4191
+ (function (ImageSize) {
4192
+ ImageSize[ImageSize["EXTRA_SMALL"] = 480] = "EXTRA_SMALL";
4193
+ ImageSize[ImageSize["SMALL"] = 760] = "SMALL";
4194
+ ImageSize[ImageSize["MEDIUM"] = 1024] = "MEDIUM";
4195
+ ImageSize[ImageSize["LARGE"] = 1440] = "LARGE";
4196
+ ImageSize[ImageSize["EXTRA_LARGE"] = 1920] = "EXTRA_LARGE";
4197
+ })(ImageSize || (ImageSize = {}));
4198
+ const CLIENT_NOT_INITIALIZED = 'ClientManager is not initialized. Please call init() first.';
4199
+ const INIT_SCRIPT_SUCCESS_MESSAGE = '[Seed Protocol] Finished running init script';
4200
+ var SeedModels;
4201
+ (function (SeedModels) {
4202
+ SeedModels["Seed"] = "Seed";
4203
+ SeedModels["Metadata"] = "Metadata";
4204
+ SeedModels["Version"] = "Version";
4205
+ })(SeedModels || (SeedModels = {}));
4206
+ // Internal SDK schema that should not be created in app's files directory
4207
+ const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
4208
+ const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
4209
+ /** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
4210
+ const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
4211
+ /**
4212
+ * Check if a schema is an internal SDK schema that should not be created in app files
4213
+ */
4214
+ function isInternalSchema(schemaName, schemaId) {
4215
+ return schemaName === SEED_PROTOCOL_SCHEMA_NAME ||
4216
+ (schemaId !== undefined && INTERNAL_SCHEMA_IDS.includes(schemaId));
4217
+ }
4218
+ /**
4219
+ * Model ids (schemaFileId) of the internal Seed Protocol storage models. Storage seeds are always
4220
+ * these models, even if a user schema also defines a model named Image/File/Html.
4221
+ */
4222
+ const INTERNAL_STORAGE_MODEL_FILE_IDS = {
4223
+ image: 'SEEDPROTOCOL_IMAGE',
4224
+ file: 'SEEDPROTOCOL_FILE',
4225
+ html: 'SEEDPROTOCOL_HTML',
4226
+ };
4227
+
4228
+ const logger$1 = debug('seedSdk:helpers:ensureImageLocal');
4229
+ /** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
4230
+ const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
4231
+ const IMAGE_SIZES = [
4232
+ ImageSize.EXTRA_SMALL,
4233
+ ImageSize.SMALL,
4234
+ ImageSize.MEDIUM,
4235
+ ImageSize.LARGE,
4236
+ ImageSize.EXTRA_LARGE,
4237
+ ];
4238
+ const inFlightByKey = new Map();
4239
+ const normalizeArweaveTxIdForEnsure = (raw) => {
4240
+ if (raw == null || raw === '')
4241
+ return undefined;
4242
+ const t = String(raw).trim();
4243
+ if (ARWEAVE_TX_ID_RE.test(t))
4244
+ return t;
4245
+ const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
4246
+ if (m)
4247
+ return m[1];
4248
+ const embedded = t.match(/[a-z0-9_-]{43}/gi);
4249
+ if (embedded) {
4250
+ for (const candidate of embedded) {
4251
+ if (ARWEAVE_TX_ID_RE.test(candidate))
4252
+ return candidate;
4253
+ }
4254
+ }
4255
+ return undefined;
4256
+ };
4257
+ const closestImageSize = (width) => {
4258
+ let best = ImageSize.EXTRA_SMALL;
4259
+ let bestDist = Math.abs(best - width);
4260
+ for (const size of IMAGE_SIZES) {
4261
+ const dist = Math.abs(size - width);
4262
+ if (dist < bestDist) {
4263
+ best = size;
4264
+ bestDist = dist;
4265
+ }
4266
+ }
4267
+ return best;
4268
+ };
4269
+ const mapRequestedWidthsToImageSizes = (widths) => {
4270
+ const requested = widths && widths.length > 0 ? widths : [ImageSize.EXTRA_SMALL];
4271
+ const unique = new Set();
4272
+ for (const w of requested) {
4273
+ if (typeof w !== 'number' || !Number.isFinite(w) || w <= 0)
4274
+ continue;
4275
+ unique.add(closestImageSize(w));
4276
+ }
4277
+ if (unique.size === 0) {
4278
+ unique.add(ImageSize.EXTRA_SMALL);
4279
+ }
4280
+ return Array.from(unique).sort((a, b) => a - b);
4281
+ };
4282
+ const getBasename = (filePath) => {
4283
+ const path = BaseFileManager.getPathModule();
4284
+ return path.basename(filePath);
4285
+ };
4286
+ const getBasenameWithoutExtension = (fileName) => {
4287
+ const match = fileName.match(/^(.*[\/\\])?([^\/\\]+?)(\.[^.\/\\]*)?$/);
4288
+ return match?.[2] ?? fileName;
4289
+ };
4290
+ const resolveMatchingImagePath = async (needle) => {
4291
+ const dirPath = BaseFileManager.getFilesPath('images');
4292
+ const dirExists = await BaseFileManager.pathExists(dirPath);
4293
+ if (!dirExists)
4294
+ return undefined;
4295
+ const fs = await BaseFileManager.getFs();
4296
+ const path = BaseFileManager.getPathModule();
4297
+ const files = await fs.promises.readdir(dirPath);
4298
+ // Prefer exact basename match (files only); skip size dirs.
4299
+ const exact = files.find((file) => path.basename(file) === needle);
4300
+ if (exact) {
4301
+ const candidate = BaseFileManager.getFilesPath('images', exact);
4302
+ try {
4303
+ const zenfs = await BaseFileManager.getFs();
4304
+ const stat = await zenfs.promises.stat(candidate);
4305
+ if (stat.isFile())
4306
+ return candidate;
4307
+ }
4308
+ catch {
4309
+ // fall through
4310
+ }
4311
+ }
4312
+ const matchingFiles = files.filter((file) => {
4313
+ const base = path.basename(file);
4314
+ return base.includes(needle);
4315
+ });
4316
+ for (const file of matchingFiles) {
4317
+ const candidate = BaseFileManager.getFilesPath('images', file);
4318
+ try {
4319
+ const zenfs = await BaseFileManager.getFs();
4320
+ const stat = await zenfs.promises.stat(candidate);
4321
+ if (stat.isFile())
4322
+ return candidate;
4323
+ }
4324
+ catch {
4325
+ continue;
4326
+ }
4327
+ }
4328
+ return undefined;
4329
+ };
4330
+ const sizedVariantPath = (originalFilePath, size) => {
4331
+ const path = BaseFileManager.getPathModule();
4332
+ const dir = path.dirname(originalFilePath);
4333
+ const base = getBasenameWithoutExtension(getBasename(originalFilePath));
4334
+ return path.join(dir, String(size), `${base}.webp`);
4335
+ };
4336
+ const ensureKey = (txId, fileName, sizes) => {
4337
+ const idPart = txId ?? fileName ?? '';
4338
+ return `${idPart}|${sizes.join(',')}`;
4339
+ };
4340
+ const runEnsureImageLocal = async (params) => {
4341
+ if (!supportsOpfsFileDownloads()) {
4342
+ return { status: 'unsupported' };
4343
+ }
4344
+ const fileName = params.fileName?.trim() || undefined;
4345
+ const txId = normalizeArweaveTxIdForEnsure(params.transactionId) ??
4346
+ normalizeArweaveTxIdForEnsure(fileName);
4347
+ if (!txId && !fileName) {
4348
+ return { status: 'missing-id' };
4349
+ }
4350
+ const targetSizes = mapRequestedWidthsToImageSizes(params.widths);
4351
+ const needles = [fileName, txId].filter((n) => typeof n === 'string' && n.length > 0);
4352
+ try {
4353
+ let filePath;
4354
+ for (const needle of needles) {
4355
+ filePath = await resolveMatchingImagePath(needle);
4356
+ if (filePath)
4357
+ break;
4358
+ }
4359
+ if (!filePath && txId) {
4360
+ await downloadTransactionIdWithDedupe(txId);
4361
+ for (const needle of needles) {
4362
+ filePath = await resolveMatchingImagePath(needle);
4363
+ if (filePath)
4364
+ break;
4365
+ }
4366
+ // Downloads store as bare tx id
4367
+ if (!filePath) {
4368
+ const direct = BaseFileManager.getFilesPath('images', txId);
4369
+ if (await BaseFileManager.pathExists(direct)) {
4370
+ filePath = direct;
4371
+ }
4372
+ }
4373
+ }
4374
+ if (!filePath) {
4375
+ return { status: 'failed' };
4376
+ }
4377
+ const createdWidths = [];
4378
+ for (const size of targetSizes) {
4379
+ const variantPath = sizedVariantPath(filePath, size);
4380
+ const exists = await BaseFileManager.pathExists(variantPath);
4381
+ if (exists)
4382
+ continue;
4383
+ await BaseFileManager.resizeImage({
4384
+ filePath,
4385
+ width: size,
4386
+ height: size,
4387
+ });
4388
+ createdWidths.push(size);
4389
+ }
4390
+ return {
4391
+ status: 'ready',
4392
+ filePath,
4393
+ createdWidths,
4394
+ };
4395
+ }
4396
+ catch (error) {
4397
+ logger$1('ensureImageLocal failed', error);
4398
+ return { status: 'failed' };
4399
+ }
4400
+ };
4401
+ /**
4402
+ * Ensure an image original exists in OPFS (downloading from Arweave if needed)
4403
+ * and create only the requested ImageSize variant(s) for that one file.
4404
+ */
4405
+ const ensureImageLocal = async (params) => {
4406
+ if (!supportsOpfsFileDownloads()) {
4407
+ return { status: 'unsupported' };
4408
+ }
4409
+ const fileName = params.fileName?.trim() || undefined;
4410
+ const txId = normalizeArweaveTxIdForEnsure(params.transactionId) ??
4411
+ normalizeArweaveTxIdForEnsure(fileName);
4412
+ if (!txId && !fileName) {
4413
+ return { status: 'missing-id' };
4414
+ }
4415
+ const targetSizes = mapRequestedWidthsToImageSizes(params.widths);
4416
+ const key = ensureKey(txId, fileName, targetSizes);
4417
+ const existing = inFlightByKey.get(key);
4418
+ if (existing) {
4419
+ return existing;
4420
+ }
4421
+ const inFlight = (async () => {
4422
+ try {
4423
+ return await runEnsureImageLocal({
4424
+ transactionId: txId,
4425
+ fileName,
4426
+ widths: targetSizes,
4427
+ });
4428
+ }
4429
+ finally {
4430
+ inFlightByKey.delete(key);
4431
+ }
4432
+ })();
4433
+ inFlightByKey.set(key, inFlight);
4434
+ return inFlight;
4435
+ };
4436
+
4437
+ const randomId = customAlphabet(alphanumeric, 10);
4438
+ /**
4439
+ * A 10-character local id. Never starts with "0x" (about 1 in 3,844 random ids would), so code that
4440
+ * tells local ids from EAS uids by that prefix can't mistake one for the other.
4441
+ */
4442
+ const generateId = () => {
4443
+ let id = randomId();
4444
+ while (id.startsWith('0x'))
4445
+ id = randomId();
4446
+ return id;
4447
+ };
4448
+
4449
+ var generateId$1 = /*#__PURE__*/Object.freeze({
4450
+ __proto__: null,
4451
+ generateId: generateId
4452
+ });
4453
+
4454
+ const logger = debug('seedSdk:shared:helpers');
4455
+ const toSnakeCase = (str) => {
4456
+ return str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
4457
+ };
4458
+ const getMimeType = (base64) => {
4459
+ if (!base64) {
4460
+ return null;
4461
+ }
4462
+ const result = base64.match(/^data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,/);
4463
+ if (result && result.length > 1) {
4464
+ return result[1];
4465
+ }
4466
+ else {
4467
+ return null; // MIME type could not be determined
4468
+ }
4469
+ };
4470
+ const getCorrectId = (localIdOrUid) => {
4471
+ const id = {
4472
+ localId: undefined,
4473
+ uid: undefined,
4474
+ };
4475
+ if (!localIdOrUid) {
4476
+ return id;
4477
+ }
4478
+ if (localIdOrUid.length === 10) {
4479
+ id.localId = localIdOrUid;
4480
+ }
4481
+ if (localIdOrUid.startsWith('0x') && localIdOrUid.length === 66) {
4482
+ id.uid = localIdOrUid;
4483
+ }
4484
+ return id;
4485
+ };
4486
+ const getDataTypeFromString = (data) => {
4487
+ const nonImageBase64Regex = /^(?!data:image\/(?:jpeg|png|gif|bmp|webp);base64,)[A-Za-z0-9+/=]+$/;
4488
+ if (nonImageBase64Regex.test(data)) {
4489
+ return 'base64';
4490
+ }
4491
+ // Regular expression for base64 (simple version, checking for base64 format)
4492
+ const imageBase64Regex = /^data:image\/[a-zA-Z]+;base64,[A-Za-z0-9+/]+={0,2}$/;
4493
+ if (imageBase64Regex.test(data)) {
4494
+ return 'imageBase64';
4495
+ }
4496
+ // Blob URLs are fetchable but session-scoped; recognize them as url type
4497
+ if (data.startsWith('blob:')) {
4498
+ return 'url';
4499
+ }
4500
+ // Regular expression for URL (simple version, checking for common URL format)
4501
+ const urlRegex = /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/;
4502
+ if (urlRegex.test(data)) {
4503
+ return 'url';
4504
+ }
4505
+ return null;
4506
+ };
4507
+ const convertTxIdToImage = async (txId) => {
4508
+ const imageFilePath = BaseFileManager.getFilesPath('images', txId);
4509
+ const fileExists = await BaseFileManager.pathExists(imageFilePath);
4510
+ if (!fileExists) {
4511
+ logger(`[ItemView] [updateImage] ${imageFilePath} does not exist`);
4512
+ return;
4513
+ }
4514
+ const buffer = await BaseFileManager.readFileAsBuffer(imageFilePath);
4515
+ // Convert Blob to ArrayBuffer if needed, or use Buffer directly
4516
+ let arrayBuffer;
4517
+ if (buffer instanceof Blob) {
4518
+ arrayBuffer = await buffer.arrayBuffer();
4519
+ }
4520
+ else if (buffer instanceof ArrayBuffer) {
4521
+ arrayBuffer = buffer;
4522
+ }
4523
+ else {
4524
+ // Node.js Buffer
4525
+ const sliced = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
4526
+ // Handle SharedArrayBuffer case by creating a new ArrayBuffer
4527
+ if (sliced instanceof SharedArrayBuffer) {
4528
+ const uint8Array = new Uint8Array(sliced);
4529
+ arrayBuffer = uint8Array.buffer.slice(0);
4530
+ }
4531
+ else {
4532
+ arrayBuffer = sliced;
4533
+ }
4534
+ }
4535
+ const uint = new Uint8Array(arrayBuffer);
4536
+ const imageBlob = new Blob([uint]);
4537
+ return URL.createObjectURL(imageBlob);
4538
+ };
4539
+ /**
4540
+ * Constructs an Arweave URL for a storage transaction ID
4541
+ * @param storageTransactionId - The Arweave transaction ID
4542
+ * @returns The full URL to access the transaction data on Arweave (e.g., https://arweave.net/raw/{transactionId})
4543
+ * @deprecated Use BaseArweaveClient.getRawUrl() instead for better consistency and testability
4544
+ */
4545
+ const getArweaveUrlForTransaction = (storageTransactionId) => {
4546
+ return BaseArweaveClient.getRawUrl(storageTransactionId);
4547
+ };
4548
+
4549
+ /**
4550
+ * Save/restore helper for swapping a single facade implementation in tests.
4551
+ */
4552
+ function createFacadeTestHandle(getImpl, setImpl, next) {
4553
+ const previous = getImpl();
4554
+ setImpl(next);
4555
+ return {
4556
+ restore() {
4557
+ setImpl(previous);
4558
+ },
4559
+ };
4560
+ }
4561
+
4562
+ class BasePathResolver {
4563
+ static configure(impl) {
4564
+ if (!impl) {
4565
+ throw new Error('Cannot configure PathResolver with undefined or null. Ensure the platform-specific PathResolver is properly created.');
4566
+ }
4567
+ BasePathResolver._impl = impl;
4568
+ }
4569
+ static createForTesting(impl) {
4570
+ return createFacadeTestHandle(() => BasePathResolver._impl, (next) => {
4571
+ BasePathResolver._impl = next;
4572
+ }, impl);
4573
+ }
4574
+ static requireImpl() {
4575
+ if (!BasePathResolver._impl) {
4576
+ throw new Error('PathResolver not configured. Please ensure the platform-specific PathResolver is registered. For Node.js, import from @seedprotocol/sdk/node. For browser, the SDK should auto-initialize.');
4577
+ }
4578
+ return BasePathResolver._impl;
4579
+ }
4580
+ /**
4581
+ * @deprecated Prefer static facade methods (e.g. BasePathResolver.getDotSeedDir()).
4582
+ */
4583
+ static getInstance() {
4584
+ return BasePathResolver.requireImpl();
4585
+ }
4586
+ static getRootWithNodeModules() {
4587
+ return BasePathResolver.requireImpl().getRootWithNodeModules();
4588
+ }
4589
+ static getSdkRootDir() {
4590
+ return BasePathResolver.requireImpl().getSdkRootDir();
4591
+ }
4592
+ static getNodeModulesDir() {
4593
+ return BasePathResolver.requireImpl().getNodeModulesDir();
4594
+ }
4595
+ static getDotSeedDir(schemaFileDir) {
4596
+ return BasePathResolver.requireImpl().getDotSeedDir(schemaFileDir);
4597
+ }
4598
+ static findConfigFile(searchDir) {
4599
+ return BasePathResolver.requireImpl().findConfigFile(searchDir);
4600
+ }
4601
+ static getAppPaths(schemaFileDir) {
4602
+ return BasePathResolver.requireImpl().getAppPaths(schemaFileDir);
4603
+ }
4604
+ }
4605
+ BasePathResolver._impl = null;
4606
+
4607
+ export { generateId as $, seeds as A, uploadProcesses as B, versions as C, DEFAULT_TEXT_MAX_LENGTH as D, BaseDb as E, AmbiguousModelError as F, eventEmitter as G, toSnakeCase as H, BasePathResolver as I, BaseFileManager as J, getPropertyIdForModelAndName as K, resolveItemModelFileId as L, ModelPropertyDataTypes as M, resolveSeedIdsFromRefString as N, normalizeRelationPropertyValue as O, Property as P, isPublishedSeedRef as Q, getStorageDirForDataType as R, getContentSha256 as S, THtmlEmbeddedDataUriPolicy as T, buildArweaveContentTags as U, getItemStorageSubdir as V, getItemStorageLocalFileName as W, normalizePublisher as X, getAllAddressesFromDb as Y, scheduleBulkFilesDownloadFromEasSync as Z, EAS_SEED_DATA_SYNCED_TO_DB_EVENT as _, TProperty as a, SchemaSchema as a$, normalizeHexAddress as a0, getItemStoragePropertiesForModel as a1, addModelsToDb as a2, INIT_SCRIPT_SUCCESS_MESSAGE as a3, SCHEMA_TS as a4, getCorrectId as a5, SEED_CONFIG_FILE as a6, SEED_CONFIG_FALLBACKS as a7, isNode as a8, ZERO_BYTES32 as a9, normalizeAddressConfig as aA, normalizeAddressList as aB, normalizeArweaveTxIdForEnsure as aC, normalizeFeedItemFields as aD, resolveMediaRef as aE, isInternalSchema as aF, writeModelToDb as aG, writePropertyToDb as aH, addSchemaToDb as aI, renameModelInDb as aJ, loadModelsFromDbForSchema as aK, downloadAllFilesRequestHandler as aL, downloadAllFilesBinaryRequestHandler as aM, INTERNAL_SCHEMA_IDS as aN, linkModelToSchema as aO, getWatchedAddressesFromDb as aP, getOwnedAddressesFromDb as aQ, CLIENT_NOT_INITIALIZED as aR, getStorageTransactionIdForSeedUid as aS, convertTxIdToImage as aT, downloadTransactionIdWithDedupe as aU, getPropertyIdForSchemaFileId as aV, getDataTypeFromString as aW, getMimeType as aX, PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP as aY, ModelSchema as aZ, BaseFileManager$1 as a_, resolveModelRecord as aa, getItemModelScope as ab, VERSION_SCHEMA_UID as ac, INTERNAL_PROPERTY_NAMES as ad, isStorageSeedRef as ae, defaultAttestationData as af, INTERNAL_DATA_TYPES as ag, isBrowser as ah, getModelIdByFileId as ai, getModelId as aj, setCachedPropertyRefresher as ak, getArweaveUrlForTransaction as al, INTERNAL_STORAGE_MODEL_FILE_IDS as am, CONTENT_SHA256_TAG as an, CONTENT_TYPE_TAG as ao, ImageSize as ap, SEED_PROTOCOL_SCHEMA_NAME as aq, SeedModels as ar, VERSION_SCHEMA_DEF as as, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as at, classifyMediaRef as au, closestImageSize as av, contentSha256TagMatches as aw, ensureImageLocal as ax, getAddressesForItemsFilter as ay, getFeedItemStringField as az, TPropertyConstructor as b, ModelSchemaSchema as b0, resolveModelRecord$1 as b1, db as b2, download as b3, generateId$1 as b4, TPropertyDataType as c, TPropertyDefs as d, TStorageType as e, TValidationRules as f, normalizePropertyRecordSchema as g, appState as h, isDataType as i, arweaveL1FinalizeJobs as j, config as k, easSyncProcesses as l, metadata as m, normalizeDataType as n, htmlEmbeddedImageCoPublish as o, modelRelations as p, modelSchemas as q, modelUids as r, models as s, modelsRelations as t, properties as u, propertiesRelations as v, propertyUidRelations as w, propertyUids as x, publishProcesses as y, schemas as z };
4608
+ //# sourceMappingURL=BasePathResolver-Cm4apKRb.js.map