untested WIP
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
pgsql:
|
||||||
|
image: postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: duxcore
|
||||||
|
POSTGRES_PASSWORD: 123web123
|
||||||
|
POSTGRES_DB: duxcore
|
||||||
|
volumes:
|
||||||
|
- ./postgres:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
pgsql-boss:
|
||||||
|
image: postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: pg-boss
|
||||||
|
POSTGRES_PASSWORD: 123web123
|
||||||
|
POSTGRES_DB: pg-boss
|
||||||
|
volumes:
|
||||||
|
- ./postgres-pgb:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- 2345:5432
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:6.2-alpine
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
command: redis-server --save 20 1 --loglevel warning --requirepass iamatotallysecurepassworddonttestmebrox
|
||||||
|
volumes:
|
||||||
|
- ./redis:/data
|
||||||
|
|
||||||
|
adminer:
|
||||||
|
image: adminer
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
depends_on:
|
||||||
|
- pgsql
|
||||||
|
redisinsight:
|
||||||
|
image: redis/redisinsight:latest
|
||||||
|
container_name: redisinsight
|
||||||
|
ports:
|
||||||
|
- "5540:5540"
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
meta {
|
||||||
|
name: Teapot
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: http://localhost:3000/v1/teapot
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"name": "ttscm",
|
||||||
|
"type": "collection",
|
||||||
|
"ignore": [
|
||||||
|
"node_modules",
|
||||||
|
".git"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -4,8 +4,22 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ttscm-api",
|
"name": "ttscm-api",
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/collection": "^2.1.1",
|
||||||
|
"@duxcore/eventra": "^1.1.0",
|
||||||
|
"@prisma/adapter-pg": "^7.3.0",
|
||||||
|
"cors": "^2.8.6",
|
||||||
|
"cuid": "^3.0.0",
|
||||||
|
"hono": "^4.11.5",
|
||||||
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"keypair": "^1.0.4",
|
||||||
|
"prisma": "^7.3.0",
|
||||||
|
"zod": "^4.3.6",
|
||||||
|
"zon": "^1.0.3",
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
@@ -13,14 +27,286 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
|
"@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@10.5.0", "", { "dependencies": { "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw=="],
|
||||||
|
|
||||||
|
"@chevrotain/gast": ["@chevrotain/gast@10.5.0", "", { "dependencies": { "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A=="],
|
||||||
|
|
||||||
|
"@chevrotain/types": ["@chevrotain/types@10.5.0", "", {}, "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A=="],
|
||||||
|
|
||||||
|
"@chevrotain/utils": ["@chevrotain/utils@10.5.0", "", {}, "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ=="],
|
||||||
|
|
||||||
|
"@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||||
|
|
||||||
|
"@duxcore/eventra": ["@duxcore/eventra@1.1.0", "", {}, "sha512-XYLksXvOjr3uGw9oh0wgKVF0POiz1Gjk/Ety8chEQdEwzDAiyydztB8TtjF/Pfr+vdM/ceMV/OOQliBZLnfONA=="],
|
||||||
|
|
||||||
|
"@electric-sql/pglite": ["@electric-sql/pglite@0.3.15", "", {}, "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ=="],
|
||||||
|
|
||||||
|
"@electric-sql/pglite-socket": ["@electric-sql/pglite-socket@0.0.20", "", { "peerDependencies": { "@electric-sql/pglite": "0.3.15" }, "bin": { "pglite-server": "dist/scripts/server.js" } }, "sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg=="],
|
||||||
|
|
||||||
|
"@electric-sql/pglite-tools": ["@electric-sql/pglite-tools@0.2.20", "", { "peerDependencies": { "@electric-sql/pglite": "0.3.15" } }, "sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A=="],
|
||||||
|
|
||||||
|
"@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
|
||||||
|
|
||||||
|
"@mrleebo/prisma-ast": ["@mrleebo/prisma-ast@0.13.1", "", { "dependencies": { "chevrotain": "^10.5.0", "lilconfig": "^2.1.0" } }, "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw=="],
|
||||||
|
|
||||||
|
"@prisma/adapter-pg": ["@prisma/adapter-pg@7.3.0", "", { "dependencies": { "@prisma/driver-adapter-utils": "7.3.0", "pg": "^8.16.3", "postgres-array": "3.0.4" } }, "sha512-iuYQMbIPO6i9O45Fv8TB7vWu00BXhCaNAShenqF7gLExGDbnGp5BfFB4yz1K59zQ59jF6tQ9YHrg0P6/J3OoLg=="],
|
||||||
|
|
||||||
|
"@prisma/config": ["@prisma/config@7.3.0", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-QyMV67+eXF7uMtKxTEeQqNu/Be7iH+3iDZOQZW5ttfbSwBamCSdwPszA0dum+Wx27I7anYTPLmRmMORKViSW1A=="],
|
||||||
|
|
||||||
|
"@prisma/debug": ["@prisma/debug@7.3.0", "", {}, "sha512-yh/tHhraCzYkffsI1/3a7SHX8tpgbJu1NPnuxS4rEpJdWAUDHUH25F1EDo6PPzirpyLNkgPPZdhojQK804BGtg=="],
|
||||||
|
|
||||||
|
"@prisma/dev": ["@prisma/dev@0.20.0", "", { "dependencies": { "@electric-sql/pglite": "0.3.15", "@electric-sql/pglite-socket": "0.0.20", "@electric-sql/pglite-tools": "0.2.20", "@hono/node-server": "1.19.9", "@mrleebo/prisma-ast": "0.13.1", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", "foreground-child": "3.3.1", "get-port-please": "3.2.0", "hono": "4.11.4", "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", "remeda": "2.33.4", "std-env": "3.10.0", "valibot": "1.2.0", "zeptomatch": "2.1.0" } }, "sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ=="],
|
||||||
|
|
||||||
|
"@prisma/driver-adapter-utils": ["@prisma/driver-adapter-utils@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-Wdlezh1ck0Rq2dDINkfSkwbR53q53//Eo1vVqVLwtiZ0I6fuWDGNPxwq+SNAIHnsU+FD/m3aIJKevH3vF13U3w=="],
|
||||||
|
|
||||||
|
"@prisma/engines": ["@prisma/engines@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0", "@prisma/engines-version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", "@prisma/fetch-engine": "7.3.0", "@prisma/get-platform": "7.3.0" } }, "sha512-cWRQoPDXPtR6stOWuWFZf9pHdQ/o8/QNWn0m0zByxf5Kd946Q875XdEJ52pEsX88vOiXUmjuPG3euw82mwQNMg=="],
|
||||||
|
|
||||||
|
"@prisma/engines-version": ["@prisma/engines-version@7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", "", {}, "sha512-IH2va2ouUHihyiTTRW889LjKAl1CusZOvFfZxCDNpjSENt7g2ndFsK0vdIw/72v7+jCN6YgkHmdAP/BI7SDgyg=="],
|
||||||
|
|
||||||
|
"@prisma/fetch-engine": ["@prisma/fetch-engine@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0", "@prisma/engines-version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", "@prisma/get-platform": "7.3.0" } }, "sha512-Mm0F84JMqM9Vxk70pzfNpGJ1lE4hYjOeLMu7nOOD1i83nvp8MSAcFYBnHqLvEZiA6onUR+m8iYogtOY4oPO5lQ=="],
|
||||||
|
|
||||||
|
"@prisma/get-platform": ["@prisma/get-platform@7.2.0", "", { "dependencies": { "@prisma/debug": "7.2.0" } }, "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA=="],
|
||||||
|
|
||||||
|
"@prisma/query-plan-executor": ["@prisma/query-plan-executor@7.2.0", "", {}, "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ=="],
|
||||||
|
|
||||||
|
"@prisma/studio-core": ["@prisma/studio-core@0.13.1", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg=="],
|
||||||
|
|
||||||
|
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
||||||
|
|
||||||
|
"@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.10", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA=="],
|
||||||
|
|
||||||
|
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
|
"@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
|
||||||
|
|
||||||
|
"@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="],
|
||||||
|
|
||||||
|
"aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="],
|
||||||
|
|
||||||
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
||||||
|
|
||||||
|
"c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="],
|
||||||
|
|
||||||
|
"chevrotain": ["chevrotain@10.5.0", "", { "dependencies": { "@chevrotain/cst-dts-gen": "10.5.0", "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "@chevrotain/utils": "10.5.0", "lodash": "4.17.21", "regexp-to-ast": "0.5.0" } }, "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A=="],
|
||||||
|
|
||||||
|
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||||
|
|
||||||
|
"citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="],
|
||||||
|
|
||||||
|
"confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="],
|
||||||
|
|
||||||
|
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||||
|
|
||||||
|
"cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
|
||||||
|
|
||||||
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||||
|
|
||||||
|
"cuid": ["cuid@3.0.0", "", {}, "sha512-WZYYkHdIDnaxdeP8Misq3Lah5vFjJwGuItJuV+tvMafosMzw0nF297T7mrm8IOWiPJkV6gc7sa8pzx27+w25Zg=="],
|
||||||
|
|
||||||
|
"deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="],
|
||||||
|
|
||||||
|
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
|
||||||
|
|
||||||
|
"denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="],
|
||||||
|
|
||||||
|
"destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
|
||||||
|
|
||||||
|
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||||
|
|
||||||
|
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||||
|
|
||||||
|
"effect": ["effect@3.18.4", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA=="],
|
||||||
|
|
||||||
|
"empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
|
||||||
|
|
||||||
|
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
|
||||||
|
|
||||||
|
"fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
|
||||||
|
|
||||||
|
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||||
|
|
||||||
|
"generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="],
|
||||||
|
|
||||||
|
"get-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="],
|
||||||
|
|
||||||
|
"giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
|
||||||
|
|
||||||
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
|
"grammex": ["grammex@3.1.12", "", {}, "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ=="],
|
||||||
|
|
||||||
|
"graphmatch": ["graphmatch@1.1.0", "", {}, "sha512-0E62MaTW5rPZVRLyIJZG/YejmdA/Xr1QydHEw3Vt+qOKkMIOE8WDLc9ZX2bmAjtJFZcId4lEdrdmASsEy7D1QA=="],
|
||||||
|
|
||||||
|
"hono": ["hono@4.11.5", "", {}, "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g=="],
|
||||||
|
|
||||||
|
"http-status-codes": ["http-status-codes@2.3.0", "", {}, "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA=="],
|
||||||
|
|
||||||
|
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||||
|
|
||||||
|
"is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="],
|
||||||
|
|
||||||
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
||||||
|
|
||||||
|
"jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="],
|
||||||
|
|
||||||
|
"jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
|
||||||
|
|
||||||
|
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
|
||||||
|
|
||||||
|
"keypair": ["keypair@1.0.4", "", {}, "sha512-zwhgOhhniaL7oxMgUMKKw5219PWWABMO+dgMnzJOQ2/5L3XJtTJGhW2PEXlxXj9zaccdReZJZ83+4NPhVfNVDg=="],
|
||||||
|
|
||||||
|
"lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
|
||||||
|
|
||||||
|
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||||
|
|
||||||
|
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
|
||||||
|
|
||||||
|
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
|
||||||
|
|
||||||
|
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="],
|
||||||
|
|
||||||
|
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="],
|
||||||
|
|
||||||
|
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
|
||||||
|
|
||||||
|
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
|
||||||
|
|
||||||
|
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
|
||||||
|
|
||||||
|
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||||
|
|
||||||
|
"lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="],
|
||||||
|
|
||||||
|
"named-placeholders": ["named-placeholders@1.1.6", "", { "dependencies": { "lru.min": "^1.1.0" } }, "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w=="],
|
||||||
|
|
||||||
|
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||||
|
|
||||||
|
"nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="],
|
||||||
|
|
||||||
|
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||||
|
|
||||||
|
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
|
||||||
|
|
||||||
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
|
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||||
|
|
||||||
|
"perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
|
||||||
|
|
||||||
|
"pg": ["pg@8.17.2", "", { "dependencies": { "pg-connection-string": "^2.10.1", "pg-pool": "^3.11.0", "pg-protocol": "^1.11.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw=="],
|
||||||
|
|
||||||
|
"pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="],
|
||||||
|
|
||||||
|
"pg-connection-string": ["pg-connection-string@2.10.1", "", {}, "sha512-iNzslsoeSH2/gmDDKiyMqF64DATUCWj3YJ0wP14kqcsf2TUklwimd+66yYojKwZCA7h2yRNLGug71hCBA2a4sw=="],
|
||||||
|
|
||||||
|
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
|
||||||
|
|
||||||
|
"pg-pool": ["pg-pool@3.11.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w=="],
|
||||||
|
|
||||||
|
"pg-protocol": ["pg-protocol@1.11.0", "", {}, "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g=="],
|
||||||
|
|
||||||
|
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
|
||||||
|
|
||||||
|
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
|
||||||
|
|
||||||
|
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
|
||||||
|
|
||||||
|
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
|
||||||
|
|
||||||
|
"postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="],
|
||||||
|
|
||||||
|
"postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="],
|
||||||
|
|
||||||
|
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
||||||
|
|
||||||
|
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
||||||
|
|
||||||
|
"prisma": ["prisma@7.3.0", "", { "dependencies": { "@prisma/config": "7.3.0", "@prisma/dev": "0.20.0", "@prisma/engines": "7.3.0", "@prisma/studio-core": "0.13.1", "mysql2": "3.15.3", "postgres": "3.4.7" }, "peerDependencies": { "better-sqlite3": ">=9.0.0", "typescript": ">=5.4.0" }, "optionalPeers": ["better-sqlite3", "typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-ApYSOLHfMN8WftJA+vL6XwAPOh/aZ0BgUyyKPwUFgjARmG6EBI9LzDPf6SWULQMSAxydV9qn5gLj037nPNlg2w=="],
|
||||||
|
|
||||||
|
"proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="],
|
||||||
|
|
||||||
|
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
|
||||||
|
|
||||||
|
"rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
|
||||||
|
|
||||||
|
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
|
||||||
|
|
||||||
|
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
||||||
|
|
||||||
|
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||||
|
|
||||||
|
"regexp-to-ast": ["regexp-to-ast@0.5.0", "", {}, "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw=="],
|
||||||
|
|
||||||
|
"remeda": ["remeda@2.33.4", "", {}, "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ=="],
|
||||||
|
|
||||||
|
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
|
||||||
|
|
||||||
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
|
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||||
|
|
||||||
|
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||||
|
|
||||||
|
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||||
|
|
||||||
|
"seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="],
|
||||||
|
|
||||||
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
|
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||||
|
|
||||||
|
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
|
||||||
|
|
||||||
|
"sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="],
|
||||||
|
|
||||||
|
"std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
|
||||||
|
|
||||||
|
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
|
||||||
|
"valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="],
|
||||||
|
|
||||||
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|
||||||
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
|
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
|
||||||
|
|
||||||
|
"zeptomatch": ["zeptomatch@2.1.0", "", { "dependencies": { "grammex": "^3.1.11", "graphmatch": "^1.1.0" } }, "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA=="],
|
||||||
|
|
||||||
|
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||||
|
|
||||||
|
"zon": ["zon@1.0.3", "", {}, "sha512-FKLlkaI8bU0ORFgZIzbqgvT7ei7aHob2jvhDPLgkwxccDurBRviDlD2eC2px6kEox0VlW0rK3VBwjsvtGV6g0w=="],
|
||||||
|
|
||||||
|
"@prisma/dev/hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="],
|
||||||
|
|
||||||
|
"@prisma/engines/@prisma/get-platform": ["@prisma/get-platform@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg=="],
|
||||||
|
|
||||||
|
"@prisma/fetch-engine/@prisma/get-platform": ["@prisma/get-platform@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg=="],
|
||||||
|
|
||||||
|
"@prisma/get-platform/@prisma/debug": ["@prisma/debug@7.2.0", "", {}, "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw=="],
|
||||||
|
|
||||||
|
"nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="],
|
||||||
|
|
||||||
|
"pg-types/postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
||||||
|
|
||||||
|
"proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file should be your main import to use Prisma-related types and utilities in a browser.
|
||||||
|
* Use it to get access to models, enums, and input types.
|
||||||
|
*
|
||||||
|
* This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
|
||||||
|
* See `client.ts` for the standard, server-side entry point.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Prisma from './internal/prismaNamespaceBrowser.ts'
|
||||||
|
export { Prisma }
|
||||||
|
export * as $Enums from './enums.ts'
|
||||||
|
export * from './enums.ts';
|
||||||
|
/**
|
||||||
|
* Model Session
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Session = Prisma.SessionModel
|
||||||
|
/**
|
||||||
|
* Model User
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type User = Prisma.UserModel
|
||||||
|
/**
|
||||||
|
* Model Role
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Role = Prisma.RoleModel
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
|
||||||
|
* If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as process from 'node:process'
|
||||||
|
import * as path from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
globalThis['__dirname'] = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import * as $Enums from "./enums.ts"
|
||||||
|
import * as $Class from "./internal/class.ts"
|
||||||
|
import * as Prisma from "./internal/prismaNamespace.ts"
|
||||||
|
|
||||||
|
export * as $Enums from './enums.ts'
|
||||||
|
export * from "./enums.ts"
|
||||||
|
/**
|
||||||
|
* ## Prisma Client
|
||||||
|
*
|
||||||
|
* Type-safe database client for TypeScript
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient()
|
||||||
|
* // Fetch zero or more Sessions
|
||||||
|
* const sessions = await prisma.session.findMany()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/client).
|
||||||
|
*/
|
||||||
|
export const PrismaClient = $Class.getPrismaClientClass()
|
||||||
|
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||||
|
export { Prisma }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model Session
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Session = Prisma.SessionModel
|
||||||
|
/**
|
||||||
|
* Model User
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type User = Prisma.UserModel
|
||||||
|
/**
|
||||||
|
* Model Role
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Role = Prisma.RoleModel
|
||||||
@@ -0,0 +1,352 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file exports various common sort, input & filter types that are not directly linked to a particular model.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import * as $Enums from "./enums.ts"
|
||||||
|
import type * as Prisma from "./internal/prismaNamespace.ts"
|
||||||
|
|
||||||
|
|
||||||
|
export type StringFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
mode?: Prisma.QueryMode
|
||||||
|
not?: Prisma.NestedStringFilter<$PrismaModel> | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateTimeFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BoolFilter<$PrismaModel = never> = {
|
||||||
|
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateTimeNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SortOrderInput = {
|
||||||
|
sort: Prisma.SortOrder
|
||||||
|
nulls?: Prisma.NullsOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
mode?: Prisma.QueryMode
|
||||||
|
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
mode?: Prisma.QueryMode
|
||||||
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IntFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntFilter<$PrismaModel> | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
mode?: Prisma.QueryMode
|
||||||
|
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IntWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_avg?: Prisma.NestedFloatFilter<$PrismaModel>
|
||||||
|
_sum?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringFilter<$PrismaModel> | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedBoolFilter<$PrismaModel = never> = {
|
||||||
|
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedIntFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntFilter<$PrismaModel> | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedIntNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedIntWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_avg?: Prisma.NestedFloatFilter<$PrismaModel>
|
||||||
|
_sum?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedFloatFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel>
|
||||||
|
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedFloatFilter<$PrismaModel> | number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file exports all enum related types from the schema.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This file is empty because there are no enums in the schema.
|
||||||
|
export {}
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* WARNING: This is an internal file that is subject to change!
|
||||||
|
*
|
||||||
|
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||||
|
*
|
||||||
|
* Please import the `PrismaClient` class from the `client.ts` file instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import type * as Prisma from "./prismaNamespace.ts"
|
||||||
|
|
||||||
|
|
||||||
|
const config: runtime.GetPrismaClientConfig = {
|
||||||
|
"previewFeatures": [],
|
||||||
|
"clientVersion": "7.3.0",
|
||||||
|
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
|
||||||
|
"activeProvider": "postgresql",
|
||||||
|
"inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId Int @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n",
|
||||||
|
"runtimeDataModel": {
|
||||||
|
"models": {},
|
||||||
|
"enums": {},
|
||||||
|
"types": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
|
||||||
|
|
||||||
|
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||||
|
const { Buffer } = await import('node:buffer')
|
||||||
|
const wasmArray = Buffer.from(wasmBase64, 'base64')
|
||||||
|
return new WebAssembly.Module(wasmArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.compilerWasm = {
|
||||||
|
getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.mjs"),
|
||||||
|
|
||||||
|
getQueryCompilerWasmModule: async () => {
|
||||||
|
const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.wasm-base64.mjs")
|
||||||
|
return await decodeBase64AsWasm(wasm)
|
||||||
|
},
|
||||||
|
|
||||||
|
importName: "./query_compiler_fast_bg.js"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export type LogOptions<ClientOptions extends Prisma.PrismaClientOptions> =
|
||||||
|
'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array<Prisma.LogLevel | Prisma.LogDefinition> ? Prisma.GetEvents<ClientOptions['log']> : never : never
|
||||||
|
|
||||||
|
export interface PrismaClientConstructor {
|
||||||
|
/**
|
||||||
|
* ## Prisma Client
|
||||||
|
*
|
||||||
|
* Type-safe database client for TypeScript
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient()
|
||||||
|
* // Fetch zero or more Sessions
|
||||||
|
* const sessions = await prisma.session.findMany()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/client).
|
||||||
|
*/
|
||||||
|
|
||||||
|
new <
|
||||||
|
Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions,
|
||||||
|
LogOpts extends LogOptions<Options> = LogOptions<Options>,
|
||||||
|
OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends { omit: infer U } ? U : Prisma.PrismaClientOptions['omit'],
|
||||||
|
ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
|
||||||
|
>(options: Prisma.Subset<Options, Prisma.PrismaClientOptions> ): PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Prisma Client
|
||||||
|
*
|
||||||
|
* Type-safe database client for TypeScript
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient()
|
||||||
|
* // Fetch zero or more Sessions
|
||||||
|
* const sessions = await prisma.session.findMany()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/client).
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface PrismaClient<
|
||||||
|
in LogOpts extends Prisma.LogLevel = never,
|
||||||
|
in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = undefined,
|
||||||
|
in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
|
||||||
|
> {
|
||||||
|
[K: symbol]: { types: Prisma.TypeMap<ExtArgs>['other'] }
|
||||||
|
|
||||||
|
$on<V extends LogOpts>(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect with the database
|
||||||
|
*/
|
||||||
|
$connect(): runtime.Types.Utils.JsPromise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the database
|
||||||
|
*/
|
||||||
|
$disconnect(): runtime.Types.Utils.JsPromise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a prepared raw query and returns the number of affected rows.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};`
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a raw query and returns the number of affected rows.
|
||||||
|
* Susceptible to SQL injections, see documentation.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com')
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a prepared raw query and returns the `SELECT` data.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};`
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a raw query and returns the `SELECT` data.
|
||||||
|
* Susceptible to SQL injections, see documentation.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com')
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<T>;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const [george, bob, alice] = await prisma.$transaction([
|
||||||
|
* prisma.user.create({ data: { name: 'George' } }),
|
||||||
|
* prisma.user.create({ data: { name: 'Bob' } }),
|
||||||
|
* prisma.user.create({ data: { name: 'Alice' } }),
|
||||||
|
* ])
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions).
|
||||||
|
*/
|
||||||
|
$transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
|
||||||
|
|
||||||
|
$transaction<R>(fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<R>
|
||||||
|
|
||||||
|
$extends: runtime.Types.Extensions.ExtendsHook<"extends", Prisma.TypeMapCb<OmitOpts>, ExtArgs, runtime.Types.Utils.Call<Prisma.TypeMapCb<OmitOpts>, {
|
||||||
|
extArgs: ExtArgs
|
||||||
|
}>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.session`: Exposes CRUD operations for the **Session** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more Sessions
|
||||||
|
* const sessions = await prisma.session.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get session(): Prisma.SessionDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.user`: Exposes CRUD operations for the **User** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more Users
|
||||||
|
* const users = await prisma.user.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get user(): Prisma.UserDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.role`: Exposes CRUD operations for the **Role** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more Roles
|
||||||
|
* const roles = await prisma.role.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get role(): Prisma.RoleDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrismaClientClass(): PrismaClientConstructor {
|
||||||
|
return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor
|
||||||
|
}
|
||||||
@@ -0,0 +1,964 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* WARNING: This is an internal file that is subject to change!
|
||||||
|
*
|
||||||
|
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||||
|
*
|
||||||
|
* All exports from this file are wrapped under a `Prisma` namespace object in the client.ts file.
|
||||||
|
* While this enables partial backward compatibility, it is not part of the stable public API.
|
||||||
|
*
|
||||||
|
* If you are looking for your Models, Enums, and Input Types, please import them from the respective
|
||||||
|
* model files in the `model` directory!
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import type * as Prisma from "../models.ts"
|
||||||
|
import { type PrismaClient } from "./class.ts"
|
||||||
|
|
||||||
|
export type * from '../models.ts'
|
||||||
|
|
||||||
|
export type DMMF = typeof runtime.DMMF
|
||||||
|
|
||||||
|
export type PrismaPromise<T> = runtime.Types.Public.PrismaPromise<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prisma Errors
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError
|
||||||
|
export type PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError
|
||||||
|
|
||||||
|
export const PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError
|
||||||
|
export type PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError
|
||||||
|
|
||||||
|
export const PrismaClientRustPanicError = runtime.PrismaClientRustPanicError
|
||||||
|
export type PrismaClientRustPanicError = runtime.PrismaClientRustPanicError
|
||||||
|
|
||||||
|
export const PrismaClientInitializationError = runtime.PrismaClientInitializationError
|
||||||
|
export type PrismaClientInitializationError = runtime.PrismaClientInitializationError
|
||||||
|
|
||||||
|
export const PrismaClientValidationError = runtime.PrismaClientValidationError
|
||||||
|
export type PrismaClientValidationError = runtime.PrismaClientValidationError
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-export of sql-template-tag
|
||||||
|
*/
|
||||||
|
export const sql = runtime.sqltag
|
||||||
|
export const empty = runtime.empty
|
||||||
|
export const join = runtime.join
|
||||||
|
export const raw = runtime.raw
|
||||||
|
export const Sql = runtime.Sql
|
||||||
|
export type Sql = runtime.Sql
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decimal.js
|
||||||
|
*/
|
||||||
|
export const Decimal = runtime.Decimal
|
||||||
|
export type Decimal = runtime.Decimal
|
||||||
|
|
||||||
|
export type DecimalJsLike = runtime.DecimalJsLike
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extensions
|
||||||
|
*/
|
||||||
|
export type Extension = runtime.Types.Extensions.UserArgs
|
||||||
|
export const getExtensionContext = runtime.Extensions.getExtensionContext
|
||||||
|
export type Args<T, F extends runtime.Operation> = runtime.Types.Public.Args<T, F>
|
||||||
|
export type Payload<T, F extends runtime.Operation = never> = runtime.Types.Public.Payload<T, F>
|
||||||
|
export type Result<T, A, F extends runtime.Operation> = runtime.Types.Public.Result<T, A, F>
|
||||||
|
export type Exact<A, W> = runtime.Types.Public.Exact<A, W>
|
||||||
|
|
||||||
|
export type PrismaVersion = {
|
||||||
|
client: string
|
||||||
|
engine: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prisma Client JS version: 7.3.0
|
||||||
|
* Query Engine version: 9d6ad21cbbceab97458517b147a6a09ff43aa735
|
||||||
|
*/
|
||||||
|
export const prismaVersion: PrismaVersion = {
|
||||||
|
client: "7.3.0",
|
||||||
|
engine: "9d6ad21cbbceab97458517b147a6a09ff43aa735"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility Types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Bytes = runtime.Bytes
|
||||||
|
export type JsonObject = runtime.JsonObject
|
||||||
|
export type JsonArray = runtime.JsonArray
|
||||||
|
export type JsonValue = runtime.JsonValue
|
||||||
|
export type InputJsonObject = runtime.InputJsonObject
|
||||||
|
export type InputJsonArray = runtime.InputJsonArray
|
||||||
|
export type InputJsonValue = runtime.InputJsonValue
|
||||||
|
|
||||||
|
|
||||||
|
export const NullTypes = {
|
||||||
|
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
|
||||||
|
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
|
||||||
|
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const DbNull = runtime.DbNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const JsonNull = runtime.JsonNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const AnyNull = runtime.AnyNull
|
||||||
|
|
||||||
|
|
||||||
|
type SelectAndInclude = {
|
||||||
|
select: any
|
||||||
|
include: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type SelectAndOmit = {
|
||||||
|
select: any
|
||||||
|
omit: any
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From T, pick a set of properties whose keys are in the union K
|
||||||
|
*/
|
||||||
|
type Prisma__Pick<T, K extends keyof T> = {
|
||||||
|
[P in K]: T[P];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Enumerable<T> = T | Array<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subset
|
||||||
|
* @desc From `T` pick properties that exist in `U`. Simple version of Intersection
|
||||||
|
*/
|
||||||
|
export type Subset<T, U> = {
|
||||||
|
[key in keyof T]: key extends keyof U ? T[key] : never;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SelectSubset
|
||||||
|
* @desc From `T` pick properties that exist in `U`. Simple version of Intersection.
|
||||||
|
* Additionally, it validates, if both select and include are present. If the case, it errors.
|
||||||
|
*/
|
||||||
|
export type SelectSubset<T, U> = {
|
||||||
|
[key in keyof T]: key extends keyof U ? T[key] : never
|
||||||
|
} &
|
||||||
|
(T extends SelectAndInclude
|
||||||
|
? 'Please either choose `select` or `include`.'
|
||||||
|
: T extends SelectAndOmit
|
||||||
|
? 'Please either choose `select` or `omit`.'
|
||||||
|
: {})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subset + Intersection
|
||||||
|
* @desc From `T` pick properties that exist in `U` and intersect `K`
|
||||||
|
*/
|
||||||
|
export type SubsetIntersection<T, U, K> = {
|
||||||
|
[key in keyof T]: key extends keyof U ? T[key] : never
|
||||||
|
} &
|
||||||
|
K
|
||||||
|
|
||||||
|
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XOR is needed to have a real mutually exclusive union type
|
||||||
|
* https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types
|
||||||
|
*/
|
||||||
|
export type XOR<T, U> =
|
||||||
|
T extends object ?
|
||||||
|
U extends object ?
|
||||||
|
(Without<T, U> & U) | (Without<U, T> & T)
|
||||||
|
: U : T
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is T a Record?
|
||||||
|
*/
|
||||||
|
type IsObject<T extends any> = T extends Array<any>
|
||||||
|
? False
|
||||||
|
: T extends Date
|
||||||
|
? False
|
||||||
|
: T extends Uint8Array
|
||||||
|
? False
|
||||||
|
: T extends BigInt
|
||||||
|
? False
|
||||||
|
: T extends object
|
||||||
|
? True
|
||||||
|
: False
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If it's T[], return T
|
||||||
|
*/
|
||||||
|
export type UnEnumerate<T extends unknown> = T extends Array<infer U> ? U : T
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From ts-toolbelt
|
||||||
|
*/
|
||||||
|
|
||||||
|
type __Either<O extends object, K extends Key> = Omit<O, K> &
|
||||||
|
{
|
||||||
|
// Merge all but K
|
||||||
|
[P in K]: Prisma__Pick<O, P & keyof O> // With K possibilities
|
||||||
|
}[K]
|
||||||
|
|
||||||
|
type EitherStrict<O extends object, K extends Key> = Strict<__Either<O, K>>
|
||||||
|
|
||||||
|
type EitherLoose<O extends object, K extends Key> = ComputeRaw<__Either<O, K>>
|
||||||
|
|
||||||
|
type _Either<
|
||||||
|
O extends object,
|
||||||
|
K extends Key,
|
||||||
|
strict extends Boolean
|
||||||
|
> = {
|
||||||
|
1: EitherStrict<O, K>
|
||||||
|
0: EitherLoose<O, K>
|
||||||
|
}[strict]
|
||||||
|
|
||||||
|
export type Either<
|
||||||
|
O extends object,
|
||||||
|
K extends Key,
|
||||||
|
strict extends Boolean = 1
|
||||||
|
> = O extends unknown ? _Either<O, K, strict> : never
|
||||||
|
|
||||||
|
export type Union = any
|
||||||
|
|
||||||
|
export type PatchUndefined<O extends object, O1 extends object> = {
|
||||||
|
[K in keyof O]: O[K] extends undefined ? At<O1, K> : O[K]
|
||||||
|
} & {}
|
||||||
|
|
||||||
|
/** Helper Types for "Merge" **/
|
||||||
|
export type IntersectOf<U extends Union> = (
|
||||||
|
U extends unknown ? (k: U) => void : never
|
||||||
|
) extends (k: infer I) => void
|
||||||
|
? I
|
||||||
|
: never
|
||||||
|
|
||||||
|
export type Overwrite<O extends object, O1 extends object> = {
|
||||||
|
[K in keyof O]: K extends keyof O1 ? O1[K] : O[K];
|
||||||
|
} & {};
|
||||||
|
|
||||||
|
type _Merge<U extends object> = IntersectOf<Overwrite<U, {
|
||||||
|
[K in keyof U]-?: At<U, K>;
|
||||||
|
}>>;
|
||||||
|
|
||||||
|
type Key = string | number | symbol;
|
||||||
|
type AtStrict<O extends object, K extends Key> = O[K & keyof O];
|
||||||
|
type AtLoose<O extends object, K extends Key> = O extends unknown ? AtStrict<O, K> : never;
|
||||||
|
export type At<O extends object, K extends Key, strict extends Boolean = 1> = {
|
||||||
|
1: AtStrict<O, K>;
|
||||||
|
0: AtLoose<O, K>;
|
||||||
|
}[strict];
|
||||||
|
|
||||||
|
export type ComputeRaw<A extends any> = A extends Function ? A : {
|
||||||
|
[K in keyof A]: A[K];
|
||||||
|
} & {};
|
||||||
|
|
||||||
|
export type OptionalFlat<O> = {
|
||||||
|
[K in keyof O]?: O[K];
|
||||||
|
} & {};
|
||||||
|
|
||||||
|
type _Record<K extends keyof any, T> = {
|
||||||
|
[P in K]: T;
|
||||||
|
};
|
||||||
|
|
||||||
|
// cause typescript not to expand types and preserve names
|
||||||
|
type NoExpand<T> = T extends unknown ? T : never;
|
||||||
|
|
||||||
|
// this type assumes the passed object is entirely optional
|
||||||
|
export type AtLeast<O extends object, K extends string> = NoExpand<
|
||||||
|
O extends unknown
|
||||||
|
? | (K extends keyof O ? { [P in K]: O[P] } & O : O)
|
||||||
|
| {[P in keyof O as P extends K ? P : never]-?: O[P]} & O
|
||||||
|
: never>;
|
||||||
|
|
||||||
|
type _Strict<U, _U = U> = U extends unknown ? U & OptionalFlat<_Record<Exclude<Keys<_U>, keyof U>, never>> : never;
|
||||||
|
|
||||||
|
export type Strict<U extends object> = ComputeRaw<_Strict<U>>;
|
||||||
|
/** End Helper Types for "Merge" **/
|
||||||
|
|
||||||
|
export type Merge<U extends object> = ComputeRaw<_Merge<Strict<U>>>;
|
||||||
|
|
||||||
|
export type Boolean = True | False
|
||||||
|
|
||||||
|
export type True = 1
|
||||||
|
|
||||||
|
export type False = 0
|
||||||
|
|
||||||
|
export type Not<B extends Boolean> = {
|
||||||
|
0: 1
|
||||||
|
1: 0
|
||||||
|
}[B]
|
||||||
|
|
||||||
|
export type Extends<A1 extends any, A2 extends any> = [A1] extends [never]
|
||||||
|
? 0 // anything `never` is false
|
||||||
|
: A1 extends A2
|
||||||
|
? 1
|
||||||
|
: 0
|
||||||
|
|
||||||
|
export type Has<U extends Union, U1 extends Union> = Not<
|
||||||
|
Extends<Exclude<U1, U>, U1>
|
||||||
|
>
|
||||||
|
|
||||||
|
export type Or<B1 extends Boolean, B2 extends Boolean> = {
|
||||||
|
0: {
|
||||||
|
0: 0
|
||||||
|
1: 1
|
||||||
|
}
|
||||||
|
1: {
|
||||||
|
0: 1
|
||||||
|
1: 1
|
||||||
|
}
|
||||||
|
}[B1][B2]
|
||||||
|
|
||||||
|
export type Keys<U extends Union> = U extends unknown ? keyof U : never
|
||||||
|
|
||||||
|
export type GetScalarType<T, O> = O extends object ? {
|
||||||
|
[P in keyof T]: P extends keyof O
|
||||||
|
? O[P]
|
||||||
|
: never
|
||||||
|
} : never
|
||||||
|
|
||||||
|
type FieldPaths<
|
||||||
|
T,
|
||||||
|
U = Omit<T, '_avg' | '_sum' | '_count' | '_min' | '_max'>
|
||||||
|
> = IsObject<T> extends True ? U : T
|
||||||
|
|
||||||
|
export type GetHavingFields<T> = {
|
||||||
|
[K in keyof T]: Or<
|
||||||
|
Or<Extends<'OR', K>, Extends<'AND', K>>,
|
||||||
|
Extends<'NOT', K>
|
||||||
|
> extends True
|
||||||
|
? // infer is only needed to not hit TS limit
|
||||||
|
// based on the brilliant idea of Pierre-Antoine Mills
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/30188#issuecomment-478938437
|
||||||
|
T[K] extends infer TK
|
||||||
|
? GetHavingFields<UnEnumerate<TK> extends object ? Merge<UnEnumerate<TK>> : never>
|
||||||
|
: never
|
||||||
|
: {} extends FieldPaths<T[K]>
|
||||||
|
? never
|
||||||
|
: K
|
||||||
|
}[keyof T]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert tuple to union
|
||||||
|
*/
|
||||||
|
type _TupleToUnion<T> = T extends (infer E)[] ? E : never
|
||||||
|
type TupleToUnion<K extends readonly any[]> = _TupleToUnion<K>
|
||||||
|
export type MaybeTupleToUnion<T> = T extends any[] ? TupleToUnion<T> : T
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like `Pick`, but additionally can also accept an array of keys
|
||||||
|
*/
|
||||||
|
export type PickEnumerable<T, K extends Enumerable<keyof T> | keyof T> = Prisma__Pick<T, MaybeTupleToUnion<K>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclude all keys with underscores
|
||||||
|
*/
|
||||||
|
export type ExcludeUnderscoreKeys<T extends string> = T extends `_${string}` ? never : T
|
||||||
|
|
||||||
|
|
||||||
|
export type FieldRef<Model, FieldType> = runtime.FieldRef<Model, FieldType>
|
||||||
|
|
||||||
|
type FieldRefInputType<Model, FieldType> = Model extends never ? never : FieldRef<Model, FieldType>
|
||||||
|
|
||||||
|
|
||||||
|
export const ModelName = {
|
||||||
|
Session: 'Session',
|
||||||
|
User: 'User',
|
||||||
|
Role: 'Role'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface TypeMapCb<GlobalOmitOptions = {}> extends runtime.Types.Utils.Fn<{extArgs: runtime.Types.Extensions.InternalArgs }, runtime.Types.Utils.Record<string, any>> {
|
||||||
|
returns: TypeMap<this['params']['extArgs'], GlobalOmitOptions>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> = {
|
||||||
|
globalOmitOptions: {
|
||||||
|
omit: GlobalOmitOptions
|
||||||
|
}
|
||||||
|
meta: {
|
||||||
|
modelProps: "session" | "user" | "role"
|
||||||
|
txIsolationLevel: TransactionIsolationLevel
|
||||||
|
}
|
||||||
|
model: {
|
||||||
|
Session: {
|
||||||
|
payload: Prisma.$SessionPayload<ExtArgs>
|
||||||
|
fields: Prisma.SessionFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.SessionFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.SessionFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.SessionFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.SessionFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.SessionFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.SessionCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.SessionCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
createManyAndReturn: {
|
||||||
|
args: Prisma.SessionCreateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>[]
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.SessionDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.SessionUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.SessionDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.SessionUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateManyAndReturn: {
|
||||||
|
args: Prisma.SessionUpdateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>[]
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.SessionUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$SessionPayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.SessionAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateSession>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.SessionGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.SessionGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.SessionCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.SessionCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
User: {
|
||||||
|
payload: Prisma.$UserPayload<ExtArgs>
|
||||||
|
fields: Prisma.UserFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.UserFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.UserFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.UserFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.UserFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.UserFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.UserCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.UserCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
createManyAndReturn: {
|
||||||
|
args: Prisma.UserCreateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>[]
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.UserDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.UserUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.UserDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.UserUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateManyAndReturn: {
|
||||||
|
args: Prisma.UserUpdateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>[]
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.UserUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$UserPayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.UserAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateUser>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.UserGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.UserGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.UserCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.UserCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Role: {
|
||||||
|
payload: Prisma.$RolePayload<ExtArgs>
|
||||||
|
fields: Prisma.RoleFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.RoleFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.RoleFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.RoleFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.RoleFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.RoleFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.RoleCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.RoleCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
createManyAndReturn: {
|
||||||
|
args: Prisma.RoleCreateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>[]
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.RoleDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.RoleUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.RoleDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.RoleUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateManyAndReturn: {
|
||||||
|
args: Prisma.RoleUpdateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>[]
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.RoleUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RolePayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.RoleAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateRole>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.RoleGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.RoleGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.RoleCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.RoleCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} & {
|
||||||
|
other: {
|
||||||
|
payload: any
|
||||||
|
operations: {
|
||||||
|
$executeRaw: {
|
||||||
|
args: [query: TemplateStringsArray | Sql, ...values: any[]],
|
||||||
|
result: any
|
||||||
|
}
|
||||||
|
$executeRawUnsafe: {
|
||||||
|
args: [query: string, ...values: any[]],
|
||||||
|
result: any
|
||||||
|
}
|
||||||
|
$queryRaw: {
|
||||||
|
args: [query: TemplateStringsArray | Sql, ...values: any[]],
|
||||||
|
result: any
|
||||||
|
}
|
||||||
|
$queryRawUnsafe: {
|
||||||
|
args: [query: string, ...values: any[]],
|
||||||
|
result: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enums
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const TransactionIsolationLevel = runtime.makeStrictEnum({
|
||||||
|
ReadUncommitted: 'ReadUncommitted',
|
||||||
|
ReadCommitted: 'ReadCommitted',
|
||||||
|
RepeatableRead: 'RepeatableRead',
|
||||||
|
Serializable: 'Serializable'
|
||||||
|
} as const)
|
||||||
|
|
||||||
|
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
|
||||||
|
|
||||||
|
|
||||||
|
export const SessionScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
sessionKey: 'sessionKey',
|
||||||
|
userId: 'userId',
|
||||||
|
expires: 'expires',
|
||||||
|
refreshTokenGenerated: 'refreshTokenGenerated',
|
||||||
|
refreshedAt: 'refreshedAt',
|
||||||
|
invalidatedAt: 'invalidatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type SessionScalarFieldEnum = (typeof SessionScalarFieldEnum)[keyof typeof SessionScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const UserScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
permissions: 'permissions',
|
||||||
|
login: 'login',
|
||||||
|
name: 'name',
|
||||||
|
email: 'email',
|
||||||
|
emailVerified: 'emailVerified',
|
||||||
|
image: 'image',
|
||||||
|
userId: 'userId',
|
||||||
|
token: 'token',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const RoleScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
title: 'title',
|
||||||
|
moniker: 'moniker',
|
||||||
|
permissions: 'permissions',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RoleScalarFieldEnum = (typeof RoleScalarFieldEnum)[keyof typeof RoleScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const SortOrder = {
|
||||||
|
asc: 'asc',
|
||||||
|
desc: 'desc'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||||
|
|
||||||
|
|
||||||
|
export const QueryMode = {
|
||||||
|
default: 'default',
|
||||||
|
insensitive: 'insensitive'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
|
||||||
|
|
||||||
|
|
||||||
|
export const NullsOrder = {
|
||||||
|
first: 'first',
|
||||||
|
last: 'last'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field references
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'String'
|
||||||
|
*/
|
||||||
|
export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'String[]'
|
||||||
|
*/
|
||||||
|
export type ListStringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'DateTime'
|
||||||
|
*/
|
||||||
|
export type DateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'DateTime[]'
|
||||||
|
*/
|
||||||
|
export type ListDateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'Boolean'
|
||||||
|
*/
|
||||||
|
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'Int'
|
||||||
|
*/
|
||||||
|
export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'Int[]'
|
||||||
|
*/
|
||||||
|
export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'Float'
|
||||||
|
*/
|
||||||
|
export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'Float[]'
|
||||||
|
*/
|
||||||
|
export type ListFloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float[]'>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch Payload for updateMany & deleteMany & createMany
|
||||||
|
*/
|
||||||
|
export type BatchPayload = {
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defineExtension = runtime.Extensions.defineExtension as unknown as runtime.Types.Extensions.ExtendsHook<"define", TypeMapCb, runtime.Types.Extensions.DefaultArgs>
|
||||||
|
export type DefaultPrismaClient = PrismaClient
|
||||||
|
export type ErrorFormat = 'pretty' | 'colorless' | 'minimal'
|
||||||
|
export type PrismaClientOptions = ({
|
||||||
|
/**
|
||||||
|
* Instance of a Driver Adapter, e.g., like one provided by `@prisma/adapter-pg`.
|
||||||
|
*/
|
||||||
|
adapter: runtime.SqlDriverAdapterFactory
|
||||||
|
accelerateUrl?: never
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* Prisma Accelerate URL allowing the client to connect through Accelerate instead of a direct database.
|
||||||
|
*/
|
||||||
|
accelerateUrl: string
|
||||||
|
adapter?: never
|
||||||
|
}) & {
|
||||||
|
/**
|
||||||
|
* @default "colorless"
|
||||||
|
*/
|
||||||
|
errorFormat?: ErrorFormat
|
||||||
|
/**
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* // Shorthand for `emit: 'stdout'`
|
||||||
|
* log: ['query', 'info', 'warn', 'error']
|
||||||
|
*
|
||||||
|
* // Emit as events only
|
||||||
|
* log: [
|
||||||
|
* { emit: 'event', level: 'query' },
|
||||||
|
* { emit: 'event', level: 'info' },
|
||||||
|
* { emit: 'event', level: 'warn' }
|
||||||
|
* { emit: 'event', level: 'error' }
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* / Emit as events and log to stdout
|
||||||
|
* og: [
|
||||||
|
* { emit: 'stdout', level: 'query' },
|
||||||
|
* { emit: 'stdout', level: 'info' },
|
||||||
|
* { emit: 'stdout', level: 'warn' }
|
||||||
|
* { emit: 'stdout', level: 'error' }
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* Read more in our [docs](https://pris.ly/d/logging).
|
||||||
|
*/
|
||||||
|
log?: (LogLevel | LogDefinition)[]
|
||||||
|
/**
|
||||||
|
* The default values for transactionOptions
|
||||||
|
* maxWait ?= 2000
|
||||||
|
* timeout ?= 5000
|
||||||
|
*/
|
||||||
|
transactionOptions?: {
|
||||||
|
maxWait?: number
|
||||||
|
timeout?: number
|
||||||
|
isolationLevel?: TransactionIsolationLevel
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Global configuration for omitting model fields by default.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient({
|
||||||
|
* omit: {
|
||||||
|
* user: {
|
||||||
|
* password: true
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
omit?: GlobalOmitConfig
|
||||||
|
/**
|
||||||
|
* SQL commenter plugins that add metadata to SQL queries as comments.
|
||||||
|
* Comments follow the sqlcommenter format: https://google.github.io/sqlcommenter/
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient({
|
||||||
|
* adapter,
|
||||||
|
* comments: [
|
||||||
|
* traceContext(),
|
||||||
|
* queryInsights(),
|
||||||
|
* ],
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
comments?: runtime.SqlCommenterPlugin[]
|
||||||
|
}
|
||||||
|
export type GlobalOmitConfig = {
|
||||||
|
session?: Prisma.SessionOmit
|
||||||
|
user?: Prisma.UserOmit
|
||||||
|
role?: Prisma.RoleOmit
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Types for Logging */
|
||||||
|
export type LogLevel = 'info' | 'query' | 'warn' | 'error'
|
||||||
|
export type LogDefinition = {
|
||||||
|
level: LogLevel
|
||||||
|
emit: 'stdout' | 'event'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CheckIsLogLevel<T> = T extends LogLevel ? T : never;
|
||||||
|
|
||||||
|
export type GetLogType<T> = CheckIsLogLevel<
|
||||||
|
T extends LogDefinition ? T['level'] : T
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type GetEvents<T extends any[]> = T extends Array<LogLevel | LogDefinition>
|
||||||
|
? GetLogType<T[number]>
|
||||||
|
: never;
|
||||||
|
|
||||||
|
export type QueryEvent = {
|
||||||
|
timestamp: Date
|
||||||
|
query: string
|
||||||
|
params: string
|
||||||
|
duration: number
|
||||||
|
target: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LogEvent = {
|
||||||
|
timestamp: Date
|
||||||
|
message: string
|
||||||
|
target: string
|
||||||
|
}
|
||||||
|
/* End Types for Logging */
|
||||||
|
|
||||||
|
|
||||||
|
export type PrismaAction =
|
||||||
|
| 'findUnique'
|
||||||
|
| 'findUniqueOrThrow'
|
||||||
|
| 'findMany'
|
||||||
|
| 'findFirst'
|
||||||
|
| 'findFirstOrThrow'
|
||||||
|
| 'create'
|
||||||
|
| 'createMany'
|
||||||
|
| 'createManyAndReturn'
|
||||||
|
| 'update'
|
||||||
|
| 'updateMany'
|
||||||
|
| 'updateManyAndReturn'
|
||||||
|
| 'upsert'
|
||||||
|
| 'delete'
|
||||||
|
| 'deleteMany'
|
||||||
|
| 'executeRaw'
|
||||||
|
| 'queryRaw'
|
||||||
|
| 'aggregate'
|
||||||
|
| 'count'
|
||||||
|
| 'runCommandRaw'
|
||||||
|
| 'findRaw'
|
||||||
|
| 'groupBy'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `PrismaClient` proxy available in interactive transactions.
|
||||||
|
*/
|
||||||
|
export type TransactionClient = Omit<DefaultPrismaClient, runtime.ITXClientDenyList>
|
||||||
|
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* WARNING: This is an internal file that is subject to change!
|
||||||
|
*
|
||||||
|
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||||
|
*
|
||||||
|
* All exports from this file are wrapped under a `Prisma` namespace object in the browser.ts file.
|
||||||
|
* While this enables partial backward compatibility, it is not part of the stable public API.
|
||||||
|
*
|
||||||
|
* If you are looking for your Models, Enums, and Input Types, please import them from the respective
|
||||||
|
* model files in the `model` directory!
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/index-browser"
|
||||||
|
|
||||||
|
export type * from '../models.ts'
|
||||||
|
export type * from './prismaNamespace.ts'
|
||||||
|
|
||||||
|
export const Decimal = runtime.Decimal
|
||||||
|
|
||||||
|
|
||||||
|
export const NullTypes = {
|
||||||
|
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
|
||||||
|
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
|
||||||
|
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const DbNull = runtime.DbNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const JsonNull = runtime.JsonNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const AnyNull = runtime.AnyNull
|
||||||
|
|
||||||
|
|
||||||
|
export const ModelName = {
|
||||||
|
Session: 'Session',
|
||||||
|
User: 'User',
|
||||||
|
Role: 'Role'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enums
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const TransactionIsolationLevel = runtime.makeStrictEnum({
|
||||||
|
ReadUncommitted: 'ReadUncommitted',
|
||||||
|
ReadCommitted: 'ReadCommitted',
|
||||||
|
RepeatableRead: 'RepeatableRead',
|
||||||
|
Serializable: 'Serializable'
|
||||||
|
} as const)
|
||||||
|
|
||||||
|
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
|
||||||
|
|
||||||
|
|
||||||
|
export const SessionScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
sessionKey: 'sessionKey',
|
||||||
|
userId: 'userId',
|
||||||
|
expires: 'expires',
|
||||||
|
refreshTokenGenerated: 'refreshTokenGenerated',
|
||||||
|
refreshedAt: 'refreshedAt',
|
||||||
|
invalidatedAt: 'invalidatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type SessionScalarFieldEnum = (typeof SessionScalarFieldEnum)[keyof typeof SessionScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const UserScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
permissions: 'permissions',
|
||||||
|
login: 'login',
|
||||||
|
name: 'name',
|
||||||
|
email: 'email',
|
||||||
|
emailVerified: 'emailVerified',
|
||||||
|
image: 'image',
|
||||||
|
userId: 'userId',
|
||||||
|
token: 'token',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const RoleScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
title: 'title',
|
||||||
|
moniker: 'moniker',
|
||||||
|
permissions: 'permissions',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RoleScalarFieldEnum = (typeof RoleScalarFieldEnum)[keyof typeof RoleScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const SortOrder = {
|
||||||
|
asc: 'asc',
|
||||||
|
desc: 'desc'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||||
|
|
||||||
|
|
||||||
|
export const QueryMode = {
|
||||||
|
default: 'default',
|
||||||
|
insensitive: 'insensitive'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
|
||||||
|
|
||||||
|
|
||||||
|
export const NullsOrder = {
|
||||||
|
first: 'first',
|
||||||
|
last: 'last'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This is a barrel export file for all models and their related types.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
export type * from './models/Session.ts'
|
||||||
|
export type * from './models/User.ts'
|
||||||
|
export type * from './models/Role.ts'
|
||||||
|
export type * from './commonInputTypes.ts'
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+28
-1
@@ -1,12 +1,39 @@
|
|||||||
{
|
{
|
||||||
"name": "ttscm-api",
|
"name": "ttscm-api",
|
||||||
|
"homepage": "https://totaltech.net",
|
||||||
|
"author": {
|
||||||
|
"name": "Jackson Roberts",
|
||||||
|
"email": "jackson.roberts@totaltech.net",
|
||||||
|
"url": "https://totaltech.net"
|
||||||
|
},
|
||||||
"module": "src/index.ts",
|
"module": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest"
|
"@types/bun": "latest",
|
||||||
|
"@types/jsonwebtoken": "^9.0.10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "NODE_ENV=development bun --watch src/index.ts",
|
||||||
|
"db:gen": "prisma generate",
|
||||||
|
"db:push": "prisma migrate dev --skip-generate",
|
||||||
|
"utils:dev": "docker compose -f .docker/docker-compose.yml up --build",
|
||||||
|
"utils:gen_private_keys": "bun ./utils/genPrivateKeys"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/collection": "^2.1.1",
|
||||||
|
"@duxcore/eventra": "^1.1.0",
|
||||||
|
"@prisma/adapter-pg": "^7.3.0",
|
||||||
|
"cors": "^2.8.6",
|
||||||
|
"cuid": "^3.0.0",
|
||||||
|
"hono": "^4.11.5",
|
||||||
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"keypair": "^1.0.4",
|
||||||
|
"prisma": "^7.3.0",
|
||||||
|
"zod": "^4.3.6",
|
||||||
|
"zon": "^1.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import 'dotenv/config'
|
||||||
|
import { defineConfig, env } from 'prisma/config'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
schema: 'prisma/schema.prisma',
|
||||||
|
migrations: {
|
||||||
|
path: 'prisma/migrations',
|
||||||
|
},
|
||||||
|
datasource: {
|
||||||
|
url: env('DATABASE_URL'),
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// This is your Prisma schema file,
|
||||||
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||||
|
|
||||||
|
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||||
|
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client"
|
||||||
|
output = "../generated/prisma"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
sessionKey String @unique @default(cuid())
|
||||||
|
userId String
|
||||||
|
expires DateTime
|
||||||
|
refreshTokenGenerated Boolean @default(false)
|
||||||
|
refreshedAt DateTime?
|
||||||
|
invalidatedAt DateTime?
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
roles Role[]
|
||||||
|
permissions String?
|
||||||
|
login String @unique
|
||||||
|
name String?
|
||||||
|
email String @unique
|
||||||
|
emailVerified DateTime?
|
||||||
|
image String?
|
||||||
|
|
||||||
|
userId Int @unique
|
||||||
|
token String?
|
||||||
|
|
||||||
|
sessions Session[]
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
model Role {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
title String
|
||||||
|
moniker String @unique // e.g. admin, super_admin, moderator
|
||||||
|
|
||||||
|
permissions String
|
||||||
|
users User[]
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class AuthenticationError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "AuthenticationError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export default class AuthorizationError extends Error {
|
||||||
|
public status: number;
|
||||||
|
|
||||||
|
constructor(message: string, cause?: string, status?: number) {
|
||||||
|
super();
|
||||||
|
this.name = "AuthorizationError";
|
||||||
|
this.status = status ?? 401;
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class BodyError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "BodyError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class ExpiredAccessTokenError extends Error {
|
||||||
|
constructor(cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "ExpiredAccessTokenError";
|
||||||
|
this.message = "The provided access token has expired.";
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class ExpiredRefreshTokenError extends Error {
|
||||||
|
constructor(cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "ExpiredRefreshTokenError";
|
||||||
|
this.message = "The provided refresh token has expired.";
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
export default class GenericError extends Error {
|
||||||
|
public status: number;
|
||||||
|
|
||||||
|
constructor(info: {
|
||||||
|
name: string;
|
||||||
|
message: string;
|
||||||
|
cause?: string;
|
||||||
|
status?: number;
|
||||||
|
}) {
|
||||||
|
super();
|
||||||
|
this.name = info.name;
|
||||||
|
this.status = info.status ?? 400;
|
||||||
|
this.message = info.message;
|
||||||
|
this.cause = info.cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export default class InsufficientPermission extends Error {
|
||||||
|
public status: number;
|
||||||
|
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "InsufficientPermission";
|
||||||
|
this.status = 403;
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export default class MissingBodyValue extends Error {
|
||||||
|
constructor(valueName: string) {
|
||||||
|
super();
|
||||||
|
this.name = "MissingBodyValue";
|
||||||
|
this.message = `Value '${valueName}' is missing from the body.`;
|
||||||
|
this.cause =
|
||||||
|
"A value that was required by the body of this request is missing.";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class PermissionsVerificationError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "PermissionsVerificationError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class RoleError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "RoleError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class SessionError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "SessionError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class SessionTokenError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "SessionTokenError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default class UserError extends Error {
|
||||||
|
constructor(message: string, cause?: string) {
|
||||||
|
super();
|
||||||
|
this.name = "UserError";
|
||||||
|
this.message = message;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
# Keep environment variables out of version control
|
||||||
|
.env
|
||||||
|
|
||||||
|
/generated/prisma
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// This file was generated by Prisma, and assumes you run Prisma commands using `bun --bun run prisma [command]`.
|
||||||
|
import { defineConfig, env } from "prisma/config";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
schema: "prisma/schema.prisma",
|
||||||
|
migrations: {
|
||||||
|
path: "prisma/migrations",
|
||||||
|
},
|
||||||
|
datasource: {
|
||||||
|
url: env("DATABASE_URL"),
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Hono } from "hono";
|
||||||
|
import { apiResponse } from "../modules/api-utils/apiResponse";
|
||||||
|
import { ZodError } from "zod";
|
||||||
|
import { cors } from "hono/cors";
|
||||||
|
import GenericError from "../Errors/GenericError";
|
||||||
|
import teapot from "./teapot";
|
||||||
|
|
||||||
|
const app = new Hono();
|
||||||
|
const v1 = new Hono();
|
||||||
|
|
||||||
|
app.onError((err, ctx) => {
|
||||||
|
const errClassName = err.constructor.name;
|
||||||
|
|
||||||
|
if (
|
||||||
|
errClassName.toLowerCase().includes("prisma") ||
|
||||||
|
err.message.toLowerCase().includes("prisma") ||
|
||||||
|
err.name.toLowerCase().includes("prisma")
|
||||||
|
) {
|
||||||
|
console.trace(err);
|
||||||
|
return ctx.json(apiResponse.internalError(), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err instanceof ZodError) {
|
||||||
|
return ctx.json(
|
||||||
|
apiResponse.zodError(err),
|
||||||
|
//@ts-ignore
|
||||||
|
apiResponse.zodError(err).status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = apiResponse.error(err);
|
||||||
|
return ctx.json(response, response.status);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use("*", cors());
|
||||||
|
|
||||||
|
app.notFound((c) => {
|
||||||
|
const response = apiResponse.error(
|
||||||
|
new GenericError({
|
||||||
|
name: "NotFound",
|
||||||
|
message: `Cannot ${c.req.method.toUpperCase()} ${c.req.path}`,
|
||||||
|
status: 404,
|
||||||
|
cause: "Unknown",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return c.json(response, response.status);
|
||||||
|
});
|
||||||
|
|
||||||
|
v1.route("/teapot", teapot);
|
||||||
|
|
||||||
|
app.route("/v1", v1);
|
||||||
|
|
||||||
|
export default app;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Hono } from "hono/tiny";
|
||||||
|
import { createRoute } from "../modules/api-utils/createRoute";
|
||||||
|
|
||||||
|
/* /v1/teapot */
|
||||||
|
export default createRoute("get", ["/"], (c) => {
|
||||||
|
c.status(418);
|
||||||
|
return c.json({
|
||||||
|
status: 418,
|
||||||
|
message: "I'm not a teapot",
|
||||||
|
successful: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { PrismaPg } from '@prisma/adapter-pg'
|
||||||
|
import { PrismaClient } from '../generated/prisma/client'
|
||||||
|
|
||||||
|
const connectionString = `${process.env.DATABASE_URL}`
|
||||||
|
const adapter = new PrismaPg({ connectionString })
|
||||||
|
|
||||||
|
|
||||||
|
interface EnvKey {
|
||||||
|
PORT: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ENV CONSTANTS
|
||||||
|
|
||||||
|
export const PORT = process.env.PORT;
|
||||||
|
|
||||||
|
export const prisma = new PrismaClient({ adapter })
|
||||||
|
|
||||||
|
export const sessionDuration = 30 * 24 * 60 * 60000;
|
||||||
|
export const accessTokenDuration = "10min";
|
||||||
|
export const refreshTokenDuration = "30d";
|
||||||
|
|
||||||
|
export const accessTokenPrivateKey = readFileSync(
|
||||||
|
`${import.meta.dir}/../.accessToken.key`
|
||||||
|
).toString();
|
||||||
|
export const refreshTokenPrivateKey = readFileSync(
|
||||||
|
`${import.meta.dir}/../.refreshToken.key`
|
||||||
|
).toString();
|
||||||
|
export const permissionsPrivateKey = readFileSync(
|
||||||
|
`${import.meta.dir}/../.permissions.key`
|
||||||
|
);
|
||||||
|
export const apiKeyTokenPrivateKey = readFileSync(
|
||||||
|
`${import.meta.dir}/../.apiKeyToken.key`
|
||||||
|
);
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
import UserController from "./UserController";
|
||||||
|
import { Collection } from "@discordjs/collection";
|
||||||
|
import jwt, { JsonWebTokenError } from "jsonwebtoken";
|
||||||
|
import { permissionsPrivateKey, prisma } from "../constants";
|
||||||
|
import PermissionsVerificationError from "../Errors/PermissionsVerificationError";
|
||||||
|
import { mergeArrays } from "../modules/tools/mergeArrays";
|
||||||
|
import { signPermissions } from "../modules/permission-utils/signPermissions";
|
||||||
|
import { DecodedPermissionsBlock } from "../types/PermissionTypes";
|
||||||
|
import { permissionValidator } from "../modules/permission-utils/permissionValidator";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { roles } from "../managers/roles";
|
||||||
|
import GenericError from "../Errors/GenericError";
|
||||||
|
import RoleError from "../Errors/RoleError";
|
||||||
|
import { Role, User } from "../../generated/prisma/client";
|
||||||
|
import { events } from "../modules/globalEvents";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roles
|
||||||
|
*
|
||||||
|
* Roles are for adding onto a users permissions. They are not for defining a default users permissions.
|
||||||
|
*
|
||||||
|
* Roles have two forms of identifiers, titles and monikers. The title is something that can be capitalized and publicly displayed,
|
||||||
|
* so if you make modifications, and you need to be able to see how they were able to do that without having explicit permission to
|
||||||
|
* make the modifications, the title is what would be shown to you. The moniker is the human readable identifier. So in an api
|
||||||
|
* response where you need to get the roles of a user, instead of being given a bunch of id's, you will be given a bunch of monikers
|
||||||
|
* which are easy to read and easy to identify.
|
||||||
|
*/
|
||||||
|
export class RoleController {
|
||||||
|
public readonly id: string;
|
||||||
|
public title: string;
|
||||||
|
public moniker: string; // e.g. admin, super_admin, moderator
|
||||||
|
|
||||||
|
private _permissionsToken: string;
|
||||||
|
private _users: (User & { roles: Role[] })[];
|
||||||
|
|
||||||
|
public readonly createdAt: Date;
|
||||||
|
public updatedAt: Date;
|
||||||
|
|
||||||
|
public deleted: boolean = false;
|
||||||
|
|
||||||
|
constructor(roledata: Role & { users: (User & { roles: Role[] })[] }) {
|
||||||
|
this.id = roledata.id;
|
||||||
|
this.title = roledata.title;
|
||||||
|
this.moniker = roledata.moniker;
|
||||||
|
|
||||||
|
this._permissionsToken = roledata.permissions;
|
||||||
|
this._users = roledata.users;
|
||||||
|
|
||||||
|
this.createdAt = roledata.createdAt;
|
||||||
|
this.updatedAt = roledata.updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _signPermissions = signPermissions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Permissions
|
||||||
|
*
|
||||||
|
* This method is vital to maintining the security of this system. This method is here to ensure
|
||||||
|
* that the permissions object is authentic and signed by our system.
|
||||||
|
*
|
||||||
|
* @param permissionsToken - Signed permissions JWT
|
||||||
|
* @returns - Verified object with permissions in it.
|
||||||
|
*/
|
||||||
|
private _verifyPermissions(permissionsToken: string) {
|
||||||
|
let perms: DecodedPermissionsBlock;
|
||||||
|
try {
|
||||||
|
perms = jwt.verify(permissionsToken, permissionsPrivateKey, {
|
||||||
|
algorithms: ["RS256"],
|
||||||
|
issuer: "roles",
|
||||||
|
subject: this.id,
|
||||||
|
}) as DecodedPermissionsBlock;
|
||||||
|
} catch (err) {
|
||||||
|
events.emit("role:permissions:verification_error", {
|
||||||
|
currentSigned: this._permissionsToken,
|
||||||
|
attemptedVerification: permissionsToken,
|
||||||
|
err: err as Error,
|
||||||
|
role: this,
|
||||||
|
});
|
||||||
|
throw new PermissionsVerificationError(
|
||||||
|
`Unable to verify permissions for role '${this.title}, it is recommended that you override and rewrite these permissions immediately.`,
|
||||||
|
(err as Error).message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return perms as { permissions: string[] };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Users
|
||||||
|
*
|
||||||
|
* This will get all the users that have this role and return it as a collection dictionary where the key is
|
||||||
|
* the `id` of the user and the value is the users `UserController`.
|
||||||
|
*
|
||||||
|
* @returns {Collection<string, UserController>} - A collection of all the users that are assigned to this role
|
||||||
|
*/
|
||||||
|
public getUsers() {
|
||||||
|
const collection = new Collection<string, UserController>();
|
||||||
|
this._users.map((v) => collection.set(v.id, new UserController(v)));
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check Permission
|
||||||
|
*
|
||||||
|
* Check to see if a role has a specified set of permissions.
|
||||||
|
*
|
||||||
|
* @param permission - The permission to check for
|
||||||
|
* @returns {boolean} Does this role have the specified permission
|
||||||
|
*/
|
||||||
|
public checkPermission(permission: string): boolean {
|
||||||
|
const permissions = this._verifyPermissions(this._permissionsToken);
|
||||||
|
return permissionValidator(permission, permissions.permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set permissions
|
||||||
|
*
|
||||||
|
* This will remove all existing permissions and replate them with the permissions defined in the params
|
||||||
|
* of this method.
|
||||||
|
*
|
||||||
|
* @param permissions - Array of all Permissions
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
public async setPermissions(...permissions: string[]) {
|
||||||
|
/*
|
||||||
|
Make sure the current permissions are verified before updating them again. Basically speaking if the permissions
|
||||||
|
are tampered with in any way, this bricks the further modification of the permissions
|
||||||
|
*/
|
||||||
|
const previous = this._verifyPermissions(this._permissionsToken);
|
||||||
|
|
||||||
|
const newPermissionsToken = this._signPermissions({
|
||||||
|
issuer: "roles",
|
||||||
|
subject: this.id,
|
||||||
|
permissions,
|
||||||
|
});
|
||||||
|
const newRaw = await prisma.role.update({
|
||||||
|
where: { id: this.id },
|
||||||
|
data: { permissions: newPermissionsToken },
|
||||||
|
});
|
||||||
|
|
||||||
|
events.emit("role:permissions:updated", {
|
||||||
|
current: permissions,
|
||||||
|
currentSigned: newPermissionsToken,
|
||||||
|
previous: previous.permissions,
|
||||||
|
previousSigned: this._permissionsToken,
|
||||||
|
action: "set",
|
||||||
|
role: this,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._permissionsToken = newPermissionsToken;
|
||||||
|
this.updatedAt = newRaw.updatedAt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Permissions
|
||||||
|
*
|
||||||
|
* This will take the permissions provided in the params of the method and combine them into the pre-existing
|
||||||
|
* permissions of this role.
|
||||||
|
*
|
||||||
|
* @param permissions - Array of added Permissions
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
public async addPermissions(...permissions: string[]) {
|
||||||
|
/*
|
||||||
|
Make sure the current permissions are verified before updating them again. Basically speaking if the permissions
|
||||||
|
are tampered with in any way, this bricks the further modification of the permissions
|
||||||
|
*/
|
||||||
|
const previous = this._verifyPermissions(this._permissionsToken);
|
||||||
|
|
||||||
|
const newPermissionsToken = this._signPermissions({
|
||||||
|
issuer: "roles",
|
||||||
|
subject: this.id,
|
||||||
|
permissions: mergeArrays(previous.permissions, permissions),
|
||||||
|
});
|
||||||
|
const newRaw = await prisma.role.update({
|
||||||
|
where: { id: this.id },
|
||||||
|
data: { permissions: newPermissionsToken },
|
||||||
|
});
|
||||||
|
|
||||||
|
events.emit("role:permissions:updated", {
|
||||||
|
current: permissions,
|
||||||
|
currentSigned: newPermissionsToken,
|
||||||
|
previous: previous.permissions,
|
||||||
|
previousSigned: this._permissionsToken,
|
||||||
|
action: "added",
|
||||||
|
role: this,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._permissionsToken = newPermissionsToken;
|
||||||
|
this.updatedAt = newRaw.updatedAt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove Permissions
|
||||||
|
*
|
||||||
|
* This will take the permissions provided in the params of the method and remove them from the exisitng
|
||||||
|
* permissions object for this role.
|
||||||
|
*
|
||||||
|
* @param permissions - Array of removed Permissions
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
public async removePermissions(...permissions: string[]) {
|
||||||
|
/*
|
||||||
|
Make sure the current permissions are verified before updating them again. Basically speaking if the permissions
|
||||||
|
are tampered with in any way, this bricks the further modification of the permissions
|
||||||
|
*/
|
||||||
|
const previous = this._verifyPermissions(this._permissionsToken);
|
||||||
|
|
||||||
|
const newPermissionsToken = this._signPermissions({
|
||||||
|
issuer: "roles",
|
||||||
|
subject: this.id,
|
||||||
|
permissions: previous.permissions.filter((v) => !permissions.includes(v)),
|
||||||
|
});
|
||||||
|
const newRaw = await prisma.role.update({
|
||||||
|
where: { id: this.id },
|
||||||
|
data: { permissions: newPermissionsToken },
|
||||||
|
});
|
||||||
|
|
||||||
|
events.emit("role:permissions:updated", {
|
||||||
|
current: permissions,
|
||||||
|
currentSigned: newPermissionsToken,
|
||||||
|
previous: previous.permissions,
|
||||||
|
previousSigned: this._permissionsToken,
|
||||||
|
action: "removed",
|
||||||
|
role: this,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._permissionsToken = newPermissionsToken;
|
||||||
|
this.updatedAt = newRaw.updatedAt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Current Permissions
|
||||||
|
*
|
||||||
|
* Get all of the permissions for this role.
|
||||||
|
* @returns {string[]} - Existing permissions in an array
|
||||||
|
*/
|
||||||
|
public getPermissions() {
|
||||||
|
const permissions = this._verifyPermissions(this._permissionsToken!);
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update(
|
||||||
|
data: Partial<{
|
||||||
|
title: string;
|
||||||
|
moniker: string;
|
||||||
|
permissions: string[];
|
||||||
|
}>
|
||||||
|
) {
|
||||||
|
const schema = z
|
||||||
|
.object({
|
||||||
|
title: z.string().min(1, "Title cannot be empty."),
|
||||||
|
moniker: z.string().min(1, "Moniker cannot be empty."),
|
||||||
|
permissions: z.array(
|
||||||
|
z.string().min(1, "Permission node cannot be empty")
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.partial()
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
data = schema.parse(data);
|
||||||
|
|
||||||
|
if (data.moniker) {
|
||||||
|
const checkMoniker = await prisma.role.findFirst({
|
||||||
|
where: { moniker: data.moniker },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (checkMoniker)
|
||||||
|
throw new RoleError(
|
||||||
|
"Moniker is already taken.",
|
||||||
|
"Another role with this moniker already exists in the databse."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedRole = await prisma.role.update({
|
||||||
|
where: { id: this.id },
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
permissions: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.permissions) await this.setPermissions(...data.permissions);
|
||||||
|
|
||||||
|
events.emit("role:updated", { role: this, updateData: data });
|
||||||
|
this.title = data.title ?? this.title;
|
||||||
|
this.moniker = data.moniker ?? this.moniker;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Role
|
||||||
|
*
|
||||||
|
* @returns {Promise<RoleController>} The Remains of a deleted role.
|
||||||
|
*/
|
||||||
|
public async delete() {
|
||||||
|
const deletedData = await prisma.role.delete({ where: { id: this.id } });
|
||||||
|
|
||||||
|
this.deleted = true;
|
||||||
|
events.emit("role:deleted", this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To JSON
|
||||||
|
*
|
||||||
|
* Create a JSON object that can be used in things like API responses.
|
||||||
|
*
|
||||||
|
* @param opts - Optional values to include in the response.
|
||||||
|
* @returns - JSON-Friendly object.
|
||||||
|
*/
|
||||||
|
public toJson(opts?: { viewUsers?: boolean; viewPermissions?: boolean }) {
|
||||||
|
let object = {
|
||||||
|
id: this.id,
|
||||||
|
title: this.title,
|
||||||
|
moniker: this.moniker,
|
||||||
|
permissions: opts?.viewPermissions
|
||||||
|
? this._verifyPermissions(this._permissionsToken).permissions
|
||||||
|
: undefined,
|
||||||
|
users: opts?.viewUsers
|
||||||
|
? this._users.map((v) => ({
|
||||||
|
id: v.id,
|
||||||
|
name: v.name,
|
||||||
|
login: v.login,
|
||||||
|
roles: v.roles.map((r:any) => r.id),
|
||||||
|
}))
|
||||||
|
: undefined,
|
||||||
|
createdAt: this.createdAt,
|
||||||
|
updatedAt: this.updatedAt,
|
||||||
|
};
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
import {
|
||||||
|
prisma,
|
||||||
|
refreshTokenDuration,
|
||||||
|
accessTokenDuration,
|
||||||
|
accessTokenPrivateKey,
|
||||||
|
refreshTokenPrivateKey,
|
||||||
|
} from "../constants";
|
||||||
|
import SessionTokenError from "../Errors/SessionTokenError";
|
||||||
|
import { events } from "../modules/globalEvents";
|
||||||
|
import UserController from "./UserController";
|
||||||
|
import { users } from "../managers/users";
|
||||||
|
import { Session } from "../../generated/prisma/client";
|
||||||
|
|
||||||
|
export interface SessionPayloadObject {
|
||||||
|
userID: string;
|
||||||
|
sessionKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionTokensObject {
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DecodedSession = SessionPayloadObject & {
|
||||||
|
iat: number;
|
||||||
|
exp: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session Controller
|
||||||
|
*
|
||||||
|
* This class is for create a controller that can manage, generate and refresh tokens, self terminate and self delete
|
||||||
|
* all sessions. This also allows you to access all data about a session.
|
||||||
|
*/
|
||||||
|
export class SessionController {
|
||||||
|
public readonly id: string;
|
||||||
|
public readonly sessionKey: string;
|
||||||
|
public readonly userId: string;
|
||||||
|
public readonly expires: Date;
|
||||||
|
public refreshedAt: Date | null;
|
||||||
|
public invalidatedAt: Date | null;
|
||||||
|
|
||||||
|
public terminated: boolean = false;
|
||||||
|
|
||||||
|
private _refreshTokenGenrated: boolean;
|
||||||
|
|
||||||
|
constructor(sessionData: Session) {
|
||||||
|
this.id = sessionData.id;
|
||||||
|
this.sessionKey = sessionData.sessionKey;
|
||||||
|
this.userId = sessionData.userId;
|
||||||
|
this.expires = sessionData.expires;
|
||||||
|
this.refreshedAt = sessionData.refreshedAt;
|
||||||
|
this.invalidatedAt = sessionData.invalidatedAt;
|
||||||
|
|
||||||
|
this._refreshTokenGenrated = sessionData.refreshTokenGenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
private _generateAccessToken() {
|
||||||
|
const payload: SessionPayloadObject = {
|
||||||
|
sessionKey: this.sessionKey,
|
||||||
|
userID: this.userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return jwt.sign(payload, accessTokenPrivateKey, {
|
||||||
|
algorithm: "RS256",
|
||||||
|
expiresIn: accessTokenDuration,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
private _generateRefreshToken() {
|
||||||
|
const payload: SessionPayloadObject = {
|
||||||
|
sessionKey: this.sessionKey,
|
||||||
|
userID: this.userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return jwt.sign(payload, refreshTokenPrivateKey, {
|
||||||
|
algorithm: "RS256",
|
||||||
|
expiresIn: refreshTokenDuration,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate the Session
|
||||||
|
*
|
||||||
|
* The purpose for this function is if you wanted to be able to listen for somebody using an invalid session,
|
||||||
|
* you just have to invalidate it with this function and go from there.
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>} - nothing
|
||||||
|
*/
|
||||||
|
public async invalidate() {
|
||||||
|
const invalidationDate = new Date();
|
||||||
|
|
||||||
|
if (this.invalidatedAt)
|
||||||
|
throw new Error("Session has already been invalidated.");
|
||||||
|
|
||||||
|
await prisma.session.update({
|
||||||
|
data: { invalidatedAt: invalidationDate },
|
||||||
|
where: { id: this.id },
|
||||||
|
});
|
||||||
|
this.invalidatedAt = invalidationDate;
|
||||||
|
|
||||||
|
events.emit("session:invalidated", this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminate the session
|
||||||
|
*
|
||||||
|
* Terminating the session will immediately delete the session making it impossible for it to be referenced again.
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>} - nothing
|
||||||
|
*/
|
||||||
|
public async terminate() {
|
||||||
|
await prisma.session.delete({ where: { id: this.id } });
|
||||||
|
events.emit("session:terminated", this);
|
||||||
|
this.terminated = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Tokens
|
||||||
|
*
|
||||||
|
* **NOTE**: This method can only be ran once per session.
|
||||||
|
*
|
||||||
|
* Running this function will allow you to generate an accessToken and a refreshToken. Each token
|
||||||
|
* will be generated with their own respective private keys.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns {Promise<SessionTokensObject>} An object containing the `accessToken` and `refreshToken`
|
||||||
|
*/
|
||||||
|
public async generateTokens(): Promise<SessionTokensObject> {
|
||||||
|
if (this._refreshTokenGenrated)
|
||||||
|
throw new Error("Tokens have alredy been generated for this session.");
|
||||||
|
|
||||||
|
const accessToken = this._generateAccessToken();
|
||||||
|
const refreshToken = this._generateRefreshToken();
|
||||||
|
|
||||||
|
const newRefreshDate = new Date();
|
||||||
|
await prisma.session.update({
|
||||||
|
data: { refreshTokenGenerated: true, refreshedAt: newRefreshDate },
|
||||||
|
where: { id: this.id },
|
||||||
|
});
|
||||||
|
this._refreshTokenGenrated = true;
|
||||||
|
this.refreshedAt = newRefreshDate;
|
||||||
|
|
||||||
|
let tokens = { accessToken, refreshToken };
|
||||||
|
|
||||||
|
events.emit("session:tokens_generated", { session: this, tokens });
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the session
|
||||||
|
*
|
||||||
|
* Refreshing the session will generate a new accessToken for the user to authenticate their requests with.
|
||||||
|
*
|
||||||
|
* **NOTE**: Best practice when implementing token refreshing into the UI is that if for any reason this method
|
||||||
|
* throws an error, imediately purge the existing tokens and have the user login again. This way you don't hold
|
||||||
|
* them up any longer than necessary.
|
||||||
|
*
|
||||||
|
* @param refreshToken - The refresh token provided at session generation
|
||||||
|
* @returns {Promise<string>} The new access token.
|
||||||
|
*/
|
||||||
|
public refresh(refreshToken: string): Promise<string> {
|
||||||
|
return new Promise(async (res, rej) => {
|
||||||
|
if (this.expires.getTime() <= Date.now()) {
|
||||||
|
await this.terminate();
|
||||||
|
throw new SessionTokenError("Session has Expired.");
|
||||||
|
}
|
||||||
|
jwt.verify(
|
||||||
|
refreshToken,
|
||||||
|
refreshTokenPrivateKey,
|
||||||
|
{
|
||||||
|
algorithms: ["RS256"],
|
||||||
|
},
|
||||||
|
async (err, decode) => {
|
||||||
|
if (err) {
|
||||||
|
if (
|
||||||
|
err.name == "TokenExpiredError" ||
|
||||||
|
err.message == "invalid signature"
|
||||||
|
)
|
||||||
|
this.terminate();
|
||||||
|
rej(err);
|
||||||
|
}
|
||||||
|
const data: DecodedSession = decode as DecodedSession;
|
||||||
|
|
||||||
|
if (
|
||||||
|
data.sessionKey !== this.sessionKey ||
|
||||||
|
data.userID !== this.userId
|
||||||
|
)
|
||||||
|
rej(
|
||||||
|
new SessionTokenError(
|
||||||
|
"Refresh token does not match this session."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await prisma.session.update({
|
||||||
|
data: { refreshedAt: new Date() },
|
||||||
|
where: { id: this.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
const newToken = this._generateAccessToken();
|
||||||
|
events.emit("session:token_refresh", {
|
||||||
|
session: this,
|
||||||
|
tokens: { accessToken: newToken, refreshToken },
|
||||||
|
});
|
||||||
|
|
||||||
|
return res(newToken);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch Session User
|
||||||
|
*
|
||||||
|
* Fetch the user controller of the user that created the session.
|
||||||
|
*
|
||||||
|
* @returns {Promise<UserController>} The user that created this session.
|
||||||
|
*/
|
||||||
|
public async fetchUser(): Promise<UserController> {
|
||||||
|
return (await users.fetchUser({ id: this.userId }))!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
import { Collection } from "@discordjs/collection";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { Role } from "../../generated/prisma/client";
|
||||||
|
import { User } from "../../generated/prisma/browser";
|
||||||
|
import { SessionTokensObject } from "./SessionController";
|
||||||
|
import { sessions } from "../managers/sessions";
|
||||||
|
import BodyError from "../Errors/BodyError";
|
||||||
|
import { prisma } from "../constants";
|
||||||
|
import { events } from "../modules/globalEvents";
|
||||||
|
import { RoleController } from "./RoleController";
|
||||||
|
import { roles } from "../managers/roles";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class UserController {
|
||||||
|
public id: string;
|
||||||
|
public name: string | null;
|
||||||
|
public login: string;
|
||||||
|
public email: string;
|
||||||
|
public image: string | null;
|
||||||
|
|
||||||
|
private _roles: Collection<string, Role>;
|
||||||
|
|
||||||
|
public createdAt: Date;
|
||||||
|
public updatedAt: Date;
|
||||||
|
constructor(userdata: User & { roles: Role[] }) {
|
||||||
|
this.id = userdata.id;
|
||||||
|
this.name = userdata.name;
|
||||||
|
this.login = userdata.login;
|
||||||
|
this.email = userdata.email;
|
||||||
|
this.image = userdata.image;
|
||||||
|
this.updatedAt = userdata.updatedAt;
|
||||||
|
this.createdAt = userdata.createdAt;
|
||||||
|
|
||||||
|
this._roles = (() => {
|
||||||
|
let collection = new Collection<string, Role>();
|
||||||
|
userdata.roles.map((v: any) => collection.set(v.id, v));
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the internal values
|
||||||
|
*
|
||||||
|
* This is an internal method used to update all the internal values when we query the database. This way
|
||||||
|
* everything stays upto date even when we pass around the user controller.
|
||||||
|
*
|
||||||
|
* @param userdata - User object from Prisma
|
||||||
|
*/
|
||||||
|
private _updateInternalValues(userdata: User) {
|
||||||
|
this.id = userdata.id;
|
||||||
|
this.name = userdata.name;
|
||||||
|
this.login = userdata.login;
|
||||||
|
this.email = userdata.email;
|
||||||
|
this.image = userdata.image;
|
||||||
|
this.updatedAt = userdata.updatedAt;
|
||||||
|
this.createdAt = userdata.createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Session
|
||||||
|
*
|
||||||
|
* This will create a session in the database that is linked to the user and will then create a pair of access and refresh
|
||||||
|
* tokens to provide to the user such that they can authorized their api requests.
|
||||||
|
*
|
||||||
|
* @returns {Promise<SessionTokensObject>} - Object with an access token and a refresh token.
|
||||||
|
*/
|
||||||
|
public async createSession(): Promise<SessionTokensObject> {
|
||||||
|
return sessions.create({ user: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the user
|
||||||
|
*
|
||||||
|
* Take in a partial of the user data and validate it then updated it if it passes validation and return
|
||||||
|
* the updated `UserController` object.
|
||||||
|
*
|
||||||
|
* @param data - A partial of the user data
|
||||||
|
* @returns {Promise<UserController>} - The updated user controller
|
||||||
|
*/
|
||||||
|
public async update(data: Partial<User>) {
|
||||||
|
// Parsed Data With Schema
|
||||||
|
const pData = z
|
||||||
|
.object({
|
||||||
|
name: z.string().optional(),
|
||||||
|
image: z.string().optional(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
|
.parse(data);
|
||||||
|
|
||||||
|
if (Object.keys(data).length == 0)
|
||||||
|
throw new BodyError("Body cannot be empty.");
|
||||||
|
|
||||||
|
const updatedUser = await prisma.user.update({
|
||||||
|
where: { id: this.id },
|
||||||
|
data: pData,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._updateInternalValues(updatedUser);
|
||||||
|
events.emit("user:updated", { user: this, updatedValues: data });
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch Roles
|
||||||
|
*
|
||||||
|
* This method will fetch all of the roles that a user belongs to and will return each of their controllers in a collection
|
||||||
|
* of role id's and RoleControllers.
|
||||||
|
*
|
||||||
|
* @returns {Promise<Collection<string, RoleController>>} A collection of all the roles a user has
|
||||||
|
*/
|
||||||
|
public async fetchRoles(): Promise<Collection<string, RoleController>> {
|
||||||
|
const collection = new Collection<string, RoleController>();
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
this._roles.map(async (v) =>
|
||||||
|
collection.set(v.id, await roles.fetch(v.id))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check Permission
|
||||||
|
*
|
||||||
|
* Check if this user has this specific permission. This method will not only check explicit permissions defined in
|
||||||
|
* the database under users and roles, but will also generate implicit permissions for resources that the user has
|
||||||
|
* access to but doesn't specifically have defined under any given permissions object.
|
||||||
|
*
|
||||||
|
* @param permission - The permission to check for
|
||||||
|
* @returns {boolean} Does this user have the specified permission
|
||||||
|
*/
|
||||||
|
public async hasPermission(permission: string) {
|
||||||
|
let resources = await prisma.user.findFirst({
|
||||||
|
where: { id: this.id },
|
||||||
|
select: {
|
||||||
|
sessions: {
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
apiKeys: {
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
projects: {
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const implicitPermissions = Object.keys(resources ?? {})
|
||||||
|
.filter((v) => resources![v].length > 0)
|
||||||
|
.map(
|
||||||
|
(v) =>
|
||||||
|
`resource.${v}.[${(resources![v] as { id: string }[])
|
||||||
|
.map((o) => o.id)
|
||||||
|
.join(",")}].user.${this.id}.implicit`
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(implicitPermissions);
|
||||||
|
|
||||||
|
let checks = [
|
||||||
|
(await this.fetchRoles()).map((v) => v.checkPermission(permission)),
|
||||||
|
].flatMap((v) => v);
|
||||||
|
|
||||||
|
return checks.includes(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To JSON
|
||||||
|
*
|
||||||
|
* Create an object that can be safely returned to the user of an api request such that when you
|
||||||
|
* need to return data to the end user, you don't accidently return data that could be harmful
|
||||||
|
* if leaked.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
* - Safe return is to return only data that is considered "safe", and not detrimental to pass around
|
||||||
|
*
|
||||||
|
* @param opts - Options to change the output
|
||||||
|
* @returns - An object that is JSON friendly
|
||||||
|
*/
|
||||||
|
public toJson(opts?: { safeReturn: boolean }) {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
roles: opts?.safeReturn
|
||||||
|
? undefined
|
||||||
|
: this._roles.size > 0
|
||||||
|
? this._roles.map((v) => v.moniker)
|
||||||
|
: undefined,
|
||||||
|
login: opts?.safeReturn ? undefined : this.login,
|
||||||
|
email: opts?.safeReturn ? undefined : this.email,
|
||||||
|
image: this.image,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-1
@@ -1 +1,7 @@
|
|||||||
console.log("Hello via Bun!");
|
import app from "./api/server";
|
||||||
|
import { PORT } from "./constants";
|
||||||
|
|
||||||
|
Bun.serve({
|
||||||
|
port: PORT,
|
||||||
|
fetch: app.fetch
|
||||||
|
});
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import { Collection } from "@discordjs/collection";
|
||||||
|
import GenericError from "../Errors/GenericError";
|
||||||
|
import RoleError from "../Errors/RoleError";
|
||||||
|
import { prisma } from "../constants";
|
||||||
|
import { RoleController } from "../controllers/RoleController";
|
||||||
|
import { signPermissions } from "../modules/permission-utils/signPermissions";
|
||||||
|
import cuid from "cuid";
|
||||||
|
import UserController from "../controllers/UserController";
|
||||||
|
import InsufficientPermission from "../Errors/InsufficientPermission";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const roles = {
|
||||||
|
/**
|
||||||
|
* Create a role
|
||||||
|
*
|
||||||
|
* @param data - Data required to make a role
|
||||||
|
* @returns {RoleController} - The new role
|
||||||
|
*/
|
||||||
|
async create(data: {
|
||||||
|
title: string;
|
||||||
|
moniker: string;
|
||||||
|
permissions?: string[];
|
||||||
|
}) {
|
||||||
|
const schema = z.object({
|
||||||
|
title: z.string().min(1, "Title cannot be empty"),
|
||||||
|
moniker: z.string().min(1, "Moniker cannot be empty"),
|
||||||
|
permissions: z
|
||||||
|
.array(z.string().min(1, "Cannot have a blank permission node."))
|
||||||
|
.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
data = await schema.parseAsync(data);
|
||||||
|
|
||||||
|
const checkMoniker = await prisma.role.findFirst({
|
||||||
|
where: { moniker: data.moniker },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (checkMoniker)
|
||||||
|
throw new RoleError(
|
||||||
|
"Moniker is already taken.",
|
||||||
|
"Another role with this moniker already exists in the databse."
|
||||||
|
);
|
||||||
|
|
||||||
|
const id = cuid();
|
||||||
|
const newRole = await prisma.role.create({
|
||||||
|
data: {
|
||||||
|
id,
|
||||||
|
title: data.title,
|
||||||
|
moniker: data.moniker,
|
||||||
|
permissions: signPermissions({
|
||||||
|
issuer: "roles",
|
||||||
|
subject: id,
|
||||||
|
permissions: data.permissions ?? [],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
users: {
|
||||||
|
include: {
|
||||||
|
roles: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const controller = new RoleController(newRole);
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a role
|
||||||
|
*
|
||||||
|
* Fetch a role using either it's id or it's moniker.
|
||||||
|
*
|
||||||
|
* @param identifier - Role `id` or `moniker`
|
||||||
|
* @param identifier - Options for fetching a role.
|
||||||
|
* @returns {RoleController} - Role Controller
|
||||||
|
*/
|
||||||
|
async fetch(identifier:string, opt?: { requestingUser?: UserController }) {
|
||||||
|
const roleData = await prisma.role.findFirst({
|
||||||
|
where: { OR: [{ id: identifier }, { moniker: identifier }] },
|
||||||
|
include: {
|
||||||
|
users: {
|
||||||
|
include: {
|
||||||
|
roles: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!roleData)
|
||||||
|
throw new GenericError({
|
||||||
|
name: "UnknownRole",
|
||||||
|
message: "Unknown role...",
|
||||||
|
status: 404,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
opt?.requestingUser &&
|
||||||
|
!(await opt.requestingUser.hasPermission(
|
||||||
|
this._buildPermissionNode(roleData.id, "read")
|
||||||
|
))
|
||||||
|
)
|
||||||
|
throw new InsufficientPermission(
|
||||||
|
"You do not have permission to access this role."
|
||||||
|
);
|
||||||
|
const controller = new RoleController(roleData);
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all roles
|
||||||
|
*
|
||||||
|
* This will give you all of the roles and their respective controllers
|
||||||
|
*
|
||||||
|
* @param opt - Options for fetching all roles.
|
||||||
|
* @returns {Collection<string, RoleController>} A collection of all the roles and their id's
|
||||||
|
*/
|
||||||
|
async fetchAllRoles(opt?: { requestingUser?: UserController }) {
|
||||||
|
let collection = new Collection<string, RoleController>();
|
||||||
|
const roles = await prisma.role.findMany({
|
||||||
|
include: { users: { include: { roles: true } } },
|
||||||
|
});
|
||||||
|
|
||||||
|
roles. map((v:any) => collection.set(v.id, new RoleController(v)));
|
||||||
|
|
||||||
|
if (opt?.requestingUser) {
|
||||||
|
const permittedRoles = await Promise.all(
|
||||||
|
collection.map(async (v) =>
|
||||||
|
(await opt.requestingUser?.hasPermission(
|
||||||
|
this._buildPermissionNode(v.id, "read")
|
||||||
|
))
|
||||||
|
? v.id
|
||||||
|
: null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
collection = collection.filter((v) =>
|
||||||
|
permittedRoles.filter((x) => x !== null).includes(v.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Permissino Node
|
||||||
|
*
|
||||||
|
* Build a role centric permission node with a role id and permission scope.
|
||||||
|
*
|
||||||
|
* **FORMAT**: `roles.{id}.{scope}
|
||||||
|
*
|
||||||
|
* @param id - Role ID
|
||||||
|
* @param scope - Scope of the permission node
|
||||||
|
* @returns {string} Constructed Permission Node
|
||||||
|
*/
|
||||||
|
_buildPermissionNode(id: string, scope: "read" | "write") {
|
||||||
|
return ["roles", id, scope].join(".");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO automatic string transformation for monikers to be all lower case with no spaces and only underscores.
|
||||||
|
*
|
||||||
|
* @TODO create and inheritance and ordering system @see https://www.prisma.io/docs/concepts/components/prisma-schema/relations/self-relations
|
||||||
|
*
|
||||||
|
* @TODO go through and make sure all the zod schemas have mins, maxes, etc.
|
||||||
|
*
|
||||||
|
* @TODO Limit those who can give out the `*` permission to those with the `*` permission.
|
||||||
|
* - Maybe also limit the use of `*` all together?
|
||||||
|
*/
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import {
|
||||||
|
prisma,
|
||||||
|
refreshTokenDuration,
|
||||||
|
sessionDuration,
|
||||||
|
accessTokenDuration,
|
||||||
|
accessTokenPrivateKey,
|
||||||
|
refreshTokenPrivateKey,
|
||||||
|
} from "../constants";
|
||||||
|
import UserController from "../controllers/UserController";
|
||||||
|
import {
|
||||||
|
SessionController,
|
||||||
|
DecodedSession,
|
||||||
|
SessionPayloadObject,
|
||||||
|
SessionTokensObject,
|
||||||
|
} from "../controllers/SessionController";
|
||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
import SessionError from "../Errors/SessionError";
|
||||||
|
import SessionTokenError from "../Errors/SessionTokenError";
|
||||||
|
import ExpiredAccessTokenError from "../Errors/ExpiredAccessTokenError";
|
||||||
|
import ExpiredRefreshTokenError from "../Errors/ExpiredRefreshTokenError";
|
||||||
|
import { events } from "../modules/globalEvents";
|
||||||
|
|
||||||
|
export interface SessionCreationData {
|
||||||
|
user: UserController;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sessions = {
|
||||||
|
/**
|
||||||
|
* Create a session
|
||||||
|
*
|
||||||
|
* This will create a session instance in the databse that will be linked to both the session token
|
||||||
|
* and the refresh token.
|
||||||
|
*
|
||||||
|
* @param data - The params needed to create the session tokens
|
||||||
|
* @returns {Promise<SessionTokensObject>} Session Token and the Refresh Token
|
||||||
|
*/
|
||||||
|
async create(data: SessionCreationData): Promise<SessionTokensObject> {
|
||||||
|
const session = await prisma.session.create({
|
||||||
|
data: {
|
||||||
|
expires: new Date(Date.now() + sessionDuration),
|
||||||
|
userId: data.user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const controller = new SessionController(session);
|
||||||
|
|
||||||
|
// Trigger Global Event
|
||||||
|
events.emit("session:created", {
|
||||||
|
user: data.user,
|
||||||
|
session: controller,
|
||||||
|
});
|
||||||
|
|
||||||
|
let tokens: SessionTokensObject = await controller.generateTokens();
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a session
|
||||||
|
*
|
||||||
|
* This method is designed to be as versitile as possible, if you are looking for a session, use this method with
|
||||||
|
* your choice of `accessToken`, `refreshToken`, `id`, or `sessionKey`. The identifier value is a partial type.
|
||||||
|
*
|
||||||
|
* @param identifier - An object allowing you to put either session token, sessionKey, or id in to fetch the desired session.
|
||||||
|
* @returns {Promise<SessionController>} The controller for the desired session.
|
||||||
|
*/
|
||||||
|
async fetch(
|
||||||
|
identifier: Partial<{
|
||||||
|
refreshToken: string;
|
||||||
|
accessToken: string;
|
||||||
|
id: string;
|
||||||
|
sessionKey: string;
|
||||||
|
}>
|
||||||
|
) {
|
||||||
|
if (identifier.refreshToken || identifier.accessToken) {
|
||||||
|
const decodedJWT = identifier.refreshToken
|
||||||
|
? ((await new Promise((res, rej) =>
|
||||||
|
jwt.verify(
|
||||||
|
identifier.refreshToken!,
|
||||||
|
refreshTokenPrivateKey,
|
||||||
|
{
|
||||||
|
algorithms: ["RS256"],
|
||||||
|
},
|
||||||
|
async (err, decode) => {
|
||||||
|
if (
|
||||||
|
err &&
|
||||||
|
(err.name == "TokenExpiredError" ||
|
||||||
|
err.message == "invalid signature")
|
||||||
|
) {
|
||||||
|
let sessionDat = await prisma.session.findFirst({
|
||||||
|
where: {
|
||||||
|
sessionKey: (
|
||||||
|
jwt.decode(identifier.refreshToken!) as DecodedSession
|
||||||
|
).sessionKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sessionDat)
|
||||||
|
return rej(new SessionError("Invalid session."));
|
||||||
|
let session = new SessionController(sessionDat);
|
||||||
|
|
||||||
|
await session.terminate();
|
||||||
|
if (err.message == "invalid signature")
|
||||||
|
return rej(new SessionError("Invalid session."));
|
||||||
|
|
||||||
|
return rej(new ExpiredRefreshTokenError("It epired."));
|
||||||
|
}
|
||||||
|
if (err) return rej(err);
|
||||||
|
|
||||||
|
return res(decode as DecodedSession);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)) as DecodedSession)
|
||||||
|
: ((await new Promise((res, rej) =>
|
||||||
|
jwt.verify(
|
||||||
|
identifier.accessToken!,
|
||||||
|
accessTokenPrivateKey,
|
||||||
|
{
|
||||||
|
algorithms: ["RS256"],
|
||||||
|
},
|
||||||
|
(err, decode) => {
|
||||||
|
if (err && err.name == "TokenExpiredError")
|
||||||
|
return rej(new ExpiredAccessTokenError());
|
||||||
|
if (err) return rej(err);
|
||||||
|
return res(decode as DecodedSession);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)) as DecodedSession);
|
||||||
|
|
||||||
|
const sessionData = await prisma.session.findFirst({
|
||||||
|
where: { sessionKey: decodedJWT.sessionKey },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sessionData) throw new SessionError("Invalid Session");
|
||||||
|
if (identifier.accessToken && decodedJWT.exp > Date.now())
|
||||||
|
throw new ExpiredAccessTokenError();
|
||||||
|
|
||||||
|
if (identifier.refreshToken && decodedJWT.exp > Date.now()) {
|
||||||
|
let sess = new SessionController(sessionData);
|
||||||
|
await sess.terminate();
|
||||||
|
throw new SessionError("Invalid Session...", "Expired Refresh Token");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SessionController(sessionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionData = await prisma.session.findFirst({
|
||||||
|
where: { OR: [{ sessionKey: identifier.sessionKey, id: identifier.id }] },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sessionData) throw new SessionError("Invalid Session");
|
||||||
|
|
||||||
|
return new SessionController(sessionData);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO As a consequence of the above, need to setup pgBoss for cron and event loop.
|
||||||
|
*/
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { User } from "../../generated/prisma/client";
|
||||||
|
import { prisma } from "../constants";
|
||||||
|
import { SessionTokensObject } from "../controllers/SessionController";
|
||||||
|
import UserController from "../controllers/UserController";
|
||||||
|
|
||||||
|
export const users = {
|
||||||
|
/**
|
||||||
|
* Authenticate The User
|
||||||
|
*
|
||||||
|
* If the user has already been registered, this function will supply them with a session id, otherwise
|
||||||
|
* this method will create an account, then create a session id.
|
||||||
|
*
|
||||||
|
* @summary It creates a user if one doesn't exist and will supply a session id
|
||||||
|
*
|
||||||
|
* @async
|
||||||
|
* @param ghCode - The code supplied in the callback url of a GitHub oAuth transaction
|
||||||
|
*/
|
||||||
|
/* async authenticate(ghCode: string): Promise<SessionTokensObject> {
|
||||||
|
const token = await ghApp.oauth.createToken({ code: ghCode }).catch((e) => {
|
||||||
|
throw new AuthenticationError("Invalid OAuth code...");
|
||||||
|
});
|
||||||
|
const userOK = await ghApp.oauth.getUserOctokit({
|
||||||
|
token: token.authentication.token,
|
||||||
|
});
|
||||||
|
const ghUser = await userOK.request("GET /user");
|
||||||
|
let user =
|
||||||
|
(await this.fetchUser({ userId: ghUser.data.id })) ??
|
||||||
|
(await this.createUser(token.authentication.token));
|
||||||
|
|
||||||
|
const tokens = await sessions.create({ user });
|
||||||
|
events.emit("user:authenticated", { user, tokens });
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}, */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if the user exists
|
||||||
|
*
|
||||||
|
* @param partial - A partial object that you can feed any value from the database into.
|
||||||
|
* @returns {Promise<boolean>} Does the user exist?
|
||||||
|
*/
|
||||||
|
async userExists(partial: Partial<User>): Promise<boolean> {
|
||||||
|
const match = await prisma.user.findFirst({ where: partial });
|
||||||
|
return !!match;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a user
|
||||||
|
*
|
||||||
|
* This method takes in a unique identifier for the user you are trying to fetch, and returns
|
||||||
|
* the controller for the user if the user exists. If the user doesn't exist, or no identifier
|
||||||
|
* was provided, this will reutrn `null`.
|
||||||
|
*
|
||||||
|
* @param identifier - A partial identifier for a user (e.g. id, email, userID, etc.)
|
||||||
|
* @returns {Promise<UserController>} The controller for the user
|
||||||
|
*/
|
||||||
|
async fetchUser(
|
||||||
|
identifier: Partial<{
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
login: string;
|
||||||
|
userId: number;
|
||||||
|
}>
|
||||||
|
) {
|
||||||
|
if (Object.keys(identifier).length == 0) return null;
|
||||||
|
const userData = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
//@ts-ignore
|
||||||
|
OR: Object.keys(identifier).map((v) => ({ [v]: identifier[v] })),
|
||||||
|
},
|
||||||
|
include: { roles: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!userData) return null;
|
||||||
|
|
||||||
|
return new UserController(userData);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new user
|
||||||
|
*
|
||||||
|
* This method will poll GitHub and get all the information on the user to then create the
|
||||||
|
* record in our database. On top of that it also pushes it into the user cache.
|
||||||
|
*
|
||||||
|
* @param token - The Github token provided by the auth method
|
||||||
|
* @returns {Promise<UserController>} The new user controller for the user
|
||||||
|
*/
|
||||||
|
async createUser(token: string): Promise<UserController> {
|
||||||
|
const ghUser = await (
|
||||||
|
await ghApp.oauth.getUserOctokit({ token })
|
||||||
|
).request("GET /user");
|
||||||
|
|
||||||
|
const emails = await (
|
||||||
|
await ghApp.oauth.getUserOctokit({ token })
|
||||||
|
).request("GET /user/emails");
|
||||||
|
|
||||||
|
const newUser = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
userId: ghUser.data.id,
|
||||||
|
email: emails.data[0].email,
|
||||||
|
image: ghUser.data.avatar_url,
|
||||||
|
name: ghUser.data.name,
|
||||||
|
login: ghUser.data.login,
|
||||||
|
token,
|
||||||
|
},
|
||||||
|
include: { roles: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
let controller = new UserController(newUser);
|
||||||
|
events.emit("user:created", controller);
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO Figure out default permissions
|
||||||
|
*/
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { ZodError } from "zod";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
export const apiResponse = {
|
||||||
|
successful: (message: string, data?: any) => ({
|
||||||
|
status: 200,
|
||||||
|
message,
|
||||||
|
data,
|
||||||
|
successful: true,
|
||||||
|
meta: {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
created: (message: string, data?: any) => ({
|
||||||
|
status: 201,
|
||||||
|
message,
|
||||||
|
data,
|
||||||
|
successful: true,
|
||||||
|
meta: {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
error: (err: Error) => ({
|
||||||
|
// @ts-ignore
|
||||||
|
status: err["status"] ?? 400,
|
||||||
|
message: err.message,
|
||||||
|
error: err.name,
|
||||||
|
successful: false,
|
||||||
|
meta: {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
internalError: () => ({
|
||||||
|
status: 500,
|
||||||
|
message: "An Internal Server Error has occured...",
|
||||||
|
error: "InternalServerError",
|
||||||
|
successful: false,
|
||||||
|
meta: {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
zodError: (err: ZodError) => {
|
||||||
|
const data = JSON.parse(err.message);
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
message: "TypeError",
|
||||||
|
error: data,
|
||||||
|
successful: false,
|
||||||
|
meta: {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { Handler, Hono, MiddlewareHandler } from "hono";
|
||||||
|
import { Variables } from "../../types/HonoTypes";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a route.
|
||||||
|
*
|
||||||
|
* This method exists to serve the purpose of allowing us to split all of our api routes into different files and
|
||||||
|
* easily and quickly be able to rope them back into the main api server instance.
|
||||||
|
*
|
||||||
|
* One of the sortfallings of this method is that I was not able to figure out how to integrate the middleware to come
|
||||||
|
* before the handler, so if somebody feels upto it please figure out a way to have the middleware come before the handler
|
||||||
|
* method naturally as you would if you using a plain hono method.
|
||||||
|
*
|
||||||
|
* @TODO Move middleware handlers to come before primary handler naturally.
|
||||||
|
*
|
||||||
|
* @param method - HTTP Method
|
||||||
|
* @param path - URL Path
|
||||||
|
* @param handler - Handler function for Hono
|
||||||
|
* @param middleware - Array of Middleware Handlers for Hono
|
||||||
|
* @returns {Hono} - A new Hono instance containing the newly created route.
|
||||||
|
*/
|
||||||
|
export function createRoute(
|
||||||
|
method: string | string[],
|
||||||
|
path: string[],
|
||||||
|
handler: Handler<{
|
||||||
|
Variables: Variables;
|
||||||
|
}>,
|
||||||
|
...middleware: MiddlewareHandler<{
|
||||||
|
Variables: Variables;
|
||||||
|
}>[]
|
||||||
|
): Hono<{ Variables: Variables }> {
|
||||||
|
if (middleware)
|
||||||
|
return new Hono<{ Variables: Variables }>().on(
|
||||||
|
method as any,
|
||||||
|
path,
|
||||||
|
...middleware,
|
||||||
|
handler
|
||||||
|
);
|
||||||
|
return new Hono<{ Variables: Variables }>().on(method as any, path, handler);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { Eventra } from "@duxcore/eventra";
|
||||||
|
import UserController from "../controllers/UserController";
|
||||||
|
import {
|
||||||
|
SessionController,
|
||||||
|
SessionTokensObject,
|
||||||
|
} from "../controllers/SessionController";
|
||||||
|
import { RoleController } from "../controllers/RoleController";
|
||||||
|
import { JsonWebTokenError } from "jsonwebtoken";
|
||||||
|
import { User } from "../../generated/prisma/client";
|
||||||
|
|
||||||
|
interface EventTypes {
|
||||||
|
"api:started": () => void;
|
||||||
|
"user:created": (user: UserController) => void;
|
||||||
|
"user:updated": (data: {
|
||||||
|
user: UserController;
|
||||||
|
updatedValues: Partial<User>;
|
||||||
|
}) => void;
|
||||||
|
"user:authenticated": (data: {
|
||||||
|
user: UserController;
|
||||||
|
tokens: SessionTokensObject;
|
||||||
|
}) => void;
|
||||||
|
"session:created": (data: {
|
||||||
|
user: UserController;
|
||||||
|
session: SessionController;
|
||||||
|
}) => void;
|
||||||
|
"session:tokens_generated": (data: {
|
||||||
|
session: SessionController;
|
||||||
|
tokens: SessionTokensObject;
|
||||||
|
}) => void;
|
||||||
|
"session:token_refresh": (data: {
|
||||||
|
session: SessionController;
|
||||||
|
tokens: SessionTokensObject;
|
||||||
|
}) => void;
|
||||||
|
"session:invalidated": (session: SessionController) => void;
|
||||||
|
"session:terminated": (session: SessionController) => void;
|
||||||
|
"role:created": (role: RoleController) => void;
|
||||||
|
"role:deleted": (role: RoleController) => void;
|
||||||
|
"role:updated": (data: {
|
||||||
|
role: RoleController;
|
||||||
|
updateData: Parameters<typeof RoleController.prototype.update>["0"];
|
||||||
|
}) => void;
|
||||||
|
"role:permissions:updated": (data: {
|
||||||
|
previous: string[];
|
||||||
|
previousSigned: string;
|
||||||
|
current: string[];
|
||||||
|
currentSigned: string;
|
||||||
|
action: "set" | "added" | "removed";
|
||||||
|
role: RoleController;
|
||||||
|
}) => void;
|
||||||
|
"role:permissions:verification_error": (data: {
|
||||||
|
currentSigned: string;
|
||||||
|
attemptedVerification: string;
|
||||||
|
err: Error;
|
||||||
|
role: RoleController;
|
||||||
|
}) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const events = new Eventra<EventTypes>();
|
||||||
|
|
||||||
|
export function setupEventDebugger() {
|
||||||
|
events.any((eventName, ...args) => {
|
||||||
|
console.log(`[ Event Debugger ] (${eventName})`);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export function genImplicitPerm(
|
||||||
|
resource: string,
|
||||||
|
resourceId: string,
|
||||||
|
userId: string
|
||||||
|
) {
|
||||||
|
return ["resource", resource, resourceId, "user", userId, "implicit"].join(
|
||||||
|
"."
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* Permission Validator
|
||||||
|
*
|
||||||
|
* This method is used for validaing user and role permissions. This method is given a single or and array
|
||||||
|
* of permission nodes that the user has and it is also given the permission node that is required for whatever
|
||||||
|
* query they are trying to execute, and this will determine if any of the permission nodes match or will
|
||||||
|
* verify the given permission node.
|
||||||
|
*
|
||||||
|
* Special token types:
|
||||||
|
* - Asterisk (*): verifies it's token and all following tokens.
|
||||||
|
* - Question Mark (?): verifies it's token and only it's token.
|
||||||
|
* - Inclusive List ([a,b,c]): verifies only the tokens in the list.
|
||||||
|
* - Exclusive List (<a,b,c>): verifies all tokens except for the ones in the list.
|
||||||
|
*
|
||||||
|
* @param permission - The required permission
|
||||||
|
* @param permissionExpressions - The owned permission(s)
|
||||||
|
* @returns {boolean} Does the user have the permission?
|
||||||
|
*/
|
||||||
|
export function permissionValidator(
|
||||||
|
permission: string,
|
||||||
|
permissionExpressions: string | string[]
|
||||||
|
): boolean {
|
||||||
|
if (typeof permissionExpressions === "string") {
|
||||||
|
// If the second parameter is a string, treat it as a single expression
|
||||||
|
permissionExpressions = [permissionExpressions];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each expression in the array and check if any of them match the permission
|
||||||
|
for (const expression of permissionExpressions) {
|
||||||
|
const rx = expression
|
||||||
|
.replace(/\./g, "\\.")
|
||||||
|
.replace(/\*/g, ".*")
|
||||||
|
.replace(/\?/g, ".")
|
||||||
|
.replace(/\[([^\]\[]*)\]/g, "($1)")
|
||||||
|
.replace(/<([^<>]+)>/g, "(?:(?!$1)[^.])*")
|
||||||
|
.replace(/,/g, "|");
|
||||||
|
|
||||||
|
if (new RegExp(`^${rx}$`).test(permission)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO It's okay, you can't always get everything done and that is fine.
|
||||||
|
* Just take a breath and move on, come back if you feel upto it.
|
||||||
|
* What you make is good and whilst you can always do more,
|
||||||
|
* you can't do everything. Nothing will ever be perfect,
|
||||||
|
* so stop trying to be perfect and allow your self to move on
|
||||||
|
* even if you know there is more you can do.
|
||||||
|
*/
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
import { permissionsPrivateKey } from "../../constants";
|
||||||
|
import { PermissionIssuers } from "../../types/PermissionTypes";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign Permissions
|
||||||
|
*
|
||||||
|
* This will sign the array of permissions with the private key for permissions, and then return
|
||||||
|
* a JWT which will be stored in the databse.
|
||||||
|
*
|
||||||
|
* @param permissions - All the permissions to be signed
|
||||||
|
* @returns {string} - The signed permissions object
|
||||||
|
*/
|
||||||
|
export function signPermissions(data: {
|
||||||
|
issuer: PermissionIssuers;
|
||||||
|
subject: string;
|
||||||
|
permissions: string[];
|
||||||
|
}) {
|
||||||
|
return jwt.sign({ permissions: data.permissions }, permissionsPrivateKey, {
|
||||||
|
algorithm: "RS256",
|
||||||
|
issuer: data.issuer,
|
||||||
|
subject: data.subject,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { blake2sHex } from "blakets";
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
|
export default class Password {
|
||||||
|
public static generateSalt(options?: GenerateSaltOptions): string {
|
||||||
|
const length = options?.length ?? 12;
|
||||||
|
const randomBytes = crypto.randomBytes(Math.ceil(length / 2));
|
||||||
|
return randomBytes.toString("hex").slice(0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static hash(password: string, options?: HashPasswordOptions): string {
|
||||||
|
const salt =
|
||||||
|
options?.overrideSalt ?? Password.generateSalt(options?.saltOpts);
|
||||||
|
const hash = blake2sHex(`$BLAKE2s$${password}$${salt}`);
|
||||||
|
return `BLAKE2s$${hash}$${salt}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static validate(newPass: string, hashed: string): boolean {
|
||||||
|
const [algo, oldHash, salt] = hashed.split(/\$/g);
|
||||||
|
return crypto.timingSafeEqual(
|
||||||
|
Buffer.from(hashed),
|
||||||
|
Buffer.from(Password.hash(newPass, { overrideSalt: salt }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HashPasswordOptions {
|
||||||
|
overrideSalt?: string;
|
||||||
|
saltOpts?: GenerateSaltOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GenerateSaltOptions {
|
||||||
|
length?: number; // default 12
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const mergeArrays = (a, b, predicate = (a, b) => a === b) => {
|
||||||
|
const c = [...a]; // copy to avoid side effects
|
||||||
|
// add all items from B to copy C if they're not already present
|
||||||
|
b.forEach((bItem) =>
|
||||||
|
c.some((cItem) => predicate(bItem, cItem)) ? null : c.push(bItem)
|
||||||
|
);
|
||||||
|
return c;
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export type Variables = {
|
||||||
|
foo: "bar"
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export type PermissionIssuers = "roles" | "user" | "api_key";
|
||||||
|
export interface DecodedPermissionsBlock {
|
||||||
|
permissions: string[];
|
||||||
|
iat: number; // Issued at
|
||||||
|
iss: PermissionIssuers; // Issuer
|
||||||
|
sub: string; // Subject
|
||||||
|
}
|
||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
// Bundler mode
|
// Bundler mode
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": false,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
|
|
||||||
// Best practices
|
// Best practices
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import keypair from "keypair";
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
Generating Private Keys
|
||||||
|
-----------------
|
||||||
|
This script will go through and genrate all the keys necessary for running the Credential Manager API locally.
|
||||||
|
This process might take several minutes.
|
||||||
|
-----------------`);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
[
|
||||||
|
".accessToken.key",
|
||||||
|
".refreshToken.key",
|
||||||
|
".permissions.key",
|
||||||
|
".apiKeyToken.key",
|
||||||
|
].map(async (v) => {
|
||||||
|
if (
|
||||||
|
await Bun.file(v)
|
||||||
|
.exists()
|
||||||
|
.then((bool) => {
|
||||||
|
if (bool) {
|
||||||
|
console.log(`'${v}' already exists`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
console.log(`Generating '${v}'...`);
|
||||||
|
const keys = keypair({ bits: 4096 });
|
||||||
|
|
||||||
|
await Bun.write(v, keys.private);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("\nGenerated All Keys Successfully!");
|
||||||
Reference in New Issue
Block a user