@joystick.js/db-canary 0.0.0-canary.2209

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 (354) hide show
  1. package/.build/getFilesToBuild.js +26 -0
  2. package/.build/getPlatformSafeFilePath.js +6 -0
  3. package/.build/getPlatformSafePath.js +6 -0
  4. package/.build/index.js +88 -0
  5. package/.build/isWindows.js +3 -0
  6. package/API_KEY +1 -0
  7. package/README.md +1821 -0
  8. package/data/data.mdb +0 -0
  9. package/data/lock.mdb +0 -0
  10. package/dist/client/database.js +1 -0
  11. package/dist/client/index.js +1 -0
  12. package/dist/server/cluster/index.js +1 -0
  13. package/dist/server/cluster/master.js +20 -0
  14. package/dist/server/cluster/worker.js +1 -0
  15. package/dist/server/index.js +1 -0
  16. package/dist/server/lib/api_key_manager.js +9 -0
  17. package/dist/server/lib/auth_manager.js +1 -0
  18. package/dist/server/lib/auto_index_manager.js +1 -0
  19. package/dist/server/lib/backup_manager.js +1 -0
  20. package/dist/server/lib/connection_manager.js +1 -0
  21. package/dist/server/lib/disk_utils.js +2 -0
  22. package/dist/server/lib/http_server.js +405 -0
  23. package/dist/server/lib/index_manager.js +1 -0
  24. package/dist/server/lib/load_settings.js +1 -0
  25. package/dist/server/lib/logger.js +1 -0
  26. package/dist/server/lib/op_types.js +1 -0
  27. package/dist/server/lib/operation_dispatcher.js +1 -0
  28. package/dist/server/lib/operations/admin.js +1 -0
  29. package/dist/server/lib/operations/bulk_write.js +1 -0
  30. package/dist/server/lib/operations/create_index.js +1 -0
  31. package/dist/server/lib/operations/delete_one.js +1 -0
  32. package/dist/server/lib/operations/drop_index.js +1 -0
  33. package/dist/server/lib/operations/find.js +1 -0
  34. package/dist/server/lib/operations/find_one.js +1 -0
  35. package/dist/server/lib/operations/get_indexes.js +1 -0
  36. package/dist/server/lib/operations/insert_one.js +1 -0
  37. package/dist/server/lib/operations/update_one.js +1 -0
  38. package/dist/server/lib/performance_monitor.js +1 -0
  39. package/dist/server/lib/query_engine.js +1 -0
  40. package/dist/server/lib/recovery_manager.js +1 -0
  41. package/dist/server/lib/replication_manager.js +1 -0
  42. package/dist/server/lib/safe_json_parse.js +1 -0
  43. package/dist/server/lib/send_response.js +1 -0
  44. package/dist/server/lib/tcp_protocol.js +1 -0
  45. package/dist/server/lib/write_forwarder.js +1 -0
  46. package/dist/server/lib/write_queue.js +1 -0
  47. package/increment_version.js +3 -0
  48. package/logs/.013e15b54597d05db4b4b53ecc37b10c92a72927-audit.json +20 -0
  49. package/logs/.02de550a67ea0f5961faa2dfd458a4d06f59ebd1-audit.json +20 -0
  50. package/logs/.03494ba24eb3c72214b4068a77d54b8993bee651-audit.json +20 -0
  51. package/logs/.06309ec60b339be1259a7993dd09c732f8907fbc-audit.json +20 -0
  52. package/logs/.0663a04dcfa17285661e5e1b8cfa51f41523b210-audit.json +20 -0
  53. package/logs/.0f06e6c4c9b824622729e13927587479e5060391-audit.json +20 -0
  54. package/logs/.16ccf58682ecb22b3e3ec63f0da1b7fe9be56528-audit.json +20 -0
  55. package/logs/.1fa1a5d02f496474b1ab473524c65c984146a9ad-audit.json +20 -0
  56. package/logs/.2223c0ae3bea6f0d62c62b1d319cc8634856abb7-audit.json +20 -0
  57. package/logs/.23dc79ffda3e083665e6f5993f59397adcbf4a46-audit.json +20 -0
  58. package/logs/.28104f49b03906b189eefd1cd462cb46c3c0af22-audit.json +20 -0
  59. package/logs/.29cdbf13808abe6a0ce70ee2f2efdd680ce3fd8e-audit.json +20 -0
  60. package/logs/.2a9889afd071f77f41f5170d08703a0afca866b7-audit.json +20 -0
  61. package/logs/.2acec3d1940a2bbed487528b703ee5948959a599-audit.json +20 -0
  62. package/logs/.2fb60ff326338c02bfedbcd0e936444e4a216750-audit.json +20 -0
  63. package/logs/.318fc7a19530d76a345f030f7cad00dda15300e7-audit.json +20 -0
  64. package/logs/.3cf27043e19085f908cedc7701e6d013463208ee-audit.json +25 -0
  65. package/logs/.3d90d785415817fc443402843b7c95f8371adc9b-audit.json +20 -0
  66. package/logs/.4074bca620375f72966fc52dfd439577727671e5-audit.json +20 -0
  67. package/logs/.40eecf018417ea80a70ea8ec7a3cc9406bc6334b-audit.json +20 -0
  68. package/logs/.50e974f1ef7c365fca6a1251b2e2c2252914cb5e-audit.json +20 -0
  69. package/logs/.52cb7d9e4223cf26ba36006ac26b949a97c7923c-audit.json +20 -0
  70. package/logs/.54befcdb84c15aad980705a31bcc9f555c3577ab-audit.json +20 -0
  71. package/logs/.57dfb70e22eddb84db2e3c0ceeefac5c0b9baffa-audit.json +20 -0
  72. package/logs/.5f0b24705a1eaad4eca4968f2d86f91b3f9be683-audit.json +20 -0
  73. package/logs/.61ba98fdda7db58576b382fee07904e5db1169d6-audit.json +20 -0
  74. package/logs/.6235017727ef6b199d569a99d6aa8c8e80a1b475-audit.json +20 -0
  75. package/logs/.63db16193699219489d218a1ddea5dde3750cae4-audit.json +20 -0
  76. package/logs/.64fb67dfe14149c9eef728d79bf30a54da809c60-audit.json +20 -0
  77. package/logs/.669137453368987c1f311b5345342527afb54e50-audit.json +20 -0
  78. package/logs/.7a71f8c89ea28ae266d356aeff6306e876a30fbb-audit.json +20 -0
  79. package/logs/.7afbaa90fe9dc3a7d682676f9bb79f9a1b1fd9a6-audit.json +20 -0
  80. package/logs/.7ca29e322cd05327035de850099e7610864f2347-audit.json +20 -0
  81. package/logs/.83335ab3347e449dae03455a110aaf7f120d4802-audit.json +20 -0
  82. package/logs/.8c2487b5fd445d2c8e5c483c80b9fa99bbf1ca58-audit.json +20 -0
  83. package/logs/.8c8b9dc386922c9f3b4c13251af7052aac1d24c0-audit.json +20 -0
  84. package/logs/.8d6155d94640c4863301ae0fee5e4e7372a21446-audit.json +20 -0
  85. package/logs/.944a3119a243deea7c8270d5d9e582bb1d0eaa10-audit.json +20 -0
  86. package/logs/.9816a845c30fb2909f3b26a23eeb3538ebcad5db-audit.json +20 -0
  87. package/logs/.9dc08784e38b865488177c26d4af5934555e0323-audit.json +20 -0
  88. package/logs/.9dd27d2e0e454ac0a37600206d1cac5493b0d7ee-audit.json +20 -0
  89. package/logs/.a3d486feeac7654c59b547de96600e8849a06d4f-audit.json +20 -0
  90. package/logs/.a5b811f4def22250f86cc18870d7c4573625df22-audit.json +20 -0
  91. package/logs/.a61648eb5f830e0b6f508ac35e4f8f629d2ad4c7-audit.json +20 -0
  92. package/logs/.a89016d507045771b4b5a65656944a9c0f1e528b-audit.json +20 -0
  93. package/logs/.a99bee160a1c590be959af46bacc02724803f691-audit.json +20 -0
  94. package/logs/.ada7906d6243fd7da802f03d86c4ae5dd9df6236-audit.json +20 -0
  95. package/logs/.b518339ee942143b6af983af167f5bbb6983b4de-audit.json +20 -0
  96. package/logs/.b51b124b166d53c9519017856ea610d61d65fabe-audit.json +20 -0
  97. package/logs/.b7a6aee19f58e55633d5e4a3709041c47dfff975-audit.json +20 -0
  98. package/logs/.bd7a8a6ba9c55d557a4867ab53f02e3ec2e1553d-audit.json +20 -0
  99. package/logs/.c1435dafe453b169d6392b25065f3cf4ab6fbb21-audit.json +20 -0
  100. package/logs/.c17e1ce043109f77dc2f0e2aa290a9d1ed842c03-audit.json +20 -0
  101. package/logs/.ca62637ce9540e5a38a2fbedb2115febb6ad308a-audit.json +15 -0
  102. package/logs/.ccee67b9c176967f8977071409a41f5cb5cd6ad4-audit.json +20 -0
  103. package/logs/.db24043417ea79a6f14cd947476399e53930b48d-audit.json +20 -0
  104. package/logs/.e0f12acccb57829f5f33712bb2e2607ecd808147-audit.json +20 -0
  105. package/logs/.e9b6cc33d0bbd2e644c4e2bf44d177f850016557-audit.json +20 -0
  106. package/logs/.f15291d434808e3bdca7963ccd2e73893be027e6-audit.json +20 -0
  107. package/logs/.f4bdf9e21ef84f8a3fae3ffb32bbc39275991351-audit.json +15 -0
  108. package/logs/.fbac3aefac1e81b4230df5aa50667cb90d51024f-audit.json +20 -0
  109. package/logs/.fcfd495c0a9169db243f4a4f21878ee02b76413c-audit.json +20 -0
  110. package/logs/admin-2025-09-12.log +580 -0
  111. package/logs/admin-2025-09-15.log +283 -0
  112. package/logs/admin-error-2025-09-12.log +22 -0
  113. package/logs/admin-error-2025-09-15.log +10 -0
  114. package/logs/api_key_manager-2025-09-12.log +658 -0
  115. package/logs/api_key_manager-2025-09-15.log +295 -0
  116. package/logs/api_key_manager-error-2025-09-12.log +0 -0
  117. package/logs/api_key_manager-error-2025-09-15.log +0 -0
  118. package/logs/auth_manager-2025-09-12.log +4432 -0
  119. package/logs/auth_manager-2025-09-15.log +2000 -0
  120. package/logs/auth_manager-error-2025-09-12.log +11 -0
  121. package/logs/auth_manager-error-2025-09-15.log +5 -0
  122. package/logs/auto_index_manager-2025-09-12.log +84 -0
  123. package/logs/auto_index_manager-2025-09-15.log +45 -0
  124. package/logs/auto_index_manager-error-2025-09-12.log +6 -0
  125. package/logs/auto_index_manager-error-2025-09-15.log +0 -0
  126. package/logs/backup_manager-2025-09-12.log +198 -0
  127. package/logs/backup_manager-2025-09-15.log +90 -0
  128. package/logs/backup_manager-error-2025-09-12.log +198 -0
  129. package/logs/backup_manager-error-2025-09-15.log +90 -0
  130. package/logs/bulk_write-2025-09-12.log +66 -0
  131. package/logs/bulk_write-2025-09-15.log +38 -0
  132. package/logs/bulk_write-error-2025-09-12.log +0 -0
  133. package/logs/bulk_write-error-2025-09-15.log +0 -0
  134. package/logs/connection_manager-2025-09-12.log +2412 -0
  135. package/logs/connection_manager-2025-09-15.log +1132 -0
  136. package/logs/connection_manager-error-2025-09-12.log +0 -0
  137. package/logs/connection_manager-error-2025-09-15.log +0 -0
  138. package/logs/create_index-2025-09-12.log +302 -0
  139. package/logs/create_index-2025-09-15.log +158 -0
  140. package/logs/create_index-error-2025-09-12.log +30 -0
  141. package/logs/create_index-error-2025-09-15.log +13 -0
  142. package/logs/delete_one-2025-09-12.log +73 -0
  143. package/logs/delete_one-2025-09-15.log +43 -0
  144. package/logs/delete_one-error-2025-09-12.log +0 -0
  145. package/logs/delete_one-error-2025-09-15.log +0 -0
  146. package/logs/disk_utils-2025-09-12.log +4954 -0
  147. package/logs/disk_utils-2025-09-15.log +2446 -0
  148. package/logs/disk_utils-error-2025-09-12.log +0 -0
  149. package/logs/disk_utils-error-2025-09-15.log +0 -0
  150. package/logs/drop_index-2025-09-12.log +41 -0
  151. package/logs/drop_index-2025-09-15.log +23 -0
  152. package/logs/drop_index-error-2025-09-12.log +11 -0
  153. package/logs/drop_index-error-2025-09-15.log +5 -0
  154. package/logs/find-2025-09-12.log +1050 -0
  155. package/logs/find-2025-09-15.log +592 -0
  156. package/logs/find-error-2025-09-12.log +1 -0
  157. package/logs/find-error-2025-09-15.log +0 -0
  158. package/logs/find_one-2025-09-12.log +425 -0
  159. package/logs/find_one-2025-09-15.log +264 -0
  160. package/logs/find_one-error-2025-09-12.log +5 -0
  161. package/logs/find_one-error-2025-09-15.log +0 -0
  162. package/logs/get_indexes-2025-09-12.log +84 -0
  163. package/logs/get_indexes-2025-09-15.log +56 -0
  164. package/logs/get_indexes-error-2025-09-12.log +6 -0
  165. package/logs/get_indexes-error-2025-09-15.log +0 -0
  166. package/logs/http_server-2025-09-12.log +2772 -0
  167. package/logs/http_server-2025-09-15.log +1276 -0
  168. package/logs/http_server-error-2025-09-12.log +212 -0
  169. package/logs/http_server-error-2025-09-15.log +44 -0
  170. package/logs/index_manager-2025-09-12.log +5031 -0
  171. package/logs/index_manager-2025-09-15.log +2909 -0
  172. package/logs/index_manager-error-2025-09-12.log +80 -0
  173. package/logs/index_manager-error-2025-09-15.log +38 -0
  174. package/logs/insert_one-2025-09-12.log +2181 -0
  175. package/logs/insert_one-2025-09-15.log +1293 -0
  176. package/logs/insert_one-error-2025-09-12.log +0 -0
  177. package/logs/insert_one-error-2025-09-15.log +0 -0
  178. package/logs/master-2025-09-12.log +1882 -0
  179. package/logs/master-2025-09-15.log +910 -0
  180. package/logs/master-error-2025-09-12.log +80 -0
  181. package/logs/master-error-2025-09-15.log +0 -0
  182. package/logs/operation_dispatcher-2025-09-12.log +751 -0
  183. package/logs/operation_dispatcher-2025-09-15.log +359 -0
  184. package/logs/operation_dispatcher-error-2025-09-12.log +33 -0
  185. package/logs/operation_dispatcher-error-2025-09-15.log +11 -0
  186. package/logs/performance_monitor-2025-09-12.log +14889 -0
  187. package/logs/performance_monitor-2025-09-15.log +6803 -0
  188. package/logs/performance_monitor-error-2025-09-12.log +0 -0
  189. package/logs/performance_monitor-error-2025-09-15.log +0 -0
  190. package/logs/query_engine-2025-09-12.log +5310 -0
  191. package/logs/query_engine-2025-09-15.log +2639 -0
  192. package/logs/query_engine-error-2025-09-12.log +0 -0
  193. package/logs/query_engine-error-2025-09-15.log +0 -0
  194. package/logs/recovery_manager-2025-09-12.log +462 -0
  195. package/logs/recovery_manager-2025-09-15.log +210 -0
  196. package/logs/recovery_manager-error-2025-09-12.log +22 -0
  197. package/logs/recovery_manager-error-2025-09-15.log +10 -0
  198. package/logs/replication-2025-09-12.log +1923 -0
  199. package/logs/replication-2025-09-15.log +917 -0
  200. package/logs/replication-error-2025-09-12.log +33 -0
  201. package/logs/replication-error-2025-09-15.log +15 -0
  202. package/logs/server-2025-09-12.log +2601 -0
  203. package/logs/server-2025-09-15.log +1191 -0
  204. package/logs/server-error-2025-09-12.log +0 -0
  205. package/logs/server-error-2025-09-15.log +0 -0
  206. package/logs/tcp_protocol-2025-09-12.log +22 -0
  207. package/logs/tcp_protocol-2025-09-15.log +10 -0
  208. package/logs/tcp_protocol-error-2025-09-12.log +22 -0
  209. package/logs/tcp_protocol-error-2025-09-15.log +10 -0
  210. package/logs/test-2025-09-12.log +0 -0
  211. package/logs/test-2025-09-15.log +0 -0
  212. package/logs/test-error-2025-09-12.log +0 -0
  213. package/logs/test-error-2025-09-15.log +0 -0
  214. package/logs/update_one-2025-09-12.log +173 -0
  215. package/logs/update_one-2025-09-15.log +118 -0
  216. package/logs/update_one-error-2025-09-12.log +0 -0
  217. package/logs/update_one-error-2025-09-15.log +0 -0
  218. package/logs/worker-2025-09-12.log +1457 -0
  219. package/logs/worker-2025-09-15.log +695 -0
  220. package/logs/worker-error-2025-09-12.log +0 -0
  221. package/logs/worker-error-2025-09-15.log +0 -0
  222. package/logs/write_forwarder-2025-09-12.log +1956 -0
  223. package/logs/write_forwarder-2025-09-15.log +932 -0
  224. package/logs/write_forwarder-error-2025-09-12.log +66 -0
  225. package/logs/write_forwarder-error-2025-09-15.log +30 -0
  226. package/logs/write_queue-2025-09-12.log +612 -0
  227. package/logs/write_queue-2025-09-15.log +301 -0
  228. package/logs/write_queue-error-2025-09-12.log +184 -0
  229. package/logs/write_queue-error-2025-09-15.log +83 -0
  230. package/package.json +48 -0
  231. package/prompts/01-core-infrastructure.md +56 -0
  232. package/prompts/02-secondary-indexing.md +65 -0
  233. package/prompts/03-write-serialization.md +63 -0
  234. package/prompts/04-enhanced-authentication.md +75 -0
  235. package/prompts/05-comprehensive-admin-operations.md +75 -0
  236. package/prompts/06-backup-and-restore-system.md +106 -0
  237. package/prompts/07-production-safety-features.md +107 -0
  238. package/prompts/08-tcp-client-library.md +121 -0
  239. package/prompts/09-api-method-chaining.md +134 -0
  240. package/prompts/10-automatic-index-creation.md +223 -0
  241. package/prompts/11-operation-naming-consistency.md +268 -0
  242. package/prompts/12-tcp-replication-system.md +333 -0
  243. package/prompts/13-master-read-write-operations.md +57 -0
  244. package/prompts/14-index-upsert-operations.md +68 -0
  245. package/prompts/15-client-api-return-types.md +81 -0
  246. package/prompts/16-server-setup-ui.md +97 -0
  247. package/prompts/17-emergency-password-change.md +108 -0
  248. package/prompts/18-joystick-framework-integration.md +116 -0
  249. package/prompts/19-api-key-authentication-system.md +137 -0
  250. package/prompts/20-configurable-server-port.md +105 -0
  251. package/prompts/21-multi-database-support.md +161 -0
  252. package/prompts/FULL_TEXT_SEARCH.md +293 -0
  253. package/prompts/PROMPTS.md +158 -0
  254. package/prompts/README.md +221 -0
  255. package/prompts/TYPESCRIPT_GENERATION.md +179 -0
  256. package/src/client/database.js +166 -0
  257. package/src/client/index.js +752 -0
  258. package/src/server/cluster/index.js +53 -0
  259. package/src/server/cluster/master.js +774 -0
  260. package/src/server/cluster/worker.js +537 -0
  261. package/src/server/index.js +540 -0
  262. package/src/server/lib/api_key_manager.js +473 -0
  263. package/src/server/lib/auth_manager.js +375 -0
  264. package/src/server/lib/auto_index_manager.js +681 -0
  265. package/src/server/lib/backup_manager.js +650 -0
  266. package/src/server/lib/connection_manager.js +218 -0
  267. package/src/server/lib/disk_utils.js +118 -0
  268. package/src/server/lib/http_server.js +1165 -0
  269. package/src/server/lib/index_manager.js +756 -0
  270. package/src/server/lib/load_settings.js +143 -0
  271. package/src/server/lib/logger.js +135 -0
  272. package/src/server/lib/op_types.js +29 -0
  273. package/src/server/lib/operation_dispatcher.js +268 -0
  274. package/src/server/lib/operations/admin.js +808 -0
  275. package/src/server/lib/operations/bulk_write.js +367 -0
  276. package/src/server/lib/operations/create_index.js +68 -0
  277. package/src/server/lib/operations/delete_one.js +114 -0
  278. package/src/server/lib/operations/drop_index.js +58 -0
  279. package/src/server/lib/operations/find.js +340 -0
  280. package/src/server/lib/operations/find_one.js +319 -0
  281. package/src/server/lib/operations/get_indexes.js +52 -0
  282. package/src/server/lib/operations/insert_one.js +113 -0
  283. package/src/server/lib/operations/update_one.js +225 -0
  284. package/src/server/lib/performance_monitor.js +313 -0
  285. package/src/server/lib/query_engine.js +243 -0
  286. package/src/server/lib/recovery_manager.js +388 -0
  287. package/src/server/lib/replication_manager.js +727 -0
  288. package/src/server/lib/safe_json_parse.js +21 -0
  289. package/src/server/lib/send_response.js +47 -0
  290. package/src/server/lib/tcp_protocol.js +130 -0
  291. package/src/server/lib/write_forwarder.js +636 -0
  292. package/src/server/lib/write_queue.js +335 -0
  293. package/test_data/data.mdb +0 -0
  294. package/test_data/lock.mdb +0 -0
  295. package/tests/client/index.test.js +1232 -0
  296. package/tests/server/cluster/cluster.test.js +248 -0
  297. package/tests/server/cluster/master_read_write_operations.test.js +577 -0
  298. package/tests/server/index.test.js +651 -0
  299. package/tests/server/integration/authentication_integration.test.js +294 -0
  300. package/tests/server/integration/auto_indexing_integration.test.js +268 -0
  301. package/tests/server/integration/backup_integration.test.js +513 -0
  302. package/tests/server/integration/indexing_integration.test.js +126 -0
  303. package/tests/server/integration/production_safety_integration.test.js +358 -0
  304. package/tests/server/integration/replication_integration.test.js +227 -0
  305. package/tests/server/integration/write_serialization_integration.test.js +246 -0
  306. package/tests/server/lib/api_key_manager.test.js +516 -0
  307. package/tests/server/lib/auth_manager.test.js +317 -0
  308. package/tests/server/lib/auto_index_manager.test.js +275 -0
  309. package/tests/server/lib/backup_manager.test.js +238 -0
  310. package/tests/server/lib/connection_manager.test.js +221 -0
  311. package/tests/server/lib/disk_utils.test.js +63 -0
  312. package/tests/server/lib/http_server.test.js +389 -0
  313. package/tests/server/lib/index_manager.test.js +301 -0
  314. package/tests/server/lib/load_settings.test.js +107 -0
  315. package/tests/server/lib/load_settings_port_config.test.js +243 -0
  316. package/tests/server/lib/logger.test.js +282 -0
  317. package/tests/server/lib/operations/admin.test.js +638 -0
  318. package/tests/server/lib/operations/bulk_write.test.js +128 -0
  319. package/tests/server/lib/operations/create_index.test.js +138 -0
  320. package/tests/server/lib/operations/delete_one.test.js +52 -0
  321. package/tests/server/lib/operations/drop_index.test.js +72 -0
  322. package/tests/server/lib/operations/find.test.js +93 -0
  323. package/tests/server/lib/operations/find_one.test.js +91 -0
  324. package/tests/server/lib/operations/get_indexes.test.js +87 -0
  325. package/tests/server/lib/operations/insert_one.test.js +42 -0
  326. package/tests/server/lib/operations/update_one.test.js +89 -0
  327. package/tests/server/lib/performance_monitor.test.js +185 -0
  328. package/tests/server/lib/query_engine.test.js +46 -0
  329. package/tests/server/lib/recovery_manager.test.js +414 -0
  330. package/tests/server/lib/replication_manager.test.js +202 -0
  331. package/tests/server/lib/safe_json_parse.test.js +45 -0
  332. package/tests/server/lib/send_response.test.js +155 -0
  333. package/tests/server/lib/tcp_protocol.test.js +169 -0
  334. package/tests/server/lib/write_forwarder.test.js +258 -0
  335. package/tests/server/lib/write_queue.test.js +255 -0
  336. package/tsconfig.json +30 -0
  337. package/types/client/index.d.ts +447 -0
  338. package/types/server/cluster/index.d.ts +28 -0
  339. package/types/server/cluster/master.d.ts +115 -0
  340. package/types/server/cluster/worker.d.ts +1 -0
  341. package/types/server/lib/auth_manager.d.ts +13 -0
  342. package/types/server/lib/backup_manager.d.ts +43 -0
  343. package/types/server/lib/connection_manager.d.ts +15 -0
  344. package/types/server/lib/disk_utils.d.ts +3 -0
  345. package/types/server/lib/index_manager.d.ts +24 -0
  346. package/types/server/lib/load_settings.d.ts +4 -0
  347. package/types/server/lib/logger.d.ts +44 -0
  348. package/types/server/lib/op_types.d.ts +6 -0
  349. package/types/server/lib/performance_monitor.d.ts +68 -0
  350. package/types/server/lib/query_engine.d.ts +10 -0
  351. package/types/server/lib/safe_json_parse.d.ts +7 -0
  352. package/types/server/lib/send_response.d.ts +3 -0
  353. package/types/server/lib/tcp_protocol.d.ts +12 -0
  354. package/types/server/lib/write_queue.d.ts +2 -0
