@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
package/README.md ADDED
@@ -0,0 +1,1821 @@
1
+ # JoystickDB
2
+
3
+ A high-performance, production-ready TCP-based database server built on LMDB with comprehensive client libraries, multi-database support, replication, and enterprise features for Node.js applications.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Features](#features)
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [Server Setup](#server-setup)
12
+ - [Client Usage](#client-usage)
13
+ - [Multi-Database Operations](#multi-database-operations)
14
+ - [Database Operations](#database-operations)
15
+ - [Indexing](#indexing)
16
+ - [HTTP API](#http-api)
17
+ - [Replication](#replication)
18
+ - [Administration](#administration)
19
+ - [Backup & Restore](#backup--restore)
20
+ - [Configuration](#configuration)
21
+ - [Production Deployment](#production-deployment)
22
+ - [API Reference](#api-reference)
23
+
24
+ ## Overview
25
+
26
+ JoystickDB is a lightweight, blazing-fast database server that provides MongoDB-like operations over TCP using MessagePack for efficient data serialization. Built on top of LMDB (Lightning Memory-Mapped Database), it offers ACID transactions, high performance, minimal resource usage, and enterprise-grade features like multi-database support, replication, and automatic backups.
27
+
28
+ **Think of it as**: A simpler, faster alternative to MongoDB that's perfect for applications that need reliable data storage without the complexity of a full database cluster, now with full multi-database support for better data organization.
29
+
30
+ ## Features
31
+
32
+ ### Core Database Features
33
+ - **Multi-Database Support**: Organize data across multiple isolated databases with MongoDB-like chaining API
34
+ - **High Performance**: Built on LMDB with MessagePack serialization for maximum speed
35
+ - **MongoDB-like API**: Familiar CRUD operations and query syntax - easy to learn
36
+ - **ACID Transactions**: Your data is always consistent and safe
37
+ - **TCP Protocol**: Efficient binary communication over the network
38
+ - **Automatic Indexing**: Smart index creation based on your query patterns
39
+ - **Secondary Indexes**: Create custom indexes for lightning-fast queries
40
+ - **Database Isolation**: Complete data separation between databases with proper key namespacing
41
+
42
+ ### Production & Enterprise Features
43
+ - **API Key Authentication**: Secure API key-based authentication system with user management
44
+ - **HTTP API**: RESTful HTTP endpoints for user management and external integrations
45
+ - **TCP Replication**: Master-slave replication for high availability and read scaling
46
+ - **Password Authentication**: Secure bcrypt password hashing with rate limiting
47
+ - **Role-Based Access Control**: Read, write, and read_write user roles
48
+ - **Clustering**: Multi-process clustering support for better performance
49
+ - **Backup & Restore**: Automatic S3-compatible backup system with scheduling
50
+ - **Admin Interface**: Comprehensive administrative operations and monitoring
51
+ - **Connection Pooling**: Efficient connection management and resource usage
52
+ - **Health Monitoring**: Built-in performance metrics and health checks
53
+ - **Write Serialization**: Ensures data consistency under high concurrent load
54
+
55
+ ### Developer Experience
56
+ - **Fluent API**: Chain methods for intuitive database operations
57
+ - **Multi-Database Chaining**: `client.db('database').collection('collection')` API pattern
58
+ - **Backward Compatibility**: Existing single-database API still supported
59
+ - **Auto-Reconnection**: Client automatically reconnects on network issues
60
+ - **TypeScript Support**: Full TypeScript definitions included
61
+ - **Comprehensive Logging**: Detailed logs for debugging and monitoring
62
+ - **Easy Setup**: Get started in minutes with minimal configuration
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ npm install joystick-db
68
+ ```
69
+
70
+ ## Quick Start
71
+
72
+ ### 1. Start the Server
73
+
74
+ ```bash
75
+ # Start with default settings (port 1983)
76
+ npm start
77
+
78
+ # Or with custom port
79
+ PORT=3000 npm start
80
+
81
+ # With clustering (uses all CPU cores)
82
+ WORKER_COUNT=4 npm start
83
+ ```
84
+
85
+ ### 2. Setup Authentication (One-time)
86
+
87
+ When you first start JoystickDB, it automatically generates a secure API key and displays setup instructions:
88
+
89
+ ```
90
+ JoystickDB Setup
91
+
92
+ 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.
93
+
94
+ === STORE THIS KEY SECURELY -- IT WILL NOT BE DISPLAYED AGAIN ===
95
+ USGwrwK36RM97xiWs6Df1yFuxPLfo4aY
96
+ ===
97
+
98
+ To create a user, send a POST request to the server:
99
+
100
+ fetch('http://localhost:1984/api/users', {
101
+ method: 'POST',
102
+ headers: {
103
+ 'Content-Type': 'application/json',
104
+ 'x-joystick-db-api-key': 'USGwrwK36RM97xiWs6Df1yFuxPLfo4aY'
105
+ },
106
+ body: JSON.stringify({
107
+ username: 'admin',
108
+ password: 'your_secure_password',
109
+ role: 'read_write'
110
+ })
111
+ });
112
+ ```
113
+
114
+ **Important**: Save the API key securely - it will not be displayed again and is required for user management operations.
115
+
116
+ ### 3. Create Your First Admin User
117
+
118
+ Use the API key to create an admin user via HTTP:
119
+
120
+ ```javascript
121
+ // Create admin user via HTTP API
122
+ const response = await fetch('http://localhost:1983/api/users', {
123
+ method: 'POST',
124
+ headers: {
125
+ 'Content-Type': 'application/json',
126
+ 'x-joystick-db-api-key': 'your-api-key-from-step-2'
127
+ },
128
+ body: JSON.stringify({
129
+ username: 'admin',
130
+ password: 'your_secure_password',
131
+ role: 'read_write'
132
+ })
133
+ });
134
+
135
+ const result = await response.json();
136
+ console.log('✅ Admin user created:', result);
137
+ ```
138
+
139
+ ### 4. Connect and Use Your Database
140
+
141
+ ```javascript
142
+ import joystickdb from 'joystick-db';
143
+
144
+ const client = joystickdb.client({
145
+ port: 1983,
146
+ authentication: {
147
+ username: 'admin',
148
+ password: 'your_secure_password'
149
+ }
150
+ });
151
+
152
+ client.on('authenticated', async () => {
153
+ console.log('🎉 Connected to JoystickDB!');
154
+
155
+ // NEW: Multi-database support with MongoDB-like chaining
156
+ const users_db = client.db('user_management');
157
+ const users = users_db.collection('users');
158
+
159
+ // Insert a document
160
+ const result = await users.insert_one({
161
+ name: 'John Doe',
162
+ email: 'john@example.com',
163
+ age: 30,
164
+ hobbies: ['reading', 'coding', 'gaming']
165
+ });
166
+
167
+ console.log('✅ User created with ID:', result.inserted_id);
168
+
169
+ // Find the document
170
+ const user = await users.find_one({ name: 'John Doe' });
171
+ console.log('👤 Found user:', user);
172
+
173
+ // Update the document
174
+ await users.update_one(
175
+ { name: 'John Doe' },
176
+ { $set: { age: 31 }, $push: { hobbies: 'photography' } }
177
+ );
178
+
179
+ console.log('✏️ User updated!');
180
+
181
+ // Work with different databases
182
+ const inventory_db = client.db('inventory');
183
+ const products = inventory_db.collection('products');
184
+
185
+ await products.insert_one({
186
+ name: 'Laptop',
187
+ price: 999.99,
188
+ category: 'electronics'
189
+ });
190
+
191
+ console.log('📦 Product added to inventory database!');
192
+ });
193
+ ```
194
+
195
+ ## Server Setup
196
+
197
+ ### Basic Server Configuration
198
+
199
+ JoystickDB uses the `JOYSTICK_DB_SETTINGS` environment variable for configuration. Set this to a JSON string containing your settings:
200
+
201
+ ```bash
202
+ export JOYSTICK_DB_SETTINGS='{
203
+ "port": 1983,
204
+ "database": {
205
+ "path": "./data",
206
+ "auto_map_size": true
207
+ },
208
+ "authentication": {
209
+ "rate_limit": {
210
+ "max_attempts": 5,
211
+ "window_ms": 300000
212
+ }
213
+ },
214
+ "replication": {
215
+ "enabled": false,
216
+ "mode": "async",
217
+ "secondaries": []
218
+ },
219
+ "backup": {
220
+ "enabled": true,
221
+ "schedule": "0 2 * * *",
222
+ "retention_days": 30
223
+ },
224
+ "s3": {
225
+ "region": "us-east-1",
226
+ "bucket": "my-database-backups"
227
+ }
228
+ }'
229
+ ```
230
+
231
+ ### Environment Variables
232
+
233
+ ```bash
234
+ # Core server configuration via JSON
235
+ JOYSTICK_DB_SETTINGS='{"port": 1983, "database": {"path": "./data"}}'
236
+
237
+ # Additional server options
238
+ WORKER_COUNT=4 # Number of worker processes
239
+ NODE_ENV=production # Environment mode
240
+
241
+ # AWS S3 for backups (optional)
242
+ AWS_REGION=us-east-1
243
+ AWS_ACCESS_KEY_ID=your-access-key
244
+ AWS_SECRET_ACCESS_KEY=your-secret-key
245
+ ```
246
+
247
+ ### Programmatic Server Creation
248
+
249
+ ```javascript
250
+ import { create_server } from 'joystick-db/server';
251
+
252
+ const server = await create_server();
253
+
254
+ server.listen(1983, () => {
255
+ console.log('🚀 JoystickDB server running on port 1983');
256
+ });
257
+
258
+ // Graceful shutdown
259
+ process.on('SIGTERM', async () => {
260
+ console.log('🛑 Shutting down gracefully...');
261
+ await server.cleanup();
262
+ server.close();
263
+ });
264
+ ```
265
+
266
+ ## Client Usage
267
+
268
+ ### Connection Options
269
+
270
+ ```javascript
271
+ const client = joystickdb.client({
272
+ host: 'localhost', // Server hostname
273
+ port: 1983, // Server port
274
+ timeout: 5000, // Request timeout (5 seconds)
275
+ reconnect: true, // Auto-reconnect on disconnect
276
+ max_reconnect_attempts: 10, // Max reconnection attempts
277
+ reconnect_delay: 1000, // Initial reconnect delay (1 second)
278
+ authentication: {
279
+ username: 'your-username', // Your database username
280
+ password: 'your-password' // Your database password
281
+ },
282
+ auto_connect: true // Connect automatically when created
283
+ });
284
+ ```
285
+
286
+ ### Event Handling
287
+
288
+ ```javascript
289
+ client.on('connect', () => {
290
+ console.log('🔌 Connected to JoystickDB');
291
+ });
292
+
293
+ client.on('authenticated', () => {
294
+ console.log('🔐 Authentication successful - ready to use!');
295
+ });
296
+
297
+ client.on('error', (error) => {
298
+ console.error('❌ Client error:', error.message);
299
+ });
300
+
301
+ client.on('disconnect', () => {
302
+ console.log('📡 Disconnected from server');
303
+ });
304
+
305
+ client.on('reconnecting', ({ attempt, delay }) => {
306
+ console.log(`🔄 Reconnecting... attempt ${attempt}, delay ${delay}ms`);
307
+ });
308
+ ```
309
+
310
+ ## Multi-Database Operations
311
+
312
+ JoystickDB now supports multiple isolated databases, allowing you to organize your data more effectively. Each database maintains complete isolation with separate collections, indexes, and storage.
313
+
314
+ ### Multi-Database API
315
+
316
+ JoystickDB uses MongoDB's familiar chaining pattern for multi-database operations:
317
+
318
+ ```javascript
319
+ // Connect to different databases
320
+ const user_db = client.db('user_management');
321
+ const inventory_db = client.db('inventory');
322
+ const analytics_db = client.db('analytics');
323
+
324
+ // Each database has its own collections
325
+ const users = user_db.collection('users');
326
+ const profiles = user_db.collection('profiles');
327
+
328
+ const products = inventory_db.collection('products');
329
+ const categories = inventory_db.collection('categories');
330
+
331
+ const events = analytics_db.collection('events');
332
+ const reports = analytics_db.collection('reports');
333
+
334
+ // Operations are completely isolated between databases
335
+ await users.insert_one({ name: 'John', role: 'admin' });
336
+ await products.insert_one({ name: 'Laptop', price: 999 });
337
+ await events.insert_one({ type: 'login', user_id: 'john123' });
338
+
339
+ // Each database maintains separate indexes and statistics
340
+ await users.create_index('email');
341
+ await products.create_index('category');
342
+ await events.create_index('timestamp');
343
+ ```
344
+
345
+ ### Database Management Operations
346
+
347
+ ```javascript
348
+ // List all databases on the server
349
+ const databases = await client.list_databases();
350
+ console.log('📚 Available databases:', databases.databases);
351
+
352
+ // Get database-specific statistics
353
+ const user_db = client.db('user_management');
354
+ const stats = await user_db.get_stats();
355
+ console.log('📊 User DB stats:', stats);
356
+
357
+ // List collections in a specific database
358
+ const collections = await user_db.list_collections();
359
+ console.log('📋 Collections in user_management:', collections.collections);
360
+
361
+ // Create a collection explicitly (optional - collections are created automatically)
362
+ await user_db.create_collection('audit_logs', {
363
+ // Collection options can be specified here
364
+ });
365
+
366
+ // Drop an entire database (admin operation - use with caution!)
367
+ await user_db.drop_database();
368
+ console.log('🗑️ Database dropped');
369
+ ```
370
+
371
+ ### Database Naming Rules
372
+
373
+ Database names must follow these rules:
374
+
375
+ - Must be 1-64 characters long
376
+ - Can contain letters, numbers, underscores, and hyphens
377
+ - Cannot start with a number
378
+ - Cannot be reserved names: `admin`, `config`, `local`
379
+
380
+ ```javascript
381
+ // Valid database names
382
+ const app_db = client.db('my_app');
383
+ const user_data = client.db('user-data');
384
+ const analytics2024 = client.db('analytics_2024');
385
+
386
+ // Invalid database names (will throw errors)
387
+ // client.db('admin'); // Reserved name
388
+ // client.db('123invalid'); // Starts with number
389
+ // client.db(''); // Empty name
390
+ // client.db('a'.repeat(65)); // Too long
391
+ ```
392
+
393
+
394
+ ## Database Operations
395
+
396
+ JoystickDB provides a clean, MongoDB-like chaining API for multi-database operations.
397
+
398
+ ### Multi-Database Chaining API
399
+
400
+ Work with JoystickDB across multiple databases using the intuitive chaining pattern:
401
+
402
+ ```javascript
403
+ // Get database and collection references
404
+ const user_db = client.db('user_management');
405
+ const inventory_db = client.db('inventory');
406
+
407
+ const users = user_db.collection('users');
408
+ const products = inventory_db.collection('products');
409
+
410
+ // Insert documents into different databases
411
+ const user = await users.insert_one({
412
+ name: 'Alice Smith',
413
+ email: 'alice@example.com',
414
+ age: 28,
415
+ tags: ['developer', 'javascript'],
416
+ created_at: new Date()
417
+ });
418
+
419
+ const product = await products.insert_one({
420
+ name: 'Wireless Mouse',
421
+ price: 29.99,
422
+ category: 'electronics',
423
+ stock: 150
424
+ });
425
+
426
+ console.log('👤 Created user in user_management DB:', user.inserted_id);
427
+ console.log('📦 Created product in inventory DB:', product.inserted_id);
428
+
429
+ // Bulk operations across databases
430
+ const user_bulk = await users.bulk_write([
431
+ { insert_one: { document: { name: 'Bob', age: 25, role: 'designer' } } },
432
+ { insert_one: { document: { name: 'Carol', age: 30, role: 'manager' } } },
433
+ { insert_one: { document: { name: 'Dave', age: 35, role: 'developer' } } }
434
+ ]);
435
+
436
+ const product_bulk = await products.bulk_write([
437
+ { insert_one: { document: { name: 'Keyboard', price: 79.99, category: 'electronics' } } },
438
+ { insert_one: { document: { name: 'Monitor', price: 299.99, category: 'electronics' } } }
439
+ ]);
440
+
441
+ console.log('👥 Created users:', user_bulk.inserted_count);
442
+ console.log('📦 Created products:', product_bulk.inserted_count);
443
+ ```
444
+
445
+ ### Finding Documents Across Databases
446
+
447
+ ```javascript
448
+ const user_db = client.db('user_management');
449
+ const inventory_db = client.db('inventory');
450
+
451
+ const users = user_db.collection('users');
452
+ const products = inventory_db.collection('products');
453
+
454
+ // Find in user database
455
+ const alice = await users.find_one({ name: 'Alice Smith' });
456
+ console.log('Found Alice in user DB:', alice);
457
+
458
+ // Find in inventory database
459
+ const electronics = await products.find({
460
+ category: 'electronics',
461
+ price: { $lte: 100 }
462
+ });
463
+ console.log('Found affordable electronics:', electronics.documents);
464
+
465
+ // Each database maintains separate query performance
466
+ const recent_users = await users.find({}, {
467
+ sort: { created_at: -1 },
468
+ limit: 10
469
+ });
470
+
471
+ const expensive_products = await products.find({
472
+ price: { $gte: 200 }
473
+ }, {
474
+ sort: { price: -1 },
475
+ limit: 5
476
+ });
477
+ ```
478
+
479
+ ### Updating and Deleting Across Databases
480
+
481
+ ```javascript
482
+ const user_db = client.db('user_management');
483
+ const inventory_db = client.db('inventory');
484
+
485
+ const users = user_db.collection('users');
486
+ const products = inventory_db.collection('products');
487
+
488
+ // Update in user database
489
+ await users.update_one(
490
+ { name: 'Alice Smith' },
491
+ {
492
+ $set: {
493
+ age: 29,
494
+ last_updated: new Date(),
495
+ status: 'active'
496
+ },
497
+ $push: { tags: 'senior' }
498
+ }
499
+ );
500
+
501
+ // Update in inventory database
502
+ await products.update_one(
503
+ { name: 'Wireless Mouse' },
504
+ {
505
+ $set: { price: 24.99 },
506
+ $inc: { stock: -5 }
507
+ }
508
+ );
509
+
510
+ // Delete from user database
511
+ await users.delete_one({
512
+ status: 'inactive',
513
+ last_login: { $lt: new Date(Date.now() - 365*24*60*60*1000) }
514
+ });
515
+
516
+ // Delete from inventory database
517
+ await products.delete_one({
518
+ stock: { $lte: 0 },
519
+ discontinued: true
520
+ });
521
+ ```
522
+
523
+
524
+ ### Query Operators (MongoDB-style)
525
+
526
+ All query operators work consistently across all databases:
527
+
528
+ ```javascript
529
+ const user_db = client.db('user_management');
530
+ const inventory_db = client.db('inventory');
531
+
532
+ const users = user_db.collection('users');
533
+ const products = inventory_db.collection('products');
534
+
535
+ // Comparison operators work in any database
536
+ await users.find({ age: { $gt: 25 } });
537
+ await products.find({ price: { $gte: 50, $lte: 200 } });
538
+
539
+ // Text matching with regular expressions
540
+ await users.find({
541
+ name: { $regex: '^John' }
542
+ });
543
+
544
+ await products.find({
545
+ name: { $regex: 'wireless', $options: 'i' } // Case insensitive
546
+ });
547
+
548
+ // Array operations
549
+ await users.find({
550
+ tags: { $in: ['developer', 'designer'] }
551
+ });
552
+
553
+ await products.find({
554
+ categories: { $all: ['electronics', 'accessories'] }
555
+ });
556
+
557
+ // Complex queries across databases
558
+ await users.find({
559
+ age: { $gte: 25, $lte: 35 },
560
+ tags: { $in: ['developer', 'designer'] },
561
+ status: 'active',
562
+ name: { $regex: 'Smith$' }
563
+ });
564
+
565
+ await products.find({
566
+ price: { $gte: 100 },
567
+ category: 'electronics',
568
+ stock: { $gt: 0 },
569
+ name: { $regex: 'pro', $options: 'i' }
570
+ });
571
+ ```
572
+
573
+ ## Indexing
574
+
575
+ Indexes work independently within each database, providing optimal performance for database-specific query patterns.
576
+
577
+ ### Automatic Indexing (Per Database)
578
+
579
+ JoystickDB automatically creates indexes based on query patterns within each database:
580
+
581
+ ```javascript
582
+ const user_db = client.db('user_management');
583
+ const inventory_db = client.db('inventory');
584
+
585
+ const users = user_db.collection('users');
586
+ const products = inventory_db.collection('products');
587
+
588
+ // First query in user database - might be slow
589
+ const user1 = await users.find_one({ email: 'john@example.com' });
590
+
591
+ // JoystickDB creates index for user database email queries
592
+ const user2 = await users.find_one({ email: 'jane@example.com' }); // Much faster!
593
+
594
+ // Separate automatic indexing for inventory database
595
+ const product1 = await products.find_one({ sku: 'MOUSE001' });
596
+ const product2 = await products.find_one({ sku: 'KEYBOARD002' }); // Auto-indexed!
597
+
598
+ // Each database maintains its own automatic indexing statistics
599
+ ```
600
+
601
+ ### Manual Index Management (Per Database)
602
+
603
+ Create and manage indexes independently for each database:
604
+
605
+ ```javascript
606
+ const user_db = client.db('user_management');
607
+ const inventory_db = client.db('inventory');
608
+
609
+ const users = user_db.collection('users');
610
+ const products = inventory_db.collection('products');
611
+
612
+ // Create indexes in user database
613
+ await users.create_index('email');
614
+ await users.create_index('username', { unique: true });
615
+ console.log('📇 User database indexes created');
616
+
617
+ // Create indexes in inventory database
618
+ await products.create_index('sku', { unique: true });
619
+ await products.create_index('category');
620
+ await products.create_index('price');
621
+ console.log('📇 Inventory database indexes created');
622
+
623
+ // List indexes for each database separately
624
+ const user_indexes = await users.get_indexes();
625
+ const product_indexes = await products.get_indexes();
626
+
627
+ console.log('📋 User DB indexes:', user_indexes.indexes);
628
+ console.log('📋 Inventory DB indexes:', product_indexes.indexes);
629
+
630
+ // Drop indexes independently
631
+ await users.drop_index('email');
632
+ await products.drop_index('category');
633
+ ```
634
+
635
+ ### Cross-Database Index Isolation
636
+
637
+ Indexes are completely isolated between databases:
638
+
639
+ ```javascript
640
+ const db1 = client.db('database1');
641
+ const db2 = client.db('database2');
642
+
643
+ const collection1 = db1.collection('items');
644
+ const collection2 = db2.collection('items');
645
+
646
+ // Create index in database1 only
647
+ await collection1.create_index('name');
648
+
649
+ // This collection in database2 has no indexes yet
650
+ const items1 = await collection1.find({ name: 'test' }); // Uses index
651
+ const items2 = await collection2.find({ name: 'test' }); // No index, full scan
652
+
653
+ // Create separate index in database2
654
+ await collection2.create_index('name');
655
+
656
+ // Now both have independent indexes
657
+ const items1_fast = await collection1.find({ name: 'test' }); // Uses db1 index
658
+ const items2_fast = await collection2.find({ name: 'test' }); // Uses db2 index
659
+ ```
660
+
661
+ ### Index Performance Benefits
662
+
663
+ ```javascript
664
+ const inventory_db = client.db('inventory');
665
+ const products = inventory_db.collection('products');
666
+
667
+ // Without index: Searches through ALL products (slow for large datasets)
668
+ const expensive_products = await products.find({ price: { $gte: 1000 } });
669
+
670
+ // Create index on price
671
+ await products.create_index('price');
672
+
673
+ // With index: Jumps directly to expensive products (super fast!)
674
+ const expensive_products_fast = await products.find({ price: { $gte: 1000 } });
675
+
676
+ // Compound queries benefit from multiple indexes
677
+ await products.create_index('category');
678
+ const gaming_laptops = await products.find({
679
+ category: 'laptops',
680
+ price: { $gte: 800 }
681
+ }); // Uses both category and price indexes
682
+ ```
683
+
684
+ ## HTTP API
685
+
686
+ JoystickDB provides RESTful HTTP endpoints for user management and external integrations. The HTTP API uses API key authentication for secure access.
687
+
688
+ ### Authentication
689
+
690
+ All HTTP API requests require an API key in the `x-joystick-db-api-key` header:
691
+
692
+ ```javascript
693
+ const headers = {
694
+ 'Content-Type': 'application/json',
695
+ 'x-joystick-db-api-key': 'your-api-key-here'
696
+ };
697
+ ```
698
+
699
+ ### User Management Endpoints
700
+
701
+ #### Create User
702
+
703
+ Create a new user with username, password, and role.
704
+
705
+ ```http
706
+ POST /api/users
707
+ Content-Type: application/json
708
+ x-joystick-db-api-key: your-api-key
709
+
710
+ {
711
+ "username": "john_doe",
712
+ "password": "secure_password123",
713
+ "role": "read_write"
714
+ }
715
+ ```
716
+
717
+ **Response:**
718
+ ```json
719
+ {
720
+ "success": true,
721
+ "message": "User created successfully",
722
+ "username": "john_doe",
723
+ "role": "read_write"
724
+ }
725
+ ```
726
+
727
+ **Roles:**
728
+ - `read` - Can only read data from all databases
729
+ - `write` - Can only write data to all databases
730
+ - `read_write` - Can read and write data to all databases (admin privileges)
731
+
732
+ #### Get User
733
+
734
+ Retrieve user information by username.
735
+
736
+ ```http
737
+ GET /api/users?username=john_doe
738
+ x-joystick-db-api-key: your-api-key
739
+ ```
740
+
741
+ **Response:**
742
+ ```json
743
+ {
744
+ "success": true,
745
+ "user": {
746
+ "username": "john_doe",
747
+ "role": "read_write",
748
+ "created_at": "2024-01-15T10:30:00.000Z"
749
+ }
750
+ }
751
+ ```
752
+
753
+ #### Update User
754
+
755
+ Update user password or role.
756
+
757
+ ```http
758
+ PUT /api/users
759
+ Content-Type: application/json
760
+ x-joystick-db-api-key: your-api-key
761
+
762
+ {
763
+ "username": "john_doe",
764
+ "password": "new_secure_password456",
765
+ "role": "read"
766
+ }
767
+ ```
768
+
769
+ **Response:**
770
+ ```json
771
+ {
772
+ "success": true,
773
+ "message": "User updated successfully",
774
+ "username": "john_doe",
775
+ "updates": ["password", "role"]
776
+ }
777
+ ```
778
+
779
+ #### Delete User
780
+
781
+ Remove a user from the system.
782
+
783
+ ```http
784
+ DELETE /api/users?username=john_doe
785
+ x-joystick-db-api-key: your-api-key
786
+ ```
787
+
788
+ **Response:**
789
+ ```json
790
+ {
791
+ "success": true,
792
+ "message": "User deleted successfully",
793
+ "username": "john_doe"
794
+ }
795
+ ```
796
+
797
+ ### HTTP API Examples
798
+
799
+ #### JavaScript/Node.js
800
+
801
+ ```javascript
802
+ const API_KEY = 'your-api-key-here';
803
+ const BASE_URL = 'http://localhost:1983';
804
+
805
+ // Create user
806
+ const create_user = async (username, password, role) => {
807
+ const response = await fetch(`${BASE_URL}/api/users`, {
808
+ method: 'POST',
809
+ headers: {
810
+ 'Content-Type': 'application/json',
811
+ 'x-joystick-db-api-key': API_KEY
812
+ },
813
+ body: JSON.stringify({ username, password, role })
814
+ });
815
+
816
+ return await response.json();
817
+ };
818
+
819
+ // Get user
820
+ const get_user = async (username) => {
821
+ const response = await fetch(`${BASE_URL}/api/users?username=${username}`, {
822
+ headers: {
823
+ 'x-joystick-db-api-key': API_KEY
824
+ }
825
+ });
826
+
827
+ return await response.json();
828
+ };
829
+
830
+ // Update user
831
+ const update_user = async (username, updates) => {
832
+ const response = await fetch(`${BASE_URL}/api/users`, {
833
+ method: 'PUT',
834
+ headers: {
835
+ 'Content-Type': 'application/json',
836
+ 'x-joystick-db-api-key': API_KEY
837
+ },
838
+ body: JSON.stringify({ username, ...updates })
839
+ });
840
+
841
+ return await response.json();
842
+ };
843
+
844
+ // Delete user
845
+ const delete_user = async (username) => {
846
+ const response = await fetch(`${BASE_URL}/api/users?username=${username}`, {
847
+ method: 'DELETE',
848
+ headers: {
849
+ 'x-joystick-db-api-key': API_KEY
850
+ }
851
+ });
852
+
853
+ return await response.json();
854
+ };
855
+
856
+ // Usage examples
857
+ const demo = async () => {
858
+ // Create a new user
859
+ const create_result = await create_user('alice', 'secure123', 'read_write');
860
+ console.log('User created:', create_result);
861
+
862
+ // Get user info
863
+ const user_info = await get_user('alice');
864
+ console.log('User info:', user_info);
865
+
866
+ // Update user role
867
+ const update_result = await update_user('alice', { role: 'read' });
868
+ console.log('User updated:', update_result);
869
+
870
+ // Delete user
871
+ const delete_result = await delete_user('alice');
872
+ console.log('User deleted:', delete_result);
873
+ };
874
+ ```
875
+
876
+ #### cURL Examples
877
+
878
+ ```bash
879
+ # Create user
880
+ curl -X POST http://localhost:1983/api/users \
881
+ -H "Content-Type: application/json" \
882
+ -H "x-joystick-db-api-key: your-api-key-here" \
883
+ -d '{"username": "alice", "password": "secure123", "role": "read_write"}'
884
+
885
+ # Get user
886
+ curl -X GET "http://localhost:1983/api/users?username=alice" \
887
+ -H "x-joystick-db-api-key: your-api-key-here"
888
+
889
+ # Update user
890
+ curl -X PUT http://localhost:1983/api/users \
891
+ -H "Content-Type: application/json" \
892
+ -H "x-joystick-db-api-key: your-api-key-here" \
893
+ -d '{"username": "alice", "role": "read"}'
894
+
895
+ # Delete user
896
+ curl -X DELETE "http://localhost:1983/api/users?username=alice" \
897
+ -H "x-joystick-db-api-key: your-api-key-here"
898
+ ```
899
+
900
+ ### Error Responses
901
+
902
+ The HTTP API returns consistent error responses:
903
+
904
+ ```json
905
+ {
906
+ "success": false,
907
+ "error": "Invalid API key"
908
+ }
909
+ ```
910
+
911
+ **Common Error Codes:**
912
+ - `400` - Bad Request (invalid data)
913
+ - `401` - Unauthorized (invalid API key)
914
+ - `404` - Not Found (user doesn't exist)
915
+ - `409` - Conflict (user already exists)
916
+ - `500` - Internal Server Error
917
+
918
+ ## Replication
919
+
920
+ Replication creates copies of your database on multiple servers for high availability and better performance. Multi-database support is fully compatible with replication.
921
+
922
+ ### How Replication Works
923
+
924
+ - **Primary Node**: The main database that handles all writes across all databases
925
+ - **Secondary Nodes**: Read-only copies that stay in sync with the primary for all databases
926
+ - **Write Forwarding**: Secondary nodes can forward write requests to the primary
927
+ - **Automatic Sync**: Changes on primary are automatically copied to secondaries for all databases
928
+ - **Database Isolation**: Replication maintains database separation on all nodes
929
+
930
+ ### Setting Up Replication
931
+
932
+ #### 1. Configure Primary Node
933
+
934
+ ```bash
935
+ # Primary server configuration via JOYSTICK_DB_SETTINGS
936
+ export JOYSTICK_DB_SETTINGS='{
937
+ "port": 1983,
938
+ "replication": {
939
+ "enabled": true,
940
+ "mode": "async",
941
+ "timeout_ms": 5000,
942
+ "batch_size": 100,
943
+ "secondaries": [
944
+ {
945
+ "id": "secondary-1",
946
+ "ip": "192.168.1.100",
947
+ "port": 1984,
948
+ "private_key": "base64-encoded-private-key",
949
+ "enabled": true
950
+ },
951
+ {
952
+ "id": "secondary-2",
953
+ "ip": "192.168.1.101",
954
+ "port": 1984,
955
+ "private_key": "base64-encoded-private-key",
956
+ "enabled": true
957
+ }
958
+ ]
959
+ }
960
+ }'
961
+ ```
962
+
963
+ #### 2. Configure Secondary Nodes
964
+
965
+ ```bash
966
+ # Secondary server configuration via JOYSTICK_DB_SETTINGS
967
+ export JOYSTICK_DB_SETTINGS='{
968
+ "port": 1984,
969
+ "write_forwarder": {
970
+ "enabled": true,
971
+ "primary": {
972
+ "ip": "192.168.1.10",
973
+ "port": 1983,
974
+ "private_key": "base64-encoded-private-key"
975
+ }
976
+ }
977
+ }'
978
+ ```
979
+
980
+ ### Managing Replication
981
+
982
+ ```javascript
983
+ // Connect to primary node
984
+ const client = joystickdb.client({
985
+ port: 1983,
986
+ authentication: {
987
+ username: 'admin',
988
+ password: 'your-password'
989
+ }
990
+ });
991
+
992
+ // Check replication status
993
+ const status = await client.get_replication_status();
994
+ console.log('🔄 Replication enabled:', status.enabled);
995
+ console.log('📡 Connected secondaries:', status.connected_secondaries);
996
+ console.log('📊 Queue length:', status.queue_length);
997
+
998
+ // Add a new secondary node dynamically
999
+ await client.add_secondary({
1000
+ id: 'secondary-3',
1001
+ ip: '192.168.1.102',
1002
+ port: 1984,
1003
+ private_key: 'base64-encoded-private-key'
1004
+ });
1005
+
1006
+ // Check health of secondary nodes
1007
+ const health = await client.get_secondary_health();
1008
+ console.log('💚 Healthy secondaries:', health.healthy_secondaries);
1009
+ console.log('📈 Total secondaries:', health.total_secondaries);
1010
+
1011
+ // Force synchronization with all secondaries
1012
+ await client.sync_secondaries();
1013
+ console.log('🔄 Forced sync completed');
1014
+
1015
+ // Remove a secondary node
1016
+ await client.remove_secondary('secondary-1');
1017
+ console.log('➖ Secondary removed');
1018
+ ```
1019
+
1020
+ ### Using Replication for Read Scaling
1021
+
1022
+ ```javascript
1023
+ // Connect to primary for writes
1024
+ const primary = joystickdb.client({
1025
+ host: '192.168.1.10',
1026
+ port: 1983,
1027
+ authentication: {
1028
+ username: 'admin',
1029
+ password: 'your-password'
1030
+ }
1031
+ });
1032
+
1033
+ // Connect to secondary for reads (better performance)
1034
+ const secondary = joystickdb.client({
1035
+ host: '192.168.1.100',
1036
+ port: 1984,
1037
+ authentication: {
1038
+ username: 'admin',
1039
+ password: 'your-password'
1040
+ }
1041
+ });
1042
+
1043
+ // Write to primary (all databases replicated)
1044
+ const user_db = primary.db('user_management');
1045
+ const inventory_db = primary.db('inventory');
1046
+
1047
+ await user_db.collection('users').insert_one({
1048
+ name: 'New User',
1049
+ email: 'new@example.com'
1050
+ });
1051
+
1052
+ await inventory_db.collection('products').insert_one({
1053
+ name: 'New Product',
1054
+ price: 99.99
1055
+ });
1056
+
1057
+ // Read from secondary (reduces load on primary, all databases available)
1058
+ const secondary_user_db = secondary.db('user_management');
1059
+ const secondary_inventory_db = secondary.db('inventory');
1060
+
1061
+ const users = await secondary_user_db.collection('users').find({});
1062
+ const products = await secondary_inventory_db.collection('products').find({});
1063
+
1064
+ console.log('👥 Users from secondary:', users.documents.length);
1065
+ console.log('📦 Products from secondary:', products.documents.length);
1066
+ ```
1067
+
1068
+ ## Administration
1069
+
1070
+ ### Database Statistics and Monitoring
1071
+
1072
+ ```javascript
1073
+ // Get comprehensive server statistics
1074
+ const stats = await client.get_stats();
1075
+
1076
+ console.log('🖥️ Server Info:');
1077
+ console.log(' Uptime:', stats.server.uptime_formatted);
1078
+ console.log(' Version:', stats.server.version);
1079
+ console.log(' Node.js:', stats.server.node_version);
1080
+
1081
+ console.log('💾 Memory Usage:');
1082
+ console.log(' Heap Used:', Math.round(stats.memory.heapUsed / 1024 / 1024), 'MB');
1083
+ console.log(' Heap Total:', Math.round(stats.memory.heapTotal / 1024 / 1024), 'MB');
1084
+
1085
+ console.log('🗄️ Database:');
1086
+ console.log(' Size:', stats.database.used_space_mb, 'MB');
1087
+ console.log(' Databases:', stats.database.databases);
1088
+ console.log(' Collections:', stats.database.collections);
1089
+
1090
+ console.log('⚡ Performance:');
1091
+ console.log(' Operations/sec:', stats.performance.ops_per_second);
1092
+ console.log(' Avg Response Time:', stats.performance.avg_response_time_ms, 'ms');
1093
+
1094
+ console.log('🔌 Connections:');
1095
+ console.log(' Active:', stats.connections.active);
1096
+ console.log(' Total:', stats.connections.total);
1097
+ ```
1098
+
1099
+ ### Multi-Database Administration
1100
+
1101
+ ```javascript
1102
+ // List all databases on the server
1103
+ const databases = await client.list_databases();
1104
+ console.log('📚 Available databases:', databases.databases);
1105
+
1106
+ // Get statistics for a specific database
1107
+ const user_db = client.db('user_management');
1108
+ const user_db_stats = await user_db.get_stats();
1109
+ console.log('📊 User management DB stats:', user_db_stats);
1110
+
1111
+ // List collections in each database
1112
+ for (const db_name of databases.databases) {
1113
+ const db = client.db(db_name);
1114
+ const collections = await db.list_collections();
1115
+ console.log(`📋 Collections in ${db_name}:`, collections.collections);
1116
+ }
1117
+
1118
+ // Create collections explicitly in different databases
1119
+ const analytics_db = client.db('analytics');
1120
+ await analytics_db.create_collection('events');
1121
+ await analytics_db.create_collection('reports');
1122
+
1123
+ const inventory_db = client.db('inventory');
1124
+ await inventory_db.create_collection('products');
1125
+ await inventory_db.create_collection('categories');
1126
+ ```
1127
+
1128
+ ### Collection and Document Management
1129
+
1130
+ ```javascript
1131
+ // List documents across different databases
1132
+ const user_db = client.db('user_management');
1133
+ const inventory_db = client.db('inventory');
1134
+
1135
+ // List documents in user management database
1136
+ const user_docs = await client.list_documents('users', {
1137
+ database: 'user_management',
1138
+ limit: 50,
1139
+ skip: 0,
1140
+ sort_field: 'created_at',
1141
+ sort_order: 'desc'
1142
+ });
1143
+
1144
+ // List documents in inventory database
1145
+ const product_docs = await client.list_documents('products', {
1146
+ database: 'inventory',
1147
+ limit: 50,
1148
+ skip: 0,
1149
+ sort_field: 'price',
1150
+ sort_order: 'asc'
1151
+ });
1152
+
1153
+ console.log('📄 User documents:', user_docs.documents.length);
1154
+ console.log('📄 Product documents:', product_docs.documents.length);
1155
+
1156
+ // Get specific documents by ID from different databases
1157
+ const user_doc = await client.get_document('users', 'user-id-here', 'user_management');
1158
+ const product_doc = await client.get_document('products', 'product-id-here', 'inventory');
1159
+
1160
+ // Advanced document querying across databases
1161
+ const active_users = await client.query_documents('users', {
1162
+ status: 'active',
1163
+ last_login: { $gte: new Date(Date.now() - 30*24*60*60*1000) }
1164
+ }, {
1165
+ database: 'user_management',
1166
+ limit: 100,
1167
+ sort: { last_login: -1 }
1168
+ });
1169
+
1170
+ const expensive_products = await client.query_documents('products', {
1171
+ price: { $gte: 500 },
1172
+ stock: { $gt: 0 }
1173
+ }, {
1174
+ database: 'inventory',
1175
+ limit: 50,
1176
+ sort: { price: -1 }
1177
+ });
1178
+ ```
1179
+
1180
+ ### Health Checks and Monitoring
1181
+
1182
+ ```javascript
1183
+ // Simple health check
1184
+ const ping_result = await client.ping();
1185
+ if (ping_result.ok === 1) {
1186
+ console.log('✅ Database is healthy');
1187
+ } else {
1188
+ console.log('❌ Database is not responding');
1189
+ }
1190
+
1191
+ // Reload server configuration without restart
1192
+ const reload_result = await client.reload();
1193
+ console.log('🔄 Configuration reloaded:', reload_result.message);
1194
+
1195
+ // Monitor performance over time
1196
+ setInterval(async () => {
1197
+ const stats = await client.get_stats();
1198
+ console.log(`📊 ${new Date().toISOString()}: ${stats.performance.ops_per_second} ops/sec, ${stats.connections.active} connections, ${stats.database.databases} databases`);
1199
+ }, 30000); // Every 30 seconds
1200
+ ```
1201
+
1202
+ ## Backup & Restore
1203
+
1204
+ JoystickDB includes automatic backup capabilities with S3 integration. Backups include all databases and maintain database isolation during restore operations.
1205
+
1206
+ ### Automatic Backups
1207
+
1208
+ Configure automatic backups via the `JOYSTICK_DB_SETTINGS` environment variable:
1209
+
1210
+ ```bash
1211
+ export JOYSTICK_DB_SETTINGS='{
1212
+ "backup": {
1213
+ "enabled": true,
1214
+ "schedule": "0 2 * * *",
1215
+ "retention_days": 30,
1216
+ "compression": true
1217
+ },
1218
+ "s3": {
1219
+ "region": "us-east-1",
1220
+ "bucket": "my-database-backups",
1221
+ "access_key_id": "your-access-key",
1222
+ "secret_access_key": "your-secret-key"
1223
+ }
1224
+ }'
1225
+ ```
1226
+
1227
+ ### Manual Backup Operations
1228
+
1229
+ ```javascript
1230
+ // Create an immediate backup (includes all databases)
1231
+ const backup_result = await client.backup_now();
1232
+ console.log('💾 Backup created:', backup_result.filename);
1233
+ console.log('📊 Backup size:', backup_result.size_mb, 'MB');
1234
+ console.log('⏱️ Time taken:', backup_result.duration_ms, 'ms');
1235
+ console.log('🗄️ Databases backed up:', backup_result.databases_count);
1236
+
1237
+ // List all available backups
1238
+ const backups = await client.list_backups();
1239
+ console.log('📋 Available backups:');
1240
+ backups.backups.forEach(backup => {
1241
+ console.log(` 📦 ${backup.filename} (${backup.size_mb} MB) - ${backup.created_at}`);
1242
+ console.log(` Databases: ${backup.databases_count}, Collections: ${backup.collections_count}`);
1243
+ });
1244
+
1245
+ // Restore from a specific backup (restores all databases)
1246
+ const restore_result = await client.restore_backup('backup-2024-01-15-02-00-00.tar.gz');
1247
+ console.log('🔄 Restore completed in:', restore_result.duration_ms, 'ms');
1248
+ console.log('🗄️ Restored databases:', restore_result.databases_restored);
1249
+ console.log('📊 Restored collections:', restore_result.collections_restored);
1250
+ ```
1251
+
1252
+ ### Backup Best Practices
1253
+
1254
+ ```javascript
1255
+ // Test your backups regularly
1256
+ const test_backup = async () => {
1257
+ console.log('🧪 Testing backup system...');
1258
+
1259
+ // Create a test backup
1260
+ const backup = await client.backup_now();
1261
+ console.log('✅ Backup created successfully');
1262
+
1263
+ // Verify backup exists and contains all databases
1264
+ const backups = await client.list_backups();
1265
+ const latest = backups.backups.find(b => b.filename === backup.filename);
1266
+
1267
+ if (latest && latest.size_mb > 0 && latest.databases_count > 0) {
1268
+ console.log('✅ Backup verification passed');
1269
+ console.log(`📊 Backup contains ${latest.databases_count} databases`);
1270
+ } else {
1271
+ console.log('❌ Backup verification failed');
1272
+ }
1273
+ };
1274
+
1275
+ // Run backup test monthly
1276
+ setInterval(test_backup, 30 * 24 * 60 * 60 * 1000); // 30 days
1277
+ ```
1278
+
1279
+ ## Configuration
1280
+
1281
+ ### Complete Configuration Reference
1282
+
1283
+ ```json
1284
+ {
1285
+ "port": 1983,
1286
+ "cluster": true,
1287
+ "worker_count": 4,
1288
+
1289
+ "database": {
1290
+ "path": "./data",
1291
+ "auto_map_size": true,
1292
+ "map_size": 1073741824,
1293
+ "max_dbs": 100
1294
+ },
1295
+
1296
+ "authentication": {
1297
+ "rate_limit": {
1298
+ "max_attempts": 5,
1299
+ "window_ms": 300000,
1300
+ "lockout_duration_ms": 900000
1301
+ }
1302
+ },
1303
+
1304
+ "replication": {
1305
+ "enabled": false,
1306
+ "mode": "async",
1307
+ "timeout_ms": 5000,
1308
+ "retry_attempts": 3,
1309
+ "batch_size": 100,
1310
+ "secondaries": []
1311
+ },
1312
+
1313
+ "write_forwarder": {
1314
+ "enabled": false,
1315
+ "primary": {
1316
+ "ip": "127.0.0.1",
1317
+ "port": 1983,
1318
+ "private_key": "base64-encoded-key"
1319
+ },
1320
+ "timeout_ms": 5000,
1321
+ "retry_attempts": 3
1322
+ },
1323
+
1324
+ "s3": {
1325
+ "region": "us-east-1",
1326
+ "bucket": "my-backups",
1327
+ "access_key_id": "AKIA...",
1328
+ "secret_access_key": "...",
1329
+ "endpoint": "https://s3.amazonaws.com"
1330
+ },
1331
+
1332
+ "backup": {
1333
+ "enabled": true,
1334
+ "schedule": "0 2 * * *",
1335
+ "retention_days": 30,
1336
+ "compression": true
1337
+ },
1338
+
1339
+ "logging": {
1340
+ "level": "info",
1341
+ "file": "./logs/joystickdb.log",
1342
+ "max_size": "20m",
1343
+ "max_files": "14d"
1344
+ },
1345
+
1346
+ "performance": {
1347
+ "connection_pool_size": 1000,
1348
+ "idle_timeout": 600000,
1349
+ "request_timeout": 5000,
1350
+ "auto_index_threshold": 3
1351
+ }
1352
+ }
1353
+ ```
1354
+
1355
+ ### Environment Variable Overrides
1356
+
1357
+ ```bash
1358
+ # Server settings
1359
+ JOYSTICKDB_PORT=1983
1360
+ JOYSTICKDB_CLUSTER=true
1361
+ JOYSTICKDB_WORKER_COUNT=4
1362
+
1363
+ # Database settings
1364
+ JOYSTICKDB_DATABASE_PATH=./data
1365
+ JOYSTICKDB_DATABASE_AUTO_MAP_SIZE=true
1366
+ JOYSTICKDB_DATABASE_MAX_DBS=100
1367
+
1368
+ # Replication settings
1369
+ JOYSTICKDB_REPLICATION_ENABLED=false
1370
+ JOYSTICKDB_REPLICATION_MODE=async
1371
+
1372
+ # S3 settings
1373
+ JOYSTICKDB_S3_REGION=us-east-1
1374
+ JOYSTICKDB_S3_BUCKET=my-backups
1375
+ AWS_ACCESS_KEY_ID=your-access-key
1376
+ AWS_SECRET_ACCESS_KEY=your-secret-key
1377
+
1378
+ # Backup settings
1379
+ JOYSTICKDB_BACKUP_ENABLED=true
1380
+ JOYSTICKDB_BACKUP_RETENTION_DAYS=30
1381
+
1382
+ # Logging
1383
+ JOYSTICKDB_LOG_LEVEL=info
1384
+ ```
1385
+
1386
+ ## Production Deployment
1387
+
1388
+ ### Docker Deployment
1389
+
1390
+ ```dockerfile
1391
+ FROM node:18-alpine
1392
+
1393
+ WORKDIR /app
1394
+
1395
+ # Install dependencies
1396
+ COPY package*.json ./
1397
+ RUN npm ci --only=production
1398
+
1399
+ # Copy application code
1400
+ COPY . .
1401
+
1402
+ # Create data and logs directories
1403
+ RUN mkdir -p data logs
1404
+
1405
+ # Expose port
1406
+ EXPOSE 1983
1407
+
1408
+ # Create volumes for persistent data
1409
+ VOLUME ["/app/data", "/app/logs"]
1410
+
1411
+ # Health check
1412
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
1413
+ CMD node -e "
1414
+ const client = require('./src/client/index.js').default.client({port: 1983, timeout: 2000, reconnect: false});
1415
+ client.ping().then(() => process.exit(0)).catch(() => process.exit(1));
1416
+ "
1417
+
1418
+ # Start the server
1419
+ CMD ["npm", "start"]
1420
+ ```
1421
+
1422
+ ### Docker Compose
1423
+
1424
+ ```yaml
1425
+ version: '3.8'
1426
+
1427
+ services:
1428
+ joystickdb:
1429
+ build: .
1430
+ ports:
1431
+ - "1983:1983"
1432
+ volumes:
1433
+ - ./data:/app/data
1434
+ - ./logs:/app/logs
1435
+ environment:
1436
+ - NODE_ENV=production
1437
+ - WORKER_COUNT=4
1438
+ - JOYSTICKDB_LOG_LEVEL=info
1439
+ - JOYSTICK_DB_SETTINGS={"port": 1983, "database": {"path": "./data", "max_dbs": 100}}
1440
+ restart: unless-stopped
1441
+ healthcheck:
1442
+ test: ["CMD", "npm", "run", "health-check"]
1443
+ interval: 30s
1444
+ timeout: 10s
1445
+ retries: 3
1446
+ start_period: 40s
1447
+
1448
+ # Optional: Secondary node for replication
1449
+ joystickdb-secondary:
1450
+ build: .
1451
+ ports:
1452
+ - "1984:1984"
1453
+ volumes:
1454
+ - ./data-secondary:/app/data
1455
+ - ./logs-secondary:/app/logs
1456
+ environment:
1457
+ - NODE_ENV=production
1458
+ - JOYSTICKDB_PORT=1984
1459
+ - JOYSTICK_DB_SETTINGS={"port": 1984, "database": {"path": "./data", "max_dbs": 100}}
1460
+ restart: unless-stopped
1461
+ depends_on:
1462
+ - joystickdb
1463
+ ```
1464
+
1465
+ ### Kubernetes Deployment
1466
+
1467
+ ```yaml
1468
+ apiVersion: apps/v1
1469
+ kind: Deployment
1470
+ metadata:
1471
+ name: joystickdb
1472
+ labels:
1473
+ app: joystickdb
1474
+ spec:
1475
+ replicas: 3
1476
+ selector:
1477
+ matchLabels:
1478
+ app: joystickdb
1479
+ template:
1480
+ metadata:
1481
+ labels:
1482
+ app: joystickdb
1483
+ spec:
1484
+ containers:
1485
+ - name: joystickdb
1486
+ image: joystickdb:latest
1487
+ ports:
1488
+ - containerPort: 1983
1489
+ env:
1490
+ - name: WORKER_COUNT
1491
+ value: "2"
1492
+ - name: NODE_ENV
1493
+ value: "production"
1494
+ - name: JOYSTICKDB_LOG_LEVEL
1495
+ value: "info"
1496
+ - name: JOYSTICK_DB_SETTINGS
1497
+ valueFrom:
1498
+ configMapKeyRef:
1499
+ name: joystickdb-config
1500
+ key: settings.json
1501
+ resources:
1502
+ requests:
1503
+ memory: "256Mi"
1504
+ cpu: "250m"
1505
+ limits:
1506
+ memory: "512Mi"
1507
+ cpu: "500m"
1508
+ volumeMounts:
1509
+ - name: data
1510
+ mountPath: /app/data
1511
+ livenessProbe:
1512
+ exec:
1513
+ command:
1514
+ - npm
1515
+ - run
1516
+ - health-check
1517
+ initialDelaySeconds: 30
1518
+ periodSeconds: 30
1519
+ readinessProbe:
1520
+ exec:
1521
+ command:
1522
+ - npm
1523
+ - run
1524
+ - health-check
1525
+ initialDelaySeconds: 5
1526
+ periodSeconds: 10
1527
+ volumes:
1528
+ - name: data
1529
+ persistentVolumeClaim:
1530
+ claimName: joystickdb-data
1531
+ ---
1532
+ apiVersion: v1
1533
+ kind: ConfigMap
1534
+ metadata:
1535
+ name: joystickdb-config
1536
+ data:
1537
+ settings.json: |
1538
+ {
1539
+ "port": 1983,
1540
+ "database": {
1541
+ "path": "./data",
1542
+ "auto_map_size": true,
1543
+ "max_dbs": 100
1544
+ },
1545
+ "authentication": {
1546
+ "rate_limit": {
1547
+ "max_attempts": 5,
1548
+ "window_ms": 300000
1549
+ }
1550
+ },
1551
+ "backup": {
1552
+ "enabled": true,
1553
+ "schedule": "0 2 * * *",
1554
+ "retention_days": 30
1555
+ },
1556
+ "logging": {
1557
+ "level": "info"
1558
+ }
1559
+ }
1560
+ ---
1561
+ apiVersion: v1
1562
+ kind: Service
1563
+ metadata:
1564
+ name: joystickdb-service
1565
+ spec:
1566
+ selector:
1567
+ app: joystickdb
1568
+ ports:
1569
+ - port: 1983
1570
+ targetPort: 1983
1571
+ type: LoadBalancer
1572
+ ```
1573
+
1574
+ ### Monitoring and Health Checks
1575
+
1576
+ ```javascript
1577
+ // Health check endpoint
1578
+ const health_check = async () => {
1579
+ try {
1580
+ const client = joystickdb.client({
1581
+ port: 1983,
1582
+ timeout: 2000,
1583
+ reconnect: false
1584
+ });
1585
+
1586
+ const result = await client.ping();
1587
+ client.disconnect();
1588
+
1589
+ return result.ok === 1;
1590
+ } catch (error) {
1591
+ return false;
1592
+ }
1593
+ };
1594
+
1595
+ // Performance monitoring
1596
+ const monitor_performance = async () => {
1597
+ const client = joystickdb.client({
1598
+ port: 1983,
1599
+ authentication: {
1600
+ username: 'admin',
1601
+ password: process.env.DB_PASSWORD
1602
+ }
1603
+ });
1604
+
1605
+ const stats = await client.get_stats();
1606
+
1607
+ // Log metrics to your monitoring system
1608
+ console.log('Metrics:', {
1609
+ uptime: stats.server.uptime,
1610
+ memory_usage: stats.memory.heapUsed,
1611
+ ops_per_second: stats.performance.ops_per_second,
1612
+ active_connections: stats.connections.active,
1613
+ database_count: stats.database.databases,
1614
+ total_collections: stats.database.collections,
1615
+ database_size: stats.database.used_space_mb
1616
+ });
1617
+
1618
+ client.disconnect();
1619
+ };
1620
+ ```
1621
+
1622
+ ## API Reference
1623
+
1624
+ ### Client Methods
1625
+
1626
+ #### Connection Management
1627
+ - `client.connect()` - Establish connection to server
1628
+ - `client.disconnect()` - Close connection to server
1629
+ - `client.ping()` - Test server connectivity and responsiveness
1630
+
1631
+ #### Authentication & Setup
1632
+ - `client.setup()` - Initial server setup (generates password) - **DEPRECATED**
1633
+ - `client.authenticate()` - Manual authentication (usually automatic)
1634
+
1635
+ #### Multi-Database Interface
1636
+ - `client.db(database_name)` - Get database interface for method chaining
1637
+ - `client.list_databases()` - List all databases on the server
1638
+
1639
+ #### Database-Level Operations
1640
+ - `database.collection(collection_name)` - Get collection interface within database
1641
+ - `database.list_collections()` - List collections in the database
1642
+ - `database.get_stats()` - Get database-specific statistics
1643
+ - `database.drop_database()` - Drop the entire database (admin operation)
1644
+ - `database.create_collection(collection_name, options)` - Create collection explicitly
1645
+
1646
+ #### CRUD Operations (Collection Chaining API)
1647
+ - `collection.insert_one(document, options)` - Insert single document
1648
+ - `collection.find_one(filter, options)` - Find single document
1649
+ - `collection.find(filter, options)` - Find multiple documents
1650
+ - `collection.update_one(filter, update, options)` - Update single document
1651
+ - `collection.delete_one(filter, options)` - Delete single document
1652
+ - `collection.bulk_write(operations, options)` - Bulk operations
1653
+
1654
+ #### Index Management (Collection Chaining API)
1655
+ - `collection.create_index(field, options)` - Create index on field
1656
+ - `collection.upsert_index(field, options)` - Create or update index (upsert)
1657
+ - `collection.drop_index(field)` - Drop index on field
1658
+ - `collection.get_indexes()` - List all indexes for collection
1659
+
1660
+ #### Auto-Indexing Management
1661
+ - `client.get_auto_index_stats()` - Get automatic indexing statistics
1662
+
1663
+ #### Replication Management
1664
+ - `client.get_replication_status()` - Get replication status and statistics
1665
+ - `client.add_secondary(secondary_config)` - Add new secondary node
1666
+ - `client.remove_secondary(secondary_id)` - Remove secondary node
1667
+ - `client.sync_secondaries()` - Force synchronization with secondaries
1668
+ - `client.get_secondary_health()` - Get health status of secondary nodes
1669
+ - `client.get_forwarder_status()` - Get write forwarder status (for secondary nodes)
1670
+
1671
+ #### Administration
1672
+ - `client.get_stats()` - Get comprehensive server statistics
1673
+ - `client.list_collections()` - List all collections in default database (backward compatible)
1674
+ - `client.list_documents(collection, options)` - List documents with pagination and sorting
1675
+ - `client.get_document(collection, document_id, database)` - Get document by ID
1676
+ - `client.query_documents(collection, filter, options)` - Advanced document query with filtering
1677
+ - `client.insert_document(collection, document)` - Admin insert operation
1678
+ - `client.update_document(collection, document_id, update)` - Admin update operation by ID
1679
+ - `client.delete_document(collection, document_id)` - Admin delete operation by ID
1680
+
1681
+ #### Backup & Restore
1682
+ - `client.backup_now()` - Create immediate backup (includes all databases)
1683
+ - `client.list_backups()` - List all available backups
1684
+ - `client.restore_backup(backup_name)` - Restore from backup (restores all databases)
1685
+
1686
+ #### Server Management
1687
+ - `client.reload()` - Reload server configuration
1688
+
1689
+ ### HTTP API Methods
1690
+
1691
+ #### User Management (via HTTP)
1692
+ - `POST /api/users` - Create new user with username, password, and role
1693
+ - `GET /api/users?username=<username>` - Get user information by username
1694
+ - `PUT /api/users` - Update user password or role
1695
+ - `DELETE /api/users?username=<username>` - Delete user by username
1696
+
1697
+ All HTTP API endpoints require the `x-joystick-db-api-key` header for authentication.
1698
+
1699
+ ### Events
1700
+
1701
+ The client emits these events that you can listen to:
1702
+
1703
+ - `connect` - Connection established with server
1704
+ - `authenticated` - Authentication successful, ready to use
1705
+ - `error` - Error occurred (connection, authentication, etc.)
1706
+ - `disconnect` - Connection closed
1707
+ - `reconnecting` - Reconnection attempt in progress
1708
+ - `response` - Unsolicited server response received
1709
+
1710
+ ### Query Options
1711
+
1712
+ #### Find Options
1713
+ ```javascript
1714
+ {
1715
+ limit: 10, // Maximum number of documents to return
1716
+ skip: 0, // Number of documents to skip
1717
+ sort: { field: 1 }, // Sort order (1 = ascending, -1 = descending)
1718
+ projection: { field: 1 } // Fields to include (1) or exclude (0)
1719
+ }
1720
+ ```
1721
+
1722
+ #### Update Options
1723
+ ```javascript
1724
+ {
1725
+ upsert: false // Create document if it doesn't exist
1726
+ }
1727
+ ```
1728
+
1729
+ #### Index Options
1730
+ ```javascript
1731
+ {
1732
+ unique: false, // Enforce uniqueness
1733
+ sparse: false // Skip documents missing the indexed field
1734
+ }
1735
+ ```
1736
+
1737
+ ### Update Operators
1738
+
1739
+ JoystickDB supports these MongoDB-style update operators:
1740
+
1741
+ - `$set` - Set field values
1742
+ - `$unset` - Remove fields
1743
+ - `$inc` - Increment numeric values
1744
+ - `$push` - Add elements to arrays
1745
+ - `$pull` - Remove elements from arrays
1746
+
1747
+ ### Query Operators
1748
+
1749
+ JoystickDB supports these MongoDB-style query operators:
1750
+
1751
+ - `$eq` - Equal to
1752
+ - `$ne` - Not equal to
1753
+ - `$gt` - Greater than
1754
+ - `$gte` - Greater than or equal to
1755
+ - `$lt` - Less than
1756
+ - `$lte` - Less than or equal to
1757
+ - `$in` - Value in array
1758
+ - `$nin` - Value not in array
1759
+ - `$exists` - Field exists
1760
+ - `$regex` - Regular expression match
1761
+
1762
+ ### Error Handling
1763
+
1764
+ ```javascript
1765
+ try {
1766
+ const user_db = client.db('user_management');
1767
+ const users = user_db.collection('users');
1768
+ const result = await users.insert_one({ name: 'John' });
1769
+ } catch (error) {
1770
+ if (error.message.includes('Authentication')) {
1771
+ // Handle authentication error
1772
+ console.error('Please check your username and password');
1773
+ } else if (error.message.includes('timeout')) {
1774
+ // Handle timeout error
1775
+ console.error('Server is not responding');
1776
+ } else if (error.message.includes('Connection')) {
1777
+ // Handle connection error
1778
+ console.error('Cannot connect to server');
1779
+ } else if (error.message.includes('Invalid database name')) {
1780
+ // Handle database naming error
1781
+ console.error('Database name violates naming rules');
1782
+ } else {
1783
+ // Handle other errors
1784
+ console.error('Database error:', error.message);
1785
+ }
1786
+ }
1787
+ ```
1788
+
1789
+ ### Performance Tips
1790
+
1791
+ 1. **Use Indexes**: Create indexes on frequently queried fields in each database
1792
+ 2. **Batch Operations**: Use `bulk_write` for multiple operations
1793
+ 3. **Limit Results**: Always use `limit` for large result sets
1794
+ 4. **Use Projections**: Only fetch fields you need
1795
+ 5. **Connection Pooling**: Reuse client connections
1796
+ 6. **Monitor Performance**: Use `get_stats()` to track performance
1797
+ 7. **Database Organization**: Use separate databases to organize related data
1798
+ 8. **Index Per Database**: Create indexes specific to each database's query patterns
1799
+
1800
+ ### Best Practices
1801
+
1802
+ 1. **Always Handle Errors**: Wrap database calls in try-catch blocks
1803
+ 2. **Use Environment Variables**: Store passwords and config in env vars
1804
+ 3. **Regular Backups**: Enable automatic backups for production
1805
+ 4. **Monitor Health**: Set up health checks and monitoring
1806
+ 5. **Use Replication**: Set up replication for high availability
1807
+ 6. **Index Strategy**: Create indexes based on your query patterns per database
1808
+ 7. **Connection Management**: Properly close connections when done
1809
+ 8. **Secure API Keys**: Store API keys securely and rotate them regularly
1810
+ 9. **User Management**: Use appropriate roles (read/write/read_write) for users
1811
+ 10. **HTTP API Security**: Always use HTTPS in production for HTTP API calls
1812
+ 11. **Database Organization**: Use meaningful database names and organize data logically
1813
+ 12. **Multi-Database Design**: Separate concerns across databases (users, inventory, analytics, etc.)
1814
+ 13. **Database Naming**: Follow naming conventions and avoid reserved names
1815
+ 14. **Backward Compatibility**: Gradually migrate from single-database to multi-database API
1816
+
1817
+ ---
1818
+
1819
+ For more examples and advanced usage, see the `/test` directory in the repository.
1820
+
1821
+ **Need Help?** Check out the comprehensive test suite for real-world usage examples, or refer to the detailed configuration options above.