@seedprotocol/sdk 0.4.32 → 0.5.1

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 (323) hide show
  1. package/dist/BasePathResolver-BDgc7c4T.js +485 -0
  2. package/dist/BasePathResolver-BDgc7c4T.js.map +1 -0
  3. package/dist/{ModelProperty-e_hXSFvf.js → ModelProperty-D-ysg8zA.js} +37 -43
  4. package/dist/ModelProperty-D-ysg8zA.js.map +1 -0
  5. package/dist/{Schema-DonRkUOJ.js → Schema-CyCftnKI.js} +40 -40
  6. package/dist/{Schema-DonRkUOJ.js.map → Schema-CyCftnKI.js.map} +1 -1
  7. package/dist/{SchemaValidationService-DcmfhQae.js → SchemaValidationService-POM6jHbJ.js} +9 -5
  8. package/dist/{SchemaValidationService-DcmfhQae.js.map → SchemaValidationService-POM6jHbJ.js.map} +1 -1
  9. package/dist/{backfillMetadataPropertyIds-CKTfvFgQ.js → backfillMetadataPropertyIds-DzZw57iJ.js} +3 -11
  10. package/dist/{backfillMetadataPropertyIds-CKTfvFgQ.js.map → backfillMetadataPropertyIds-DzZw57iJ.js.map} +1 -1
  11. package/dist/cjs/{ModelProperty-BQYU5hPQ.js → ModelProperty-CmuGJvyi.js} +25 -26
  12. package/dist/cjs/{ModelProperty-BQYU5hPQ.js.map → ModelProperty-CmuGJvyi.js.map} +1 -1
  13. package/dist/cjs/{Schema-BcRHcQ0W.js → Schema-gpFnZMhB.js} +28 -29
  14. package/dist/cjs/{Schema-BcRHcQ0W.js.map → Schema-gpFnZMhB.js.map} +1 -1
  15. package/dist/cjs/{SchemaValidationService-CQNDgyZl.js → SchemaValidationService-E3xTSRai.js} +9 -10
  16. package/dist/cjs/{SchemaValidationService-CQNDgyZl.js.map → SchemaValidationService-E3xTSRai.js.map} +1 -1
  17. package/dist/cjs/{backfillMetadataPropertyIds-Dn4oVmEv.js → backfillMetadataPropertyIds-_bivrvRs.js} +11 -12
  18. package/dist/cjs/{backfillMetadataPropertyIds-Dn4oVmEv.js.map → backfillMetadataPropertyIds-_bivrvRs.js.map} +1 -1
  19. package/dist/cjs/eas-BwDKJmlb.js +112 -0
  20. package/dist/cjs/eas-BwDKJmlb.js.map +1 -0
  21. package/dist/cjs/{getItem-DpnPrzl3.js → getItem-MShQw3sz.js} +11 -12
  22. package/dist/cjs/{getItem-DpnPrzl3.js.map → getItem-MShQw3sz.js.map} +1 -1
  23. package/dist/cjs/{getPublishPayload-CGKMEL3H.js → getPublishPayload-C1nOOXp_.js} +93 -83
  24. package/dist/cjs/getPublishPayload-C1nOOXp_.js.map +1 -0
  25. package/dist/cjs/{getPublishUploads-DeI0f2UN.js → getPublishUploads-BjgxgrKD.js} +17 -18
  26. package/dist/cjs/{getPublishUploads-DeI0f2UN.js.map → getPublishUploads-BjgxgrKD.js.map} +1 -1
  27. package/dist/cjs/{getSegmentedItemProperties-BgS_FhAx.js → getSegmentedItemProperties-Cuw7wcxb.js} +64 -15
  28. package/dist/cjs/getSegmentedItemProperties-Cuw7wcxb.js.map +1 -0
  29. package/dist/cjs/{index-BnAqr2le.js → index-9Z2FOvLD.js} +12 -13
  30. package/dist/cjs/index-9Z2FOvLD.js.map +1 -0
  31. package/dist/cjs/{index-ByozbTn_.js → index-vk2DeF2D.js} +1237 -3235
  32. package/dist/cjs/index-vk2DeF2D.js.map +1 -0
  33. package/dist/cjs/index.browser-BSf8HpnU.js +22 -0
  34. package/dist/cjs/index.browser-BSf8HpnU.js.map +1 -0
  35. package/dist/cjs/{ownership-CsWuaNfH.js → ownership-DhWda0J9.js} +11 -25
  36. package/dist/cjs/{ownership-CsWuaNfH.js.map → ownership-DhWda0J9.js.map} +1 -1
  37. package/dist/cjs/{property-CeR45LMx.js → property-D3Ww2_Qh.js} +13 -14
  38. package/dist/cjs/{property-CeR45LMx.js.map → property-D3Ww2_Qh.js.map} +1 -1
  39. package/dist/cjs/{syncDbWithEas-CA2Lum5V.js → syncDbWithEas-Dht3_7UD.js} +26 -39
  40. package/dist/cjs/syncDbWithEas-Dht3_7UD.js.map +1 -0
  41. package/dist/configurePlatform-R5neRbQ9.js +27 -0
  42. package/dist/configurePlatform-R5neRbQ9.js.map +1 -0
  43. package/dist/constants-B5S5JPDK.js +660 -0
  44. package/dist/constants-B5S5JPDK.js.map +1 -0
  45. package/dist/constants-DMHTYMgJ.js +120 -0
  46. package/dist/constants-DMHTYMgJ.js.map +1 -0
  47. package/dist/db-Cvh84NY7.js +1972 -0
  48. package/dist/db-Cvh84NY7.js.map +1 -0
  49. package/dist/eas-D9b7z2Wn.js +68 -0
  50. package/dist/eas-D9b7z2Wn.js.map +1 -0
  51. package/dist/{getItem-GOXWo_Iy.js → getItem-B81V3m4S.js} +10 -6
  52. package/dist/{getItem-GOXWo_Iy.js.map → getItem-B81V3m4S.js.map} +1 -1
  53. package/dist/{getPublishPayload-D16enahU.js → getPublishPayload-CNYsn8-6.js} +87 -74
  54. package/dist/getPublishPayload-CNYsn8-6.js.map +1 -0
  55. package/dist/{getPublishUploads-wGqH19UY.js → getPublishUploads-D9rPHkB7.js} +14 -10
  56. package/dist/{getPublishUploads-wGqH19UY.js.map → getPublishUploads-D9rPHkB7.js.map} +1 -1
  57. package/dist/{getSegmentedItemProperties-Be3kYWY3.js → getSegmentedItemProperties-Bg3_b-b1.js} +18 -15
  58. package/dist/getSegmentedItemProperties-Bg3_b-b1.js.map +1 -0
  59. package/dist/{index-BcXKZQpX.js → index--F3Wolt5.js} +1171 -5452
  60. package/dist/index--F3Wolt5.js.map +1 -0
  61. package/dist/{index-BFyMxc7e.js → index-QMrBK-L3.js} +2 -2
  62. package/dist/index-QMrBK-L3.js.map +1 -0
  63. package/dist/index-oi4roUVf.js +22 -0
  64. package/dist/index-oi4roUVf.js.map +1 -0
  65. package/dist/index.node-Bow8kHew.js +503 -0
  66. package/dist/index.node-Bow8kHew.js.map +1 -0
  67. package/dist/main.cjs +16 -15
  68. package/dist/main.cjs.map +1 -1
  69. package/dist/main.js +31 -22
  70. package/dist/main.js.map +1 -1
  71. package/dist/node.js +37 -363
  72. package/dist/node.js.map +1 -1
  73. package/dist/{ownership-C17YhE7J.js → ownership-BF_ZUKIp.js} +13 -9
  74. package/dist/{ownership-C17YhE7J.js.map → ownership-BF_ZUKIp.js.map} +1 -1
  75. package/dist/platform.browser.js +3499 -0
  76. package/dist/platform.browser.js.map +1 -0
  77. package/dist/platform.node.js +19 -0
  78. package/dist/platform.node.js.map +1 -0
  79. package/dist/{property-CRAau-Q-.js → property-BdyDfcSc.js} +14 -11
  80. package/dist/property-BdyDfcSc.js.map +1 -0
  81. package/dist/src/Item/Item.d.ts.map +1 -1
  82. package/dist/src/Item/service/actors/fetchDataFromEas.d.ts.map +1 -1
  83. package/dist/src/Model/service/actors/createModelProperties.d.ts.map +1 -1
  84. package/dist/src/Model/service/modelMachine.d.ts +1 -1
  85. package/dist/src/browser/db/Db.d.ts +17 -18
  86. package/dist/src/browser/db/Db.d.ts.map +1 -1
  87. package/dist/src/browser/helpers/ArweaveClient.d.ts +10 -27
  88. package/dist/src/browser/helpers/ArweaveClient.d.ts.map +1 -1
  89. package/dist/src/browser/helpers/EasClient.d.ts +6 -4
  90. package/dist/src/browser/helpers/EasClient.d.ts.map +1 -1
  91. package/dist/src/browser/helpers/FileManager.d.ts +27 -26
  92. package/dist/src/browser/helpers/FileManager.d.ts.map +1 -1
  93. package/dist/src/browser/helpers/PathResolver.d.ts +6 -5
  94. package/dist/src/browser/helpers/PathResolver.d.ts.map +1 -1
  95. package/dist/src/browser/helpers/QueryClient.d.ts +6 -5
  96. package/dist/src/browser/helpers/QueryClient.d.ts.map +1 -1
  97. package/dist/src/browser/workers/filesDownload.d.ts.map +1 -1
  98. package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
  99. package/dist/src/client/actors/processSchemaFiles.d.ts.map +1 -1
  100. package/dist/src/client/actors/saveConfig.d.ts.map +1 -1
  101. package/dist/src/db/Db/BaseDb.d.ts +6 -26
  102. package/dist/src/db/Db/BaseDb.d.ts.map +1 -1
  103. package/dist/src/db/read/getPublishPayload.d.ts.map +1 -1
  104. package/dist/src/db/write/createMetadata.d.ts.map +1 -1
  105. package/dist/src/db/write/updateMetadata.d.ts.map +1 -1
  106. package/dist/src/eas.d.ts +4 -37
  107. package/dist/src/eas.d.ts.map +1 -1
  108. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts +1 -101
  109. package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts.map +1 -1
  110. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts +1 -51
  111. package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts.map +1 -1
  112. package/dist/src/helpers/ArweaveClient/index.d.ts +2 -2
  113. package/dist/src/helpers/ArweaveClient/index.d.ts.map +1 -1
  114. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts +1 -15
  115. package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts.map +1 -1
  116. package/dist/src/helpers/ArweaveClient/uploadApiVerification.d.ts +1 -22
  117. package/dist/src/helpers/ArweaveClient/uploadApiVerification.d.ts.map +1 -1
  118. package/dist/src/helpers/EasClient/BaseEasClient.d.ts +1 -9
  119. package/dist/src/helpers/EasClient/BaseEasClient.d.ts.map +1 -1
  120. package/dist/src/helpers/FileManager/BaseFileManager.d.ts +4 -2
  121. package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
  122. package/dist/src/helpers/FileManager/IFileManager.d.ts +44 -0
  123. package/dist/src/helpers/FileManager/IFileManager.d.ts.map +1 -0
  124. package/dist/src/helpers/PathResolver/BasePathResolver.d.ts +16 -12
  125. package/dist/src/helpers/PathResolver/BasePathResolver.d.ts.map +1 -1
  126. package/dist/src/helpers/PathResolver/IPathResolver.d.ts +16 -0
  127. package/dist/src/helpers/PathResolver/IPathResolver.d.ts.map +1 -0
  128. package/dist/src/helpers/QueryClient/BaseQueryClient.d.ts +1 -6
  129. package/dist/src/helpers/QueryClient/BaseQueryClient.d.ts.map +1 -1
  130. package/dist/src/helpers/constants.d.ts +4 -22
  131. package/dist/src/helpers/constants.d.ts.map +1 -1
  132. package/dist/src/helpers/db.d.ts.map +1 -1
  133. package/dist/src/helpers/easPropertyCanonical.d.ts +1 -14
  134. package/dist/src/helpers/easPropertyCanonical.d.ts.map +1 -1
  135. package/dist/src/helpers/easRevokedFilter.d.ts +1 -9
  136. package/dist/src/helpers/easRevokedFilter.d.ts.map +1 -1
  137. package/dist/src/helpers/easUid.d.ts +1 -12
  138. package/dist/src/helpers/easUid.d.ts.map +1 -1
  139. package/dist/src/helpers/ethereumUtils.d.ts +5 -0
  140. package/dist/src/helpers/ethereumUtils.d.ts.map +1 -0
  141. package/dist/src/helpers/file/fetchAll/index.d.ts +1 -1
  142. package/dist/src/helpers/file/fetchAll/index.d.ts.map +1 -1
  143. package/dist/src/helpers/gateway/gatewayState.d.ts +2 -0
  144. package/dist/src/helpers/gateway/gatewayState.d.ts.map +1 -0
  145. package/dist/src/helpers/gateway/resolveSeedGatewayEndpoints.d.ts +2 -0
  146. package/dist/src/helpers/gateway/resolveSeedGatewayEndpoints.d.ts.map +1 -0
  147. package/dist/src/helpers/gateway/seedGatewayConfig.d.ts +2 -0
  148. package/dist/src/helpers/gateway/seedGatewayConfig.d.ts.map +1 -0
  149. package/dist/src/helpers/generateId.d.ts +2 -0
  150. package/dist/src/helpers/generateId.d.ts.map +1 -0
  151. package/dist/src/helpers/getSchemaForItemProperty.d.ts +1 -1
  152. package/dist/src/helpers/getSchemaForItemProperty.d.ts.map +1 -1
  153. package/dist/src/helpers/getSegmentedItemProperties.d.ts.map +1 -1
  154. package/dist/src/helpers/index.d.ts +15 -10
  155. package/dist/src/helpers/index.d.ts.map +1 -1
  156. package/dist/src/helpers/isSqliteUniqueConstraintError.d.ts +7 -0
  157. package/dist/src/helpers/isSqliteUniqueConstraintError.d.ts.map +1 -0
  158. package/dist/src/helpers/mediaRef.d.ts.map +1 -1
  159. package/dist/src/helpers/property/index.d.ts.map +1 -1
  160. package/dist/src/index.d.ts +9 -7
  161. package/dist/src/index.d.ts.map +1 -1
  162. package/dist/src/interfaces/IDb.d.ts +11 -0
  163. package/dist/src/interfaces/IDb.d.ts.map +1 -1
  164. package/dist/src/node/db/Db.d.ts +22 -37
  165. package/dist/src/node/db/Db.d.ts.map +1 -1
  166. package/dist/src/node/helpers/ArweaveClient.d.ts +4 -30
  167. package/dist/src/node/helpers/ArweaveClient.d.ts.map +1 -1
  168. package/dist/src/node/helpers/EasClient.d.ts +4 -6
  169. package/dist/src/node/helpers/EasClient.d.ts.map +1 -1
  170. package/dist/src/node/helpers/FileManager.d.ts +26 -25
  171. package/dist/src/node/helpers/FileManager.d.ts.map +1 -1
  172. package/dist/src/node/helpers/PathResolver.d.ts +6 -5
  173. package/dist/src/node/helpers/PathResolver.d.ts.map +1 -1
  174. package/dist/src/node/helpers/QueryClient.d.ts +4 -6
  175. package/dist/src/node/helpers/QueryClient.d.ts.map +1 -1
  176. package/dist/src/node/helpers/scripts.d.ts +5 -7
  177. package/dist/src/node/helpers/scripts.d.ts.map +1 -1
  178. package/dist/src/node/index.d.ts +2 -9
  179. package/dist/src/node/index.d.ts.map +1 -1
  180. package/dist/src/node/webpack/index.d.ts +1 -1
  181. package/dist/src/node/webpack/index.d.ts.map +1 -1
  182. package/dist/src/platform/configurePlatform.d.ts +6 -0
  183. package/dist/src/platform/configurePlatform.d.ts.map +1 -0
  184. package/dist/src/platform/index.browser.d.ts +3 -0
  185. package/dist/src/platform/index.browser.d.ts.map +1 -0
  186. package/dist/src/platform/index.d.ts +9 -0
  187. package/dist/src/platform/index.d.ts.map +1 -0
  188. package/dist/src/platform/index.node.d.ts +3 -0
  189. package/dist/src/platform/index.node.d.ts.map +1 -0
  190. package/dist/src/platform/types.d.ts +14 -0
  191. package/dist/src/platform/types.d.ts.map +1 -0
  192. package/dist/src/stores/eas.d.ts +1 -18
  193. package/dist/src/stores/eas.d.ts.map +1 -1
  194. package/dist/src/testing/platformTestHandle.d.ts +8 -0
  195. package/dist/src/testing/platformTestHandle.d.ts.map +1 -0
  196. package/dist/src/types/gateway.d.ts +2 -0
  197. package/dist/src/types/gateway.d.ts.map +1 -0
  198. package/dist/src/types/index.d.ts +5 -0
  199. package/dist/src/types/index.d.ts.map +1 -1
  200. package/dist/src/types/item.d.ts +1 -1
  201. package/dist/src/types/item.d.ts.map +1 -1
  202. package/dist/src/types/machines.d.ts +10 -0
  203. package/dist/src/types/machines.d.ts.map +1 -1
  204. package/dist/src/types/seedProtocol.d.ts +1 -1
  205. package/dist/src/types/seedProtocol.d.ts.map +1 -1
  206. package/dist/src/vite/index.d.ts +2 -47
  207. package/dist/src/vite/index.d.ts.map +1 -1
  208. package/dist/{syncDbWithEas-CB5aXPtf.js → syncDbWithEas-DMOJHtkP.js} +20 -15
  209. package/dist/syncDbWithEas-DMOJHtkP.js.map +1 -0
  210. package/dist/{updateSeedRevokedAt-BIu5Q4Po.js → updateSeedRevokedAt-Ba0OhDQj.js} +2 -2
  211. package/dist/{updateSeedRevokedAt-BIu5Q4Po.js.map → updateSeedRevokedAt-Ba0OhDQj.js.map} +1 -1
  212. package/dist/vite.cjs +5 -481
  213. package/dist/vite.cjs.map +1 -1
  214. package/dist/vite.js +1 -483
  215. package/dist/vite.js.map +1 -1
  216. package/package.json +42 -37
  217. package/dist/ArweaveClient-CZpZgmR2.js +0 -204
  218. package/dist/ArweaveClient-CZpZgmR2.js.map +0 -1
  219. package/dist/ArweaveClient-Cs7AL9dp.js +0 -204
  220. package/dist/ArweaveClient-Cs7AL9dp.js.map +0 -1
  221. package/dist/Db-CF6R7HIy.js +0 -2098
  222. package/dist/Db-CF6R7HIy.js.map +0 -1
  223. package/dist/Db-CZkONsdT.js +0 -248
  224. package/dist/Db-CZkONsdT.js.map +0 -1
  225. package/dist/EasClient-PXOzSzPG.js +0 -29
  226. package/dist/EasClient-PXOzSzPG.js.map +0 -1
  227. package/dist/EasClient-qfTiM2we.js +0 -29
  228. package/dist/EasClient-qfTiM2we.js.map +0 -1
  229. package/dist/FileManager-5GkHtxF7.js +0 -1256
  230. package/dist/FileManager-5GkHtxF7.js.map +0 -1
  231. package/dist/FileManager-jORQ8Bb6.js +0 -177
  232. package/dist/FileManager-jORQ8Bb6.js.map +0 -1
  233. package/dist/ModelProperty-e_hXSFvf.js.map +0 -1
  234. package/dist/PathResolver-B4_X69Rd.js +0 -204
  235. package/dist/PathResolver-B4_X69Rd.js.map +0 -1
  236. package/dist/PathResolver-Dz0RVGIz.js +0 -78
  237. package/dist/PathResolver-Dz0RVGIz.js.map +0 -1
  238. package/dist/QueryClient-CXHZ239d.js +0 -51
  239. package/dist/QueryClient-CXHZ239d.js.map +0 -1
  240. package/dist/QueryClient-D_UK4YLm.js +0 -35
  241. package/dist/QueryClient-D_UK4YLm.js.map +0 -1
  242. package/dist/arweave-default-shim.js +0 -6
  243. package/dist/cjs/getPublishPayload-CGKMEL3H.js.map +0 -1
  244. package/dist/cjs/getSegmentedItemProperties-BgS_FhAx.js.map +0 -1
  245. package/dist/cjs/index-BnAqr2le.js.map +0 -1
  246. package/dist/cjs/index-ByozbTn_.js.map +0 -1
  247. package/dist/cjs/syncDbWithEas-CA2Lum5V.js.map +0 -1
  248. package/dist/debug-default-shim.js +0 -27
  249. package/dist/getPublishPayload-D16enahU.js.map +0 -1
  250. package/dist/getSegmentedItemProperties-Be3kYWY3.js.map +0 -1
  251. package/dist/index-BFyMxc7e.js.map +0 -1
  252. package/dist/index-BcXKZQpX.js.map +0 -1
  253. package/dist/index-C9p-skT3.js +0 -18
  254. package/dist/index-C9p-skT3.js.map +0 -1
  255. package/dist/property-CRAau-Q-.js.map +0 -1
  256. package/dist/queries-Ct7CcQ3g.js +0 -16
  257. package/dist/queries-Ct7CcQ3g.js.map +0 -1
  258. package/dist/src/Item/queries.d.ts +0 -27
  259. package/dist/src/Item/queries.d.ts.map +0 -1
  260. package/dist/src/graphql/fragments/Attestation.d.ts +0 -2
  261. package/dist/src/graphql/fragments/Attestation.d.ts.map +0 -1
  262. package/dist/src/graphql/fragments/Schema.d.ts +0 -2
  263. package/dist/src/graphql/fragments/Schema.d.ts.map +0 -1
  264. package/dist/src/graphql/fragments/index.d.ts +0 -3
  265. package/dist/src/graphql/fragments/index.d.ts.map +0 -1
  266. package/dist/src/graphql/gql/fragment-masking.d.ts +0 -20
  267. package/dist/src/graphql/gql/fragment-masking.d.ts.map +0 -1
  268. package/dist/src/graphql/gql/gql.d.ts +0 -107
  269. package/dist/src/graphql/gql/gql.d.ts.map +0 -1
  270. package/dist/src/graphql/gql/graphql.d.ts +0 -2969
  271. package/dist/src/graphql/gql/graphql.d.ts.map +0 -1
  272. package/dist/src/graphql/gql/index.d.ts +0 -3
  273. package/dist/src/graphql/gql/index.d.ts.map +0 -1
  274. package/dist/src/helpers/ArweaveClient/queries.d.ts +0 -13
  275. package/dist/src/helpers/ArweaveClient/queries.d.ts.map +0 -1
  276. package/dist/src/helpers/file/queries.d.ts +0 -9
  277. package/dist/src/helpers/file/queries.d.ts.map +0 -1
  278. package/dist/src/helpers/image/queries.d.ts +0 -7
  279. package/dist/src/helpers/image/queries.d.ts.map +0 -1
  280. package/dist/src/node/codegen/drizzle.d.ts +0 -5
  281. package/dist/src/node/codegen/drizzle.d.ts.map +0 -1
  282. package/dist/src/node/codegen/index.d.ts +0 -2
  283. package/dist/src/node/codegen/index.d.ts.map +0 -1
  284. package/dist/src/node/codegen/ts-to-proto.d.ts +0 -9
  285. package/dist/src/node/codegen/ts-to-proto.d.ts.map +0 -1
  286. package/dist/src/node/db/node.app.db.config.d.ts +0 -4
  287. package/dist/src/node/db/node.app.db.config.d.ts.map +0 -1
  288. package/dist/src/node/helpers/index.d.ts +0 -3
  289. package/dist/src/node/helpers/index.d.ts.map +0 -1
  290. package/dist/src/vite/arweave-default-shim.d.ts +0 -4
  291. package/dist/src/vite/arweave-default-shim.d.ts.map +0 -1
  292. package/dist/src/vite/debug-default-shim.d.ts +0 -3
  293. package/dist/src/vite/debug-default-shim.d.ts.map +0 -1
  294. package/dist/src/vite/easFix.d.ts +0 -2
  295. package/dist/src/vite/easFix.d.ts.map +0 -1
  296. package/dist/syncDbWithEas-CB5aXPtf.js.map +0 -1
  297. /package/dist/db/drizzle/{drizzle/0000_married_malice.sql → 0000_married_malice.sql} +0 -0
  298. /package/dist/db/drizzle/{drizzle/0001_sweet_bruce_banner.sql → 0001_sweet_bruce_banner.sql} +0 -0
  299. /package/dist/db/drizzle/{drizzle/0002_bitter_proudstar.sql → 0002_bitter_proudstar.sql} +0 -0
  300. /package/dist/db/drizzle/{drizzle/0003_cultured_senator_kelly.sql → 0003_cultured_senator_kelly.sql} +0 -0
  301. /package/dist/db/drizzle/{drizzle/0004_add_publisher_to_seeds.sql → 0004_add_publisher_to_seeds.sql} +0 -0
  302. /package/dist/db/drizzle/{drizzle/0005_bright_lily_hollister.sql → 0005_bright_lily_hollister.sql} +0 -0
  303. /package/dist/db/drizzle/{drizzle/0006_add_publisher_to_versions_and_metadata.sql → 0006_add_publisher_to_versions_and_metadata.sql} +0 -0
  304. /package/dist/db/drizzle/{drizzle/0007_add_required_to_properties.sql → 0007_add_required_to_properties.sql} +0 -0
  305. /package/dist/db/drizzle/{drizzle/0008_add_revoked_at_to_seeds.sql → 0008_add_revoked_at_to_seeds.sql} +0 -0
  306. /package/dist/db/drizzle/{drizzle/0009_happy_namor.sql → 0009_happy_namor.sql} +0 -0
  307. /package/dist/db/drizzle/{drizzle/0010_add_arweave_l1_finalize_jobs.sql → 0010_add_arweave_l1_finalize_jobs.sql} +0 -0
  308. /package/dist/db/drizzle/{drizzle/0011_normalize_placeholder_uids.sql → 0011_normalize_placeholder_uids.sql} +0 -0
  309. /package/dist/db/drizzle/{drizzle/0012_html_embedded_image_co_publish.sql → 0012_html_embedded_image_co_publish.sql} +0 -0
  310. /package/dist/db/drizzle/{drizzle/0013_eas_sync_processes.sql → 0013_eas_sync_processes.sql} +0 -0
  311. /package/dist/db/drizzle/{drizzle/meta → meta}/0000_snapshot.json +0 -0
  312. /package/dist/db/drizzle/{drizzle/meta → meta}/0001_snapshot.json +0 -0
  313. /package/dist/db/drizzle/{drizzle/meta → meta}/0002_snapshot.json +0 -0
  314. /package/dist/db/drizzle/{drizzle/meta → meta}/0003_snapshot.json +0 -0
  315. /package/dist/db/drizzle/{drizzle/meta → meta}/0004_snapshot.json +0 -0
  316. /package/dist/db/drizzle/{drizzle/meta → meta}/0005_snapshot.json +0 -0
  317. /package/dist/db/drizzle/{drizzle/meta → meta}/0006_snapshot.json +0 -0
  318. /package/dist/db/drizzle/{drizzle/meta → meta}/0007_snapshot.json +0 -0
  319. /package/dist/db/drizzle/{drizzle/meta → meta}/0008_snapshot.json +0 -0
  320. /package/dist/db/drizzle/{drizzle/meta → meta}/0009_snapshot.json +0 -0
  321. /package/dist/db/drizzle/{drizzle/meta → meta}/0010_snapshot.json +0 -0
  322. /package/dist/db/drizzle/{drizzle/meta → meta}/0013_snapshot.json +0 -0
  323. /package/dist/db/drizzle/{drizzle/meta → meta}/_journal.json +0 -0
