refactor: move into api/db packages

This commit is contained in:
Henry
2026-01-25 22:01:49 +00:00
parent 327089e10e
commit 4353b9620b
17 changed files with 32 additions and 27 deletions

View File

@@ -48,14 +48,12 @@
"@trpc/server": "catalog:",
"date-fns": "^4.1.0",
"geist": "^1.3.1",
"ioredis": "^5.9.2",
"jose": "^6.1.2",
"next": "15.5.9",
"next-runtime-env": "^1.7.2",
"next-themes": "^0.4.6",
"nextjs-cors": "^2.2.0",
"posthog-js": "^1.254.0",
"rate-limiter-flexible": "^9.0.1",
"react": "catalog:react18",
"react-beautiful-dnd": "^13.1.1",
"react-contenteditable": "^3.3.7",

View File

@@ -2,7 +2,7 @@ import { toNodeHandler } from "better-auth/node";
import { initAuth } from "@kan/auth/server";
import { createDrizzleClient } from "@kan/db/client";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export const config = { api: { bodyParser: false } };

View File

@@ -1,6 +1,6 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },

View File

@@ -1,6 +1,6 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },

View File

@@ -3,7 +3,7 @@ import { env } from "next-runtime-env";
import { createNextApiContext } from "@kan/api/trpc";
import { createStripeClient } from "@kan/stripe";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },

View File

@@ -6,7 +6,7 @@ import { createNextApiContext } from "@kan/api/trpc";
import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { createStripeClient } from "@kan/stripe";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const workspaceSlugSchema = z
.string()

View File

@@ -3,7 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
import { createNextApiContext } from "@kan/api/trpc";
import { integrations } from "@kan/db/schema";
import { addYears } from "date-fns";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },

View File

@@ -4,7 +4,7 @@ import { createNextApiHandler } from "@trpc/server/adapters/next";
import { appRouter } from "@kan/api/root";
import { createTRPCContext } from "@kan/api/trpc";
import { env } from "~/env";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const nextApiHandler = createNextApiHandler({
router: appRouter,

View File

@@ -4,7 +4,7 @@ import { jwtVerify } from "jose";
import { z } from "zod";
import { env } from "~/env";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const requestSchema = z.object({
token: z.string().min(1),

View File

@@ -6,7 +6,7 @@ import { env as nextRuntimeEnv } from "next-runtime-env";
import { createNextApiContext } from "@kan/api/trpc";
import { env } from "~/env";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
const allowedContentTypes = ["image/jpeg", "image/png"];

View File

@@ -6,7 +6,7 @@ import { appRouter } from "@kan/api";
import { createRESTContext } from "@kan/api/trpc";
import { env } from "~/env";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { openApiDocument } from "@kan/api/openapi";
import { withRateLimit } from "~/utils/rateLimit";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },

View File

@@ -23,6 +23,10 @@
"./openapi": {
"types": "./dist/openapi.d.ts",
"default": "./src/openapi.ts"
},
"./utils/rateLimit": {
"types": "./dist/utils/rateLimit.d.ts",
"default": "./src/utils/rateLimit.ts"
}
},
"license": "GPL-3.0",
@@ -43,6 +47,7 @@
"@kan/shared": "workspace:^",
"@kan/stripe": "workspace:^",
"@trpc/server": "catalog:",
"rate-limiter-flexible": "^9.0.1",
"superjson": "2.2.1",
"trpc-to-openapi": "^2.3.2",
"zod": "catalog:"

View File

@@ -4,7 +4,7 @@ import {
RateLimiterMemory,
} from "rate-limiter-flexible";
import { getRedisClient } from "./redis";
import { getRedisClient } from "@kan/db/redis";
export interface RateLimitOptions {
points?: number;
@@ -13,7 +13,6 @@ export interface RateLimitOptions {
errorMessage?: string;
}
const defaultIdentifier = (req: NextApiRequest): string => {
// Try to identify the IP address of the request
const forwardedFor = req.headers["x-forwarded-for"];
@@ -32,7 +31,6 @@ const defaultIdentifier = (req: NextApiRequest): string => {
return ip;
};
const DEFAULT_OPTIONS = {
points: 100,
duration: 60,
@@ -40,7 +38,6 @@ const DEFAULT_OPTIONS = {
identifier: defaultIdentifier,
} as const;
function createRateLimiter(options: RateLimitOptions = {}) {
const redis = getRedisClient();
const points = options.points ?? DEFAULT_OPTIONS.points;
@@ -48,6 +45,7 @@ function createRateLimiter(options: RateLimitOptions = {}) {
// Use Redis if available, otherwise fall back to in-memory storage
if (redis) {
console.log("Using Redis for rate limiting");
return new RateLimiterRedis({
storeClient: redis,
points,
@@ -55,6 +53,7 @@ function createRateLimiter(options: RateLimitOptions = {}) {
});
}
console.log("Using in-memory for rate limiting");
return new RateLimiterMemory({
points,
duration,
@@ -97,3 +96,4 @@ export function withRateLimit(
}
};
}

View File

@@ -23,6 +23,10 @@
"./repository/*": {
"types": "./dist/repository/*.d.ts",
"default": "./src/repository/*.ts"
},
"./redis": {
"types": "./dist/redis.d.ts",
"default": "./src/redis.ts"
}
},
"license": "GPL-3.0",
@@ -43,6 +47,7 @@
"@kan/shared": "workspace:^",
"drizzle-orm": "^0.42.0",
"drizzle-zod": "^0.5.1",
"ioredis": "^5.9.2",
"pg": "^8.11.3",
"uuid": "^11.1.0",
"zod": "catalog:"

View File

@@ -1,7 +1,5 @@
import Redis from "ioredis";
import { env } from "~/env";
let redisClient: Redis | null = null;
export function getRedisClient(): Redis | null {
@@ -9,7 +7,7 @@ export function getRedisClient(): Redis | null {
return redisClient;
}
const redisUrl = env.REDIS_URL;
const redisUrl = process.env.REDIS_URL;
if (!redisUrl) {
return null;
@@ -31,4 +29,3 @@ export async function closeRedisClient(): Promise<void> {
}
}

12
pnpm-lock.yaml generated
View File

@@ -166,9 +166,6 @@ importers:
geist:
specifier: ^1.3.1
version: 1.4.2(next@15.5.9(@babel/core@7.28.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
ioredis:
specifier: ^5.9.2
version: 5.9.2
jose:
specifier: ^6.1.2
version: 6.1.2
@@ -187,9 +184,6 @@ importers:
posthog-js:
specifier: ^1.254.0
version: 1.261.0
rate-limiter-flexible:
specifier: ^9.0.1
version: 9.0.1
react:
specifier: catalog:react18
version: 18.3.1
@@ -320,6 +314,9 @@ importers:
'@trpc/server':
specifier: 'catalog:'
version: 11.5.0(typescript@5.9.2)
rate-limiter-flexible:
specifier: ^9.0.1
version: 9.0.1
superjson:
specifier: 2.2.1
version: 2.2.1
@@ -403,6 +400,9 @@ importers:
drizzle-zod:
specifier: ^0.5.1
version: 0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@types/pg@8.15.5)(kysely@0.28.8)(pg@8.16.3))(zod@3.25.76)
ioredis:
specifier: ^5.9.2
version: 5.9.2
pg:
specifier: ^8.11.3
version: 8.16.3