trpc: add context, middleware

This commit is contained in:
vchikalkin 2023-03-19 16:09:10 +03:00
parent 8994cd8ec8
commit 9696ced8c2
11 changed files with 91 additions and 4 deletions

6
.env
View File

@ -9,4 +9,8 @@ USERS_SUPER=["akalinina","vchikalkin"]
URL_GET_USER_DIRECT=
URL_CRM_GRAPHQL_DIRECT=
URL_CORE_FINGAP_DIRECT=
URL_1C_TRANSTAX_DIRECT=
URL_1C_TRANSTAX_DIRECT=
####### SERVER ########
# DEFAULT: 'token'
COOKIE_TOKEN_NAME=

View File

@ -2,6 +2,7 @@ const { z } = require('zod');
const envSchema = z.object({
BASE_PATH: z.string().optional().default(''),
COOKIE_TOKEN_NAME: z.string().optional().default('token'),
PORT: z.string().optional(),
URL_1C_TRANSTAX_DIRECT: z.string(),
URL_CORE_FINGAP_DIRECT: z.string(),

View File

@ -8,6 +8,7 @@ const publicRuntimeConfigSchema = envSchema.pick({
const serverRuntimeConfigSchema = envSchema.pick({
BASE_PATH: true,
COOKIE_TOKEN_NAME: true,
PORT: true,
URL_1C_TRANSTAX_DIRECT: true,
URL_CORE_FINGAP_DIRECT: true,

12
apps/web/config/server.js Normal file
View File

@ -0,0 +1,12 @@
import { serverRuntimeConfigSchema } from './schema/runtime-config';
import getConfig from 'next/config';
const { serverRuntimeConfig } = getConfig();
function getServerConfig() {
const { COOKIE_TOKEN_NAME } = serverRuntimeConfigSchema.parse(serverRuntimeConfig);
return { COOKIE_TOKEN_NAME };
}
export default getServerConfig;

View File

@ -21,7 +21,9 @@
"@trpc/react-query": "^10.13.0",
"@trpc/server": "^10.13.0",
"axios": "^1.3.4",
"cookies-next": "^2.1.1",
"dayjs": "^1.11.7",
"jwt-decode": "^3.1.2",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mobx": "^6.8.0",

View File

@ -1,8 +1,9 @@
/* eslint-disable canonical/filename-match-regex */
import { createContext } from '@/trpc/context';
import appRouter from '@/trpc/routers';
import * as trpcNext from '@trpc/server/adapters/next';
export default trpcNext.createNextApiHandler({
createContext: () => ({}),
createContext,
router: appRouter,
});

16
apps/web/trpc/context.ts Normal file
View File

@ -0,0 +1,16 @@
import getServerConfig from '@/config/server';
import type { inferAsyncReturnType } from '@trpc/server';
import type { CreateNextContextOptions } from '@trpc/server/adapters/next';
import { getCookie } from 'cookies-next';
const { COOKIE_TOKEN_NAME } = getServerConfig();
export async function createContext({ req, res }: CreateNextContextOptions) {
const token = getCookie(COOKIE_TOKEN_NAME, { req, res });
return {
token,
};
}
export type Context = inferAsyncReturnType<typeof createContext>;

View File

@ -0,0 +1,28 @@
import { t } from './server';
import { TRPCError } from '@trpc/server';
import jwtDecode from 'jwt-decode';
type TokenPayload = {
domain: string;
username: string;
};
export const user = t.middleware(async ({ ctx, next }) => {
if (ctx.token === undefined || ctx.token === null || typeof ctx.token !== 'string') {
throw new TRPCError({
code: 'UNAUTHORIZED',
});
}
const decoded = jwtDecode<TokenPayload>(ctx.token);
const domainName = `${decoded.domain}\\${decoded.username}`;
return next({
ctx: {
user: {
...decoded,
domainName,
},
},
});
});

View File

@ -1,3 +1,4 @@
import { user } from '../../middleware';
import { t } from '../../server';
import { CalculateInputSchema, CalculateOutputSchema } from './types';
import { validate } from './validation';
@ -6,6 +7,7 @@ import { QueryClient } from '@tanstack/react-query';
const calculateRouter = t.router({
calculate: t.procedure
.use(user)
.input(CalculateInputSchema)
.output(CalculateOutputSchema)
.query(async ({ input }) => {

View File

@ -1,6 +1,7 @@
import type { Context } from './context';
import { initTRPC } from '@trpc/server';
import SuperJSON from 'superjson';
export const t = initTRPC.create({
export const t = initTRPC.context<Context>().create({
transformer: SuperJSON,
});

View File

@ -2112,6 +2112,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.2.tgz#c076ed1d7b6095078ad3cf21dfeea951842778b1"
integrity sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==
"@types/node@^16.10.2":
version "16.18.16"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.16.tgz#09ff98b144abae2d7cce3e9fe9040ab2bf73222c"
integrity sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
@ -3369,11 +3374,20 @@ convert-source-map@^2.0.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
cookie@^0.4.2:
cookie@^0.4.0, cookie@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookies-next@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cookies-next/-/cookies-next-2.1.1.tgz#8d82f1b78fccfb19d9d7c26766fa5707a3ec4695"
integrity sha512-AZGZPdL1hU3jCjN2UMJTGhLOYzNUN9Gm+v8BdptYIHUdwz397Et1p+sZRfvAl8pKnnmMdX2Pk9xDRKCGBum6GA==
dependencies:
"@types/cookie" "^0.4.1"
"@types/node" "^16.10.2"
cookie "^0.4.0"
copy-anything@^2.0.1:
version "2.0.6"
resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
@ -6494,6 +6508,11 @@ jws@^3.2.2:
jwa "^1.4.1"
safe-buffer "^5.0.1"
jwt-decode@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
keyv@^4.5.2:
version "4.5.2"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56"