mindoodb 0.0.2 → 0.0.4

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 (305) hide show
  1. package/README-server.md +1001 -0
  2. package/README.md +89 -28
  3. package/dist/__mocks__/expo-standard-web-crypto.d.ts +10 -0
  4. package/dist/__mocks__/expo-standard-web-crypto.d.ts.map +1 -0
  5. package/dist/__mocks__/expo-standard-web-crypto.js +22 -0
  6. package/dist/__mocks__/expo-standard-web-crypto.js.map +1 -0
  7. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.d.ts +8 -0
  8. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.d.ts.map +1 -0
  9. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.js +16 -0
  10. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.js.map +1 -0
  11. package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.d.ts +1 -1
  12. package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.d.ts.map +1 -1
  13. package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.js +2 -2
  14. package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.js.map +1 -1
  15. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +30 -1
  16. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
  17. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +152 -5
  18. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
  19. package/dist/appendonlystores/network/HttpTransport.d.ts +17 -2
  20. package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
  21. package/dist/appendonlystores/network/HttpTransport.js +129 -0
  22. package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
  23. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +22 -2
  24. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
  25. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +110 -0
  26. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
  27. package/dist/appendonlystores/network/index.d.ts +1 -1
  28. package/dist/appendonlystores/network/index.d.ts.map +1 -1
  29. package/dist/appendonlystores/network/index.js.map +1 -1
  30. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts +65 -0
  31. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts.map +1 -0
  32. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js +741 -0
  33. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js.map +1 -0
  34. package/dist/browser/appendonlystores/IndexedDBContentAddressedStoreFactory.d.ts +25 -0
  35. package/dist/browser/appendonlystores/IndexedDBContentAddressedStoreFactory.d.ts.map +1 -0
  36. package/dist/browser/appendonlystores/IndexedDBContentAddressedStoreFactory.js +41 -0
  37. package/dist/browser/appendonlystores/IndexedDBContentAddressedStoreFactory.js.map +1 -0
  38. package/dist/browser/cache/IndexedDBLocalCacheStore.d.ts +21 -0
  39. package/dist/browser/cache/IndexedDBLocalCacheStore.d.ts.map +1 -0
  40. package/dist/browser/cache/IndexedDBLocalCacheStore.js +106 -0
  41. package/dist/browser/cache/IndexedDBLocalCacheStore.js.map +1 -0
  42. package/dist/browser/index.d.ts +8 -0
  43. package/dist/browser/index.d.ts.map +1 -1
  44. package/dist/browser/index.js +21 -1
  45. package/dist/browser/index.js.map +1 -1
  46. package/dist/core/BaseMindooDB.d.ts +115 -13
  47. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  48. package/dist/core/BaseMindooDB.js +1232 -269
  49. package/dist/core/BaseMindooDB.js.map +1 -1
  50. package/dist/core/BaseMindooTenant.d.ts +69 -6
  51. package/dist/core/BaseMindooTenant.d.ts.map +1 -1
  52. package/dist/core/BaseMindooTenant.js +302 -109
  53. package/dist/core/BaseMindooTenant.js.map +1 -1
  54. package/dist/core/BaseMindooTenantDirectory.d.ts +13 -10
  55. package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
  56. package/dist/core/BaseMindooTenantDirectory.js +144 -27
  57. package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
  58. package/dist/core/BaseMindooTenantFactory.d.ts +27 -29
  59. package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
  60. package/dist/core/BaseMindooTenantFactory.js +185 -112
  61. package/dist/core/BaseMindooTenantFactory.js.map +1 -1
  62. package/dist/core/MindooDBServerAdmin.d.ts +238 -0
  63. package/dist/core/MindooDBServerAdmin.d.ts.map +1 -0
  64. package/dist/core/MindooDBServerAdmin.js +345 -0
  65. package/dist/core/MindooDBServerAdmin.js.map +1 -0
  66. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +68 -0
  67. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -0
  68. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.js +659 -0
  69. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.js.map +1 -0
  70. package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts +45 -3
  71. package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts.map +1 -1
  72. package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +184 -23
  73. package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -1
  74. package/dist/core/appendonlystores/MaterializationPlanner.d.ts +49 -0
  75. package/dist/core/appendonlystores/MaterializationPlanner.d.ts.map +1 -0
  76. package/dist/core/appendonlystores/MaterializationPlanner.js +325 -0
  77. package/dist/core/appendonlystores/MaterializationPlanner.js.map +1 -0
  78. package/dist/core/appendonlystores/bloom.d.ts +85 -0
  79. package/dist/core/appendonlystores/bloom.d.ts.map +1 -0
  80. package/dist/core/appendonlystores/bloom.js +228 -0
  81. package/dist/core/appendonlystores/bloom.js.map +1 -0
  82. package/dist/core/appendonlystores/network/NetworkTransport.d.ts +37 -2
  83. package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -1
  84. package/dist/core/appendonlystores/network/types.d.ts +12 -0
  85. package/dist/core/appendonlystores/network/types.d.ts.map +1 -1
  86. package/dist/core/appendonlystores/network/types.js.map +1 -1
  87. package/dist/core/appendonlystores/types.d.ts +206 -0
  88. package/dist/core/appendonlystores/types.d.ts.map +1 -1
  89. package/dist/core/automerge-adapter.d.ts +15 -0
  90. package/dist/core/automerge-adapter.d.ts.map +1 -0
  91. package/dist/core/automerge-adapter.js +73 -0
  92. package/dist/core/automerge-adapter.js.map +1 -0
  93. package/dist/core/cache/CacheManager.d.ts +75 -0
  94. package/dist/core/cache/CacheManager.d.ts.map +1 -0
  95. package/dist/core/cache/CacheManager.js +101 -0
  96. package/dist/core/cache/CacheManager.js.map +1 -0
  97. package/dist/core/cache/EncryptedLocalCacheStore.d.ts +41 -0
  98. package/dist/core/cache/EncryptedLocalCacheStore.d.ts.map +1 -0
  99. package/dist/core/cache/EncryptedLocalCacheStore.js +120 -0
  100. package/dist/core/cache/EncryptedLocalCacheStore.js.map +1 -0
  101. package/dist/core/cache/LocalCacheStore.d.ts +50 -0
  102. package/dist/core/cache/LocalCacheStore.d.ts.map +1 -0
  103. package/dist/core/cache/LocalCacheStore.js +39 -0
  104. package/dist/core/cache/LocalCacheStore.js.map +1 -0
  105. package/dist/core/crypto/pbkdf2Iterations.d.ts +12 -0
  106. package/dist/core/crypto/pbkdf2Iterations.d.ts.map +1 -0
  107. package/dist/core/crypto/pbkdf2Iterations.js +55 -0
  108. package/dist/core/crypto/pbkdf2Iterations.js.map +1 -0
  109. package/dist/core/crypto/privateKeyEncryption.d.ts +5 -0
  110. package/dist/core/crypto/privateKeyEncryption.d.ts.map +1 -0
  111. package/dist/core/crypto/privateKeyEncryption.js +87 -0
  112. package/dist/core/crypto/privateKeyEncryption.js.map +1 -0
  113. package/dist/core/index.d.ts +18 -6
  114. package/dist/core/index.d.ts.map +1 -1
  115. package/dist/core/index.js +42 -1
  116. package/dist/core/index.js.map +1 -1
  117. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts +4 -1
  118. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts.map +1 -1
  119. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js +39 -11
  120. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js.map +1 -1
  121. package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.d.ts +1 -0
  122. package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.d.ts.map +1 -1
  123. package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.js +3 -0
  124. package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.js.map +1 -1
  125. package/dist/core/indexing/virtualviews/VirtualView.d.ts +43 -0
  126. package/dist/core/indexing/virtualviews/VirtualView.d.ts.map +1 -1
  127. package/dist/core/indexing/virtualviews/VirtualView.js +173 -0
  128. package/dist/core/indexing/virtualviews/VirtualView.js.map +1 -1
  129. package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts +7 -0
  130. package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts.map +1 -1
  131. package/dist/core/indexing/virtualviews/VirtualViewEntryData.js +28 -0
  132. package/dist/core/indexing/virtualviews/VirtualViewEntryData.js.map +1 -1
  133. package/dist/core/keys/KeyBag.d.ts +56 -12
  134. package/dist/core/keys/KeyBag.d.ts.map +1 -1
  135. package/dist/core/keys/KeyBag.js +156 -70
  136. package/dist/core/keys/KeyBag.js.map +1 -1
  137. package/dist/core/keys/KeyContext.d.ts +4 -0
  138. package/dist/core/keys/KeyContext.d.ts.map +1 -0
  139. package/dist/core/keys/KeyContext.js +17 -0
  140. package/dist/core/keys/KeyContext.js.map +1 -0
  141. package/dist/core/types.d.ts +512 -60
  142. package/dist/core/types.d.ts.map +1 -1
  143. package/dist/core/types.js +9 -1
  144. package/dist/core/types.js.map +1 -1
  145. package/dist/core/uri/MindooURI.d.ts +58 -0
  146. package/dist/core/uri/MindooURI.d.ts.map +1 -0
  147. package/dist/core/uri/MindooURI.js +169 -0
  148. package/dist/core/uri/MindooURI.js.map +1 -0
  149. package/dist/core/userid/index.d.ts +0 -10
  150. package/dist/core/userid/index.d.ts.map +1 -1
  151. package/dist/core/utils/idGeneration.d.ts.map +1 -1
  152. package/dist/core/utils/idGeneration.js +37 -3
  153. package/dist/core/utils/idGeneration.js.map +1 -1
  154. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +544 -0
  155. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -0
  156. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js +1358 -0
  157. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js.map +1 -0
  158. package/dist/node/attachments/writeAttachmentToFile.d.ts +15 -0
  159. package/dist/node/attachments/writeAttachmentToFile.d.ts.map +1 -0
  160. package/dist/node/attachments/writeAttachmentToFile.js +73 -0
  161. package/dist/node/attachments/writeAttachmentToFile.js.map +1 -0
  162. package/dist/node/cache/FileSystemLocalCacheStore.d.ts +17 -0
  163. package/dist/node/cache/FileSystemLocalCacheStore.d.ts.map +1 -0
  164. package/dist/node/cache/FileSystemLocalCacheStore.js +128 -0
  165. package/dist/node/cache/FileSystemLocalCacheStore.js.map +1 -0
  166. package/dist/node/cli/change-identity-password.d.ts +7 -0
  167. package/dist/node/cli/change-identity-password.d.ts.map +1 -0
  168. package/dist/node/cli/change-identity-password.js +67 -0
  169. package/dist/node/cli/change-identity-password.js.map +1 -0
  170. package/dist/node/cli/cli-utils.d.ts +16 -0
  171. package/dist/node/cli/cli-utils.d.ts.map +1 -0
  172. package/dist/node/cli/cli-utils.js +113 -0
  173. package/dist/node/cli/cli-utils.js.map +1 -0
  174. package/dist/node/cli/identity-export-public.d.ts +4 -0
  175. package/dist/node/cli/identity-export-public.d.ts.map +1 -0
  176. package/dist/node/cli/identity-export-public.js +55 -0
  177. package/dist/node/cli/identity-export-public.js.map +1 -0
  178. package/dist/node/cli/identity-info.d.ts +4 -0
  179. package/dist/node/cli/identity-info.d.ts.map +1 -0
  180. package/dist/node/cli/identity-info.js +57 -0
  181. package/dist/node/cli/identity-info.js.map +1 -0
  182. package/dist/node/index.d.ts +2 -0
  183. package/dist/node/index.d.ts.map +1 -1
  184. package/dist/node/index.js +8 -1
  185. package/dist/node/index.js.map +1 -1
  186. package/dist/node/server/CapabilityMatcher.d.ts +45 -0
  187. package/dist/node/server/CapabilityMatcher.d.ts.map +1 -0
  188. package/dist/node/server/CapabilityMatcher.js +117 -0
  189. package/dist/node/server/CapabilityMatcher.js.map +1 -0
  190. package/dist/node/server/MindooDBServer.d.ts +87 -0
  191. package/dist/node/server/MindooDBServer.d.ts.map +1 -0
  192. package/dist/node/server/MindooDBServer.js +1040 -0
  193. package/dist/node/server/MindooDBServer.js.map +1 -0
  194. package/dist/node/server/ServerSync.d.ts +41 -0
  195. package/dist/node/server/ServerSync.d.ts.map +1 -0
  196. package/dist/node/server/ServerSync.js +187 -0
  197. package/dist/node/server/ServerSync.js.map +1 -0
  198. package/dist/node/server/StoreFactory.d.ts +45 -0
  199. package/dist/node/server/StoreFactory.d.ts.map +1 -0
  200. package/dist/node/server/StoreFactory.js +89 -0
  201. package/dist/node/server/StoreFactory.js.map +1 -0
  202. package/dist/node/server/SystemAdminAuth.d.ts +65 -0
  203. package/dist/node/server/SystemAdminAuth.d.ts.map +1 -0
  204. package/dist/node/server/SystemAdminAuth.js +200 -0
  205. package/dist/node/server/SystemAdminAuth.js.map +1 -0
  206. package/dist/node/server/SystemIpAllowlist.d.ts +21 -0
  207. package/dist/node/server/SystemIpAllowlist.d.ts.map +1 -0
  208. package/dist/node/server/SystemIpAllowlist.js +210 -0
  209. package/dist/node/server/SystemIpAllowlist.js.map +1 -0
  210. package/dist/node/server/TenantManager.d.ts +85 -0
  211. package/dist/node/server/TenantManager.d.ts.map +1 -0
  212. package/dist/node/server/TenantManager.js +493 -0
  213. package/dist/node/server/TenantManager.js.map +1 -0
  214. package/dist/node/server/add-to-network.d.ts +20 -0
  215. package/dist/node/server/add-to-network.d.ts.map +1 -0
  216. package/dist/node/server/add-to-network.js +275 -0
  217. package/dist/node/server/add-to-network.js.map +1 -0
  218. package/dist/node/server/config.d.ts +51 -0
  219. package/dist/node/server/config.d.ts.map +1 -0
  220. package/dist/node/server/config.js +218 -0
  221. package/dist/node/server/config.js.map +1 -0
  222. package/dist/node/server/resolveServerPassword.d.ts +7 -0
  223. package/dist/node/server/resolveServerPassword.d.ts.map +1 -0
  224. package/dist/node/server/resolveServerPassword.js +25 -0
  225. package/dist/node/server/resolveServerPassword.js.map +1 -0
  226. package/dist/node/server/server.d.ts +22 -0
  227. package/dist/node/server/server.d.ts.map +1 -0
  228. package/dist/node/server/server.js +225 -0
  229. package/dist/node/server/server.js.map +1 -0
  230. package/dist/node/server/serverinit.d.ts +21 -0
  231. package/dist/node/server/serverinit.d.ts.map +1 -0
  232. package/dist/node/server/serverinit.js +317 -0
  233. package/dist/node/server/serverinit.js.map +1 -0
  234. package/dist/node/server/types.d.ts +162 -0
  235. package/dist/node/server/types.d.ts.map +1 -0
  236. package/dist/node/server/types.js +24 -0
  237. package/dist/node/server/types.js.map +1 -0
  238. package/dist/node/server/validation.d.ts +47 -0
  239. package/dist/node/server/validation.d.ts.map +1 -0
  240. package/dist/node/server/validation.js +114 -0
  241. package/dist/node/server/validation.js.map +1 -0
  242. package/dist/reactnative/cache/MMKVLocalCacheStore.d.ts +48 -0
  243. package/dist/reactnative/cache/MMKVLocalCacheStore.d.ts.map +1 -0
  244. package/dist/reactnative/cache/MMKVLocalCacheStore.js +113 -0
  245. package/dist/reactnative/cache/MMKVLocalCacheStore.js.map +1 -0
  246. package/dist/reactnative/crypto/AESAdapter.d.ts +18 -0
  247. package/dist/reactnative/crypto/AESAdapter.d.ts.map +1 -0
  248. package/dist/reactnative/crypto/AESAdapter.js +112 -0
  249. package/dist/reactnative/crypto/AESAdapter.js.map +1 -0
  250. package/dist/reactnative/crypto/Ed25519Adapter.d.ts +34 -0
  251. package/dist/reactnative/crypto/Ed25519Adapter.d.ts.map +1 -0
  252. package/dist/reactnative/crypto/Ed25519Adapter.js +386 -0
  253. package/dist/reactnative/crypto/Ed25519Adapter.js.map +1 -0
  254. package/dist/reactnative/crypto/ExpoGoCryptoAdapter.d.ts +23 -0
  255. package/dist/reactnative/crypto/ExpoGoCryptoAdapter.d.ts.map +1 -0
  256. package/dist/reactnative/crypto/ExpoGoCryptoAdapter.js +51 -0
  257. package/dist/reactnative/crypto/ExpoGoCryptoAdapter.js.map +1 -0
  258. package/dist/reactnative/crypto/HMACAdapter.d.ts +13 -0
  259. package/dist/reactnative/crypto/HMACAdapter.d.ts.map +1 -0
  260. package/dist/reactnative/crypto/HMACAdapter.js +50 -0
  261. package/dist/reactnative/crypto/HMACAdapter.js.map +1 -0
  262. package/dist/reactnative/crypto/KeyFormatConverter.d.ts +21 -0
  263. package/dist/reactnative/crypto/KeyFormatConverter.d.ts.map +1 -0
  264. package/dist/reactnative/crypto/KeyFormatConverter.js +72 -0
  265. package/dist/reactnative/crypto/KeyFormatConverter.js.map +1 -0
  266. package/dist/reactnative/crypto/PBKDF2Adapter.d.ts +19 -0
  267. package/dist/reactnative/crypto/PBKDF2Adapter.d.ts.map +1 -0
  268. package/dist/reactnative/crypto/PBKDF2Adapter.js +67 -0
  269. package/dist/reactnative/crypto/PBKDF2Adapter.js.map +1 -0
  270. package/dist/reactnative/crypto/QuickCryptoAdapter.d.ts +37 -0
  271. package/dist/reactnative/crypto/QuickCryptoAdapter.d.ts.map +1 -0
  272. package/dist/reactnative/crypto/QuickCryptoAdapter.js +72 -0
  273. package/dist/reactnative/crypto/QuickCryptoAdapter.js.map +1 -0
  274. package/dist/reactnative/crypto/RSAAdapter.d.ts +38 -0
  275. package/dist/reactnative/crypto/RSAAdapter.d.ts.map +1 -0
  276. package/dist/reactnative/crypto/RSAAdapter.js +184 -0
  277. package/dist/reactnative/crypto/RSAAdapter.js.map +1 -0
  278. package/dist/reactnative/crypto/ReactNativeCryptoAdapter.d.ts +33 -0
  279. package/dist/reactnative/crypto/ReactNativeCryptoAdapter.d.ts.map +1 -0
  280. package/dist/reactnative/crypto/ReactNativeCryptoAdapter.js +61 -0
  281. package/dist/reactnative/crypto/ReactNativeCryptoAdapter.js.map +1 -0
  282. package/dist/reactnative/crypto/SHA256Adapter.d.ts +9 -0
  283. package/dist/reactnative/crypto/SHA256Adapter.d.ts.map +1 -0
  284. package/dist/reactnative/crypto/SHA256Adapter.js +29 -0
  285. package/dist/reactnative/crypto/SHA256Adapter.js.map +1 -0
  286. package/dist/reactnative/crypto/SubtleCryptoPolyfill.d.ts +63 -0
  287. package/dist/reactnative/crypto/SubtleCryptoPolyfill.d.ts.map +1 -0
  288. package/dist/reactnative/crypto/SubtleCryptoPolyfill.js +350 -0
  289. package/dist/reactnative/crypto/SubtleCryptoPolyfill.js.map +1 -0
  290. package/dist/reactnative/index.d.ts +9 -0
  291. package/dist/reactnative/index.d.ts.map +1 -0
  292. package/dist/reactnative/index.js +41 -0
  293. package/dist/reactnative/index.js.map +1 -0
  294. package/package.json +63 -7
  295. package/patches/PATCHES.md +111 -0
  296. package/patches/react-native+0.76.9.patch +34 -0
  297. package/patches/react-native-quick-crypto+1.0.7.patch +42 -0
  298. package/scripts/cli.js +21 -0
  299. package/scripts/setup-react-native.js +228 -0
  300. package/templates/reactnative/App.js +252 -0
  301. package/templates/reactnative/app.json +29 -0
  302. package/templates/reactnative/babel.config.js +6 -0
  303. package/templates/reactnative/index.js +26 -0
  304. package/templates/reactnative/metro.config.snippet.js +39 -0
  305. package/templates/reactnative/mindoodb-polyfills.js +116 -0
