subatom-infer
v1.3.7
Published
Production-grade runtime validation and type-inference library for Node.js and TypeScript
Downloads
993
Readme
Subatom Infer
Production-grade, high-performance runtime validation, strict schema transformation, and compile-time type inference engine powered by the unified
infernamespace.
📖 Documentation
For complete guides, API references, and interactive examples, visit the Official Documentation.
⚡ Highlights & Key Architecture
- 🚀 Dual Pipeline Execution: Synchronous execution throws when encountering async refinements/transforms; asynchronous pipeline evaluates fully non-blocking.
- 🛡️ Bidirectional Typing (
Schema<Out, In>): Clearly separates runtime input preconditions from validated/transformed output types. - 🔒 Immutable AST & Memory Safety: Zero runtime side-effects, full prototype poisoning protection, and thread-safe schema composition.
- 🎯 Discriminated Diagnostic AST: Exact JSON/array paths, key-level issue grouping, and structured error trees (
.flatten(),.format(),.prettifyError()). - 📦 Zero-Bloat ESM & CJS: Full dual export compatibility with strict TypeScript declarations.
📦 Installation
npm install subatom-infer
# or
pnpm add subatom-infer
# or
yarn add subatom-infer
# or
bun add subatom-infer
🚀 Quick Start
import { infer, type Infer } from "subatom-infer";
// 1. Define schema
const UserSchema = infer.object({
id: infer.uuid(),
username: infer.string().min(3).max(30),
email: infer.string().email(),
role: infer.enum(["admin", "user", "guest"]).default("user"),
profile: infer.object({
bio: infer.string().max(200).optional(),
avatarUrl: infer.string().url().optional(),
}),
});
// 2. Infer static TypeScript types
export type User = Infer<typeof UserSchema>;
// 3. Validate synchronously
const result = UserSchema.safeParse({
id: "123e4567-e89b-12d3-a456-426614174000",
username: "alex",
email: "[email protected]",
});
if (result.success) {
console.log("Valid user:", result.data);
} else {
console.error("Validation error:", result.error.flatten());
}
📖 Complete API Reference
1. Execution & Parsing Engine
Every schema instance exposes synchronous and asynchronous parsing methods:
| Method | Return Signature | Description & Behavior |
| --- | --- | --- |
| .parse(input) | TOutput | Synchronous. Throws ValidationError on failure or if async pipelines. |
| .safeParse(input) | SafeParseResult<TOutput> | Returns { success: true, data } or { success: false, error }. |
| .parseAsync(input) | Promise<TOutput> | Asynchronous execution. Awaits all async transformations, refinements, and sub-schemas. |
| .safeParseAsync(input) / .spa() | Promise<SafeParseResult> | Non-throwing Promise resolving to a strongly typed discriminated union. Alias: .spa(). |
2. Primitives & String Validation
Primitives & Unit Types
infer.string();
infer.number();
infer.boolean();
infer.bigint();
infer.date();
infer.symbol();
infer.undefined();
infer.null();
infer.void();
infer.any();
infer.unknown();
infer.never();
infer.nan();
infer.literal("ACTIVE");
String Format & Rule Modifiers
infer.string()
.min(5)
.max(100)
.length(20)
.email()
.url()
.httpUrl()
.uuid()
.guid()
.cuid()
.cuid2()
.ulid()
.nanoid()
.regex(/^[a-z]+$/i)
.startsWith("sub_")
.endsWith("_node")
.includes("@")
.datetime()
.date()
.time()
.duration()
.ipv4()
.ipv6()
.hostname()
.trim()
.toLowerCase()
.toUpperCase();
3. Numbers & BigInt Constraints
Number Constraints
infer.number()
.int() // Integer only
.safe() // Safe IEEE-754 range
.finite() // Rejects Infinity
.positive() // > 0
.nonnegative() // >= 0
.negative() // < 0
.nonpositive() // <= 0
.min(1)
.max(100)
.gte(1)
.lte(100)
.gt(0)
.lt(101)
.multipleOf(5);
BigInt Constraints
infer.bigint()
.positive() // > 0n
.nonnegative() // >= 0n
.negative() // < 0n
.nonpositive() // <= 0n
.min(100n)
.max(1000000n)
.multipleOf(10n);
4. Objects & Structural Policies
const BaseUser = infer.object({
id: infer.uuid(),
name: infer.string(),
role: infer.enum(["admin", "user"]),
});
// Object Policy Modifiers
const StrictUser = BaseUser.strict(); // Rejects unrecognized keys
const LooseUser = BaseUser.passthrough(); // Retains unknown keys
const StrippedUser = BaseUser.strip(); // Default: strips extra properties
const CatchallUser = BaseUser.catchall(infer.boolean()); // Validates unknown keys
// Structural Composition & Transformations
const ExtendedUser = BaseUser.extend({ email: infer.email() });
const MergedSchema = BaseUser.merge(infer.object({ traceId: infer.string() }));
const PickedName = BaseUser.pick({ name: true });
const OmittedId = BaseUser.omit({ id: true });
const PartialUser = BaseUser.partial(); // All fields optional
const RequiredUser = PartialUser.required(); // All fields required
const DeepOptional = BaseUser.deepPartial(); // Recursively optional
const UserKeysEnum = BaseUser.keyof(); // Returns EnumSchema of keys
5. Collections & Data Structures
// Arrays & Tuples
const Tags = infer.array(infer.string()).min(1).max(10).nonempty();
const Coord = infer.tuple([
infer.number(),
infer.number(),
infer.number().optional(),
]);
// Dynamic Key-Value Records
const Config = infer.record(
infer.string().min(2),
infer.number()
);
// Native JavaScript Sets & Maps
const Roles = infer.set(infer.string()).min(1);
const Lookup = infer.map(infer.uuid(), infer.boolean());
6. Combinators & Special Schemas
// Tagged / Discriminated Union (O(1) matching)
const Event = infer.discriminatedUnion("type", [
infer.object({ type: infer.literal("click"), x: infer.number() }),
infer.object({ type: infer.literal("hover"), element: infer.string() })
]);
// Union & Intersection
const StrOrNum = infer.union([infer.string(), infer.number()]);
const Combined = infer.intersection(SchemaA, SchemaB);
// Functions & Promises
const AddFn = infer.function(
infer.tuple([infer.number(), infer.number()]),
infer.number()
);
const AsyncStr = infer.promise(infer.string());
// File & Binary Blobs
const Upload = infer.file().max(5_000_000).mime("image/png");
// Recursive & Self-Referencing Types
const Node = infer.lazy(() => infer.object({
next: Node.optional()
}));
7. Modifiers, Pipelines, Refinements & Codecs
// 1. Modifiers & Defaults
const OptStr = infer.string().optional(); // string | undefined
const NullableNum = infer.number().nullable(); // number | null
const NullishDate = infer.date().nullish(); // Date | null | undefined
const DefaultPort = infer.number().default(3000);
const PrefaultVal = infer.string().prefault("anonymous");
const SafeValue = infer.number().catch(0);
// 2. Transformation Pipeline & Pipe
const StrToDate = infer.string().transform((val) => new Date(val));
const PipedValidation = infer.pipe(
infer.string().min(2),
infer.string().email()
);
// 3. Refinements & SuperRefine
const PasswordCheck = infer.object({
password: infer.string().min(8),
confirm: infer.string()
}).superRefine((data, ctx) => {
if (data.password !== data.confirm) {
ctx.addIssue({ code: "custom", message: "Passwords must match" });
}
});
// 4. Nominal Branding & Bidirectional Codecs
const UserIdSchema = infer.brand(infer.uuid(), "UserId");
const Base64Codec = infer.codec(
infer.string().transform((str) => Buffer.from(str, "base64")),
(buf: Buffer) => buf.toString("base64")
);
8. Coercion Engine & Error Formatting API
infer.coerce.string();
infer.coerce.number().int();
infer.coerce.boolean();
infer.coerce.bigint();
infer.coerce.date();
// Automatically parses strings
const parsedNum = infer.coerce.number().parse("42"); // 42 (number)
Error Tree Formatting
try {
UserSchema.parse(badInput);
} catch (err) {
// Form & field error record
err.flatten();
// Deeply nested issue tree
err.format();
// Pretty CLI string format
console.log(err.prettifyError());
}
🛠️ TypeScript Support & Type Inference
Subatom Infer extracts exact compile-time types from your runtime schemas:
import { infer, type Infer, type Input, type Output } from "subatom-infer";
const ProductSchema = infer.object({
id: infer.string().uuid(),
price: infer.coerce.number(),
createdAt: infer.string().transform((s) => new Date(s)),
});
// Output type (after transformations & coercions)
type Product = Infer<typeof ProductSchema>;
// Equivalent to: Output<typeof ProductSchema>
// { id: string; price: number; createdAt: Date; }
// Input type (pre-transformation input requirement)
type ProductInput = Input<typeof ProductSchema>;
// { id: string; price: string | number; createdAt: string; }
📄 License
Distributed under the MIT License. Generated by Subatom Library Architect Suite.
