@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,681 @@
1
+ /**
2
+ * @fileoverview Automatic index management system for JoystickDB with intelligent query analysis.
3
+ * Monitors query patterns, analyzes performance metrics, and automatically creates/removes indexes
4
+ * based on usage patterns, frequency thresholds, and performance improvements. Provides comprehensive
5
+ * statistics tracking, configurable thresholds, and cleanup of unused indexes.
6
+ */
7
+
8
+ import { get_database } from './query_engine.js';
9
+ import { create_index, get_indexes, drop_index } from './index_manager.js';
10
+ import { get_settings } from './load_settings.js';
11
+ import create_logger from './logger.js';
12
+
13
+ const { create_context_logger } = create_logger('auto_index_manager');
14
+
15
+ /** @type {Object|null} LMDB database instance for storing auto-indexing data */
16
+ let auto_index_db = null;
17
+
18
+ /** @type {Map<string, Map<string, Object>>} Query statistics by collection and field */
19
+ let query_stats = new Map();
20
+
21
+ /** @type {Map<string, Map<string, Object>>} Auto-created index metadata by collection and field */
22
+ let auto_index_metadata = new Map();
23
+
24
+ /** @type {NodeJS.Timeout|null} Timer for periodic index evaluation */
25
+ let evaluation_timer = null;
26
+
27
+ /**
28
+ * Initializes the auto-index database and loads existing metadata and statistics.
29
+ * Sets up the evaluation timer for periodic index analysis.
30
+ * @returns {Object} LMDB database instance for auto-indexing data
31
+ */
32
+ const initialize_auto_index_database = () => {
33
+ if (!auto_index_db) {
34
+ const main_db = get_database();
35
+ auto_index_db = main_db.openDB('auto_indexes', { create: true });
36
+
37
+ load_auto_index_metadata();
38
+ load_query_stats();
39
+ start_evaluation_timer();
40
+ }
41
+ return auto_index_db;
42
+ };
43
+
44
+ /**
45
+ * Gets the initialized auto-index database instance.
46
+ * @returns {Object} LMDB database instance for auto-indexing data
47
+ * @throws {Error} When auto-index database is not initialized
48
+ */
49
+ const get_auto_index_database = () => {
50
+ if (!auto_index_db) {
51
+ throw new Error('Auto index database not initialized. Call initialize_auto_index_database first.');
52
+ }
53
+ return auto_index_db;
54
+ };
55
+
56
+ /**
57
+ * Gets auto-indexing configuration from settings with fallback defaults.
58
+ * @returns {Object} Auto-indexing configuration object
59
+ * @returns {boolean} returns.enabled - Whether auto-indexing is enabled
60
+ * @returns {number} returns.frequency_threshold - Minimum query count for index creation
61
+ * @returns {number} returns.performance_threshold_ms - Performance threshold in milliseconds
62
+ * @returns {number} returns.max_auto_indexes_per_collection - Maximum auto-indexes per collection
63
+ * @returns {number} returns.monitoring_window_hours - Query monitoring window in hours
64
+ * @returns {number} returns.cleanup_unused_after_hours - Hours before cleaning unused indexes
65
+ * @returns {Array<string>} returns.excluded_fields - Fields to exclude from auto-indexing
66
+ * @returns {Array<string>} returns.included_collections - Collections to include (or ['*'] for all)
67
+ * @returns {Array<string>} returns.excluded_collections - Collections to exclude
68
+ */
69
+ const get_auto_index_config = () => {
70
+ try {
71
+ const settings = get_settings();
72
+ return settings.auto_indexing || {
73
+ enabled: true,
74
+ frequency_threshold: 100,
75
+ performance_threshold_ms: 50,
76
+ max_auto_indexes_per_collection: 10,
77
+ monitoring_window_hours: 24,
78
+ cleanup_unused_after_hours: 168,
79
+ excluded_fields: ['_id', 'created_at'],
80
+ included_collections: ['*'],
81
+ excluded_collections: []
82
+ };
83
+ } catch (error) {
84
+ return {
85
+ enabled: true,
86
+ frequency_threshold: 100,
87
+ performance_threshold_ms: 50,
88
+ max_auto_indexes_per_collection: 10,
89
+ monitoring_window_hours: 24,
90
+ cleanup_unused_after_hours: 168,
91
+ excluded_fields: ['_id', 'created_at'],
92
+ included_collections: ['*'],
93
+ excluded_collections: []
94
+ };
95
+ }
96
+ };
97
+
98
+ /**
99
+ * Determines if a collection should be monitored for auto-indexing.
100
+ * @param {string} collection_name - Name of the collection to check
101
+ * @returns {boolean} True if collection should be monitored
102
+ */
103
+ const should_monitor_collection = (collection_name) => {
104
+ const config = get_auto_index_config();
105
+
106
+ if (config.excluded_collections.includes(collection_name)) {
107
+ return false;
108
+ }
109
+
110
+ if (config.included_collections.includes('*')) {
111
+ return true;
112
+ }
113
+
114
+ return config.included_collections.includes(collection_name);
115
+ };
116
+
117
+ /**
118
+ * Determines if a field should be monitored for auto-indexing.
119
+ * @param {string} field_name - Name of the field to check
120
+ * @returns {boolean} True if field should be monitored
121
+ */
122
+ const should_monitor_field = (field_name) => {
123
+ const config = get_auto_index_config();
124
+ return !config.excluded_fields.includes(field_name);
125
+ };
126
+
127
+ /**
128
+ * Extracts monitorable field names from a query filter.
129
+ * @param {Object} filter - Query filter object
130
+ * @returns {Array<string>} Array of field names that should be monitored
131
+ */
132
+ const extract_query_fields = (filter) => {
133
+ const fields = [];
134
+
135
+ if (!filter || typeof filter !== 'object') {
136
+ return fields;
137
+ }
138
+
139
+ for (const [field, value] of Object.entries(filter)) {
140
+ if (should_monitor_field(field)) {
141
+ fields.push(field);
142
+ }
143
+ }
144
+
145
+ return fields;
146
+ };
147
+
148
+ /**
149
+ * Records a query for auto-indexing analysis, tracking performance and usage patterns.
150
+ * @param {string} collection_name - Name of the collection queried
151
+ * @param {Object} filter - Query filter used
152
+ * @param {number} execution_time_ms - Query execution time in milliseconds
153
+ * @param {boolean} [used_index=false] - Whether query used an existing index
154
+ * @param {string|null} [indexed_field=null] - Specific field that used an index
155
+ */
156
+ const record_query = (collection_name, filter, execution_time_ms, used_index = false, indexed_field = null) => {
157
+ const log = create_context_logger();
158
+ const config = get_auto_index_config();
159
+
160
+ if (!config.enabled || !should_monitor_collection(collection_name)) {
161
+ return;
162
+ }
163
+
164
+ // Only record if auto index database is initialized
165
+ if (!auto_index_db) {
166
+ return;
167
+ }
168
+
169
+ const fields = extract_query_fields(filter);
170
+ const now = new Date();
171
+
172
+ if (!query_stats.has(collection_name)) {
173
+ query_stats.set(collection_name, new Map());
174
+ }
175
+
176
+ const collection_stats = query_stats.get(collection_name);
177
+
178
+ for (const field of fields) {
179
+ if (!collection_stats.has(field)) {
180
+ collection_stats.set(field, {
181
+ query_count: 0,
182
+ total_time_ms: 0,
183
+ avg_time_ms: 0,
184
+ last_queried: now,
185
+ slow_query_count: 0,
186
+ used_index_count: 0
187
+ });
188
+ }
189
+
190
+ const field_stats = collection_stats.get(field);
191
+ field_stats.query_count++;
192
+ field_stats.total_time_ms += execution_time_ms;
193
+ field_stats.avg_time_ms = field_stats.total_time_ms / field_stats.query_count;
194
+ field_stats.last_queried = now;
195
+
196
+ if (execution_time_ms > config.performance_threshold_ms) {
197
+ field_stats.slow_query_count++;
198
+ }
199
+
200
+ // Increment used_index_count for the specific field that used the index
201
+ // If no indexed_field is specified but used_index is true, assume all fields used indexes
202
+ if (used_index && (indexed_field === field || indexed_field === null)) {
203
+ field_stats.used_index_count++;
204
+ }
205
+ }
206
+
207
+ log.debug('Query recorded for auto-indexing analysis', {
208
+ collection: collection_name,
209
+ fields,
210
+ execution_time_ms,
211
+ used_index,
212
+ indexed_field
213
+ });
214
+ };
215
+
216
+ const save_query_stats = () => {
217
+ const log = create_context_logger();
218
+
219
+ try {
220
+ const auto_index_db = get_auto_index_database();
221
+ const stats_data = {};
222
+
223
+ for (const [collection, fields] of query_stats.entries()) {
224
+ stats_data[collection] = {};
225
+ for (const [field, stats] of fields.entries()) {
226
+ stats_data[collection][field] = {
227
+ ...stats,
228
+ last_queried: stats.last_queried.toISOString()
229
+ };
230
+ }
231
+ }
232
+
233
+ auto_index_db.put('query_stats', stats_data);
234
+
235
+ log.debug('Query statistics saved to database');
236
+ } catch (error) {
237
+ log.error('Failed to save query statistics', { error: error.message });
238
+ }
239
+ };
240
+
241
+ const load_query_stats = () => {
242
+ const log = create_context_logger();
243
+
244
+ try {
245
+ const auto_index_db = get_auto_index_database();
246
+ const stats_data = auto_index_db.get('query_stats');
247
+
248
+ if (stats_data) {
249
+ query_stats.clear();
250
+
251
+ for (const [collection, fields] of Object.entries(stats_data)) {
252
+ const collection_stats = new Map();
253
+
254
+ for (const [field, stats] of Object.entries(fields)) {
255
+ collection_stats.set(field, {
256
+ ...stats,
257
+ last_queried: new Date(stats.last_queried)
258
+ });
259
+ }
260
+
261
+ query_stats.set(collection, collection_stats);
262
+ }
263
+
264
+ log.debug('Query statistics loaded from database');
265
+ }
266
+ } catch (error) {
267
+ log.error('Failed to load query statistics', { error: error.message });
268
+ }
269
+ };
270
+
271
+ const save_auto_index_metadata = () => {
272
+ const log = create_context_logger();
273
+
274
+ try {
275
+ const auto_index_db = get_auto_index_database();
276
+ const metadata_data = {};
277
+
278
+ for (const [collection, fields] of auto_index_metadata.entries()) {
279
+ metadata_data[collection] = {};
280
+ for (const [field, metadata] of fields.entries()) {
281
+ metadata_data[collection][field] = {
282
+ ...metadata,
283
+ created_at: metadata.created_at.toISOString(),
284
+ last_used: metadata.last_used ? metadata.last_used.toISOString() : null
285
+ };
286
+ }
287
+ }
288
+
289
+ auto_index_db.put('auto_index_metadata', metadata_data);
290
+
291
+ log.debug('Auto index metadata saved to database');
292
+ } catch (error) {
293
+ log.error('Failed to save auto index metadata', { error: error.message });
294
+ }
295
+ };
296
+
297
+ const load_auto_index_metadata = () => {
298
+ const log = create_context_logger();
299
+
300
+ try {
301
+ const auto_index_db = get_auto_index_database();
302
+ const metadata_data = auto_index_db.get('auto_index_metadata');
303
+
304
+ if (metadata_data) {
305
+ auto_index_metadata.clear();
306
+
307
+ for (const [collection, fields] of Object.entries(metadata_data)) {
308
+ const collection_metadata = new Map();
309
+
310
+ for (const [field, metadata] of Object.entries(fields)) {
311
+ collection_metadata.set(field, {
312
+ ...metadata,
313
+ created_at: new Date(metadata.created_at),
314
+ last_used: metadata.last_used ? new Date(metadata.last_used) : null
315
+ });
316
+ }
317
+
318
+ auto_index_metadata.set(collection, collection_metadata);
319
+ }
320
+
321
+ log.debug('Auto index metadata loaded from database');
322
+ }
323
+ } catch (error) {
324
+ log.error('Failed to load auto index metadata', { error: error.message });
325
+ }
326
+ };
327
+
328
+ const is_auto_created_index = (collection_name, field_name) => {
329
+ try {
330
+ const collection_metadata = auto_index_metadata.get(collection_name);
331
+ return !!(collection_metadata && collection_metadata.has(field_name));
332
+ } catch (error) {
333
+ return false;
334
+ }
335
+ };
336
+
337
+ const get_auto_index_candidates = () => {
338
+ const config = get_auto_index_config();
339
+ const candidates = [];
340
+ const now = new Date();
341
+ const window_ms = config.monitoring_window_hours * 60 * 60 * 1000;
342
+
343
+ for (const [collection, fields] of query_stats.entries()) {
344
+ const existing_indexes = get_indexes('default', collection);
345
+ const auto_index_count = existing_indexes.filter(index =>
346
+ is_auto_created_index(collection, index.field)
347
+ ).length;
348
+
349
+ if (auto_index_count >= config.max_auto_indexes_per_collection) {
350
+ continue;
351
+ }
352
+
353
+ for (const [field, stats] of fields.entries()) {
354
+ const time_since_last_query = now - stats.last_queried;
355
+
356
+ if (time_since_last_query > window_ms) {
357
+ continue;
358
+ }
359
+
360
+ const has_existing_index = existing_indexes.some(index => index.field === field);
361
+ if (has_existing_index) {
362
+ continue;
363
+ }
364
+
365
+ const meets_frequency_threshold = stats.query_count >= config.frequency_threshold;
366
+ const meets_performance_threshold = stats.avg_time_ms >= config.performance_threshold_ms;
367
+ const has_slow_queries = stats.slow_query_count > 0;
368
+
369
+ if (meets_frequency_threshold || (meets_performance_threshold && has_slow_queries)) {
370
+ candidates.push({
371
+ collection,
372
+ field,
373
+ stats: { ...stats },
374
+ priority: stats.slow_query_count * 2 + (stats.query_count / config.frequency_threshold)
375
+ });
376
+ }
377
+ }
378
+ }
379
+
380
+ return candidates.sort((a, b) => b.priority - a.priority);
381
+ };
382
+
383
+ const create_automatic_index = async (collection_name, field_name, stats) => {
384
+ const log = create_context_logger();
385
+
386
+ try {
387
+ await create_index('default', collection_name, field_name, { sparse: true });
388
+
389
+ if (!auto_index_metadata.has(collection_name)) {
390
+ auto_index_metadata.set(collection_name, new Map());
391
+ }
392
+
393
+ const collection_metadata = auto_index_metadata.get(collection_name);
394
+ collection_metadata.set(field_name, {
395
+ created_at: new Date(),
396
+ query_count_at_creation: stats.query_count,
397
+ avg_performance_improvement_ms: 0,
398
+ last_used: null,
399
+ usage_count: 0,
400
+ auto_created: true
401
+ });
402
+
403
+ save_auto_index_metadata();
404
+
405
+ log.info('Automatic index created', {
406
+ collection: collection_name,
407
+ field: field_name,
408
+ query_count: stats.query_count,
409
+ avg_time_ms: stats.avg_time_ms,
410
+ slow_query_count: stats.slow_query_count
411
+ });
412
+
413
+ return true;
414
+ } catch (error) {
415
+ log.error('Failed to create automatic index', {
416
+ collection: collection_name,
417
+ field: field_name,
418
+ error: error.message
419
+ });
420
+ return false;
421
+ }
422
+ };
423
+
424
+ const evaluate_and_create_indexes = async () => {
425
+ const log = create_context_logger();
426
+ const config = get_auto_index_config();
427
+
428
+ if (!config.enabled) {
429
+ return;
430
+ }
431
+
432
+ try {
433
+ const candidates = get_auto_index_candidates();
434
+
435
+ if (candidates.length === 0) {
436
+ log.debug('No automatic index candidates found');
437
+ return;
438
+ }
439
+
440
+ log.info('Evaluating automatic index candidates', {
441
+ candidate_count: candidates.length
442
+ });
443
+
444
+ for (const candidate of candidates.slice(0, 5)) {
445
+ const success = await create_automatic_index(
446
+ candidate.collection,
447
+ candidate.field,
448
+ candidate.stats
449
+ );
450
+
451
+ if (success) {
452
+ await new Promise(resolve => setTimeout(resolve, 100));
453
+ }
454
+ }
455
+ } catch (error) {
456
+ log.error('Failed to evaluate automatic indexes', { error: error.message });
457
+ }
458
+ };
459
+
460
+ const cleanup_unused_indexes = async () => {
461
+ const log = create_context_logger();
462
+ const config = get_auto_index_config();
463
+ const now = new Date();
464
+ const cleanup_threshold_ms = config.cleanup_unused_after_hours * 60 * 60 * 1000;
465
+
466
+ try {
467
+ for (const [collection, fields] of auto_index_metadata.entries()) {
468
+ for (const [field, metadata] of fields.entries()) {
469
+ if (!metadata.last_used) {
470
+ const time_since_creation = now - metadata.created_at;
471
+ if (time_since_creation > cleanup_threshold_ms) {
472
+ await drop_index('default', collection, field);
473
+ fields.delete(field);
474
+
475
+ log.info('Removed unused automatic index', {
476
+ collection,
477
+ field,
478
+ created_at: metadata.created_at,
479
+ usage_count: metadata.usage_count
480
+ });
481
+ }
482
+ } else {
483
+ const time_since_last_use = now - metadata.last_used;
484
+ if (time_since_last_use > cleanup_threshold_ms) {
485
+ await drop_index('default', collection, field);
486
+ fields.delete(field);
487
+
488
+ log.info('Removed unused automatic index', {
489
+ collection,
490
+ field,
491
+ last_used: metadata.last_used,
492
+ usage_count: metadata.usage_count
493
+ });
494
+ }
495
+ }
496
+ }
497
+ }
498
+
499
+ save_auto_index_metadata();
500
+ } catch (error) {
501
+ log.error('Failed to cleanup unused indexes', { error: error.message });
502
+ }
503
+ };
504
+
505
+ const record_index_usage = (collection_name, field_name) => {
506
+ const collection_metadata = auto_index_metadata.get(collection_name);
507
+
508
+ if (collection_metadata && collection_metadata.has(field_name)) {
509
+ const metadata = collection_metadata.get(field_name);
510
+ metadata.last_used = new Date();
511
+ metadata.usage_count++;
512
+ }
513
+ };
514
+
515
+ const start_evaluation_timer = () => {
516
+ const config = get_auto_index_config();
517
+
518
+ if (evaluation_timer) {
519
+ clearInterval(evaluation_timer);
520
+ }
521
+
522
+ if (config.enabled) {
523
+ evaluation_timer = setInterval(async () => {
524
+ save_query_stats();
525
+ await evaluate_and_create_indexes();
526
+ await cleanup_unused_indexes();
527
+ }, 60000);
528
+ }
529
+ };
530
+
531
+ const stop_evaluation_timer = () => {
532
+ if (evaluation_timer) {
533
+ clearInterval(evaluation_timer);
534
+ evaluation_timer = null;
535
+ }
536
+ };
537
+
538
+ const get_query_statistics = (collection_name = null) => {
539
+ if (collection_name) {
540
+ const collection_stats = query_stats.get(collection_name);
541
+ if (!collection_stats) {
542
+ return {};
543
+ }
544
+
545
+ const stats = {};
546
+ for (const [field, field_stats] of collection_stats.entries()) {
547
+ stats[field] = { ...field_stats };
548
+ }
549
+ return stats;
550
+ }
551
+
552
+ const all_stats = {};
553
+ for (const [collection, fields] of query_stats.entries()) {
554
+ all_stats[collection] = {};
555
+ for (const [field, field_stats] of fields.entries()) {
556
+ all_stats[collection][field] = { ...field_stats };
557
+ }
558
+ }
559
+
560
+ return all_stats;
561
+ };
562
+
563
+ const get_auto_index_statistics = () => {
564
+ const stats = {
565
+ total_auto_indexes: 0,
566
+ collections: {}
567
+ };
568
+
569
+ for (const [collection, fields] of auto_index_metadata.entries()) {
570
+ stats.collections[collection] = {};
571
+
572
+ for (const [field, metadata] of fields.entries()) {
573
+ stats.total_auto_indexes++;
574
+ stats.collections[collection][field] = { ...metadata };
575
+ }
576
+ }
577
+
578
+ return stats;
579
+ };
580
+
581
+ const force_index_evaluation = async (collection_name = null) => {
582
+ const log = create_context_logger();
583
+
584
+ try {
585
+ if (collection_name) {
586
+ const candidates = get_auto_index_candidates().filter(
587
+ candidate => candidate.collection === collection_name
588
+ );
589
+
590
+ for (const candidate of candidates) {
591
+ await create_automatic_index(
592
+ candidate.collection,
593
+ candidate.field,
594
+ candidate.stats
595
+ );
596
+ }
597
+
598
+ log.info('Forced index evaluation completed', {
599
+ collection: collection_name,
600
+ candidates_processed: candidates.length
601
+ });
602
+ } else {
603
+ await evaluate_and_create_indexes();
604
+ log.info('Forced index evaluation completed for all collections');
605
+ }
606
+
607
+ return { acknowledged: true };
608
+ } catch (error) {
609
+ log.error('Failed to force index evaluation', { error: error.message });
610
+ throw error;
611
+ }
612
+ };
613
+
614
+ const remove_automatic_indexes = async (collection_name, field_names = null) => {
615
+ const log = create_context_logger();
616
+
617
+ try {
618
+ const collection_metadata = auto_index_metadata.get(collection_name);
619
+ if (!collection_metadata) {
620
+ return { acknowledged: true, removed_count: 0 };
621
+ }
622
+
623
+ const fields_to_remove = field_names || Array.from(collection_metadata.keys());
624
+ let removed_count = 0;
625
+
626
+ for (const field_name of fields_to_remove) {
627
+ if (collection_metadata.has(field_name)) {
628
+ await drop_index('default', collection_name, field_name);
629
+ collection_metadata.delete(field_name);
630
+ removed_count++;
631
+
632
+ log.info('Removed automatic index', {
633
+ collection: collection_name,
634
+ field: field_name
635
+ });
636
+ }
637
+ }
638
+
639
+ save_auto_index_metadata();
640
+
641
+ return { acknowledged: true, removed_count };
642
+ } catch (error) {
643
+ log.error('Failed to remove automatic indexes', {
644
+ collection: collection_name,
645
+ field_names,
646
+ error: error.message
647
+ });
648
+ throw error;
649
+ }
650
+ };
651
+
652
+ const cleanup_auto_index_database = () => {
653
+ stop_evaluation_timer();
654
+ if (auto_index_db) {
655
+ try {
656
+ // Clear database entries instead of saving them
657
+ auto_index_db.remove('query_stats');
658
+ auto_index_db.remove('auto_index_metadata');
659
+ } catch (error) {
660
+ // Ignore errors during cleanup
661
+ }
662
+ }
663
+ query_stats.clear();
664
+ auto_index_metadata.clear();
665
+ auto_index_db = null;
666
+ };
667
+
668
+ export {
669
+ initialize_auto_index_database,
670
+ get_auto_index_database,
671
+ record_query,
672
+ record_index_usage,
673
+ get_query_statistics,
674
+ get_auto_index_statistics,
675
+ force_index_evaluation,
676
+ remove_automatic_indexes,
677
+ is_auto_created_index,
678
+ start_evaluation_timer,
679
+ stop_evaluation_timer,
680
+ cleanup_auto_index_database
681
+ };