Appearance
Zero-Drift Type Contracts
In traditional full-stack web applications, frontend API types and backend response structures frequently drift out of sync. A renamed backend column or altered enum causes silent runtime errors on the client.
MEGSTAT POS eliminates this class of defects through an end-to-end type contract architecture shared across npm workspaces: @megstat/db, @megstat/contracts, and @megstat/schemas.
The Contract Architecture
text
Packages Pipeline:
packages/db packages/contracts packages/schemas
─────────── ────────────────── ────────────────
Prisma Schema Prisma Select Constants Zod Schemas
│ │ │
▼ ▼ ▼
Generated Client ──────────▶ Derived Wire<T> Types ─────────▶ Shared Request
(Model types) (Dates -> ISO strings) Validation
(Decimals -> numbers)
│ │
├────────────────────────────────┤
▼ ▼
Frontend & Backend Codebases1. Reusable Select Constants (@megstat/contracts)
Prisma queries in backend routes do not use inline object literals. Instead, each domain exports typed Select constants satisfying Prisma model types:
ts
// packages/contracts/src/selects/sales.ts
import type { SaleSelect } from "@megstat/db/types";
export const saleListItemSelect = {
id: true,
invoiceNo: true,
status: true,
total: true,
paid: true,
createdAt: true,
customer: {
select: { id: true, name: true, phone: true }
}
} as const satisfies SaleSelect;Using as const satisfies <Model>Select ensures that if a database column in schema.prisma is renamed or deleted, @megstat/contracts fails to compile immediately.
2. The Wire<T> Mapped Type
Prisma returns instances of Decimal for financial fields and JavaScript Date objects for timestamps. However, HTTP JSON responses serialize these into numbers (or strings) and ISO 8601 strings.
packages/contracts/src/wire.ts defines a recursive mapped type that converts backend runtime types into their exact wire representation:
ts
import type { Decimal, JsonValue } from "@prisma/client/runtime/client";
type WireLeaf = string | number | boolean | bigint | null | undefined;
export type Wire<T> =
T extends Decimal ? number
: T extends Date ? string
: T extends WireLeaf ? T
: T extends readonly (infer U)[] ? Wire<U>[]
: T extends JsonValue ? T
: T extends object ? { [K in keyof T]: Wire<T[K]> }
: T;Wire types are derived directly from the select constants:
ts
// packages/contracts/src/wire/sales.ts
import type { Prisma } from "@megstat/db/types";
import type { Wire } from "../wire";
import type { saleListItemSelect } from "../selects/sales";
export type SaleListItemWire = Wire<
Prisma.SaleGetPayload<{ select: typeof saleListItemSelect }>
>;3. Resolution Safety Guards
Because Prisma generated files can include // @ts-nocheck, a broken @prisma/client path could silently turn Decimal into any. In that scenario, T extends Decimal would match everything, collapsing all wire types to number without warnings.
packages/contracts/src/wire.ts includes compile-time assertions:
ts
type IsAny<T> = 0 extends 1 & T ? true : false;
type Equal<A, B> = (<G>() => G extends A ? 1 : 2) extends (<G>() => G extends B ? 1 : 2) ? true : false;
type Expect<T extends true> = T;
// If @prisma/client stops resolving, this fails compilation:
type _AssertDecimalResolved = Expect<Equal<IsAny<Decimal>, false>>;
type _AssertJsonValueResolved = Expect<Equal<IsAny<JsonValue>, false>>;4. Shared Zod Schemas (@megstat/schemas)
All 92+ request validation schemas live in @megstat/schemas.
- Backend routes validate inputs using
validate("json", schema). - Frontend forms validate before dispatch using
validateWithSchema(schema, data). - Form payloads submit parsed and coerced output (
z.coerce.number(),.trim(), and schema defaults).
5. Automatic Wire Serialization (backend/src/http/serialize.ts)
To ensure compliance with Wire<T>, all response builders in backend/src/http/response.ts (ok, created, paginated, withData) route payloads through recursive toWire() serialization:
Decimalis converted to rounded 2-decimal numbers (round2).Dateis converted to ISO strings.- Eliminates stringified numbers from API payloads.
