Skip to content

Commit 8ee6f5f

Browse files
committed
feat: add tRPC and Drizzle ORM integration
1 parent 3a387f5 commit 8ee6f5f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+5887
-6624
lines changed

.editorconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ root = true
55
[*]
66
charset = utf-8
77
indent_style = space
8-
indent_size = 2
8+
# https://github.com/microsoft/vscode/issues/6447#issuecomment-221075881
9+
# indent_size = 2
910
end_of_line = lf
1011
insert_final_newline = true
1112
trim_trailing_whitespace = true

backend/.env.example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
SUPABASE_URL=
2-
SUPABASE_KEY=
3-
DATABASE_URL=
1+
PUBLIC_SUPABASE_URL=
2+
SUPABASE_ANON_KEY=
3+
POSTGRES_URL=

backend/app.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,64 @@
11
import type { ErrorRequestHandler, NextFunction, Request, Response } from 'express'
22

3+
import * as trpcExpress from '@trpc/server/adapters/express'
34
import cookieParser from 'cookie-parser'
45
import cors from 'cors'
56
import Debug from 'debug'
67
import express from 'express'
78
import createError from 'http-errors'
89
import logger from 'morgan'
910
import { createServer } from 'node:http'
10-
import path from 'node:path'
1111
import process from 'node:process'
1212
import { fileURLToPath } from 'node:url'
13+
import { dirname, join } from 'pathe'
1314

15+
import { userRouter } from './src/routes/auth.js'
1416
import routes from './src/routes/index.js'
17+
import { router } from './src/routes/trpc.js'
1518

1619
const __filename = fileURLToPath(import.meta.url)
17-
const __dirname = path.dirname(__filename)
20+
const __dirname = dirname(__filename)
21+
22+
function createContext({
23+
req,
24+
res,
25+
}: trpcExpress.CreateExpressContextOptions) {
26+
return {}
27+
}
28+
type Context = Awaited<ReturnType<typeof createContext>>
1829

1930
const app = express()
2031

2132
app.use(cors({
33+
origin: true,
2234
credentials: true,
2335
exposedHeaders: ['set-cookie'],
2436
}))
2537

26-
app.set('views', path.join(__dirname, 'views'))
27-
app.set('view engine', 'hbs')
38+
export const appRouter = router({
39+
user: userRouter,
40+
})
41+
42+
export type AppRouter = typeof appRouter
43+
44+
app.use(
45+
'/trpc',
46+
trpcExpress.createExpressMiddleware({
47+
router: appRouter,
48+
createContext,
49+
}),
50+
)
2851

2952
app.use(logger('dev'))
3053
app.use(express.json())
3154
app.use(express.urlencoded({ extended: false }))
3255
// need cookieParser middleware before we can do anything with cookies
3356
app.use(cookieParser())
3457
// let static middleware do its job
35-
app.use(express.static(path.join(__dirname, 'public')))
58+
app.use(express.static(join(__dirname, 'public')))
3659

3760
app.use('/', routes)
61+
app.get(/favicon.*/, (req, res) => res.status(204).end())
3862

