@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,473 @@
1
+ /**
2
+ * @fileoverview API key management for JoystickDB authentication system.
3
+ *
4
+ * Handles API key file generation, validation, and user management operations.
5
+ * Provides secure API key-based authentication for database setup and user management.
6
+ */
7
+
8
+ import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
9
+ import crypto from 'crypto';
10
+ import bcrypt from 'bcrypt';
11
+ import create_logger from './logger.js';
12
+ import { get_database, build_collection_key, generate_document_id } from './query_engine.js';
13
+
14
+ const { create_context_logger } = create_logger('api_key_manager');
15
+ const log = create_context_logger();
16
+
17
+ /** @type {string} Path to API key file */
18
+ const API_KEY_FILE_PATH = './API_KEY';
19
+
20
+ /** @type {string} Collection name for storing users */
21
+ const USERS_COLLECTION = '_users';
22
+
23
+ /** @type {number} BCrypt salt rounds for password hashing */
24
+ const SALT_ROUNDS = 12;
25
+
26
+ /** @type {string|null} Cached API key */
27
+ let cached_api_key = null;
28
+
29
+ /** @type {boolean} Flag to track if admin user exists */
30
+ let admin_user_exists = false;
31
+
32
+ /**
33
+ * Generates a cryptographically secure 32-character alphanumeric API key.
34
+ * @returns {string} 32-character alphanumeric API key
35
+ */
36
+ const generate_api_key = () => {
37
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
38
+ let result = '';
39
+ const bytes = crypto.randomBytes(32);
40
+
41
+ for (let i = 0; i < 32; i++) {
42
+ result += chars[bytes[i] % chars.length];
43
+ }
44
+
45
+ return result;
46
+ };
47
+
48
+ /**
49
+ * Loads API key from file or generates new one if it doesn't exist.
50
+ * @returns {string} API key from file or newly generated key
51
+ */
52
+ const load_or_generate_api_key = () => {
53
+ if (cached_api_key) {
54
+ return cached_api_key;
55
+ }
56
+
57
+ if (existsSync(API_KEY_FILE_PATH)) {
58
+ try {
59
+ cached_api_key = readFileSync(API_KEY_FILE_PATH, 'utf8').trim();
60
+ log.info('API key loaded from file');
61
+ return cached_api_key;
62
+ } catch (error) {
63
+ log.error('Failed to read API key file', { error: error.message });
64
+ throw new Error(`Failed to read API key file: ${error.message}`);
65
+ }
66
+ }
67
+
68
+ // Generate new API key
69
+ const api_key = generate_api_key();
70
+
71
+ try {
72
+ writeFileSync(API_KEY_FILE_PATH, api_key, { mode: 0o600 });
73
+ cached_api_key = api_key;
74
+
75
+ log.info('New API key generated and saved', { file_path: API_KEY_FILE_PATH });
76
+
77
+ // Display startup message
78
+ display_startup_message(api_key);
79
+
80
+ return api_key;
81
+ } catch (error) {
82
+ log.error('Failed to save API key file', { error: error.message });
83
+ throw new Error(`Failed to save API key file: ${error.message}`);
84
+ }
85
+ };
86
+
87
+ /**
88
+ * Displays the startup message with API key and setup instructions.
89
+ * @param {string} api_key - Generated API key to display
90
+ */
91
+ const display_startup_message = (api_key) => {
92
+ const port = process.env.JOYSTICK_DB_PORT || '1983';
93
+ const http_port = process.env.JOYSTICK_DB_HTTP_PORT || '1984';
94
+
95
+ console.log('\nJoystickDB Setup\n');
96
+ console.log('To finish setting up your database and enable operations for authenticated users, you will need to create an admin user via the database\'s admin API using the API key displayed below.\n');
97
+ console.log('=== STORE THIS KEY SECURELY -- IT WILL NOT BE DISPLAYED AGAIN ===');
98
+ console.log(api_key);
99
+ console.log('===\n');
100
+ console.log('To create a user, send a POST request to the server:\n');
101
+ console.log(`fetch('http://localhost:${http_port}/api/users', {`);
102
+ console.log(' method: \'POST\',');
103
+ console.log(' headers: {');
104
+ console.log(' \'Content-Type\': \'application/json\',');
105
+ console.log(` 'x-joystick-db-api-key': '${api_key}'`);
106
+ console.log(' },');
107
+ console.log(' body: JSON.stringify({');
108
+ console.log(' username: \'admin\',');
109
+ console.log(' password: \'your_secure_password\',');
110
+ console.log(' role: \'read_write\'');
111
+ console.log(' })');
112
+ console.log('});\n');
113
+ console.log('==!==');
114
+ console.log('Store this key securely. It will not be displayed again.');
115
+ console.log('==!==\n');
116
+ console.log(`API key saved to: ${API_KEY_FILE_PATH}\n`);
117
+ };
118
+
119
+ /**
120
+ * Validates an API key against the stored key.
121
+ * @param {string} provided_key - API key to validate
122
+ * @returns {boolean} True if API key is valid
123
+ */
124
+ const validate_api_key = (provided_key) => {
125
+ if (!provided_key) {
126
+ return false;
127
+ }
128
+
129
+ const stored_key = load_or_generate_api_key();
130
+ return provided_key === stored_key;
131
+ };
132
+
133
+ /**
134
+ * Validates username format (alphanumeric, 3-50 characters).
135
+ * @param {string} username - Username to validate
136
+ * @returns {boolean} True if username is valid
137
+ */
138
+ const validate_username = (username) => {
139
+ if (!username || typeof username !== 'string') {
140
+ return false;
141
+ }
142
+
143
+ return /^[a-zA-Z0-9]{3,50}$/.test(username);
144
+ };
145
+
146
+ /**
147
+ * Validates password complexity requirements.
148
+ * @param {string} password - Password to validate
149
+ * @returns {Object} Validation result
150
+ * @returns {boolean} returns.valid - Whether password is valid
151
+ * @returns {string} returns.error - Error message if invalid
152
+ */
153
+ const validate_password = (password) => {
154
+ if (!password || typeof password !== 'string') {
155
+ return { valid: false, error: 'Password is required' };
156
+ }
157
+
158
+ if (password.length < 8) {
159
+ return { valid: false, error: 'Password must be at least 8 characters long' };
160
+ }
161
+
162
+ if (password.length > 128) {
163
+ return { valid: false, error: 'Password must be no more than 128 characters long' };
164
+ }
165
+
166
+ return { valid: true };
167
+ };
168
+
169
+ /**
170
+ * Validates role value against allowed options.
171
+ * @param {string} role - Role to validate
172
+ * @returns {boolean} True if role is valid
173
+ */
174
+ const validate_role = (role) => {
175
+ const allowed_roles = ['read', 'write', 'read_write'];
176
+ return allowed_roles.includes(role);
177
+ };
178
+
179
+ /**
180
+ * Creates a new user in the database.
181
+ * @param {Object} user_data - User data
182
+ * @param {string} user_data.username - Username
183
+ * @param {string} user_data.password - Plain text password
184
+ * @param {string} user_data.role - User role
185
+ * @returns {Promise<Object>} Created user data
186
+ * @throws {Error} When validation fails or user already exists
187
+ */
188
+ const create_user = async (user_data) => {
189
+ const { username, password, role } = user_data;
190
+
191
+ // Validate input
192
+ if (!validate_username(username)) {
193
+ throw new Error('Username must be alphanumeric and 3-50 characters long');
194
+ }
195
+
196
+ const password_validation = validate_password(password);
197
+ if (!password_validation.valid) {
198
+ throw new Error(password_validation.error);
199
+ }
200
+
201
+ if (!validate_role(role)) {
202
+ throw new Error('Role must be one of: read, write, read_write');
203
+ }
204
+
205
+ const db = get_database();
206
+
207
+ // Hash password
208
+ const password_hash = await bcrypt.hash(password, SALT_ROUNDS);
209
+
210
+ // Create user document
211
+ const user_document = {
212
+ username,
213
+ password_hash,
214
+ role,
215
+ created_at: new Date().toISOString(),
216
+ updated_at: new Date().toISOString()
217
+ };
218
+
219
+ // Store user in database using transaction
220
+ const user_key = build_collection_key(USERS_COLLECTION, username);
221
+ let stored_user = null;
222
+
223
+ await db.transaction(() => {
224
+ const existing_user = db.get(user_key);
225
+
226
+ if (existing_user) {
227
+ throw new Error('Username already exists');
228
+ }
229
+
230
+ db.put(user_key, JSON.stringify(user_document));
231
+ stored_user = user_document;
232
+ });
233
+
234
+ // Check if this is the first admin user
235
+ if (role === 'read_write') {
236
+ admin_user_exists = true;
237
+ log.info('Admin user created, API key requirement relaxed for authenticated operations');
238
+ }
239
+
240
+ log.info('User created successfully', { username, role });
241
+
242
+ // Return user data without password hash
243
+ return {
244
+ username: user_document.username,
245
+ role: user_document.role,
246
+ created_at: user_document.created_at
247
+ };
248
+ };
249
+
250
+ /**
251
+ * Gets all users from the database.
252
+ * @returns {Array<Object>} Array of user objects without password hashes
253
+ */
254
+ const get_all_users = () => {
255
+ const db = get_database();
256
+ const users = [];
257
+
258
+ for (const { key, value } of db.getRange({ start: `${USERS_COLLECTION}:`, end: `${USERS_COLLECTION}:\xFF` })) {
259
+ const parsed_user = JSON.parse(value);
260
+ const user_data = {
261
+ username: parsed_user.username,
262
+ role: parsed_user.role,
263
+ created_at: parsed_user.created_at,
264
+ updated_at: parsed_user.updated_at
265
+ };
266
+ users.push(user_data);
267
+ }
268
+
269
+ return users;
270
+ };
271
+
272
+ /**
273
+ * Gets a user by username.
274
+ * @param {string} username - Username to find
275
+ * @returns {Object|null} User object without password hash, or null if not found
276
+ */
277
+ const get_user = (username) => {
278
+ const db = get_database();
279
+ const user_key = build_collection_key(USERS_COLLECTION, username);
280
+ const user_data = db.get(user_key);
281
+
282
+ if (!user_data) {
283
+ return null;
284
+ }
285
+
286
+ const user = JSON.parse(user_data);
287
+
288
+ return {
289
+ username: user.username,
290
+ role: user.role,
291
+ created_at: user.created_at,
292
+ updated_at: user.updated_at
293
+ };
294
+ };
295
+
296
+ /**
297
+ * Updates a user's role or password.
298
+ * @param {string} username - Username to update
299
+ * @param {Object} updates - Updates to apply
300
+ * @param {string} [updates.password] - New password
301
+ * @param {string} [updates.role] - New role
302
+ * @returns {Promise<Object>} Updated user data
303
+ * @throws {Error} When user not found or validation fails
304
+ */
305
+ const update_user = async (username, updates) => {
306
+ const db = get_database();
307
+ const user_key = build_collection_key(USERS_COLLECTION, username);
308
+
309
+ // Validate password first if provided (before transaction)
310
+ let password_hash = null;
311
+ if (updates.password) {
312
+ const password_validation = validate_password(updates.password);
313
+ if (!password_validation.valid) {
314
+ throw new Error(password_validation.error);
315
+ }
316
+
317
+ password_hash = await bcrypt.hash(updates.password, SALT_ROUNDS);
318
+ }
319
+
320
+ // Validate role if provided (before transaction)
321
+ if (updates.role && !validate_role(updates.role)) {
322
+ throw new Error('Role must be one of: read, write, read_write');
323
+ }
324
+
325
+ // Check if user exists first
326
+ const existing_user_data = db.get(user_key);
327
+ if (!existing_user_data) {
328
+ throw new Error('User not found');
329
+ }
330
+
331
+ const existing_user = JSON.parse(existing_user_data);
332
+ const user_to_update = { ...existing_user };
333
+
334
+ if (updates.role) {
335
+ user_to_update.role = updates.role;
336
+ }
337
+
338
+ if (password_hash) {
339
+ user_to_update.password_hash = password_hash;
340
+ }
341
+
342
+ user_to_update.updated_at = new Date().toISOString();
343
+
344
+ // Update using putSync for immediate persistence
345
+ db.putSync(user_key, JSON.stringify(user_to_update));
346
+
347
+ log.info('User updated successfully', { username, updates: Object.keys(updates) });
348
+
349
+ return {
350
+ username: user_to_update.username,
351
+ role: user_to_update.role,
352
+ created_at: user_to_update.created_at,
353
+ updated_at: user_to_update.updated_at
354
+ };
355
+ };
356
+
357
+ /**
358
+ * Deletes a user from the database.
359
+ * @param {string} username - Username to delete
360
+ * @returns {boolean} True if user was deleted
361
+ * @throws {Error} When user not found
362
+ */
363
+ const delete_user = (username) => {
364
+ const db = get_database();
365
+ const user_key = build_collection_key(USERS_COLLECTION, username);
366
+
367
+ // Check if user exists first
368
+ const existing_user = db.get(user_key);
369
+ if (!existing_user) {
370
+ throw new Error('User not found');
371
+ }
372
+
373
+ // Delete using removeSync (synchronous remove)
374
+ const result = db.removeSync(user_key);
375
+
376
+ log.info('User deleted successfully', { username });
377
+ return true;
378
+ };
379
+
380
+ /**
381
+ * Verifies a user's password.
382
+ * @param {string} username - Username
383
+ * @param {string} password - Plain text password
384
+ * @returns {Promise<Object|null>} User object if password is correct, null otherwise
385
+ */
386
+ const verify_user_password = async (username, password) => {
387
+ const db = get_database();
388
+ const user_key = build_collection_key(USERS_COLLECTION, username);
389
+ const user_data = db.get(user_key);
390
+
391
+ if (!user_data) {
392
+ return null;
393
+ }
394
+
395
+ const user = JSON.parse(user_data);
396
+ const is_valid = await bcrypt.compare(password, user.password_hash);
397
+
398
+ if (is_valid) {
399
+ return {
400
+ username: user.username,
401
+ role: user.role,
402
+ created_at: user.created_at,
403
+ updated_at: user.updated_at
404
+ };
405
+ }
406
+
407
+ return null;
408
+ };
409
+
410
+ /**
411
+ * Checks if an admin user exists in the database.
412
+ * @returns {boolean} True if admin user exists
413
+ */
414
+ const check_admin_user_exists = () => {
415
+ if (admin_user_exists) {
416
+ return true;
417
+ }
418
+
419
+ const db = get_database();
420
+
421
+ for (const { value } of db.getRange({ start: `${USERS_COLLECTION}:`, end: `${USERS_COLLECTION}:\xFF` })) {
422
+ const parsed_user = JSON.parse(value);
423
+ if (parsed_user.role === 'read_write') {
424
+ admin_user_exists = true;
425
+ return true;
426
+ }
427
+ }
428
+
429
+ return false;
430
+ };
431
+
432
+ /**
433
+ * Initializes the API key manager.
434
+ */
435
+ const initialize_api_key_manager = () => {
436
+ load_or_generate_api_key();
437
+ admin_user_exists = check_admin_user_exists();
438
+
439
+ if (admin_user_exists) {
440
+ log.info('Admin user detected, API key requirement relaxed for authenticated operations');
441
+ }
442
+ };
443
+
444
+ /**
445
+ * Resets API key manager state (for testing).
446
+ */
447
+ const reset_api_key_state = () => {
448
+ cached_api_key = null;
449
+ admin_user_exists = false;
450
+
451
+ // Remove API key file if it exists
452
+ if (existsSync(API_KEY_FILE_PATH)) {
453
+ try {
454
+ unlinkSync(API_KEY_FILE_PATH);
455
+ } catch (error) {
456
+ // Ignore errors when removing file
457
+ }
458
+ }
459
+ };
460
+
461
+ export {
462
+ load_or_generate_api_key,
463
+ validate_api_key,
464
+ create_user,
465
+ get_all_users,
466
+ get_user,
467
+ update_user,
468
+ delete_user,
469
+ verify_user_password,
470
+ check_admin_user_exists,
471
+ initialize_api_key_manager,
472
+ reset_api_key_state
473
+ };