diff --git a/package-lock.json b/package-lock.json index fc2a1a8..9846505 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "ajv": "^8.14.0", "ajv-formats": "^3.0.1", - "fastify": "^4.27.0", "recoil-tdf": "^1.0.0", "tiny-typed-emitter": "^2.1.0", "ws": "^8.17.0" @@ -28,6 +27,7 @@ "@typescript-eslint/parser": "^7.11.0", "eslint": "8.57.0", "eslint-config-prettier": "^9.1.0", + "fastify": "^4.27.0", "json-schema-to-typescript": "^14.0.4", "pino-pretty": "^11.1.0", "prettier": "3.2.5", @@ -174,6 +174,7 @@ "version": "3.5.0", "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", "integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==", + "dev": true, "dependencies": { "ajv": "^8.11.0", "ajv-formats": "^2.1.1", @@ -184,6 +185,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "dependencies": { "ajv": "^8.0.0" }, @@ -209,12 +211,14 @@ "node_modules/@fastify/error": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", - "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==" + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==", + "dev": true }, "node_modules/@fastify/fast-json-stringify-compiler": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "dev": true, "dependencies": { "fast-json-stringify": "^5.7.0" } @@ -233,6 +237,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3" } @@ -639,6 +644,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -649,7 +655,8 @@ "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", - "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "dev": true }, "node_modules/acorn": { "version": "8.11.3", @@ -752,6 +759,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, "engines": { "node": ">=8.0.0" } @@ -760,6 +768,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.3.2.tgz", "integrity": "sha512-st8e519GWHa/azv8S87mcJvZs4WsgTBjOw/Ih1CP6u+8SZvcOeAYNG6JbsIrAUUJJ7JfmrnOkR8ipDS+u9SIRQ==", + "dev": true, "dependencies": { "@fastify/error": "^3.3.0", "fastq": "^1.17.1" @@ -775,6 +784,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, "funding": [ { "type": "github", @@ -815,6 +825,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, "funding": [ { "type": "github", @@ -922,6 +933,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -1342,6 +1354,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, "engines": { "node": ">=6" } @@ -1350,6 +1363,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, "engines": { "node": ">=0.8.x" } @@ -1366,7 +1380,8 @@ "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", - "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", + "dev": true }, "node_modules/fast-copy": { "version": "3.0.2", @@ -1377,7 +1392,8 @@ "node_modules/fast-decode-uri-component": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", - "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "dev": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -1422,6 +1438,7 @@ "version": "5.16.0", "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.0.tgz", "integrity": "sha512-A4bg6E15QrkuVO3f0SwIASgzMzR6XC4qTyTqhf3hYXy0iazbAdZKwkE+ox4WgzKyzM6ygvbdq3r134UjOaaAnA==", + "dev": true, "dependencies": { "@fastify/merge-json-schemas": "^0.1.0", "ajv": "^8.10.0", @@ -1442,6 +1459,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dev": true, "dependencies": { "fast-decode-uri-component": "^1.0.1" } @@ -1450,6 +1468,7 @@ "version": "3.5.0", "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, "engines": { "node": ">=6" } @@ -1463,12 +1482,14 @@ "node_modules/fast-uri": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz", - "integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==" + "integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==", + "dev": true }, "node_modules/fastify": { "version": "4.27.0", "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.27.0.tgz", "integrity": "sha512-ci9IXzbigB8dyi0mSy3faa3Bsj0xWAPb9JeT4KRzubdSb6pNhcADRUaXCBml6V1Ss/a05kbtQls5LBmhHydoTA==", + "dev": true, "funding": [ { "type": "github", @@ -1508,6 +1529,7 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -1563,6 +1585,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.0.tgz", "integrity": "sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", @@ -1640,6 +1663,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -1744,6 +1768,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, "funding": [ { "type": "github", @@ -1814,6 +1839,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, "engines": { "node": ">= 0.10" } @@ -1927,6 +1953,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3" } @@ -2009,6 +2036,7 @@ "version": "5.13.0", "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.13.0.tgz", "integrity": "sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==", + "dev": true, "dependencies": { "cookie": "^0.6.0", "process-warning": "^3.0.0", @@ -2239,6 +2267,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, "engines": { "node": ">=14.0.0" } @@ -2379,6 +2408,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/pino/-/pino-9.1.0.tgz", "integrity": "sha512-qUcgfrlyOtjwhNLdbhoL7NR4NkHjzykAPw0V2QLFbvu/zss29h4NkRnibyFzBrNCbzCOY3WZ9hhKSwfOkNggYA==", + "dev": true, "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", @@ -2400,6 +2430,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dev": true, "dependencies": { "readable-stream": "^4.0.0", "split2": "^4.0.0" @@ -2409,6 +2440,7 @@ "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -2464,7 +2496,8 @@ "node_modules/pino-std-serializers": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", - "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==" + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "dev": true }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -2494,6 +2527,7 @@ "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, "engines": { "node": ">= 0.6.0" } @@ -2501,12 +2535,14 @@ "node_modules/process-warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", - "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "dev": true }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -2556,7 +2592,8 @@ "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true }, "node_modules/readable-stream": { "version": "3.6.2", @@ -2576,6 +2613,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, "engines": { "node": ">= 12.13.0" } @@ -2616,6 +2654,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "dev": true, "engines": { "node": ">=10" } @@ -2624,6 +2663,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -2632,7 +2672,8 @@ "node_modules/rfdc": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==" + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true }, "node_modules/rimraf": { "version": "3.0.2", @@ -2720,6 +2761,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -2739,6 +2781,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "dev": true, "dependencies": { "ret": "~0.4.0" } @@ -2747,6 +2790,7 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "dev": true, "engines": { "node": ">=10" } @@ -2754,12 +2798,14 @@ "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "dev": true }, "node_modules/semver": { "version": "7.6.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -2770,7 +2816,8 @@ "node_modules/set-cookie-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", + "dev": true }, "node_modules/shebang-command": { "version": "2.0.0", @@ -2818,6 +2865,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", + "dev": true, "dependencies": { "atomic-sleep": "^1.0.0" } @@ -2826,6 +2874,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, "engines": { "node": ">= 10.x" } @@ -2840,6 +2889,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -2989,6 +3039,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.0.1.tgz", "integrity": "sha512-O5O/RbdV3CjhtwFa4slXvrb/26lzsf4/NMts3QFIRniIsi+584QSneJXaHXasqcZO+B7pWZkr+4h9knhnAQevg==", + "dev": true, "dependencies": { "real-require": "^0.2.0" } @@ -3024,6 +3075,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "dev": true, "engines": { "node": ">=12" } diff --git a/package.json b/package.json index b09a9c9..f2e3a06 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "dependencies": { "ajv": "^8.14.0", "ajv-formats": "^3.0.1", - "fastify": "^4.27.0", "recoil-tdf": "^1.0.0", "tiny-typed-emitter": "^2.1.0", "ws": "^8.17.0" @@ -39,8 +38,9 @@ "@types/ws": "^8.5.10", "@typescript-eslint/eslint-plugin": "^7.11.0", "@typescript-eslint/parser": "^7.11.0", - "eslint": "8.57.0", "eslint-config-prettier": "^9.1.0", + "eslint": "8.57.0", + "fastify": "^4.27.0", "json-schema-to-typescript": "^14.0.4", "pino-pretty": "^11.1.0", "prettier": "3.2.5", diff --git a/src/main.ts b/src/main.ts index 6d09f9c..6ec8b10 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,28 +1,174 @@ -import Fastify from 'fastify'; +import fs from 'node:fs/promises'; +import { setTimeout } from 'node:timers/promises'; +import { once } from 'node:events'; +import { Ajv, JSONSchemaType } from 'ajv'; +import { GamesManager } from './games.js'; +import { + callTachyonAutohost, + createTachyonEvent, + KillRequest, + PlayerAddRequest, + PlayerKickRequest, + PlayerMuteRequest, + PlayersSpecRequest, + precompileSchemas, + SendCommandRequest, + SendMessageRequest, + StartRequest, + StartResponse, + SubscribeUpdatesRequest, + TachyonAutohost, + TachyonError, + TachyonServer, +} from './tachyonTypes.js'; +import { TachyonClient, TachyonClientOpts } from './tachyonClient.js'; -import StartRequestSchema from './schemas/startRequest.json' with { type: 'json' }; -import type { StartRequest } from './types/startRequest.js'; +precompileSchemas(); -import { GamesManager } from './games.js'; +class Autohost implements TachyonAutohost { + private server?: TachyonServer; + + constructor(private manager: GamesManager) {} + + async start(req: StartRequest): Promise { + const { ip, port } = await this.manager.start(req); + return { ips: [ip], port }; + } + + async kill(_req: KillRequest): Promise { + throw new TachyonError('command_unimplemented', 'kill not implemented'); + } + + async playerAdd(_req: PlayerAddRequest): Promise { + throw new TachyonError('command_unimplemented', 'playerAdd not implemented'); + } + + async playerKick(_req: PlayerKickRequest): Promise { + throw new TachyonError('command_unimplemented', 'playerKick not implemented'); + } + + async playerMute(_req: PlayerMuteRequest): Promise { + throw new TachyonError('command_unimplemented', 'playerMute not implemented'); + } + + async playersSpec(_req: PlayersSpecRequest): Promise { + throw new TachyonError('command_unimplemented', 'playersSpec not implemented'); + } + + async sendCommand(_req: SendCommandRequest): Promise { + throw new TachyonError('command_unimplemented', 'sendCommand not implemented'); + } + + async sendMessage(_req: SendMessageRequest): Promise { + throw new TachyonError('command_unimplemented', 'sendMessage not implemented'); + } + + async subscribeUpdates(_req: SubscribeUpdatesRequest): Promise { + throw new TachyonError('command_unimplemented', 'subscribeUpdates not implemented'); + } -const server = Fastify({ - logger: true, -}); + connected(server: TachyonServer): void { + this.server = server; + server.status({ currentGames: 0, maxGames: 10 }); + } -const manager = new GamesManager(); + disconnected(): void { + this.server = undefined; + } +} + +interface Config { + hostname: string; + port: number | null; + clientId: string; + clientSecret: string; +} -server.post<{ Body: StartRequest }>( - '/start', - { schema: { body: StartRequestSchema } }, - async (req) => { - const connectInfo = await manager.start(req.body); - return JSON.stringify(connectInfo); +const ConfigSchema: JSONSchemaType = { + $id: 'Config', + type: 'object', + properties: { + hostname: { type: 'string' }, + port: { type: 'number' }, + clientId: { type: 'string' }, + clientSecret: { type: 'string' }, }, -); + required: ['hostname', 'clientId', 'clientSecret'], + additionalProperties: true, +}; + +const ajv = new Ajv({ strict: true }); +const validateConfig = ajv.compile(ConfigSchema); + +async function main(argv: string[]) { + if (argv.length < 3) { + console.error('Usage: autohost '); + process.exit(1); + } + const configPath = argv[2]; + const config = JSON.parse(await fs.readFile(configPath, 'utf-8')); + if (!validateConfig(config)) { + console.error('Invalid config:', validateConfig.errors); + process.exit(1); + } + + const manager = new GamesManager(); + const autohost = new Autohost(manager); + + const clientOpts: TachyonClientOpts = { + hostname: config.hostname, + clientId: config.clientId, + clientSecret: config.clientSecret, + }; + if (config.port) { + clientOpts.port = config.port; + } + + // This is a simple exponential backoff reconnect loop, we + // just keep trying to connect to the server and if we get + // disconnected we wait a bit and try again. + const minReconnectDelay = 50; + const maxReconnectDelay = 30000; + let nextReconnectDelay: number = minReconnectDelay; + for (;;) { + console.log('Connecting to', config.hostname, '...'); + const client = new TachyonClient(clientOpts); + + client.on('connected', () => { + console.log('Connected to the Tachyon server'); + nextReconnectDelay = minReconnectDelay; + const ts: TachyonServer = { + status: (status) => client.send(createTachyonEvent('autohost/status', status)), + update: (update) => client.send(createTachyonEvent('autohost/update', update)), + }; + autohost.connected(ts); + }); + + client.on('message', async (msg) => { + if (msg.type == 'response') { + console.warn( + "Unexpected response, we don't send requests, commandId: ", + msg.commandId, + ); + return; + } + if (msg.type == 'event') return; + client.send(await callTachyonAutohost(msg, autohost)); + }); + + try { + await once(client, 'close'); + } catch (err) { + console.error('Client connection error:', err); + nextReconnectDelay = Math.min(nextReconnectDelay * 2, maxReconnectDelay); + } finally { + autohost.disconnected(); + } + console.log(`Reconnecting in ${nextReconnectDelay}ms...`); + await setTimeout(nextReconnectDelay); + } +} -try { - await server.listen({ port: 8080 }); -} catch (e) { - server.log.error(e); - process.exit(1); +if (import.meta.filename == process.argv[1]) { + await main(process.argv); }