From e4868f6fdc6dd69653f2813038178de90166944c Mon Sep 17 00:00:00 2001 From: Kostas Drakontidis Date: Sun, 24 May 2026 00:03:51 +0300 Subject: [PATCH 1/5] install mqtt & redis packages --- src/officesense_pi/package-lock.json | 522 ++++++++++++++++++++++++++- src/officesense_pi/package.json | 4 +- 2 files changed, 522 insertions(+), 4 deletions(-) diff --git a/src/officesense_pi/package-lock.json b/src/officesense_pi/package-lock.json index 69828bd..458d0ac 100644 --- a/src/officesense_pi/package-lock.json +++ b/src/officesense_pi/package-lock.json @@ -12,7 +12,9 @@ "@prisma/adapter-better-sqlite3": "^7.8.0", "@prisma/client": "^7.8.0", "dotenv": "^17.4.2", - "express": "^5.2.1" + "express": "^5.2.1", + "mqtt": "^5.15.1", + "redis": "^5.12.1" }, "devDependencies": { "@types/better-sqlite3": "^7.6.13", @@ -23,6 +25,15 @@ "typescript": "^6.0.3" } }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@electric-sql/pglite": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz", @@ -870,6 +881,78 @@ } } }, + "node_modules/@redis/bloom": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.12.1.tgz", + "integrity": "sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==", + "license": "MIT", + "engines": { + "node": ">= 18.19.0" + }, + "peerDependencies": { + "@redis/client": "^5.12.1" + } + }, + "node_modules/@redis/client": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.12.1.tgz", + "integrity": "sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==", + "license": "MIT", + "dependencies": { + "cluster-key-slot": "1.1.2" + }, + "engines": { + "node": ">= 18.19.0" + }, + "peerDependencies": { + "@node-rs/xxhash": "^1.1.0", + "@opentelemetry/api": ">=1 <2" + }, + "peerDependenciesMeta": { + "@node-rs/xxhash": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@redis/json": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.12.1.tgz", + "integrity": "sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==", + "license": "MIT", + "engines": { + "node": ">= 18.19.0" + }, + "peerDependencies": { + "@redis/client": "^5.12.1" + } + }, + "node_modules/@redis/search": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.12.1.tgz", + "integrity": "sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==", + "license": "MIT", + "engines": { + "node": ">= 18.19.0" + }, + "peerDependencies": { + "@redis/client": "^5.12.1" + } + }, + "node_modules/@redis/time-series": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.12.1.tgz", + "integrity": "sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==", + "license": "MIT", + "engines": { + "node": ">= 18.19.0" + }, + "peerDependencies": { + "@redis/client": "^5.12.1" + } + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -944,7 +1027,6 @@ "version": "25.7.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz", "integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.21.0" @@ -975,6 +1057,15 @@ "csstype": "^3.2.2" } }, + "node_modules/@types/readable-stream": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz", + "integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", @@ -996,6 +1087,27 @@ "@types/node": "*" } }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -1121,6 +1233,18 @@ "url": "https://opencollective.com/express" } }, + "node_modules/broker-factory": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.14.tgz", + "integrity": "sha512-L45k5HMbPIrMid0nTOZ/UPXG/c0aRuQKVrSDFIb1zOkvfiyHgYmIjc3cSiN1KwQIvRDOtKE0tfb3I9EZ3CmpQQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "fast-unique-numbers": "^9.0.27", + "tslib": "^2.8.1", + "worker-factory": "^7.0.49" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -1145,6 +1269,12 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1247,6 +1377,36 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "license": "ISC" }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/commist": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", + "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, "node_modules/confbox": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", @@ -1581,6 +1741,24 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -1670,6 +1848,19 @@ "devOptional": true, "license": "MIT" }, + "node_modules/fast-unique-numbers": { + "version": "9.0.27", + "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.27.tgz", + "integrity": "sha512-nDA9ADeINN8SA2u2wCtU+siWFTTDqQR37XvgPIDDmboWQeExz7X0mImxuaN+kJddliIqy2FpVRmnvRZ+j8i1/A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.2.0" + } + }, "node_modules/fast-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", @@ -1919,6 +2110,12 @@ "node": ">= 0.4" } }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, "node_modules/hono": { "version": "4.12.18", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", @@ -2004,6 +2201,15 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "license": "ISC" }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2043,6 +2249,16 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -2057,6 +2273,12 @@ "devOptional": true, "license": "Apache-2.0" }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/lru.min": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", @@ -2155,6 +2377,141 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, + "node_modules/mqtt": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.15.1.tgz", + "integrity": "sha512-V1WnkGuJh3ec9QXzy5Iylw8OOBK+Xu1WhxcQ9mMpLThG+/JZIMV1PgLNRgIiqXhZnvnVLsuyxHl5A/3bHHbcAA==", + "license": "MIT", + "dependencies": { + "@types/readable-stream": "^4.0.21", + "@types/ws": "^8.18.1", + "commist": "^3.2.0", + "concat-stream": "^2.0.0", + "debug": "^4.4.1", + "help-me": "^5.0.0", + "lru-cache": "^10.4.3", + "minimist": "^1.2.8", + "mqtt-packet": "^9.0.2", + "number-allocator": "^1.0.14", + "readable-stream": "^4.7.0", + "rfdc": "^1.4.1", + "socks": "^2.8.6", + "split2": "^4.2.0", + "worker-timers": "^8.0.23", + "ws": "^8.18.3" + }, + "bin": { + "mqtt": "build/bin/mqtt.js", + "mqtt_pub": "build/bin/pub.js", + "mqtt_sub": "build/bin/sub.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/mqtt-packet": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz", + "integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==", + "license": "MIT", + "dependencies": { + "bl": "^6.0.8", + "debug": "^4.3.4", + "process-nextick-args": "^2.0.1" + } + }, + "node_modules/mqtt-packet/node_modules/bl": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz", + "integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==", + "license": "MIT", + "dependencies": { + "@types/readable-stream": "^4.0.0", + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "node_modules/mqtt-packet/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/mqtt-packet/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/mqtt/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/mqtt/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2222,6 +2579,16 @@ "node": ">=10" } }, + "node_modules/number-allocator": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", + "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.1", + "js-sdsl": "4.3.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -2392,6 +2759,21 @@ } } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/proper-lockfile": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", @@ -2569,6 +2951,22 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/redis": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-5.12.1.tgz", + "integrity": "sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==", + "license": "MIT", + "dependencies": { + "@redis/bloom": "5.12.1", + "@redis/client": "5.12.1", + "@redis/json": "5.12.1", + "@redis/search": "5.12.1", + "@redis/time-series": "5.12.1" + }, + "engines": { + "node": ">= 18.19.0" + } + }, "node_modules/remeda": { "version": "2.33.4", "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", @@ -2609,6 +3007,12 @@ "node": ">= 4" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -2881,6 +3285,39 @@ "simple-concat": "^1.0.0" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sqlstring": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", @@ -2962,6 +3399,12 @@ "node": ">=0.6" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/tsx": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", @@ -3025,6 +3468,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, "node_modules/typescript": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", @@ -3043,7 +3492,6 @@ "version": "7.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz", "integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==", - "dev": true, "license": "MIT" }, "node_modules/unpipe": { @@ -3101,12 +3549,80 @@ "node": ">= 8" } }, + "node_modules/worker-factory": { + "version": "7.0.49", + "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.49.tgz", + "integrity": "sha512-lW7tpgy6aUv2dFsQhv1yv+XFzdkCf/leoKRTGMPVK5/die6RrUjqgJHJf556qO+ZfytNG6wPXc17E8zzsOLUDw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "fast-unique-numbers": "^9.0.27", + "tslib": "^2.8.1" + } + }, + "node_modules/worker-timers": { + "version": "8.0.31", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.31.tgz", + "integrity": "sha512-ngkq5S6JuZyztom8tDgBzorLo9byhBMko/sXfgiUD945AuzKGg1GCgDMCC3NaYkicLpGKXutONM36wEX8UbBCA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "tslib": "^2.8.1", + "worker-timers-broker": "^8.0.16", + "worker-timers-worker": "^9.0.14" + } + }, + "node_modules/worker-timers-broker": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.16.tgz", + "integrity": "sha512-JyP3AvUGyPGbBGW7XiUewm2+0pN/aYo1QpVf5kdXAfkDZcN3p7NbWrG6XnyDEpDIvfHk/+LCnOW/NsuiU9riYA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "broker-factory": "^3.1.14", + "fast-unique-numbers": "^9.0.27", + "tslib": "^2.8.1", + "worker-timers-worker": "^9.0.14" + } + }, + "node_modules/worker-timers-worker": { + "version": "9.0.14", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.14.tgz", + "integrity": "sha512-/qF06C60sXmSLfUl7WglvrDIbspmPOM8UrG63Dnn4bi2x4/DfqHS/+dxF5B+MdHnYO5tVuZYLHdAodrKdabTIg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "tslib": "^2.8.1", + "worker-factory": "^7.0.49" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/zeptomatch": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", diff --git a/src/officesense_pi/package.json b/src/officesense_pi/package.json index b762990..322579d 100644 --- a/src/officesense_pi/package.json +++ b/src/officesense_pi/package.json @@ -23,6 +23,8 @@ "@prisma/adapter-better-sqlite3": "^7.8.0", "@prisma/client": "^7.8.0", "dotenv": "^17.4.2", - "express": "^5.2.1" + "express": "^5.2.1", + "mqtt": "^5.15.1", + "redis": "^5.12.1" } } From 18932a3f4d864607021fa5bd856e3af8caa84f46 Mon Sep 17 00:00:00 2001 From: Kostas Drakontidis Date: Sun, 24 May 2026 00:03:59 +0300 Subject: [PATCH 2/5] add room entity --- src/officesense_pi/prisma/schema.prisma | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/officesense_pi/prisma/schema.prisma b/src/officesense_pi/prisma/schema.prisma index 2ee1290..13ca304 100644 --- a/src/officesense_pi/prisma/schema.prisma +++ b/src/officesense_pi/prisma/schema.prisma @@ -19,4 +19,9 @@ model Tag { id String @id @default(uuid()) userId String @unique user User @relation(fields: [userId], references: [id]) -} \ No newline at end of file +} + +model Room { + id String @id @default(uuid()) + name String +} From 9d024de5a6f6f9975785464b990a1b7e044116e6 Mon Sep 17 00:00:00 2001 From: Kostas Drakontidis Date: Sun, 24 May 2026 00:04:43 +0300 Subject: [PATCH 3/5] get data from tag table instead of user --- src/officesense_pi/src/api/lookup/lookup.repository.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/officesense_pi/src/api/lookup/lookup.repository.ts b/src/officesense_pi/src/api/lookup/lookup.repository.ts index 27c08ca..f50f025 100644 --- a/src/officesense_pi/src/api/lookup/lookup.repository.ts +++ b/src/officesense_pi/src/api/lookup/lookup.repository.ts @@ -1,9 +1,9 @@ import { prisma } from "../../lib/prisma.js"; export async function existsByUUID(uuid: string): Promise { - const user = await prisma.user.findUnique({ + const tag = await prisma.tag.findUnique({ where: { id: uuid } }); - return !!user; + return !!tag; } From a3d28e8cd53a355cae63845eca32665dd0eade23 Mon Sep 17 00:00:00 2001 From: Kostas Drakontidis Date: Sun, 24 May 2026 00:18:31 +0300 Subject: [PATCH 4/5] prisma migrations --- .../migration.sql | 20 +++++++++++++++++++ .../migration.sql | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/officesense_pi/prisma/migrations/20260514162920_add_room_entity/migration.sql create mode 100644 src/officesense_pi/prisma/migrations/20260514174139_room_name_typo/migration.sql diff --git a/src/officesense_pi/prisma/migrations/20260514162920_add_room_entity/migration.sql b/src/officesense_pi/prisma/migrations/20260514162920_add_room_entity/migration.sql new file mode 100644 index 0000000..00af0a9 --- /dev/null +++ b/src/officesense_pi/prisma/migrations/20260514162920_add_room_entity/migration.sql @@ -0,0 +1,20 @@ +-- CreateTable +CREATE TABLE "Room" ( + "id" TEXT NOT NULL PRIMARY KEY, + "nameame" TEXT NOT NULL +); + +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_User" ( + "id" TEXT NOT NULL PRIMARY KEY, + "firstName" TEXT NOT NULL, + "lastName" TEXT NOT NULL, + "faceEmbedding" BLOB +); +INSERT INTO "new_User" ("faceEmbedding", "firstName", "id", "lastName") SELECT "faceEmbedding", "firstName", "id", "lastName" FROM "User"; +DROP TABLE "User"; +ALTER TABLE "new_User" RENAME TO "User"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/src/officesense_pi/prisma/migrations/20260514174139_room_name_typo/migration.sql b/src/officesense_pi/prisma/migrations/20260514174139_room_name_typo/migration.sql new file mode 100644 index 0000000..a0c23a7 --- /dev/null +++ b/src/officesense_pi/prisma/migrations/20260514174139_room_name_typo/migration.sql @@ -0,0 +1,19 @@ +/* + Warnings: + + - You are about to drop the column `nameame` on the `Room` table. All the data in the column will be lost. + - Added the required column `name` to the `Room` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Room" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL +); +INSERT INTO "new_Room" ("id") SELECT "id" FROM "Room"; +DROP TABLE "Room"; +ALTER TABLE "new_Room" RENAME TO "Room"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; From 565900c9d47a5ae7fdf8cec093bf96d21ad3fb22 Mon Sep 17 00:00:00 2001 From: Kostas Drakontidis Date: Sun, 24 May 2026 00:19:09 +0300 Subject: [PATCH 5/5] init fully working core code --- src/officesense_pi/src/config/config.ts | 57 ++++++++++ src/officesense_pi/src/core/analyze.ts | 122 ++++++++++++++++++++++ src/officesense_pi/src/core/bootstrap.ts | 16 +++ src/officesense_pi/src/core/mqtt.ts | 48 +++++++++ src/officesense_pi/src/core/redis.ts | 28 +++++ src/officesense_pi/src/core/transition.ts | 94 +++++++++++++++++ src/officesense_pi/src/index.ts | 19 ++-- 7 files changed, 377 insertions(+), 7 deletions(-) create mode 100644 src/officesense_pi/src/config/config.ts create mode 100644 src/officesense_pi/src/core/analyze.ts create mode 100644 src/officesense_pi/src/core/bootstrap.ts create mode 100644 src/officesense_pi/src/core/mqtt.ts create mode 100644 src/officesense_pi/src/core/redis.ts create mode 100644 src/officesense_pi/src/core/transition.ts diff --git a/src/officesense_pi/src/config/config.ts b/src/officesense_pi/src/config/config.ts new file mode 100644 index 0000000..f45d078 --- /dev/null +++ b/src/officesense_pi/src/config/config.ts @@ -0,0 +1,57 @@ +interface Config { + api: { + address: string; + port: number; + }; + mqtt: { + host: string; + port: number; + username: string; + password: string; + topic: string; + }; + redis: { + host: string; + port: number; + }; + core: { + hysteresis: number; + candidateHysteresis: number; + debounceMS: number; + minSamples: number; + transitionTTL: number; + transitionCleanupInterval: number; + lossThreshold: number; + userTTL: number; + }; +} + +const config: Config = { + api: { + address: "0.0.0.0", + port: 80, + }, + mqtt: { + host: "192.168.1.2", + port: 1883, + username: "user", + password: "pass", + topic: "scanners/+", + }, + redis: { + host: "192.168.1.2", + port: 6379, + }, + core: { + hysteresis: 6, + candidateHysteresis: 3, + debounceMS: 3000, + minSamples: 4, + transitionTTL: 5 * 60 * 1000, + transitionCleanupInterval: 60 * 1000, + lossThreshold: 5000, + userTTL: 3 * 60 * 1000 + }, +} + +export default config; \ No newline at end of file diff --git a/src/officesense_pi/src/core/analyze.ts b/src/officesense_pi/src/core/analyze.ts new file mode 100644 index 0000000..4462be7 --- /dev/null +++ b/src/officesense_pi/src/core/analyze.ts @@ -0,0 +1,122 @@ +import { getRedis } from "./redis.js"; +import { prisma } from "../lib/prisma.js"; +import { RoomTransition, transitions } from "./transition.js"; +import config from "../config/config.js"; + +const adjectives = [ + "Crazy", + "Silent", + "Dark", + "Fast", + "Lucky", + "Wild", + "Epic" +]; + +const nouns = [ + "Tiger", + "Wolf", + "Falcon", + "Shadow", + "Ninja", + "Dragon", + "Phoenix" +]; + +function generateNickname() { + const adjective = + adjectives[Math.floor(Math.random() * adjectives.length)]; + + const noun = + nouns[Math.floor(Math.random() * nouns.length)]; + + const number = Math.floor(Math.random() * 1000); + + return `${adjective}${noun}${number}`; +} + +function newUser(): { pseudoID: string, psuedoName: string } { + return { + pseudoID: crypto.randomUUID(), + psuedoName: generateNickname() + }; +} + +export async function analyzeData(roomID: string, metrics: { + tagID: string, + rssi: number +}) { + console.log(`\n=======================================================\n` + + `ROOM_ID: ${roomID}\nTAG_ID: ${metrics.tagID}\nRSSI: ${metrics.rssi}\n` + + `=======================================================\n`); + + const userID = ( + await prisma.tag.findUnique({ + where: { id: metrics.tagID }, + select: { userId: true }, + }) + )?.userId; + + console.log(`[SQLite] Resolved USER_ID: ${userID}`); + + if (!userID) + return; + + const redis = getRedis(); + const res = await redis.get(`user:${userID}`); + + if (!res) { + const user = newUser(); + console.log(`[Redis] Created USER: ${user.psuedoName} USER_ID: ${user.pseudoID}`); + + // trigger camera + + await redis.set(`user:${userID}`, JSON.stringify({ + userID: user.pseudoID, + name: user.psuedoName, + rssi: metrics.rssi, + room: roomID, + verified: false, + timestamp: Date.now() + }), { PX: config.core.userTTL }); + + console.log("[Redis] Stored new user in redis."); + + return; + } + + let resObj = JSON.parse(res); + console.log(`[Redis] User exists in redis in ROOM_ID: ${resObj["room"]}`); + + if (roomID == resObj["room"]) { + console.log("[Redis] Same room, updating redis..."); + resObj["rssi"] = metrics.rssi; + resObj["timestamp"] = Date.now() + + await redis.set(`user:${userID}`, JSON.stringify(resObj), { PX: config.core.userTTL }); + + return; + } + + let transition = transitions.get(userID); + + if (!transition) { + console.log("[!] Starting new transition"); + transition = new RoomTransition(); + transitions.set(userID, transition); + } + + if (transition.shouldTransitionTo(roomID, metrics.rssi, resObj["rssi"], resObj["timestamp"])) { + // trigger camera + + console.log(`[!] Transition done ${resObj["room"]} -> ${roomID}`); + + resObj["rssi"] = metrics.rssi; + resObj["room"] = roomID; + resObj["timestamp"] = Date.now() + + + await redis.set(`user:${userID}`, JSON.stringify(resObj), { PX: config.core.userTTL }); + } else + console.log("[!] Transition declined"); +} \ No newline at end of file diff --git a/src/officesense_pi/src/core/bootstrap.ts b/src/officesense_pi/src/core/bootstrap.ts new file mode 100644 index 0000000..a089428 --- /dev/null +++ b/src/officesense_pi/src/core/bootstrap.ts @@ -0,0 +1,16 @@ +import { initRedis } from "./redis.js"; +import * as mqtt from "./mqtt.js"; +import { cleanupWorker } from "./transition.js"; + +export async function bootstrap() { + try { + await initRedis(); + await mqtt.start(); + cleanupWorker(); + + console.log("Core started."); + } catch (err: any) { + console.log("Bootstrap failed:", err.message); + process.exit(1); + } +} \ No newline at end of file diff --git a/src/officesense_pi/src/core/mqtt.ts b/src/officesense_pi/src/core/mqtt.ts new file mode 100644 index 0000000..11fe6a3 --- /dev/null +++ b/src/officesense_pi/src/core/mqtt.ts @@ -0,0 +1,48 @@ +import mqtt, { MqttClient } from "mqtt"; +import config from "../config/config.js"; +import { analyzeData } from "./analyze.js"; + +function initMqtt(): Promise { + return new Promise((resolve, reject) => { + const client = mqtt.connect( + `mqtt://${config.mqtt.host}:${config.mqtt.port}`, + { + username: config.mqtt.username, + password: config.mqtt.password + } + ); + + client.once("connect", () => { + console.log("MQTT connected."); + + client.subscribe(config.mqtt.topic, (err) => { + if (err) { + reject(err); + } else { + console.log("MQTT subscribed."); + resolve(client); + } + }); + }); + + client.once("error", (err) => { + reject(err); + }); + }); +} + +export async function start() { + try { + const mqttClient = await initMqtt(); + + mqttClient.on("message", (topic, message) => { + analyzeData(topic.split("/").pop()!, JSON.parse(message.toString())); + }); + + mqttClient.on("error", (err) => { + console.log(err.message); + }) + } catch (err: any) { + console.log("MQTT connection failed:", err.message); + } +} diff --git a/src/officesense_pi/src/core/redis.ts b/src/officesense_pi/src/core/redis.ts new file mode 100644 index 0000000..c9b1944 --- /dev/null +++ b/src/officesense_pi/src/core/redis.ts @@ -0,0 +1,28 @@ +import { createClient, type RedisClientType } from "redis"; +import config from "../config/config.js"; + +let redisClient: RedisClientType; + +export async function initRedis(): Promise { + redisClient = createClient({ + url: `redis://${config.redis.host}:${config.redis.port}` + }); + + redisClient.on("error", (err) => { + console.log("Redis error:", err.message); + }); + + await redisClient.connect(); + + console.log("Redis connected."); + + return redisClient; +} + +export function getRedis(): RedisClientType { + if (!redisClient) { + throw new Error("Redis not initialized"); + } + + return redisClient; +} \ No newline at end of file diff --git a/src/officesense_pi/src/core/transition.ts b/src/officesense_pi/src/core/transition.ts new file mode 100644 index 0000000..f7c33d0 --- /dev/null +++ b/src/officesense_pi/src/core/transition.ts @@ -0,0 +1,94 @@ +import config from "../config/config.js"; + +export const transitions = new Map(); + +export function cleanupWorker() { + setInterval(() => { + const now = Date.now(); + + for (const [userID, transition] of transitions) { + const inactiveFor = now - transition.lastSeen; + + if (inactiveFor > 5 * config.core.transitionTTL) + transitions.delete(userID); + } + }, config.core.transitionCleanupInterval); +} + +type Candidate = { + roomID: string | null; + since: number | null; + samples: number; + rssi: number | null; +}; + +export class RoomTransition { + candidate: Candidate; + lastSeen: number; + + constructor() { + this.lastSeen = Date.now(); + this.candidate = { roomID: null, since: null, samples: 0, rssi: null }; + } + + shouldTransitionTo(roomID: string, candidateRSSI: number, currRSSI: number, lastCurrentSeen: number) { + const now = Date.now(); + this.lastSeen = now; + + const stronger = candidateRSSI > currRSSI + config.core.hysteresis; + + const signalLost = now - lastCurrentSeen > config.core.lossThreshold; + + console.log(`[TRANSITION] stronger = ${stronger}`); + console.log(`[TRANSITION] signalLost = ${signalLost}`); + + if (!stronger && !signalLost) { + this.reset(); + return false; + } + + const noCandidate = this.candidate.roomID == null; + const betterCandidate = this.candidate.roomID != roomID && + this.candidate.rssi !== null && + candidateRSSI > this.candidate.rssi + config.core.candidateHysteresis; + + console.log(`[TRANSITION] noCandidate = ${noCandidate}`); + console.log(`[TRANSITION] betterCandidate = ${betterCandidate}`); + + if (noCandidate || betterCandidate) { + this.candidate.roomID = roomID; + this.candidate.since = now; + this.candidate.samples = 1; + this.candidate.rssi = candidateRSSI; + + return false; + } + + this.candidate.samples++; + this.candidate.rssi = candidateRSSI; + + console.log(`[TRANSITION] samples = ${this.candidate.samples}`); + console.log(`[TRANSITION] candidateRSSI = ${this.candidate.rssi}`); + + const enoughTime = now - (this.candidate.since ?? now) >= config.core.debounceMS; + const enoughConfirmations = this.candidate.samples >= config.core.minSamples; + + console.log(`[TRANSITION] enoughTime = ${enoughTime}`); + console.log(`[TRANSITION] enoughConfirmations = ${enoughConfirmations}`); + console.log(`[TRANSITION] signalLost = ${signalLost}`); + + if ((enoughTime && enoughConfirmations) || signalLost) { + this.reset(); + return true; + } + + return false; + } + + reset() { + this.candidate.roomID = null; + this.candidate.since = null; + this.candidate.samples = 0; + this.candidate.rssi = null; + } +} \ No newline at end of file diff --git a/src/officesense_pi/src/index.ts b/src/officesense_pi/src/index.ts index 8844cdd..e0e57d8 100644 --- a/src/officesense_pi/src/index.ts +++ b/src/officesense_pi/src/index.ts @@ -1,12 +1,17 @@ import express from "express"; import lookupRoutes from "./api/lookup/lookup.routes.js"; +import config from "./config/config.js"; +import { bootstrap } from "./core/bootstrap.js"; -const app = express(); -const PORT = 80; -const ADDRESS = "0.0.0.0"; +(async () => { + const app = express(); -app.use("/", lookupRoutes); + app.use("/", lookupRoutes); -app.listen(PORT, ADDRESS, () => { - console.log(`Server listening on ${ADDRESS}:${PORT}`); -}); + app.listen(config.api.port, config.api.address, () => { + console.log(`Server listening on ${config.api.address}:${config.api.port}`); + }); + + bootstrap(); + +})()