Skip to content

antistructured/sigiljs

Repository files navigation

SigilJS

Executable data contracts for JavaScript runtime boundaries.

Define structure once, then enforce, transform, project, and prove it across runtime boundaries.

SigilJS – Executable Data Contracts in Plain JS


Install

npm install @weipertda/sigiljs

or:

bun add @weipertda/sigiljs

SigilJS is written in JavaScript and ships TypeScript declarations for public API consumption. The declarations are intentionally conservative: they describe the runtime API, but do not yet infer precise object shapes from every contract definition. For typed usage, pass an explicit generic such as sigil.exact<User>(...); see docs/typescript.md.


30-second example

import { oneOf, optional, sigil } from '@weipertda/sigiljs';

const User = sigil.exact({
  id: String,
  email: String,
  role: oneOf('admin', 'user'),
  age: optional(Number),
});

const result = User.safeParse(unknownInput);

if (result.success) {
  // result.data is trusted — id, email, role, age are verified
  saveUser(result.data);
} else {
  console.error(result.error.message);
}

Five pillars

Pillar Purpose Methods
Define Declare structure in JavaScript sigil(), sigil.exact(), optional(), oneOf(), union()
Enforce Validate runtime data parse(), safeParse(), assert(), check()
Transform Normalize trusted data transform(), pipe(), trim(), serialize()
Project Generate tooling artifacts toJSONSchema(), toTypeScript(), toOpenAPI(), toFormConstraints(), describe()
Prove Test contract behavior mock(), cases(), test(), diff()

Why SigilJS

Data crosses runtime boundaries constantly — API responses, form submissions, database rows, AI outputs, CLI inputs. That data is untrusted until a contract enforces it.

SigilJS provides one contract object per shape that you can:

  • enforce at any runtime boundary
  • project into JSON Schema, TypeScript, OpenAPI, or form metadata
  • use to generate test fixtures and run self-tests
  • compare across versions with structural diffs
  • consume from TypeScript projects without missing declaration errors

A sigil is not a schema. It is a contract object that lives in your JavaScript and travels with your data.


Boundary examples

Use SigilJS anywhere data crosses a boundary: APIs, databases, forms, events, queues, webhooks, config files, local storage, plugin systems, and AI structured outputs.

API response

const ApiResponse = sigil.exact({
  id: String,
  name: String,
  role: oneOf('admin', 'user'),
});

const result = ApiResponse.safeParse(await response.json());

if (!result.success) {
  throw new Error(`Unexpected API shape: ${result.error.message}`);
}
return result.data;

Database record

const UserRecord = sigil.exact({
  id: String,
  email: String,
  role: oneOf('admin', 'user'),
  createdAt: String,
});

const user = UserRecord.parse(rowFromDatabase);

Form submission

const SignupForm = sigil.exact({
  name: String,
  email: String,
  plan: oneOf('free', 'pro'),
});

const result = SignupForm.safeParse(formValues);
if (!result.success) {
  showFieldError(result.error.path?.at(-1), result.error.message);
}

AI structured output

const LeadIntent = sigil.exact({
  name: String,
  urgency: oneOf('low', 'medium', 'high'),
  summary: String,
});

// JSON Schema bridges the contract to LLM structured output APIs
const schema = LeadIntent.toJSONSchema();
// Pass schema to your LLM provider as the output format

const result = LeadIntent.safeParse(llmOutput);
if (result.success) {
  handleTrustedLead(result.data);
}

More boundary recipes: docs/recipes/


Stable API quick map

// Define
import { sigil, optional, oneOf, union, pipe, trim } from '@weipertda/sigiljs';

sigil.exact(definition)       // exact object contract

// Enforce
contract.parse(value)         // throws on invalid
contract.safeParse(value)     // { success, data } | { success, error }
contract.assert(value)        // throws on invalid, returns void
contract.check(value)         // boolean

// Transform
contract.transform(fn)        // returns new contract with transform
contract.serialize(value)     // validates and returns

// Project
contract.describe()           // stable contract description model
contract.toJSONSchema()       // JSON Schema
contract.toTypeScript(name)   // TypeScript type declaration
contract.toOpenAPI()          // OpenAPI schema
contract.toFormConstraints()  // form field metadata (experimental)

// Prove
contract.mock()               // deterministic valid sample
contract.cases()              // { valid, invalid } test case sets
contract.test(cases)          // run and report contract behavior
contract.diff(other)          // structural change report

See docs/api.md for the full API reference.


Projection example

const User = sigil({ id: String, name: String, email: String },
  { name: 'User', version: '1.0.0' });

User.toJSONSchema();
User.toTypeScript('User');
User.toOpenAPI();
User.describe();

Contract diff example

sigil diff contracts/user-v1.sigil contracts/user-v2.sigil
Contract changes:

BREAKING
- required property: email

NON-BREAKING
- added property: displayName

CLI (experimental)

SigilJS includes a dependency-free CLI for contract workflows. The CLI is Bun-first and experimental — commands, output shapes, exit-code guarantees, CWD/module-loading behavior, and .sigil compatibility may change before 1.0.0.

sigil check contracts/user.sigil data/user.json
sigil json-schema contracts/user.sigil
sigil types contracts/user.sigil User
sigil mock contracts/user.sigil
sigil cases contracts/user.sigil.js
sigil diff contracts/user-v1.sigil contracts/user-v2.sigil

The CLI supports both .sigil text files and .sigil.js JavaScript module files.

See docs/cli.md and examples/cli/.


Experimental features

The following APIs are experimental — they are tested and usable, but their surface may change before 1.0.0:

  • HTTP helpershttpContract() for framework-neutral request/response boundaries
  • Form constraintscontract.toFormConstraints() for form field metadata
  • CLI workflowssigil bin for terminal contract workflows

See docs/experimental.md.

Future @sigil/* package extraction is intentionally deferred until the core API stabilizes at 1.0.0.


Docs

Getting started

Real-world recipes

CLI

Boundaries

Projections

Testing

Reference


SigilJS vs Zod

Zod is a mature, expressive TypeScript-first validation library with a large ecosystem. SigilJS is a smaller executable data contract system for teams that want one readable runtime contract object they can enforce, transform, describe, and project across system boundaries without a TypeScript compiler dependency.

SigilJS does not claim to replace Zod. It is a focused alternative when you need runtime contracts with zero runtime dependencies, cross-boundary projection workflows, and a CLI for contract tooling.


Status

Version 0.18.0. Core API is ready for broader public 0.x usage feedback, but this is not a 1.0.0 release. HTTP helpers, form constraints, and CLI are experimental.

See docs/stability.md and docs/known-limitations.md.


License

MIT