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,1040 @@
1
+ "use strict";
2
+ /**
3
+ * MindooDB Server - Express HTTP server implementing the sync API.
4
+ *
5
+ * Security features:
6
+ * - Capabilities-based system admin authorization via config.json
7
+ * - Challenge/response (Ed25519) authentication for /system/* endpoints
8
+ * - JWT-based session management for system admins
9
+ * - Input validation on all identifiers (path traversal prevention)
10
+ * - Rate limiting per endpoint tier
11
+ * - Security headers (helmet) and CORS
12
+ * - Error sanitization (no internal details leaked)
13
+ * - Request size limits and timeouts
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ var __importDefault = (this && this.__importDefault) || function (mod) {
49
+ return (mod && mod.__esModule) ? mod : { "default": mod };
50
+ };
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.MindooDBServer = void 0;
53
+ const express_1 = __importStar(require("express"));
54
+ const https_1 = __importDefault(require("https"));
55
+ const path_1 = __importDefault(require("path"));
56
+ const fs_1 = require("fs");
57
+ const helmet_1 = __importDefault(require("helmet"));
58
+ const cors_1 = __importDefault(require("cors"));
59
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
60
+ const types_1 = require("../../core/appendonlystores/network/types");
61
+ const TenantManager_1 = require("./TenantManager");
62
+ const CapabilityMatcher_1 = require("./CapabilityMatcher");
63
+ const SystemAdminAuth_1 = require("./SystemAdminAuth");
64
+ const config_1 = require("./config");
65
+ const SystemIpAllowlist_1 = require("./SystemIpAllowlist");
66
+ const validation_1 = require("./validation");
67
+ class MindooDBServer {
68
+ constructor(dataDir, serverPassword, staticDir, config, configPath) {
69
+ this.app = (0, express_1.default)();
70
+ this.tenantManager = new TenantManager_1.TenantManager(dataDir, serverPassword);
71
+ this.staticDir = staticDir;
72
+ this.configPath = configPath ?? path_1.default.join(dataDir, "config.json");
73
+ this.serverConfig = config ?? { capabilities: {} };
74
+ this.capabilityMatcher = new CapabilityMatcher_1.CapabilityMatcher(this.serverConfig);
75
+ const cryptoAdapter = this.tenantManager.getCryptoAdapter();
76
+ this.systemAdminAuth = new SystemAdminAuth_1.SystemAdminAuthService(cryptoAdapter, this.serverConfig);
77
+ const principalCount = Object.values(this.serverConfig.capabilities).reduce((sum, arr) => sum + arr.length, 0);
78
+ if (principalCount === 0) {
79
+ console.log(`[MindooDBServer] WARNING: No system admin principals configured. All /system/* endpoints are locked down.`);
80
+ }
81
+ else {
82
+ console.log(`[MindooDBServer] System admin auth configured with ${principalCount} principal(s)`);
83
+ }
84
+ this.setupMiddleware();
85
+ this.setupRoutes();
86
+ }
87
+ getApp() {
88
+ return this.app;
89
+ }
90
+ getTenantManager() {
91
+ return this.tenantManager;
92
+ }
93
+ getSystemAdminAuth() {
94
+ return this.systemAdminAuth;
95
+ }
96
+ getServerConfig() {
97
+ return this.serverConfig;
98
+ }
99
+ getConfigPath() {
100
+ return this.configPath;
101
+ }
102
+ reloadConfig(newConfig) {
103
+ this.serverConfig = newConfig;
104
+ this.capabilityMatcher.reload(newConfig);
105
+ this.systemAdminAuth.reloadPrincipals(newConfig);
106
+ }
107
+ listen(port) {
108
+ const server = this.app.listen(port, () => {
109
+ console.log(`[MindooDBServer] Listening on port ${port}`);
110
+ });
111
+ server.setTimeout(30000);
112
+ }
113
+ listenTls(port, certPath, keyPath) {
114
+ const tlsOptions = {
115
+ cert: (0, fs_1.readFileSync)(certPath),
116
+ key: (0, fs_1.readFileSync)(keyPath),
117
+ };
118
+ const server = https_1.default.createServer(tlsOptions, this.app);
119
+ server.listen(port, () => {
120
+ console.log(`[MindooDBServer] Listening on HTTPS port ${port}`);
121
+ });
122
+ server.setTimeout(30000);
123
+ }
124
+ setupMiddleware() {
125
+ this.app.use((0, helmet_1.default)());
126
+ const corsOrigin = process.env.MINDOODB_CORS_ORIGIN;
127
+ this.app.use((0, cors_1.default)({
128
+ origin: corsOrigin || false,
129
+ methods: ["GET", "POST", "PUT", "DELETE"],
130
+ allowedHeaders: ["Content-Type", "Authorization"],
131
+ }));
132
+ this.app.use((0, express_rate_limit_1.default)({
133
+ windowMs: 60000,
134
+ max: 500,
135
+ standardHeaders: true,
136
+ legacyHeaders: false,
137
+ message: { error: "Too many requests, please try again later" },
138
+ }));
139
+ this.app.use(express_1.default.json({ limit: "5mb" }));
140
+ this.app.use((req, res, next) => {
141
+ console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
142
+ next();
143
+ });
144
+ }
145
+ setupRoutes() {
146
+ // Root redirect
147
+ this.app.get("/", (req, res) => {
148
+ if (this.staticDir && (0, fs_1.existsSync)(path_1.default.join(this.staticDir, "index.html"))) {
149
+ res.redirect(302, "/statics/index.html");
150
+ }
151
+ else {
152
+ res.status(404).json({ error: "Not found" });
153
+ }
154
+ });
155
+ this.app.get("/health", (req, res) => {
156
+ res.json({ status: "ok", timestamp: Date.now() });
157
+ });
158
+ this.app.get("/.well-known/mindoodb-server-info", (req, res) => {
159
+ const info = this.tenantManager.getServerPublicInfo();
160
+ if (!info) {
161
+ res.status(503).json({ error: "Server identity not initialized" });
162
+ return;
163
+ }
164
+ res.json(info);
165
+ });
166
+ // Static file serving
167
+ if (this.staticDir) {
168
+ const resolvedStaticDir = path_1.default.resolve(this.staticDir);
169
+ this.app.use("/statics", (req, res, next) => {
170
+ if (req.path.includes("..")) {
171
+ res.status(400).json({ error: "Invalid path" });
172
+ return;
173
+ }
174
+ next();
175
+ }, express_1.default.static(resolvedStaticDir, { dotfiles: "deny", etag: true }));
176
+ console.log(`[MindooDBServer] Serving static files from ${resolvedStaticDir} at /statics/`);
177
+ }
178
+ // System admin routes (replaces former /admin/*)
179
+ const systemIpRaw = (0, SystemIpAllowlist_1.readSystemIpAllowListFromEnv)();
180
+ if (!(0, SystemIpAllowlist_1.isSystemIpAllowListDisabled)(systemIpRaw)) {
181
+ console.log(`[MindooDBServer] MINDOODB_ADMIN_ALLOWED_IPS is set — /system/* limited to: ${systemIpRaw}`);
182
+ }
183
+ const systemRateLimit = (0, express_rate_limit_1.default)({
184
+ windowMs: 60000,
185
+ max: 30,
186
+ standardHeaders: true,
187
+ legacyHeaders: false,
188
+ message: { error: "Too many system requests, please try again later" },
189
+ });
190
+ const systemRouter = (0, express_1.Router)();
191
+ this.setupSystemRoutes(systemRouter);
192
+ this.app.use("/system", SystemIpAllowlist_1.systemIpAllowlistMiddleware, systemRateLimit, systemRouter);
193
+ // Tenant-scoped routes
194
+ this.app.use("/:tenantId", this.tenantMiddleware.bind(this), this.createTenantRouter());
195
+ this.app.use(this.errorHandler.bind(this));
196
+ }
197
+ // ==================== System Admin Auth Middleware ====================
198
+ /**
199
+ * JWT-based middleware for /system/* routes (excluding /system/auth/*).
200
+ * Extracts and validates the bearer token, then checks capabilities
201
+ * for the current (method, path, username, publicsignkey).
202
+ */
203
+ async systemAdminMiddleware(req, res, next) {
204
+ const auth = req.headers.authorization;
205
+ if (!auth || !auth.startsWith("Bearer ")) {
206
+ res.status(401).json({ error: "Missing or invalid Authorization header" });
207
+ return;
208
+ }
209
+ const token = auth.substring(7);
210
+ const payload = await this.systemAdminAuth.validateToken(token);
211
+ if (!payload) {
212
+ res.status(401).json({ error: "Invalid or expired token" });
213
+ return;
214
+ }
215
+ // The original request path relative to the /system mount is in req.path,
216
+ // but we need the full path for capability matching.
217
+ const fullPath = `/system${req.path}`;
218
+ const method = req.method.toUpperCase();
219
+ if (!this.capabilityMatcher.isAuthorized(method, fullPath, payload.sub, payload.publicsignkey)) {
220
+ res.status(403).json({ error: "Forbidden: insufficient capabilities" });
221
+ return;
222
+ }
223
+ req.systemAdmin = {
224
+ username: payload.sub,
225
+ publicsignkey: payload.publicsignkey,
226
+ };
227
+ next();
228
+ }
229
+ // ==================== Tenant Middleware ====================
230
+ tenantMiddleware(req, res, next) {
231
+ const rawTenantId = req.params.tenantId?.toLowerCase();
232
+ if (!rawTenantId) {
233
+ res.status(400).json({ error: "Tenant ID required" });
234
+ return;
235
+ }
236
+ try {
237
+ (0, validation_1.validateTenantIdFormat)(rawTenantId);
238
+ }
239
+ catch {
240
+ res.status(400).json({ error: "Invalid tenant ID format" });
241
+ return;
242
+ }
243
+ if (!this.tenantManager.tenantExists(rawTenantId)) {
244
+ res.status(404).json({ error: "Tenant not found" });
245
+ return;
246
+ }
247
+ req.tenantId = rawTenantId;
248
+ next();
249
+ }
250
+ // ==================== System Routes ====================
251
+ setupSystemRoutes(router) {
252
+ // Auth endpoints — no JWT required (these *produce* JWTs)
253
+ const authRateLimit = (0, express_rate_limit_1.default)({
254
+ windowMs: 60000,
255
+ max: 20,
256
+ standardHeaders: true,
257
+ legacyHeaders: false,
258
+ message: { error: "Too many authentication attempts, please try again later" },
259
+ });
260
+ router.post("/auth/challenge", authRateLimit, this.handleSystemChallenge.bind(this));
261
+ router.post("/auth/authenticate", authRateLimit, this.handleSystemAuthenticate.bind(this));
262
+ // All other /system/* routes require JWT + capability check
263
+ const authMiddleware = this.systemAdminMiddleware.bind(this);
264
+ // Tenant CRUD
265
+ router.get("/tenants", authMiddleware, (req, res) => {
266
+ try {
267
+ const tenants = this.tenantManager.listTenants();
268
+ const response = { tenants };
269
+ res.json(response);
270
+ }
271
+ catch (error) {
272
+ console.error("[MindooDBServer] Error listing tenants:", error);
273
+ res.status(500).json({ error: "Failed to list tenants" });
274
+ }
275
+ });
276
+ router.post("/tenants/:tenantId", authMiddleware, (req, res) => {
277
+ try {
278
+ const tenantId = req.params.tenantId.toLowerCase();
279
+ try {
280
+ (0, validation_1.validateTenantId)(tenantId);
281
+ }
282
+ catch (validationError) {
283
+ res.status(400).json({
284
+ error: validationError instanceof validation_1.ValidationError
285
+ ? validationError.message
286
+ : "Invalid tenantId format",
287
+ });
288
+ return;
289
+ }
290
+ const request = {
291
+ ...req.body,
292
+ tenantId,
293
+ };
294
+ if (!request.adminSigningPublicKey) {
295
+ res.status(400).json({ error: "adminSigningPublicKey is required" });
296
+ return;
297
+ }
298
+ if (!request.adminEncryptionPublicKey) {
299
+ res.status(400).json({ error: "adminEncryptionPublicKey is required" });
300
+ return;
301
+ }
302
+ if (request.adminUsername !== undefined) {
303
+ (0, validation_1.validateUsername)(request.adminUsername);
304
+ }
305
+ (0, validation_1.validateStringLength)(request.adminSigningPublicKey, validation_1.MAX_PEM_KEY_LENGTH, "adminSigningPublicKey");
306
+ (0, validation_1.validateStringLength)(request.adminEncryptionPublicKey, validation_1.MAX_PEM_KEY_LENGTH, "adminEncryptionPublicKey");
307
+ if (this.tenantManager.tenantExists(tenantId)) {
308
+ res.status(409).json({ error: `Tenant ${tenantId} already exists` });
309
+ return;
310
+ }
311
+ const context = this.tenantManager.registerTenant(request);
312
+ const response = {
313
+ success: true,
314
+ tenantId: context.tenantId,
315
+ message: `Tenant ${context.tenantId} registered successfully`,
316
+ };
317
+ res.status(201).json(response);
318
+ }
319
+ catch (error) {
320
+ if (error instanceof validation_1.ValidationError) {
321
+ res.status(400).json({ error: error.message });
322
+ return;
323
+ }
324
+ console.error("[MindooDBServer] Error registering tenant:", error);
325
+ res.status(500).json({ error: "Failed to register tenant" });
326
+ }
327
+ });
328
+ router.put("/tenants/:tenantId", authMiddleware, (req, res) => {
329
+ try {
330
+ const tenantId = req.params.tenantId.toLowerCase();
331
+ try {
332
+ (0, validation_1.validateTenantId)(tenantId);
333
+ }
334
+ catch {
335
+ res.status(400).json({ error: "Invalid tenantId format" });
336
+ return;
337
+ }
338
+ if (!this.tenantManager.tenantExists(tenantId)) {
339
+ res.status(404).json({ error: "Tenant not found" });
340
+ return;
341
+ }
342
+ this.tenantManager.updateTenantConfig(tenantId, req.body);
343
+ res.json({ success: true, message: `Tenant ${tenantId} updated` });
344
+ }
345
+ catch (error) {
346
+ if (error instanceof validation_1.ValidationError) {
347
+ res.status(400).json({ error: error.message });
348
+ return;
349
+ }
350
+ console.error("[MindooDBServer] Error updating tenant:", error);
351
+ res.status(500).json({ error: "Failed to update tenant" });
352
+ }
353
+ });
354
+ router.delete("/tenants/:tenantId", authMiddleware, (req, res) => {
355
+ try {
356
+ const tenantId = req.params.tenantId.toLowerCase();
357
+ try {
358
+ (0, validation_1.validateTenantId)(tenantId);
359
+ }
360
+ catch {
361
+ res.status(400).json({ error: "Invalid tenantId format" });
362
+ return;
363
+ }
364
+ if (!this.tenantManager.tenantExists(tenantId)) {
365
+ res.status(404).json({ error: "Tenant not found" });
366
+ return;
367
+ }
368
+ this.tenantManager.removeTenant(tenantId);
369
+ res.json({ success: true, message: `Tenant ${tenantId} removed` });
370
+ }
371
+ catch (error) {
372
+ console.error("[MindooDBServer] Error removing tenant:", error);
373
+ res.status(500).json({ error: "Failed to remove tenant" });
374
+ }
375
+ });
376
+ // Trusted server management
377
+ router.get("/trusted-servers", authMiddleware, (req, res) => {
378
+ try {
379
+ res.json({ servers: this.tenantManager.listTrustedServers() });
380
+ }
381
+ catch (error) {
382
+ console.error("[MindooDBServer] Error listing trusted servers:", error);
383
+ res.status(500).json({ error: "Failed to list trusted servers" });
384
+ }
385
+ });
386
+ router.post("/trusted-servers", authMiddleware, (req, res) => {
387
+ try {
388
+ const { name, signingPublicKey, encryptionPublicKey } = req.body;
389
+ if (!name || !signingPublicKey || !encryptionPublicKey) {
390
+ res.status(400).json({ error: "name, signingPublicKey, and encryptionPublicKey are required" });
391
+ return;
392
+ }
393
+ (0, validation_1.validateStringLength)(name, 256, "name");
394
+ (0, validation_1.validateStringLength)(signingPublicKey, validation_1.MAX_PEM_KEY_LENGTH, "signingPublicKey");
395
+ (0, validation_1.validateStringLength)(encryptionPublicKey, validation_1.MAX_PEM_KEY_LENGTH, "encryptionPublicKey");
396
+ const server = { name, signingPublicKey, encryptionPublicKey };
397
+ this.tenantManager.addTrustedServer(server);
398
+ res.status(201).json({ success: true, message: `Trusted server "${name}" added` });
399
+ }
400
+ catch (error) {
401
+ if (error instanceof validation_1.ValidationError) {
402
+ res.status(400).json({ error: error.message });
403
+ return;
404
+ }
405
+ if (error instanceof Error && error.message.includes("already exists")) {
406
+ res.status(409).json({ error: error.message });
407
+ return;
408
+ }
409
+ console.error("[MindooDBServer] Error adding trusted server:", error);
410
+ res.status(500).json({ error: "Failed to add trusted server" });
411
+ }
412
+ });
413
+ router.delete("/trusted-servers/:serverName", authMiddleware, (req, res) => {
414
+ try {
415
+ const serverName = req.params.serverName;
416
+ (0, validation_1.validateStringLength)(serverName, 256, "serverName");
417
+ const removed = this.tenantManager.removeTrustedServer(serverName);
418
+ if (!removed) {
419
+ res.status(404).json({ error: "Trusted server not found" });
420
+ return;
421
+ }
422
+ res.json({ success: true, message: `Trusted server "${serverName}" removed` });
423
+ }
424
+ catch (error) {
425
+ if (error instanceof validation_1.ValidationError) {
426
+ res.status(400).json({ error: error.message });
427
+ return;
428
+ }
429
+ console.error("[MindooDBServer] Error removing trusted server:", error);
430
+ res.status(500).json({ error: "Failed to remove trusted server" });
431
+ }
432
+ });
433
+ // Per-tenant sync server management
434
+ router.get("/tenants/:tenantId/sync-servers", authMiddleware, (req, res) => {
435
+ try {
436
+ const tenantId = req.params.tenantId.toLowerCase();
437
+ try {
438
+ (0, validation_1.validateTenantId)(tenantId);
439
+ }
440
+ catch {
441
+ res.status(400).json({ error: "Invalid tenantId format" });
442
+ return;
443
+ }
444
+ if (!this.tenantManager.tenantExists(tenantId)) {
445
+ res.status(404).json({ error: "Tenant not found" });
446
+ return;
447
+ }
448
+ const servers = this.tenantManager.getTenantSyncServers(tenantId);
449
+ res.json({ servers });
450
+ }
451
+ catch (error) {
452
+ console.error("[MindooDBServer] Error listing sync servers:", error);
453
+ res.status(500).json({ error: "Failed to list sync servers" });
454
+ }
455
+ });
456
+ router.post("/tenants/:tenantId/sync-servers", authMiddleware, (req, res) => {
457
+ try {
458
+ const tenantId = req.params.tenantId.toLowerCase();
459
+ try {
460
+ (0, validation_1.validateTenantId)(tenantId);
461
+ }
462
+ catch {
463
+ res.status(400).json({ error: "Invalid tenantId format" });
464
+ return;
465
+ }
466
+ if (!this.tenantManager.tenantExists(tenantId)) {
467
+ res.status(404).json({ error: "Tenant not found" });
468
+ return;
469
+ }
470
+ const { name, url, syncIntervalMs, databases } = req.body;
471
+ if (!name || !url) {
472
+ res.status(400).json({ error: "name and url are required" });
473
+ return;
474
+ }
475
+ if (!databases || !Array.isArray(databases) || databases.length === 0) {
476
+ res.status(400).json({ error: "databases array is required and must not be empty" });
477
+ return;
478
+ }
479
+ (0, validation_1.validateStringLength)(name, 256, "name");
480
+ (0, validation_1.validateStringLength)(url, 2048, "url");
481
+ const config = { name, url, databases };
482
+ if (syncIntervalMs !== undefined) {
483
+ config.syncIntervalMs = syncIntervalMs;
484
+ }
485
+ this.tenantManager.addTenantSyncServer(tenantId, config);
486
+ res.status(201).json({ success: true, message: `Sync server "${name}" configured for tenant ${tenantId}` });
487
+ }
488
+ catch (error) {
489
+ if (error instanceof validation_1.ValidationError) {
490
+ res.status(400).json({ error: error.message });
491
+ return;
492
+ }
493
+ console.error("[MindooDBServer] Error adding sync server:", error);
494
+ res.status(500).json({ error: "Failed to add sync server" });
495
+ }
496
+ });
497
+ router.delete("/tenants/:tenantId/sync-servers/:serverName", authMiddleware, (req, res) => {
498
+ try {
499
+ const tenantId = req.params.tenantId.toLowerCase();
500
+ try {
501
+ (0, validation_1.validateTenantId)(tenantId);
502
+ }
503
+ catch {
504
+ res.status(400).json({ error: "Invalid tenantId format" });
505
+ return;
506
+ }
507
+ if (!this.tenantManager.tenantExists(tenantId)) {
508
+ res.status(404).json({ error: "Tenant not found" });
509
+ return;
510
+ }
511
+ const serverName = decodeURIComponent(req.params.serverName);
512
+ (0, validation_1.validateStringLength)(serverName, 256, "serverName");
513
+ const removed = this.tenantManager.removeTenantSyncServer(tenantId, serverName);
514
+ if (!removed) {
515
+ res.status(404).json({ error: "Sync server not found" });
516
+ return;
517
+ }
518
+ res.json({ success: true, message: `Sync server "${serverName}" removed from tenant ${tenantId}` });
519
+ }
520
+ catch (error) {
521
+ if (error instanceof validation_1.ValidationError) {
522
+ res.status(400).json({ error: error.message });
523
+ return;
524
+ }
525
+ console.error("[MindooDBServer] Error removing sync server:", error);
526
+ res.status(500).json({ error: "Failed to remove sync server" });
527
+ }
528
+ });
529
+ // Per-tenant trigger-sync (moved from /:tenantId/admin/trigger-sync)
530
+ router.post("/tenants/:tenantId/trigger-sync", authMiddleware, this.handleTriggerSync.bind(this));
531
+ // Runtime config management
532
+ router.get("/config/backups", authMiddleware, (req, res) => {
533
+ try {
534
+ res.json({ backups: (0, config_1.listConfigBackups)(this.configPath) });
535
+ }
536
+ catch (error) {
537
+ console.error("[MindooDBServer] Error listing config backups:", error);
538
+ res.status(500).json({ error: "Failed to list config backups" });
539
+ }
540
+ });
541
+ router.get("/config/backups/:backupFile", authMiddleware, (req, res) => {
542
+ try {
543
+ const backupFile = decodeURIComponent(req.params.backupFile);
544
+ if (!(0, config_1.isConfigBackupFilename)(backupFile)) {
545
+ res.status(400).json({ error: "Invalid config backup filename" });
546
+ return;
547
+ }
548
+ const config = (0, config_1.loadConfigBackup)(this.configPath, backupFile);
549
+ res.json({ file: backupFile, config });
550
+ }
551
+ catch (error) {
552
+ if (error instanceof Error && error.message.startsWith("Config backup not found:")) {
553
+ res.status(404).json({ error: "Config backup not found" });
554
+ return;
555
+ }
556
+ if (error instanceof Error && error.message.startsWith("Invalid config backup filename:")) {
557
+ res.status(400).json({ error: "Invalid config backup filename" });
558
+ return;
559
+ }
560
+ console.error("[MindooDBServer] Error reading config backup:", error);
561
+ res.status(500).json({ error: "Failed to read config backup" });
562
+ }
563
+ });
564
+ router.get("/config", authMiddleware, (req, res) => {
565
+ res.json(this.serverConfig);
566
+ });
567
+ router.put("/config", authMiddleware, this.handleUpdateConfig.bind(this));
568
+ }
569
+ // ==================== System Auth Handlers ====================
570
+ async handleSystemChallenge(req, res) {
571
+ try {
572
+ const { username, publicsignkey } = req.body;
573
+ if (!username || typeof username !== "string") {
574
+ res.status(400).json({ error: "username is required" });
575
+ return;
576
+ }
577
+ if (!publicsignkey || typeof publicsignkey !== "string") {
578
+ res.status(400).json({ error: "publicsignkey is required" });
579
+ return;
580
+ }
581
+ (0, validation_1.validateUsername)(username);
582
+ (0, validation_1.validateStringLength)(publicsignkey, validation_1.MAX_PEM_KEY_LENGTH, "publicsignkey");
583
+ const challenge = await this.systemAdminAuth.generateChallenge(username, publicsignkey);
584
+ res.json({ challenge });
585
+ }
586
+ catch (error) {
587
+ if (error instanceof Error && error.message === "Unknown system admin principal") {
588
+ res.status(404).json({ error: "System admin principal not found" });
589
+ return;
590
+ }
591
+ if (error instanceof validation_1.ValidationError) {
592
+ res.status(400).json({ error: error.message });
593
+ return;
594
+ }
595
+ console.error("[MindooDBServer] System challenge error:", error);
596
+ res.status(500).json({ error: "Internal server error" });
597
+ }
598
+ }
599
+ async handleSystemAuthenticate(req, res) {
600
+ try {
601
+ const { challenge, signature } = req.body;
602
+ if (!challenge || !signature) {
603
+ res.status(400).json({ error: "challenge and signature are required" });
604
+ return;
605
+ }
606
+ (0, validation_1.validateStringLength)(challenge, validation_1.MAX_CHALLENGE_LENGTH, "challenge");
607
+ (0, validation_1.validateStringLength)(signature, validation_1.MAX_SIGNATURE_LENGTH, "signature");
608
+ const signatureBytes = this.base64ToUint8Array(signature);
609
+ const result = await this.systemAdminAuth.authenticate(challenge, signatureBytes);
610
+ res.json(result);
611
+ }
612
+ catch (error) {
613
+ if (error instanceof validation_1.ValidationError) {
614
+ res.status(400).json({ error: error.message });
615
+ return;
616
+ }
617
+ console.error("[MindooDBServer] System authenticate error:", error);
618
+ res.status(500).json({ error: "Internal server error" });
619
+ }
620
+ }
621
+ // ==================== Config Update Handler ====================
622
+ async handleUpdateConfig(req, res) {
623
+ try {
624
+ let newConfig;
625
+ try {
626
+ newConfig = (0, config_1.validateServerConfig)(req.body, "request body");
627
+ }
628
+ catch (err) {
629
+ res.status(400).json({
630
+ error: err instanceof Error ? err.message : "Invalid config format",
631
+ });
632
+ return;
633
+ }
634
+ // Self-lockout protection: verify the calling admin retains PUT /system/config access
635
+ const callingAdmin = req.systemAdmin;
636
+ const proposedMatcher = new CapabilityMatcher_1.CapabilityMatcher(newConfig);
637
+ if (!proposedMatcher.isAuthorized("PUT", "/system/config", callingAdmin.username, callingAdmin.publicsignkey)) {
638
+ res.status(400).json({
639
+ error: "This change would remove your own access to PUT /system/config",
640
+ });
641
+ return;
642
+ }
643
+ // Backup the current config before overwriting
644
+ const { existsSync: fsExists } = await import("fs");
645
+ let backupFile = null;
646
+ if (fsExists(this.configPath)) {
647
+ backupFile = (0, config_1.backupConfig)(this.configPath);
648
+ }
649
+ // Persist new config to disk
650
+ (0, config_1.writeConfig)(this.configPath, newConfig);
651
+ // Hot-swap in-memory state
652
+ this.reloadConfig(newConfig);
653
+ console.log(`[MindooDBServer] Config updated by ${callingAdmin.username}` +
654
+ (backupFile ? ` (backup: ${backupFile})` : ""));
655
+ res.json({
656
+ success: true,
657
+ ...(backupFile ? { backupFile } : {}),
658
+ });
659
+ }
660
+ catch (error) {
661
+ console.error("[MindooDBServer] Error updating config:", error);
662
+ res.status(500).json({ error: "Failed to update config" });
663
+ }
664
+ }
665
+ // ==================== Tenant Routes ====================
666
+ createTenantRouter() {
667
+ const router = (0, express_1.Router)({ mergeParams: true });
668
+ // Auth endpoints get stricter rate limiting
669
+ const authRateLimit = (0, express_rate_limit_1.default)({
670
+ windowMs: 60000,
671
+ max: 20,
672
+ standardHeaders: true,
673
+ legacyHeaders: false,
674
+ message: { error: "Too many authentication attempts, please try again later" },
675
+ });
676
+ // Sync endpoints get a higher limit
677
+ const syncRateLimit = (0, express_rate_limit_1.default)({
678
+ windowMs: 60000,
679
+ max: 200,
680
+ standardHeaders: true,
681
+ legacyHeaders: false,
682
+ message: { error: "Too many sync requests, please try again later" },
683
+ });
684
+ router.post("/auth/challenge", authRateLimit, this.handleChallenge.bind(this));
685
+ router.post("/auth/authenticate", authRateLimit, this.handleAuthenticate.bind(this));
686
+ router.post("/sync/findNewEntries", syncRateLimit, this.handleFindNewEntries.bind(this));
687
+ router.post("/sync/findNewEntriesForDoc", syncRateLimit, this.handleFindNewEntriesForDoc.bind(this));
688
+ router.post("/sync/findEntries", syncRateLimit, this.handleFindEntries.bind(this));
689
+ router.post("/sync/scanEntriesSince", syncRateLimit, this.handleScanEntriesSince.bind(this));
690
+ router.post("/sync/getIdBloomSummary", syncRateLimit, this.handleGetIdBloomSummary.bind(this));
691
+ router.post("/sync/getCompactionStatus", syncRateLimit, this.handleGetCompactionStatus.bind(this));
692
+ router.get("/sync/capabilities", syncRateLimit, this.handleGetCapabilities.bind(this));
693
+ router.post("/sync/getEntries", syncRateLimit, this.handleGetEntries.bind(this));
694
+ router.post("/sync/putEntries", syncRateLimit, this.handlePutEntries.bind(this));
695
+ router.post("/sync/hasEntries", syncRateLimit, this.handleHasEntries.bind(this));
696
+ router.get("/sync/getAllIds", syncRateLimit, this.handleGetAllIds.bind(this));
697
+ router.post("/sync/resolveDependencies", syncRateLimit, this.handleResolveDependencies.bind(this));
698
+ router.post("/sync/planDocumentMaterialization", syncRateLimit, this.handlePlanDocumentMaterialization.bind(this));
699
+ router.post("/sync/planDocumentMaterializationBatch", syncRateLimit, this.handlePlanDocumentMaterializationBatch.bind(this));
700
+ return router;
701
+ }
702
+ // ==================== Validation Helpers ====================
703
+ validateDbId(dbId) {
704
+ return (0, validation_1.validateIdentifier)(dbId, "dbId");
705
+ }
706
+ // ==================== Tenant Auth Handlers ====================
707
+ async handleChallenge(req, res) {
708
+ try {
709
+ const { username } = req.body;
710
+ (0, validation_1.validateUsername)(username);
711
+ const authService = await this.tenantManager.getAuthService(req.tenantId);
712
+ const challenge = await authService.generateChallenge(username);
713
+ res.json({ challenge });
714
+ }
715
+ catch (error) {
716
+ this.handleRequestError(error, res);
717
+ }
718
+ }
719
+ async handleAuthenticate(req, res) {
720
+ try {
721
+ const { challenge, signature } = req.body;
722
+ if (!challenge || !signature) {
723
+ res.status(400).json({ error: "challenge and signature are required" });
724
+ return;
725
+ }
726
+ (0, validation_1.validateStringLength)(challenge, validation_1.MAX_CHALLENGE_LENGTH, "challenge");
727
+ (0, validation_1.validateStringLength)(signature, validation_1.MAX_SIGNATURE_LENGTH, "signature");
728
+ const authService = await this.tenantManager.getAuthService(req.tenantId);
729
+ const signatureBytes = this.base64ToUint8Array(signature);
730
+ const result = await authService.authenticate(challenge, signatureBytes);
731
+ res.json(result);
732
+ }
733
+ catch (error) {
734
+ this.handleRequestError(error, res);
735
+ }
736
+ }
737
+ // ==================== Sync Handlers ====================
738
+ async handleFindNewEntries(req, res) {
739
+ try {
740
+ const token = this.extractToken(req);
741
+ const { dbId, haveIds } = req.body;
742
+ const validDbId = this.validateDbId(dbId);
743
+ (0, validation_1.validateArraySize)(haveIds, validation_1.MAX_HAVE_IDS, "haveIds");
744
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
745
+ const entries = await serverStore.handleFindNewEntries(token, haveIds || []);
746
+ res.json({
747
+ entries: entries.map((e) => this.serializeEntryMetadata(e)),
748
+ });
749
+ }
750
+ catch (error) {
751
+ this.handleRequestError(error, res);
752
+ }
753
+ }
754
+ async handleFindNewEntriesForDoc(req, res) {
755
+ try {
756
+ const token = this.extractToken(req);
757
+ const { dbId, haveIds, docId } = req.body;
758
+ const validDbId = this.validateDbId(dbId);
759
+ if (!docId) {
760
+ res.status(400).json({ error: "docId is required" });
761
+ return;
762
+ }
763
+ (0, validation_1.validateArraySize)(haveIds, validation_1.MAX_HAVE_IDS, "haveIds");
764
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
765
+ const entries = await serverStore.handleFindNewEntriesForDoc(token, haveIds || [], docId);
766
+ res.json({
767
+ entries: entries.map((e) => this.serializeEntryMetadata(e)),
768
+ });
769
+ }
770
+ catch (error) {
771
+ this.handleRequestError(error, res);
772
+ }
773
+ }
774
+ async handleFindEntries(req, res) {
775
+ try {
776
+ const token = this.extractToken(req);
777
+ const { dbId, type, creationDateFrom, creationDateUntil } = req.body;
778
+ const validDbId = this.validateDbId(dbId);
779
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
780
+ const entries = await serverStore.handleFindEntries(token, type, creationDateFrom ?? null, creationDateUntil ?? null);
781
+ res.json({
782
+ entries: entries.map((e) => this.serializeEntryMetadata(e)),
783
+ });
784
+ }
785
+ catch (error) {
786
+ this.handleRequestError(error, res);
787
+ }
788
+ }
789
+ async handleScanEntriesSince(req, res) {
790
+ try {
791
+ const token = this.extractToken(req);
792
+ const { dbId, cursor, limit, filters } = req.body;
793
+ const validDbId = this.validateDbId(dbId);
794
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
795
+ const result = await serverStore.handleScanEntriesSince(token, cursor ?? null, limit, filters);
796
+ res.json({
797
+ entries: result.entries.map((e) => this.serializeEntryMetadata(e)),
798
+ nextCursor: result.nextCursor,
799
+ hasMore: result.hasMore,
800
+ });
801
+ }
802
+ catch (error) {
803
+ this.handleRequestError(error, res);
804
+ }
805
+ }
806
+ async handleGetIdBloomSummary(req, res) {
807
+ try {
808
+ const token = this.extractToken(req);
809
+ const { dbId } = req.body;
810
+ const validDbId = this.validateDbId(dbId);
811
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
812
+ const summary = await serverStore.handleGetIdBloomSummary(token);
813
+ res.json({ summary: summary });
814
+ }
815
+ catch (error) {
816
+ this.handleRequestError(error, res);
817
+ }
818
+ }
819
+ async handleGetCapabilities(req, res) {
820
+ try {
821
+ const token = this.extractToken(req);
822
+ const rawDbId = req.query.dbId || "directory";
823
+ const validDbId = this.validateDbId(rawDbId);
824
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
825
+ const capabilities = await serverStore.handleGetCapabilities(token);
826
+ res.json({ capabilities: capabilities });
827
+ }
828
+ catch (error) {
829
+ this.handleRequestError(error, res);
830
+ }
831
+ }
832
+ async handleGetCompactionStatus(req, res) {
833
+ try {
834
+ const token = this.extractToken(req);
835
+ const { dbId } = req.body;
836
+ const validDbId = this.validateDbId(dbId);
837
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
838
+ const status = await serverStore.handleGetCompactionStatus(token);
839
+ res.json({ status: status });
840
+ }
841
+ catch (error) {
842
+ this.handleRequestError(error, res);
843
+ }
844
+ }
845
+ async handleGetEntries(req, res) {
846
+ try {
847
+ const token = this.extractToken(req);
848
+ const { dbId, ids } = req.body;
849
+ const validDbId = this.validateDbId(dbId);
850
+ (0, validation_1.validateArraySize)(ids, validation_1.MAX_ENTRY_IDS, "ids");
851
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
852
+ const entries = await serverStore.handleGetEntries(token, ids || []);
853
+ res.json({
854
+ entries: entries.map((e) => ({
855
+ ...this.serializeEntryMetadata(e),
856
+ rsaEncryptedPayload: this.uint8ArrayToBase64(e.rsaEncryptedPayload),
857
+ })),
858
+ });
859
+ }
860
+ catch (error) {
861
+ this.handleRequestError(error, res);
862
+ }
863
+ }
864
+ async handlePutEntries(req, res) {
865
+ try {
866
+ const token = this.extractToken(req);
867
+ const { dbId, entries } = req.body;
868
+ const validDbId = this.validateDbId(dbId);
869
+ (0, validation_1.validateArraySize)(entries, validation_1.MAX_PUT_ENTRIES, "entries");
870
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
871
+ const deserializedEntries = (entries || []).map((e) => this.deserializeEntry(e));
872
+ await serverStore.handlePutEntries(token, deserializedEntries);
873
+ res.json({ success: true });
874
+ }
875
+ catch (error) {
876
+ this.handleRequestError(error, res);
877
+ }
878
+ }
879
+ async handleHasEntries(req, res) {
880
+ try {
881
+ const token = this.extractToken(req);
882
+ const { dbId, ids } = req.body;
883
+ const validDbId = this.validateDbId(dbId);
884
+ (0, validation_1.validateArraySize)(ids, validation_1.MAX_ENTRY_IDS, "ids");
885
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
886
+ const existingIds = await serverStore.handleHasEntries(token, ids || []);
887
+ res.json({ ids: existingIds });
888
+ }
889
+ catch (error) {
890
+ this.handleRequestError(error, res);
891
+ }
892
+ }
893
+ async handleGetAllIds(req, res) {
894
+ try {
895
+ const token = this.extractToken(req);
896
+ const rawDbId = req.query.dbId || "directory";
897
+ const validDbId = this.validateDbId(rawDbId);
898
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
899
+ const ids = await serverStore.handleGetAllIds(token);
900
+ res.json({ ids });
901
+ }
902
+ catch (error) {
903
+ this.handleRequestError(error, res);
904
+ }
905
+ }
906
+ async handleResolveDependencies(req, res) {
907
+ try {
908
+ const token = this.extractToken(req);
909
+ const { dbId, startId, options } = req.body;
910
+ const validDbId = this.validateDbId(dbId);
911
+ if (!startId) {
912
+ res.status(400).json({ error: "startId is required" });
913
+ return;
914
+ }
915
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
916
+ const ids = await serverStore.handleResolveDependencies(token, startId, options);
917
+ res.json({ ids });
918
+ }
919
+ catch (error) {
920
+ this.handleRequestError(error, res);
921
+ }
922
+ }
923
+ async handlePlanDocumentMaterialization(req, res) {
924
+ try {
925
+ const token = this.extractToken(req);
926
+ const { dbId, docId, options } = req.body;
927
+ const validDbId = this.validateDbId(dbId);
928
+ if (!docId) {
929
+ res.status(400).json({ error: "docId is required" });
930
+ return;
931
+ }
932
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
933
+ const plan = await serverStore.handlePlanDocumentMaterialization(token, docId, options);
934
+ res.json({ plan: plan });
935
+ }
936
+ catch (error) {
937
+ this.handleRequestError(error, res);
938
+ }
939
+ }
940
+ async handlePlanDocumentMaterializationBatch(req, res) {
941
+ try {
942
+ const token = this.extractToken(req);
943
+ const { dbId, docIds, options } = req.body;
944
+ const validDbId = this.validateDbId(dbId);
945
+ (0, validation_1.validateArraySize)(docIds, validation_1.MAX_HAVE_IDS, "docIds");
946
+ const serverStore = await this.tenantManager.getServerStore(req.tenantId, validDbId);
947
+ const batchPlan = await serverStore.handlePlanDocumentMaterializationBatch(token, docIds || [], options);
948
+ res.json({ batchPlan: batchPlan });
949
+ }
950
+ catch (error) {
951
+ this.handleRequestError(error, res);
952
+ }
953
+ }
954
+ // ==================== Management Handlers ====================
955
+ async handleTriggerSync(req, res) {
956
+ res.json({ success: true, message: "Sync triggered (not yet implemented)" });
957
+ }
958
+ // ==================== Helper Methods ====================
959
+ extractToken(req) {
960
+ const auth = req.headers.authorization;
961
+ if (!auth || !auth.startsWith("Bearer ")) {
962
+ throw new types_1.NetworkError("INVALID_TOKEN", "Missing or invalid Authorization header");
963
+ }
964
+ return auth.substring(7);
965
+ }
966
+ handleRequestError(error, res) {
967
+ if (error instanceof validation_1.ValidationError) {
968
+ res.status(400).json({ error: error.message });
969
+ return;
970
+ }
971
+ if (error instanceof Error && error.name === "NetworkError") {
972
+ const networkError = error;
973
+ const status = this.getStatusForErrorType(networkError.type);
974
+ res.status(status).json({ error: networkError.message });
975
+ return;
976
+ }
977
+ console.error("[MindooDBServer] Request error:", error);
978
+ res.status(500).json({ error: "Internal server error" });
979
+ }
980
+ getStatusForErrorType(type) {
981
+ switch (type) {
982
+ case "INVALID_TOKEN":
983
+ return 401;
984
+ case "USER_REVOKED":
985
+ return 403;
986
+ case "USER_NOT_FOUND":
987
+ return 404;
988
+ case "INVALID_SIGNATURE":
989
+ return 403;
990
+ case "CHALLENGE_EXPIRED":
991
+ return 401;
992
+ default:
993
+ return 500;
994
+ }
995
+ }
996
+ errorHandler(err, req, res, next) {
997
+ console.error("[MindooDBServer] Unhandled error:", err);
998
+ res.status(500).json({ error: "Internal server error" });
999
+ }
1000
+ // ==================== Serialization ====================
1001
+ serializeEntryMetadata(metadata) {
1002
+ return {
1003
+ entryType: metadata.entryType,
1004
+ id: metadata.id,
1005
+ contentHash: metadata.contentHash,
1006
+ docId: metadata.docId,
1007
+ dependencyIds: metadata.dependencyIds,
1008
+ createdAt: metadata.createdAt,
1009
+ createdByPublicKey: metadata.createdByPublicKey,
1010
+ decryptionKeyId: metadata.decryptionKeyId,
1011
+ signature: this.uint8ArrayToBase64(metadata.signature),
1012
+ originalSize: metadata.originalSize,
1013
+ encryptedSize: metadata.encryptedSize,
1014
+ };
1015
+ }
1016
+ deserializeEntry(serialized) {
1017
+ return {
1018
+ entryType: serialized.entryType,
1019
+ id: serialized.id,
1020
+ contentHash: serialized.contentHash,
1021
+ docId: serialized.docId,
1022
+ dependencyIds: serialized.dependencyIds,
1023
+ createdAt: serialized.createdAt,
1024
+ createdByPublicKey: serialized.createdByPublicKey,
1025
+ decryptionKeyId: serialized.decryptionKeyId,
1026
+ signature: this.base64ToUint8Array(serialized.signature),
1027
+ originalSize: serialized.originalSize,
1028
+ encryptedSize: serialized.encryptedSize,
1029
+ encryptedData: this.base64ToUint8Array(serialized.encryptedData),
1030
+ };
1031
+ }
1032
+ uint8ArrayToBase64(bytes) {
1033
+ return Buffer.from(bytes).toString("base64");
1034
+ }
1035
+ base64ToUint8Array(base64) {
1036
+ return new Uint8Array(Buffer.from(base64, "base64"));
1037
+ }
1038
+ }
1039
+ exports.MindooDBServer = MindooDBServer;
1040
+ //# sourceMappingURL=MindooDBServer.js.map