@@ -0,0 +1,1972 @@
1
+ import { B as BaseDb, m as models, i as modelSchemas, r as schemas, p as properties, b as appState, f as metadata } from './BasePathResolver-BDgc7c4T.js';
2
+ import { toSnakeCase } from 'drizzle-orm/casing';
3
+ import { eq, and, isNull } from 'drizzle-orm';
4
+ import { upperFirst, camelCase } from 'lodash-es';
5
+ import debug from 'debug';
6
+ import 'drizzle-orm/sqlite-core';
7
+
8
+ /**
9
+ * Detect SQLite UNIQUE constraint failures across better-sqlite3 and drizzle/wasm wrappers.
10
+ * Drizzle often surfaces `Failed query: insert into...` without "UNIQUE constraint" on message,
11
+ * with the real SQLITE_CONSTRAINT_UNIQUE on cause / nested error.
12
+ */
13
+ function isSqliteUniqueConstraintError(error) {
14
+ const seen = new Set();
15
+ const queue = [error];
16
+ while (queue.length > 0) {
17
+ const current = queue.shift();
18
+ if (current == null || seen.has(current))
19
+ continue;
20
+ seen.add(current);
21
+ if (typeof current === 'string') {
22
+ if (matchesUniqueConstraintText(current))
23
+ return true;
24
+ continue;
25
+ }
26
+ if (typeof current !== 'object')
27
+ continue;
28
+ const err = current;
29
+ const code = err.code;
30
+ if (code === 'SQLITE_CONSTRAINT_UNIQUE' ||
31
+ code === 2067 ||
32
+ code === '2067') {
33
+ return true;
34
+ }
35
+ for (const key of ['message', 'msg', 'stack']) {
36
+ const value = err[key];
37
+ if (typeof value === 'string' && matchesUniqueConstraintText(value)) {
38
+ return true;
39
+ }
40
+ }
41
+ // Drizzle / wasm often nest the real SQLite error
42
+ for (const key of ['cause', 'reason', 'error', 'originalError', 'err']) {
43
+ if (err[key] != null)
44
+ queue.push(err[key]);
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+ function matchesUniqueConstraintText(text) {
50
+ const lower = text.toLowerCase();
51
+ return (lower.includes('unique constraint') ||
52
+ lower.includes('sqlite_constraint_unique') ||
53
+ (lower.includes('constraint failed') && lower.includes('unique')) ||
54
+ /\brc\s*=\s*2067\b/i.test(text) ||
55
+ (text.includes('2067') && lower.includes('constraint')));
56
+ }
57
+
58
+ const logger = debug('seedSdk:helpers:db');
59
+ /**
60
+ * Resolve property_id from model name/type and property name.
61
+ * Handles property name variants (e.g. htmlId -> html, avatarImageIds -> avatarImages).
62
+ * @param modelNameOrType - Model name (PascalCase) or model type (snake_case)
63
+ * @param propertyName - Property name as stored in metadata (may have Id/Ids suffix)
64
+ * @returns properties.id or null if not found
65
+ */
66
+ async function getPropertyIdForModelAndName(modelNameOrType, propertyName) {
67
+ const db = BaseDb.getAppDb();
68
+ if (!db)
69
+ return null;
70
+ if (!modelNameOrType || !propertyName)
71
+ return null;
72
+ const normalizedModelName = upperFirst(camelCase(modelNameOrType));
73
+ const propertyNamesToTry = [propertyName];
74
+ if (propertyName.endsWith('Ids')) {
75
+ propertyNamesToTry.push(propertyName.slice(0, -3));
76
+ }
77
+ if (propertyName.endsWith('Id')) {
78
+ propertyNamesToTry.push(propertyName.slice(0, -2));
79
+ }
80
+ for (const pName of propertyNamesToTry) {
81
+ const rows = await db
82
+ .select({ id: properties.id })
83
+ .from(properties)
84
+ .innerJoin(models, eq(properties.modelId, models.id))
85
+ .where(and(eq(models.name, normalizedModelName), eq(properties.name, pName)))
86
+ .limit(1);
87
+ if (rows.length > 0 && rows[0].id != null) {
88
+ return rows[0].id;
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Migrate metadata rows when a property is renamed.
95
+ * Updates metadata.propertyName from old to new for all rows that reference the renamed property.
96
+ * Called from renameModelProperty to prevent duplicate ItemProperties.
97
+ * @param modelName - Model name (PascalCase)
98
+ * @param oldPropertyName - Current property name before rename
99
+ * @param newPropertyName - New property name after rename
100
+ * @param propertySchemaFileId - Optional schema file ID for the property (most reliable lookup)
101
+ * @returns Count of metadata rows updated
102
+ */
103
+ async function migrateMetadataForPropertyRename(modelName, oldPropertyName, newPropertyName, propertySchemaFileId) {
104
+ const db = BaseDb.getAppDb();
105
+ if (!db) {
106
+ logger('[migrateMetadataForPropertyRename] Database not available, skipping');
107
+ return 0;
108
+ }
109
+ const normalizedModelName = upperFirst(camelCase(modelName));
110
+ // Find the property row by schemaFileId (preferred) or by name
111
+ let propertyId = null;
112
+ if (propertySchemaFileId) {
113
+ const rows = await db
114
+ .select({ id: properties.id })
115
+ .from(properties)
116
+ .innerJoin(models, eq(properties.modelId, models.id))
117
+ .where(and(eq(models.name, normalizedModelName), eq(properties.schemaFileId, propertySchemaFileId)))
118
+ .limit(1);
119
+ if (rows.length > 0 && rows[0].id != null) {
120
+ propertyId = rows[0].id;
121
+ }
122
+ }
123
+ if (propertyId == null) {
124
+ propertyId = await getPropertyIdForModelAndName(modelName, oldPropertyName);
125
+ }
126
+ if (propertyId == null) {
127
+ logger(`[migrateMetadataForPropertyRename] Property not found: ${modelName}.${oldPropertyName}, skipping`);
128
+ return 0;
129
+ }
130
+ // Primary path: update metadata by propertyId
131
+ const toUpdateByPropertyId = await db
132
+ .select({ localId: metadata.localId })
133
+ .from(metadata)
134
+ .where(eq(metadata.propertyId, propertyId));
135
+ const updatedByPropertyId = toUpdateByPropertyId.length;
136
+ if (updatedByPropertyId > 0) {
137
+ await db
138
+ .update(metadata)
139
+ .set({ propertyName: newPropertyName })
140
+ .where(eq(metadata.propertyId, propertyId));
141
+ }
142
+ // Fallback: update metadata with null propertyId (legacy rows) by propertyName + modelType
143
+ const modelType = toSnakeCase(modelName);
144
+ const toUpdateByFallback = await db
145
+ .select({ localId: metadata.localId })
146
+ .from(metadata)
147
+ .where(and(eq(metadata.propertyName, oldPropertyName), eq(metadata.modelType, modelType), isNull(metadata.propertyId)));
148
+ const updatedByFallback = toUpdateByFallback.length;
149
+ if (updatedByFallback > 0) {
150
+ await db
151
+ .update(metadata)
152
+ .set({ propertyName: newPropertyName })
153
+ .where(and(eq(metadata.propertyName, oldPropertyName), eq(metadata.modelType, modelType), isNull(metadata.propertyId)));
154
+ }
155
+ if (updatedByFallback > 0) {
156
+ logger(`[migrateMetadataForPropertyRename] Fallback updated ${updatedByFallback} rows (propertyId was null)`);
157
+ }
158
+ const total = updatedByPropertyId + updatedByFallback;
159
+ if (total > 0) {
160
+ logger(`[migrateMetadataForPropertyRename] Migrated ${total} metadata rows for ${modelName}.${oldPropertyName} -> ${newPropertyName}`);
161
+ }
162
+ return total;
163
+ }
164
+ const escapeSqliteString = (value) => {
165
+ if (typeof value !== 'string') {
166
+ throw new Error(`Value must be a string, instead got: ${JSON.stringify(value)}`);
167
+ }
168
+ return value.replace(/'/g, "''");
169
+ };
170
+ const getObjectForRow = (row) => {
171
+ const obj = {};
172
+ row.columnNames.forEach((colName, index) => {
173
+ const value = row.row[index];
174
+ if (typeof value !== 'string') {
175
+ obj[colName] = row.row[index];
176
+ return;
177
+ }
178
+ // Try to parse the value as JSON
179
+ try {
180
+ obj[colName] = JSON.parse(value);
181
+ }
182
+ catch (e) {
183
+ // If it fails, just set the value as a string
184
+ obj[colName] = value;
185
+ }
186
+ });
187
+ return obj;
188
+ };
189
+ const getSqlResultObject = (queryResult) => {
190
+ if (!queryResult || !queryResult.rows || queryResult.rows.length === 0) {
191
+ return;
192
+ }
193
+ let obj;
194
+ if (queryResult.rows.length === 1) {
195
+ obj = getObjectForRow(queryResult.rows[0]);
196
+ }
197
+ if (queryResult.rows.length > 1) {
198
+ obj = queryResult.rows.reduce((acc, row) => {
199
+ const rowObj = getObjectForRow(row);
200
+ acc.push(rowObj);
201
+ return acc;
202
+ }, []);
203
+ }
204
+ return obj;
205
+ };
206
+ /**
207
+ * Find or create a models row by schemaFileId (preferred) or name.
208
+ * Reuses an existing same-name row (especially schemaFileId=null stubs created via
209
+ * ref resolution) instead of inserting a second row — models.name is not unique,
210
+ * and duplicate names break createOrUpdate lookups (e.g. Resource.tags → Tag).
211
+ */
212
+ const findOrCreateModelRecord = async (db, modelName, modelFileId) => {
213
+ if (modelFileId) {
214
+ const byFileId = await db
215
+ .select()
216
+ .from(models)
217
+ .where(eq(models.schemaFileId, modelFileId))
218
+ .limit(1);
219
+ if (byFileId.length > 0) {
220
+ const record = byFileId[0];
221
+ if (record.name !== modelName) {
222
+ await db
223
+ .update(models)
224
+ .set({ name: modelName })
225
+ .where(eq(models.id, record.id));
226
+ return { ...record, name: modelName };
227
+ }
228
+ return record;
229
+ }
230
+ }
231
+ const byName = (await db
232
+ .select()
233
+ .from(models)
234
+ .where(eq(models.name, modelName)));
235
+ if (byName.length > 0) {
236
+ // Prefer exact file-id match, then adoptable null schemaFileId stub, then any single row.
237
+ let chosen = (modelFileId
238
+ ? byName.find((r) => r.schemaFileId === modelFileId)
239
+ : undefined) ||
240
+ byName.find((r) => !r.schemaFileId) ||
241
+ (byName.length === 1 ? byName[0] : undefined) ||
242
+ byName.find((r) => !!r.schemaFileId) ||
243
+ byName[0];
244
+ if (modelFileId && chosen.schemaFileId !== modelFileId) {
245
+ const conflict = await db
246
+ .select()
247
+ .from(models)
248
+ .where(eq(models.schemaFileId, modelFileId))
249
+ .limit(1);
250
+ if (conflict.length > 0) {
251
+ return conflict[0];
252
+ }
253
+ // Adopt stub (null schemaFileId) or sole same-name row by attaching this file id.
254
+ if (!chosen.schemaFileId || byName.length === 1) {
255
+ await db
256
+ .update(models)
257
+ .set({ schemaFileId: modelFileId, isEdited: false })
258
+ .where(eq(models.id, chosen.id));
259
+ chosen = { ...chosen, schemaFileId: modelFileId, isEdited: false };
260
+ logger(`Adopted existing model "${modelName}" (id: ${chosen.id}) with schemaFileId "${modelFileId}"`);
261
+ }
262
+ }
263
+ return chosen;
264
+ }
265
+ try {
266
+ const inserted = await db
267
+ .insert(models)
268
+ .values({
269
+ name: modelName,
270
+ schemaFileId: modelFileId || null,
271
+ isEdited: false,
272
+ })
273
+ .returning();
274
+ return inserted[0];
275
+ }
276
+ catch (error) {
277
+ if (isSqliteUniqueConstraintError(error) && modelFileId) {
278
+ const existing = await db
279
+ .select()
280
+ .from(models)
281
+ .where(eq(models.schemaFileId, modelFileId))
282
+ .limit(1);
283
+ if (existing.length > 0) {
284
+ return existing[0];
285
+ }
286
+ }
287
+ // Race: another writer inserted by name — reuse rather than throw on duplicates.
288
+ const raced = (await db
289
+ .select()
290
+ .from(models)
291
+ .where(eq(models.name, modelName)));
292
+ if (raced.length > 0) {
293
+ return ((modelFileId
294
+ ? raced.find((r) => r.schemaFileId === modelFileId)
295
+ : undefined) ||
296
+ raced.find((r) => !r.schemaFileId) ||
297
+ raced[0]);
298
+ }
299
+ throw error;
300
+ }
301
+ };
302
+ const createOrUpdate = async (db, table, values) => {
303
+ const valueFilters = [];
304
+ const propertiesToExcludeFromDb = ['ref'];
305
+ const safeValues = Object.keys(values).reduce((acc, key) => {
306
+ if (!propertiesToExcludeFromDb.includes(key)) {
307
+ acc[key] = values[key];
308
+ }
309
+ return acc;
310
+ }, {});
311
+ for (const [key, value] of Object.entries(safeValues)) {
312
+ let finalValue = value;
313
+ if (key === 'TObject') {
314
+ continue;
315
+ }
316
+ if (typeof value === 'object') {
317
+ finalValue = JSON.stringify(value);
318
+ }
319
+ const column = table[key];
320
+ if (!column) {
321
+ throw new Error(`Column not found for ${key}`);
322
+ }
323
+ if (typeof finalValue === 'undefined') {
324
+ finalValue = null;
325
+ }
326
+ if (finalValue === null) {
327
+ valueFilters.push(isNull(table[key]));
328
+ continue;
329
+ }
330
+ valueFilters.push(eq(table[key], finalValue));
331
+ }
332
+ // console.log('valueFilters:', valueFilters)
333
+ // for ( const filter of valueFilters ) {
334
+ // console.log('filter:', Object.keys(filter))
335
+ // }
336
+ // Build a query to find the record based on properties
337
+ const existingRecords = await db
338
+ .select()
339
+ .from(table)
340
+ .where(and(...valueFilters));
341
+ if (existingRecords.length > 1) {
342
+ throw new Error('Multiple records found');
343
+ }
344
+ if (existingRecords.length > 0) {
345
+ // If record exists, update it
346
+ await db
347
+ .update(table)
348
+ .set(safeValues)
349
+ .where(and(...valueFilters));
350
+ return existingRecords[0];
351
+ }
352
+ else {
353
+ // If no record exists, create a new one
354
+ const newRecord = await db.insert(table).values(safeValues).returning();
355
+ return newRecord[0];
356
+ }
357
+ };
358
+ /**
359
+ * Searches the database for an existing schema by schemaFileId (preferred) or name and creates it if it doesn't exist
360
+ * @param schema - The schema to add to the database
361
+ * @param schemaFileId - Optional schemaFileId from JSON file for change tracking
362
+ * @param schemaData - Optional full schema content as JSON string (SchemaFileFormat)
363
+ * @param isDraft - Optional flag indicating if schema is in draft state (default: false)
364
+ * @param isEdited - Optional flag indicating if schema has been edited locally (default: false)
365
+ * @returns The schema record (either existing or newly created)
366
+ */
367
+ const addSchemaToDb = async (schema, schemaFileId, schemaData, isDraft, isEdited) => {
368
+ const db = BaseDb.getAppDb();
369
+ if (!db) {
370
+ throw new Error('Database not found');
371
+ }
372
+ // First, try to find existing schema by schemaFileId (preferred for change tracking)
373
+ if (schemaFileId) {
374
+ const existingByFileId = await db
375
+ .select()
376
+ .from(schemas)
377
+ .where(eq(schemas.schemaFileId, schemaFileId))
378
+ .limit(1);
379
+ if (existingByFileId.length > 0) {
380
+ // Update fields if provided
381
+ const updates = {};
382
+ if (schemaFileId && !existingByFileId[0].schemaFileId) {
383
+ updates.schemaFileId = schemaFileId;
384
+ }
385
+ // Always update name if it's different (handles name changes)
386
+ if (schema.name && existingByFileId[0].name !== schema.name) {
387
+ updates.name = schema.name;
388
+ }
389
+ if (schemaData !== undefined) {
390
+ updates.schemaData = schemaData;
391
+ }
392
+ if (schema.version !== undefined && existingByFileId[0].version !== schema.version) {
393
+ updates.version = schema.version;
394
+ }
395
+ if (isDraft !== undefined && existingByFileId[0].isDraft !== isDraft) {
396
+ updates.isDraft = isDraft;
397
+ }
398
+ if (isEdited !== undefined && existingByFileId[0].isEdited !== isEdited) {
399
+ updates.isEdited = isEdited;
400
+ }
401
+ if (schema.updatedAt && existingByFileId[0].updatedAt !== schema.updatedAt) {
402
+ updates.updatedAt = schema.updatedAt;
403
+ }
404
+ if (Object.keys(updates).length > 0) {
405
+ await db
406
+ .update(schemas)
407
+ .set(updates)
408
+ .where(eq(schemas.id, existingByFileId[0].id));
409
+ return { ...existingByFileId[0], ...updates };
410
+ }
411
+ return existingByFileId[0];
412
+ }
413
+ }
414
+ // For drafts, check if there's an existing draft by name (not by schemaFileId)
415
+ if (isDraft === true) {
416
+ const existingDrafts = await db
417
+ .select()
418
+ .from(schemas)
419
+ .where(eq(schemas.name, schema.name))
420
+ .limit(1);
421
+ if (existingDrafts.length > 0 && existingDrafts[0].isDraft === true) {
422
+ // Update existing draft
423
+ const updates = {};
424
+ // Update schemaFileId if provided and different from existing
425
+ if (schemaFileId && existingDrafts[0].schemaFileId !== schemaFileId) {
426
+ updates.schemaFileId = schemaFileId;
427
+ }
428
+ if (schemaData !== undefined) {
429
+ updates.schemaData = schemaData;
430
+ }
431
+ if (schema.version !== undefined) {
432
+ updates.version = schema.version;
433
+ }
434
+ updates.updatedAt = schema.updatedAt || Date.now();
435
+ if (Object.keys(updates).length > 0) {
436
+ await db
437
+ .update(schemas)
438
+ .set(updates)
439
+ .where(eq(schemas.id, existingDrafts[0].id));
440
+ return { ...existingDrafts[0], ...updates };
441
+ }
442
+ return existingDrafts[0];
443
+ }
444
+ }
445
+ // Fallback: Search for existing schema by name
446
+ // BUT: If we have a schemaFileId, also check if any record with that schemaFileId exists
447
+ // (in case the name changed but we're looking up by the new name)
448
+ if (schemaFileId) {
449
+ // Double-check by schemaFileId - maybe the name changed and we're looking up by new name
450
+ const doubleCheckByFileId = await db
451
+ .select()
452
+ .from(schemas)
453
+ .where(eq(schemas.schemaFileId, schemaFileId))
454
+ .limit(1);
455
+ if (doubleCheckByFileId.length > 0) {
456
+ // Found by schemaFileId - update it (name might have changed)
457
+ const updates = {};
458
+ // Always update name if it's different (handles name changes)
459
+ if (schema.name && doubleCheckByFileId[0].name !== schema.name) {
460
+ updates.name = schema.name;
461
+ }
462
+ if (schemaData !== undefined) {
463
+ updates.schemaData = schemaData;
464
+ }
465
+ if (schema.version !== undefined && doubleCheckByFileId[0].version !== schema.version) {
466
+ updates.version = schema.version;
467
+ }
468
+ if (isDraft !== undefined && doubleCheckByFileId[0].isDraft !== isDraft) {
469
+ updates.isDraft = isDraft;
470
+ }
471
+ if (isEdited !== undefined && doubleCheckByFileId[0].isEdited !== isEdited) {
472
+ updates.isEdited = isEdited;
473
+ }
474
+ if (schema.updatedAt && doubleCheckByFileId[0].updatedAt !== schema.updatedAt) {
475
+ updates.updatedAt = schema.updatedAt;
476
+ }
477
+ if (Object.keys(updates).length > 0) {
478
+ await db
479
+ .update(schemas)
480
+ .set(updates)
481
+ .where(eq(schemas.id, doubleCheckByFileId[0].id));
482
+ return { ...doubleCheckByFileId[0], ...updates };
483
+ }
484
+ return doubleCheckByFileId[0];
485
+ }
486
+ }
487
+ // Final fallback: Search by name (only if no schemaFileId or schemaFileId lookup failed)
488
+ // If isDraft is explicitly false, first try to find non-draft, but also check for drafts
489
+ // to handle the case where a draft exists and we're loading a non-draft version
490
+ let existingSchemas = await db
491
+ .select()
492
+ .from(schemas)
493
+ .where(isDraft === false
494
+ ? and(eq(schemas.name, schema.name), eq(schemas.isDraft, false))
495
+ : eq(schemas.name, schema.name))
496
+ .limit(1);
497
+ // If isDraft is false and we didn't find a non-draft, check for a draft with the same name
498
+ // This handles the case where a draft was created first and we're now loading the non-draft version
499
+ if (isDraft === false && existingSchemas.length === 0) {
500
+ const draftSchemas = await db
501
+ .select()
502
+ .from(schemas)
503
+ .where(and(eq(schemas.name, schema.name), eq(schemas.isDraft, true)))
504
+ .limit(1);
505
+ if (draftSchemas.length > 0) {
506
+ // Found a draft - we'll update it to non-draft below
507
+ logger(`Found draft schema "${schema.name}" with schemaFileId "${draftSchemas[0].schemaFileId}", will update to non-draft with schemaFileId "${schemaFileId}"`);
508
+ existingSchemas = draftSchemas;
509
+ }
510
+ }
511
+ if (existingSchemas.length > 0) {
512
+ // Update fields if provided
513
+ const updates = {};
514
+ // Update schemaFileId if provided and different from existing (or if existing doesn't have one or is null)
515
+ // This is important for preserving IDs from schema files when drafts exist
516
+ // BUT: Don't overwrite a non-draft schema's schemaFileId with a new generated one
517
+ // This prevents loadOrCreateSchema from overwriting correct IDs from fixture files
518
+ if (schemaFileId && existingSchemas[0].schemaFileId !== schemaFileId) {
519
+ // Only update if:
520
+ // 1. Existing schema is a draft (can be updated)
521
+ // 2. Existing schema has no schemaFileId (should be set)
522
+ // 3. We're explicitly setting isDraft to false (updating from draft to non-draft)
523
+ const shouldUpdate = existingSchemas[0].isDraft === true ||
524
+ !existingSchemas[0].schemaFileId ||
525
+ (isDraft === false && existingSchemas[0].isDraft === true);
526
+ if (shouldUpdate) {
527
+ logger(`Updating schemaFileId from "${existingSchemas[0].schemaFileId}" to "${schemaFileId}" for schema "${schema.name}"`);
528
+ updates.schemaFileId = schemaFileId;
529
+ }
530
+ else {
531
+ logger(`Preserving existing schemaFileId "${existingSchemas[0].schemaFileId}" for non-draft schema "${schema.name}" (new schemaFileId "${schemaFileId}" would overwrite it)`);
532
+ }
533
+ }
534
+ // Always update name if it's different (handles name changes)
535
+ if (schema.name && existingSchemas[0].name !== schema.name) {
536
+ updates.name = schema.name;
537
+ }
538
+ if (schemaData !== undefined) {
539
+ updates.schemaData = schemaData;
540
+ }
541
+ if (schema.version !== undefined && existingSchemas[0].version !== schema.version) {
542
+ updates.version = schema.version;
543
+ }
544
+ // If isDraft is explicitly false and we found a draft, update it to non-draft
545
+ if (isDraft === false && existingSchemas[0].isDraft === true) {
546
+ updates.isDraft = false;
547
+ }
548
+ else if (isDraft !== undefined && existingSchemas[0].isDraft !== isDraft) {
549
+ updates.isDraft = isDraft;
550
+ }
551
+ if (isEdited !== undefined && existingSchemas[0].isEdited !== isEdited) {
552
+ updates.isEdited = isEdited;
553
+ }
554
+ if (schema.updatedAt && existingSchemas[0].updatedAt !== schema.updatedAt) {
555
+ updates.updatedAt = schema.updatedAt;
556
+ }
557
+ if (Object.keys(updates).length > 0) {
558
+ logger(`Applying updates to schema "${schema.name}" (id: ${existingSchemas[0].id}):`, Object.keys(updates));
559
+ await db
560
+ .update(schemas)
561
+ .set(updates)
562
+ .where(eq(schemas.id, existingSchemas[0].id));
563
+ const updated = { ...existingSchemas[0], ...updates };
564
+ logger(`Schema "${schema.name}" updated. New schemaFileId: "${updated.schemaFileId}", isDraft: ${updated.isDraft}`);
565
+ return updated;
566
+ }
567
+ logger(`No updates needed for schema "${schema.name}" (id: ${existingSchemas[0].id})`);
568
+ return existingSchemas[0];
569
+ }
570
+ const newSchema = await db.insert(schemas).values({
571
+ name: schema.name,
572
+ version: schema.version,
573
+ schemaFileId: schemaFileId || null,
574
+ schemaData: schemaData || null,
575
+ isDraft: isDraft ?? false,
576
+ isEdited: isEdited ?? false,
577
+ createdAt: schema.createdAt,
578
+ updatedAt: schema.updatedAt,
579
+ }).returning();
580
+ // Notify React useSchemas so it can invalidate; live query often doesn't re-run when schemas table is inserted.
581
+ if (typeof BroadcastChannel !== 'undefined') {
582
+ try {
583
+ await new Promise((r) => setTimeout(r, 10));
584
+ new BroadcastChannel('seed-schemas-invalidate').postMessage({});
585
+ }
586
+ catch (_) { }
587
+ }
588
+ return newSchema[0];
589
+ };
590
+ /**
591
+ * Rename a model in the database
592
+ * Updates the model name and all properties that reference it
593
+ * @param oldName - The current model name
594
+ * @param newName - The new model name
595
+ * @param schemaNameOrId - Schema name or schema ID to scope the rename (required when multiple schemas have models with the same name)
596
+ * @returns The updated model record
597
+ */
598
+ const renameModelInDb = async (oldName, newName, schemaNameOrId) => {
599
+ const db = BaseDb.getAppDb();
600
+ if (!db) {
601
+ throw new Error('Database not found');
602
+ }
603
+ const _mod_0 = await import('./BasePathResolver-BDgc7c4T.js');
604
+ const _ns_0 = _mod_0.S;
605
+ const { schemas: schemasTable } = _ns_0;
606
+ // Find the model by old name, optionally scoped by schema
607
+ let existingModels;
608
+ if (schemaNameOrId !== undefined) {
609
+ if (typeof schemaNameOrId === 'number') {
610
+ const rows = await db
611
+ .select({
612
+ id: models.id,
613
+ name: models.name,
614
+ schemaFileId: models.schemaFileId,
615
+ isEdited: models.isEdited,
616
+ })
617
+ .from(models)
618
+ .innerJoin(modelSchemas, eq(models.id, modelSchemas.modelId))
619
+ .where(and(eq(models.name, oldName), eq(modelSchemas.schemaId, schemaNameOrId)))
620
+ .limit(1);
621
+ existingModels = rows;
622
+ }
623
+ else {
624
+ const rows = await db
625
+ .select({
626
+ id: models.id,
627
+ name: models.name,
628
+ schemaFileId: models.schemaFileId,
629
+ isEdited: models.isEdited,
630
+ })
631
+ .from(models)
632
+ .innerJoin(modelSchemas, eq(models.id, modelSchemas.modelId))
633
+ .innerJoin(schemasTable, eq(modelSchemas.schemaId, schemasTable.id))
634
+ .where(and(eq(models.name, oldName), eq(schemasTable.name, schemaNameOrId)))
635
+ .limit(1);
636
+ existingModels = rows;
637
+ }
638
+ }
639
+ else {
640
+ existingModels = await db
641
+ .select({
642
+ id: models.id,
643
+ name: models.name,
644
+ schemaFileId: models.schemaFileId,
645
+ isEdited: models.isEdited,
646
+ })
647
+ .from(models)
648
+ .where(eq(models.name, oldName))
649
+ .limit(1);
650
+ }
651
+ if (existingModels.length === 0) {
652
+ if (schemaNameOrId !== undefined) {
653
+ throw new Error(`Model "${oldName}" not found in schema "${schemaNameOrId}"`);
654
+ }
655
+ // Backward compat: model doesn't exist, create it with new name
656
+ const newModel = await db.insert(models).values({ name: newName }).returning();
657
+ return newModel[0];
658
+ }
659
+ const modelToRename = existingModels[0];
660
+ // Check if a model with the new name already exists in the same schema
661
+ let existingWithNewName;
662
+ if (schemaNameOrId !== undefined) {
663
+ if (typeof schemaNameOrId === 'number') {
664
+ existingWithNewName = await db
665
+ .select({
666
+ id: models.id,
667
+ name: models.name,
668
+ schemaFileId: models.schemaFileId,
669
+ isEdited: models.isEdited,
670
+ })
671
+ .from(models)
672
+ .innerJoin(modelSchemas, eq(models.id, modelSchemas.modelId))
673
+ .where(and(eq(models.name, newName), eq(modelSchemas.schemaId, schemaNameOrId)))
674
+ .limit(1);
675
+ }
676
+ else {
677
+ existingWithNewName = await db
678
+ .select({
679
+ id: models.id,
680
+ name: models.name,
681
+ schemaFileId: models.schemaFileId,
682
+ isEdited: models.isEdited,
683
+ })
684
+ .from(models)
685
+ .innerJoin(modelSchemas, eq(models.id, modelSchemas.modelId))
686
+ .innerJoin(schemasTable, eq(modelSchemas.schemaId, schemasTable.id))
687
+ .where(and(eq(models.name, newName), eq(schemasTable.name, schemaNameOrId)))
688
+ .limit(1);
689
+ }
690
+ }
691
+ else {
692
+ existingWithNewName = await db
693
+ .select({
694
+ id: models.id,
695
+ name: models.name,
696
+ schemaFileId: models.schemaFileId,
697
+ isEdited: models.isEdited,
698
+ })
699
+ .from(models)
700
+ .where(eq(models.name, newName))
701
+ .limit(1);
702
+ }
703
+ if (existingWithNewName.length > 0) {
704
+ // New name already exists in this schema, return it
705
+ return existingWithNewName[0];
706
+ }
707
+ // Update the model name
708
+ await db
709
+ .update(models)
710
+ .set({ name: newName })
711
+ .where(eq(models.id, modelToRename.id));
712
+ return { ...modelToRename, name: newName };
713
+ };
714
+ /**
715
+ * Check if a property has been locally edited (has unsaved changes)
716
+ * This checks both the in-memory cache (for current session) and the database
717
+ * (for persistence across reloads) by comparing database values with schema file values.
718
+ * @param modelName - The name of the model
719
+ * @param propertyName - The name of the property
720
+ * @param schemaFileValue - Optional schema file value to compare against database
721
+ * @returns true if the property is marked as edited, false otherwise
722
+ */
723
+ async function checkIfPropertyIsEdited(modelName, propertyName, schemaFileValue) {
724
+ try {
725
+ // When schemaFileValue is provided (schema sync path), do database check FIRST.
726
+ // This avoids the ModelProperty dynamic import which can hang due to circular
727
+ // dependency (ModelProperty -> helpers/db) when called from addModelsToDb during init.
728
+ if (schemaFileValue) {
729
+ const db = BaseDb.getAppDb();
730
+ if (db) {
731
+ // Find the model
732
+ const modelRecords = await db
733
+ .select()
734
+ .from(models)
735
+ .where(eq(models.name, modelName))
736
+ .limit(1);
737
+ if (modelRecords.length > 0) {
738
+ const modelRecord = modelRecords[0];
739
+ // Find the property in the database
740
+ const propertyRecords = await db
741
+ .select()
742
+ .from(properties)
743
+ .where(and(eq(properties.name, propertyName), eq(properties.modelId, modelRecord.id)))
744
+ .limit(1);
745
+ if (propertyRecords.length > 0) {
746
+ const dbProperty = propertyRecords[0];
747
+ // Compare database value with schema file value
748
+ // If they differ, the property has been edited
749
+ if (dbProperty.dataType !== schemaFileValue.dataType) {
750
+ logger(`Property ${modelName}:${propertyName} has been edited (dataType differs: DB=${dbProperty.dataType}, Schema=${schemaFileValue.dataType})`);
751
+ return true;
752
+ }
753
+ // Check refModelId if it's a relation
754
+ if (schemaFileValue.ref) {
755
+ const refModelRecords = await db
756
+ .select()
757
+ .from(models)
758
+ .where(eq(models.name, schemaFileValue.ref))
759
+ .limit(1);
760
+ if (refModelRecords.length > 0) {
761
+ const expectedRefModelId = refModelRecords[0].id;
762
+ if (dbProperty.refModelId !== expectedRefModelId) {
763
+ logger(`Property ${modelName}:${propertyName} has been edited (refModelId differs)`);
764
+ return true;
765
+ }
766
+ }
767
+ }
768
+ else if (dbProperty.refModelId !== null) {
769
+ // Schema file has no ref, but DB has one
770
+ logger(`Property ${modelName}:${propertyName} has been edited (refModelId differs)`);
771
+ return true;
772
+ }
773
+ // Check refValueType
774
+ if (dbProperty.refValueType !== (schemaFileValue.refValueType || null)) {
775
+ logger(`Property ${modelName}:${propertyName} has been edited (refValueType differs)`);
776
+ return true;
777
+ }
778
+ // Check required (for Relation/Image properties)
779
+ if (schemaFileValue.required !== undefined) {
780
+ const schemaRequired = !!schemaFileValue.required;
781
+ const dbRequired = dbProperty.required === true;
782
+ if (dbRequired !== schemaRequired) {
783
+ logger(`Property ${modelName}:${propertyName} has been edited (required differs: DB=${dbRequired}, Schema=${schemaRequired})`);
784
+ return true;
785
+ }
786
+ }
787
+ }
788
+ }
789
+ }
790
+ }
791
+ return false;
792
+ }
793
+ catch (error) {
794
+ // If we can't check, assume it's not edited to be safe
795
+ logger('Error checking if property is edited:', error);
796
+ return false;
797
+ }
798
+ }
799
+ /**
800
+ * Adds models and their properties to the database.
801
+ * Optionally connects models to a schema via join records.
802
+ * @param models - The model definitions to add
803
+ * @param schema - Optional schema to connect models to
804
+ * @param modelRenames - Optional map of old model names to new model names for handling renames
805
+ * @param schemaFileData - Optional object containing schemaFileId mappings from JSON file: { schemaFileId, modelFileIds: Map<modelName, id>, propertyFileIds: Map<modelName, Map<propertyName, id>> }
806
+ */
807
+ const addModelsToDb = async (models$1, schema, modelRenames, schemaFileData) => {
808
+ const db = BaseDb.getAppDb();
809
+ if (!db) {
810
+ throw new Error('Database not found');
811
+ }
812
+ // If schema is provided, add it to the database
813
+ // Note: schema might already be a database record (with id) if passed from importJsonSchema
814
+ let schemaRecord;
815
+ if (schema) {
816
+ // Check if schema already has an id (it's already a database record)
817
+ // SchemaType includes id, so check if it's set
818
+ if (schema.id !== null && schema.id !== undefined) {
819
+ schemaRecord = schema;
820
+ logger(`Using existing schema record with id: ${schemaRecord.id}`);
821
+ }
822
+ else {
823
+ schemaRecord = await addSchemaToDb(schema, schemaFileData?.schemaFileId);
824
+ logger(`Created/found schema record with id: ${schemaRecord.id}`);
825
+ }
826
+ }
827
+ // Handle model renames first if provided
828
+ if (modelRenames && schemaRecord) {
829
+ const schemaNameOrId = schemaRecord.name ?? schemaRecord.id;
830
+ for (const [oldName, newName] of modelRenames.entries()) {
831
+ await renameModelInDb(oldName, newName, schemaNameOrId);
832
+ }
833
+ }
834
+ // Search for all models by schemaFileId (preferred) or name and create them if they don't exist
835
+ const modelRecords = new Map();
836
+ const modelProcessingErrors = [];
837
+ for (const [modelName, modelClass] of Object.entries(models$1)) {
838
+ try {
839
+ const modelFileId = schemaFileData?.modelFileIds?.get(modelName);
840
+ let modelRecord = await findOrCreateModelRecord(db, modelName, modelFileId);
841
+ // Keep schemaFileId aligned when findOrCreate returned a row that still needs adoption
842
+ // (e.g. sole same-name row that already had a different non-null id — rare).
843
+ if (modelFileId && modelRecord.schemaFileId !== modelFileId) {
844
+ const existingWithFileId = await db
845
+ .select()
846
+ .from(models)
847
+ .where(eq(models.schemaFileId, modelFileId))
848
+ .limit(1);
849
+ if (existingWithFileId.length > 0 && existingWithFileId[0].id !== modelRecord.id) {
850
+ logger(`WARNING: Model "${modelName}" (id: ${modelRecord.id}) conflicts with existing model "${existingWithFileId[0].name}" (id: ${existingWithFileId[0].id}) both trying to use schemaFileId "${modelFileId}"`);
851
+ modelRecord = existingWithFileId[0];
852
+ }
853
+ else if (!modelRecord.schemaFileId) {
854
+ await db
855
+ .update(models)
856
+ .set({ schemaFileId: modelFileId })
857
+ .where(eq(models.id, modelRecord.id));
858
+ modelRecord = { ...modelRecord, schemaFileId: modelFileId };
859
+ }
860
+ }
861
+ modelRecords.set(modelName, modelRecord);
862
+ // Get all existing properties for this model upfront to handle renamed properties
863
+ const allDbProperties = await db
864
+ .select()
865
+ .from(properties)
866
+ .where(eq(properties.modelId, modelRecord.id));
867
+ // Track which DB properties have been matched to schema properties
868
+ const matchedDbPropertyIds = new Set();
869
+ // Get properties from Model context (where they're stored as an object when Model is created)
870
+ // modelClass.properties returns ModelProperty instances from DB, but we need the context properties
871
+ // which are stored as an object when Model.create() is called with properties
872
+ const modelContext = modelClass._getSnapshotContext?.() || {};
873
+ const contextProperties = modelContext.properties || {};
874
+ // When models are created from JSON, properties are stored as _pendingPropertyDefinitions
875
+ const pendingProperties = modelContext._pendingPropertyDefinitions || {};
876
+ // If context properties are empty, try modelClass.properties (for backward compatibility)
877
+ // but convert ModelProperty instances to object format
878
+ let schema = {};
879
+ if (Object.keys(contextProperties).length > 0) {
880
+ schema = contextProperties;
881
+ }
882
+ else if (Object.keys(pendingProperties).length > 0) {
883
+ // Use pending property definitions (from JSON import)
884
+ schema = pendingProperties;
885
+ }
886
+ else {
887
+ const _mod_1 = await import('./index--F3Wolt5.js');
888
+ const _ns_1 = _mod_1.ac;
889
+ const modelHelpersMod = _ns_1;
890
+ const { modelPropertiesToObject } = modelHelpersMod;
891
+ const modelProperties = modelClass.properties || [];
892
+ schema = modelPropertiesToObject(modelProperties);
893
+ }
894
+ const schemaPropertyNames = new Set(Object.keys(schema));
895
+ // Search for all properties and create them if they don't exist
896
+ // Properties are unique by name + modelId, so we search using both
897
+ const schemaEntries = Object.entries(schema);
898
+ for (let index = 0; index < schemaEntries.length; index++) {
899
+ const [propertyName, propertyValues] = schemaEntries[index];
900
+ if (!propertyValues) {
901
+ throw new Error(`Property values not found for ${propertyName}`);
902
+ }
903
+ // Get property schemaFileId if available
904
+ let propertyFileId = schemaFileData?.propertyFileIds?.get(modelName)?.get(propertyName);
905
+ // If no propertyFileId from map, generate a random ID
906
+ // IDs should be generated in the import process before calling addModelsToDb
907
+ if (!propertyFileId) {
908
+ const _mod_2 = await import('./index--F3Wolt5.js');
909
+ const _ns_2 = _mod_2.ab;
910
+ const { generateId } = _ns_2;
911
+ propertyFileId = generateId();
912
+ logger(`Generated propertyFileId "${propertyFileId}" for property "${modelName}:${propertyName}" (not found in propertyFileIds map)`);
913
+ }
914
+ // First, try to find by schemaFileId (preferred for change tracking)
915
+ let existingProperty;
916
+ if (propertyFileId) {
917
+ existingProperty = allDbProperties.find((p) => p.schemaFileId === propertyFileId && !matchedDbPropertyIds.has(p.id));
918
+ }
919
+ // Fallback: check if property exists by name + modelId
920
+ if (!existingProperty) {
921
+ existingProperty = allDbProperties.find((p) => p.name === propertyName && !matchedDbPropertyIds.has(p.id));
922
+ }
923
+ // Prepare property values
924
+ const propertyData = {
925
+ name: propertyName,
926
+ modelId: modelRecord.id,
927
+ dataType: propertyValues.dataType,
928
+ schemaFileId: propertyFileId || null,
929
+ required: propertyValues.required ?? false,
930
+ };
931
+ // Handle ref property - create ref model if needed
932
+ // Check both ref and refModelName (refModelName is set by createModelFromJson)
933
+ let expectedRefModelId = null;
934
+ const refModelName = propertyValues.ref || propertyValues.refModelName;
935
+ if (refModelName) {
936
+ // When ref model was already processed in this batch, use it (avoids db round-trip)
937
+ const cachedRef = modelRecords.get(refModelName);
938
+ const refModelFileId = schemaFileData?.modelFileIds?.get(refModelName);
939
+ const refModel = cachedRef
940
+ ? cachedRef
941
+ : await findOrCreateModelRecord(db, refModelName, refModelFileId);
942
+ if (!cachedRef) {
943
+ modelRecords.set(refModelName, refModel);
944
+ }
945
+ propertyData.refModelId = refModel.id ?? null;
946
+ expectedRefModelId = refModel.id ?? null;
947
+ }
948
+ else {
949
+ // If it's not a Relation type, ensure refModelId is null
950
+ propertyData.refModelId = null;
951
+ }
952
+ if (propertyValues.refValueType) {
953
+ propertyData.refValueType = propertyValues.refValueType;
954
+ }
955
+ else {
956
+ // If refValueType is not set, ensure it's null
957
+ propertyData.refValueType = null;
958
+ }
959
+ // If not found by name, try to find by position/characteristics (for renamed properties)
960
+ if (!existingProperty) {
961
+ // Look for unmatched DB properties that could be this renamed property
962
+ // Match by: same dataType, same refModelId (if applicable), and not matching any schema property name
963
+ const potentialMatches = allDbProperties.filter((p) => !matchedDbPropertyIds.has(p.id) &&
964
+ !schemaPropertyNames.has(p.name) && // This DB property doesn't match any schema property name
965
+ p.dataType === propertyValues.dataType &&
966
+ (expectedRefModelId === null
967
+ ? p.refModelId === null
968
+ : p.refModelId === expectedRefModelId) &&
969
+ (propertyValues.refValueType
970
+ ? p.refValueType === propertyValues.refValueType
971
+ : p.refValueType === null));
972
+ // If we find exactly one match, or if we're at the same position index, use it
973
+ // For now, use the first match (could be enhanced to use position more precisely)
974
+ if (potentialMatches.length > 0) {
975
+ const matchedProperty = potentialMatches[0];
976
+ existingProperty = matchedProperty;
977
+ logger(`Found renamed property: ${modelName}:${matchedProperty.name} -> ${propertyName} (matched by characteristics)`);
978
+ }
979
+ }
980
+ if (existingProperty) {
981
+ // Mark this DB property as matched
982
+ matchedDbPropertyIds.add(existingProperty.id);
983
+ // When syncing from schema (schemaFileData present), skip the expensive checkIfPropertyIsEdited.
984
+ // It can hang for minutes in browser due to circular deps / SQLite contention during init.
985
+ // Use DB isEdited column as a fast check: if already marked edited, preserve.
986
+ const skipEditCheck = !!schemaFileData;
987
+ const isPropertyEdited = skipEditCheck
988
+ ? existingProperty.isEdited === true
989
+ : await checkIfPropertyIsEdited(modelName, existingProperty.name, {
990
+ dataType: propertyValues.dataType,
991
+ ref: propertyValues.ref,
992
+ refValueType: propertyValues.refValueType,
993
+ required: propertyValues.required,
994
+ });
995
+ if (isPropertyEdited) {
996
+ // Property has been locally edited - skip update to preserve local changes
997
+ logger(`Skipping update for property ${modelName}:${existingProperty.name} -> ${propertyName} - it has been locally edited and will be preserved`);
998
+ continue;
999
+ }
1000
+ // Property exists (possibly with different name) - update it with new values from schema file
1001
+ // This handles both regular updates and renames
1002
+ // Ensure schemaFileId is updated if we have it
1003
+ // Preserve existing isEdited value if it was true (local edits take precedence)
1004
+ const updateData = { ...propertyData };
1005
+ if (existingProperty.isEdited === true) {
1006
+ // Preserve isEdited = true if property was locally edited
1007
+ delete updateData.isEdited;
1008
+ }
1009
+ else {
1010
+ updateData.isEdited = false;
1011
+ }
1012
+ // Skip db.update when data unchanged (avoids slow OPFS writes in browser)
1013
+ const unchanged = existingProperty.name === updateData.name &&
1014
+ existingProperty.dataType === updateData.dataType &&
1015
+ existingProperty.schemaFileId === (updateData.schemaFileId ?? null) &&
1016
+ existingProperty.required === (updateData.required ?? false) &&
1017
+ existingProperty.refModelId === (updateData.refModelId ?? null) &&
1018
+ existingProperty.refValueType === (updateData.refValueType ?? null) &&
1019
+ existingProperty.isEdited === (updateData.isEdited ?? false);
1020
+ if (!unchanged) {
1021
+ await db
1022
+ .update(properties)
1023
+ .set(updateData)
1024
+ .where(eq(properties.id, existingProperty.id));
1025
+ }
1026
+ }
1027
+ else {
1028
+ // Property doesn't exist, create it with schemaFileId
1029
+ // Set isEdited = false when loading from schema file
1030
+ const propertyDataWithIsEdited = {
1031
+ ...propertyData,
1032
+ isEdited: false,
1033
+ };
1034
+ // Global schemaFileId lookup (unique across all models) before insert — avoids
1035
+ // UNIQUE races when the property already exists on another model row or from a prior pass.
1036
+ if (propertyFileId) {
1037
+ const existingByFileId = await db
1038
+ .select()
1039
+ .from(properties)
1040
+ .where(eq(properties.schemaFileId, propertyFileId))
1041
+ .limit(1);
1042
+ if (existingByFileId.length > 0) {
1043
+ const found = existingByFileId[0];
1044
+ matchedDbPropertyIds.add(found.id);
1045
+ logger(`Property ${modelName}:${propertyName} already exists by schemaFileId "${propertyFileId}" (id: ${found.id}), skipping insert`);
1046
+ continue;
1047
+ }
1048
+ }
1049
+ logger(`Creating new property ${modelName}:${propertyName} with schemaFileId: ${propertyData.schemaFileId}`);
1050
+ try {
1051
+ await db.insert(properties).values(propertyDataWithIsEdited);
1052
+ }
1053
+ catch (insertError) {
1054
+ // Treat UNIQUE constraint as success - property already exists (e.g. from concurrent addModelsToDb call)
1055
+ if (isSqliteUniqueConstraintError(insertError)) {
1056
+ logger(`Property ${modelName}:${propertyName} already exists (UNIQUE constraint), treating as success`);
1057
+ }
1058
+ else {
1059
+ throw insertError;
1060
+ }
1061
+ }
1062
+ }
1063
+ }
1064
+ }
1065
+ catch (error) {
1066
+ const errorMessage = error?.message || String(error);
1067
+ logger(`Error processing model "${modelName}": ${errorMessage}`);
1068
+ modelProcessingErrors.push({ modelName, error: errorMessage });
1069
+ // Continue processing other models even if one fails
1070
+ }
1071
+ }
1072
+ if (modelProcessingErrors.length > 0) {
1073
+ console.warn(`[addModelsToDb] Errors occurred while processing ${modelProcessingErrors.length} model(s):`, modelProcessingErrors.map(e => `${e.modelName}: ${e.error}`).join('; '));
1074
+ logger(`Errors processing models: ${modelProcessingErrors.map(e => e.modelName).join(', ')}`);
1075
+ }
1076
+ // If schema was provided, create modelSchema join records to connect models to the schema
1077
+ if (schemaRecord && schemaRecord.id) {
1078
+ const modelIds = [...modelRecords.entries()]
1079
+ .filter(([, r]) => r.id)
1080
+ .map(([name, r]) => ({ modelName: name, modelId: r.id }));
1081
+ if (modelIds.length === 0) {
1082
+ logger('No model IDs to link, skipping schema linking');
1083
+ }
1084
+ else {
1085
+ // Single batch query: get all existing joins for this schema
1086
+ const existingJoins = await db
1087
+ .select({ modelId: modelSchemas.modelId })
1088
+ .from(modelSchemas)
1089
+ .where(eq(modelSchemas.schemaId, schemaRecord.id));
1090
+ const existingSet = new Set(existingJoins.map((r) => r.modelId));
1091
+ const toInsert = modelIds.filter(({ modelId }) => !existingSet.has(modelId));
1092
+ if (toInsert.length > 0) {
1093
+ for (const { modelName, modelId } of toInsert) {
1094
+ await db.insert(modelSchemas).values({
1095
+ modelId,
1096
+ schemaId: schemaRecord.id,
1097
+ });
1098
+ logger(`Created join table entry for model ${modelName} (id: ${modelId}) to schema (id: ${schemaRecord.id})`);
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ else if (schemaRecord && !schemaRecord.id) {
1104
+ logger(`Warning: schemaRecord provided but has no id, cannot create join table entries`);
1105
+ }
1106
+ };
1107
+ /**
1108
+ * Loads models from the database for a given schema by querying the model_schemas join table.
1109
+ * This ensures that models added to the database (via model_schemas) are included even if
1110
+ * they're not in the schemaData JSON.
1111
+ * @param schemaId - The ID of the schema record in the database
1112
+ * @returns A map of model names to model data (compatible with SchemaFileFormat.models)
1113
+ */
1114
+ const loadModelsFromDbForSchema = async (schemaId) => {
1115
+ const db = BaseDb.getAppDb();
1116
+ if (!db) {
1117
+ logger('Database not found, cannot load models from DB');
1118
+ return {};
1119
+ }
1120
+ try {
1121
+ // Query model_schemas join table to find all models linked to this schema
1122
+ const modelSchemaRecords = await db
1123
+ .select({
1124
+ modelId: modelSchemas.modelId,
1125
+ modelName: models.name,
1126
+ schemaFileId: models.schemaFileId,
1127
+ })
1128
+ .from(modelSchemas)
1129
+ .innerJoin(models, eq(modelSchemas.modelId, models.id))
1130
+ .where(eq(modelSchemas.schemaId, schemaId));
1131
+ const models$1 = {};
1132
+ // For each model, load its properties
1133
+ for (const { modelId, modelName, schemaFileId } of modelSchemaRecords) {
1134
+ if (!modelId || !modelName)
1135
+ continue;
1136
+ // Get all properties for this model
1137
+ const propertyRecords = await db
1138
+ .select()
1139
+ .from(properties)
1140
+ .where(eq(properties.modelId, modelId));
1141
+ // Reconstruct properties object
1142
+ const modelProperties = {};
1143
+ for (const prop of propertyRecords) {
1144
+ // Build a basic property structure from database fields
1145
+ // Note: This is a simplified reconstruction - full property schemas
1146
+ // (like Relation details, List configs, etc.) should come from schemaData
1147
+ const propertyData = {
1148
+ dataType: prop.dataType,
1149
+ };
1150
+ if (prop.schemaFileId) {
1151
+ propertyData.schemaFileId = prop.schemaFileId;
1152
+ }
1153
+ // Add ref information if it's a relation
1154
+ if (prop.refModelId) {
1155
+ // Get the referenced model name
1156
+ const refModelRecords = await db
1157
+ .select({ name: models.name })
1158
+ .from(models)
1159
+ .where(eq(models.id, prop.refModelId))
1160
+ .limit(1);
1161
+ if (refModelRecords.length > 0) {
1162
+ propertyData.ref = refModelRecords[0].name;
1163
+ }
1164
+ }
1165
+ if (prop.refValueType) {
1166
+ propertyData.refValueType = prop.refValueType;
1167
+ }
1168
+ modelProperties[prop.name] = propertyData;
1169
+ }
1170
+ // Create model structure. Include id (schemaFileId) so processSchemaFiles can populate
1171
+ // modelFileIds and Model.create can skip duplicate-name logic, preventing model
1172
+ // duplication on reload (Post 1 1, Post 2 1, etc.).
1173
+ models$1[modelName] = {
1174
+ properties: modelProperties,
1175
+ ...(schemaFileId ? { id: schemaFileId } : {}),
1176
+ // Note: description would need to be stored separately
1177
+ // or reconstructed from schemaData if available
1178
+ };
1179
+ }
1180
+ logger(`Loaded ${Object.keys(models$1).length} models from database for schema ${schemaId}`);
1181
+ return models$1;
1182
+ }
1183
+ catch (error) {
1184
+ logger(`Error loading models from database for schema ${schemaId}:`, error);
1185
+ return {};
1186
+ }
1187
+ };
1188
+ /**
1189
+ * Returns model name by database model ID.
1190
+ */
1191
+ async function getModelNameByModelId(modelId) {
1192
+ const db = BaseDb.getAppDb();
1193
+ if (!db)
1194
+ return undefined;
1195
+ try {
1196
+ const rows = await db
1197
+ .select({ name: models.name })
1198
+ .from(models)
1199
+ .where(eq(models.id, modelId))
1200
+ .limit(1);
1201
+ return rows.length > 0 ? rows[0].name : undefined;
1202
+ }
1203
+ catch {
1204
+ return undefined;
1205
+ }
1206
+ }
1207
+ /**
1208
+ * Resolves modelName and dataType for a property by its schemaFileId (e.g. context.id).
1209
+ * Used when machine context lacks these (e.g. just-created property renamed before full context is set).
1210
+ */
1211
+ async function getPropertyModelNameAndDataType(schemaFileId) {
1212
+ const db = BaseDb.getAppDb();
1213
+ if (!db || !schemaFileId)
1214
+ return undefined;
1215
+ try {
1216
+ const rows = await db
1217
+ .select({
1218
+ dataType: properties.dataType,
1219
+ modelId: properties.modelId,
1220
+ })
1221
+ .from(properties)
1222
+ .where(eq(properties.schemaFileId, schemaFileId))
1223
+ .limit(1);
1224
+ if (rows.length === 0)
1225
+ return undefined;
1226
+ const modelRows = await db
1227
+ .select({ name: models.name })
1228
+ .from(models)
1229
+ .where(eq(models.id, rows[0].modelId))
1230
+ .limit(1);
1231
+ if (modelRows.length === 0)
1232
+ return undefined;
1233
+ return {
1234
+ modelName: modelRows[0].name,
1235
+ dataType: rows[0].dataType ?? '',
1236
+ };
1237
+ }
1238
+ catch {
1239
+ return undefined;
1240
+ }
1241
+ }
1242
+ /**
1243
+ * Saves a property's changes to the database without updating the JSON schema file.
1244
+ * This is used when properties are edited but the schema hasn't been saved as a new version yet.
1245
+ * @param property - The ModelPropertyMachineContext with updated values
1246
+ */
1247
+ const savePropertyToDb = async (property) => {
1248
+ const db = BaseDb.getAppDb();
1249
+ if (!db) {
1250
+ throw new Error('Database not found');
1251
+ }
1252
+ if (!property.name) {
1253
+ throw new Error('Property name is required');
1254
+ }
1255
+ // Find the model: prefer modelId (reliable), then modelName as name, then modelName as schemaFileId
1256
+ // (context.modelName can be a model schemaFileId when schema uses that as identifier)
1257
+ let modelRecord;
1258
+ if (property.modelId != null && typeof property.modelId === 'number') {
1259
+ const byId = await db
1260
+ .select()
1261
+ .from(models)
1262
+ .where(eq(models.id, property.modelId))
1263
+ .limit(1);
1264
+ modelRecord = byId[0];
1265
+ }
1266
+ if (!modelRecord && property.modelName) {
1267
+ const byName = await db
1268
+ .select()
1269
+ .from(models)
1270
+ .where(eq(models.name, property.modelName))
1271
+ .limit(1);
1272
+ modelRecord = byName[0];
1273
+ }
1274
+ if (!modelRecord && property.modelName) {
1275
+ const bySchemaFileId = await db
1276
+ .select()
1277
+ .from(models)
1278
+ .where(eq(models.schemaFileId, property.modelName))
1279
+ .limit(1);
1280
+ modelRecord = bySchemaFileId[0];
1281
+ }
1282
+ // Fallback: resolve model from existing property row (by schemaFileId) when modelName is wrong
1283
+ const schemaFileId = property._propertyFileId || (typeof property.id === 'string' ? property.id : undefined);
1284
+ if (!modelRecord && schemaFileId) {
1285
+ const propRows = await db
1286
+ .select({ modelId: properties.modelId })
1287
+ .from(properties)
1288
+ .where(eq(properties.schemaFileId, schemaFileId))
1289
+ .limit(1);
1290
+ if (propRows.length > 0 && propRows[0].modelId) {
1291
+ const byPropModelId = await db
1292
+ .select()
1293
+ .from(models)
1294
+ .where(eq(models.id, propRows[0].modelId))
1295
+ .limit(1);
1296
+ modelRecord = byPropModelId[0];
1297
+ }
1298
+ }
1299
+ if (!modelRecord) {
1300
+ throw new Error(`Model not found in database (modelId=${property.modelId}, modelName=${property.modelName})`);
1301
+ }
1302
+ // Find existing property - try multiple strategies to handle name changes
1303
+ // 1. First try by schemaFileId (most reliable - doesn't change when name changes)
1304
+ let existingProperties = [];
1305
+ logger(`[savePropertyToDb] Looking for property ${property.modelName}:${property.name} (schemaFileId: ${schemaFileId}, originalName: ${property._originalValues?.name})`);
1306
+ if (schemaFileId) {
1307
+ existingProperties = await db
1308
+ .select()
1309
+ .from(properties)
1310
+ .where(and(eq(properties.schemaFileId, schemaFileId), eq(properties.modelId, modelRecord.id)))
1311
+ .limit(1);
1312
+ logger(`[savePropertyToDb] Found ${existingProperties.length} properties by schemaFileId`);
1313
+ }
1314
+ // 2. If not found by schemaFileId, try by original name (if name was changed)
1315
+ if (existingProperties.length === 0 && property._originalValues?.name && property._originalValues.name !== property.name) {
1316
+ logger(`[savePropertyToDb] Trying to find by original name: ${property._originalValues.name}`);
1317
+ existingProperties = await db
1318
+ .select()
1319
+ .from(properties)
1320
+ .where(and(eq(properties.name, property._originalValues.name), eq(properties.modelId, modelRecord.id)))
1321
+ .limit(1);
1322
+ logger(`[savePropertyToDb] Found ${existingProperties.length} properties by original name`);
1323
+ }
1324
+ // 3. Fallback: try by current name
1325
+ if (existingProperties.length === 0) {
1326
+ logger(`[savePropertyToDb] Trying to find by current name: ${property.name}`);
1327
+ existingProperties = await db
1328
+ .select()
1329
+ .from(properties)
1330
+ .where(and(eq(properties.name, property.name), eq(properties.modelId, modelRecord.id)))
1331
+ .limit(1);
1332
+ logger(`[savePropertyToDb] Found ${existingProperties.length} properties by current name`);
1333
+ }
1334
+ // Prepare property data
1335
+ const propertyData = {
1336
+ name: property.name,
1337
+ modelId: modelRecord.id,
1338
+ dataType: property.dataType || '',
1339
+ };
1340
+ // Preserve schemaFileId if we have it
1341
+ if (schemaFileId) {
1342
+ propertyData.schemaFileId = schemaFileId;
1343
+ }
1344
+ // Handle ref property - create ref model if needed
1345
+ if (property.refModelName) {
1346
+ const refModel = await createOrUpdate(db, models, {
1347
+ name: property.refModelName,
1348
+ });
1349
+ propertyData.refModelId = refModel.id;
1350
+ }
1351
+ else if (property.refModelId) {
1352
+ propertyData.refModelId = property.refModelId;
1353
+ }
1354
+ else {
1355
+ // If it's not a Relation type, ensure refModelId is null
1356
+ propertyData.refModelId = null;
1357
+ }
1358
+ if (property.refValueType) {
1359
+ propertyData.refValueType = property.refValueType;
1360
+ }
1361
+ else {
1362
+ // If refValueType is not set, ensure it's null
1363
+ propertyData.refValueType = null;
1364
+ }
1365
+ propertyData.required = property.required ?? false;
1366
+ if (existingProperties.length > 0) {
1367
+ // Property exists, update it with new values (including new name)
1368
+ // Set isEdited = true when property is edited
1369
+ const existingProperty = existingProperties[0];
1370
+ await db
1371
+ .update(properties)
1372
+ .set({
1373
+ ...propertyData,
1374
+ isEdited: true, // Mark as edited when saving changes
1375
+ })
1376
+ .where(eq(properties.id, existingProperty.id));
1377
+ logger(`Updated property ${property.modelName}:${property._originalValues?.name || 'unknown'} -> ${property.name} in database`);
1378
+ }
1379
+ else {
1380
+ // Property doesn't exist, create it
1381
+ // Set isEdited = true for runtime-created properties
1382
+ try {
1383
+ await db.insert(properties).values({
1384
+ ...propertyData,
1385
+ isEdited: true, // Runtime-created properties are edited
1386
+ });
1387
+ logger(`Created property ${property.modelName}:${property.name} in database`);
1388
+ }
1389
+ catch (insertError) {
1390
+ // Treat UNIQUE constraint as success - property already exists (e.g. from concurrent addModelsToDb or race)
1391
+ if (isSqliteUniqueConstraintError(insertError)) {
1392
+ logger(`Property ${property.modelName}:${property.name} already exists (UNIQUE constraint), treating as success`);
1393
+ }
1394
+ else {
1395
+ throw insertError;
1396
+ }
1397
+ }
1398
+ }
1399
+ };
1400
+ function parseAddressConfig(value) {
1401
+ if (!value)
1402
+ return null;
1403
+ try {
1404
+ const parsed = JSON.parse(value);
1405
+ if (Array.isArray(parsed)) {
1406
+ return { owned: parsed, watched: [] };
1407
+ }
1408
+ if (parsed && typeof parsed === 'object' && Array.isArray(parsed.owned)) {
1409
+ return {
1410
+ owned: parsed.owned,
1411
+ watched: Array.isArray(parsed.watched) ? parsed.watched : [],
1412
+ };
1413
+ }
1414
+ return null;
1415
+ }
1416
+ catch {
1417
+ return null;
1418
+ }
1419
+ }
1420
+ const getOwnedAddressesFromDb = async () => {
1421
+ const config = await getAddressConfigFromDb();
1422
+ return config?.owned ?? [];
1423
+ };
1424
+ const getWatchedAddressesFromDb = async () => {
1425
+ const config = await getAddressConfigFromDb();
1426
+ return config?.watched ?? [];
1427
+ };
1428
+ /**
1429
+ * Returns addresses for useItems/getItemsData addressFilter.
1430
+ * Encapsulates owned (with additional sync addresses) and watched logic.
1431
+ */
1432
+ const getAddressesForItemsFilter = async (addressFilter) => {
1433
+ if (addressFilter === 'owned') {
1434
+ const _mod_3 = await import('./index--F3Wolt5.js');
1435
+ const _ns_3 = _mod_3.aa;
1436
+ const { getGetAdditionalSyncAddresses } = _ns_3;
1437
+ let ownedAddresses = await getOwnedAddressesFromDb();
1438
+ const additionalGetter = getGetAdditionalSyncAddresses();
1439
+ if (additionalGetter) {
1440
+ const additional = await additionalGetter();
1441
+ if (additional?.length) {
1442
+ const seen = new Set(ownedAddresses.map((a) => a.toLowerCase()));
1443
+ for (const addr of additional) {
1444
+ if (addr && !seen.has(addr.toLowerCase())) {
1445
+ seen.add(addr.toLowerCase());
1446
+ ownedAddresses = [...ownedAddresses, addr];
1447
+ }
1448
+ }
1449
+ }
1450
+ }
1451
+ return ownedAddresses;
1452
+ }
1453
+ return getWatchedAddressesFromDb();
1454
+ };
1455
+ /**
1456
+ * Returns owned + watched addresses. Use for EAS sync and file download.
1457
+ */
1458
+ const getAllAddressesFromDb = async () => {
1459
+ const config = await getAddressConfigFromDb();
1460
+ if (!config)
1461
+ return [];
1462
+ return [...config.owned, ...config.watched];
1463
+ };
1464
+ async function getAddressConfigFromDb() {
1465
+ const appDb = BaseDb.getAppDb();
1466
+ if (!appDb) {
1467
+ return new Promise((resolve) => {
1468
+ setTimeout(async () => {
1469
+ resolve(await getAddressConfigFromDb());
1470
+ }, 500);
1471
+ });
1472
+ }
1473
+ const appStatesRecords = await appDb
1474
+ .select()
1475
+ .from(appState)
1476
+ .where(eq(appState.key, 'addresses'))
1477
+ .limit(1);
1478
+ if (!appStatesRecords || appStatesRecords.length === 0) {
1479
+ return null;
1480
+ }
1481
+ const addressArrayString = appStatesRecords[0].value;
1482
+ return parseAddressConfig(addressArrayString);
1483
+ }
1484
+ const getAddressesFromDb = async () => {
1485
+ const config = await getAddressConfigFromDb();
1486
+ if (!config || config.owned.length === 0) {
1487
+ throw new Error('No addresses found');
1488
+ }
1489
+ return config.owned;
1490
+ };
1491
+ /**
1492
+ * Like getAddressesFromDb but returns [] instead of throwing when no addresses are configured.
1493
+ * Returns owned addresses. Use getAllAddressesFromDb for sync (owned + watched).
1494
+ */
1495
+ const getAddressesFromDbOptional = async () => {
1496
+ const config = await getAddressConfigFromDb();
1497
+ return config?.owned ?? [];
1498
+ };
1499
+ /**
1500
+ * Write model to database and create model_schemas join entry
1501
+ * @param modelFileId - The model file ID (schema_file_id)
1502
+ * @param data - Model data including modelName, schemaId, and optional properties
1503
+ */
1504
+ async function writeModelToDb(modelFileId, data) {
1505
+ const db = BaseDb.getAppDb();
1506
+ if (!db)
1507
+ throw new Error('Database not available');
1508
+ // Find or create model record
1509
+ let modelRecords = await db
1510
+ .select()
1511
+ .from(models)
1512
+ .where(eq(models.schemaFileId, modelFileId))
1513
+ .limit(1);
1514
+ let modelId;
1515
+ if (modelRecords.length === 0) {
1516
+ // Create new model record
1517
+ // Check again right before insert to avoid race conditions
1518
+ const doubleCheck = await db
1519
+ .select()
1520
+ .from(models)
1521
+ .where(eq(models.schemaFileId, modelFileId))
1522
+ .limit(1);
1523
+ if (doubleCheck.length > 0) {
1524
+ // Another process created it, use existing
1525
+ modelId = doubleCheck[0].id;
1526
+ logger(`Model with schemaFileId "${modelFileId}" was created by another process, using existing record (id: ${modelId})`);
1527
+ }
1528
+ else {
1529
+ try {
1530
+ const newModel = await db.insert(models).values({
1531
+ name: data.modelName,
1532
+ schemaFileId: modelFileId,
1533
+ isEdited: true, // Runtime-created models are edited
1534
+ }).returning();
1535
+ modelId = newModel[0].id;
1536
+ }
1537
+ catch (error) {
1538
+ // Handle unique constraint violation
1539
+ if (isSqliteUniqueConstraintError(error)) {
1540
+ logger(`Unique constraint violation for schemaFileId "${modelFileId}", attempting to find existing model`);
1541
+ const existing = await db
1542
+ .select()
1543
+ .from(models)
1544
+ .where(eq(models.schemaFileId, modelFileId))
1545
+ .limit(1);
1546
+ if (existing.length > 0) {
1547
+ modelId = existing[0].id;
1548
+ logger(`Found existing model with schemaFileId "${modelFileId}" (id: ${modelId}) after constraint violation`);
1549
+ }
1550
+ else {
1551
+ throw error;
1552
+ }
1553
+ }
1554
+ else {
1555
+ throw error;
1556
+ }
1557
+ }
1558
+ }
1559
+ }
1560
+ else {
1561
+ // Update existing model record
1562
+ modelId = modelRecords[0].id;
1563
+ const updates = {};
1564
+ if (data.modelName !== modelRecords[0].name) {
1565
+ updates.name = data.modelName;
1566
+ }
1567
+ if (Object.keys(updates).length > 0) {
1568
+ await db
1569
+ .update(models)
1570
+ .set(updates)
1571
+ .where(eq(models.id, modelId));
1572
+ }
1573
+ }
1574
+ // Validate that modelId and schemaId are valid before creating join entry
1575
+ if (!modelId || !Number.isInteger(modelId) || modelId <= 0) {
1576
+ throw new Error(`Invalid modelId: ${modelId}. Model record must be created successfully before creating join entry.`);
1577
+ }
1578
+ if (!data.schemaId || !Number.isInteger(data.schemaId) || data.schemaId <= 0) {
1579
+ throw new Error(`Invalid schemaId: ${data.schemaId}. Schema record must exist before creating join entry.`);
1580
+ }
1581
+ // Create model_schemas join entry
1582
+ // CRITICAL: This must happen AFTER the model record is fully saved and committed
1583
+ // The modelId comes from .returning() which ensures the record is committed
1584
+ const existingJoin = await db
1585
+ .select()
1586
+ .from(modelSchemas)
1587
+ .where(and(eq(modelSchemas.modelId, modelId), eq(modelSchemas.schemaId, data.schemaId)))
1588
+ .limit(1);
1589
+ if (existingJoin.length === 0) {
1590
+ // Only provide modelId and schemaId - id is auto-increment and should not be included
1591
+ // Don't use type cast - let Drizzle infer the correct type without id
1592
+ // Verify both modelId and schemaId exist before inserting join record
1593
+ try {
1594
+ // Verify modelId exists
1595
+ const modelCheck = await db
1596
+ .select({ id: models.id })
1597
+ .from(models)
1598
+ .where(eq(models.id, modelId))
1599
+ .limit(1);
1600
+ if (modelCheck.length === 0) {
1601
+ throw new Error(`Model with id ${modelId} does not exist in database. Cannot create join record.`);
1602
+ }
1603
+ // Verify schemaId exists and get name/fileId for invalidation broadcast
1604
+ const _mod_4 = await import('./BasePathResolver-BDgc7c4T.js');
1605
+ const _ns_4 = _mod_4.S;
1606
+ const schemaSchemaMod = _ns_4;
1607
+ const { schemas: schemasTable } = schemaSchemaMod;
1608
+ const schemaCheck = await db
1609
+ .select({
1610
+ id: schemasTable.id,
1611
+ name: schemasTable.name,
1612
+ schemaFileId: schemasTable.schemaFileId,
1613
+ })
1614
+ .from(schemasTable)
1615
+ .where(eq(schemasTable.id, data.schemaId))
1616
+ .limit(1);
1617
+ if (schemaCheck.length === 0) {
1618
+ throw new Error(`Schema with id ${data.schemaId} does not exist in database. Cannot create join record.`);
1619
+ }
1620
+ logger(`Creating join record: modelId=${modelId}, schemaId=${data.schemaId} (both verified to exist)`);
1621
+ await db.insert(modelSchemas).values({
1622
+ modelId,
1623
+ schemaId: data.schemaId,
1624
+ });
1625
+ // Notify React useModels so it can invalidate; live query over join often doesn't re-run when model_schemas is inserted.
1626
+ // Yield so the insert is visible to the refetch that will run when the broadcast is received.
1627
+ if (typeof BroadcastChannel !== 'undefined') {
1628
+ await new Promise((r) => setTimeout(r, 10));
1629
+ const row = schemaCheck[0];
1630
+ try {
1631
+ new BroadcastChannel('seed-models-invalidate').postMessage({
1632
+ schemaName: row.name ?? undefined,
1633
+ schemaFileId: row.schemaFileId ?? undefined,
1634
+ });
1635
+ }
1636
+ catch (_) { }
1637
+ }
1638
+ logger(`Successfully created join record for model ${data.modelName} (id: ${modelId}) to schema (id: ${data.schemaId})`);
1639
+ }
1640
+ catch (error) {
1641
+ if (error?.code === 'SQLITE_CONSTRAINT_FOREIGNKEY') {
1642
+ logger(`FOREIGN KEY constraint failed when creating join record for model "${data.modelName}"`);
1643
+ logger(`modelId: ${modelId}, schemaId: ${data.schemaId}`);
1644
+ logger(`Error details:`, error);
1645
+ // Re-throw with more context
1646
+ throw new Error(`FOREIGN KEY constraint failed when creating join record for model "${data.modelName}" (modelId: ${modelId}, schemaId: ${data.schemaId}). ${error.message}`);
1647
+ }
1648
+ throw error;
1649
+ }
1650
+ }
1651
+ // Write properties if provided
1652
+ if (data.properties) {
1653
+ for (const [propName, propData] of Object.entries(data.properties)) {
1654
+ // Check if property already exists in database
1655
+ const existingProps = await db
1656
+ .select()
1657
+ .from(properties)
1658
+ .where(and(eq(properties.name, propName), eq(properties.modelId, modelId)))
1659
+ .limit(1);
1660
+ let propertyFileId;
1661
+ if (existingProps.length > 0 && existingProps[0].schemaFileId) {
1662
+ // Use existing property's schemaFileId
1663
+ propertyFileId = existingProps[0].schemaFileId;
1664
+ logger(`Using existing propertyFileId "${propertyFileId}" for property "${data.modelName}:${propName}"`);
1665
+ }
1666
+ else if (propData.id) {
1667
+ // Use provided ID
1668
+ propertyFileId = propData.id;
1669
+ }
1670
+ else {
1671
+ // Generate random propertyFileId
1672
+ // IDs should be generated in the import process before calling writeModelToDb
1673
+ const _mod_5 = await import('./index--F3Wolt5.js');
1674
+ const _ns_5 = _mod_5.ab;
1675
+ const { generateId } = _ns_5;
1676
+ propertyFileId = generateId();
1677
+ logger(`Generated propertyFileId "${propertyFileId}" for property "${data.modelName}:${propName}"`);
1678
+ }
1679
+ await writePropertyToDb(propertyFileId, {
1680
+ modelId,
1681
+ name: propName,
1682
+ ...propData,
1683
+ });
1684
+ }
1685
+ }
1686
+ logger(`Wrote model ${data.modelName} (${modelFileId}) to database`);
1687
+ }
1688
+ /**
1689
+ * Write property to database
1690
+ * @param propertyFileId - The property file ID (schema_file_id)
1691
+ * @param data - Property data including modelId, name, dataType, and other property fields
1692
+ * @param isEdited - Optional flag indicating if property has been edited locally (default: false)
1693
+ */
1694
+ async function writePropertyToDb(propertyFileId, data, isEdited = false) {
1695
+ const db = BaseDb.getAppDb();
1696
+ if (!db)
1697
+ throw new Error('Database not available');
1698
+ // Find existing property by schemaFileId first (preferred for uniqueness)
1699
+ let existingProperties = await db
1700
+ .select()
1701
+ .from(properties)
1702
+ .where(eq(properties.schemaFileId, propertyFileId))
1703
+ .limit(1);
1704
+ // Fallback: find by modelId and name if not found by schemaFileId
1705
+ if (existingProperties.length === 0) {
1706
+ existingProperties = await db
1707
+ .select()
1708
+ .from(properties)
1709
+ .where(and(eq(properties.name, data.name), eq(properties.modelId, data.modelId)))
1710
+ .limit(1);
1711
+ }
1712
+ // Prepare property data
1713
+ const propertyData = {
1714
+ name: data.name,
1715
+ modelId: data.modelId,
1716
+ dataType: data.dataType || '',
1717
+ schemaFileId: propertyFileId,
1718
+ isEdited: isEdited, // Persist isEdited flag
1719
+ };
1720
+ // Handle ref property - create ref model if needed
1721
+ // Check refModelName first, then ref (for backwards compatibility with schema files)
1722
+ const refModelName = data.refModelName || data.ref;
1723
+ if (refModelName) {
1724
+ const refModel = await createOrUpdate(db, models, {
1725
+ name: refModelName,
1726
+ });
1727
+ propertyData.refModelId = refModel.id;
1728
+ }
1729
+ else if (data.refModelId) {
1730
+ propertyData.refModelId = data.refModelId;
1731
+ }
1732
+ else {
1733
+ // If it's not a Relation type, ensure refModelId is null
1734
+ propertyData.refModelId = null;
1735
+ }
1736
+ if (data.refValueType) {
1737
+ propertyData.refValueType = data.refValueType;
1738
+ }
1739
+ else {
1740
+ // If refValueType is not set, ensure it's null
1741
+ propertyData.refValueType = null;
1742
+ }
1743
+ propertyData.required = data.required ?? false;
1744
+ // Note: Additional property fields like storageType, localStorageDir, filenameSuffix
1745
+ // are not stored in the properties table but may be in the schema JSON
1746
+ if (existingProperties.length > 0) {
1747
+ // Property exists, update it with new values.
1748
+ // Use existing row id for WHERE (not name+modelId) so renames work: the row
1749
+ // may have the old name but we're updating to the new one.
1750
+ const existing = existingProperties[0];
1751
+ await db
1752
+ .update(properties)
1753
+ .set(propertyData)
1754
+ .where(eq(properties.id, existing.id));
1755
+ logger(`Updated property ${data.name} (${propertyFileId}) in database`);
1756
+ }
1757
+ else {
1758
+ // Property doesn't exist, create it
1759
+ // Double-check before insert to avoid race conditions
1760
+ const doubleCheck = await db
1761
+ .select()
1762
+ .from(properties)
1763
+ .where(eq(properties.schemaFileId, propertyFileId))
1764
+ .limit(1);
1765
+ if (doubleCheck.length > 0) {
1766
+ // Another process created it, update it instead
1767
+ await db
1768
+ .update(properties)
1769
+ .set(propertyData)
1770
+ .where(eq(properties.id, doubleCheck[0].id));
1771
+ logger(`Property with schemaFileId "${propertyFileId}" was created by another process, updated existing record`);
1772
+ }
1773
+ else {
1774
+ try {
1775
+ await db.insert(properties).values(propertyData);
1776
+ logger(`Created property ${data.name} (${propertyFileId}) in database`);
1777
+ }
1778
+ catch (error) {
1779
+ // Handle unique constraint violation
1780
+ if (isSqliteUniqueConstraintError(error)) {
1781
+ logger(`Unique constraint violation for property schemaFileId "${propertyFileId}", attempting to find existing property`);
1782
+ const existing = await db
1783
+ .select()
1784
+ .from(properties)
1785
+ .where(eq(properties.schemaFileId, propertyFileId))
1786
+ .limit(1);
1787
+ if (existing.length > 0) {
1788
+ await db
1789
+ .update(properties)
1790
+ .set(propertyData)
1791
+ .where(eq(properties.id, existing[0].id));
1792
+ logger(`Found existing property with schemaFileId "${propertyFileId}" (id: ${existing[0].id}) after constraint violation, updated it`);
1793
+ }
1794
+ else {
1795
+ throw new Error(`Failed to create or find property "${data.name}" with schemaFileId "${propertyFileId}": ${error.message}`);
1796
+ }
1797
+ }
1798
+ else {
1799
+ throw error;
1800
+ }
1801
+ }
1802
+ }
1803
+ }
1804
+ }
1805
+ /**
1806
+ * Get schema database ID from schema name or schemaFileId
1807
+ * @param schemaNameOrFileId - Schema name (string) or schemaFileId (string)
1808
+ * @returns Schema database ID
1809
+ * @throws Error if schema not found
1810
+ */
1811
+ async function getSchemaId(schemaNameOrFileId) {
1812
+ const db = BaseDb.getAppDb();
1813
+ if (!db) {
1814
+ throw new Error('Database not available');
1815
+ }
1816
+ const _mod_6 = await import('./BasePathResolver-BDgc7c4T.js');
1817
+ const _ns_6 = _mod_6.S;
1818
+ const schemaSchemaMod = _ns_6;
1819
+ const { schemas: schemasTable } = schemaSchemaMod;
1820
+ const drizzleMod = await import('drizzle-orm');
1821
+ const { eq, desc } = drizzleMod;
1822
+ // Try to find by schemaFileId first (more reliable)
1823
+ let records = await db
1824
+ .select()
1825
+ .from(schemasTable)
1826
+ .where(eq(schemasTable.schemaFileId, schemaNameOrFileId))
1827
+ .orderBy(desc(schemasTable.version))
1828
+ .limit(1);
1829
+ // If not found by schemaFileId, try by name
1830
+ if (records.length === 0) {
1831
+ records = await db
1832
+ .select()
1833
+ .from(schemasTable)
1834
+ .where(eq(schemasTable.name, schemaNameOrFileId))
1835
+ .orderBy(desc(schemasTable.version))
1836
+ .limit(1);
1837
+ }
1838
+ if (records.length === 0) {
1839
+ throw new Error(`Schema "${schemaNameOrFileId}" not found in database`);
1840
+ }
1841
+ return records[0].id;
1842
+ }
1843
+ /**
1844
+ * Get schema database ID from schemaFileId
1845
+ * @param schemaFileId - The schema file ID
1846
+ * @returns Schema database ID
1847
+ * @throws Error if schema not found
1848
+ */
1849
+ async function getSchemaIdByFileId(schemaFileId) {
1850
+ const db = BaseDb.getAppDb();
1851
+ if (!db) {
1852
+ throw new Error('Database not available');
1853
+ }
1854
+ const _mod_7 = await import('./BasePathResolver-BDgc7c4T.js');
1855
+ const _ns_7 = _mod_7.S;
1856
+ const schemaSchemaMod = _ns_7;
1857
+ const { schemas: schemasTable } = schemaSchemaMod;
1858
+ const drizzleMod = await import('drizzle-orm');
1859
+ const { eq, desc } = drizzleMod;
1860
+ const records = await db
1861
+ .select()
1862
+ .from(schemasTable)
1863
+ .where(eq(schemasTable.schemaFileId, schemaFileId))
1864
+ .orderBy(desc(schemasTable.version))
1865
+ .limit(1);
1866
+ if (records.length === 0) {
1867
+ throw new Error(`Schema with file ID "${schemaFileId}" not found in database`);
1868
+ }
1869
+ return records[0].id;
1870
+ }
1871
+ /**
1872
+ * Get model database ID from model name or modelFileId
1873
+ * @param modelNameOrFileId - Model name (string) or modelFileId (string)
1874
+ * @param schemaNameOrId - Optional schema name or ID to narrow search
1875
+ * @returns Model database ID
1876
+ * @throws Error if model not found
1877
+ */
1878
+ async function getModelId(modelNameOrFileId, schemaNameOrId) {
1879
+ const db = BaseDb.getAppDb();
1880
+ if (!db) {
1881
+ throw new Error('Database not available');
1882
+ }
1883
+ const _mod_8 = await import('./BasePathResolver-BDgc7c4T.js');
1884
+ const _ns_8 = _mod_8.M;
1885
+ const modelSchemaMod = _ns_8;
1886
+ const { models: modelsTable } = modelSchemaMod;
1887
+ const drizzleMod = await import('drizzle-orm');
1888
+ const { eq, and, or } = drizzleMod;
1889
+ // Try to find by modelFileId first (more reliable)
1890
+ let records = await db
1891
+ .select()
1892
+ .from(modelsTable)
1893
+ .where(eq(modelsTable.schemaFileId, modelNameOrFileId))
1894
+ .limit(1);
1895
+ // If not found by modelFileId, try by name
1896
+ if (records.length === 0) {
1897
+ [eq(modelsTable.name, modelNameOrFileId)];
1898
+ // If schema is provided, narrow the search
1899
+ if (schemaNameOrId !== undefined) {
1900
+ const _mod_9 = await import('./BasePathResolver-BDgc7c4T.js');
1901
+ const _ns_9 = _mod_9.x;
1902
+ const modelSchemaSchemaMod = _ns_9;
1903
+ const { modelSchemas } = modelSchemaSchemaMod;
1904
+ const _mod_10 = await import('./BasePathResolver-BDgc7c4T.js');
1905
+ const _ns_10 = _mod_10.S;
1906
+ const schemaSchemaMod = _ns_10;
1907
+ const { schemas: schemasTable } = schemaSchemaMod;
1908
+ if (typeof schemaNameOrId === 'number') {
1909
+ // schemaNameOrId is schemaId
1910
+ records = await db
1911
+ .select({ id: modelsTable.id })
1912
+ .from(modelsTable)
1913
+ .innerJoin(modelSchemas, eq(modelsTable.id, modelSchemas.modelId))
1914
+ .where(and(eq(modelsTable.name, modelNameOrFileId), eq(modelSchemas.schemaId, schemaNameOrId)))
1915
+ .limit(1);
1916
+ }
1917
+ else {
1918
+ // schemaNameOrId is schemaName
1919
+ records = await db
1920
+ .select({ id: modelsTable.id })
1921
+ .from(modelsTable)
1922
+ .innerJoin(modelSchemas, eq(modelsTable.id, modelSchemas.modelId))
1923
+ .innerJoin(schemasTable, eq(modelSchemas.schemaId, schemasTable.id))
1924
+ .where(and(eq(modelsTable.name, modelNameOrFileId), eq(schemasTable.name, schemaNameOrId)))
1925
+ .limit(1);
1926
+ }
1927
+ }
1928
+ else {
1929
+ // No schema filter, just search by name
1930
+ records = await db
1931
+ .select()
1932
+ .from(modelsTable)
1933
+ .where(eq(modelsTable.name, modelNameOrFileId))
1934
+ .limit(1);
1935
+ }
1936
+ }
1937
+ if (records.length === 0) {
1938
+ const schemaInfo = schemaNameOrId ? ` in schema "${schemaNameOrId}"` : '';
1939
+ throw new Error(`Model "${modelNameOrFileId}"${schemaInfo} not found in database`);
1940
+ }
1941
+ return records[0].id;
1942
+ }
1943
+ /**
1944
+ * Get model database ID from modelFileId
1945
+ * @param modelFileId - The model file ID (schema_file_id)
1946
+ * @returns Model database ID
1947
+ * @throws Error if model not found
1948
+ */
1949
+ async function getModelIdByFileId(modelFileId) {
1950
+ const db = BaseDb.getAppDb();
1951
+ if (!db) {
1952
+ throw new Error('Database not available');
1953
+ }
1954
+ const _mod_11 = await import('./BasePathResolver-BDgc7c4T.js');
1955
+ const _ns_11 = _mod_11.M;
1956
+ const modelSchemaMod = _ns_11;
1957
+ const { models: modelsTable } = modelSchemaMod;
1958
+ const drizzleMod = await import('drizzle-orm');
1959
+ const { eq } = drizzleMod;
1960
+ const records = await db
1961
+ .select()
1962
+ .from(modelsTable)
1963
+ .where(eq(modelsTable.schemaFileId, modelFileId))
1964
+ .limit(1);
1965
+ if (records.length === 0) {
1966
+ throw new Error(`Model with file ID "${modelFileId}" not found in database`);
1967
+ }
1968
+ return records[0].id;
1969
+ }
1970
+
1971
+ export { addModelsToDb, addSchemaToDb, createOrUpdate, escapeSqliteString, getAddressesForItemsFilter, getAddressesFromDb, getAddressesFromDbOptional, getAllAddressesFromDb, getModelId, getModelIdByFileId, getModelNameByModelId, getObjectForRow, getOwnedAddressesFromDb, getPropertyIdForModelAndName, getPropertyModelNameAndDataType, getSchemaId, getSchemaIdByFileId, getSqlResultObject, getWatchedAddressesFromDb, loadModelsFromDbForSchema, migrateMetadataForPropertyRename, renameModelInDb, savePropertyToDb, writeModelToDb, writePropertyToDb };
1972
+ //# sourceMappingURL=db-Cvh84NY7.js.map