fix: resolve OpenAPI 500 error caused by BigInt serialization in stopGracePeriodSwarm

Change Drizzle column mode from "bigint" to "number" for stopGracePeriodSwarm
across all 6 service schemas. This fixes JSON.stringify failing silently in the
@dokploy/trpc-openapi adapter, which unlike the tRPC endpoint does not use
superjson and cannot serialize BigInt values.

No database migration needed — only the JS representation changes. The values
are nanosecond grace periods that fit safely within Number.MAX_SAFE_INTEGER.

Also adds onError logging and export const config to the OpenAPI route handler
to match the tRPC route and improve debuggability.

Fixes #3793
This commit is contained in:
Vibe Code
2026-02-25 00:20:25 +01:00
parent 9d09e51cf7
commit d7886fb7c9
11 changed files with 38 additions and 30 deletions

View File

@@ -57,7 +57,7 @@ const createApplication = (
env: null,
},
replicas: 1,
stopGracePeriodSwarm: 0n,
stopGracePeriodSwarm: 0,
ulimitsSwarm: null,
serverId: "server-id",
...overrides,
@@ -76,8 +76,8 @@ describe("mechanizeDockerContainer", () => {
});
});
it("converts bigint stopGracePeriodSwarm to a number and keeps zero values", async () => {
const application = createApplication({ stopGracePeriodSwarm: 0n });
it("passes stopGracePeriodSwarm as a number and keeps zero values", async () => {
const application = createApplication({ stopGracePeriodSwarm: 0 });
await mechanizeDockerContainer(application);

View File

@@ -112,7 +112,7 @@ const menuItems: MenuItem[] = [
const hasStopGracePeriodSwarm = (
value: unknown,
): value is { stopGracePeriodSwarm: bigint | number | string | null } =>
): value is { stopGracePeriodSwarm: number | string | null } =>
typeof value === "object" &&
value !== null &&
"stopGracePeriodSwarm" in value;

View File

@@ -16,7 +16,7 @@ import { api } from "@/utils/api";
const hasStopGracePeriodSwarm = (
value: unknown,
): value is { stopGracePeriodSwarm: bigint | number | string | null } =>
): value is { stopGracePeriodSwarm: number | string | null } =>
typeof value === "object" &&
value !== null &&
"stopGracePeriodSwarm" in value;
@@ -59,7 +59,7 @@ export const StopGracePeriodForm = ({ id, type }: StopGracePeriodFormProps) => {
const form = useForm<any>({
defaultValues: {
value: null as bigint | null,
value: null as number | null,
},
});
@@ -69,9 +69,7 @@ export const StopGracePeriodForm = ({ id, type }: StopGracePeriodFormProps) => {
const normalizedValue =
value === null || value === undefined
? null
: typeof value === "bigint"
? value
: BigInt(value);
: Number(value);
form.reset({
value: normalizedValue,
});
@@ -126,7 +124,7 @@ export const StopGracePeriodForm = ({ id, type }: StopGracePeriodFormProps) => {
}
onChange={(e) =>
field.onChange(
e.target.value ? BigInt(e.target.value) : null,
e.target.value ? Number(e.target.value) : null,
)
}
/>

View File

@@ -16,7 +16,22 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return createOpenApiNextHandler({
router: appRouter,
createContext: createTRPCContext,
onError:
process.env.NODE_ENV === "development"
? ({ path, error }: { path: string | undefined; error: Error }) => {
console.error(
`❌ OpenAPI failed on ${path ?? "<no-path>"}: ${error.message}`,
);
}
: undefined,
})(req, res);
};
export default handler;
export const config = {
api: {
bodyParser: false,
sizeLimit: "1gb",
},
};