3963
// catch 404 and forward to error handler
4064
app.use(function (req, res, next) {
@@ -46,9 +70,8 @@ app.use(function (err: Parameters<ErrorRequestHandler>[0], req: Request, res: Re
4670
res.locals.message = err.message
4771
res.locals.error = req.app.get('env') === 'development' ? err : {}
4872

49-
// render the error page
5073
res.status(err.status || 500)
51-
res.render('error')
74+
res.send('error')
5275
})
5376

5477
const PORT = Number(process.env.PORT || '5001')
@@ -70,12 +93,10 @@ server.on('error', function onError(error: NodeJS.ErrnoException) {
7093
switch (error.code) {
7194
case 'EACCES':
7295
console.error(bind + ' requires elevated privileges')
73-
process.exit(1)
74-
break
96+
throw error
7597
case 'EADDRINUSE':
7698
console.error(bind + ' is already in use')
77-
process.exit(1)
78-
break
99+
throw error
79100
default:
80101
throw error
81102
}

backend/drizzle.config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { defineConfig } from 'drizzle-kit'
2+
3+
import { env } from './env'
4+
5+
export default defineConfig({
6+
schemaFilter: ['auth', 'public'],
7+
dialect: 'postgresql',
8+
out: './drizzle',
9+
schema: './drizzle/schema.ts',
10+
dbCredentials: {
11+
url: env.POSTGRES_URL,
12+
},
13+
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{
2+
}

backend/drizzle/meta/_journal.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"version": "7",
3+
"dialect": "postgresql",
4+
"entries": []
5+
}

backend/drizzle/relations.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { relations } from "drizzle-orm/relations";
2+
import { flowStateInAuth, samlRelayStatesInAuth, ssoProvidersInAuth, ssoDomainsInAuth, mfaFactorsInAuth, mfaChallengesInAuth, sessionsInAuth, mfaAmrClaimsInAuth, samlProvidersInAuth, usersInAuth, oneTimeTokensInAuth, refreshTokensInAuth, identitiesInAuth, userVocabRecord, profiles } from "./schema";
3+
4+
export const samlRelayStatesInAuthRelations = relations(samlRelayStatesInAuth, ({one}) => ({
5+
flowStateInAuth: one(flowStateInAuth, {
6+
fields: [samlRelayStatesInAuth.flowStateId],
7+
references: [flowStateInAuth.id]
8+
}),
9+
ssoProvidersInAuth: one(ssoProvidersInAuth, {
10+
fields: [samlRelayStatesInAuth.ssoProviderId],
11+
references: [ssoProvidersInAuth.id]
12+
}),
13+
}));
14+
15+
export const flowStateInAuthRelations = relations(flowStateInAuth, ({many}) => ({
16+
samlRelayStatesInAuths: many(samlRelayStatesInAuth),
17+
}));
18+
19+
export const ssoProvidersInAuthRelations = relations(ssoProvidersInAuth, ({many}) => ({
20+
samlRelayStatesInAuths: many(samlRelayStatesInAuth),
21+
ssoDomainsInAuths: many(ssoDomainsInAuth),
22+
samlProvidersInAuths: many(samlProvidersInAuth),
23+
}));
24+
25+
export const ssoDomainsInAuthRelations = relations(ssoDomainsInAuth, ({one}) => ({
26+
ssoProvidersInAuth: one(ssoProvidersInAuth, {
27+
fields: [ssoDomainsInAuth.ssoProviderId],
28+
references: [ssoProvidersInAuth.id]
29+
}),
30+
}));
31+
32+
export const mfaChallengesInAuthRelations = relations(mfaChallengesInAuth, ({one}) => ({
33+
mfaFactorsInAuth: one(mfaFactorsInAuth, {
34+
fields: [mfaChallengesInAuth.factorId],
35+
references: [mfaFactorsInAuth.id]
36+
}),
37+
}));
38+
39+
export const mfaFactorsInAuthRelations = relations(mfaFactorsInAuth, ({one, many}) => ({
40+
mfaChallengesInAuths: many(mfaChallengesInAuth),
41+
usersInAuth: one(usersInAuth, {
42+
fields: [mfaFactorsInAuth.userId],
43+
references: [usersInAuth.id]
44+
}),
45+
}));
46+
47+
export const mfaAmrClaimsInAuthRelations = relations(mfaAmrClaimsInAuth, ({one}) => ({
48+
sessionsInAuth: one(sessionsInAuth, {
49+
fields: [mfaAmrClaimsInAuth.sessionId],
50+
references: [sessionsInAuth.id]
51+
}),
52+
}));
53+
54+
export const sessionsInAuthRelations = relations(sessionsInAuth, ({one, many}) => ({
55+
mfaAmrClaimsInAuths: many(mfaAmrClaimsInAuth),
56+
refreshTokensInAuths: many(refreshTokensInAuth),
57+
usersInAuth: one(usersInAuth, {
58+
fields: [sessionsInAuth.userId],
59+
references: [usersInAuth.id]
60+
}),
61+
}));
62+
63+
export const samlProvidersInAuthRelations = relations(samlProvidersInAuth, ({one}) => ({
64+
ssoProvidersInAuth: one(ssoProvidersInAuth, {
65+
fields: [samlProvidersInAuth.ssoProviderId],
66+
references: [ssoProvidersInAuth.id]
67+
}),
68+
}));
69+
70+
export const oneTimeTokensInAuthRelations = relations(oneTimeTokensInAuth, ({one}) => ({
71+
usersInAuth: one(usersInAuth, {
72+
fields: [oneTimeTokensInAuth.userId],
73+
references: [usersInAuth.id]
74+
}),
75+
}));
76+
77+
export const usersInAuthRelations = relations(usersInAuth, ({many}) => ({
78+
oneTimeTokensInAuths: many(oneTimeTokensInAuth),
79+
identitiesInAuths: many(identitiesInAuth),
80+
sessionsInAuths: many(sessionsInAuth),
81+
mfaFactorsInAuths: many(mfaFactorsInAuth),
82+
userVocabRecords: many(userVocabRecord),
83+
profiles: many(profiles),
84+
}));
85+
86+
export const refreshTokensInAuthRelations = relations(refreshTokensInAuth, ({one}) => ({
87+
sessionsInAuth: one(sessionsInAuth, {
88+
fields: [refreshTokensInAuth.sessionId],
89+
references: [sessionsInAuth.id]
90+
}),
91+
}));
92+
93+
export const identitiesInAuthRelations = relations(identitiesInAuth, ({one}) => ({
94+
usersInAuth: one(usersInAuth, {
95+
fields: [identitiesInAuth.userId],
96+
references: [usersInAuth.id]
97+
}),
98+
}));
99+
100+
export const userVocabRecordRelations = relations(userVocabRecord, ({one}) => ({
101+
usersInAuth: one(usersInAuth, {
102+
fields: [userVocabRecord.userId],
103+
references: [usersInAuth.id]
104+
}),
105+
}));
106+
107+
export const profilesRelations = relations(profiles, ({one}) => ({
108+
usersInAuth: one(usersInAuth, {
109+
fields: [profiles.id],
110+
references: [usersInAuth.id]
111+
}),
112+
}));

0 commit comments

Comments
 (0)