refactor: migrate from node-sqlite3-wasm to better-sqlite3

Replace all db.run(sql, [params]) calls with db.prepare(sql).run(...params)
across all source modules and test files. Also remove the node-sqlite3-wasm
import from tests/db.test.ts and update the type annotation accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Mueller 2026-04-06 21:17:44 +02:00
parent 25d07a6bc4
commit e760853781
16 changed files with 154 additions and 751 deletions

View File

@ -8,8 +8,6 @@
"name": "display-middleware", "name": "display-middleware",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@types/bcryptjs": "^2.4.6",
"bcrypt": "^5.1.1",
"bcryptjs": "^3.0.3", "bcryptjs": "^3.0.3",
"better-sqlite3": "^9.6.0", "better-sqlite3": "^9.6.0",
"cors": "^2.8.6", "cors": "^2.8.6",
@ -20,7 +18,7 @@
"pg": "^8.20.0" "pg": "^8.20.0"
}, },
"devDependencies": { "devDependencies": {
"@types/bcrypt": "^5.0.2", "@types/bcryptjs": "^2.4.6",
"@types/better-sqlite3": "^7.6.13", "@types/better-sqlite3": "^7.6.13",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/express": "^4.17.25", "@types/express": "^4.17.25",
@ -505,26 +503,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
"license": "BSD-3-Clause",
"dependencies": {
"detect-libc": "^2.0.0",
"https-proxy-agent": "^5.0.0",
"make-dir": "^3.1.0",
"node-fetch": "^2.6.7",
"nopt": "^5.0.0",
"npmlog": "^5.0.1",
"rimraf": "^3.0.2",
"semver": "^7.3.5",
"tar": "^6.1.11"
},
"bin": {
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@noble/hashes": { "node_modules/@noble/hashes": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
@ -944,20 +922,11 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/bcrypt": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
"integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/bcryptjs": { "node_modules/@types/bcryptjs": {
"version": "2.4.6", "version": "2.4.6",
"resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz",
"integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/better-sqlite3": { "node_modules/@types/better-sqlite3": {
@ -1264,12 +1233,6 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
} }
}, },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"license": "ISC"
},
"node_modules/abort-controller": { "node_modules/abort-controller": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@ -1321,50 +1284,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/agent-base/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/agent-base/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": { "node_modules/ansi-styles": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
@ -1378,40 +1297,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/aproba": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz",
"integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==",
"license": "ISC"
},
"node_modules/are-we-there-yet": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
"deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/are-we-there-yet/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/array-flatten": { "node_modules/array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -1442,12 +1327,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/base64-js": { "node_modules/base64-js": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -1468,20 +1347,6 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/bcrypt": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
"integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.11",
"node-addon-api": "^5.0.0"
},
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/bcryptjs": { "node_modules/bcryptjs": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz",
@ -1547,16 +1412,6 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/brace-expansion": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/broker-factory": { "node_modules/broker-factory": {
"version": "3.1.14", "version": "3.1.14",
"resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.14.tgz", "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.14.tgz",
@ -1685,24 +1540,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"license": "ISC",
"bin": {
"color-support": "bin.js"
}
},
"node_modules/combined-stream": { "node_modules/combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -1732,12 +1569,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/concat-stream": { "node_modules/concat-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
@ -1774,12 +1605,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"license": "ISC"
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@ -1911,12 +1736,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"license": "MIT"
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -1995,12 +1814,6 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/encodeurl": { "node_modules/encodeurl": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
@ -2343,36 +2156,6 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"license": "ISC",
"dependencies": {
"minipass": "^3.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/fs-minipass/node_modules/minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"license": "ISC"
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -2397,27 +2180,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gauge": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
"deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"aproba": "^1.0.3 || ^2.0.0",
"color-support": "^1.1.2",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.1",
"object-assign": "^4.1.1",
"signal-exit": "^3.0.0",
"string-width": "^4.2.3",
"strip-ansi": "^6.0.1",
"wide-align": "^1.1.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/get-func-name": { "node_modules/get-func-name": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
@ -2497,27 +2259,6 @@
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@ -2558,12 +2299,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"license": "ISC"
},
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
@ -2602,42 +2337,6 @@
"url": "https://opencollective.com/express" "url": "https://opencollective.com/express"
} }
}, },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/https-proxy-agent/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/https-proxy-agent/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/human-signals": { "node_modules/human-signals": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
@ -2680,17 +2379,6 @@
], ],
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@ -2721,15 +2409,6 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-stream": { "node_modules/is-stream": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
@ -2901,30 +2580,6 @@
"@jridgewell/sourcemap-codec": "^1.5.5" "@jridgewell/sourcemap-codec": "^1.5.5"
} }
}, },
"node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"license": "MIT",
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -3026,18 +2681,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": { "node_modules/minimist": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
@ -3047,52 +2690,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"license": "ISC",
"engines": {
"node": ">=8"
}
},
"node_modules/minizlib": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"license": "MIT",
"dependencies": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"license": "MIT",
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/mkdirp-classic": { "node_modules/mkdirp-classic": {
"version": "0.5.3", "version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
@ -3260,53 +2857,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/node-addon-api": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
"license": "MIT"
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-sqlite3-wasm": { "node_modules/node-sqlite3-wasm": {
"version": "0.8.55", "version": "0.8.55",
"resolved": "https://registry.npmjs.org/node-sqlite3-wasm/-/node-sqlite3-wasm-0.8.55.tgz", "resolved": "https://registry.npmjs.org/node-sqlite3-wasm/-/node-sqlite3-wasm-0.8.55.tgz",
"integrity": "sha512-C2m7JzZgKiv9XVZ1ts9oPmS56PCvyHeQffTOF2KNO2TVZzq5IW2s+NFeEZn+eP6bnAuD2We/O9cOJSjQVf7Xxw==", "integrity": "sha512-C2m7JzZgKiv9XVZ1ts9oPmS56PCvyHeQffTOF2KNO2TVZzq5IW2s+NFeEZn+eP6bnAuD2We/O9cOJSjQVf7Xxw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"license": "ISC",
"dependencies": {
"abbrev": "1"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/npm-run-path": { "node_modules/npm-run-path": {
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
@ -3336,19 +2892,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/npmlog": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
"deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"are-we-there-yet": "^2.0.0",
"console-control-strings": "^1.1.0",
"gauge": "^3.0.0",
"set-blocking": "^2.0.0"
}
},
"node_modules/number-allocator": { "node_modules/number-allocator": {
"version": "1.0.14", "version": "1.0.14",
"resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
@ -3465,15 +3008,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": { "node_modules/path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -3863,22 +3397,6 @@
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.60.1", "version": "4.60.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
@ -4007,12 +3525,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@ -4121,12 +3633,6 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
"node_modules/simple-concat": { "node_modules/simple-concat": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
@ -4247,32 +3753,6 @@
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
} }
}, },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-final-newline": { "node_modules/strip-final-newline": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
@ -4384,24 +3864,6 @@
"node": ">=6.4.0" "node": ">=6.4.0"
} }
}, },
"node_modules/tar": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"license": "ISC",
"dependencies": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
"minipass": "^5.0.0",
"minizlib": "^2.1.1",
"mkdirp": "^1.0.3",
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/tar-fs": { "node_modules/tar-fs": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
@ -4521,12 +3983,6 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.8.1", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@ -5283,22 +4739,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -5332,15 +4772,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"license": "ISC",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/worker-factory": { "node_modules/worker-factory": {
"version": "7.0.49", "version": "7.0.49",
"resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.49.tgz", "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.49.tgz",
@ -5424,12 +4855,6 @@
"node": ">=0.4" "node": ">=0.4"
} }
}, },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz",

