- TypeScript 91.5%
- Shell 8.5%
|
|
||
|---|---|---|
| .forgejo | ||
| .runseal | ||
| docs | ||
| lib | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| deno.json | ||
| negentropy.toml | ||
| README.md | ||
| runseal.toml | ||
shield
A minimal fault substrate for TypeScript. Native throw, family-scoped kinds, no Result monad, no
runtime dependencies.
A business domain declares its failure vocabulary once:
export const fault = family("land", {
dirty: z.object({ branch: z.string() }),
missing: z.object({ path: z.string() }),
});
The declaration is the single source of truth: kinds and their payload shapes flow into both the runtime factories and the type of every handler. shield consumes the shape and never validates — validation, if you want it, is the business's own call.
Throw at the disease:
shield.assert(status.clean, () => fault.dirty({ branch }));
Recover locally, or dispose at the boundary:
const text = await io.fault.attempt(() => io.read(path), { missing: () => "" });
await run(main).catch(land.fault.consume({
dirty: (f) => io.fail(`dirty on ${f.meta.branch}`),
missing: (f) => io.fail(`no path ${f.meta.path}`),
ahead: (f) => io.fail(`behind by ${f.meta.by}`),
}));
consume is exhaustive: every kind is handled or the compiler stops you. run absorbs every
non-fault into a foreign fault, so a handler always faces a fault, and a bug still crashes loudly
unless you route it on purpose.
See docs/constitution.md for the full design.