One config, three synchronised data layers. A Prisma schema, Zod runtime validators, and TypeScript interfaces — generated together so they cannot drift apart.
npx @mrkt_frwd/trio schema.json --out ./generatedThe database, the runtime validator and the compiler each need to know the same shape, and keeping three hand-written definitions in agreement is a chore nobody wins at. Write it once:
{
"User": {
"id": { "type": "number", "id": true },
"email": { "type": "string", "unique": true },
"name": { "type": "string", "optional": true }
}
}Out come schema.prisma, schemas.ts and types.ts, agreeing on every field — including
optionality, which is the one people get wrong by hand.
An unknown type is an error, never a fallback.
An earlier version fell back to String for anything it did not recognise. So this:
{ "Account": { "balance": { "type": "decimal" } } }produced a Prisma String, a z.string(), and a TypeScript string. A money column
shipped as text, all three layers in perfect agreement, nothing raised anywhere. Three
layers that agree and are all wrong together is the exact failure this tool exists to
prevent, so a type it does not know now names the field and stops:
✗ Account.balance: unknown type "wat". Known types: bigint, boolean, bytes, date,
decimal, float, json, number, string, uuid
refusing to generate — 1 problem(s). Nothing was written.
Nothing is written unless the whole config validates, so a bad field cannot leave a
half-generated schema behind. check() reports every problem at once rather than the
first.
decimal is a real type now: Decimal in Prisma, and a string at the runtime boundary,
because a JavaScript number cannot hold it losslessly. The generated schema says so in a
comment.
string · number · float · decimal · bigint · boolean · date · json ·
bytes · uuid
const { generate, generateSchemas, check } = require('@mrkt_frwd/trio');
check(config); // string[] of problems, empty if valid
generate(config); // { 'schema.prisma': …, 'schemas.ts': …, 'types.ts': … }
generateSchemas(config, './out'); // validates, then writesNode 18+. No dependencies.
MIT © Joe Asare. Built at Joe Asare Studio.