refactor: migrate monorepo from pnpm to Bun runtime and workspaces
- root: bun workspaces via package.json, packageManager bun@1.4.0, scripts use bun --filter - backend: Bun.serve, bun test (vitest removed), bun --watch dev script, tsconfig types bun - tests: migrate 6 test files from vitest to bun:test (mock.module) - validate: replace @hono/zod-validator with hono validator + zod safeParse (fixes TS2589) - lockfile: bunfig.toml saveTextLockfile, regenerated bun.lock (text) for turbo - docs: AGENTS.md, README.md, stack.md updated to Bun stack
This commit is contained in:
@@ -1,57 +1,62 @@
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import type { Context } from 'hono';
|
||||
import type { ZodIssue, ZodSchema } from 'zod';
|
||||
import type { Context, MiddlewareHandler } from 'hono';
|
||||
import { validator } from 'hono/validator';
|
||||
import type { ZodTypeAny, z } from 'zod';
|
||||
import { validationProblem } from './problem-builders';
|
||||
import { zodIssuesToRecord } from './zod-issues';
|
||||
|
||||
type ValidationTarget = 'json' | 'query' | 'param' | 'header' | 'form';
|
||||
|
||||
function makeValidator(target: ValidationTarget, schema: ZodSchema) {
|
||||
return zValidator(
|
||||
target,
|
||||
schema,
|
||||
(result: { success: boolean; error?: { issues: ZodIssue[] } }, c: Context) => {
|
||||
if (result.success) {
|
||||
return;
|
||||
}
|
||||
type ValidationInput<S extends ZodTypeAny, T extends ValidationTarget> = {
|
||||
out: { [K in T]: z.output<S> };
|
||||
};
|
||||
|
||||
const requestId = c.get('requestId');
|
||||
const instance = requestId ? `/requests/${requestId}` : undefined;
|
||||
const issues = result.error?.issues ?? [];
|
||||
function makeValidator<S extends ZodTypeAny, T extends ValidationTarget>(
|
||||
target: T,
|
||||
schema: S,
|
||||
): MiddlewareHandler<{}, string, ValidationInput<S, T>> {
|
||||
const middleware = validator(target, (value: unknown, c: Context) => {
|
||||
const result = schema.safeParse(value);
|
||||
|
||||
return c.json(
|
||||
validationProblem({
|
||||
detail: `Invalid ${target} data`,
|
||||
instance,
|
||||
errors: zodIssuesToRecord(issues),
|
||||
}),
|
||||
400,
|
||||
{
|
||||
'Content-Type': 'application/problem+json',
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
if (result.success) {
|
||||
return result.data;
|
||||
}
|
||||
|
||||
const requestId = c.get('requestId');
|
||||
const instance = requestId ? `/requests/${requestId}` : undefined;
|
||||
|
||||
return c.json(
|
||||
validationProblem({
|
||||
detail: `Invalid ${target} data`,
|
||||
instance,
|
||||
errors: zodIssuesToRecord(result.error.issues),
|
||||
}),
|
||||
400,
|
||||
{
|
||||
'Content-Type': 'application/problem+json',
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
return middleware as unknown as MiddlewareHandler<{}, string, ValidationInput<S, T>>;
|
||||
}
|
||||
|
||||
export const validate = {
|
||||
json(schema: ZodSchema) {
|
||||
json<S extends ZodTypeAny>(schema: S) {
|
||||
return makeValidator('json', schema);
|
||||
},
|
||||
|
||||
query(schema: ZodSchema) {
|
||||
query<S extends ZodTypeAny>(schema: S) {
|
||||
return makeValidator('query', schema);
|
||||
},
|
||||
|
||||
param(schema: ZodSchema) {
|
||||
param<S extends ZodTypeAny>(schema: S) {
|
||||
return makeValidator('param', schema);
|
||||
},
|
||||
|
||||
header(schema: ZodSchema) {
|
||||
header<S extends ZodTypeAny>(schema: S) {
|
||||
return makeValidator('header', schema);
|
||||
},
|
||||
|
||||
form(schema: ZodSchema) {
|
||||
form<S extends ZodTypeAny>(schema: S) {
|
||||
return makeValidator('form', schema);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dotenv/config';
|
||||
import { type Prisma, PrismaClient } from '@generated/prisma/client';
|
||||
import type { Result } from '@gruperly/shared';
|
||||
import { PrismaPg } from '@prisma/adapter-pg';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dotenv/config';
|
||||
import { serve } from '@hono/node-server';
|
||||
import app from '@/app';
|
||||
import { getPrismaClient } from '@/lib/prisma';
|
||||
import { logger } from '@/logger';
|
||||
@@ -8,22 +6,13 @@ const port = Number(process.env.PORT ?? 4000);
|
||||
|
||||
logger.info(`Server running on http://localhost:${port}`);
|
||||
|
||||
const server = serve({
|
||||
fetch: app.fetch,
|
||||
const server = Bun.serve({
|
||||
port,
|
||||
fetch: app.fetch,
|
||||
});
|
||||
|
||||
async function shutdown(): Promise<void> {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.close((error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
server.stop(true);
|
||||
await getPrismaClient().$disconnect();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user