View File

@ -44,10 +44,9 @@ router.get('/:id', (req: Request, res: Response): void => {
} }
// Update last_seen // Update last_seen
db.run( db.prepare(
`UPDATE displays SET last_seen = datetime('now') WHERE id = ?`, `UPDATE displays SET last_seen = datetime('now') WHERE id = ?`
[displayId] ).run(displayId);
);
const json = buildDisplayJson(displayId); const json = buildDisplayJson(displayId);
if (!json) { if (!json) {

View File

@ -43,11 +43,10 @@ router.post('/', (req, res): void => {
const { name, description, layout_id, api_token, refresh_sec } = req.body; const { name, description, layout_id, api_token, refresh_sec } = req.body;
if (!name) { res.status(400).json({ error: 'name is required' }); return; } if (!name) { res.status(400).json({ error: 'name is required' }); return; }
const result = db.run( const result = db.prepare(
`INSERT INTO displays (name, description, layout_id, api_token, refresh_sec) `INSERT INTO displays (name, description, layout_id, api_token, refresh_sec)
VALUES (?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?)`
[name, description ?? null, layout_id ?? null, api_token ?? null, refresh_sec ?? 300] ).run(name, description ?? null, layout_id ?? null, api_token ?? null, refresh_sec ?? 300);
);
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
res.status(201).json(db.prepare('SELECT * FROM displays WHERE id = ?').get(id)); res.status(201).json(db.prepare('SELECT * FROM displays WHERE id = ?').get(id));
} catch (err) { } catch (err) {
@ -78,7 +77,7 @@ router.put('/:id', (req, res): void => {
} }
values.push(id); values.push(id);
db.run(`UPDATE displays SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE displays SET ${fields.join(', ')} WHERE id = ?`).run(...values);
const display = db.prepare('SELECT * FROM displays WHERE id = ?').get(id); const display = db.prepare('SELECT * FROM displays WHERE id = ?').get(id);
if (!display) { res.status(404).json({ error: 'Display not found' }); return; } if (!display) { res.status(404).json({ error: 'Display not found' }); return; }
res.json(display); res.json(display);
@ -91,7 +90,7 @@ router.put('/:id', (req, res): void => {
router.delete('/:id', (req, res): void => { router.delete('/:id', (req, res): void => {
try { try {
const db = getDb(); const db = getDb();
const result = db.run('DELETE FROM displays WHERE id = ?', [parseInt(req.params.id)]); const result = db.prepare('DELETE FROM displays WHERE id = ?').run(parseInt(req.params.id));
if ((result.changes as number) === 0) { res.status(404).json({ error: 'Display not found' }); return; } if ((result.changes as number) === 0) { res.status(404).json({ error: 'Display not found' }); return; }
res.status(204).send(); res.status(204).send();
} catch (err) { } catch (err) {

View File

@ -1,16 +1,13 @@
import { Database } from 'node-sqlite3-wasm'; import Database from 'better-sqlite3';
import { migrate001 } from './migrations/001-initial'; import { migrate001 } from './migrations/001-initial';
let dbInstance: Database | null = null; let dbInstance: Database.Database | null = null;
export function initDb(path: string): Database { export function initDb(path: string): Database.Database {
// node-sqlite3-wasm: pass undefined for in-memory DB const db = new Database(path === ':memory:' ? ':memory:' : path);
const db = new Database(path === ':memory:' ? undefined : path);
// Enable WAL mode (file-based databases only, :memory: uses 'memory' mode) db.pragma('journal_mode = WAL');
db.exec('PRAGMA journal_mode = WAL'); db.pragma('foreign_keys = ON');
// Enable foreign key constraints
db.exec('PRAGMA foreign_keys = ON');
// Run migrations // Run migrations
migrate001(db); migrate001(db);
@ -19,7 +16,7 @@ export function initDb(path: string): Database {
return db; return db;
} }
export function getDb(): Database { export function getDb(): Database.Database {
if (!dbInstance) { if (!dbInstance) {
throw new Error('Database not initialized. Call initDb() first.'); throw new Error('Database not initialized. Call initDb() first.');
} }

View File

@ -1,4 +1,4 @@
import { Database } from 'node-sqlite3-wasm'; import Database from 'better-sqlite3';
export function migrate001(db: Database): void { export function migrate001(db: Database): void {
db.exec(` db.exec(`

View File

@ -19,10 +19,9 @@ async function main(): Promise<void> {
if (userCount.count === 0) { if (userCount.count === 0) {
const hash = bcrypt.hashSync('admin', 10); const hash = bcrypt.hashSync('admin', 10);
db.run( db.prepare(
`INSERT INTO users (username, password_hash) VALUES (?, ?)`, `INSERT INTO users (username, password_hash) VALUES (?, ?)`
['admin', hash] ).run('admin', hash);
);
console.log('Created default admin user (admin/admin)'); console.log('Created default admin user (admin/admin)');
} }

View File

@ -54,10 +54,9 @@ export function updateDatapointValue(id: number, rawValue: string): Datapoint |
const transformed = applyTransform(rawValue, config); const transformed = applyTransform(rawValue, config);
db.run( db.prepare(
`UPDATE datapoints SET value = ?, status = 'ok', updated_at = datetime('now') WHERE id = ?`, `UPDATE datapoints SET value = ?, status = 'ok', updated_at = datetime('now') WHERE id = ?`
[transformed, id] ).run(transformed, id);
);
return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint | undefined; return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint | undefined;
} }
@ -87,7 +86,7 @@ export function updateDatapoint(id: number, data: DatapointUpdate): Datapoint |
if (fields.length === 0) return getDatapointById(id); if (fields.length === 0) return getDatapointById(id);
values.push(id); values.push(id);
db.run(`UPDATE datapoints SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE datapoints SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return getDatapointById(id); return getDatapointById(id);
} }
@ -97,11 +96,10 @@ export function createDatapointFromMqtt(
topicPath: string topicPath: string
): Datapoint { ): Datapoint {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO datapoints (name, label, source_type, source_id, topic_id, enabled) `INSERT INTO datapoints (name, label, source_type, source_id, topic_id, enabled)
VALUES (?, ?, 'mqtt', ?, ?, 1)`, VALUES (?, ?, 'mqtt', ?, ?, 1)`
[topicPath, topicPath, brokerId, topicId] ).run(topicPath, topicPath, brokerId, topicId);
);
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint; return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint;
} }
@ -112,11 +110,10 @@ export function createDatapointFromPg(
queryName: string queryName: string
): Datapoint { ): Datapoint {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO datapoints (name, label, source_type, source_id, query_id, enabled) `INSERT INTO datapoints (name, label, source_type, source_id, query_id, enabled)
VALUES (?, ?, 'postgresql', ?, ?, 1)`, VALUES (?, ?, 'postgresql', ?, ?, 1)`
[queryName, queryName, sourceId, queryId] ).run(queryName, queryName, sourceId, queryId);
);
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint; return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint;
} }

View File

@ -92,17 +92,16 @@ export function getLayoutById(id: number): LayoutWithElements | undefined {
export function createLayout(data: CreateLayoutData): Layout { export function createLayout(data: CreateLayoutData): Layout {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO layouts (name, type, width, height, grid_cols, grid_rows) `INSERT INTO layouts (name, type, width, height, grid_cols, grid_rows)
VALUES (?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?)`
[ ).run(
data.name, data.name,
data.type ?? 'free', data.type ?? 'free',
data.width ?? 800, data.width ?? 800,
data.height ?? 480, data.height ?? 480,
data.grid_cols ?? null, data.grid_cols ?? null,
data.grid_rows ?? null, data.grid_rows ?? null,
]
); );
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM layouts WHERE id = ?').get(id) as Layout; return db.prepare('SELECT * FROM layouts WHERE id = ?').get(id) as Layout;
@ -125,41 +124,40 @@ export function updateLayout(id: number, data: UpdateLayoutData): Layout | undef
} }
values.push(id); values.push(id);
db.run(`UPDATE layouts SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE layouts SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return db.prepare('SELECT * FROM layouts WHERE id = ?').get(id) as Layout | undefined; return db.prepare('SELECT * FROM layouts WHERE id = ?').get(id) as Layout | undefined;
} }
export function deleteLayout(id: number): boolean { export function deleteLayout(id: number): boolean {
const db = getDb(); const db = getDb();
const result = db.run('DELETE FROM layouts WHERE id = ?', [id]); const result = db.prepare('DELETE FROM layouts WHERE id = ?').run(id);
return (result.changes as number) > 0; return (result.changes as number) > 0;
} }
export function addElement(layoutId: number, data: CreateElementData): LayoutElement { export function addElement(layoutId: number, data: CreateElementData): LayoutElement {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO layout_elements `INSERT INTO layout_elements
(layout_id, datapoint_id, type, x, y, width, height, font_size, font_weight, (layout_id, datapoint_id, type, x, y, width, height, font_size, font_weight,
text_align, icon, style, static_text, grid_col, grid_row, sort_order) text_align, icon, style, static_text, grid_col, grid_row, sort_order)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
[ ).run(
layoutId, layoutId,
data.datapoint_id ?? null, data.datapoint_id ?? null,
data.type, data.type,
data.x ?? 0, data.x ?? 0,
data.y ?? 0, data.y ?? 0,
data.width ?? null, data.width ?? null,
data.height ?? null, data.height ?? null,
data.font_size ?? 24, data.font_size ?? 24,
data.font_weight ?? 'normal', data.font_weight ?? 'normal',
data.text_align ?? 'left', data.text_align ?? 'left',
data.icon ?? null, data.icon ?? null,
data.style ?? 'plain', data.style ?? 'plain',
data.static_text ?? null, data.static_text ?? null,
data.grid_col ?? null, data.grid_col ?? null,
data.grid_row ?? null, data.grid_row ?? null,
data.sort_order ?? 0, data.sort_order ?? 0,
]
); );
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM layout_elements WHERE id = ?').get(id) as LayoutElement; return db.prepare('SELECT * FROM layout_elements WHERE id = ?').get(id) as LayoutElement;
@ -200,12 +198,12 @@ export function updateElement(id: number, data: UpdateElementData): LayoutElemen
} }
values.push(id); values.push(id);
db.run(`UPDATE layout_elements SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE layout_elements SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return db.prepare('SELECT * FROM layout_elements WHERE id = ?').get(id) as LayoutElement | undefined; return db.prepare('SELECT * FROM layout_elements WHERE id = ?').get(id) as LayoutElement | undefined;
} }
export function deleteElement(id: number): boolean { export function deleteElement(id: number): boolean {
const db = getDb(); const db = getDb();
const result = db.run('DELETE FROM layout_elements WHERE id = ?', [id]); const result = db.prepare('DELETE FROM layout_elements WHERE id = ?').run(id);
return (result.changes as number) > 0; return (result.changes as number) > 0;
} }

View File

@ -55,18 +55,17 @@ export function getBrokerById(id: number): MqttBroker | undefined {
export function createBroker(data: CreateBrokerData): MqttBroker { export function createBroker(data: CreateBrokerData): MqttBroker {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO mqtt_brokers (name, host, port, username, password, use_tls, enabled) `INSERT INTO mqtt_brokers (name, host, port, username, password, use_tls, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?, ?)`
[ ).run(
data.name, data.name,
data.host, data.host,
data.port ?? 1883, data.port ?? 1883,
data.username ?? null, data.username ?? null,
data.password ?? null, data.password ?? null,
data.use_tls ?? 0, data.use_tls ?? 0,
data.enabled ?? 1, data.enabled ?? 1,
]
); );
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM mqtt_brokers WHERE id = ?').get(id) as MqttBroker; return db.prepare('SELECT * FROM mqtt_brokers WHERE id = ?').get(id) as MqttBroker;
@ -89,14 +88,14 @@ export function updateBroker(id: number, data: UpdateBrokerData): MqttBroker | u
fields.push("updated_at = datetime('now')"); fields.push("updated_at = datetime('now')");
values.push(id); values.push(id);
db.run(`UPDATE mqtt_brokers SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE mqtt_brokers SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return getBrokerById(id); return getBrokerById(id);
} }
export function deleteBroker(id: number): boolean { export function deleteBroker(id: number): boolean {
const db = getDb(); const db = getDb();
disconnectBroker(id); disconnectBroker(id);
const result = db.run('DELETE FROM mqtt_brokers WHERE id = ?', [id]); const result = db.prepare('DELETE FROM mqtt_brokers WHERE id = ?').run(id);
return (result.changes as number) > 0; return (result.changes as number) > 0;
} }
@ -107,10 +106,9 @@ function buildConnectUrl(broker: MqttBroker): string {
function setStatus(id: number, status: string): void { function setStatus(id: number, status: string): void {
const db = getDb(); const db = getDb();
db.run( db.prepare(
`UPDATE mqtt_brokers SET status = ?, updated_at = datetime('now') WHERE id = ?`, `UPDATE mqtt_brokers SET status = ?, updated_at = datetime('now') WHERE id = ?`
[status, id] ).run(status, id);
);
} }
export function connectBroker(id: number): Promise<mqtt.MqttClient> { export function connectBroker(id: number): Promise<mqtt.MqttClient> {
@ -172,7 +170,7 @@ export function connectBroker(id: number): Promise<mqtt.MqttClient> {
.get(id, t) as MqttTopic | undefined; .get(id, t) as MqttTopic | undefined;
if (!topicRecord) continue; if (!topicRecord) continue;
db.run('UPDATE mqtt_topics SET last_payload = ? WHERE id = ?', [p, topicRecord.id]); db.prepare('UPDATE mqtt_topics SET last_payload = ? WHERE id = ?').run(p, topicRecord.id);
const extracted = extractValue(p, topicRecord.json_path); const extracted = extractValue(p, topicRecord.json_path);
if (extracted === null) continue; if (extracted === null) continue;

View File

@ -40,7 +40,7 @@ export function updateTopic(id: number, data: UpdateTopicData): MqttTopic | unde
} }
values.push(id); values.push(id);
db.run(`UPDATE mqtt_topics SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE mqtt_topics SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return db.prepare('SELECT * FROM mqtt_topics WHERE id = ?').get(id) as MqttTopic | undefined; return db.prepare('SELECT * FROM mqtt_topics WHERE id = ?').get(id) as MqttTopic | undefined;
} }
@ -51,11 +51,10 @@ function ensureTopicExists(brokerId: number, topic: string): void {
.get(brokerId, topic); .get(brokerId, topic);
if (!existing) { if (!existing) {
db.run( db.prepare(
`INSERT INTO mqtt_topics (broker_id, topic, selected, ignored) `INSERT INTO mqtt_topics (broker_id, topic, selected, ignored)
VALUES (?, ?, 0, 0)`, VALUES (?, ?, 0, 0)`
[brokerId, topic] ).run(brokerId, topic);
);
} }
} }
@ -105,10 +104,9 @@ export function startDiscovery(brokerId: number, prefix?: string): Promise<MqttT
discoveredTopics.add(t); discoveredTopics.add(t);
ensureTopicExists(brokerId, t); ensureTopicExists(brokerId, t);
} }
db.run( db.prepare(
'UPDATE mqtt_topics SET last_payload = ? WHERE broker_id = ? AND topic = ?', 'UPDATE mqtt_topics SET last_payload = ? WHERE broker_id = ? AND topic = ?'
[p, brokerId, t] ).run(p, brokerId, t);
);
} }
payloadCache.clear(); payloadCache.clear();
}; };
@ -179,11 +177,10 @@ export function addManualTopic(brokerId: number, topic: string): MqttTopic {
if (existing) return existing; if (existing) return existing;
const result = db.run( const result = db.prepare(
`INSERT INTO mqtt_topics (broker_id, topic, selected, ignored) `INSERT INTO mqtt_topics (broker_id, topic, selected, ignored)
VALUES (?, ?, 0, 0)`, VALUES (?, ?, 0, 0)`
[brokerId, topic] ).run(brokerId, topic);
);
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM mqtt_topics WHERE id = ?').get(id) as MqttTopic; return db.prepare('SELECT * FROM mqtt_topics WHERE id = ?').get(id) as MqttTopic;
} }

View File

@ -39,16 +39,15 @@ export function getQueryById(id: number): PgQuery | undefined {
export function createQuery(data: CreateQueryData): PgQuery { export function createQuery(data: CreateQueryData): PgQuery {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO pg_queries (source_id, name, query, interval_sec, result_column) `INSERT INTO pg_queries (source_id, name, query, interval_sec, result_column)
VALUES (?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?)`
[ ).run(
data.source_id, data.source_id,
data.name, data.name,
data.query, data.query,
data.interval_sec ?? 60, data.interval_sec ?? 60,
data.result_column, data.result_column,
]
); );
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM pg_queries WHERE id = ?').get(id) as PgQuery; return db.prepare('SELECT * FROM pg_queries WHERE id = ?').get(id) as PgQuery;
@ -67,14 +66,14 @@ export function updateQuery(id: number, data: UpdateQueryData): PgQuery | undefi
if (fields.length === 0) return getQueryById(id); if (fields.length === 0) return getQueryById(id);
values.push(id); values.push(id);
db.run(`UPDATE pg_queries SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE pg_queries SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return getQueryById(id); return getQueryById(id);
} }
export function deleteQuery(id: number): boolean { export function deleteQuery(id: number): boolean {
const db = getDb(); const db = getDb();
stopQueryTimer(id); stopQueryTimer(id);
const result = db.run('DELETE FROM pg_queries WHERE id = ?', [id]); const result = db.prepare('DELETE FROM pg_queries WHERE id = ?').run(id);
return (result.changes as number) > 0; return (result.changes as number) > 0;
} }
@ -99,10 +98,9 @@ async function executeQuery(queryId: number): Promise<void> {
const valueStr = String(rawValue); const valueStr = String(rawValue);
const db = getDb(); const db = getDb();
db.run( db.prepare(
`UPDATE pg_queries SET last_result = ?, last_run_at = datetime('now') WHERE id = ?`, `UPDATE pg_queries SET last_result = ?, last_run_at = datetime('now') WHERE id = ?`
[valueStr, queryId] ).run(valueStr, queryId);
);
const dp = getDatapointByQueryId(queryId); const dp = getDatapointByQueryId(queryId);
if (dp) { if (dp) {

View File

@ -42,19 +42,18 @@ export function getSourceById(id: number): PgSource | undefined {
export function createSource(data: CreateSourceData): PgSource { export function createSource(data: CreateSourceData): PgSource {
const db = getDb(); const db = getDb();
const result = db.run( const result = db.prepare(
`INSERT INTO pg_sources (name, host, port, database_name, username, password, use_tls, enabled) `INSERT INTO pg_sources (name, host, port, database_name, username, password, use_tls, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
[ ).run(
data.name, data.name,
data.host, data.host,
data.port ?? 5432, data.port ?? 5432,
data.database_name, data.database_name,
data.username, data.username,
data.password, data.password,
data.use_tls ?? 0, data.use_tls ?? 0,
data.enabled ?? 1, data.enabled ?? 1,
]
); );
const id = result.lastInsertRowid as number; const id = result.lastInsertRowid as number;
return db.prepare('SELECT * FROM pg_sources WHERE id = ?').get(id) as PgSource; return db.prepare('SELECT * FROM pg_sources WHERE id = ?').get(id) as PgSource;
@ -77,20 +76,20 @@ export function updateSource(id: number, data: UpdateSourceData): PgSource | und
if (fields.length === 0) return getSourceById(id); if (fields.length === 0) return getSourceById(id);
values.push(id); values.push(id);
db.run(`UPDATE pg_sources SET ${fields.join(', ')} WHERE id = ?`, values); db.prepare(`UPDATE pg_sources SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return getSourceById(id); return getSourceById(id);
} }
export function deleteSource(id: number): boolean { export function deleteSource(id: number): boolean {
const db = getDb(); const db = getDb();
disconnectSource(id); disconnectSource(id);
const result = db.run('DELETE FROM pg_sources WHERE id = ?', [id]); const result = db.prepare('DELETE FROM pg_sources WHERE id = ?').run(id);
return (result.changes as number) > 0; return (result.changes as number) > 0;
} }
function setStatus(id: number, status: string): void { function setStatus(id: number, status: string): void {
const db = getDb(); const db = getDb();
db.run('UPDATE pg_sources SET status = ? WHERE id = ?', [status, id]); db.prepare('UPDATE pg_sources SET status = ? WHERE id = ?').run(status, id);
} }
export async function connectSource(id: number): Promise<Pool> { export async function connectSource(id: number): Promise<Pool> {

View File

@ -8,10 +8,9 @@ beforeAll(() => {
const db = initDb(':memory:'); const db = initDb(':memory:');
// Create a test user // Create a test user
const hash = bcrypt.hashSync('correctpassword', 10); const hash = bcrypt.hashSync('correctpassword', 10);
db.run( db.prepare(
`INSERT INTO users (username, password_hash) VALUES (?, ?)`, `INSERT INTO users (username, password_hash) VALUES (?, ?)`
['testuser', hash] ).run('testuser', hash);
);
}); });
afterAll(() => { afterAll(() => {

View File

@ -9,22 +9,22 @@ beforeAll(() => {
const db = initDb(':memory:'); const db = initDb(':memory:');
// Create a layout // Create a layout
db.run( db.prepare(
`INSERT INTO layouts (id, name, type, width, height) `INSERT INTO layouts (id, name, type, width, height)
VALUES (1, 'Test Layout', 'free', 800, 480)` VALUES (1, 'Test Layout', 'free', 800, 480)`
); ).run();
// Display without token // Display without token
db.run( db.prepare(
`INSERT INTO displays (id, name, layout_id, refresh_sec) `INSERT INTO displays (id, name, layout_id, refresh_sec)
VALUES (1, 'Open Display', 1, 60)` VALUES (1, 'Open Display', 1, 60)`
); ).run();
// Display with token auth // Display with token auth
db.run( db.prepare(
`INSERT INTO displays (id, name, layout_id, api_token, refresh_sec) `INSERT INTO displays (id, name, layout_id, api_token, refresh_sec)
VALUES (2, 'Secure Display', 1, 'secret-token-123', 300)` VALUES (2, 'Secure Display', 1, 'secret-token-123', 300)`
); ).run();
}); });
afterAll(() => { afterAll(() => {

View File

@ -1,8 +1,8 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { Database } from 'node-sqlite3-wasm'; import type Database from 'better-sqlite3';
import { initDb, closeDb } from '../src/db/index'; import { initDb, closeDb } from '../src/db/index';
let db: Database; let db: InstanceType<typeof Database>;
beforeAll(() => { beforeAll(() => {
db = initDb(':memory:'); db = initDb(':memory:');
@ -96,10 +96,9 @@ describe('Table creation', () => {
describe('Broker insert and retrieve', () => { describe('Broker insert and retrieve', () => {
it('should insert and retrieve a broker', () => { it('should insert and retrieve a broker', () => {
const result = db.run( const result = db.prepare(
`INSERT INTO mqtt_brokers (name, host, port) VALUES (?, ?, ?)`, `INSERT INTO mqtt_brokers (name, host, port) VALUES (?, ?, ?)`
['Test Broker', 'mqtt.example.com', 1883] ).run('Test Broker', 'mqtt.example.com', 1883);
);
expect(result.lastInsertRowid).toBeGreaterThan(0); expect(result.lastInsertRowid).toBeGreaterThan(0);
const broker = db const broker = db
@ -119,22 +118,22 @@ describe('Broker insert and retrieve', () => {
}); });
it('should cascade delete topics when broker is deleted', () => { it('should cascade delete topics when broker is deleted', () => {
const broker = db.run(`INSERT INTO mqtt_brokers (name, host) VALUES (?, ?)`, [ const broker = db.prepare(`INSERT INTO mqtt_brokers (name, host) VALUES (?, ?)`).run(
'Cascade Broker', 'Cascade Broker',
'cascade.example.com', 'cascade.example.com',
]); );
db.run(`INSERT INTO mqtt_topics (broker_id, topic) VALUES (?, ?)`, [ db.prepare(`INSERT INTO mqtt_topics (broker_id, topic) VALUES (?, ?)`).run(
broker.lastInsertRowid, broker.lastInsertRowid,
'sensors/temp', 'sensors/temp',
]); );
const topicsBefore = db const topicsBefore = db
.prepare(`SELECT * FROM mqtt_topics WHERE broker_id = ?`) .prepare(`SELECT * FROM mqtt_topics WHERE broker_id = ?`)
.all(broker.lastInsertRowid); .all(broker.lastInsertRowid);
expect(topicsBefore.length).toBe(1); expect(topicsBefore.length).toBe(1);
db.run(`DELETE FROM mqtt_brokers WHERE id = ?`, [broker.lastInsertRowid]); db.prepare(`DELETE FROM mqtt_brokers WHERE id = ?`).run(broker.lastInsertRowid);
const topicsAfter = db const topicsAfter = db
.prepare(`SELECT * FROM mqtt_topics WHERE broker_id = ?`) .prepare(`SELECT * FROM mqtt_topics WHERE broker_id = ?`)
@ -144,10 +143,9 @@ describe('Broker insert and retrieve', () => {
it('should reject invalid source_type values', () => { it('should reject invalid source_type values', () => {
expect(() => { expect(() => {
db.run( db.prepare(
`INSERT INTO datapoints (name, label, source_type, source_id) VALUES (?, ?, ?, ?)`, `INSERT INTO datapoints (name, label, source_type, source_id) VALUES (?, ?, ?, ?)`
['dp1', 'Datapoint 1', 'invalid_source', 1] ).run('dp1', 'Datapoint 1', 'invalid_source', 1);
);
}).toThrow(); }).toThrow();
}); });
}); });

View File

@ -6,48 +6,48 @@ beforeAll(() => {
const db = initDb(':memory:'); const db = initDb(':memory:');
// Create a layout // Create a layout
db.run( db.prepare(
`INSERT INTO layouts (id, name, type, width, height, grid_cols, grid_rows) `INSERT INTO layouts (id, name, type, width, height, grid_cols, grid_rows)
VALUES (1, 'Test Layout', 'grid', 800, 480, 2, 3)` VALUES (1, 'Test Layout', 'grid', 800, 480, 2, 3)`
); ).run();
// Create a display with the layout // Create a display with the layout
db.run( db.prepare(
`INSERT INTO displays (id, name, layout_id, refresh_sec) `INSERT INTO displays (id, name, layout_id, refresh_sec)
VALUES (1, 'Test Display', 1, 60)` VALUES (1, 'Test Display', 1, 60)`
); ).run();
// Create a display without layout // Create a display without layout
db.run( db.prepare(
`INSERT INTO displays (id, name, layout_id, refresh_sec) `INSERT INTO displays (id, name, layout_id, refresh_sec)
VALUES (2, 'Empty Display', NULL, 300)` VALUES (2, 'Empty Display', NULL, 300)`
); ).run();
// Create a broker and topic for datapoint // Create a broker and topic for datapoint
db.run( db.prepare(
`INSERT INTO mqtt_brokers (id, name, host) VALUES (1, 'Test Broker', 'localhost')` `INSERT INTO mqtt_brokers (id, name, host) VALUES (1, 'Test Broker', 'localhost')`
); ).run();
db.run( db.prepare(
`INSERT INTO mqtt_topics (id, broker_id, topic) VALUES (1, 1, 'sensors/temp')` `INSERT INTO mqtt_topics (id, broker_id, topic) VALUES (1, 1, 'sensors/temp')`
); ).run();
// Create a datapoint // Create a datapoint
db.run( db.prepare(
`INSERT INTO datapoints (id, name, label, unit, value, source_type, source_id, topic_id, enabled) `INSERT INTO datapoints (id, name, label, unit, value, source_type, source_id, topic_id, enabled)
VALUES (1, 'temperature', 'Temperature', '°C', '22.5', 'mqtt', 1, 1, 1)` VALUES (1, 'temperature', 'Temperature', '°C', '22.5', 'mqtt', 1, 1, 1)`
); ).run();
// Create layout elements // Create layout elements
// Label element // Label element
db.run( db.prepare(
`INSERT INTO layout_elements (id, layout_id, type, x, y, static_text, sort_order) `INSERT INTO layout_elements (id, layout_id, type, x, y, static_text, sort_order)
VALUES (1, 1, 'label', 0, 0, 'Hello World', 0)` VALUES (1, 1, 'label', 0, 0, 'Hello World', 0)`
); ).run();
// Value element linked to datapoint // Value element linked to datapoint
db.run( db.prepare(
`INSERT INTO layout_elements (id, layout_id, datapoint_id, type, x, y, font_size, sort_order) `INSERT INTO layout_elements (id, layout_id, datapoint_id, type, x, y, font_size, sort_order)
VALUES (2, 1, 1, 'value', 100, 0, 32, 1)` VALUES (2, 1, 1, 'value', 100, 0, 32, 1)`
); ).run();
}); });
afterAll(() => { afterAll(() => {