@@ -0,0 +1,741 @@
1
+ "use strict";
2
+ /**
3
+ * IndexedDB-backed ContentAddressedStore for browser environments.
4
+ *
5
+ * Provides persistent, indexed storage using the IndexedDB API. All indexing
6
+ * is delegated to IDB itself (no in-memory maps), keeping memory usage low
7
+ * even for stores with hundreds of thousands of entries.
8
+ *
9
+ * Schema (IDB version 1):
10
+ * - `entries` : metadata per entry id, indexed by docId, contentHash,
11
+ * (entryType, createdAt), and (createdAt, id)
12
+ * - `content` : encrypted payload per contentHash with reference counting
13
+ * - `bloom_cache` : single cached bloom filter summary, incrementally updated
14
+ * on inserts and fully rebuilt on purge or size threshold
15
+ *
16
+ * @module IndexedDBContentAddressedStore
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.IndexedDBContentAddressedStore = void 0;
20
+ const MaterializationPlanner_1 = require("../../core/appendonlystores/MaterializationPlanner");
21
+ const logging_1 = require("../../core/logging");
22
+ // ---------------------------------------------------------------------------
23
+ // IDB Constants
24
+ // ---------------------------------------------------------------------------
25
+ const IDB_VERSION = 1;
26
+ const ENTRIES_STORE = "entries";
27
+ const CONTENT_STORE = "content";
28
+ const BLOOM_CACHE_STORE = "bloom_cache";
29
+ // Index names
30
+ const IDX_DOC_ID = "by_docId";
31
+ const IDX_ENTRY_TYPE_CREATED_AT = "by_entryType_createdAt";
32
+ const IDX_CREATED_AT_ID = "by_createdAt_id";
33
+ const IDX_CONTENT_HASH = "by_contentHash";
34
+ // Bloom cache key
35
+ const BLOOM_CACHE_KEY = "current";
36
+ // ---------------------------------------------------------------------------
37
+ // Browser-compatible bloom filter helpers (no Buffer dependency)
38
+ // ---------------------------------------------------------------------------
39
+ const DEFAULT_FALSE_POSITIVE_RATE = 0.01;
40
+ const DEFAULT_SALT = "mindoodb-bloom-v1";
41
+ function fnv1a32(input) {
42
+ let hash = 0x811c9dc5;
43
+ for (let i = 0; i < input.length; i++) {
44
+ hash ^= input.charCodeAt(i);
45
+ hash = Math.imul(hash, 0x01000193);
46
+ }
47
+ return hash >>> 0;
48
+ }
49
+ function djb2_32(input) {
50
+ let hash = 5381;
51
+ for (let i = 0; i < input.length; i++) {
52
+ hash = ((hash << 5) + hash + input.charCodeAt(i)) >>> 0;
53
+ }
54
+ return hash >>> 0;
55
+ }
56
+ function computeBloomShape(itemCount, falsePositiveRate) {
57
+ if (itemCount <= 0) {
58
+ return { bitCount: 64, hashCount: 2 };
59
+ }
60
+ const ln2 = Math.log(2);
61
+ const bitCount = Math.max(64, Math.ceil((-itemCount * Math.log(falsePositiveRate)) / (ln2 * ln2)));
62
+ const hashCount = Math.max(1, Math.round((bitCount / itemCount) * ln2));
63
+ return { bitCount, hashCount };
64
+ }
65
+ function bloomIndexes(id, bitCount, hashCount, salt) {
66
+ const h1 = fnv1a32(`${salt}:${id}`);
67
+ const h2 = djb2_32(`${id}:${salt}`) || 1;
68
+ const indexes = [];
69
+ for (let i = 0; i < hashCount; i++) {
70
+ indexes.push((h1 + i * h2) % bitCount);
71
+ }
72
+ return indexes;
73
+ }
74
+ function uint8ArrayToBase64(bytes) {
75
+ let binary = "";
76
+ for (let i = 0; i < bytes.length; i++) {
77
+ binary += String.fromCharCode(bytes[i]);
78
+ }
79
+ return btoa(binary);
80
+ }
81
+ function base64ToUint8Array(base64) {
82
+ const binary = atob(base64);
83
+ const bytes = new Uint8Array(binary.length);
84
+ for (let i = 0; i < binary.length; i++) {
85
+ bytes[i] = binary.charCodeAt(i);
86
+ }
87
+ return bytes;
88
+ }
89
+ /**
90
+ * Build a bloom filter summary from a list of entry IDs (browser-compatible).
91
+ * Produces output identical to core bloom.ts but without Node.js Buffer.
92
+ */
93
+ function createIdBloomSummaryBrowser(ids, falsePositiveRate = DEFAULT_FALSE_POSITIVE_RATE) {
94
+ const { bitCount, hashCount } = computeBloomShape(ids.length, falsePositiveRate);
95
+ const bitset = new Uint8Array(Math.ceil(bitCount / 8));
96
+ for (const id of ids) {
97
+ const idxs = bloomIndexes(id, bitCount, hashCount, DEFAULT_SALT);
98
+ for (const idx of idxs) {
99
+ const byteIndex = Math.floor(idx / 8);
100
+ const bitOffset = idx % 8;
101
+ bitset[byteIndex] |= 1 << bitOffset;
102
+ }
103
+ }
104
+ return {
105
+ version: "bloom-v1",
106
+ totalIds: ids.length,
107
+ bitCount,
108
+ hashCount,
109
+ salt: DEFAULT_SALT,
110
+ bitsetBase64: uint8ArrayToBase64(bitset),
111
+ };
112
+ }
113
+ /**
114
+ * Threshold multiplier for bloom filter rebuild.
115
+ * When totalIds exceeds originalSizedFor * BLOOM_REBUILD_FACTOR the filter
116
+ * is rebuilt from scratch to maintain the target false-positive rate.
117
+ */
118
+ const BLOOM_REBUILD_FACTOR = 2;
119
+ /**
120
+ * Incrementally add new IDs to an existing bloom filter summary.
121
+ *
122
+ * Because bloom filters only ever set bits to 1, adding IDs is safe without
123
+ * a full recompute: decode the bitset, OR in the new bits, re-encode.
124
+ *
125
+ * Returns `null` when the filter should be fully rebuilt instead (totalIds
126
+ * has grown past BLOOM_REBUILD_FACTOR * the size it was originally sized
127
+ * for, meaning the false-positive rate has degraded beyond acceptable).
128
+ */
129
+ function incrementalBloomUpdate(summary, newIds) {
130
+ if (newIds.length === 0)
131
+ return summary;
132
+ const newTotal = summary.totalIds + newIds.length;
133
+ // Check if the filter was sized for far fewer items than it now holds.
134
+ // originalSizedFor is the item count the current bitCount/hashCount was
135
+ // optimised for. We back-derive it from the bloom shape formula:
136
+ // bitCount = -(n * ln(p)) / (ln2)^2 => n = -bitCount * (ln2)^2 / ln(p)
137
+ const ln2 = Math.log(2);
138
+ const originalSizedFor = Math.max(1, Math.floor((-summary.bitCount * ln2 * ln2) /
139
+ Math.log(DEFAULT_FALSE_POSITIVE_RATE)));
140
+ if (newTotal > originalSizedFor * BLOOM_REBUILD_FACTOR) {
141
+ // False-positive rate has degraded too far; caller should rebuild.
142
+ return null;
143
+ }
144
+ const bitset = base64ToUint8Array(summary.bitsetBase64);
145
+ for (const id of newIds) {
146
+ const idxs = bloomIndexes(id, summary.bitCount, summary.hashCount, summary.salt);
147
+ for (const idx of idxs) {
148
+ const byteIndex = Math.floor(idx / 8);
149
+ const bitOffset = idx % 8;
150
+ bitset[byteIndex] |= 1 << bitOffset;
151
+ }
152
+ }
153
+ return {
154
+ ...summary,
155
+ totalIds: newTotal,
156
+ bitsetBase64: uint8ArrayToBase64(bitset),
157
+ };
158
+ }
159
+ // ---------------------------------------------------------------------------
160
+ // IDB helpers
161
+ // ---------------------------------------------------------------------------
162
+ /** Wrap an IDBRequest in a Promise. */
163
+ function reqToPromise(request) {
164
+ return new Promise((resolve, reject) => {
165
+ request.onsuccess = () => resolve(request.result);
166
+ request.onerror = () => reject(request.error);
167
+ });
168
+ }
169
+ /** Wrap an IDBTransaction completion in a Promise. */
170
+ function txToPromise(tx) {
171
+ return new Promise((resolve, reject) => {
172
+ tx.oncomplete = () => resolve();
173
+ tx.onerror = () => reject(tx.error);
174
+ tx.onabort = () => reject(tx.error ?? new Error("IndexedDB transaction aborted"));
175
+ });
176
+ }
177
+ // ---------------------------------------------------------------------------
178
+ // Main class
179
+ // ---------------------------------------------------------------------------
180
+ /**
181
+ * An IndexedDB-backed ContentAddressedStore.
182
+ *
183
+ * Each instance maps to a single IndexedDB database named
184
+ * `mindoodb_<prefix>_<storeId>` where `prefix` comes from `options.basePath`
185
+ * and defaults to `"default"`.
186
+ *
187
+ * Entries are stored in an `entries` object store with IDB indexes that
188
+ * replace the in-memory Map indexes used by the InMemory and OnDisk stores.
189
+ * Encrypted payloads are deduplicated via a `content` object store keyed
190
+ * by `contentHash` with a `refCount` field.
191
+ *
192
+ * A single `bloom_cache` record avoids recomputing the bloom filter on every
193
+ * `getIdBloomSummary()` call.
194
+ */
195
+ class IndexedDBContentAddressedStore {
196
+ constructor(storeId, logger, options) {
197
+ this.db = null;
198
+ this.openPromise = null;
199
+ this.storeId = storeId;
200
+ this.logger =
201
+ logger ??
202
+ new logging_1.MindooLogger((0, logging_1.getDefaultLogLevel)(), `IndexedDBStore:${storeId}`, true);
203
+ const prefix = options?.basePath || "default";
204
+ this.idbName = `mindoodb_${prefix}_${storeId}`;
205
+ }
206
+ // -------------------------------------------------------------------------
207
+ // IDB lifecycle
208
+ // -------------------------------------------------------------------------
209
+ /** Lazily open the IDB database, creating object stores on first access. */
210
+ ensureOpen() {
211
+ if (this.db) {
212
+ return Promise.resolve(this.db);
213
+ }
214
+ if (this.openPromise) {
215
+ return this.openPromise;
216
+ }
217
+ this.openPromise = new Promise((resolve, reject) => {
218
+ const request = indexedDB.open(this.idbName, IDB_VERSION);
219
+ request.onupgradeneeded = (event) => {
220
+ const db = event.target.result;
221
+ // entries store
222
+ if (!db.objectStoreNames.contains(ENTRIES_STORE)) {
223
+ const entriesStore = db.createObjectStore(ENTRIES_STORE, {
224
+ keyPath: "id",
225
+ });
226
+ entriesStore.createIndex(IDX_DOC_ID, "docId", { unique: false });
227
+ entriesStore.createIndex(IDX_ENTRY_TYPE_CREATED_AT, ["entryType", "createdAt"], { unique: false });
228
+ entriesStore.createIndex(IDX_CREATED_AT_ID, ["createdAt", "id"], {
229
+ unique: true,
230
+ });
231
+ entriesStore.createIndex(IDX_CONTENT_HASH, "contentHash", {
232
+ unique: false,
233
+ });
234
+ }
235
+ // content store
236
+ if (!db.objectStoreNames.contains(CONTENT_STORE)) {
237
+ db.createObjectStore(CONTENT_STORE, { keyPath: "contentHash" });
238
+ }
239
+ // bloom cache store
240
+ if (!db.objectStoreNames.contains(BLOOM_CACHE_STORE)) {
241
+ db.createObjectStore(BLOOM_CACHE_STORE, { keyPath: "key" });
242
+ }
243
+ };
244
+ request.onsuccess = () => {
245
+ this.db = request.result;
246
+ this.db.onversionchange = () => {
247
+ this.logger.warn("IndexedDB version change detected, closing connection");
248
+ this.db?.close();
249
+ this.db = null;
250
+ this.openPromise = null;
251
+ };
252
+ resolve(this.db);
253
+ };
254
+ request.onerror = () => {
255
+ this.openPromise = null;
256
+ reject(request.error);
257
+ };
258
+ request.onblocked = () => {
259
+ this.logger.warn(`IndexedDB open blocked for ${this.idbName} – close other tabs?`);
260
+ };
261
+ });
262
+ return this.openPromise;
263
+ }
264
+ // -------------------------------------------------------------------------
265
+ // ContentAddressedStore interface
266
+ // -------------------------------------------------------------------------
267
+ getId() {
268
+ return this.storeId;
269
+ }
270
+ getCacheIdentity() {
271
+ return `idb:${this.idbName}`;
272
+ }
273
+ async putEntries(entries) {
274
+ if (entries.length === 0)
275
+ return;
276
+ const db = await this.ensureOpen();
277
+ const tx = db.transaction([ENTRIES_STORE, CONTENT_STORE, BLOOM_CACHE_STORE], "readwrite");
278
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
279
+ const contentOS = tx.objectStore(CONTENT_STORE);
280
+ const bloomOS = tx.objectStore(BLOOM_CACHE_STORE);
281
+ const insertedIds = [];
282
+ for (const entry of entries) {
283
+ // Check if entry already exists (skip duplicate)
284
+ const existing = await reqToPromise(entriesOS.get(entry.id));
285
+ if (existing) {
286
+ this.logger.debug(`Entry ${entry.id} already exists, skipping`);
287
+ continue;
288
+ }
289
+ // Separate metadata from encrypted data
290
+ const { encryptedData, ...metadata } = entry;
291
+ // Store metadata
292
+ await reqToPromise(entriesOS.put(metadata));
293
+ // Deduplicate content
294
+ const existingContent = await reqToPromise(contentOS.get(entry.contentHash));
295
+ if (existingContent) {
296
+ existingContent.refCount += 1;
297
+ await reqToPromise(contentOS.put(existingContent));
298
+ this.logger.debug(`Content ${entry.contentHash.substring(0, 8)}... already exists (deduplicated)`);
299
+ }
300
+ else {
301
+ await reqToPromise(contentOS.put({
302
+ contentHash: entry.contentHash,
303
+ data: encryptedData,
304
+ refCount: 1,
305
+ }));
306
+ this.logger.debug(`Stored content for hash ${entry.contentHash.substring(0, 8)}...`);
307
+ }
308
+ insertedIds.push(entry.id);
309
+ this.logger.debug(`Stored entry ${entry.id} for doc ${entry.docId}`);
310
+ }
311
+ // Incrementally update bloom cache with newly inserted IDs
312
+ if (insertedIds.length > 0) {
313
+ const cached = await reqToPromise(bloomOS.get(BLOOM_CACHE_KEY));
314
+ if (cached && !cached.dirty && cached.summary) {
315
+ // Try incremental update (returns null if rebuild is needed)
316
+ const updated = incrementalBloomUpdate(cached.summary, insertedIds);
317
+ if (updated) {
318
+ await reqToPromise(bloomOS.put({
319
+ key: BLOOM_CACHE_KEY,
320
+ summary: updated,
321
+ dirty: false,
322
+ }));
323
+ this.logger.debug(`Incrementally updated bloom cache (+${insertedIds.length} IDs, total ${updated.totalIds})`);
324
+ }
325
+ else {
326
+ // Filter has grown past rebuild threshold; mark dirty for full recompute
327
+ await reqToPromise(bloomOS.put({ key: BLOOM_CACHE_KEY, summary: null, dirty: true }));
328
+ this.logger.debug("Bloom cache exceeded rebuild threshold, marked dirty");
329
+ }
330
+ }
331
+ else {
332
+ // No valid cache exists; mark dirty so next getIdBloomSummary() rebuilds
333
+ await reqToPromise(bloomOS.put({ key: BLOOM_CACHE_KEY, summary: null, dirty: true }));
334
+ }
335
+ }
336
+ await txToPromise(tx);
337
+ }
338
+ async getEntries(ids) {
339
+ if (ids.length === 0)
340
+ return [];
341
+ const db = await this.ensureOpen();
342
+ const tx = db.transaction([ENTRIES_STORE, CONTENT_STORE], "readonly");
343
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
344
+ const contentOS = tx.objectStore(CONTENT_STORE);
345
+ const result = [];
346
+ for (const id of ids) {
347
+ const metadata = (await reqToPromise(entriesOS.get(id)));
348
+ if (!metadata) {
349
+ this.logger.warn(`Entry ${id} not found`);
350
+ continue;
351
+ }
352
+ const contentRecord = await reqToPromise(contentOS.get(metadata.contentHash));
353
+ if (!contentRecord) {
354
+ this.logger.warn(`Content ${metadata.contentHash} not found for entry ${id}`);
355
+ continue;
356
+ }
357
+ result.push({
358
+ ...metadata,
359
+ encryptedData: new Uint8Array(contentRecord.data),
360
+ });
361
+ }
362
+ this.logger.debug(`Retrieved ${result.length} entries out of ${ids.length} requested`);
363
+ return result;
364
+ }
365
+ async hasEntries(ids) {
366
+ if (ids.length === 0)
367
+ return [];
368
+ const db = await this.ensureOpen();
369
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
370
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
371
+ const existing = [];
372
+ for (const id of ids) {
373
+ const key = await reqToPromise(entriesOS.getKey(id));
374
+ if (key !== undefined) {
375
+ existing.push(id);
376
+ }
377
+ }
378
+ this.logger.debug(`Found ${existing.length} existing entries out of ${ids.length} checked`);
379
+ return existing;
380
+ }
381
+ async findNewEntries(knownIds) {
382
+ const knownSet = new Set(knownIds);
383
+ const db = await this.ensureOpen();
384
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
385
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
386
+ const newEntries = [];
387
+ return new Promise((resolve, reject) => {
388
+ const cursorReq = entriesOS.openCursor();
389
+ cursorReq.onsuccess = () => {
390
+ const cursor = cursorReq.result;
391
+ if (!cursor) {
392
+ this.logger.debug(`Found ${newEntries.length} new entries out of total`);
393
+ resolve(newEntries);
394
+ return;
395
+ }
396
+ const metadata = cursor.value;
397
+ if (!knownSet.has(metadata.id)) {
398
+ newEntries.push(metadata);
399
+ }
400
+ cursor.continue();
401
+ };
402
+ cursorReq.onerror = () => reject(cursorReq.error);
403
+ });
404
+ }
405
+ async findNewEntriesForDoc(knownIds, docId) {
406
+ const knownSet = new Set(knownIds);
407
+ const db = await this.ensureOpen();
408
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
409
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
410
+ const index = entriesOS.index(IDX_DOC_ID);
411
+ const newEntries = [];
412
+ return new Promise((resolve, reject) => {
413
+ const cursorReq = index.openCursor(IDBKeyRange.only(docId));
414
+ cursorReq.onsuccess = () => {
415
+ const cursor = cursorReq.result;
416
+ if (!cursor) {
417
+ this.logger.debug(`Found ${newEntries.length} new entries for doc ${docId}`);
418
+ resolve(newEntries);
419
+ return;
420
+ }
421
+ const metadata = cursor.value;
422
+ if (!knownSet.has(metadata.id)) {
423
+ newEntries.push(metadata);
424
+ }
425
+ cursor.continue();
426
+ };
427
+ cursorReq.onerror = () => reject(cursorReq.error);
428
+ });
429
+ }
430
+ async findEntries(type, creationDateFrom, creationDateUntil) {
431
+ const db = await this.ensureOpen();
432
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
433
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
434
+ const index = entriesOS.index(IDX_ENTRY_TYPE_CREATED_AT);
435
+ // Build key range on [entryType, createdAt]
436
+ const lower = [type, creationDateFrom ?? -Infinity];
437
+ const upper = [type, creationDateUntil ?? Infinity];
438
+ const range = IDBKeyRange.bound(lower, upper, false, // lowerOpen: inclusive
439
+ creationDateUntil !== null // upperOpen: exclusive when creationDateUntil is set
440
+ );
441
+ const results = [];
442
+ return new Promise((resolve, reject) => {
443
+ const cursorReq = index.openCursor(range);
444
+ cursorReq.onsuccess = () => {
445
+ const cursor = cursorReq.result;
446
+ if (!cursor) {
447
+ this.logger.debug(`Found ${results.length} entries of type ${type} in date range`);
448
+ resolve(results);
449
+ return;
450
+ }
451
+ results.push(cursor.value);
452
+ cursor.continue();
453
+ };
454
+ cursorReq.onerror = () => reject(cursorReq.error);
455
+ });
456
+ }
457
+ async getAllIds() {
458
+ const db = await this.ensureOpen();
459
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
460
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
461
+ const keys = [];
462
+ return new Promise((resolve, reject) => {
463
+ const cursorReq = entriesOS.openKeyCursor();
464
+ cursorReq.onsuccess = () => {
465
+ const cursor = cursorReq.result;
466
+ if (!cursor) {
467
+ this.logger.debug(`Returning ${keys.length} entry IDs`);
468
+ resolve(keys);
469
+ return;
470
+ }
471
+ keys.push(String(cursor.primaryKey));
472
+ cursor.continue();
473
+ };
474
+ cursorReq.onerror = () => reject(cursorReq.error);
475
+ });
476
+ }
477
+ async scanEntriesSince(cursor, limit = Number.MAX_SAFE_INTEGER, filters) {
478
+ const db = await this.ensureOpen();
479
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
480
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
481
+ const index = entriesOS.index(IDX_CREATED_AT_ID);
482
+ // Build lower bound from cursor
483
+ let range = null;
484
+ if (cursor) {
485
+ range = IDBKeyRange.lowerBound([cursor.createdAt, cursor.id], true);
486
+ }
487
+ const page = [];
488
+ return new Promise((resolve, reject) => {
489
+ const cursorReq = index.openCursor(range);
490
+ let hasMore = false;
491
+ cursorReq.onsuccess = () => {
492
+ const idbCursor = cursorReq.result;
493
+ if (!idbCursor) {
494
+ const last = page.length > 0 ? page[page.length - 1] : null;
495
+ resolve({
496
+ entries: page,
497
+ nextCursor: last
498
+ ? { createdAt: last.createdAt, id: last.id }
499
+ : cursor,
500
+ hasMore,
501
+ });
502
+ return;
503
+ }
504
+ const meta = idbCursor.value;
505
+ if (page.length >= limit) {
506
+ // We already have enough entries. Check if this one matches filters
507
+ // to determine hasMore.
508
+ if (this.matchesScanFilters(meta, filters)) {
509
+ hasMore = true;
510
+ }
511
+ const last = page[page.length - 1];
512
+ resolve({
513
+ entries: page,
514
+ nextCursor: { createdAt: last.createdAt, id: last.id },
515
+ hasMore: true,
516
+ });
517
+ return;
518
+ }
519
+ if (this.matchesScanFilters(meta, filters)) {
520
+ page.push(meta);
521
+ }
522
+ idbCursor.continue();
523
+ };
524
+ cursorReq.onerror = () => reject(cursorReq.error);
525
+ });
526
+ }
527
+ async getIdBloomSummary() {
528
+ const db = await this.ensureOpen();
529
+ // Try to read from cache first
530
+ const readTx = db.transaction(BLOOM_CACHE_STORE, "readonly");
531
+ const bloomOS = readTx.objectStore(BLOOM_CACHE_STORE);
532
+ const cached = await reqToPromise(bloomOS.get(BLOOM_CACHE_KEY));
533
+ if (cached && !cached.dirty && cached.summary) {
534
+ this.logger.debug("Returning cached bloom summary");
535
+ return cached.summary;
536
+ }
537
+ // Recompute bloom summary
538
+ this.logger.debug("Recomputing bloom summary");
539
+ const ids = await this.getAllIds();
540
+ const summary = createIdBloomSummaryBrowser(ids);
541
+ // Persist to cache
542
+ const writeTx = db.transaction(BLOOM_CACHE_STORE, "readwrite");
543
+ const writeBloomOS = writeTx.objectStore(BLOOM_CACHE_STORE);
544
+ await reqToPromise(writeBloomOS.put({
545
+ key: BLOOM_CACHE_KEY,
546
+ summary,
547
+ dirty: false,
548
+ }));
549
+ await txToPromise(writeTx);
550
+ return summary;
551
+ }
552
+ async planDocumentMaterialization(docId, options) {
553
+ const entries = await this.readEntriesForDoc(docId);
554
+ return (0, MaterializationPlanner_1.computeDocumentMaterializationPlan)(docId, entries, options);
555
+ }
556
+ async planDocumentMaterializationBatch(docIds, options) {
557
+ const all = [];
558
+ // Batch doc-scoped index reads so browser planning stays proportional to
559
+ // the requested documents instead of loading the entire entries store.
560
+ const concurrency = 16;
561
+ for (let offset = 0; offset < docIds.length; offset += concurrency) {
562
+ const batch = docIds.slice(offset, offset + concurrency);
563
+ const batchResults = await Promise.all(batch.map((docId) => this.readEntriesForDoc(docId)));
564
+ for (const entries of batchResults) {
565
+ all.push(...entries);
566
+ }
567
+ }
568
+ return (0, MaterializationPlanner_1.computeBatchMaterializationPlan)(all, docIds, options);
569
+ }
570
+ async resolveDependencies(startId, options) {
571
+ const stopAtEntryType = options?.stopAtEntryType;
572
+ const maxDepth = options?.maxDepth;
573
+ const includeStart = options?.includeStart !== false;
574
+ const db = await this.ensureOpen();
575
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
576
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
577
+ const result = [];
578
+ const visited = new Set();
579
+ const queue = [
580
+ { id: startId, depth: 0 },
581
+ ];
582
+ let queueIdx = 0;
583
+ while (queueIdx < queue.length) {
584
+ const { id, depth } = queue[queueIdx++];
585
+ if (visited.has(id))
586
+ continue;
587
+ visited.add(id);
588
+ if (maxDepth !== undefined && depth > maxDepth)
589
+ continue;
590
+ const entry = (await reqToPromise(entriesOS.get(id)));
591
+ if (!entry) {
592
+ this.logger.warn(`Entry ${id} not found during dependency resolution`);
593
+ continue;
594
+ }
595
+ if (stopAtEntryType && entry.entryType === stopAtEntryType && id !== startId) {
596
+ result.push(id);
597
+ continue;
598
+ }
599
+ if (id !== startId || includeStart) {
600
+ result.push(id);
601
+ }
602
+ for (const depId of entry.dependencyIds) {
603
+ if (!visited.has(depId)) {
604
+ queue.push({ id: depId, depth: depth + 1 });
605
+ }
606
+ }
607
+ }
608
+ result.reverse();
609
+ this.logger.debug(`Resolved ${result.length} dependencies for ${startId}`);
610
+ return result;
611
+ }
612
+ async purgeDocHistory(docId) {
613
+ this.logger.info(`Purging entry history for document: ${docId}`);
614
+ const db = await this.ensureOpen();
615
+ const tx = db.transaction([ENTRIES_STORE, CONTENT_STORE, BLOOM_CACHE_STORE], "readwrite");
616
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
617
+ const contentOS = tx.objectStore(CONTENT_STORE);
618
+ const bloomOS = tx.objectStore(BLOOM_CACHE_STORE);
619
+ const docIndex = entriesOS.index(IDX_DOC_ID);
620
+ // Collect all entries for this docId
621
+ const entriesToPurge = [];
622
+ await new Promise((resolve, reject) => {
623
+ const cursorReq = docIndex.openCursor(IDBKeyRange.only(docId));
624
+ cursorReq.onsuccess = () => {
625
+ const cursor = cursorReq.result;
626
+ if (!cursor) {
627
+ resolve();
628
+ return;
629
+ }
630
+ entriesToPurge.push(cursor.value);
631
+ cursor.continue();
632
+ };
633
+ cursorReq.onerror = () => reject(cursorReq.error);
634
+ });
635
+ if (entriesToPurge.length === 0) {
636
+ this.logger.debug(`No entries found for document ${docId}, nothing to purge`);
637
+ return;
638
+ }
639
+ // Delete entries and decrement content ref counts
640
+ for (const entry of entriesToPurge) {
641
+ await reqToPromise(entriesOS.delete(entry.id));
642
+ const contentRecord = await reqToPromise(contentOS.get(entry.contentHash));
643
+ if (contentRecord) {
644
+ const newCount = contentRecord.refCount - 1;
645
+ if (newCount <= 0) {
646
+ await reqToPromise(contentOS.delete(entry.contentHash));
647
+ this.logger.debug(`Cleaned up orphaned content ${entry.contentHash.substring(0, 8)}...`);
648
+ }
649
+ else {
650
+ contentRecord.refCount = newCount;
651
+ await reqToPromise(contentOS.put(contentRecord));
652
+ }
653
+ }
654
+ }
655
+ // Invalidate bloom cache
656
+ await reqToPromise(bloomOS.put({ key: BLOOM_CACHE_KEY, summary: null, dirty: true }));
657
+ await txToPromise(tx);
658
+ this.logger.info(`Purged ${entriesToPurge.length} entries for document ${docId}`);
659
+ }
660
+ async clearAllLocalData() {
661
+ this.logger.info(`Clearing all local data for store ${this.storeId}`);
662
+ if (this.db) {
663
+ this.db.close();
664
+ this.db = null;
665
+ this.openPromise = null;
666
+ }
667
+ return new Promise((resolve, reject) => {
668
+ const request = indexedDB.deleteDatabase(this.idbName);
669
+ request.onsuccess = () => {
670
+ this.logger.info(`Deleted IndexedDB database ${this.idbName}`);
671
+ resolve();
672
+ };
673
+ request.onerror = () => reject(request.error);
674
+ request.onblocked = () => {
675
+ this.logger.warn(`IndexedDB delete blocked for ${this.idbName} – close other tabs?`);
676
+ };
677
+ });
678
+ }
679
+ async awaitIndexReady(_options) {
680
+ return {
681
+ phase: "ready",
682
+ indexingEnabled: true,
683
+ progress01: 1,
684
+ };
685
+ }
686
+ getIndexBuildStatus() {
687
+ return {
688
+ phase: "ready",
689
+ indexingEnabled: true,
690
+ progress01: 1,
691
+ };
692
+ }
693
+ // -------------------------------------------------------------------------
694
+ // Private helpers
695
+ // -------------------------------------------------------------------------
696
+ matchesScanFilters(meta, filters) {
697
+ if (filters?.docId && meta.docId !== filters.docId) {
698
+ return false;
699
+ }
700
+ if (filters?.entryTypes &&
701
+ filters.entryTypes.length > 0 &&
702
+ !filters.entryTypes.includes(meta.entryType)) {
703
+ return false;
704
+ }
705
+ if (filters?.creationDateFrom !== undefined &&
706
+ filters.creationDateFrom !== null &&
707
+ meta.createdAt < filters.creationDateFrom) {
708
+ return false;
709
+ }
710
+ if (filters?.creationDateUntil !== undefined &&
711
+ filters.creationDateUntil !== null &&
712
+ meta.createdAt >= filters.creationDateUntil) {
713
+ return false;
714
+ }
715
+ return true;
716
+ }
717
+ async readEntriesForDoc(docId) {
718
+ const db = await this.ensureOpen();
719
+ const tx = db.transaction(ENTRIES_STORE, "readonly");
720
+ const entriesOS = tx.objectStore(ENTRIES_STORE);
721
+ const index = entriesOS.index(IDX_DOC_ID);
722
+ const entries = [];
723
+ // Stream one document's metadata through the docId index so callers can
724
+ // plan or hydrate per-doc state without a whole-store metadata read.
725
+ return new Promise((resolve, reject) => {
726
+ const cursorReq = index.openCursor(IDBKeyRange.only(docId));
727
+ cursorReq.onsuccess = () => {
728
+ const cursor = cursorReq.result;
729
+ if (!cursor) {
730
+ resolve(entries);
731
+ return;
732
+ }
733
+ entries.push(cursor.value);
734
+ cursor.continue();
735
+ };
736
+ cursorReq.onerror = () => reject(cursorReq.error);
737
+ });
738
+ }
739
+ }
740
+ exports.IndexedDBContentAddressedStore = IndexedDBContentAddressedStore;
741
+ //# sourceMappingURL=IndexedDBContentAddressedStore.js.map