feat: typesafe query and more UI changes
This commit is contained in:
parent
d73bb88f1d
commit
64e358f61c
13 changed files with 1347 additions and 109 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@
|
||||||
packages/server/certs/
|
packages/server/certs/
|
||||||
packages/server/tests/stress/machines
|
packages/server/tests/stress/machines
|
||||||
packages/server/tests/stress/config.json
|
packages/server/tests/stress/config.json
|
||||||
|
packages/typesafe-db/lib/
|
||||||
|
|
|
||||||
305
package-lock.json
generated
305
package-lock.json
generated
|
|
@ -10,7 +10,8 @@
|
||||||
"license": "./LICENSE",
|
"license": "./LICENSE",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/server",
|
"packages/server",
|
||||||
"packages/admin-ui"
|
"packages/admin-ui",
|
||||||
|
"packages/typesafe-db"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/css": "^0.7.0",
|
"@eslint/css": "^0.7.0",
|
||||||
|
|
@ -10688,6 +10689,16 @@
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/diff": {
|
||||||
|
"version": "3.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||||
|
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/diff-sequences": {
|
"node_modules/diff-sequences": {
|
||||||
"version": "26.6.2",
|
"version": "26.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
|
||||||
|
|
@ -10844,6 +10855,22 @@
|
||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv-expand": {
|
||||||
|
"version": "12.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.2.tgz",
|
||||||
|
"integrity": "sha512-lXpXz2ZE1cea1gL4sz2Ipj8y4PiVjytYr3Ij0SWoms1PGxIv7m2CRKuRuCRtHdVuvM/hNJPMxt5PbhboNC4dPQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.4.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/downshift": {
|
"node_modules/downshift": {
|
||||||
"version": "9.0.9",
|
"version": "9.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/downshift/-/downshift-9.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/downshift/-/downshift-9.0.9.tgz",
|
||||||
|
|
@ -11054,6 +11081,16 @@
|
||||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/env-paths": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/environment": {
|
"node_modules/environment": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
|
||||||
|
|
@ -13465,6 +13502,101 @@
|
||||||
"assert-plus": "^1.0.0"
|
"assert-plus": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/git-diff": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/git-diff/-/git-diff-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-/Iu4prUrydE3Pb3lCBMbcSNIf81tgGt0W1ZwknnyF62t3tHmtiJTRj0f+1ZIhp3+Rh0ktz1pJVoa7ZXUCskivA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^2.3.2",
|
||||||
|
"diff": "^3.5.0",
|
||||||
|
"loglevel": "^1.6.1",
|
||||||
|
"shelljs": "^0.8.1",
|
||||||
|
"shelljs.exec": "^1.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/ansi-styles": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^1.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/chalk": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^3.2.1",
|
||||||
|
"escape-string-regexp": "^1.0.5",
|
||||||
|
"supports-color": "^5.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/color-convert": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/escape-string-regexp": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/has-flag": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/git-diff/node_modules/supports-color": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
|
|
@ -14629,6 +14761,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/interpret": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/io-ts": {
|
"node_modules/io-ts": {
|
||||||
"version": "2.2.20",
|
"version": "2.2.20",
|
||||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
||||||
|
|
@ -16941,6 +17083,120 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/kysely": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-4YAVLoF0Sf0UTqlhgQMFU9iQECdah7n+13ANkiuVfRvlK+uI0Etbgd7bVP36dKlG+NXWbhGua8vnGt+sdhvT7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/kysely-codegen": {
|
||||||
|
"version": "0.18.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/kysely-codegen/-/kysely-codegen-0.18.5.tgz",
|
||||||
|
"integrity": "sha512-bj6DMsXcKo0PrrXUk/fdjFgNC6Pwq+HPBCqhNGuD57gwUJZdci2s2OqhNneQeYpAIWGot7/481WdzTyXrClY2Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "4.1.2",
|
||||||
|
"cosmiconfig": "^9.0.0",
|
||||||
|
"dotenv": "^16.5.0",
|
||||||
|
"dotenv-expand": "^12.0.2",
|
||||||
|
"git-diff": "^2.0.6",
|
||||||
|
"micromatch": "^4.0.8",
|
||||||
|
"minimist": "^1.2.8",
|
||||||
|
"pluralize": "^8.0.0",
|
||||||
|
"zod": "^3.24.4"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"kysely-codegen": "dist/cli/bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@libsql/kysely-libsql": ">=0.3.0 <0.5.0",
|
||||||
|
"@tediousjs/connection-string": ">=0.5.0 <0.6.0",
|
||||||
|
"better-sqlite3": ">=7.6.2 <8.0.0",
|
||||||
|
"kysely": ">=0.27.0 <1.0.0",
|
||||||
|
"kysely-bun-sqlite": ">=0.3.2 <1.0.0",
|
||||||
|
"kysely-bun-worker": ">=1.2.0 <2.0.0",
|
||||||
|
"mysql2": ">=2.3.3 <4.0.0",
|
||||||
|
"pg": ">=8.8.0 <9.0.0",
|
||||||
|
"tarn": ">=3.0.0 <4.0.0",
|
||||||
|
"tedious": ">=18.0.0 <20.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@libsql/kysely-libsql": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@tediousjs/connection-string": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"better-sqlite3": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"kysely": {
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"kysely-bun-sqlite": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"kysely-bun-worker": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mysql2": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"pg": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tarn": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tedious": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/kysely-codegen/node_modules/cosmiconfig": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"env-paths": "^2.2.1",
|
||||||
|
"import-fresh": "^3.3.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"parse-json": "^5.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/d-fischer"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.9.5"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/kysely-codegen/node_modules/pluralize": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lamassu-admin": {
|
"node_modules/lamassu-admin": {
|
||||||
"resolved": "packages/admin-ui",
|
"resolved": "packages/admin-ui",
|
||||||
"link": true
|
"link": true
|
||||||
|
|
@ -21212,6 +21468,18 @@
|
||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rechoir": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"resolve": "^1.1.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/referrer-policy": {
|
"node_modules/referrer-policy": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
|
||||||
|
|
@ -22888,6 +23156,34 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/shelljs": {
|
||||||
|
"version": "0.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
|
||||||
|
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.0.0",
|
||||||
|
"interpret": "^1.0.0",
|
||||||
|
"rechoir": "^0.6.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"shjs": "bin/shjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/shelljs.exec": {
|
||||||
|
"version": "1.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/shelljs.exec/-/shelljs.exec-1.1.8.tgz",
|
||||||
|
"integrity": "sha512-vFILCw+lzUtiwBAHV8/Ex8JsFjelFMdhONIsgKNLgTzeRckp2AOYRQtHJE/9LhNvdMmE27AGtzWx0+DHpwIwSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/shellwords": {
|
"node_modules/shellwords": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
|
||||||
|
|
@ -25966,12 +26262,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
|
||||||
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
|
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
|
||||||
},
|
},
|
||||||
|
"node_modules/typesafe-db": {
|
||||||
|
"resolved": "packages/typesafe-db",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.8.3",
|
"version": "5.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|
@ -28778,9 +29077,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/typesafe-db": {
|
"packages/typesafe-db": {
|
||||||
"name": "lamassu-typesafe-db",
|
|
||||||
"version": "11.0.0-beta.0",
|
"version": "11.0.0-beta.0",
|
||||||
"extraneous": true,
|
|
||||||
"license": "../LICENSE",
|
"license": "../LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"kysely": "^0.28.2",
|
"kysely": "^0.28.2",
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/server",
|
"packages/server",
|
||||||
"packages/admin-ui"
|
"packages/admin-ui",
|
||||||
|
"packages/typesafe-db"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/css": "^0.7.0",
|
"@eslint/css": "^0.7.0",
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,6 @@ const CustomerProfile = memo(() => {
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
const [clickedItem, setClickedItem] = useState('overview')
|
const [clickedItem, setClickedItem] = useState('overview')
|
||||||
const { id: customerId } = useParams()
|
const { id: customerId } = useParams()
|
||||||
console.log(customerId)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: customerResponse,
|
data: customerResponse,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import IconButton from '@mui/material/IconButton'
|
||||||
|
import Tooltip from '@mui/material/Tooltip'
|
||||||
|
import Visibility from '@mui/icons-material/Visibility'
|
||||||
import { format } from 'date-fns/fp'
|
import { format } from 'date-fns/fp'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
|
|
@ -40,7 +43,6 @@ const CustomersList = ({ data, country, onClick, loading }) => {
|
||||||
...alignRight,
|
...alignRight,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'totalSpent',
|
|
||||||
accessorKey: 'totalSpent',
|
accessorKey: 'totalSpent',
|
||||||
size: 152,
|
size: 152,
|
||||||
enableColumnFilter: false,
|
enableColumnFilter: false,
|
||||||
|
|
@ -49,17 +51,6 @@ const CustomersList = ({ data, country, onClick, loading }) => {
|
||||||
header: 'Total spent',
|
header: 'Total spent',
|
||||||
...alignRight,
|
...alignRight,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
header: 'Last active',
|
|
||||||
// accessorKey: 'lastActive',
|
|
||||||
accessorFn: it => new Date(it.lastActive),
|
|
||||||
size: 133,
|
|
||||||
enableColumnFilter: false,
|
|
||||||
Cell: ({ cell }) =>
|
|
||||||
(cell.getValue() &&
|
|
||||||
format('yyyy-MM-dd', new Date(cell.getValue()))) ??
|
|
||||||
'',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
header: 'Last transaction',
|
header: 'Last transaction',
|
||||||
...alignRight,
|
...alignRight,
|
||||||
|
|
@ -80,12 +71,34 @@ const CustomersList = ({ data, country, onClick, loading }) => {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'lastActive',
|
||||||
|
header: 'Last active',
|
||||||
|
size: 133,
|
||||||
|
enableColumnFilter: false,
|
||||||
|
Cell: ({ cell }) =>
|
||||||
|
(cell.getValue() &&
|
||||||
|
format('yyyy-MM-dd', new Date(cell.getValue()))) ??
|
||||||
|
'',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: 'Status',
|
header: 'Status',
|
||||||
id: 'status',
|
size: 150,
|
||||||
size: 100,
|
|
||||||
enableColumnFilter: false,
|
enableColumnFilter: false,
|
||||||
accessorKey: 'authorizedStatus',
|
accessorKey: 'authorizedStatus',
|
||||||
|
sortingFn: (rowA, rowB) => {
|
||||||
|
const statusOrder = { success: 0, warning: 1, error: 2 }
|
||||||
|
const statusA = rowA.original.authorizedStatus.type
|
||||||
|
const statusB = rowB.original.authorizedStatus.type
|
||||||
|
|
||||||
|
if (statusA === statusB) {
|
||||||
|
return rowA.original.authorizedStatus.label.localeCompare(
|
||||||
|
rowB.original.authorizedStatus.label,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return statusOrder[statusA] - statusOrder[statusB]
|
||||||
|
},
|
||||||
Cell: ({ cell }) => <MainStatus statuses={[cell.getValue()]} />,
|
Cell: ({ cell }) => <MainStatus statuses={[cell.getValue()]} />,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -101,13 +114,22 @@ const CustomersList = ({ data, country, onClick, loading }) => {
|
||||||
columnVisibility: {
|
columnVisibility: {
|
||||||
id: false,
|
id: false,
|
||||||
},
|
},
|
||||||
|
sorting: [{ id: 'lastActive', desc: true }],
|
||||||
|
columnPinning: { right: ['mrt-row-actions'] },
|
||||||
},
|
},
|
||||||
state: { isLoading: loading },
|
state: { isLoading: loading },
|
||||||
getRowId: it => it.id,
|
getRowId: it => it.id,
|
||||||
muiTableBodyRowProps: ({ row }) => ({
|
enableRowActions: true,
|
||||||
onClick: () => onClick(row),
|
positionActionsColumn: 'last',
|
||||||
sx: { cursor: 'pointer' },
|
renderRowActions: ({ row }) => (
|
||||||
}),
|
<div>
|
||||||
|
<Tooltip title="Customer page">
|
||||||
|
<IconButton aria-label="Go to customer" onClick={() => onClick(row)}>
|
||||||
|
<Visibility />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -293,4 +293,31 @@ describe('getAuthorizedStatus', () => {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should return rejected status for blocked custom info request', () => {
|
||||||
|
const customer = {
|
||||||
|
authorizedOverride: null,
|
||||||
|
isSuspended: false,
|
||||||
|
customInfoRequests: [
|
||||||
|
{
|
||||||
|
infoRequestId: '550e8400-e29b-41d4-a716-446655440000',
|
||||||
|
override: 'blocked',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const triggers = {
|
||||||
|
automation: 'manual',
|
||||||
|
overrides: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
const customRequests = [{ id: '550e8400-e29b-41d4-a716-446655440000' }]
|
||||||
|
|
||||||
|
const result = getAuthorizedStatus(customer, triggers, customRequests)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
label: 'Rejected',
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ const fs = require('fs')
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
|
|
||||||
const db = require('./db')
|
const db = require('./db')
|
||||||
const anonymous = require('../lib/constants').anonymousCustomer
|
|
||||||
const complianceOverrides = require('./compliance_overrides')
|
const complianceOverrides = require('./compliance_overrides')
|
||||||
const writeFile = util.promisify(fs.writeFile)
|
const writeFile = util.promisify(fs.writeFile)
|
||||||
const notifierQueries = require('./notifier/queries')
|
const notifierQueries = require('./notifier/queries')
|
||||||
|
|
@ -17,6 +16,7 @@ const sms = require('./sms')
|
||||||
const settingsLoader = require('./new-settings-loader')
|
const settingsLoader = require('./new-settings-loader')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const externalCompliance = require('./compliance-external')
|
const externalCompliance = require('./compliance-external')
|
||||||
|
const { getCustomerList } = require('typesafe-db/lib/customers')
|
||||||
|
|
||||||
const { APPROVED, RETRY } = require('./plugins/compliance/consts')
|
const { APPROVED, RETRY } = require('./plugins/compliance/consts')
|
||||||
|
|
||||||
|
|
@ -489,88 +489,8 @@ function getSlimCustomerByIdBatch(ids) {
|
||||||
return db.any(sql, [ids]).then(customers => _.map(camelize, customers))
|
return db.any(sql, [ids]).then(customers => _.map(camelize, customers))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: getCustomersList and getCustomerById are very similar, so this should be refactored
|
function getCustomersList() {
|
||||||
|
return getCustomerList({ withCustomInfoRequest: true })
|
||||||
/**
|
|
||||||
* Query all customers, ordered by last activity
|
|
||||||
* and with aggregate columns based on their
|
|
||||||
* transactions
|
|
||||||
*
|
|
||||||
* @returns {array} Array of customers with it's transactions aggregations
|
|
||||||
*/
|
|
||||||
|
|
||||||
function getCustomersList(
|
|
||||||
phone = null,
|
|
||||||
name = null,
|
|
||||||
address = null,
|
|
||||||
id = null,
|
|
||||||
email = null,
|
|
||||||
) {
|
|
||||||
const passableErrorCodes = _.map(
|
|
||||||
Pgp.as.text,
|
|
||||||
TX_PASSTHROUGH_ERROR_CODES,
|
|
||||||
).join(',')
|
|
||||||
|
|
||||||
const sql = `SELECT id, authorized_override, days_suspended, is_suspended, front_camera_path, front_camera_override,
|
|
||||||
phone, email, sms_override, id_card_data, id_card_data_override, id_card_data_expiration,
|
|
||||||
id_card_photo_path, id_card_photo_override, us_ssn, us_ssn_override, sanctions, sanctions_at,
|
|
||||||
sanctions_override, total_txs, total_spent, GREATEST(created, last_transaction, last_data_provided, last_auth_attempt) AS last_active, fiat AS last_tx_fiat,
|
|
||||||
fiat_code AS last_tx_fiat_code, tx_class AS last_tx_class, custom_fields, notes, is_test_customer
|
|
||||||
FROM (
|
|
||||||
SELECT c.id, c.authorized_override,
|
|
||||||
greatest(0, date_part('day', c.suspended_until - NOW())) AS days_suspended,
|
|
||||||
c.suspended_until > NOW() AS is_suspended,
|
|
||||||
c.front_camera_path, c.front_camera_override,
|
|
||||||
c.phone, c.email, c.sms_override, c.id_card_data, c.id_card_data_override, c.id_card_data_expiration,
|
|
||||||
c.id_card_photo_path, c.id_card_photo_override, c.us_ssn, c.us_ssn_override, c.sanctions, c.last_auth_attempt,
|
|
||||||
GREATEST(c.phone_at, c.email_at, c.id_card_data_at, c.front_camera_at, c.id_card_photo_at, c.us_ssn_at) AS last_data_provided,
|
|
||||||
c.sanctions_at, c.sanctions_override, c.is_test_customer, c.created, t.tx_class, t.fiat, t.fiat_code, t.created as last_transaction, cn.notes,
|
|
||||||
row_number() OVER (partition by c.id order by t.created desc) AS rn,
|
|
||||||
sum(CASE WHEN t.id IS NOT NULL THEN 1 ELSE 0 END) OVER (partition by c.id) AS total_txs,
|
|
||||||
coalesce(sum(CASE WHEN error_code IS NULL OR error_code NOT IN ($1^) THEN t.fiat ELSE 0 END) OVER (partition by c.id), 0) AS total_spent, ccf.custom_fields
|
|
||||||
FROM customers c LEFT OUTER JOIN (
|
|
||||||
SELECT 'cashIn' AS tx_class, id, fiat, fiat_code, created, customer_id, error_code
|
|
||||||
FROM cash_in_txs WHERE send_confirmed = true OR batched = true UNION
|
|
||||||
SELECT 'cashOut' AS tx_class, id, fiat, fiat_code, created, customer_id, error_code
|
|
||||||
FROM cash_out_txs WHERE confirmed_at IS NOT NULL) AS t ON c.id = t.customer_id
|
|
||||||
LEFT OUTER JOIN (
|
|
||||||
SELECT cf.customer_id, json_agg(json_build_object('id', cf.custom_field_id, 'label', cf.label, 'value', cf.value)) AS custom_fields FROM (
|
|
||||||
SELECT ccfp.custom_field_id, ccfp.customer_id, cfd.label, ccfp.value FROM custom_field_definitions cfd
|
|
||||||
LEFT OUTER JOIN customer_custom_field_pairs ccfp ON cfd.id = ccfp.custom_field_id
|
|
||||||
) cf GROUP BY cf.customer_id
|
|
||||||
) ccf ON c.id = ccf.customer_id
|
|
||||||
LEFT OUTER JOIN (
|
|
||||||
SELECT customer_id, coalesce(json_agg(customer_notes.*), '[]'::json) AS notes FROM customer_notes
|
|
||||||
GROUP BY customer_notes.customer_id
|
|
||||||
) cn ON c.id = cn.customer_id
|
|
||||||
WHERE c.id != $2
|
|
||||||
) AS cl WHERE rn = 1
|
|
||||||
AND ($4 IS NULL OR phone = $4)
|
|
||||||
AND ($5 IS NULL OR CONCAT(id_card_data::json->>'firstName', ' ', id_card_data::json->>'lastName') = $5 OR id_card_data::json->>'firstName' = $5 OR id_card_data::json->>'lastName' = $5)
|
|
||||||
AND ($6 IS NULL OR id_card_data::json->>'address' = $6)
|
|
||||||
AND ($7 IS NULL OR id_card_data::json->>'documentNumber' = $7)
|
|
||||||
AND ($8 IS NULL OR email = $8)
|
|
||||||
ORDER BY last_active DESC
|
|
||||||
limit $3`
|
|
||||||
return db
|
|
||||||
.any(sql, [
|
|
||||||
passableErrorCodes,
|
|
||||||
anonymous.uuid,
|
|
||||||
null,
|
|
||||||
phone,
|
|
||||||
name,
|
|
||||||
address,
|
|
||||||
id,
|
|
||||||
email,
|
|
||||||
])
|
|
||||||
.then(customers =>
|
|
||||||
Promise.all(
|
|
||||||
_.map(
|
|
||||||
customer => getCustomInfoRequestsData(customer).then(camelizeDeep),
|
|
||||||
customers,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@ const resolvers = {
|
||||||
isAnonymous: parent => parent.customerId === anonymous.uuid,
|
isAnonymous: parent => parent.customerId === anonymous.uuid,
|
||||||
},
|
},
|
||||||
Query: {
|
Query: {
|
||||||
customers: (...[, { phone, email, name, address, id }]) =>
|
customers: () => customers.getCustomersList(),
|
||||||
customers.getCustomersList(phone, name, address, id, email),
|
|
||||||
customer: (...[, { customerId }]) =>
|
customer: (...[, { customerId }]) =>
|
||||||
customers.getCustomerById(customerId).then(addLastUsedMachineName),
|
customers.getCustomerById(customerId).then(addLastUsedMachineName),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
20
packages/typesafe-db/package.json
Normal file
20
packages/typesafe-db/package.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"name": "typesafe-db",
|
||||||
|
"version": "11.0.0-beta.0",
|
||||||
|
"license": "../LICENSE",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"kysely-codegen": "^0.18.5",
|
||||||
|
"typescript": "^5.8.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "tsc --watch",
|
||||||
|
"clean": "rm -rf lib",
|
||||||
|
"generate-types": "kysely-codegen --camel-case --out-file ./src/types/types.d.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"kysely": "^0.28.2",
|
||||||
|
"pg": "^8.16.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
159
packages/typesafe-db/src/customers.ts
Normal file
159
packages/typesafe-db/src/customers.ts
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
import db from './db.js'
|
||||||
|
import { ExpressionBuilder, sql } from 'kysely'
|
||||||
|
import { Customers, DB } from './types/types.js'
|
||||||
|
import { jsonObjectFrom } from 'kysely/helpers/postgres'
|
||||||
|
|
||||||
|
type CustomerEB = ExpressionBuilder<DB & { c: Customers }, 'c'>
|
||||||
|
|
||||||
|
const TX_PASSTHROUGH_ERROR_CODES = [
|
||||||
|
'operatorCancel',
|
||||||
|
'scoreThresholdReached',
|
||||||
|
'walletScoringError',
|
||||||
|
]
|
||||||
|
|
||||||
|
function transactionUnion(eb: CustomerEB) {
|
||||||
|
return eb
|
||||||
|
.selectFrom('cashInTxs')
|
||||||
|
.select([
|
||||||
|
'created',
|
||||||
|
'fiat',
|
||||||
|
'fiatCode',
|
||||||
|
'errorCode',
|
||||||
|
eb.val('cashIn').as('txClass'),
|
||||||
|
])
|
||||||
|
.where(({ eb, and, or, ref }) =>
|
||||||
|
and([
|
||||||
|
eb('customerId', '=', ref('c.id')),
|
||||||
|
or([eb('sendConfirmed', '=', true), eb('batched', '=', true)]),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.unionAll(
|
||||||
|
eb
|
||||||
|
.selectFrom('cashOutTxs')
|
||||||
|
.select([
|
||||||
|
'created',
|
||||||
|
'fiat',
|
||||||
|
'fiatCode',
|
||||||
|
'errorCode',
|
||||||
|
eb.val('cashOut').as('txClass'),
|
||||||
|
])
|
||||||
|
.where(({ eb, and, ref }) =>
|
||||||
|
and([
|
||||||
|
eb('customerId', '=', ref('c.id')),
|
||||||
|
eb('confirmedAt', 'is not', null),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinLatestTx(eb: CustomerEB) {
|
||||||
|
return eb
|
||||||
|
.selectFrom(eb =>
|
||||||
|
transactionUnion(eb).orderBy('created', 'desc').limit(1).as('lastTx'),
|
||||||
|
)
|
||||||
|
.select(['fiatCode', 'fiat', 'txClass', 'created'])
|
||||||
|
.as('lastTx')
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinTxsTotals(eb: CustomerEB) {
|
||||||
|
return eb
|
||||||
|
.selectFrom(eb => transactionUnion(eb).as('combinedTxs'))
|
||||||
|
.select([
|
||||||
|
eb => eb.fn.coalesce(eb.fn.countAll(), eb.val(0)).as('totalTxs'),
|
||||||
|
eb =>
|
||||||
|
eb.fn
|
||||||
|
.coalesce(
|
||||||
|
eb.fn.sum(
|
||||||
|
eb
|
||||||
|
.case()
|
||||||
|
.when(
|
||||||
|
eb.or([
|
||||||
|
eb('combinedTxs.errorCode', 'is', null),
|
||||||
|
eb(
|
||||||
|
'combinedTxs.errorCode',
|
||||||
|
'not in',
|
||||||
|
TX_PASSTHROUGH_ERROR_CODES,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.then(eb.ref('combinedTxs.fiat'))
|
||||||
|
.else(0)
|
||||||
|
.end(),
|
||||||
|
),
|
||||||
|
eb.val(0),
|
||||||
|
)
|
||||||
|
.as('totalSpent'),
|
||||||
|
])
|
||||||
|
.as('txStats')
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetCustomerListOptions {
|
||||||
|
withCustomInfoRequest: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOptions: GetCustomerListOptions = {
|
||||||
|
withCustomInfoRequest: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO left join lateral is having issues deriving type
|
||||||
|
function getCustomerList(
|
||||||
|
options: GetCustomerListOptions = defaultOptions,
|
||||||
|
): Promise<any[]> {
|
||||||
|
return db
|
||||||
|
.selectFrom('customers as c')
|
||||||
|
.leftJoinLateral(joinTxsTotals, join => join.onTrue())
|
||||||
|
.leftJoinLateral(joinLatestTx, join => join.onTrue())
|
||||||
|
.select(({ eb, fn, val, ref }) => [
|
||||||
|
'id',
|
||||||
|
'authorizedOverride',
|
||||||
|
'frontCameraPath',
|
||||||
|
'frontCameraOverride',
|
||||||
|
'idCardPhotoPath',
|
||||||
|
'idCardPhotoOverride',
|
||||||
|
'idCardData',
|
||||||
|
'idCardDataOverride',
|
||||||
|
'email',
|
||||||
|
'usSsn',
|
||||||
|
'usSsnOverride',
|
||||||
|
'sanctions',
|
||||||
|
'sanctionsOverride',
|
||||||
|
'txStats.totalSpent',
|
||||||
|
'txStats.totalTxs',
|
||||||
|
ref('lastTx.fiatCode').as('lastTxFiatCode'),
|
||||||
|
ref('lastTx.fiat').as('lastTxFiat'),
|
||||||
|
ref('lastTx.txClass').as('lastTxClass'),
|
||||||
|
fn<Date>('GREATEST', [
|
||||||
|
'c.created',
|
||||||
|
// 'lastTx.created',
|
||||||
|
'c.phoneAt',
|
||||||
|
'c.emailAt',
|
||||||
|
'c.idCardDataAt',
|
||||||
|
'c.frontCameraAt',
|
||||||
|
'c.idCardPhotoAt',
|
||||||
|
'c.usSsnAt',
|
||||||
|
'c.lastAuthAttempt',
|
||||||
|
]).as('lastActive'),
|
||||||
|
eb('c.suspendedUntil', '>', fn<Date>('NOW', [])).as('isSuspended'),
|
||||||
|
fn<number>('GREATEST', [
|
||||||
|
val(0),
|
||||||
|
fn<number>('date_part', [
|
||||||
|
val('day'),
|
||||||
|
eb('c.suspendedUntil', '-', fn<Date>('NOW', [])),
|
||||||
|
]),
|
||||||
|
]).as('daysSuspended'),
|
||||||
|
])
|
||||||
|
.$if(options.withCustomInfoRequest, qb =>
|
||||||
|
qb.select(({ eb, ref }) =>
|
||||||
|
jsonObjectFrom(
|
||||||
|
eb
|
||||||
|
.selectFrom('customersCustomInfoRequests')
|
||||||
|
.selectAll()
|
||||||
|
.where('customerId', '=', ref('c.id')),
|
||||||
|
).as('customInfoRequestData'),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.orderBy('lastActive', 'desc')
|
||||||
|
.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getCustomerList }
|
||||||
24
packages/typesafe-db/src/db.ts
Normal file
24
packages/typesafe-db/src/db.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { DB } from './types/types.js'
|
||||||
|
import { Pool } from 'pg'
|
||||||
|
import { Kysely, PostgresDialect, CamelCasePlugin } from 'kysely'
|
||||||
|
import { PSQL_URL } from 'lamassu-server/lib/constants.js'
|
||||||
|
|
||||||
|
const dialect = new PostgresDialect({
|
||||||
|
pool: new Pool({
|
||||||
|
connectionString: PSQL_URL,
|
||||||
|
max: 5,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default new Kysely<DB>({
|
||||||
|
dialect,
|
||||||
|
plugins: [new CamelCasePlugin()],
|
||||||
|
log(event) {
|
||||||
|
if (event.level === 'query') {
|
||||||
|
console.log('Query:', event.query.sql)
|
||||||
|
console.log('Parameters:', event.query.parameters)
|
||||||
|
console.log('Duration:', event.queryDurationMillis + 'ms')
|
||||||
|
console.log('---')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
745
packages/typesafe-db/src/types/types.d.ts
vendored
Normal file
745
packages/typesafe-db/src/types/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,745 @@
|
||||||
|
/**
|
||||||
|
* This file was generated by kysely-codegen.
|
||||||
|
* Please do not edit it manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ColumnType } from 'kysely'
|
||||||
|
|
||||||
|
export type AuthTokenType = 'reset_password' | 'reset_twofa'
|
||||||
|
|
||||||
|
export type CashUnit =
|
||||||
|
| 'cashbox'
|
||||||
|
| 'cassette1'
|
||||||
|
| 'cassette2'
|
||||||
|
| 'cassette3'
|
||||||
|
| 'cassette4'
|
||||||
|
| 'recycler1'
|
||||||
|
| 'recycler2'
|
||||||
|
| 'recycler3'
|
||||||
|
| 'recycler4'
|
||||||
|
| 'recycler5'
|
||||||
|
| 'recycler6'
|
||||||
|
|
||||||
|
export type CashUnitOperationType =
|
||||||
|
| 'cash-box-empty'
|
||||||
|
| 'cash-box-refill'
|
||||||
|
| 'cash-cassette-1-count-change'
|
||||||
|
| 'cash-cassette-1-empty'
|
||||||
|
| 'cash-cassette-1-refill'
|
||||||
|
| 'cash-cassette-2-count-change'
|
||||||
|
| 'cash-cassette-2-empty'
|
||||||
|
| 'cash-cassette-2-refill'
|
||||||
|
| 'cash-cassette-3-count-change'
|
||||||
|
| 'cash-cassette-3-empty'
|
||||||
|
| 'cash-cassette-3-refill'
|
||||||
|
| 'cash-cassette-4-count-change'
|
||||||
|
| 'cash-cassette-4-empty'
|
||||||
|
| 'cash-cassette-4-refill'
|
||||||
|
| 'cash-recycler-1-count-change'
|
||||||
|
| 'cash-recycler-1-empty'
|
||||||
|
| 'cash-recycler-1-refill'
|
||||||
|
| 'cash-recycler-2-count-change'
|
||||||
|
| 'cash-recycler-2-empty'
|
||||||
|
| 'cash-recycler-2-refill'
|
||||||
|
| 'cash-recycler-3-count-change'
|
||||||
|
| 'cash-recycler-3-empty'
|
||||||
|
| 'cash-recycler-3-refill'
|
||||||
|
| 'cash-recycler-4-count-change'
|
||||||
|
| 'cash-recycler-4-empty'
|
||||||
|
| 'cash-recycler-4-refill'
|
||||||
|
| 'cash-recycler-5-count-change'
|
||||||
|
| 'cash-recycler-5-empty'
|
||||||
|
| 'cash-recycler-5-refill'
|
||||||
|
| 'cash-recycler-6-count-change'
|
||||||
|
| 'cash-recycler-6-empty'
|
||||||
|
| 'cash-recycler-6-refill'
|
||||||
|
|
||||||
|
export type ComplianceType =
|
||||||
|
| 'authorized'
|
||||||
|
| 'front_camera'
|
||||||
|
| 'hard_limit'
|
||||||
|
| 'id_card_data'
|
||||||
|
| 'id_card_photo'
|
||||||
|
| 'sanctions'
|
||||||
|
| 'sms'
|
||||||
|
| 'us_ssn'
|
||||||
|
|
||||||
|
export type DiscountSource = 'individualDiscount' | 'promoCode'
|
||||||
|
|
||||||
|
export type ExternalComplianceStatus =
|
||||||
|
| 'APPROVED'
|
||||||
|
| 'PENDING'
|
||||||
|
| 'REJECTED'
|
||||||
|
| 'RETRY'
|
||||||
|
|
||||||
|
export type Generated<T> =
|
||||||
|
T extends ColumnType<infer S, infer I, infer U>
|
||||||
|
? ColumnType<S, I | undefined, U>
|
||||||
|
: ColumnType<T, T | undefined, T>
|
||||||
|
|
||||||
|
export type Int8 = ColumnType<
|
||||||
|
string,
|
||||||
|
bigint | number | string,
|
||||||
|
bigint | number | string
|
||||||
|
>
|
||||||
|
|
||||||
|
export type Json = JsonValue
|
||||||
|
|
||||||
|
export type JsonArray = JsonValue[]
|
||||||
|
|
||||||
|
export type JsonObject = {
|
||||||
|
[x: string]: JsonValue | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export type JsonPrimitive = boolean | number | string | null
|
||||||
|
|
||||||
|
export type JsonValue = JsonArray | JsonObject | JsonPrimitive
|
||||||
|
|
||||||
|
export type NotificationType =
|
||||||
|
| 'compliance'
|
||||||
|
| 'cryptoBalance'
|
||||||
|
| 'error'
|
||||||
|
| 'fiatBalance'
|
||||||
|
| 'highValueTransaction'
|
||||||
|
| 'security'
|
||||||
|
| 'transaction'
|
||||||
|
|
||||||
|
export type Numeric = ColumnType<string, number | string, number | string>
|
||||||
|
|
||||||
|
export type Role = 'superuser' | 'user'
|
||||||
|
|
||||||
|
export type SmsNoticeEvent =
|
||||||
|
| 'cash_out_dispense_ready'
|
||||||
|
| 'sms_code'
|
||||||
|
| 'sms_receipt'
|
||||||
|
|
||||||
|
export type StatusStage =
|
||||||
|
| 'authorized'
|
||||||
|
| 'confirmed'
|
||||||
|
| 'instant'
|
||||||
|
| 'insufficientFunds'
|
||||||
|
| 'notSeen'
|
||||||
|
| 'published'
|
||||||
|
| 'rejected'
|
||||||
|
|
||||||
|
export type Timestamp = ColumnType<Date, Date | string, Date | string>
|
||||||
|
|
||||||
|
export type TradeType = 'buy' | 'sell'
|
||||||
|
|
||||||
|
export type TransactionBatchStatus = 'failed' | 'open' | 'ready' | 'sent'
|
||||||
|
|
||||||
|
export type VerificationType = 'automatic' | 'blocked' | 'verified'
|
||||||
|
|
||||||
|
export interface AuthTokens {
|
||||||
|
expire: Generated<Timestamp>
|
||||||
|
token: string
|
||||||
|
type: AuthTokenType
|
||||||
|
userId: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Bills {
|
||||||
|
cashboxBatchId: string | null
|
||||||
|
cashInFee: Numeric
|
||||||
|
cashInTxsId: string
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
cryptoCode: Generated<string | null>
|
||||||
|
destinationUnit: Generated<CashUnit>
|
||||||
|
deviceTime: Int8
|
||||||
|
fiat: number
|
||||||
|
fiatCode: string
|
||||||
|
id: string
|
||||||
|
legacy: Generated<boolean | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Blacklist {
|
||||||
|
address: string
|
||||||
|
blacklistMessageId: Generated<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlacklistMessages {
|
||||||
|
allowToggle: Generated<boolean>
|
||||||
|
content: string
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashInActions {
|
||||||
|
action: string
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
error: string | null
|
||||||
|
errorCode: string | null
|
||||||
|
id: Generated<number>
|
||||||
|
txHash: string | null
|
||||||
|
txId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashInTxs {
|
||||||
|
batched: Generated<boolean>
|
||||||
|
batchId: string | null
|
||||||
|
batchTime: Timestamp | null
|
||||||
|
cashInFee: Numeric
|
||||||
|
commissionPercentage: Generated<Numeric | null>
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
cryptoAtoms: Numeric
|
||||||
|
cryptoCode: string
|
||||||
|
customerId: Generated<string | null>
|
||||||
|
deviceId: string
|
||||||
|
discount: number | null
|
||||||
|
discountSource: DiscountSource | null
|
||||||
|
email: string | null
|
||||||
|
error: string | null
|
||||||
|
errorCode: string | null
|
||||||
|
fee: Int8 | null
|
||||||
|
fiat: Numeric
|
||||||
|
fiatCode: string
|
||||||
|
id: string
|
||||||
|
isPaperWallet: Generated<boolean | null>
|
||||||
|
minimumTx: number
|
||||||
|
operatorCompleted: Generated<boolean>
|
||||||
|
phone: string | null
|
||||||
|
rawTickerPrice: Generated<Numeric | null>
|
||||||
|
send: Generated<boolean>
|
||||||
|
sendConfirmed: Generated<boolean>
|
||||||
|
sendPending: Generated<boolean>
|
||||||
|
sendTime: Timestamp | null
|
||||||
|
termsAccepted: Generated<boolean>
|
||||||
|
timedout: Generated<boolean>
|
||||||
|
toAddress: string
|
||||||
|
txCustomerPhotoAt: Timestamp | null
|
||||||
|
txCustomerPhotoPath: string | null
|
||||||
|
txHash: string | null
|
||||||
|
txVersion: number
|
||||||
|
walletScore: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashinTxTrades {
|
||||||
|
tradeId: Generated<number>
|
||||||
|
txId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashOutActions {
|
||||||
|
action: string
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
denomination1: number | null
|
||||||
|
denomination2: number | null
|
||||||
|
denomination3: number | null
|
||||||
|
denomination4: number | null
|
||||||
|
denominationRecycler1: number | null
|
||||||
|
denominationRecycler2: number | null
|
||||||
|
denominationRecycler3: number | null
|
||||||
|
denominationRecycler4: number | null
|
||||||
|
denominationRecycler5: number | null
|
||||||
|
denominationRecycler6: number | null
|
||||||
|
deviceId: Generated<string>
|
||||||
|
deviceTime: Int8 | null
|
||||||
|
dispensed1: number | null
|
||||||
|
dispensed2: number | null
|
||||||
|
dispensed3: number | null
|
||||||
|
dispensed4: number | null
|
||||||
|
dispensedRecycler1: number | null
|
||||||
|
dispensedRecycler2: number | null
|
||||||
|
dispensedRecycler3: number | null
|
||||||
|
dispensedRecycler4: number | null
|
||||||
|
dispensedRecycler5: number | null
|
||||||
|
dispensedRecycler6: number | null
|
||||||
|
error: string | null
|
||||||
|
errorCode: string | null
|
||||||
|
id: Generated<number>
|
||||||
|
layer2Address: string | null
|
||||||
|
provisioned1: number | null
|
||||||
|
provisioned2: number | null
|
||||||
|
provisioned3: number | null
|
||||||
|
provisioned4: number | null
|
||||||
|
provisionedRecycler1: number | null
|
||||||
|
provisionedRecycler2: number | null
|
||||||
|
provisionedRecycler3: number | null
|
||||||
|
provisionedRecycler4: number | null
|
||||||
|
provisionedRecycler5: number | null
|
||||||
|
provisionedRecycler6: number | null
|
||||||
|
redeem: Generated<boolean>
|
||||||
|
rejected1: number | null
|
||||||
|
rejected2: number | null
|
||||||
|
rejected3: number | null
|
||||||
|
rejected4: number | null
|
||||||
|
rejectedRecycler1: number | null
|
||||||
|
rejectedRecycler2: number | null
|
||||||
|
rejectedRecycler3: number | null
|
||||||
|
rejectedRecycler4: number | null
|
||||||
|
rejectedRecycler5: number | null
|
||||||
|
rejectedRecycler6: number | null
|
||||||
|
toAddress: string | null
|
||||||
|
txHash: string | null
|
||||||
|
txId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashOutTxs {
|
||||||
|
commissionPercentage: Generated<Numeric | null>
|
||||||
|
confirmedAt: Timestamp | null
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
cryptoAtoms: Numeric
|
||||||
|
cryptoCode: string
|
||||||
|
customerId: Generated<string | null>
|
||||||
|
denomination1: number | null
|
||||||
|
denomination2: number | null
|
||||||
|
denomination3: number | null
|
||||||
|
denomination4: number | null
|
||||||
|
denominationRecycler1: number | null
|
||||||
|
denominationRecycler2: number | null
|
||||||
|
denominationRecycler3: number | null
|
||||||
|
denominationRecycler4: number | null
|
||||||
|
denominationRecycler5: number | null
|
||||||
|
denominationRecycler6: number | null
|
||||||
|
deviceId: string
|
||||||
|
discount: number | null
|
||||||
|
discountSource: DiscountSource | null
|
||||||
|
dispense: Generated<boolean>
|
||||||
|
dispenseConfirmed: Generated<boolean | null>
|
||||||
|
email: string | null
|
||||||
|
error: string | null
|
||||||
|
errorCode: string | null
|
||||||
|
fiat: Numeric
|
||||||
|
fiatCode: string
|
||||||
|
fixedFee: Generated<Numeric>
|
||||||
|
hdIndex: Generated<number | null>
|
||||||
|
id: string
|
||||||
|
layer2Address: string | null
|
||||||
|
notified: Generated<boolean>
|
||||||
|
phone: string | null
|
||||||
|
provisioned1: number | null
|
||||||
|
provisioned2: number | null
|
||||||
|
provisioned3: number | null
|
||||||
|
provisioned4: number | null
|
||||||
|
provisionedRecycler1: number | null
|
||||||
|
provisionedRecycler2: number | null
|
||||||
|
provisionedRecycler3: number | null
|
||||||
|
provisionedRecycler4: number | null
|
||||||
|
provisionedRecycler5: number | null
|
||||||
|
provisionedRecycler6: number | null
|
||||||
|
publishedAt: Timestamp | null
|
||||||
|
rawTickerPrice: Generated<Numeric | null>
|
||||||
|
receivedCryptoAtoms: Generated<Numeric | null>
|
||||||
|
redeem: Generated<boolean>
|
||||||
|
status: Generated<StatusStage>
|
||||||
|
swept: Generated<boolean>
|
||||||
|
termsAccepted: Generated<boolean>
|
||||||
|
timedout: Generated<boolean>
|
||||||
|
toAddress: string
|
||||||
|
txCustomerPhotoAt: Timestamp | null
|
||||||
|
txCustomerPhotoPath: string | null
|
||||||
|
txVersion: number
|
||||||
|
walletScore: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashoutTxTrades {
|
||||||
|
tradeId: Generated<number>
|
||||||
|
txId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashUnitOperation {
|
||||||
|
billCountOverride: number | null
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
deviceId: string | null
|
||||||
|
id: string
|
||||||
|
operationType: CashUnitOperationType
|
||||||
|
performedBy: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComplianceOverrides {
|
||||||
|
complianceType: ComplianceType
|
||||||
|
customerId: string | null
|
||||||
|
id: string
|
||||||
|
overrideAt: Timestamp
|
||||||
|
overrideBy: string | null
|
||||||
|
verification: VerificationType
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Coupons {
|
||||||
|
code: string
|
||||||
|
discount: number
|
||||||
|
id: string
|
||||||
|
softDeleted: Generated<boolean | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomerCustomFieldPairs {
|
||||||
|
customerId: string
|
||||||
|
customFieldId: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomerExternalCompliance {
|
||||||
|
customerId: string
|
||||||
|
externalId: string
|
||||||
|
lastKnownStatus: ExternalComplianceStatus | null
|
||||||
|
lastUpdated: Generated<Timestamp>
|
||||||
|
service: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomerNotes {
|
||||||
|
content: Generated<string>
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
customerId: string
|
||||||
|
id: string
|
||||||
|
lastEditedAt: Timestamp | null
|
||||||
|
lastEditedBy: string | null
|
||||||
|
title: Generated<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Customers {
|
||||||
|
address: string | null
|
||||||
|
authorizedAt: Timestamp | null
|
||||||
|
authorizedOverride: Generated<VerificationType>
|
||||||
|
authorizedOverrideAt: Timestamp | null
|
||||||
|
authorizedOverrideBy: string | null
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
email: string | null
|
||||||
|
emailAt: Timestamp | null
|
||||||
|
frontCameraAt: Timestamp | null
|
||||||
|
frontCameraOverride: Generated<VerificationType>
|
||||||
|
frontCameraOverrideAt: Timestamp | null
|
||||||
|
frontCameraOverrideBy: string | null
|
||||||
|
frontCameraPath: string | null
|
||||||
|
id: string
|
||||||
|
idCardData: Json | null
|
||||||
|
idCardDataAt: Timestamp | null
|
||||||
|
idCardDataExpiration: Timestamp | null
|
||||||
|
idCardDataNumber: string | null
|
||||||
|
idCardDataOverride: Generated<VerificationType>
|
||||||
|
idCardDataOverrideAt: Timestamp | null
|
||||||
|
idCardDataOverrideBy: string | null
|
||||||
|
idCardDataRaw: string | null
|
||||||
|
idCardPhotoAt: Timestamp | null
|
||||||
|
idCardPhotoOverride: Generated<VerificationType>
|
||||||
|
idCardPhotoOverrideAt: Timestamp | null
|
||||||
|
idCardPhotoOverrideBy: string | null
|
||||||
|
idCardPhotoPath: string | null
|
||||||
|
isTestCustomer: Generated<boolean>
|
||||||
|
lastAuthAttempt: Timestamp | null
|
||||||
|
lastUsedMachine: string | null
|
||||||
|
name: string | null
|
||||||
|
phone: string | null
|
||||||
|
phoneAt: Timestamp | null
|
||||||
|
phoneOverride: Generated<VerificationType>
|
||||||
|
phoneOverrideAt: Timestamp | null
|
||||||
|
phoneOverrideBy: string | null
|
||||||
|
sanctions: boolean | null
|
||||||
|
sanctionsAt: Timestamp | null
|
||||||
|
sanctionsOverride: Generated<VerificationType>
|
||||||
|
sanctionsOverrideAt: Timestamp | null
|
||||||
|
sanctionsOverrideBy: string | null
|
||||||
|
smsOverride: Generated<VerificationType>
|
||||||
|
smsOverrideAt: Timestamp | null
|
||||||
|
smsOverrideBy: string | null
|
||||||
|
subscriberInfo: Json | null
|
||||||
|
subscriberInfoAt: Timestamp | null
|
||||||
|
subscriberInfoBy: string | null
|
||||||
|
suspendedUntil: Timestamp | null
|
||||||
|
usSsn: string | null
|
||||||
|
usSsnAt: Timestamp | null
|
||||||
|
usSsnOverride: Generated<VerificationType>
|
||||||
|
usSsnOverrideAt: Timestamp | null
|
||||||
|
usSsnOverrideBy: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomersCustomInfoRequests {
|
||||||
|
customerData: Json
|
||||||
|
customerId: string
|
||||||
|
infoRequestId: string
|
||||||
|
override: Generated<VerificationType>
|
||||||
|
overrideAt: Timestamp | null
|
||||||
|
overrideBy: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomFieldDefinitions {
|
||||||
|
active: Generated<boolean | null>
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomInfoRequests {
|
||||||
|
customRequest: Json | null
|
||||||
|
enabled: Generated<boolean>
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Devices {
|
||||||
|
cassette1: Generated<number>
|
||||||
|
cassette2: Generated<number>
|
||||||
|
cassette3: Generated<number>
|
||||||
|
cassette4: Generated<number>
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
deviceId: string
|
||||||
|
diagnosticsFrontUpdatedAt: Timestamp | null
|
||||||
|
diagnosticsScanUpdatedAt: Timestamp | null
|
||||||
|
diagnosticsTimestamp: Timestamp | null
|
||||||
|
display: Generated<boolean>
|
||||||
|
lastOnline: Generated<Timestamp>
|
||||||
|
location: Generated<Json>
|
||||||
|
model: string | null
|
||||||
|
name: string
|
||||||
|
numberOfCassettes: Generated<number>
|
||||||
|
numberOfRecyclers: Generated<number>
|
||||||
|
paired: Generated<boolean>
|
||||||
|
recycler1: Generated<number>
|
||||||
|
recycler2: Generated<number>
|
||||||
|
recycler3: Generated<number>
|
||||||
|
recycler4: Generated<number>
|
||||||
|
recycler5: Generated<number>
|
||||||
|
recycler6: Generated<number>
|
||||||
|
userConfigId: number | null
|
||||||
|
version: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EditedCustomerData {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
customerId: string
|
||||||
|
frontCameraAt: Timestamp | null
|
||||||
|
frontCameraBy: string | null
|
||||||
|
frontCameraPath: string | null
|
||||||
|
idCardData: Json | null
|
||||||
|
idCardDataAt: Timestamp | null
|
||||||
|
idCardDataBy: string | null
|
||||||
|
idCardPhotoAt: Timestamp | null
|
||||||
|
idCardPhotoBy: string | null
|
||||||
|
idCardPhotoPath: string | null
|
||||||
|
name: string | null
|
||||||
|
nameAt: Timestamp | null
|
||||||
|
nameBy: string | null
|
||||||
|
subscriberInfo: Json | null
|
||||||
|
subscriberInfoAt: Timestamp | null
|
||||||
|
subscriberInfoBy: string | null
|
||||||
|
usSsn: string | null
|
||||||
|
usSsnAt: Timestamp | null
|
||||||
|
usSsnBy: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EmptyUnitBills {
|
||||||
|
cashboxBatchId: string | null
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
deviceId: string
|
||||||
|
fiat: number
|
||||||
|
fiatCode: string
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HardwareCredentials {
|
||||||
|
created: Generated<Timestamp | null>
|
||||||
|
data: Json
|
||||||
|
id: string
|
||||||
|
lastUsed: Generated<Timestamp | null>
|
||||||
|
userId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IndividualDiscounts {
|
||||||
|
customerId: string
|
||||||
|
discount: number
|
||||||
|
id: string
|
||||||
|
softDeleted: Generated<boolean | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Logs {
|
||||||
|
deviceId: string | null
|
||||||
|
id: string
|
||||||
|
logLevel: string | null
|
||||||
|
message: string | null
|
||||||
|
serial: Generated<number>
|
||||||
|
serverTimestamp: Generated<Timestamp>
|
||||||
|
timestamp: Timestamp | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MachineEvents {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
deviceId: string
|
||||||
|
deviceTime: Timestamp | null
|
||||||
|
eventType: string
|
||||||
|
id: string
|
||||||
|
note: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MachineNetworkHeartbeat {
|
||||||
|
averagePacketLoss: Numeric
|
||||||
|
averageResponseTime: Numeric
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
deviceId: string
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MachineNetworkPerformance {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
deviceId: string
|
||||||
|
downloadSpeed: Numeric
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MachinePings {
|
||||||
|
deviceId: string
|
||||||
|
deviceTime: Timestamp
|
||||||
|
updated: Generated<Timestamp>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Migrations {
|
||||||
|
data: Json
|
||||||
|
id: Generated<number>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Notifications {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
detail: Json | null
|
||||||
|
id: string
|
||||||
|
message: string
|
||||||
|
read: Generated<boolean>
|
||||||
|
type: NotificationType
|
||||||
|
valid: Generated<boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OperatorIds {
|
||||||
|
id: Generated<number>
|
||||||
|
operatorId: string
|
||||||
|
service: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PairingTokens {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
id: Generated<number>
|
||||||
|
name: string
|
||||||
|
token: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SanctionsLogs {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
customerId: string
|
||||||
|
deviceId: string
|
||||||
|
id: string
|
||||||
|
sanctionedAliasFullName: string
|
||||||
|
sanctionedAliasId: string | null
|
||||||
|
sanctionedId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerLogs {
|
||||||
|
deviceId: string | null
|
||||||
|
id: string
|
||||||
|
logLevel: string | null
|
||||||
|
message: string | null
|
||||||
|
meta: Json | null
|
||||||
|
timestamp: Generated<Timestamp | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SmsNotices {
|
||||||
|
allowToggle: Generated<boolean>
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
enabled: Generated<boolean>
|
||||||
|
event: SmsNoticeEvent
|
||||||
|
id: string
|
||||||
|
message: string
|
||||||
|
messageName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Trades {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
cryptoAtoms: Numeric
|
||||||
|
cryptoCode: string
|
||||||
|
error: string | null
|
||||||
|
fiatCode: string
|
||||||
|
id: Generated<number>
|
||||||
|
type: TradeType
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionBatches {
|
||||||
|
closedAt: Timestamp | null
|
||||||
|
createdAt: Generated<Timestamp>
|
||||||
|
cryptoCode: string
|
||||||
|
errorMessage: string | null
|
||||||
|
id: string
|
||||||
|
status: Generated<TransactionBatchStatus>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UnpairedDevices {
|
||||||
|
deviceId: string
|
||||||
|
id: string
|
||||||
|
model: string | null
|
||||||
|
name: string | null
|
||||||
|
paired: Timestamp
|
||||||
|
unpaired: Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserConfig {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
data: Json
|
||||||
|
id: Generated<number>
|
||||||
|
schemaVersion: Generated<number>
|
||||||
|
type: string
|
||||||
|
valid: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserRegisterTokens {
|
||||||
|
expire: Generated<Timestamp>
|
||||||
|
role: Generated<Role | null>
|
||||||
|
token: string
|
||||||
|
useFido: Generated<boolean | null>
|
||||||
|
username: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Users {
|
||||||
|
created: Generated<Timestamp>
|
||||||
|
enabled: Generated<boolean | null>
|
||||||
|
id: string
|
||||||
|
lastAccessed: Generated<Timestamp>
|
||||||
|
lastAccessedAddress: string | null
|
||||||
|
lastAccessedFrom: string | null
|
||||||
|
password: string | null
|
||||||
|
role: Generated<Role>
|
||||||
|
tempTwofaCode: string | null
|
||||||
|
twofaCode: string | null
|
||||||
|
username: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserSessions {
|
||||||
|
expire: Timestamp
|
||||||
|
sess: Json
|
||||||
|
sid: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DB {
|
||||||
|
authTokens: AuthTokens
|
||||||
|
bills: Bills
|
||||||
|
blacklist: Blacklist
|
||||||
|
blacklistMessages: BlacklistMessages
|
||||||
|
cashInActions: CashInActions
|
||||||
|
cashInTxs: CashInTxs
|
||||||
|
cashinTxTrades: CashinTxTrades
|
||||||
|
cashOutActions: CashOutActions
|
||||||
|
cashOutTxs: CashOutTxs
|
||||||
|
cashoutTxTrades: CashoutTxTrades
|
||||||
|
cashUnitOperation: CashUnitOperation
|
||||||
|
complianceOverrides: ComplianceOverrides
|
||||||
|
coupons: Coupons
|
||||||
|
customerCustomFieldPairs: CustomerCustomFieldPairs
|
||||||
|
customerExternalCompliance: CustomerExternalCompliance
|
||||||
|
customerNotes: CustomerNotes
|
||||||
|
customers: Customers
|
||||||
|
customersCustomInfoRequests: CustomersCustomInfoRequests
|
||||||
|
customFieldDefinitions: CustomFieldDefinitions
|
||||||
|
customInfoRequests: CustomInfoRequests
|
||||||
|
devices: Devices
|
||||||
|
editedCustomerData: EditedCustomerData
|
||||||
|
emptyUnitBills: EmptyUnitBills
|
||||||
|
hardwareCredentials: HardwareCredentials
|
||||||
|
individualDiscounts: IndividualDiscounts
|
||||||
|
logs: Logs
|
||||||
|
machineEvents: MachineEvents
|
||||||
|
machineNetworkHeartbeat: MachineNetworkHeartbeat
|
||||||
|
machineNetworkPerformance: MachineNetworkPerformance
|
||||||
|
machinePings: MachinePings
|
||||||
|
migrations: Migrations
|
||||||
|
notifications: Notifications
|
||||||
|
operatorIds: OperatorIds
|
||||||
|
pairingTokens: PairingTokens
|
||||||
|
sanctionsLogs: SanctionsLogs
|
||||||
|
serverLogs: ServerLogs
|
||||||
|
smsNotices: SmsNotices
|
||||||
|
trades: Trades
|
||||||
|
transactionBatches: TransactionBatches
|
||||||
|
unpairedDevices: UnpairedDevices
|
||||||
|
userConfig: UserConfig
|
||||||
|
userRegisterTokens: UserRegisterTokens
|
||||||
|
users: Users
|
||||||
|
userSessions: UserSessions
|
||||||
|
}
|
||||||
24
packages/typesafe-db/tsconfig.json
Normal file
24
packages/typesafe-db/tsconfig.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"display": "Node 22",
|
||||||
|
"_version": "22.0.0",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["es2023"],
|
||||||
|
"module": "nodenext",
|
||||||
|
"target": "es2022",
|
||||||
|
|
||||||
|
"allowJs": true,
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "node16",
|
||||||
|
|
||||||
|
"outDir": "./lib",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["lib", "node_modules"]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue