@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.
- package/.build/getFilesToBuild.js +26 -0
- package/.build/getPlatformSafeFilePath.js +6 -0
- package/.build/getPlatformSafePath.js +6 -0
- package/.build/index.js +88 -0
- package/.build/isWindows.js +3 -0
- package/API_KEY +1 -0
- package/README.md +1821 -0
- package/data/data.mdb +0 -0
- package/data/lock.mdb +0 -0
- package/dist/client/database.js +1 -0
- package/dist/client/index.js +1 -0
- package/dist/server/cluster/index.js +1 -0
- package/dist/server/cluster/master.js +20 -0
- package/dist/server/cluster/worker.js +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/lib/api_key_manager.js +9 -0
- package/dist/server/lib/auth_manager.js +1 -0
- package/dist/server/lib/auto_index_manager.js +1 -0
- package/dist/server/lib/backup_manager.js +1 -0
- package/dist/server/lib/connection_manager.js +1 -0
- package/dist/server/lib/disk_utils.js +2 -0
- package/dist/server/lib/http_server.js +405 -0
- package/dist/server/lib/index_manager.js +1 -0
- package/dist/server/lib/load_settings.js +1 -0
- package/dist/server/lib/logger.js +1 -0
- package/dist/server/lib/op_types.js +1 -0
- package/dist/server/lib/operation_dispatcher.js +1 -0
- package/dist/server/lib/operations/admin.js +1 -0
- package/dist/server/lib/operations/bulk_write.js +1 -0
- package/dist/server/lib/operations/create_index.js +1 -0
- package/dist/server/lib/operations/delete_one.js +1 -0
- package/dist/server/lib/operations/drop_index.js +1 -0
- package/dist/server/lib/operations/find.js +1 -0
- package/dist/server/lib/operations/find_one.js +1 -0
- package/dist/server/lib/operations/get_indexes.js +1 -0
- package/dist/server/lib/operations/insert_one.js +1 -0
- package/dist/server/lib/operations/update_one.js +1 -0
- package/dist/server/lib/performance_monitor.js +1 -0
- package/dist/server/lib/query_engine.js +1 -0
- package/dist/server/lib/recovery_manager.js +1 -0
- package/dist/server/lib/replication_manager.js +1 -0
- package/dist/server/lib/safe_json_parse.js +1 -0
- package/dist/server/lib/send_response.js +1 -0
- package/dist/server/lib/tcp_protocol.js +1 -0
- package/dist/server/lib/write_forwarder.js +1 -0
- package/dist/server/lib/write_queue.js +1 -0
- package/increment_version.js +3 -0
- package/logs/.013e15b54597d05db4b4b53ecc37b10c92a72927-audit.json +20 -0
- package/logs/.02de550a67ea0f5961faa2dfd458a4d06f59ebd1-audit.json +20 -0
- package/logs/.03494ba24eb3c72214b4068a77d54b8993bee651-audit.json +20 -0
- package/logs/.06309ec60b339be1259a7993dd09c732f8907fbc-audit.json +20 -0
- package/logs/.0663a04dcfa17285661e5e1b8cfa51f41523b210-audit.json +20 -0
- package/logs/.0f06e6c4c9b824622729e13927587479e5060391-audit.json +20 -0
- package/logs/.16ccf58682ecb22b3e3ec63f0da1b7fe9be56528-audit.json +20 -0
- package/logs/.1fa1a5d02f496474b1ab473524c65c984146a9ad-audit.json +20 -0
- package/logs/.2223c0ae3bea6f0d62c62b1d319cc8634856abb7-audit.json +20 -0
- package/logs/.23dc79ffda3e083665e6f5993f59397adcbf4a46-audit.json +20 -0
- package/logs/.28104f49b03906b189eefd1cd462cb46c3c0af22-audit.json +20 -0
- package/logs/.29cdbf13808abe6a0ce70ee2f2efdd680ce3fd8e-audit.json +20 -0
- package/logs/.2a9889afd071f77f41f5170d08703a0afca866b7-audit.json +20 -0
- package/logs/.2acec3d1940a2bbed487528b703ee5948959a599-audit.json +20 -0
- package/logs/.2fb60ff326338c02bfedbcd0e936444e4a216750-audit.json +20 -0
- package/logs/.318fc7a19530d76a345f030f7cad00dda15300e7-audit.json +20 -0
- package/logs/.3cf27043e19085f908cedc7701e6d013463208ee-audit.json +25 -0
- package/logs/.3d90d785415817fc443402843b7c95f8371adc9b-audit.json +20 -0
- package/logs/.4074bca620375f72966fc52dfd439577727671e5-audit.json +20 -0
- package/logs/.40eecf018417ea80a70ea8ec7a3cc9406bc6334b-audit.json +20 -0
- package/logs/.50e974f1ef7c365fca6a1251b2e2c2252914cb5e-audit.json +20 -0
- package/logs/.52cb7d9e4223cf26ba36006ac26b949a97c7923c-audit.json +20 -0
- package/logs/.54befcdb84c15aad980705a31bcc9f555c3577ab-audit.json +20 -0
- package/logs/.57dfb70e22eddb84db2e3c0ceeefac5c0b9baffa-audit.json +20 -0
- package/logs/.5f0b24705a1eaad4eca4968f2d86f91b3f9be683-audit.json +20 -0
- package/logs/.61ba98fdda7db58576b382fee07904e5db1169d6-audit.json +20 -0
- package/logs/.6235017727ef6b199d569a99d6aa8c8e80a1b475-audit.json +20 -0
- package/logs/.63db16193699219489d218a1ddea5dde3750cae4-audit.json +20 -0
- package/logs/.64fb67dfe14149c9eef728d79bf30a54da809c60-audit.json +20 -0
- package/logs/.669137453368987c1f311b5345342527afb54e50-audit.json +20 -0
- package/logs/.7a71f8c89ea28ae266d356aeff6306e876a30fbb-audit.json +20 -0
- package/logs/.7afbaa90fe9dc3a7d682676f9bb79f9a1b1fd9a6-audit.json +20 -0
- package/logs/.7ca29e322cd05327035de850099e7610864f2347-audit.json +20 -0
- package/logs/.83335ab3347e449dae03455a110aaf7f120d4802-audit.json +20 -0
- package/logs/.8c2487b5fd445d2c8e5c483c80b9fa99bbf1ca58-audit.json +20 -0
- package/logs/.8c8b9dc386922c9f3b4c13251af7052aac1d24c0-audit.json +20 -0
- package/logs/.8d6155d94640c4863301ae0fee5e4e7372a21446-audit.json +20 -0
- package/logs/.944a3119a243deea7c8270d5d9e582bb1d0eaa10-audit.json +20 -0
- package/logs/.9816a845c30fb2909f3b26a23eeb3538ebcad5db-audit.json +20 -0
- package/logs/.9dc08784e38b865488177c26d4af5934555e0323-audit.json +20 -0
- package/logs/.9dd27d2e0e454ac0a37600206d1cac5493b0d7ee-audit.json +20 -0
- package/logs/.a3d486feeac7654c59b547de96600e8849a06d4f-audit.json +20 -0
- package/logs/.a5b811f4def22250f86cc18870d7c4573625df22-audit.json +20 -0
- package/logs/.a61648eb5f830e0b6f508ac35e4f8f629d2ad4c7-audit.json +20 -0
- package/logs/.a89016d507045771b4b5a65656944a9c0f1e528b-audit.json +20 -0
- package/logs/.a99bee160a1c590be959af46bacc02724803f691-audit.json +20 -0
- package/logs/.ada7906d6243fd7da802f03d86c4ae5dd9df6236-audit.json +20 -0
- package/logs/.b518339ee942143b6af983af167f5bbb6983b4de-audit.json +20 -0
- package/logs/.b51b124b166d53c9519017856ea610d61d65fabe-audit.json +20 -0
- package/logs/.b7a6aee19f58e55633d5e4a3709041c47dfff975-audit.json +20 -0
- package/logs/.bd7a8a6ba9c55d557a4867ab53f02e3ec2e1553d-audit.json +20 -0
- package/logs/.c1435dafe453b169d6392b25065f3cf4ab6fbb21-audit.json +20 -0
- package/logs/.c17e1ce043109f77dc2f0e2aa290a9d1ed842c03-audit.json +20 -0
- package/logs/.ca62637ce9540e5a38a2fbedb2115febb6ad308a-audit.json +15 -0
- package/logs/.ccee67b9c176967f8977071409a41f5cb5cd6ad4-audit.json +20 -0
- package/logs/.db24043417ea79a6f14cd947476399e53930b48d-audit.json +20 -0
- package/logs/.e0f12acccb57829f5f33712bb2e2607ecd808147-audit.json +20 -0
- package/logs/.e9b6cc33d0bbd2e644c4e2bf44d177f850016557-audit.json +20 -0
- package/logs/.f15291d434808e3bdca7963ccd2e73893be027e6-audit.json +20 -0
- package/logs/.f4bdf9e21ef84f8a3fae3ffb32bbc39275991351-audit.json +15 -0
- package/logs/.fbac3aefac1e81b4230df5aa50667cb90d51024f-audit.json +20 -0
- package/logs/.fcfd495c0a9169db243f4a4f21878ee02b76413c-audit.json +20 -0
- package/logs/admin-2025-09-12.log +580 -0
- package/logs/admin-2025-09-15.log +283 -0
- package/logs/admin-error-2025-09-12.log +22 -0
- package/logs/admin-error-2025-09-15.log +10 -0
- package/logs/api_key_manager-2025-09-12.log +658 -0
- package/logs/api_key_manager-2025-09-15.log +295 -0
- package/logs/api_key_manager-error-2025-09-12.log +0 -0
- package/logs/api_key_manager-error-2025-09-15.log +0 -0
- package/logs/auth_manager-2025-09-12.log +4432 -0
- package/logs/auth_manager-2025-09-15.log +2000 -0
- package/logs/auth_manager-error-2025-09-12.log +11 -0
- package/logs/auth_manager-error-2025-09-15.log +5 -0
- package/logs/auto_index_manager-2025-09-12.log +84 -0
- package/logs/auto_index_manager-2025-09-15.log +45 -0
- package/logs/auto_index_manager-error-2025-09-12.log +6 -0
- package/logs/auto_index_manager-error-2025-09-15.log +0 -0
- package/logs/backup_manager-2025-09-12.log +198 -0
- package/logs/backup_manager-2025-09-15.log +90 -0
- package/logs/backup_manager-error-2025-09-12.log +198 -0
- package/logs/backup_manager-error-2025-09-15.log +90 -0
- package/logs/bulk_write-2025-09-12.log +66 -0
- package/logs/bulk_write-2025-09-15.log +38 -0
- package/logs/bulk_write-error-2025-09-12.log +0 -0
- package/logs/bulk_write-error-2025-09-15.log +0 -0
- package/logs/connection_manager-2025-09-12.log +2412 -0
- package/logs/connection_manager-2025-09-15.log +1132 -0
- package/logs/connection_manager-error-2025-09-12.log +0 -0
- package/logs/connection_manager-error-2025-09-15.log +0 -0
- package/logs/create_index-2025-09-12.log +302 -0
- package/logs/create_index-2025-09-15.log +158 -0
- package/logs/create_index-error-2025-09-12.log +30 -0
- package/logs/create_index-error-2025-09-15.log +13 -0
- package/logs/delete_one-2025-09-12.log +73 -0
- package/logs/delete_one-2025-09-15.log +43 -0
- package/logs/delete_one-error-2025-09-12.log +0 -0
- package/logs/delete_one-error-2025-09-15.log +0 -0
- package/logs/disk_utils-2025-09-12.log +4954 -0
- package/logs/disk_utils-2025-09-15.log +2446 -0
- package/logs/disk_utils-error-2025-09-12.log +0 -0
- package/logs/disk_utils-error-2025-09-15.log +0 -0
- package/logs/drop_index-2025-09-12.log +41 -0
- package/logs/drop_index-2025-09-15.log +23 -0
- package/logs/drop_index-error-2025-09-12.log +11 -0
- package/logs/drop_index-error-2025-09-15.log +5 -0
- package/logs/find-2025-09-12.log +1050 -0
- package/logs/find-2025-09-15.log +592 -0
- package/logs/find-error-2025-09-12.log +1 -0
- package/logs/find-error-2025-09-15.log +0 -0
- package/logs/find_one-2025-09-12.log +425 -0
- package/logs/find_one-2025-09-15.log +264 -0
- package/logs/find_one-error-2025-09-12.log +5 -0
- package/logs/find_one-error-2025-09-15.log +0 -0
- package/logs/get_indexes-2025-09-12.log +84 -0
- package/logs/get_indexes-2025-09-15.log +56 -0
- package/logs/get_indexes-error-2025-09-12.log +6 -0
- package/logs/get_indexes-error-2025-09-15.log +0 -0
- package/logs/http_server-2025-09-12.log +2772 -0
- package/logs/http_server-2025-09-15.log +1276 -0
- package/logs/http_server-error-2025-09-12.log +212 -0
- package/logs/http_server-error-2025-09-15.log +44 -0
- package/logs/index_manager-2025-09-12.log +5031 -0
- package/logs/index_manager-2025-09-15.log +2909 -0
- package/logs/index_manager-error-2025-09-12.log +80 -0
- package/logs/index_manager-error-2025-09-15.log +38 -0
- package/logs/insert_one-2025-09-12.log +2181 -0
- package/logs/insert_one-2025-09-15.log +1293 -0
- package/logs/insert_one-error-2025-09-12.log +0 -0
- package/logs/insert_one-error-2025-09-15.log +0 -0
- package/logs/master-2025-09-12.log +1882 -0
- package/logs/master-2025-09-15.log +910 -0
- package/logs/master-error-2025-09-12.log +80 -0
- package/logs/master-error-2025-09-15.log +0 -0
- package/logs/operation_dispatcher-2025-09-12.log +751 -0
- package/logs/operation_dispatcher-2025-09-15.log +359 -0
- package/logs/operation_dispatcher-error-2025-09-12.log +33 -0
- package/logs/operation_dispatcher-error-2025-09-15.log +11 -0
- package/logs/performance_monitor-2025-09-12.log +14889 -0
- package/logs/performance_monitor-2025-09-15.log +6803 -0
- package/logs/performance_monitor-error-2025-09-12.log +0 -0
- package/logs/performance_monitor-error-2025-09-15.log +0 -0
- package/logs/query_engine-2025-09-12.log +5310 -0
- package/logs/query_engine-2025-09-15.log +2639 -0
- package/logs/query_engine-error-2025-09-12.log +0 -0
- package/logs/query_engine-error-2025-09-15.log +0 -0
- package/logs/recovery_manager-2025-09-12.log +462 -0
- package/logs/recovery_manager-2025-09-15.log +210 -0
- package/logs/recovery_manager-error-2025-09-12.log +22 -0
- package/logs/recovery_manager-error-2025-09-15.log +10 -0
- package/logs/replication-2025-09-12.log +1923 -0
- package/logs/replication-2025-09-15.log +917 -0
- package/logs/replication-error-2025-09-12.log +33 -0
- package/logs/replication-error-2025-09-15.log +15 -0
- package/logs/server-2025-09-12.log +2601 -0
- package/logs/server-2025-09-15.log +1191 -0
- package/logs/server-error-2025-09-12.log +0 -0
- package/logs/server-error-2025-09-15.log +0 -0
- package/logs/tcp_protocol-2025-09-12.log +22 -0
- package/logs/tcp_protocol-2025-09-15.log +10 -0
- package/logs/tcp_protocol-error-2025-09-12.log +22 -0
- package/logs/tcp_protocol-error-2025-09-15.log +10 -0
- package/logs/test-2025-09-12.log +0 -0
- package/logs/test-2025-09-15.log +0 -0
- package/logs/test-error-2025-09-12.log +0 -0
- package/logs/test-error-2025-09-15.log +0 -0
- package/logs/update_one-2025-09-12.log +173 -0
- package/logs/update_one-2025-09-15.log +118 -0
- package/logs/update_one-error-2025-09-12.log +0 -0
- package/logs/update_one-error-2025-09-15.log +0 -0
- package/logs/worker-2025-09-12.log +1457 -0
- package/logs/worker-2025-09-15.log +695 -0
- package/logs/worker-error-2025-09-12.log +0 -0
- package/logs/worker-error-2025-09-15.log +0 -0
- package/logs/write_forwarder-2025-09-12.log +1956 -0
- package/logs/write_forwarder-2025-09-15.log +932 -0
- package/logs/write_forwarder-error-2025-09-12.log +66 -0
- package/logs/write_forwarder-error-2025-09-15.log +30 -0
- package/logs/write_queue-2025-09-12.log +612 -0
- package/logs/write_queue-2025-09-15.log +301 -0
- package/logs/write_queue-error-2025-09-12.log +184 -0
- package/logs/write_queue-error-2025-09-15.log +83 -0
- package/package.json +48 -0
- package/prompts/01-core-infrastructure.md +56 -0
- package/prompts/02-secondary-indexing.md +65 -0
- package/prompts/03-write-serialization.md +63 -0
- package/prompts/04-enhanced-authentication.md +75 -0
- package/prompts/05-comprehensive-admin-operations.md +75 -0
- package/prompts/06-backup-and-restore-system.md +106 -0
- package/prompts/07-production-safety-features.md +107 -0
- package/prompts/08-tcp-client-library.md +121 -0
- package/prompts/09-api-method-chaining.md +134 -0
- package/prompts/10-automatic-index-creation.md +223 -0
- package/prompts/11-operation-naming-consistency.md +268 -0
- package/prompts/12-tcp-replication-system.md +333 -0
- package/prompts/13-master-read-write-operations.md +57 -0
- package/prompts/14-index-upsert-operations.md +68 -0
- package/prompts/15-client-api-return-types.md +81 -0
- package/prompts/16-server-setup-ui.md +97 -0
- package/prompts/17-emergency-password-change.md +108 -0
- package/prompts/18-joystick-framework-integration.md +116 -0
- package/prompts/19-api-key-authentication-system.md +137 -0
- package/prompts/20-configurable-server-port.md +105 -0
- package/prompts/21-multi-database-support.md +161 -0
- package/prompts/FULL_TEXT_SEARCH.md +293 -0
- package/prompts/PROMPTS.md +158 -0
- package/prompts/README.md +221 -0
- package/prompts/TYPESCRIPT_GENERATION.md +179 -0
- package/src/client/database.js +166 -0
- package/src/client/index.js +752 -0
- package/src/server/cluster/index.js +53 -0
- package/src/server/cluster/master.js +774 -0
- package/src/server/cluster/worker.js +537 -0
- package/src/server/index.js +540 -0
- package/src/server/lib/api_key_manager.js +473 -0
- package/src/server/lib/auth_manager.js +375 -0
- package/src/server/lib/auto_index_manager.js +681 -0
- package/src/server/lib/backup_manager.js +650 -0
- package/src/server/lib/connection_manager.js +218 -0
- package/src/server/lib/disk_utils.js +118 -0
- package/src/server/lib/http_server.js +1165 -0
- package/src/server/lib/index_manager.js +756 -0
- package/src/server/lib/load_settings.js +143 -0
- package/src/server/lib/logger.js +135 -0
- package/src/server/lib/op_types.js +29 -0
- package/src/server/lib/operation_dispatcher.js +268 -0
- package/src/server/lib/operations/admin.js +808 -0
- package/src/server/lib/operations/bulk_write.js +367 -0
- package/src/server/lib/operations/create_index.js +68 -0
- package/src/server/lib/operations/delete_one.js +114 -0
- package/src/server/lib/operations/drop_index.js +58 -0
- package/src/server/lib/operations/find.js +340 -0
- package/src/server/lib/operations/find_one.js +319 -0
- package/src/server/lib/operations/get_indexes.js +52 -0
- package/src/server/lib/operations/insert_one.js +113 -0
- package/src/server/lib/operations/update_one.js +225 -0
- package/src/server/lib/performance_monitor.js +313 -0
- package/src/server/lib/query_engine.js +243 -0
- package/src/server/lib/recovery_manager.js +388 -0
- package/src/server/lib/replication_manager.js +727 -0
- package/src/server/lib/safe_json_parse.js +21 -0
- package/src/server/lib/send_response.js +47 -0
- package/src/server/lib/tcp_protocol.js +130 -0
- package/src/server/lib/write_forwarder.js +636 -0
- package/src/server/lib/write_queue.js +335 -0
- package/test_data/data.mdb +0 -0
- package/test_data/lock.mdb +0 -0
- package/tests/client/index.test.js +1232 -0
- package/tests/server/cluster/cluster.test.js +248 -0
- package/tests/server/cluster/master_read_write_operations.test.js +577 -0
- package/tests/server/index.test.js +651 -0
- package/tests/server/integration/authentication_integration.test.js +294 -0
- package/tests/server/integration/auto_indexing_integration.test.js +268 -0
- package/tests/server/integration/backup_integration.test.js +513 -0
- package/tests/server/integration/indexing_integration.test.js +126 -0
- package/tests/server/integration/production_safety_integration.test.js +358 -0
- package/tests/server/integration/replication_integration.test.js +227 -0
- package/tests/server/integration/write_serialization_integration.test.js +246 -0
- package/tests/server/lib/api_key_manager.test.js +516 -0
- package/tests/server/lib/auth_manager.test.js +317 -0
- package/tests/server/lib/auto_index_manager.test.js +275 -0
- package/tests/server/lib/backup_manager.test.js +238 -0
- package/tests/server/lib/connection_manager.test.js +221 -0
- package/tests/server/lib/disk_utils.test.js +63 -0
- package/tests/server/lib/http_server.test.js +389 -0
- package/tests/server/lib/index_manager.test.js +301 -0
- package/tests/server/lib/load_settings.test.js +107 -0
- package/tests/server/lib/load_settings_port_config.test.js +243 -0
- package/tests/server/lib/logger.test.js +282 -0
- package/tests/server/lib/operations/admin.test.js +638 -0
- package/tests/server/lib/operations/bulk_write.test.js +128 -0
- package/tests/server/lib/operations/create_index.test.js +138 -0
- package/tests/server/lib/operations/delete_one.test.js +52 -0
- package/tests/server/lib/operations/drop_index.test.js +72 -0
- package/tests/server/lib/operations/find.test.js +93 -0
- package/tests/server/lib/operations/find_one.test.js +91 -0
- package/tests/server/lib/operations/get_indexes.test.js +87 -0
- package/tests/server/lib/operations/insert_one.test.js +42 -0
- package/tests/server/lib/operations/update_one.test.js +89 -0
- package/tests/server/lib/performance_monitor.test.js +185 -0
- package/tests/server/lib/query_engine.test.js +46 -0
- package/tests/server/lib/recovery_manager.test.js +414 -0
- package/tests/server/lib/replication_manager.test.js +202 -0
- package/tests/server/lib/safe_json_parse.test.js +45 -0
- package/tests/server/lib/send_response.test.js +155 -0
- package/tests/server/lib/tcp_protocol.test.js +169 -0
- package/tests/server/lib/write_forwarder.test.js +258 -0
- package/tests/server/lib/write_queue.test.js +255 -0
- package/tsconfig.json +30 -0
- package/types/client/index.d.ts +447 -0
- package/types/server/cluster/index.d.ts +28 -0
- package/types/server/cluster/master.d.ts +115 -0
- package/types/server/cluster/worker.d.ts +1 -0
- package/types/server/lib/auth_manager.d.ts +13 -0
- package/types/server/lib/backup_manager.d.ts +43 -0
- package/types/server/lib/connection_manager.d.ts +15 -0
- package/types/server/lib/disk_utils.d.ts +3 -0
- package/types/server/lib/index_manager.d.ts +24 -0
- package/types/server/lib/load_settings.d.ts +4 -0
- package/types/server/lib/logger.d.ts +44 -0
- package/types/server/lib/op_types.d.ts +6 -0
- package/types/server/lib/performance_monitor.d.ts +68 -0
- package/types/server/lib/query_engine.d.ts +10 -0
- package/types/server/lib/safe_json_parse.d.ts +7 -0
- package/types/server/lib/send_response.d.ts +3 -0
- package/types/server/lib/tcp_protocol.d.ts +12 -0
- package/types/server/lib/write_queue.d.ts +2 -0
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
import net from 'net';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import { encode as encode_messagepack, decode as decode_messagepack } from 'msgpackr';
|
|
4
|
+
import Database from './database.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Encodes a message with MessagePack and prepends a 4-byte length header.
|
|
8
|
+
* @param {any} data - The data to encode
|
|
9
|
+
* @returns {Buffer} The encoded message with length header
|
|
10
|
+
*/
|
|
11
|
+
const encode_message = (data) => {
|
|
12
|
+
// NOTE: Use compatible MessagePack options to avoid parsing issues.
|
|
13
|
+
const messagepack_data = encode_messagepack(data, {
|
|
14
|
+
useFloat32: false,
|
|
15
|
+
int64AsType: 'number',
|
|
16
|
+
mapsAsObjects: true
|
|
17
|
+
});
|
|
18
|
+
const length_buffer = Buffer.allocUnsafe(4);
|
|
19
|
+
length_buffer.writeUInt32BE(messagepack_data.length, 0);
|
|
20
|
+
return Buffer.concat([length_buffer, messagepack_data]);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates a message parser for handling TCP stream data with length-prefixed MessagePack messages.
|
|
25
|
+
* @returns {Object} Parser object with parse_messages and reset methods
|
|
26
|
+
*/
|
|
27
|
+
const create_message_parser = () => {
|
|
28
|
+
let buffer = Buffer.alloc(0);
|
|
29
|
+
let expected_length = null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parses incoming data and extracts complete messages.
|
|
33
|
+
* @param {Buffer} data - Raw TCP data
|
|
34
|
+
* @returns {Array} Array of decoded messages
|
|
35
|
+
* @throws {Error} When message format is invalid
|
|
36
|
+
*/
|
|
37
|
+
const parse_messages = (data) => {
|
|
38
|
+
buffer = Buffer.concat([buffer, data]);
|
|
39
|
+
const messages = [];
|
|
40
|
+
|
|
41
|
+
while (buffer.length > 0) {
|
|
42
|
+
if (expected_length === null) {
|
|
43
|
+
if (buffer.length < 4) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
expected_length = buffer.readUInt32BE(0);
|
|
48
|
+
buffer = buffer.slice(4);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (buffer.length < expected_length) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const message_data = buffer.slice(0, expected_length);
|
|
56
|
+
buffer = buffer.slice(expected_length);
|
|
57
|
+
expected_length = null;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
// NOTE: Use compatible MessagePack options to avoid parsing issues.
|
|
61
|
+
const decoded_message = decode_messagepack(message_data, {
|
|
62
|
+
useFloat32: false,
|
|
63
|
+
int64AsType: 'number',
|
|
64
|
+
mapsAsObjects: true
|
|
65
|
+
});
|
|
66
|
+
messages.push(decoded_message);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new Error(`Invalid message format: ${error.message}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return messages;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Resets the parser state, clearing buffers and expected length.
|
|
77
|
+
*/
|
|
78
|
+
const reset = () => {
|
|
79
|
+
buffer = Buffer.alloc(0);
|
|
80
|
+
expected_length = null;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
parse_messages,
|
|
85
|
+
reset
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {Object} ClientOptions
|
|
92
|
+
* @property {string} [host='localhost'] - Server hostname
|
|
93
|
+
* @property {number} [port=1983] - Server port
|
|
94
|
+
* @property {string} [password] - Authentication password (required for authenticated connections)
|
|
95
|
+
* @property {number} [timeout=5000] - Request timeout in milliseconds
|
|
96
|
+
* @property {boolean} [reconnect=true] - Enable automatic reconnection
|
|
97
|
+
* @property {number} [max_reconnect_attempts=10] - Maximum reconnection attempts
|
|
98
|
+
* @property {number} [reconnect_delay=1000] - Initial reconnection delay in milliseconds
|
|
99
|
+
* @property {boolean} [auto_connect=true] - Automatically connect on instantiation
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* JoystickDB TCP client for connecting to JoystickDB server.
|
|
104
|
+
* @extends EventEmitter
|
|
105
|
+
* @fires JoystickDBClient#connect
|
|
106
|
+
* @fires JoystickDBClient#authenticated
|
|
107
|
+
* @fires JoystickDBClient#error
|
|
108
|
+
* @fires JoystickDBClient#disconnect
|
|
109
|
+
* @fires JoystickDBClient#reconnecting
|
|
110
|
+
* @fires JoystickDBClient#response
|
|
111
|
+
*/
|
|
112
|
+
class JoystickDBClient extends EventEmitter {
|
|
113
|
+
/**
|
|
114
|
+
* Creates a new JoystickDB client instance.
|
|
115
|
+
* @param {ClientOptions} [options={}] - Client configuration options
|
|
116
|
+
*/
|
|
117
|
+
constructor(options = {}) {
|
|
118
|
+
super();
|
|
119
|
+
|
|
120
|
+
this.host = options.host || 'localhost';
|
|
121
|
+
this.port = options.port || 1983;
|
|
122
|
+
this.password = options.password || null;
|
|
123
|
+
this.timeout = options.timeout || 5000;
|
|
124
|
+
this.reconnect = options.reconnect !== false;
|
|
125
|
+
this.max_reconnect_attempts = options.max_reconnect_attempts || 10;
|
|
126
|
+
this.reconnect_delay = options.reconnect_delay || 1000;
|
|
127
|
+
|
|
128
|
+
this.socket = null;
|
|
129
|
+
this.message_parser = null;
|
|
130
|
+
this.is_connected = false;
|
|
131
|
+
this.is_authenticated = false;
|
|
132
|
+
this.is_connecting = false;
|
|
133
|
+
this.reconnect_attempts = 0;
|
|
134
|
+
this.reconnect_timeout = null;
|
|
135
|
+
|
|
136
|
+
this.pending_requests = new Map();
|
|
137
|
+
this.request_id_counter = 0;
|
|
138
|
+
this.request_queue = [];
|
|
139
|
+
|
|
140
|
+
if (options.auto_connect !== false) {
|
|
141
|
+
this.connect();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Establishes connection to the JoystickDB server.
|
|
147
|
+
*/
|
|
148
|
+
connect() {
|
|
149
|
+
if (this.is_connecting || this.is_connected) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.is_connecting = true;
|
|
154
|
+
this.socket = new net.Socket();
|
|
155
|
+
this.message_parser = create_message_parser();
|
|
156
|
+
|
|
157
|
+
const connection_timeout = setTimeout(() => {
|
|
158
|
+
if (this.socket && !this.is_connected) {
|
|
159
|
+
this.socket.destroy();
|
|
160
|
+
this.handle_connection_error(new Error('Connection timeout'));
|
|
161
|
+
}
|
|
162
|
+
}, this.timeout);
|
|
163
|
+
|
|
164
|
+
this.socket.connect(this.port, this.host, () => {
|
|
165
|
+
clearTimeout(connection_timeout);
|
|
166
|
+
this.is_connected = true;
|
|
167
|
+
this.is_connecting = false;
|
|
168
|
+
this.reconnect_attempts = 0;
|
|
169
|
+
|
|
170
|
+
this.emit('connect');
|
|
171
|
+
|
|
172
|
+
if (this.password) {
|
|
173
|
+
this.authenticate();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
this.socket.on('data', (data) => {
|
|
178
|
+
try {
|
|
179
|
+
const messages = this.message_parser.parse_messages(data);
|
|
180
|
+
|
|
181
|
+
for (const message of messages) {
|
|
182
|
+
this.handle_message(message);
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
this.emit('error', new Error(`Message parsing failed: ${error.message}`));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
this.socket.on('error', (error) => {
|
|
190
|
+
clearTimeout(connection_timeout);
|
|
191
|
+
this.handle_connection_error(error);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
this.socket.on('close', () => {
|
|
195
|
+
clearTimeout(connection_timeout);
|
|
196
|
+
this.handle_disconnect();
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Authenticates with the server using provided credentials.
|
|
202
|
+
*/
|
|
203
|
+
async authenticate() {
|
|
204
|
+
if (!this.password) {
|
|
205
|
+
this.emit('error', new Error('Password required for authentication. Provide password in client options: joystickdb.client({ password: "your_password" })'));
|
|
206
|
+
this.disconnect();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const result = await this.send_request('authentication', {
|
|
212
|
+
password: this.password
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (result.ok === 1) {
|
|
216
|
+
this.is_authenticated = true;
|
|
217
|
+
this.emit('authenticated');
|
|
218
|
+
this.process_request_queue();
|
|
219
|
+
} else {
|
|
220
|
+
throw new Error('Authentication failed');
|
|
221
|
+
}
|
|
222
|
+
} catch (error) {
|
|
223
|
+
this.emit('error', new Error(`Authentication error: ${error.message}`));
|
|
224
|
+
this.disconnect();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Handles incoming messages from the server.
|
|
230
|
+
* @param {Object} message - Decoded message from server
|
|
231
|
+
*/
|
|
232
|
+
handle_message(message) {
|
|
233
|
+
if (this.pending_requests.size > 0) {
|
|
234
|
+
const [request_id, { resolve, reject, timeout }] = this.pending_requests.entries().next().value;
|
|
235
|
+
clearTimeout(timeout);
|
|
236
|
+
this.pending_requests.delete(request_id);
|
|
237
|
+
|
|
238
|
+
if (message.ok === 1 || message.ok === true) {
|
|
239
|
+
resolve(message);
|
|
240
|
+
} else if (message.ok === 0 || message.ok === false) {
|
|
241
|
+
const error_message = typeof message.error === 'string' ? message.error : JSON.stringify(message.error) || 'Operation failed';
|
|
242
|
+
reject(new Error(error_message));
|
|
243
|
+
} else {
|
|
244
|
+
resolve(message);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
this.emit('response', message);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Handles connection errors and manages reconnection logic.
|
|
253
|
+
* @param {Error} error - The connection error
|
|
254
|
+
*/
|
|
255
|
+
handle_connection_error(error) {
|
|
256
|
+
this.is_connecting = false;
|
|
257
|
+
this.is_connected = false;
|
|
258
|
+
this.is_authenticated = false;
|
|
259
|
+
|
|
260
|
+
if (this.socket) {
|
|
261
|
+
this.socket.removeAllListeners();
|
|
262
|
+
this.socket.destroy();
|
|
263
|
+
this.socket = null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this.message_parser) {
|
|
267
|
+
this.message_parser.reset();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// NOTE: Reject all pending requests.
|
|
271
|
+
for (const [request_id, { reject, timeout }] of this.pending_requests) {
|
|
272
|
+
clearTimeout(timeout);
|
|
273
|
+
reject(new Error('Connection lost'));
|
|
274
|
+
}
|
|
275
|
+
this.pending_requests.clear();
|
|
276
|
+
|
|
277
|
+
this.emit('error', error);
|
|
278
|
+
|
|
279
|
+
if (this.reconnect && this.reconnect_attempts < this.max_reconnect_attempts) {
|
|
280
|
+
this.schedule_reconnect();
|
|
281
|
+
} else {
|
|
282
|
+
this.emit('disconnect');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Handles disconnection events and manages reconnection logic.
|
|
288
|
+
*/
|
|
289
|
+
handle_disconnect() {
|
|
290
|
+
this.is_connected = false;
|
|
291
|
+
this.is_authenticated = false;
|
|
292
|
+
this.is_connecting = false;
|
|
293
|
+
|
|
294
|
+
if (this.socket) {
|
|
295
|
+
this.socket.removeAllListeners();
|
|
296
|
+
this.socket = null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (this.message_parser) {
|
|
300
|
+
this.message_parser.reset();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// NOTE: Reject all pending requests.
|
|
304
|
+
for (const [request_id, { reject, timeout }] of this.pending_requests) {
|
|
305
|
+
clearTimeout(timeout);
|
|
306
|
+
reject(new Error('Connection closed'));
|
|
307
|
+
}
|
|
308
|
+
this.pending_requests.clear();
|
|
309
|
+
|
|
310
|
+
if (this.reconnect && this.reconnect_attempts < this.max_reconnect_attempts) {
|
|
311
|
+
this.schedule_reconnect();
|
|
312
|
+
} else {
|
|
313
|
+
this.emit('disconnect');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Schedules a reconnection attempt with exponential backoff.
|
|
319
|
+
*/
|
|
320
|
+
schedule_reconnect() {
|
|
321
|
+
this.reconnect_attempts++;
|
|
322
|
+
const delay = Math.min(
|
|
323
|
+
this.reconnect_delay * Math.pow(2, this.reconnect_attempts - 1),
|
|
324
|
+
30000
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
this.emit('reconnecting', { attempt: this.reconnect_attempts, delay });
|
|
328
|
+
|
|
329
|
+
this.reconnect_timeout = setTimeout(() => {
|
|
330
|
+
this.connect();
|
|
331
|
+
}, delay);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Sends a request to the server.
|
|
336
|
+
* @param {string} op - Operation name
|
|
337
|
+
* @param {Object} [data={}] - Request data
|
|
338
|
+
* @param {boolean} [use_queue=true] - Whether to queue request if not connected
|
|
339
|
+
* @returns {Promise<Object>} Server response
|
|
340
|
+
*/
|
|
341
|
+
send_request(op, data = {}, use_queue = true) {
|
|
342
|
+
return new Promise((resolve, reject) => {
|
|
343
|
+
const request_id = ++this.request_id_counter;
|
|
344
|
+
const message = {
|
|
345
|
+
op,
|
|
346
|
+
data
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
const request = {
|
|
350
|
+
message,
|
|
351
|
+
resolve,
|
|
352
|
+
reject,
|
|
353
|
+
request_id
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
if (!this.is_connected || (op !== 'authentication' && op !== 'setup' && op !== 'ping' && !this.is_authenticated)) {
|
|
357
|
+
if (use_queue) {
|
|
358
|
+
this.request_queue.push(request);
|
|
359
|
+
return;
|
|
360
|
+
} else {
|
|
361
|
+
reject(new Error('Not connected or authenticated'));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
this.send_request_now(request);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Immediately sends a request to the server.
|
|
372
|
+
* @param {Object} request - Request object with message, resolve, reject, and request_id
|
|
373
|
+
*/
|
|
374
|
+
send_request_now(request) {
|
|
375
|
+
const { message, resolve, reject, request_id } = request;
|
|
376
|
+
|
|
377
|
+
const timeout = setTimeout(() => {
|
|
378
|
+
this.pending_requests.delete(request_id);
|
|
379
|
+
reject(new Error('Request timeout'));
|
|
380
|
+
}, this.timeout);
|
|
381
|
+
|
|
382
|
+
this.pending_requests.set(request_id, { resolve, reject, timeout });
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
const encoded_message = encode_message(message);
|
|
386
|
+
this.socket.write(encoded_message);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
clearTimeout(timeout);
|
|
389
|
+
this.pending_requests.delete(request_id);
|
|
390
|
+
reject(error);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Processes queued requests after connection and authentication.
|
|
396
|
+
*/
|
|
397
|
+
process_request_queue() {
|
|
398
|
+
while (this.request_queue.length > 0 && this.is_connected && this.is_authenticated) {
|
|
399
|
+
const request = this.request_queue.shift();
|
|
400
|
+
this.send_request_now(request);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Disconnects from the server and disables reconnection.
|
|
406
|
+
*/
|
|
407
|
+
disconnect() {
|
|
408
|
+
this.reconnect = false;
|
|
409
|
+
|
|
410
|
+
if (this.reconnect_timeout) {
|
|
411
|
+
clearTimeout(this.reconnect_timeout);
|
|
412
|
+
this.reconnect_timeout = null;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (this.socket) {
|
|
416
|
+
this.socket.end();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
// NOTE: Backup Operations.
|
|
423
|
+
/**
|
|
424
|
+
* Triggers an immediate backup.
|
|
425
|
+
* @returns {Promise<Object>} Backup result
|
|
426
|
+
*/
|
|
427
|
+
async backup_now() {
|
|
428
|
+
return this.send_request('admin', { admin_action: 'backup_now' });
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Lists all available backups.
|
|
433
|
+
* @returns {Promise<Object>} Backups list
|
|
434
|
+
*/
|
|
435
|
+
async list_backups() {
|
|
436
|
+
return this.send_request('admin', { admin_action: 'list_backups' });
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Restores from a specific backup.
|
|
441
|
+
* @param {string} backup_name - Name of backup to restore
|
|
442
|
+
* @returns {Promise<Object>} Restore result
|
|
443
|
+
*/
|
|
444
|
+
async restore_backup(backup_name) {
|
|
445
|
+
return this.send_request('admin', {
|
|
446
|
+
admin_action: 'restore_backup',
|
|
447
|
+
backup_name
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// NOTE: Replication Operations.
|
|
452
|
+
/**
|
|
453
|
+
* Gets replication status and statistics.
|
|
454
|
+
* @returns {Promise<Object>} Replication status
|
|
455
|
+
*/
|
|
456
|
+
async get_replication_status() {
|
|
457
|
+
return this.send_request('admin', { admin_action: 'get_replication_status' });
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Adds a secondary node to replication.
|
|
462
|
+
* @param {Object} secondary - Secondary node configuration
|
|
463
|
+
* @param {string} secondary.id - Secondary node ID
|
|
464
|
+
* @param {string} secondary.ip - Secondary node IP address
|
|
465
|
+
* @param {number} secondary.port - Secondary node port
|
|
466
|
+
* @param {string} secondary.private_key - Base64 encoded private key
|
|
467
|
+
* @returns {Promise<Object>} Add secondary result
|
|
468
|
+
*/
|
|
469
|
+
async add_secondary(secondary) {
|
|
470
|
+
return this.send_request('admin', { admin_action: 'add_secondary', ...secondary });
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Removes a secondary node from replication.
|
|
475
|
+
* @param {string} secondary_id - Secondary node ID to remove
|
|
476
|
+
* @returns {Promise<Object>} Remove secondary result
|
|
477
|
+
*/
|
|
478
|
+
async remove_secondary(secondary_id) {
|
|
479
|
+
return this.send_request('admin', { admin_action: 'remove_secondary', secondary_id });
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Forces synchronization with all secondary nodes.
|
|
484
|
+
* @returns {Promise<Object>} Sync result
|
|
485
|
+
*/
|
|
486
|
+
async sync_secondaries() {
|
|
487
|
+
return this.send_request('admin', { admin_action: 'sync_secondaries' });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Gets health status of secondary nodes.
|
|
492
|
+
* @returns {Promise<Object>} Secondary health status
|
|
493
|
+
*/
|
|
494
|
+
async get_secondary_health() {
|
|
495
|
+
return this.send_request('admin', { admin_action: 'get_secondary_health' });
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Gets write forwarder status (for secondary nodes).
|
|
500
|
+
* @returns {Promise<Object>} Write forwarder status
|
|
501
|
+
*/
|
|
502
|
+
async get_forwarder_status() {
|
|
503
|
+
return this.send_request('admin', { admin_action: 'get_forwarder_status' });
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// NOTE: Health and Utility Operations.
|
|
507
|
+
/**
|
|
508
|
+
* Pings the server to check connectivity.
|
|
509
|
+
* @returns {Promise<Object>} Ping result
|
|
510
|
+
*/
|
|
511
|
+
async ping() {
|
|
512
|
+
return this.send_request('ping', {}, false);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Reloads server configuration.
|
|
517
|
+
* @returns {Promise<Object>} Reload result
|
|
518
|
+
*/
|
|
519
|
+
async reload() {
|
|
520
|
+
return this.send_request('reload');
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// NOTE: Auto-Indexing Operations.
|
|
524
|
+
/**
|
|
525
|
+
* Gets automatic indexing statistics.
|
|
526
|
+
* @returns {Promise<Object>} Auto-indexing statistics
|
|
527
|
+
*/
|
|
528
|
+
async get_auto_index_stats() {
|
|
529
|
+
return this.send_request('admin', { admin_action: 'get_auto_index_stats' });
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
// NOTE: Setup Operation.
|
|
534
|
+
/**
|
|
535
|
+
* Performs initial server setup.
|
|
536
|
+
* @returns {Promise<Object>} Setup result
|
|
537
|
+
*/
|
|
538
|
+
async setup() {
|
|
539
|
+
const result = await this.send_request('setup', {}, false);
|
|
540
|
+
|
|
541
|
+
// NOTE: Display setup instructions to user.
|
|
542
|
+
if (result.data && result.data.instructions) {
|
|
543
|
+
console.log(result.data.instructions);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return result;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// NOTE: Database Interface.
|
|
550
|
+
/**
|
|
551
|
+
* Returns a database interface for method chaining operations.
|
|
552
|
+
* @param {string} database_name - Database name
|
|
553
|
+
* @returns {Database} Database interface instance
|
|
554
|
+
*/
|
|
555
|
+
db(database_name) {
|
|
556
|
+
return new Database(this, database_name);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
// NOTE: Multi-Database Admin Operations.
|
|
561
|
+
/**
|
|
562
|
+
* Lists all databases on the server.
|
|
563
|
+
* @returns {Promise<Object>} Databases list
|
|
564
|
+
*/
|
|
565
|
+
async list_databases() {
|
|
566
|
+
return this.send_request('admin', { admin_action: 'list_databases' });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Collection interface for method chaining operations.
|
|
572
|
+
* Provides a fluent API for database operations on a specific collection.
|
|
573
|
+
*/
|
|
574
|
+
class Collection {
|
|
575
|
+
/**
|
|
576
|
+
* Creates a new Collection instance.
|
|
577
|
+
* @param {JoystickDBClient} client - The client instance
|
|
578
|
+
* @param {string} database_name - Name of the database
|
|
579
|
+
* @param {string} collection_name - Name of the collection
|
|
580
|
+
*/
|
|
581
|
+
constructor(client, database_name, collection_name) {
|
|
582
|
+
this.client = client;
|
|
583
|
+
this.database_name = database_name;
|
|
584
|
+
this.collection_name = collection_name;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Inserts a single document into the collection.
|
|
589
|
+
* @param {Object} document - Document to insert
|
|
590
|
+
* @param {Object} [options={}] - Insert options
|
|
591
|
+
* @returns {Promise<Object>} Insert result
|
|
592
|
+
*/
|
|
593
|
+
async insert_one(document, options = {}) {
|
|
594
|
+
return this.client.send_request('insert_one', {
|
|
595
|
+
database: this.database_name,
|
|
596
|
+
collection: this.collection_name,
|
|
597
|
+
document,
|
|
598
|
+
options
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Finds a single document in the collection.
|
|
604
|
+
* @param {Object} [filter={}] - Query filter
|
|
605
|
+
* @param {Object} [options={}] - Find options
|
|
606
|
+
* @returns {Promise<Object|null>} Found document or null
|
|
607
|
+
*/
|
|
608
|
+
async find_one(filter = {}, options = {}) {
|
|
609
|
+
const result = await this.client.send_request('find_one', {
|
|
610
|
+
database: this.database_name,
|
|
611
|
+
collection: this.collection_name,
|
|
612
|
+
filter,
|
|
613
|
+
options
|
|
614
|
+
});
|
|
615
|
+
return result.document;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Finds multiple documents in the collection.
|
|
620
|
+
* @param {Object} [filter={}] - Query filter
|
|
621
|
+
* @param {Object} [options={}] - Find options
|
|
622
|
+
* @returns {Promise<Array>} Array of found documents
|
|
623
|
+
*/
|
|
624
|
+
async find(filter = {}, options = {}) {
|
|
625
|
+
const result = await this.client.send_request('find', {
|
|
626
|
+
database: this.database_name,
|
|
627
|
+
collection: this.collection_name,
|
|
628
|
+
filter,
|
|
629
|
+
options
|
|
630
|
+
});
|
|
631
|
+
return result.documents || [];
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Updates a single document in the collection.
|
|
636
|
+
* @param {Object} filter - Query filter to match document
|
|
637
|
+
* @param {Object} update - Update operations
|
|
638
|
+
* @param {Object} [options={}] - Update options
|
|
639
|
+
* @returns {Promise<Object>} Update result
|
|
640
|
+
*/
|
|
641
|
+
async update_one(filter, update, options = {}) {
|
|
642
|
+
return this.client.send_request('update_one', {
|
|
643
|
+
database: this.database_name,
|
|
644
|
+
collection: this.collection_name,
|
|
645
|
+
filter,
|
|
646
|
+
update,
|
|
647
|
+
options
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Deletes a single document from the collection.
|
|
653
|
+
* @param {Object} filter - Query filter to match document
|
|
654
|
+
* @param {Object} [options={}] - Delete options
|
|
655
|
+
* @returns {Promise<Object>} Delete result
|
|
656
|
+
*/
|
|
657
|
+
async delete_one(filter, options = {}) {
|
|
658
|
+
return this.client.send_request('delete_one', {
|
|
659
|
+
database: this.database_name,
|
|
660
|
+
collection: this.collection_name,
|
|
661
|
+
filter,
|
|
662
|
+
options
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Performs multiple write operations in a single request.
|
|
668
|
+
* @param {Array<Object>} operations - Array of write operations
|
|
669
|
+
* @param {Object} [options={}] - Bulk write options
|
|
670
|
+
* @returns {Promise<Object>} Bulk write result
|
|
671
|
+
*/
|
|
672
|
+
async bulk_write(operations, options = {}) {
|
|
673
|
+
return this.client.send_request('bulk_write', {
|
|
674
|
+
database: this.database_name,
|
|
675
|
+
collection: this.collection_name,
|
|
676
|
+
operations,
|
|
677
|
+
options
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Creates an index on a collection field.
|
|
683
|
+
* @param {string} field - Field name to index
|
|
684
|
+
* @param {Object} [options={}] - Index options
|
|
685
|
+
* @returns {Promise<Object>} Index creation result
|
|
686
|
+
*/
|
|
687
|
+
async create_index(field, options = {}) {
|
|
688
|
+
return this.client.send_request('create_index', {
|
|
689
|
+
database: this.database_name,
|
|
690
|
+
collection: this.collection_name,
|
|
691
|
+
field,
|
|
692
|
+
options
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Creates or updates an index on a collection field (upsert operation).
|
|
698
|
+
* @param {string} field - Field name to index
|
|
699
|
+
* @param {Object} [options={}] - Index options
|
|
700
|
+
* @returns {Promise<Object>} Index upsert result
|
|
701
|
+
*/
|
|
702
|
+
async upsert_index(field, options = {}) {
|
|
703
|
+
return this.client.send_request('create_index', {
|
|
704
|
+
database: this.database_name,
|
|
705
|
+
collection: this.collection_name,
|
|
706
|
+
field,
|
|
707
|
+
options: { ...options, upsert: true }
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Drops an index from a collection field.
|
|
713
|
+
* @param {string} field - Field name of index to drop
|
|
714
|
+
* @returns {Promise<Object>} Index drop result
|
|
715
|
+
*/
|
|
716
|
+
async drop_index(field) {
|
|
717
|
+
return this.client.send_request('drop_index', {
|
|
718
|
+
database: this.database_name,
|
|
719
|
+
collection: this.collection_name,
|
|
720
|
+
field
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Gets all indexes for the collection.
|
|
726
|
+
* @returns {Promise<Object>} Indexes information
|
|
727
|
+
*/
|
|
728
|
+
async get_indexes() {
|
|
729
|
+
return this.client.send_request('get_indexes', {
|
|
730
|
+
database: this.database_name,
|
|
731
|
+
collection: this.collection_name
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// NOTE: Add Collection class as static property for Database class access.
|
|
737
|
+
JoystickDBClient.Collection = Collection;
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* JoystickDB client factory and utilities.
|
|
741
|
+
* @namespace
|
|
742
|
+
*/
|
|
743
|
+
const joystickdb = {
|
|
744
|
+
/**
|
|
745
|
+
* Creates a new JoystickDB client instance.
|
|
746
|
+
* @param {ClientOptions} options - Client configuration options
|
|
747
|
+
* @returns {JoystickDBClient} New client instance
|
|
748
|
+
*/
|
|
749
|
+
client: (options) => new JoystickDBClient(options)
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
export default joystickdb;
|