same-codebase.demo
↓ Callers
↓ Dependencies
api/users.ts
1export async function list(req) {
2 const sess = await authenticate(req)
3 return db.users.all(sess.uid)
api/posts.ts
1export async function feed(req) {
2 const sess = await authenticate(req)
3 return db.posts.feed(sess.uid)
api/comments.ts
1export async function get(req) {
2 const sess = await authenticate(req)
3 return db.comments.for(req.postId)
auth/middleware.ts
1import { verifyToken } from './token'
2import { getSession } from './session'
3import { rateLimit } from '../utils/rate-limit'
4
5export async function authenticate(req) {
6 const token = req.headers.authorization
7 if (!token) throw new Unauthorized()
8
9 await rateLimit(req.ip)
10 const claims = await verifyToken(token)
11 const session = await getSession(claims.sid)
12 return session
13}
utils/rate-limit.ts
1const LIMIT = 100
2
3export async function rateLimit(ip) {
4 const n = await redis.incr(`rl:${ip}`)
5 if (n > LIMIT) throw new RateLimited()
6}
auth/token.ts
1export async function verifyToken(t) {
2 const { payload, sig } = parse(t)
3 const ok = await verify(payload, sig)
4 if (!ok) throw new Unauthorized()
5 return payload as Claims
6}
auth/session.ts
1export async function getSession(sid) {
2 const row = await db.sessions.find({ sid })
3 if (!row) throw new Unauthorized()
4 if (row.exp < Date.now())
5 throw new SessionExpired()
6 return row as Session
Every API route must call authenticate() — it's what enforces auth and rate-limit.
↑ same codebase
30 tabs. No map. Where does this call go?