@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,808 @@
1
+ /**
2
+ * @fileoverview Comprehensive admin operations for database management, monitoring, and maintenance.
3
+ *
4
+ * Provides extensive administrative functionality including statistics collection, collection management,
5
+ * document operations, backup/restore, replication management, index operations, and performance monitoring.
6
+ * Supports both legacy and modern admin operation formats with comprehensive error handling.
7
+ */
8
+
9
+ import { get_database } from '../query_engine.js';
10
+ import { get_settings } from '../load_settings.js';
11
+ import { get_write_queue } from '../write_queue.js';
12
+ import { get_auth_stats } from '../auth_manager.js';
13
+ import {
14
+ get_query_statistics,
15
+ get_auto_index_statistics,
16
+ force_index_evaluation,
17
+ remove_automatic_indexes
18
+ } from '../auto_index_manager.js';
19
+ import {
20
+ create_index,
21
+ drop_index,
22
+ get_indexes
23
+ } from '../index_manager.js';
24
+ import {
25
+ test_s3_connection,
26
+ create_backup,
27
+ list_backups,
28
+ restore_backup,
29
+ cleanup_old_backups
30
+ } from '../backup_manager.js';
31
+ import { get_replication_manager } from '../replication_manager.js';
32
+ import { get_write_forwarder } from '../write_forwarder.js';
33
+ import create_logger from '../logger.js';
34
+ import { performance_monitor } from '../performance_monitor.js';
35
+
36
+ const { create_context_logger } = create_logger('admin');
37
+
38
+ /**
39
+ * Gets comprehensive server and database statistics.
40
+ * @returns {Object} Enhanced statistics including server, database, and performance metrics
41
+ * @throws {Error} When stats collection fails
42
+ */
43
+ const get_enhanced_stats = () => {
44
+ const log = create_context_logger();
45
+
46
+ try {
47
+ const db = get_database();
48
+
49
+ // Handle settings gracefully - use defaults if not loaded
50
+ let settings;
51
+ try {
52
+ settings = get_settings();
53
+ } catch (settings_error) {
54
+ settings = { port: 1983 };
55
+ }
56
+
57
+ // Safely get database stats
58
+ let db_stats = {};
59
+ try {
60
+ const raw_stats = db.getStats ? db.getStats() : {};
61
+ db_stats = {
62
+ pageSize: raw_stats.pageSize || 0,
63
+ treeDepth: raw_stats.treeDepth || 0,
64
+ treeBranchPages: raw_stats.treeBranchPages || 0,
65
+ treeLeafPages: raw_stats.treeLeafPages || 0,
66
+ entryCount: raw_stats.entryCount || 0,
67
+ mapSize: raw_stats.mapSize || 0,
68
+ lastPageNumber: raw_stats.lastPageNumber || 0
69
+ };
70
+ } catch (stats_error) {
71
+ db_stats = { error: 'Could not retrieve database stats' };
72
+ }
73
+
74
+ // Count collections and documents safely
75
+ const collections = {};
76
+ let total_documents = 0;
77
+
78
+ try {
79
+ for (const { key } of db.getRange()) {
80
+ if (typeof key === 'string' && key.includes(':') && !key.startsWith('_')) {
81
+ const collection_name = key.split(':')[0];
82
+ collections[collection_name] = (collections[collection_name] || 0) + 1;
83
+ total_documents++;
84
+ }
85
+ }
86
+ } catch (range_error) {
87
+ log.warn('Could not iterate database range for stats', { error: range_error.message });
88
+ }
89
+
90
+ // Calculate memory usage percentage
91
+ const memory_usage = process.memoryUsage();
92
+ const memory_usage_mb = {
93
+ rss: Math.round(memory_usage.rss / 1024 / 1024),
94
+ heapTotal: Math.round(memory_usage.heapTotal / 1024 / 1024),
95
+ heapUsed: Math.round(memory_usage.heapUsed / 1024 / 1024),
96
+ external: Math.round(memory_usage.external / 1024 / 1024)
97
+ };
98
+
99
+ // Calculate database size percentage
100
+ const map_size_usage_percent = db_stats.mapSize > 0
101
+ ? Math.round((db_stats.lastPageNumber * db_stats.pageSize / db_stats.mapSize) * 100)
102
+ : 0;
103
+
104
+ return {
105
+ server: {
106
+ uptime: Math.floor(process.uptime()),
107
+ uptime_formatted: format_uptime(process.uptime()),
108
+ memory_usage: memory_usage_mb,
109
+ memory_usage_raw: memory_usage,
110
+ node_version: process.version,
111
+ platform: process.platform,
112
+ arch: process.arch,
113
+ pid: process.pid,
114
+ cpu_usage: process.cpuUsage()
115
+ },
116
+ database: {
117
+ total_documents,
118
+ total_collections: Object.keys(collections).length,
119
+ collections,
120
+ stats: db_stats,
121
+ map_size_usage_percent,
122
+ disk_usage: {
123
+ map_size_mb: Math.round((db_stats.mapSize || 0) / 1024 / 1024),
124
+ used_space_mb: Math.round(((db_stats.lastPageNumber || 0) * (db_stats.pageSize || 0)) / 1024 / 1024)
125
+ }
126
+ },
127
+ performance: {
128
+ ops_per_second: calculate_ops_per_second(),
129
+ avg_response_time_ms: calculate_avg_response_time()
130
+ }
131
+ };
132
+ } catch (error) {
133
+ log.error('Failed to get enhanced stats', { error: error.message });
134
+ throw error;
135
+ }
136
+ };
137
+
138
+ /**
139
+ * Formats uptime seconds into human-readable string.
140
+ * @param {number} seconds - Uptime in seconds
141
+ * @returns {string} Formatted uptime string (e.g., "2d 3h 45m 12s")
142
+ */
143
+ const format_uptime = (seconds) => {
144
+ const days = Math.floor(seconds / 86400);
145
+ const hours = Math.floor((seconds % 86400) / 3600);
146
+ const minutes = Math.floor((seconds % 3600) / 60);
147
+ const secs = Math.floor(seconds % 60);
148
+
149
+ if (days > 0) {
150
+ return `${days}d ${hours}h ${minutes}m ${secs}s`;
151
+ } else if (hours > 0) {
152
+ return `${hours}h ${minutes}m ${secs}s`;
153
+ } else if (minutes > 0) {
154
+ return `${minutes}m ${secs}s`;
155
+ } else {
156
+ return `${secs}s`;
157
+ }
158
+ };
159
+
160
+ // Simple performance tracking (in production, this would be more sophisticated)
161
+ let operation_count = 0;
162
+ let total_response_time = 0;
163
+ let start_time = Date.now();
164
+
165
+ /**
166
+ * Calculates operations per second based on tracked operations.
167
+ * @returns {number} Operations per second
168
+ */
169
+ const calculate_ops_per_second = () => {
170
+ const elapsed_seconds = (Date.now() - start_time) / 1000;
171
+ return elapsed_seconds > 0 ? Math.round(operation_count / elapsed_seconds) : 0;
172
+ };
173
+
174
+ /**
175
+ * Calculates average response time based on tracked operations.
176
+ * @returns {number} Average response time in milliseconds
177
+ */
178
+ const calculate_avg_response_time = () => {
179
+ return operation_count > 0 ? Math.round(total_response_time / operation_count) : 0;
180
+ };
181
+
182
+ /**
183
+ * Tracks an operation for performance monitoring.
184
+ * @param {number} duration_ms - Operation duration in milliseconds
185
+ */
186
+ export const track_operation = (duration_ms) => {
187
+ operation_count++;
188
+ total_response_time += duration_ms;
189
+ };
190
+
191
+ /**
192
+ * Lists all collections in the database with metadata.
193
+ * @param {string} [database_name='default'] - Database name to list collections from
194
+ * @returns {Object} Object containing collections array, total counts
195
+ * @throws {Error} When collection listing fails
196
+ */
197
+ const list_collections = (database_name = 'default') => {
198
+ const log = create_context_logger();
199
+
200
+ try {
201
+ const db = get_database();
202
+ const collections_map = {};
203
+ let total_documents = 0;
204
+
205
+ // Look for database:collection:document_id format
206
+ try {
207
+ for (const { key } of db.getRange()) {
208
+ if (typeof key === 'string' && key.includes(':') && !key.startsWith('_')) {
209
+ const parts = key.split(':');
210
+ if (parts.length >= 3) {
211
+ const key_database = parts[0];
212
+ const collection_name = parts[1];
213
+
214
+ // Only count collections from the specified database
215
+ if (key_database === database_name) {
216
+ if (!collections_map[collection_name]) {
217
+ collections_map[collection_name] = {
218
+ name: collection_name,
219
+ document_count: 0,
220
+ indexes: [],
221
+ estimated_size_bytes: 0
222
+ };
223
+ }
224
+ collections_map[collection_name].document_count++;
225
+ total_documents++;
226
+ }
227
+ }
228
+ }
229
+ }
230
+ } catch (range_error) {
231
+ log.warn('Could not iterate database range for collections', { error: range_error.message });
232
+
233
+ // Fallback: try to find collections by checking for database-specific patterns
234
+ const potential_collections = [
235
+ 'admin_test', 'test_collection', 'queue_test', 'users', 'products',
236
+ 'orders', 'sessions', 'logs', 'analytics', 'settings', 'another_collection',
237
+ 'list_test', 'pagination_test', 'get_test', 'query_test', 'admin_insert_test',
238
+ 'admin_update_test', 'admin_delete_test'
239
+ ];
240
+
241
+ for (const collection_name of potential_collections) {
242
+ try {
243
+ // Check if this collection has any documents in the specified database
244
+ const prefix = `${database_name}:${collection_name}:`;
245
+ const range = db.getRange({ start: prefix, end: prefix + '\xFF' });
246
+
247
+ let document_count = 0;
248
+ for (const entry of range) {
249
+ document_count++;
250
+ total_documents++;
251
+ }
252
+
253
+ if (document_count > 0) {
254
+ collections_map[collection_name] = {
255
+ name: collection_name,
256
+ document_count,
257
+ indexes: [],
258
+ estimated_size_bytes: document_count * 100 // Rough estimate
259
+ };
260
+ }
261
+ } catch (collection_error) {
262
+ // Skip collections that can't be accessed
263
+ continue;
264
+ }
265
+ }
266
+ }
267
+
268
+ // Get index information for each collection safely
269
+ try {
270
+ const index_prefix = `index:${database_name}:`;
271
+ const index_range = db.getRange({ start: index_prefix, end: index_prefix + '\xFF' });
272
+ for (const { key, value } of index_range) {
273
+ if (typeof key === 'string' && key.startsWith(index_prefix)) {
274
+ const remaining_key = key.substring(index_prefix.length);
275
+ const collection_name = remaining_key.split(':')[0];
276
+ if (collections_map[collection_name]) {
277
+ if (!collections_map[collection_name].indexes.includes(remaining_key.split(':')[1])) {
278
+ collections_map[collection_name].indexes.push(remaining_key.split(':')[1]);
279
+ }
280
+ }
281
+ }
282
+ }
283
+ } catch (index_range_error) {
284
+ log.warn('Could not iterate index range', { error: index_range_error.message });
285
+ }
286
+
287
+ const collections_array = Object.values(collections_map);
288
+
289
+ return {
290
+ collections: collections_array,
291
+ total_collections: collections_array.length,
292
+ total_documents
293
+ };
294
+ } catch (error) {
295
+ log.error('Failed to list collections', { error: error.message });
296
+ throw error;
297
+ }
298
+ };
299
+
300
+ /**
301
+ * Lists documents in a collection with pagination and sorting.
302
+ * @param {string} collection - Collection name
303
+ * @param {Object} [options={}] - List options
304
+ * @param {number} [options.limit=50] - Maximum documents to return
305
+ * @param {number} [options.skip=0] - Number of documents to skip
306
+ * @param {string} [options.sort_field] - Field to sort by
307
+ * @param {string} [options.sort_order='asc'] - Sort order ('asc' or 'desc')
308
+ * @param {string} [options.database='default'] - Database name
309
+ * @returns {Object} Object containing documents array and pagination info
310
+ * @throws {Error} When collection name is missing or listing fails
311
+ */
312
+ const list_documents = (collection, options = {}) => {
313
+ const log = create_context_logger();
314
+
315
+ if (!collection) {
316
+ throw new Error('Collection name is required');
317
+ }
318
+
319
+ try {
320
+ const db = get_database();
321
+ const { limit = 50, skip = 0, sort_field, sort_order = 'asc', database = 'default' } = options;
322
+
323
+ const documents = [];
324
+ const prefix = `${database}:${collection}:`;
325
+ let count = 0;
326
+ let skipped = 0;
327
+
328
+ for (const { key, value } of db.getRange({ start: prefix, end: prefix + '\xFF' })) {
329
+ if (typeof key === 'string' && key.startsWith(prefix)) {
330
+ if (skipped < skip) {
331
+ skipped++;
332
+ continue;
333
+ }
334
+
335
+ if (count >= limit) {
336
+ break;
337
+ }
338
+
339
+ try {
340
+ const document = JSON.parse(value);
341
+ const document_id = key.substring(prefix.length);
342
+ documents.push({ _id: document_id, ...document });
343
+ count++;
344
+ } catch (parse_error) {
345
+ log.warn('Could not parse document', {
346
+ collection,
347
+ key,
348
+ error: parse_error.message
349
+ });
350
+ }
351
+ }
352
+ }
353
+
354
+ // Simple sorting if requested
355
+ if (sort_field && documents.length > 0) {
356
+ documents.sort((a, b) => {
357
+ const a_val = a[sort_field];
358
+ const b_val = b[sort_field];
359
+
360
+ if (sort_order === 'desc') {
361
+ return b_val > a_val ? 1 : b_val < a_val ? -1 : 0;
362
+ } else {
363
+ return a_val > b_val ? 1 : a_val < b_val ? -1 : 0;
364
+ }
365
+ });
366
+ }
367
+
368
+ return {
369
+ collection,
370
+ documents,
371
+ count: documents.length,
372
+ skip,
373
+ limit,
374
+ has_more: count === limit
375
+ };
376
+ } catch (error) {
377
+ log.error('Failed to list documents', { collection, error: error.message });
378
+ throw error;
379
+ }
380
+ };
381
+
382
+ /**
383
+ * Gets a specific document by ID from a collection.
384
+ * @param {string} collection - Collection name
385
+ * @param {string} document_id - Document ID
386
+ * @param {string} [database='default'] - Database name
387
+ * @returns {Object} Object containing found status and document data
388
+ * @throws {Error} When collection name or document ID is missing
389
+ */
390
+ const get_document = (collection, document_id, database = 'default') => {
391
+ const log = create_context_logger();
392
+
393
+ if (!collection || !document_id) {
394
+ throw new Error('Collection name and document ID are required');
395
+ }
396
+
397
+ try {
398
+ const db = get_database();
399
+ const key = `${database}:${collection}:${document_id}`;
400
+ const value = db.get(key);
401
+
402
+ if (!value) {
403
+ return { found: false, collection, document_id };
404
+ }
405
+
406
+ const document = JSON.parse(value);
407
+ return {
408
+ found: true,
409
+ collection,
410
+ document_id,
411
+ document: { _id: document_id, ...document }
412
+ };
413
+ } catch (error) {
414
+ log.error('Failed to get document', { collection, document_id, error: error.message });
415
+ throw error;
416
+ }
417
+ };
418
+
419
+ /**
420
+ * Queries documents in a collection with filtering and pagination.
421
+ * @param {string} collection - Collection name
422
+ * @param {Object} [filter={}] - Query filter with MongoDB-style operators
423
+ * @param {Object} [options={}] - Query options
424
+ * @param {number} [options.limit=100] - Maximum documents to return
425
+ * @param {number} [options.skip=0] - Number of documents to skip
426
+ * @param {string} [options.database='default'] - Database name
427
+ * @returns {Object} Object containing matching documents and query metadata
428
+ * @throws {Error} When collection name is missing or query fails
429
+ */
430
+ const query_documents = (collection, filter = {}, options = {}) => {
431
+ const log = create_context_logger();
432
+
433
+ if (!collection) {
434
+ throw new Error('Collection name is required');
435
+ }
436
+
437
+ try {
438
+ const db = get_database();
439
+ const { limit = 100, skip = 0, database = 'default' } = options;
440
+
441
+ const documents = [];
442
+ const prefix = `${database}:${collection}:`;
443
+ let count = 0;
444
+ let skipped = 0;
445
+ let total_examined = 0;
446
+
447
+ for (const { key, value } of db.getRange({ start: prefix, end: prefix + '\xFF' })) {
448
+ if (typeof key === 'string' && key.startsWith(prefix)) {
449
+ total_examined++;
450
+
451
+ try {
452
+ const document = JSON.parse(value);
453
+ const document_id = key.substring(prefix.length);
454
+ const full_document = { _id: document_id, ...document };
455
+
456
+ // Simple filter matching
457
+ const matches = Object.keys(filter).every(field => {
458
+ const filter_value = filter[field];
459
+ const doc_value = full_document[field];
460
+
461
+ if (typeof filter_value === 'object' && filter_value !== null) {
462
+ // Handle operators like { $gt: 5 }, { $regex: "pattern" }
463
+ return Object.keys(filter_value).every(operator => {
464
+ const op_value = filter_value[operator];
465
+ switch (operator) {
466
+ case '$gt': return doc_value > op_value;
467
+ case '$gte': return doc_value >= op_value;
468
+ case '$lt': return doc_value < op_value;
469
+ case '$lte': return doc_value <= op_value;
470
+ case '$ne': return doc_value !== op_value;
471
+ case '$in': return Array.isArray(op_value) && op_value.includes(doc_value);
472
+ case '$regex': return new RegExp(op_value).test(String(doc_value));
473
+ default: return doc_value === filter_value;
474
+ }
475
+ });
476
+ } else {
477
+ return doc_value === filter_value;
478
+ }
479
+ });
480
+
481
+ if (matches) {
482
+ if (skipped < skip) {
483
+ skipped++;
484
+ continue;
485
+ }
486
+
487
+ if (count >= limit) {
488
+ break;
489
+ }
490
+
491
+ documents.push(full_document);
492
+ count++;
493
+ }
494
+ } catch (parse_error) {
495
+ log.warn('Could not parse document during query', {
496
+ collection,
497
+ key,
498
+ error: parse_error.message
499
+ });
500
+ }
501
+ }
502
+ }
503
+
504
+ return {
505
+ collection,
506
+ filter,
507
+ documents,
508
+ count: documents.length,
509
+ total_examined,
510
+ skip,
511
+ limit,
512
+ has_more: count === limit
513
+ };
514
+ } catch (error) {
515
+ log.error('Failed to query documents', { collection, filter, error: error.message });
516
+ throw error;
517
+ }
518
+ };
519
+
520
+ /**
521
+ * Inserts a document via admin interface (delegates to insert_one operation).
522
+ * @param {string} database_name - Database name
523
+ * @param {string} collection - Collection name
524
+ * @param {Object} document - Document to insert
525
+ * @param {Object} [options={}] - Insert options
526
+ * @returns {Promise<Object>} Insert result
527
+ */
528
+ const insert_document = async (database_name, collection, document, options = {}) => {
529
+ const insert_one_module = await import('./insert_one.js');
530
+ return await insert_one_module.default(database_name, collection, document, options);
531
+ };
532
+
533
+ /**
534
+ * Updates a document via admin interface (delegates to update_one operation).
535
+ * @param {string} database_name - Database name
536
+ * @param {string} collection - Collection name
537
+ * @param {Object} filter - Filter criteria
538
+ * @param {Object} update - Update operations
539
+ * @param {Object} [options={}] - Update options
540
+ * @returns {Promise<Object>} Update result
541
+ */
542
+ const update_document = async (database_name, collection, filter, update, options = {}) => {
543
+ const update_one_module = await import('./update_one.js');
544
+ return await update_one_module.default(database_name, collection, filter, update, options);
545
+ };
546
+
547
+ /**
548
+ * Deletes a document via admin interface (delegates to delete_one operation).
549
+ * @param {string} database_name - Database name
550
+ * @param {string} collection - Collection name
551
+ * @param {Object} filter - Filter criteria
552
+ * @param {Object} [options={}] - Delete options
553
+ * @returns {Promise<Object>} Delete result
554
+ */
555
+ const delete_document = async (database_name, collection, filter, options = {}) => {
556
+ const delete_one_module = await import('./delete_one.js');
557
+ return await delete_one_module.default(database_name, collection, filter, options);
558
+ };
559
+
560
+ /**
561
+ * Main admin operation handler supporting various administrative actions.
562
+ * @param {string} admin_action - Admin action to perform
563
+ * @param {Object} [data={}] - Action-specific data
564
+ * @param {Object} connection_manager - Connection manager instance
565
+ * @param {Set} authenticated_clients - Set of authenticated client IDs
566
+ * @returns {Promise<Object>} Action result
567
+ * @throws {Error} When admin action fails
568
+ */
569
+ export default async (admin_action, data = {}, connection_manager, authenticated_clients) => {
570
+ const log = create_context_logger();
571
+ const start_time = Date.now();
572
+
573
+ try {
574
+ let result;
575
+
576
+ switch (admin_action) {
577
+ case 'stats':
578
+ result = {
579
+ server: {
580
+ uptime: Math.floor(process.uptime()),
581
+ uptime_formatted: format_uptime(process.uptime()),
582
+ node_version: process.version,
583
+ platform: process.platform,
584
+ arch: process.arch,
585
+ pid: process.pid
586
+ },
587
+ memory: performance_monitor.get_memory_stats(),
588
+ database: {
589
+ ...performance_monitor.get_database_stats(),
590
+ map_size_mb: Math.round((performance_monitor.get_database_stats()?.map_size || 0) / 1024 / 1024),
591
+ used_space_mb: Math.round((performance_monitor.get_database_stats()?.used_space || 0) / 1024 / 1024),
592
+ usage_percent: performance_monitor.get_database_stats()?.usage_percent || 0
593
+ },
594
+ performance: {
595
+ ops_per_second: calculate_ops_per_second(),
596
+ avg_response_time_ms: calculate_avg_response_time()
597
+ },
598
+ system: performance_monitor.get_system_stats(),
599
+ connections: connection_manager?.get_stats() || {},
600
+ write_queue: get_write_queue()?.get_stats() || {},
601
+ authentication: {
602
+ authenticated_clients: authenticated_clients?.size || 0,
603
+ ...get_auth_stats()
604
+ },
605
+ settings: (() => {
606
+ try {
607
+ const settings = get_settings();
608
+ return {
609
+ port: settings.port || 1983
610
+ };
611
+ } catch (error) {
612
+ return { port: 1983 };
613
+ }
614
+ })()
615
+ };
616
+ break;
617
+
618
+ case 'list_collections':
619
+ result = list_collections();
620
+ break;
621
+
622
+ case 'list_documents':
623
+ result = list_documents(data.collection, {
624
+ limit: data.limit,
625
+ skip: data.skip,
626
+ sort_field: data.sort_field,
627
+ sort_order: data.sort_order
628
+ });
629
+ break;
630
+
631
+ case 'get_document':
632
+ result = get_document(data.collection, data.document_id);
633
+ break;
634
+
635
+ case 'query_documents':
636
+ result = query_documents(data.collection, data.filter, {
637
+ limit: data.limit,
638
+ skip: data.skip
639
+ });
640
+ break;
641
+
642
+ case 'insert_document':
643
+ result = await insert_document(data.database || 'default', data.collection, data.document, data.options);
644
+ break;
645
+
646
+ case 'update_document':
647
+ // If document_id is provided, use it as a filter, otherwise use the provided filter
648
+ const final_update_filter = data.document_id ? { _id: data.document_id } : data.filter;
649
+ result = await update_document(data.database || 'default', data.collection, final_update_filter, data.update, data.options);
650
+ break;
651
+
652
+ case 'delete_document':
653
+ // If document_id is provided, use it as a filter, otherwise use the provided filter
654
+ const final_delete_filter = data.document_id ? { _id: data.document_id } : data.filter;
655
+ result = await delete_document(data.database || 'default', data.collection, final_delete_filter, data.options);
656
+ break;
657
+
658
+ case 'test_s3_connection':
659
+ result = await test_s3_connection();
660
+ break;
661
+
662
+ case 'backup_now':
663
+ result = await create_backup();
664
+ break;
665
+
666
+ case 'list_backups':
667
+ result = await list_backups();
668
+ break;
669
+
670
+ case 'restore_backup':
671
+ if (!data.backup_filename) {
672
+ throw new Error('backup_filename is required for restore operation');
673
+ }
674
+ result = await restore_backup(data.backup_filename);
675
+ break;
676
+
677
+ case 'cleanup_backups':
678
+ result = await cleanup_old_backups();
679
+ break;
680
+
681
+ case 'get_auto_index_stats':
682
+ result = get_auto_index_statistics();
683
+ break;
684
+
685
+ case 'get_query_stats':
686
+ result = get_query_statistics(data.collection);
687
+ break;
688
+
689
+ case 'evaluate_auto_indexes':
690
+ result = await force_index_evaluation(data.collection);
691
+ break;
692
+
693
+ case 'remove_auto_indexes':
694
+ if (!data.collection) {
695
+ throw new Error('collection is required for remove_auto_indexes operation');
696
+ }
697
+ result = await remove_automatic_indexes(data.collection, data.field_names);
698
+ break;
699
+
700
+ case 'create_index':
701
+ if (!data.collection || !data.field) {
702
+ throw new Error('collection and field are required for create_index operation');
703
+ }
704
+ result = await create_index(data.database || 'default', data.collection, data.field, data.options);
705
+ break;
706
+
707
+ case 'drop_index':
708
+ if (!data.collection || !data.field) {
709
+ throw new Error('collection and field are required for drop_index operation');
710
+ }
711
+ result = await drop_index(data.database || 'default', data.collection, data.field);
712
+ break;
713
+
714
+ case 'get_indexes':
715
+ if (!data.collection) {
716
+ throw new Error('collection is required for get_indexes operation');
717
+ }
718
+ result = { indexes: get_indexes(data.database || 'default', data.collection) };
719
+ break;
720
+
721
+ case 'get_replication_status':
722
+ const replication_manager = get_replication_manager();
723
+ result = replication_manager.get_replication_status();
724
+ break;
725
+
726
+ case 'add_secondary':
727
+ if (!data.id || !data.ip || !data.port || !data.private_key) {
728
+ throw new Error('id, ip, port, and private_key are required for add_secondary operation');
729
+ }
730
+ const add_replication_manager = get_replication_manager();
731
+ result = await add_replication_manager.add_secondary({
732
+ id: data.id,
733
+ ip: data.ip,
734
+ port: data.port,
735
+ private_key: data.private_key,
736
+ enabled: true
737
+ });
738
+ break;
739
+
740
+ case 'remove_secondary':
741
+ if (!data.secondary_id) {
742
+ throw new Error('secondary_id is required for remove_secondary operation');
743
+ }
744
+ const remove_replication_manager = get_replication_manager();
745
+ result = remove_replication_manager.remove_secondary(data.secondary_id);
746
+ break;
747
+
748
+ case 'sync_secondaries':
749
+ const sync_replication_manager = get_replication_manager();
750
+ result = await sync_replication_manager.sync_secondaries();
751
+ break;
752
+
753
+ case 'get_secondary_health':
754
+ const health_replication_manager = get_replication_manager();
755
+ result = health_replication_manager.get_secondary_health();
756
+ break;
757
+
758
+ case 'get_forwarder_status':
759
+ const write_forwarder = get_write_forwarder();
760
+ result = write_forwarder.get_forwarder_status();
761
+ break;
762
+
763
+ default:
764
+ // Default admin action (backward compatibility)
765
+ result = {
766
+ ...get_enhanced_stats(),
767
+ connections: connection_manager?.get_stats() || {},
768
+ write_queue: get_write_queue()?.get_stats() || {},
769
+ authentication: {
770
+ authenticated_clients: authenticated_clients?.size || 0,
771
+ ...get_auth_stats()
772
+ },
773
+ settings: (() => {
774
+ try {
775
+ const settings = get_settings();
776
+ return {
777
+ port: settings.port || 1983
778
+ };
779
+ } catch (error) {
780
+ return { port: 1983 };
781
+ }
782
+ })()
783
+ };
784
+ }
785
+
786
+ const duration_ms = Date.now() - start_time;
787
+ track_operation(duration_ms);
788
+
789
+ log.info('Admin operation completed', {
790
+ admin_action: admin_action || 'default',
791
+ duration_ms,
792
+ status: 'success'
793
+ });
794
+
795
+ return result;
796
+ } catch (error) {
797
+ const duration_ms = Date.now() - start_time;
798
+
799
+ log.error('Admin operation failed', {
800
+ admin_action: admin_action || 'default',
801
+ duration_ms,
802
+ status: 'error',
803
+ error: error.message
804
+ });
805
+
806
+ throw error;
807
+ }
808
+ };