@@ -0,0 +1,367 @@
1
+ /**
2
+ * @fileoverview Bulk write operations for JoystickDB with transaction support.
3
+ * Provides atomic bulk operations including insert, update, and delete operations
4
+ * with comprehensive error handling, index management, and write queue integration.
5
+ * Supports both snake_case and camelCase operation names for backward compatibility.
6
+ */
7
+
8
+ import { get_database, generate_document_id, build_collection_key } from '../query_engine.js';
9
+ import { get_write_queue } from '../write_queue.js';
10
+ import create_logger from '../logger.js';
11
+
12
+ const { create_context_logger } = create_logger('bulk_write');
13
+
14
+ /**
15
+ * Applies MongoDB-style update operators to a document.
16
+ * Supports $set, $unset, $inc, $push, and $pull operators for document modification.
17
+ * Creates a new document object without mutating the original.
18
+ * @param {Object} document - Original document to update
19
+ * @param {Object} update_operations - Update operations to apply
20
+ * @returns {Object} Updated document with applied operations
21
+ * @throws {Error} When unsupported update operator is used
22
+ */
23
+ const apply_update_operators = (document, update_operations) => {
24
+ const updated_document = { ...document };
25
+
26
+ for (const [operator, operations] of Object.entries(update_operations)) {
27
+ switch (operator) {
28
+ case '$set':
29
+ Object.assign(updated_document, operations);
30
+ break;
31
+
32
+ case '$unset':
33
+ for (const field of Object.keys(operations)) {
34
+ delete updated_document[field];
35
+ }
36
+ break;
37
+
38
+ case '$inc':
39
+ for (const [field, value] of Object.entries(operations)) {
40
+ updated_document[field] = (updated_document[field] || 0) + value;
41
+ }
42
+ break;
43
+
44
+ case '$push':
45
+ for (const [field, value] of Object.entries(operations)) {
46
+ if (!Array.isArray(updated_document[field])) {
47
+ updated_document[field] = [];
48
+ }
49
+ updated_document[field].push(value);
50
+ }
51
+ break;
52
+
53
+ case '$pull':
54
+ for (const [field, value] of Object.entries(operations)) {
55
+ if (Array.isArray(updated_document[field])) {
56
+ updated_document[field] = updated_document[field].filter(item => item !== value);
57
+ }
58
+ }
59
+ break;
60
+
61
+ default:
62
+ throw new Error(`Unsupported update operator: ${operator}`);
63
+ }
64
+ }
65
+
66
+ return updated_document;
67
+ };
68
+
69
+ /**
70
+ * Checks if a document matches the provided filter criteria.
71
+ * Performs exact field matching for all filter properties.
72
+ * Empty or null filters match all documents.
73
+ * @param {Object} document - Document to check against filter
74
+ * @param {Object} filter - Filter criteria for matching
75
+ * @returns {boolean} True if document matches all filter criteria
76
+ */
77
+ const matches_filter = (document, filter) => {
78
+ if (!filter || Object.keys(filter).length === 0) {
79
+ return true;
80
+ }
81
+
82
+ for (const [field, value] of Object.entries(filter)) {
83
+ if (document[field] !== value) {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ return true;
89
+ };
90
+
91
+ /**
92
+ * Processes a single insert operation within a bulk write transaction.
93
+ * Validates document, generates ID if needed, checks for duplicates, and inserts document.
94
+ * Adds creation and update timestamps automatically.
95
+ * @param {Object} db - LMDB database instance
96
+ * @param {string} database_name - Name of the database
97
+ * @param {string} collection_name - Name of the collection
98
+ * @param {Object} operation - Insert operation data
99
+ * @param {Object} operation.document - Document to insert
100
+ * @returns {Object} Insert result with inserted_id
101
+ * @throws {Error} When document is invalid or already exists
102
+ */
103
+ const process_insert_one = (db, database_name, collection_name, operation) => {
104
+ const document_data = operation.document;
105
+
106
+ if (!document_data || typeof document_data !== 'object') {
107
+ throw new Error('insertOne operation requires a valid document');
108
+ }
109
+
110
+ const document_id = document_data._id || generate_document_id();
111
+ const collection_key = build_collection_key(database_name, collection_name, document_id);
112
+
113
+ const existing_document_data = db.get(collection_key);
114
+ if (existing_document_data) {
115
+ throw new Error(`Document with _id ${document_id} already exists`);
116
+ }
117
+
118
+ const document_to_insert = {
119
+ ...document_data,
120
+ _id: document_id,
121
+ _created_at: new Date().toISOString(),
122
+ _updated_at: new Date().toISOString()
123
+ };
124
+
125
+ db.put(collection_key, JSON.stringify(document_to_insert));
126
+
127
+ return {
128
+ inserted_id: document_id
129
+ };
130
+ };
131
+
132
+ /**
133
+ * Processes a single update operation within a bulk write transaction.
134
+ * Finds matching document, applies update operators, and handles upsert if specified.
135
+ * Updates modification timestamp and tracks match/modification counts.
136
+ * @param {Object} db - LMDB database instance
137
+ * @param {string} database_name - Name of the database
138
+ * @param {string} collection_name - Name of the collection
139
+ * @param {Object} operation - Update operation data
140
+ * @param {Object} operation.filter - Filter to find document to update
141
+ * @param {Object} operation.update - Update operations to apply
142
+ * @param {boolean} [operation.upsert=false] - Whether to insert if no match found
143
+ * @returns {Object} Update result with counts and upserted_id if applicable
144
+ * @throws {Error} When filter or update is invalid
145
+ */
146
+ const process_update_one = (db, database_name, collection_name, operation) => {
147
+ const { filter, update, upsert = false } = operation;
148
+
149
+ if (!filter || typeof filter !== 'object') {
150
+ throw new Error('updateOne operation requires a valid filter');
151
+ }
152
+
153
+ if (!update || typeof update !== 'object') {
154
+ throw new Error('updateOne operation requires a valid update');
155
+ }
156
+
157
+ const collection_prefix = `${database_name}:${collection_name}:`;
158
+ let matched_count = 0;
159
+ let modified_count = 0;
160
+ let upserted_id = null;
161
+
162
+ const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
163
+ for (const { key, value: document_data } of range) {
164
+ const document = JSON.parse(document_data);
165
+ if (matches_filter(document, filter)) {
166
+ matched_count = 1;
167
+
168
+ const updated_document = apply_update_operators(document, update);
169
+ updated_document._updated_at = new Date().toISOString();
170
+
171
+ if (JSON.stringify(document) !== JSON.stringify(updated_document)) {
172
+ db.put(key, JSON.stringify(updated_document));
173
+ modified_count = 1;
174
+ }
175
+
176
+ return { matched_count, modified_count };
177
+ }
178
+ }
179
+
180
+ if (upsert) {
181
+ const document_id = generate_document_id();
182
+ const collection_key = build_collection_key(database_name, collection_name, document_id);
183
+
184
+ const new_document = {
185
+ ...filter,
186
+ _id: document_id,
187
+ _created_at: new Date().toISOString(),
188
+ _updated_at: new Date().toISOString()
189
+ };
190
+
191
+ const upserted_document = apply_update_operators(new_document, update);
192
+ db.put(collection_key, JSON.stringify(upserted_document));
193
+
194
+ upserted_id = document_id;
195
+ }
196
+
197
+ return { matched_count, modified_count, upserted_id };
198
+ };
199
+
200
+ /**
201
+ * Processes a single delete operation within a bulk write transaction.
202
+ * Finds first matching document and removes it from the database.
203
+ * Returns count of deleted documents (0 or 1).
204
+ * @param {Object} db - LMDB database instance
205
+ * @param {string} database_name - Name of the database
206
+ * @param {string} collection_name - Name of the collection
207
+ * @param {Object} operation - Delete operation data
208
+ * @param {Object} operation.filter - Filter to find document to delete
209
+ * @returns {Object} Delete result with deleted_count
210
+ * @throws {Error} When filter is invalid
211
+ */
212
+ const process_delete_one = (db, database_name, collection_name, operation) => {
213
+ const { filter } = operation;
214
+
215
+ if (!filter || typeof filter !== 'object') {
216
+ throw new Error('deleteOne operation requires a valid filter');
217
+ }
218
+
219
+ const collection_prefix = `${database_name}:${collection_name}:`;
220
+
221
+ const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
222
+ for (const { key, value: document_data } of range) {
223
+ const document = JSON.parse(document_data);
224
+ if (matches_filter(document, filter)) {
225
+ db.remove(key);
226
+ return { deleted_count: 1 };
227
+ }
228
+ }
229
+
230
+ return { deleted_count: 0 };
231
+ };
232
+
233
+ /**
234
+ * Internal bulk write implementation with transaction support.
235
+ * Processes all operations atomically within a single database transaction.
236
+ * Supports insert_one, update_one, and delete_one operations with both naming conventions.
237
+ * @param {string} database_name - Name of the database to operate on
238
+ * @param {string} collection_name - Name of the collection to operate on
239
+ * @param {Array<Object>} operations - Array of bulk operations to execute
240
+ * @param {Object} [options={}] - Additional options for bulk write
241
+ * @returns {Promise<Object>} Bulk write results with operation counts and IDs
242
+ * @throws {Error} When database name, collection name is missing, operations are invalid, or operation fails
243
+ */
244
+ const bulk_write_internal = async (database_name, collection_name, operations, options = {}) => {
245
+ const log = create_context_logger();
246
+
247
+ if (!database_name) {
248
+ throw new Error('Database name is required');
249
+ }
250
+
251
+ if (!collection_name) {
252
+ throw new Error('Collection name is required');
253
+ }
254
+
255
+ if (!Array.isArray(operations) || operations.length === 0) {
256
+ throw new Error('Operations must be a non-empty array');
257
+ }
258
+
259
+ const db = get_database();
260
+ const results = {
261
+ acknowledged: true,
262
+ inserted_count: 0,
263
+ matched_count: 0,
264
+ modified_count: 0,
265
+ deleted_count: 0,
266
+ upserted_count: 0,
267
+ inserted_ids: {},
268
+ upserted_ids: {}
269
+ };
270
+
271
+ await db.transaction(() => {
272
+ operations.forEach((operation, index) => {
273
+ const operation_type = Object.keys(operation)[0];
274
+ const operation_data = operation[operation_type];
275
+
276
+ // NOTE: Support both snake_case (preferred) and camelCase (backward compatibility).
277
+ switch (operation_type) {
278
+ case 'insert_one':
279
+ case 'insertOne': {
280
+ const result = process_insert_one(db, database_name, collection_name, operation_data);
281
+ results.inserted_count++;
282
+ results.inserted_ids[index] = result.inserted_id;
283
+ break;
284
+ }
285
+
286
+ case 'update_one':
287
+ case 'updateOne': {
288
+ const result = process_update_one(db, database_name, collection_name, operation_data);
289
+ results.matched_count += result.matched_count;
290
+ results.modified_count += result.modified_count;
291
+
292
+ if (result.upserted_id) {
293
+ results.upserted_count++;
294
+ results.upserted_ids[index] = result.upserted_id;
295
+ }
296
+ break;
297
+ }
298
+
299
+ case 'delete_one':
300
+ case 'deleteOne': {
301
+ const result = process_delete_one(db, database_name, collection_name, operation_data);
302
+ results.deleted_count += result.deleted_count;
303
+ break;
304
+ }
305
+
306
+ default:
307
+ throw new Error(`Unsupported bulk operation: ${operation_type}`);
308
+ }
309
+ });
310
+ });
311
+
312
+ log.info('Bulk write operation completed', {
313
+ database: database_name,
314
+ collection: collection_name,
315
+ operations_count: operations.length,
316
+ results
317
+ });
318
+
319
+ return results;
320
+ };
321
+
322
+ /**
323
+ * Executes bulk write operations with write queue serialization.
324
+ * Provides atomic execution of multiple write operations within a single transaction.
325
+ * Enqueues operation through write queue to ensure proper serialization and consistency.
326
+ * @param {string} database_name - Name of the database to operate on
327
+ * @param {string} collection_name - Name of the collection to operate on
328
+ * @param {Array<Object>} operations - Array of bulk operations to execute
329
+ * @param {Object} [options={}] - Additional options for bulk write
330
+ * @returns {Promise<Object>} Bulk write results
331
+ * @returns {boolean} returns.acknowledged - Whether operation was acknowledged
332
+ * @returns {number} returns.inserted_count - Number of documents inserted
333
+ * @returns {number} returns.matched_count - Number of documents matched for updates
334
+ * @returns {number} returns.modified_count - Number of documents actually modified
335
+ * @returns {number} returns.deleted_count - Number of documents deleted
336
+ * @returns {number} returns.upserted_count - Number of documents upserted
337
+ * @returns {Object} returns.inserted_ids - Map of operation index to inserted document ID
338
+ * @returns {Object} returns.upserted_ids - Map of operation index to upserted document ID
339
+ * @throws {Error} When database name, collection name is missing or operations array is invalid
340
+ */
341
+ const bulk_write = async (database_name, collection_name, operations, options = {}) => {
342
+ if (!database_name) {
343
+ throw new Error('Database name is required');
344
+ }
345
+
346
+ if (!collection_name) {
347
+ throw new Error('Collection name is required');
348
+ }
349
+
350
+ if (!Array.isArray(operations) || operations.length === 0) {
351
+ throw new Error('Operations must be a non-empty array');
352
+ }
353
+
354
+ const write_queue = get_write_queue();
355
+
356
+ return await write_queue.enqueue_write_operation(
357
+ () => bulk_write_internal(database_name, collection_name, operations, options),
358
+ {
359
+ operation: 'bulk_write',
360
+ database: database_name,
361
+ collection: collection_name,
362
+ operations_count: operations.length
363
+ }
364
+ );
365
+ };
366
+
367
+ export default bulk_write;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview Create index operation for JoystickDB collections.
3
+ * Provides functionality to create secondary indexes on collection fields with upsert capabilities.
4
+ */
5
+
6
+ import { create_index } from '../index_manager.js';
7
+ import create_logger from '../logger.js';
8
+
9
+ const { create_context_logger } = create_logger('create_index');
10
+
11
+ /**
12
+ * Creates or updates an index on a specified field in a collection.
13
+ * @param {string} database_name - Name of the database
14
+ * @param {string} collection_name - Name of the collection to create index for
15
+ * @param {string} field_name - Name of the field to index
16
+ * @param {Object} [options={}] - Index creation options
17
+ * @param {boolean} [options.unique] - Whether the index should enforce uniqueness
18
+ * @param {boolean} [options.sparse] - Whether the index should be sparse (skip null values)
19
+ * @returns {Promise<Object>} Index creation result with operation details and message
20
+ * @throws {Error} When database, collection name or field name is missing, or index creation fails
21
+ */
22
+ const create_index_operation = async (database_name, collection_name, field_name, options = {}) => {
23
+ const log = create_context_logger();
24
+
25
+ if (!database_name) {
26
+ throw new Error('Database name is required');
27
+ }
28
+
29
+ if (!collection_name) {
30
+ throw new Error('Collection name is required');
31
+ }
32
+
33
+ if (!field_name) {
34
+ throw new Error('Field name is required');
35
+ }
36
+
37
+ try {
38
+ const result = await create_index(database_name, collection_name, field_name, options);
39
+
40
+ const operation_type = result.operation_type || 'created';
41
+ const action_verb = operation_type === 'created' ? 'created' :
42
+ operation_type === 'updated' ? 'updated' :
43
+ 'already exists';
44
+
45
+ log.info(`Index ${action_verb} successfully`, {
46
+ database: database_name,
47
+ collection: collection_name,
48
+ field: field_name,
49
+ options,
50
+ operation_type
51
+ });
52
+
53
+ return {
54
+ ...result,
55
+ message: `Index ${action_verb} on ${database_name}.${collection_name}.${field_name}`
56
+ };
57
+ } catch (error) {
58
+ log.error('Failed to create/upsert index', {
59
+ database: database_name,
60
+ collection: collection_name,
61
+ field: field_name,
62
+ error: error.message
63
+ });
64
+ throw error;
65
+ }
66
+ };
67
+
68
+ export default create_index_operation;
@@ -0,0 +1,114 @@
1
+ import { get_database } from '../query_engine.js';
2
+ import { update_indexes_on_delete } from '../index_manager.js';
3
+ import { get_write_queue } from '../write_queue.js';
4
+ import create_logger from '../logger.js';
5
+
6
+ const { create_context_logger } = create_logger('delete_one');
7
+
8
+ /**
9
+ * Checks if a document matches the given filter criteria (simple equality check).
10
+ * @param {Object} document - Document to test
11
+ * @param {Object} filter - Filter criteria
12
+ * @returns {boolean} True if document matches filter
13
+ */
14
+ const matches_filter = (document, filter) => {
15
+ if (!filter || Object.keys(filter).length === 0) {
16
+ return true;
17
+ }
18
+
19
+ for (const [field, value] of Object.entries(filter)) {
20
+ if (document[field] !== value) {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ return true;
26
+ };
27
+
28
+ /**
29
+ * Internal implementation of delete_one operation without write queue serialization.
30
+ * @param {string} database_name - Name of the database
31
+ * @param {string} collection_name - Name of the collection
32
+ * @param {Object} filter - Filter criteria to match document for deletion
33
+ * @param {Object} [options={}] - Delete options (currently unused)
34
+ * @returns {Promise<Object>} Delete result with acknowledged and deleted_count
35
+ * @throws {Error} When database name, collection name is missing or filter is invalid
36
+ */
37
+ const delete_one_internal = async (database_name, collection_name, filter, options = {}) => {
38
+ const log = create_context_logger();
39
+
40
+ if (!database_name) {
41
+ throw new Error('Database name is required');
42
+ }
43
+
44
+ if (!collection_name) {
45
+ throw new Error('Collection name is required');
46
+ }
47
+
48
+ if (!filter || typeof filter !== 'object') {
49
+ throw new Error('Filter must be a valid object');
50
+ }
51
+
52
+ const db = get_database();
53
+ let deleted_count = 0;
54
+ let deleted_document = null;
55
+
56
+ await db.transaction(() => {
57
+ const collection_prefix = `${database_name}:${collection_name}:`;
58
+
59
+ const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
60
+ for (const { key, value } of range) {
61
+ try {
62
+ const document = JSON.parse(value);
63
+ if (matches_filter(document, filter)) {
64
+ db.remove(key);
65
+ deleted_document = document;
66
+ deleted_count = 1;
67
+ break;
68
+ }
69
+ } catch (parse_error) {
70
+ // Skip documents that can't be parsed
71
+ continue;
72
+ }
73
+ }
74
+ });
75
+
76
+ if (deleted_document) {
77
+ await update_indexes_on_delete(database_name, collection_name, deleted_document);
78
+ }
79
+
80
+ log.info('Delete operation completed', {
81
+ database: database_name,
82
+ collection: collection_name,
83
+ deleted_count
84
+ });
85
+
86
+ return {
87
+ acknowledged: true,
88
+ deleted_count
89
+ };
90
+ };
91
+
92
+ /**
93
+ * Deletes a single document from a collection with write queue serialization.
94
+ * @param {string} database_name - Name of the database
95
+ * @param {string} collection_name - Name of the collection
96
+ * @param {Object} filter - Filter criteria to match document for deletion
97
+ * @param {Object} [options={}] - Delete options
98
+ * @returns {Promise<Object>} Delete result with acknowledged and deleted_count
99
+ */
100
+ const delete_one = async (database_name, collection_name, filter, options = {}) => {
101
+ const write_queue = get_write_queue();
102
+
103
+ return await write_queue.enqueue_write_operation(
104
+ () => delete_one_internal(database_name, collection_name, filter, options),
105
+ {
106
+ operation: 'delete_one',
107
+ database: database_name,
108
+ collection: collection_name,
109
+ filter_keys: Object.keys(filter || {})
110
+ }
111
+ );
112
+ };
113
+
114
+ export default delete_one;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @fileoverview Drop index operation for JoystickDB collections.
3
+ * Provides functionality to remove secondary indexes from collection fields.
4
+ */
5
+
6
+ import { drop_index } from '../index_manager.js';
7
+ import create_logger from '../logger.js';
8
+
9
+ const { create_context_logger } = create_logger('drop_index');
10
+
11
+ /**
12
+ * Drops an existing index from a specified field in a collection.
13
+ * @param {string} database_name - Name of the database containing the collection
14
+ * @param {string} collection_name - Name of the collection to drop index from
15
+ * @param {string} field_name - Name of the field to remove index from
16
+ * @returns {Promise<Object>} Index drop result with operation details and message
17
+ * @throws {Error} When database name, collection name or field name is missing, or index drop fails
18
+ */
19
+ const drop_index_operation = async (database_name, collection_name, field_name) => {
20
+ const log = create_context_logger();
21
+
22
+ if (!database_name) {
23
+ throw new Error('Database name is required');
24
+ }
25
+
26
+ if (!collection_name) {
27
+ throw new Error('Collection name is required');
28
+ }
29
+
30
+ if (!field_name) {
31
+ throw new Error('Field name is required');
32
+ }
33
+
34
+ try {
35
+ const result = await drop_index(database_name, collection_name, field_name);
36
+
37
+ log.info('Index dropped successfully', {
38
+ database: database_name,
39
+ collection: collection_name,
40
+ field: field_name
41
+ });
42
+
43
+ return {
44
+ ...result,
45
+ message: `Index dropped on ${database_name}.${collection_name}.${field_name}`
46
+ };
47
+ } catch (error) {
48
+ log.error('Failed to drop index', {
49
+ database: database_name,
50
+ collection: collection_name,
51
+ field: field_name,
52
+ error: error.message
53
+ });
54
+ throw error;
55
+ }
56
+ };
57
+
58
+ export default drop_index_operation;