tRPC overhaul!
This commit is contained in:
parent
8e2df843dd
commit
091505b900
11 changed files with 404 additions and 49 deletions
|
@ -28,6 +28,7 @@
|
|||
"json2csv": "6.0.0-alpha.2",
|
||||
"next": "^13.4.12",
|
||||
"next-auth": "^4.22.3",
|
||||
"nextjs-cors": "^2.1.2",
|
||||
"postcss": "^8.4.27",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
@ -36,6 +37,7 @@
|
|||
"resend": "^0.17.2",
|
||||
"sharp": "^0.32.4",
|
||||
"superjson": "1.13.1",
|
||||
"trpc-openapi": "^1.2.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
273
pnpm-lock.yaml
generated
273
pnpm-lock.yaml
generated
|
@ -53,6 +53,9 @@ dependencies:
|
|||
next-auth:
|
||||
specifier: ^4.22.3
|
||||
version: 4.22.3(next@13.4.12)(react-dom@18.2.0)(react@18.2.0)
|
||||
nextjs-cors:
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2(next@13.4.12)
|
||||
postcss:
|
||||
specifier: ^8.4.27
|
||||
version: 8.4.27
|
||||
|
@ -77,6 +80,9 @@ dependencies:
|
|||
superjson:
|
||||
specifier: 1.13.1
|
||||
version: 1.13.1
|
||||
trpc-openapi:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0(@trpc/server@10.36.0)(zod@3.21.4)
|
||||
zod:
|
||||
specifier: ^3.21.4
|
||||
version: 3.21.4
|
||||
|
@ -1394,6 +1400,14 @@ packages:
|
|||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
mime-types: 2.1.35
|
||||
negotiator: 0.6.3
|
||||
dev: false
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.10.0):
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
|
@ -1733,6 +1747,11 @@ packages:
|
|||
streamsearch: 1.1.0
|
||||
dev: false
|
||||
|
||||
/bytes@3.1.2:
|
||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/cacheable-lookup@5.0.4:
|
||||
resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
|
||||
engines: {node: '>=10.6.0'}
|
||||
|
@ -1756,7 +1775,6 @@ packages:
|
|||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
get-intrinsic: 1.2.1
|
||||
dev: true
|
||||
|
||||
/callsites@3.1.0:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
|
@ -1838,6 +1856,15 @@ packages:
|
|||
engines: {node: '>=0.8'}
|
||||
dev: false
|
||||
|
||||
/co-body@6.1.0:
|
||||
resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==}
|
||||
dependencies:
|
||||
inflation: 2.0.0
|
||||
qs: 6.11.2
|
||||
raw-body: 2.5.2
|
||||
type-is: 1.6.18
|
||||
dev: false
|
||||
|
||||
/color-convert@1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
dependencies:
|
||||
|
@ -1927,6 +1954,17 @@ packages:
|
|||
proto-list: 1.2.4
|
||||
dev: false
|
||||
|
||||
/content-disposition@0.5.4:
|
||||
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/cookie-es@1.0.0:
|
||||
resolution: {integrity: sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==}
|
||||
dev: false
|
||||
|
||||
/cookie@0.5.0:
|
||||
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
@ -1943,6 +1981,14 @@ packages:
|
|||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||
dev: false
|
||||
|
||||
/cors@2.8.5:
|
||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
dependencies:
|
||||
object-assign: 4.1.1
|
||||
vary: 1.1.2
|
||||
dev: false
|
||||
|
||||
/cross-spawn@7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -2074,11 +2120,25 @@ packages:
|
|||
resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==}
|
||||
dev: false
|
||||
|
||||
/defu@6.1.2:
|
||||
resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==}
|
||||
dev: false
|
||||
|
||||
/delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: false
|
||||
|
||||
/depd@1.1.2:
|
||||
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/depd@2.0.0:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/deprecation@2.3.1:
|
||||
resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
|
||||
dev: false
|
||||
|
@ -2088,6 +2148,10 @@ packages:
|
|||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/destr@2.0.0:
|
||||
resolution: {integrity: sha512-FJ9RDpf3GicEBvzI3jxc2XhHzbqD8p4ANw/1kPsFBfTvP1b7Gn/Lg1vO7R9J4IVgoMbyUmFrFGZafJ1hPZpvlg==}
|
||||
dev: false
|
||||
|
||||
/detect-libc@2.0.2:
|
||||
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2795,6 +2859,11 @@ packages:
|
|||
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
||||
dev: false
|
||||
|
||||
/fresh@0.5.2:
|
||||
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: false
|
||||
|
@ -2861,7 +2930,6 @@ packages:
|
|||
has: 1.0.3
|
||||
has-proto: 1.0.1
|
||||
has-symbols: 1.0.3
|
||||
dev: true
|
||||
|
||||
/get-stream@5.2.0:
|
||||
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
|
||||
|
@ -3028,6 +3096,18 @@ packages:
|
|||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||
dev: true
|
||||
|
||||
/h3@1.7.1:
|
||||
resolution: {integrity: sha512-A9V2NEDNHet7v1gCg7CMwerSigLi0SRbhTy7C3lGb0N4YKIpPmLDjedTUopqp4dnn7COHfqUjjaz3zbtz4QduA==}
|
||||
dependencies:
|
||||
cookie-es: 1.0.0
|
||||
defu: 6.1.2
|
||||
destr: 2.0.0
|
||||
iron-webcrypto: 0.7.1
|
||||
radix3: 1.0.1
|
||||
ufo: 1.2.0
|
||||
uncrypto: 0.1.3
|
||||
dev: false
|
||||
|
||||
/has-bigints@1.0.2:
|
||||
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
|
||||
dev: true
|
||||
|
@ -3050,12 +3130,10 @@ packages:
|
|||
/has-proto@1.0.1:
|
||||
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/has-symbols@1.0.3:
|
||||
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/has-tostringtag@1.0.0:
|
||||
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
|
||||
|
@ -3126,6 +3204,17 @@ packages:
|
|||
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
||||
dev: false
|
||||
|
||||
/http-errors@2.0.0:
|
||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
depd: 2.0.0
|
||||
inherits: 2.0.4
|
||||
setprototypeof: 1.2.0
|
||||
statuses: 2.0.1
|
||||
toidentifier: 1.0.1
|
||||
dev: false
|
||||
|
||||
/http2-wrapper@1.0.3:
|
||||
resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
|
||||
engines: {node: '>=10.19.0'}
|
||||
|
@ -3143,6 +3232,13 @@ packages:
|
|||
engines: {node: '>=14.18.0'}
|
||||
dev: true
|
||||
|
||||
/iconv-lite@0.4.24:
|
||||
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
dev: false
|
||||
|
||||
/ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
dev: false
|
||||
|
@ -3164,6 +3260,11 @@ packages:
|
|||
engines: {node: '>=0.8.19'}
|
||||
dev: true
|
||||
|
||||
/inflation@2.0.0:
|
||||
resolution: {integrity: sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dev: false
|
||||
|
||||
/inflight@1.0.6:
|
||||
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||
dependencies:
|
||||
|
@ -3195,6 +3296,10 @@ packages:
|
|||
engines: {node: '>= 0.10'}
|
||||
dev: false
|
||||
|
||||
/iron-webcrypto@0.7.1:
|
||||
resolution: {integrity: sha512-K/UmlEhPCPXEHV5hAtH5C0tI5JnFuOrv4yO/j7ODPl3HaiiHBLbOLTde+ieUaAyfCATe4LoAnclyF+hmSCOVmQ==}
|
||||
dev: false
|
||||
|
||||
/is-array-buffer@3.0.2:
|
||||
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
|
||||
dependencies:
|
||||
|
@ -3569,6 +3674,10 @@ packages:
|
|||
p-locate: 5.0.0
|
||||
dev: true
|
||||
|
||||
/lodash.clonedeep@4.5.0:
|
||||
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.get@4.4.2:
|
||||
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
|
||||
dev: false
|
||||
|
@ -3602,6 +3711,15 @@ packages:
|
|||
dependencies:
|
||||
yallist: 4.0.0
|
||||
|
||||
/media-typer@0.3.0:
|
||||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/merge-descriptors@1.0.1:
|
||||
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
||||
dev: false
|
||||
|
||||
/merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
|
||||
|
@ -3609,6 +3727,11 @@ packages:
|
|||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
/methods@1.1.2:
|
||||
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/micromatch@4.0.5:
|
||||
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
@ -3628,6 +3751,12 @@ packages:
|
|||
mime-db: 1.52.0
|
||||
dev: false
|
||||
|
||||
/mime@1.6.0:
|
||||
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -3713,6 +3842,11 @@ packages:
|
|||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
dev: true
|
||||
|
||||
/negotiator@0.6.3:
|
||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/next-auth@4.22.3(next@13.4.12)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-XAgy9xV3J2eJOXrQhmxdjV6MLM29ibm6WtMXc3KY6IPZeApf+SuBuPvlqCUfbu5YsAzlg9WSw6u01dChTfeZOA==}
|
||||
peerDependencies:
|
||||
|
@ -3781,6 +3915,15 @@ packages:
|
|||
- babel-plugin-macros
|
||||
dev: false
|
||||
|
||||
/nextjs-cors@2.1.2(next@13.4.12):
|
||||
resolution: {integrity: sha512-2yOVivaaf2ILe4f/qY32hnj3oC77VCOsUQJQfhVMGsXE/YMEWUY2zy78sH9FKUCM7eG42/l3pDofIzMD781XGA==}
|
||||
peerDependencies:
|
||||
next: ^8.1.1-canary.54 || ^9.0.0 || ^10.0.0-0 || ^11.0.0 || ^12.0.0 || ^13.0.0
|
||||
dependencies:
|
||||
cors: 2.8.5
|
||||
next: 13.4.12(react-dom@18.2.0)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/node-abi@3.45.0:
|
||||
resolution: {integrity: sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -3804,6 +3947,22 @@ packages:
|
|||
whatwg-url: 5.0.0
|
||||
dev: false
|
||||
|
||||
/node-mocks-http@1.12.2:
|
||||
resolution: {integrity: sha512-xhWwC0dh35R9rf0j3bRZXuISXdHxxtMx0ywZQBwjrg3yl7KpRETzogfeCamUIjltpn0Fxvs/ZhGJul1vPLrdJQ==}
|
||||
engines: {node: '>=0.6'}
|
||||
dependencies:
|
||||
accepts: 1.3.8
|
||||
content-disposition: 0.5.4
|
||||
depd: 1.1.2
|
||||
fresh: 0.5.2
|
||||
merge-descriptors: 1.0.1
|
||||
methods: 1.1.2
|
||||
mime: 1.6.0
|
||||
parseurl: 1.3.3
|
||||
range-parser: 1.2.1
|
||||
type-is: 1.6.18
|
||||
dev: false
|
||||
|
||||
/node-releases@2.0.13:
|
||||
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
|
||||
dev: false
|
||||
|
@ -3863,7 +4022,6 @@ packages:
|
|||
/object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/object-hash@2.2.0:
|
||||
resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
|
||||
|
@ -3876,7 +4034,6 @@ packages:
|
|||
|
||||
/object-inspect@1.12.3:
|
||||
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
|
||||
dev: true
|
||||
|
||||
/object-keys@1.1.1:
|
||||
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
|
||||
|
@ -3969,6 +4126,10 @@ packages:
|
|||
is-wsl: 2.2.0
|
||||
dev: true
|
||||
|
||||
/openapi-types@12.1.3:
|
||||
resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
|
||||
dev: false
|
||||
|
||||
/openid-client@5.4.3:
|
||||
resolution: {integrity: sha512-sVQOvjsT/sbSfYsQI/9liWQGVZH/Pp3rrtlGEwgk/bbHfrUDZ24DN57lAagIwFtuEu+FM9Ev7r85s8S/yPjimQ==}
|
||||
dependencies:
|
||||
|
@ -4067,6 +4228,11 @@ packages:
|
|||
peberminta: 0.8.0
|
||||
dev: false
|
||||
|
||||
/parseurl@1.3.3:
|
||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -4369,6 +4535,13 @@ packages:
|
|||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/qs@6.11.2:
|
||||
resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==}
|
||||
engines: {node: '>=0.6'}
|
||||
dependencies:
|
||||
side-channel: 1.0.4
|
||||
dev: false
|
||||
|
||||
/queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
|
@ -4381,6 +4554,25 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/radix3@1.0.1:
|
||||
resolution: {integrity: sha512-y+AcwZ3HcUIGc9zGsNVf5+BY/LxL+z+4h4J3/pp8jxSmy1STaCocPS3qrj4tA5ehUSzqtqK+0Aygvz/r/8vy4g==}
|
||||
dev: false
|
||||
|
||||
/range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/raw-body@2.5.2:
|
||||
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
http-errors: 2.0.0
|
||||
iconv-lite: 0.4.24
|
||||
unpipe: 1.0.0
|
||||
dev: false
|
||||
|
||||
/rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
@ -4647,6 +4839,10 @@ packages:
|
|||
is-regex: 1.1.4
|
||||
dev: true
|
||||
|
||||
/safer-buffer@2.1.2:
|
||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||
dev: false
|
||||
|
||||
/scheduler@0.23.0:
|
||||
resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
|
||||
dependencies:
|
||||
|
@ -4680,6 +4876,10 @@ packages:
|
|||
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||
dev: false
|
||||
|
||||
/setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
dev: false
|
||||
|
||||
/sharp@0.32.4:
|
||||
resolution: {integrity: sha512-exUnZewqVZC6UXqXuQ8fyJJv0M968feBi04jb9GcUHrWtkRoAKnbJt8IfwT4NJs7FskArbJ14JAFGVuooszoGg==}
|
||||
engines: {node: '>=14.15.0'}
|
||||
|
@ -4721,7 +4921,6 @@ packages:
|
|||
call-bind: 1.0.2
|
||||
get-intrinsic: 1.2.1
|
||||
object-inspect: 1.12.3
|
||||
dev: true
|
||||
|
||||
/signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
@ -4783,6 +4982,11 @@ packages:
|
|||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
||||
dev: false
|
||||
|
||||
/statuses@2.0.1:
|
||||
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/streamsearch@1.1.0:
|
||||
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
@ -5087,6 +5291,11 @@ packages:
|
|||
resolution: {integrity: sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ==}
|
||||
dev: false
|
||||
|
||||
/toidentifier@1.0.1:
|
||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
dev: false
|
||||
|
||||
/tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
dev: false
|
||||
|
@ -5104,6 +5313,22 @@ packages:
|
|||
pretty-bytes: 5.6.0
|
||||
dev: false
|
||||
|
||||
/trpc-openapi@1.2.0(@trpc/server@10.36.0)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-pfYoCd/3KYXWXvUPZBKJw455OOwngKN/6SIcj7Yit19OMLJ+8yVZkEvGEeg5wUSwfsiTdRsKuvqkRPXVSwV7ew==}
|
||||
peerDependencies:
|
||||
'@trpc/server': ^10.0.0
|
||||
zod: ^3.14.4
|
||||
dependencies:
|
||||
'@trpc/server': 10.36.0
|
||||
co-body: 6.1.0
|
||||
h3: 1.7.1
|
||||
lodash.clonedeep: 4.5.0
|
||||
node-mocks-http: 1.12.2
|
||||
openapi-types: 12.1.3
|
||||
zod: 3.21.4
|
||||
zod-to-json-schema: 3.21.4(zod@3.21.4)
|
||||
dev: false
|
||||
|
||||
/ts-api-utils@1.0.1(typescript@5.1.6):
|
||||
resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==}
|
||||
engines: {node: '>=16.13.0'}
|
||||
|
@ -5182,6 +5407,14 @@ packages:
|
|||
engines: {node: '>=14.16'}
|
||||
dev: false
|
||||
|
||||
/type-is@1.6.18:
|
||||
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
media-typer: 0.3.0
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/typed-array-buffer@1.0.0:
|
||||
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -5226,6 +5459,10 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/ufo@1.2.0:
|
||||
resolution: {integrity: sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==}
|
||||
dev: false
|
||||
|
||||
/unbox-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
||||
dependencies:
|
||||
|
@ -5235,6 +5472,10 @@ packages:
|
|||
which-boxed-primitive: 1.0.2
|
||||
dev: true
|
||||
|
||||
/uncrypto@0.1.3:
|
||||
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
|
||||
dev: false
|
||||
|
||||
/universal-user-agent@6.0.0:
|
||||
resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==}
|
||||
dev: false
|
||||
|
@ -5249,6 +5490,11 @@ packages:
|
|||
engines: {node: '>= 10.0.0'}
|
||||
dev: false
|
||||
|
||||
/unpipe@1.0.0:
|
||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/untildify@4.0.0:
|
||||
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -5309,6 +5555,11 @@ packages:
|
|||
spdx-expression-parse: 3.0.1
|
||||
dev: false
|
||||
|
||||
/vary@1.1.2:
|
||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/watchpack@2.4.0:
|
||||
resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
@ -5406,6 +5657,14 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/zod-to-json-schema@3.21.4(zod@3.21.4):
|
||||
resolution: {integrity: sha512-fjUZh4nQ1s6HMccgIeE0VP4QG/YRGPmyjO9sAh890aQKPEk3nqbfUXhMFaC+Dr5KvYBm8BCyvfpZf2jY9aGSsw==}
|
||||
peerDependencies:
|
||||
zod: ^3.21.4
|
||||
dependencies:
|
||||
zod: 3.21.4
|
||||
dev: false
|
||||
|
||||
/zod@3.21.4:
|
||||
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||
dev: false
|
||||
|
|
19
src/pages/api/[...trpc].ts
Normal file
19
src/pages/api/[...trpc].ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { createOpenApiNextHandler } from "trpc-openapi";
|
||||
import cors from "nextjs-cors";
|
||||
|
||||
import { appRouter } from "~/server/api/root";
|
||||
import { createTRPCContext } from "~/server/api/trpc";
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
// Setup CORS
|
||||
cors(req, res);
|
||||
|
||||
// Handle incoming OpenAPI requests
|
||||
return createOpenApiNextHandler({
|
||||
router: appRouter,
|
||||
createContext: createTRPCContext,
|
||||
})(req, res);
|
||||
};
|
||||
|
||||
export default handler;
|
10
src/pages/api/openapi.json.ts
Normal file
10
src/pages/api/openapi.json.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
import { openApiDocument } from '../../server/openapi';
|
||||
|
||||
// Respond with our OpenAPI schema
|
||||
const handler = (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.status(200).send(openApiDocument);
|
||||
};
|
||||
|
||||
export default handler;
|
|
@ -1,5 +1,4 @@
|
|||
import { createNextApiHandler } from "@trpc/server/adapters/next";
|
||||
|
||||
import { env } from "~/env.mjs";
|
||||
import { appRouter } from "~/server/api/root";
|
||||
import { createTRPCContext } from "~/server/api/trpc";
|
|
@ -1,12 +1,17 @@
|
|||
import { z } from "zod";
|
||||
import { publishToChannel } from "~/server/ably";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import {
|
||||
adminRateLimitedProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
protectedRateLimitedProcedure,
|
||||
} from "~/server/api/trpc";
|
||||
|
||||
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||
|
||||
export const roomRouter = createTRPCRouter({
|
||||
// Create
|
||||
create: protectedProcedure
|
||||
create: protectedRateLimitedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
|
@ -42,7 +47,7 @@ export const roomRouter = createTRPCRouter({
|
|||
}),
|
||||
|
||||
// Get One
|
||||
get: protectedProcedure
|
||||
get: protectedRateLimitedProcedure
|
||||
.input(z.object({ id: z.string() }))
|
||||
.query(({ ctx, input }) => {
|
||||
return ctx.prisma.room.findUnique({
|
||||
|
@ -63,7 +68,7 @@ export const roomRouter = createTRPCRouter({
|
|||
}),
|
||||
|
||||
// Get All
|
||||
getAll: protectedProcedure.query(async ({ ctx }) => {
|
||||
getAll: protectedRateLimitedProcedure.query(async ({ ctx }) => {
|
||||
const cachedResult = await fetchCache<
|
||||
{
|
||||
id: string;
|
||||
|
@ -92,7 +97,7 @@ export const roomRouter = createTRPCRouter({
|
|||
}
|
||||
}),
|
||||
|
||||
countAll: protectedProcedure.query(async ({ ctx }) => {
|
||||
countAll: adminRateLimitedProcedure.query(async ({ ctx }) => {
|
||||
const cachedResult = await fetchCache<number>(`kv_roomcount_admin`);
|
||||
|
||||
if (cachedResult) {
|
||||
|
@ -107,7 +112,7 @@ export const roomRouter = createTRPCRouter({
|
|||
}),
|
||||
|
||||
// Update One
|
||||
set: protectedProcedure
|
||||
set: protectedRateLimitedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
|
@ -208,7 +213,7 @@ export const roomRouter = createTRPCRouter({
|
|||
}),
|
||||
|
||||
// Delete One
|
||||
delete: protectedProcedure
|
||||
delete: protectedRateLimitedProcedure
|
||||
.input(z.object({ id: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const deletedRoom = await ctx.prisma.room.delete({
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import {
|
||||
adminRateLimitedProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
} from "~/server/api/trpc";
|
||||
import { invalidateCache } from "~/server/redis";
|
||||
|
||||
export const sessionRouter = createTRPCRouter({
|
||||
deleteAllByUserId: protectedProcedure
|
||||
deleteAllByUserId: adminRateLimitedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
userId: z.string(),
|
||||
|
@ -22,7 +26,7 @@ export const sessionRouter = createTRPCRouter({
|
|||
|
||||
return !!sessions;
|
||||
}),
|
||||
deleteAll: protectedProcedure.mutation(async ({ ctx }) => {
|
||||
deleteAll: adminRateLimitedProcedure.mutation(async ({ ctx }) => {
|
||||
const sessions = await ctx.prisma.session.deleteMany();
|
||||
|
||||
if (!!sessions) {
|
||||
|
|
|
@ -3,14 +3,19 @@ import { Resend } from "resend";
|
|||
import { z } from "zod";
|
||||
import { Goodbye } from "~/components/templates/Goodbye";
|
||||
import { env } from "~/env.mjs";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import {
|
||||
adminRateLimitedProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
protectedRateLimitedProcedure,
|
||||
} from "~/server/api/trpc";
|
||||
|
||||
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
|
||||
export const userRouter = createTRPCRouter({
|
||||
countAll: protectedProcedure.query(async ({ ctx }) => {
|
||||
countAll: adminRateLimitedProcedure.query(async ({ ctx }) => {
|
||||
const cachedResult = await fetchCache<number>(`kv_usercount_admin`);
|
||||
|
||||
if (cachedResult) {
|
||||
|
@ -24,7 +29,7 @@ export const userRouter = createTRPCRouter({
|
|||
}
|
||||
}),
|
||||
|
||||
getProviders: protectedProcedure.query(async ({ ctx }) => {
|
||||
getProviders: protectedRateLimitedProcedure.query(async ({ ctx }) => {
|
||||
const providers = await ctx.prisma.user.findUnique({
|
||||
where: {
|
||||
id: ctx.session.user.id,
|
||||
|
@ -42,7 +47,7 @@ export const userRouter = createTRPCRouter({
|
|||
return account.provider;
|
||||
});
|
||||
}),
|
||||
getAll: protectedProcedure.query(async ({ ctx }) => {
|
||||
getAll: protectedRateLimitedProcedure.query(async ({ ctx }) => {
|
||||
const cachedResult = await fetchCache<
|
||||
{
|
||||
accounts: {
|
||||
|
@ -94,7 +99,7 @@ export const userRouter = createTRPCRouter({
|
|||
return users;
|
||||
}
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
delete: protectedRateLimitedProcedure
|
||||
.input(
|
||||
z
|
||||
.object({
|
||||
|
@ -132,7 +137,7 @@ export const userRouter = createTRPCRouter({
|
|||
|
||||
return !!user;
|
||||
}),
|
||||
save: protectedProcedure
|
||||
save: protectedRateLimitedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
|
@ -150,7 +155,7 @@ export const userRouter = createTRPCRouter({
|
|||
|
||||
return !!user;
|
||||
}),
|
||||
setAdmin: protectedProcedure
|
||||
setAdmin: adminRateLimitedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
userId: z.string(),
|
||||
|
@ -172,7 +177,7 @@ export const userRouter = createTRPCRouter({
|
|||
return !!user;
|
||||
}),
|
||||
|
||||
setVIP: protectedProcedure
|
||||
setVIP: adminRateLimitedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
userId: z.string(),
|
||||
|
|
|
@ -2,11 +2,19 @@ import { z } from "zod";
|
|||
import { publishToChannel } from "~/server/ably";
|
||||
|
||||
import type { Room } from "@prisma/client";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import {
|
||||
adminRateLimitedProcedure,
|
||||
createTRPCRouter,
|
||||
protectedRateLimitedProcedure,
|
||||
} from "~/server/api/trpc";
|
||||
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||
|
||||
export const voteRouter = createTRPCRouter({
|
||||
countAll: protectedProcedure.query(async ({ ctx }) => {
|
||||
countAll: adminRateLimitedProcedure
|
||||
.input(z.void())
|
||||
.output(z.number())
|
||||
.meta({ openapi: { method: "GET", path: "/votes/count" } })
|
||||
.query(async ({ ctx }) => {
|
||||
const cachedResult = await fetchCache<number>(`kv_votecount_admin`);
|
||||
|
||||
if (cachedResult) {
|
||||
|
@ -19,7 +27,7 @@ export const voteRouter = createTRPCRouter({
|
|||
return votesCount;
|
||||
}
|
||||
}),
|
||||
getAllByRoomId: protectedProcedure
|
||||
getAllByRoomId: protectedRateLimitedProcedure
|
||||
.input(z.object({ roomId: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const cachedResult = await fetchCache<
|
||||
|
@ -63,7 +71,7 @@ export const voteRouter = createTRPCRouter({
|
|||
return votesByRoomId;
|
||||
}
|
||||
}),
|
||||
set: protectedProcedure
|
||||
set: protectedRateLimitedProcedure
|
||||
.input(z.object({ value: z.string(), roomId: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const vote = await ctx.prisma.vote.upsert({
|
||||
|
|
|
@ -22,6 +22,7 @@ import { prisma } from "~/server/db";
|
|||
|
||||
type CreateContextOptions = {
|
||||
session: Session | null;
|
||||
ip: string | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -37,6 +38,7 @@ type CreateContextOptions = {
|
|||
const createInnerTRPCContext = (opts: CreateContextOptions) => {
|
||||
return {
|
||||
session: opts.session,
|
||||
ip: opts.ip,
|
||||
prisma,
|
||||
};
|
||||
};
|
||||
|
@ -54,6 +56,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
|||
const session = await getServerAuthSession({ req, res });
|
||||
|
||||
return createInnerTRPCContext({
|
||||
ip: req.socket.remoteAddress,
|
||||
session,
|
||||
});
|
||||
};
|
||||
|
@ -64,17 +67,21 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
|||
* This is where the tRPC API is initialized, connecting the context and transformer.
|
||||
*/
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
import { OpenApiMeta } from "trpc-openapi";
|
||||
import { Ratelimit } from "@upstash/ratelimit";
|
||||
import superjson from "superjson";
|
||||
import { env } from "~/env.mjs";
|
||||
import { Redis } from "@upstash/redis";
|
||||
|
||||
const t = initTRPC.context<typeof createTRPCContext>().create({
|
||||
const t = initTRPC
|
||||
.meta<OpenApiMeta>()
|
||||
.context<typeof createTRPCContext>()
|
||||
.create({
|
||||
transformer: superjson,
|
||||
errorFormatter({ shape }) {
|
||||
return shape;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 3. ROUTER & PROCEDURE (THE IMPORTANT BIT)
|
||||
|
@ -100,12 +107,20 @@ export const createTRPCRouter = t.router;
|
|||
export const publicProcedure = t.procedure;
|
||||
|
||||
/** Reusable middleware that enforces users are logged in before running the procedure. */
|
||||
const enforceRouteProtection = t.middleware(async ({ ctx, next }) => {
|
||||
const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
|
||||
// Auth
|
||||
if (!ctx.session || !ctx.session.user) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
|
||||
return next({
|
||||
ctx: {
|
||||
session: { ...ctx.session, user: ctx.session.user },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const enforceRateLimit = t.middleware(async ({ ctx, next }) => {
|
||||
const rateLimit = new Ratelimit({
|
||||
redis: Redis.fromEnv(),
|
||||
limiter: Ratelimit.slidingWindow(
|
||||
|
@ -114,13 +129,21 @@ const enforceRouteProtection = t.middleware(async ({ ctx, next }) => {
|
|||
),
|
||||
analytics: true,
|
||||
});
|
||||
|
||||
console.log(`${env.APP_ENV}_${ctx.session?.user.id || ctx.ip}`);
|
||||
console.log(ctx.ip);
|
||||
const { success } = await rateLimit.limit(
|
||||
`${env.APP_ENV}_${ctx.session.user.id}`
|
||||
`${env.APP_ENV}_${ctx.session?.user.id || ctx.ip}`
|
||||
);
|
||||
|
||||
if (!success) throw new TRPCError({ code: "TOO_MANY_REQUESTS" });
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
const enforceAdminRole = t.middleware(async ({ ctx, next }) => {
|
||||
if (!ctx.session || !ctx.session.user || !ctx.session?.user.isAdmin)
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
|
||||
return next({
|
||||
ctx: {
|
||||
session: { ...ctx.session, user: ctx.session.user },
|
||||
|
@ -136,4 +159,13 @@ const enforceRouteProtection = t.middleware(async ({ ctx, next }) => {
|
|||
*
|
||||
* @see https://trpc.io/docs/procedures
|
||||
*/
|
||||
export const protectedProcedure = t.procedure.use(enforceRouteProtection);
|
||||
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
|
||||
|
||||
export const protectedRateLimitedProcedure =
|
||||
protectedProcedure.use(enforceRateLimit);
|
||||
|
||||
export const publicRateLimitedProcedure = publicProcedure.use(enforceRateLimit);
|
||||
|
||||
export const adminProcedure = t.procedure.use(enforceAdminRole);
|
||||
|
||||
export const adminRateLimitedProcedure = adminProcedure.use(enforceAdminRole);
|
||||
|
|
12
src/server/openapi.ts
Normal file
12
src/server/openapi.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { generateOpenApiDocument } from 'trpc-openapi';
|
||||
|
||||
import { appRouter } from './api/root';
|
||||
|
||||
// Generate OpenAPI schema document
|
||||
export const openApiDocument = generateOpenApiDocument(appRouter, {
|
||||
title: 'Example CRUD API',
|
||||
description: 'OpenAPI compliant REST API built using tRPC with Next.js',
|
||||
version: '1.0.0',
|
||||
baseUrl: 'http://localhost:3000/api',
|
||||
docsUrl: 'https://github.com/jlalmes/trpc-openapi',
|
||||
});
|
Loading…
Add table
Reference in a new issue