# Schemas — `schemas.ts` _(no submodules)_ ## Purpose Owns the Zod schemas that gate every public boundary of `@suaveplan/electrobun`. Each interface in `src/types/electrobun.types.ts` has a matching schema here, and the `parseOrThrow` helper folds the parse + throw pattern into one call so every entry point reads the same way: validate, then operate on the inferred type. The schemas are the runtime contract — when a downstream library passes a stale `ProjectOptions` shape, the schema fails at the boundary rather than silently producing a broken project. The schemas use Zod 4's enum / object / readonly-array helpers to keep the TypeScript inference cheap, and `parseOrThrow` always raises `ElectrobunError(ELECTROBUN.INVALID_OPTIONS)` so consumers can branch on `error.code === "ELECTROBUN.INVALID_OPTIONS"` regardless of which entry point validated. ## Features - Enum schemas (`FeatureModuleSchema`, `NetworkingComplexitySchema`, `R3fModuleSchema`, `BuildTargetSchema`). - Composite schemas (`ProjectOptionsSchema`, `ElectrobunConfigSchema`, `GenerateIconsOptionsSchema`, `DevCommandOptionsSchema`, `BuildCommandOptionsSchema`, `PackageCommandOptionsSchema`, `SignCommandOptionsSchema`). - `parseOrThrow(schema, value, context)` — single helper that converts a Zod failure into an `ElectrobunError` carrying `details.issues`. ## Usage: Basic ```ts import { ProjectOptionsSchema } from "@suaveplan/electrobun/schemas"; const parsed = ProjectOptionsSchema.safeParse(input); if (!parsed.success) { console.error(parsed.error.issues); } ``` ## Usage: Advanced ```ts import { ProjectOptionsSchema, parseOrThrow, } from "@suaveplan/electrobun/schemas"; import { ElectrobunError } from "@suaveplan/electrobun/error-codes"; try { const validated = parseOrThrow( ProjectOptionsSchema, input, "ProjectOptions" ); await generate(validated); } catch (err) { if (err instanceof ElectrobunError) { process.stderr.write(`${err.code}: ${err.message}\n`); for (const issue of err.details["issues"] as Array<{ path: ReadonlyArray; message: string; }>) { process.stderr.write(` - ${issue.path.join(".")}: ${issue.message}\n`); } } } ``` ## API Reference - `FeatureModuleSchema`, `NetworkingComplexitySchema`, `R3fModuleSchema`, `BuildTargetSchema` — closed Zod enums. - `ProjectOptionsSchema` — full `ProjectOptions` shape; rejects empty `name`, `identifier`, `version`, `outputDir`. - `ElectrobunConfigSchema` — partial config; every field optional. - `GenerateIconsOptionsSchema` — `{ inputPath, outputDir }`. - `DevCommandOptionsSchema`, `BuildCommandOptionsSchema`, `PackageCommandOptionsSchema`, `SignCommandOptionsSchema` — per-command option shapes. - `parseOrThrow(schema, value, context)` — returns the parsed value or throws `ElectrobunError(ELECTROBUN.INVALID_OPTIONS, "${context}: invalid options", { details: { context, issues } })`. ## Implementation Notes `z.array(...).readonly()` produces a `readonly`-typed inference that matches the `readonly`-array fields on `ProjectOptions`, so the consumer gets a parsed object whose mutability matches the interface. This is important because the generator iterates the feature list and would otherwise need an explicit `Array.from(...)` to avoid a structural mismatch. `parseOrThrow` uses `safeParse` rather than `parse` so the Zod issue list lands on `details.issues`. The thrown error carries the original `cause` slot empty — the Zod issues are the cause, surfaced as structured data rather than a child `Error`. Consumers who want to log a single line should format `err.message`; consumers who want to drive remediation should walk `details.issues`.