@arki/schema

next

for @arki/[email protected] · Tier 2: standalone libraries · MIT

Standard Schema types, validation execution, issue helpers and a JSON Schema bridge.

Version 0.2.0 next

Install

0.2.0 is not on npm yet. No version is on npm yet.

Release health for @arki/[email protected]

Doc examples

4 compiled4 run0 skipped

Open gaps

4 release checks fail

  • checkfile-changelog
  • checkfile-agents-md
  • checkreadme-h2-order
  • checkpkg-engines

Used by demos

No demo uses this package yet.

Runtimes

No engines field, so no runtime requirement is declared.

Benchmarks

No benchmarks are published for this version.

README

Standard Schema types, validation execution, issue helpers and a JSON Schema bridge. Bring Zod, Valibot, ArkType or your own validator. Execution is shared with @arki/failure/schema; the dependency graph is schema → failure → Standard Schema spec types.

Install

bun add @arki/schema @arki/failure

Quick start

parse returns the schema output or a canonical failure. Narrow the result before using its value.

import { z } from 'zod';
 
import { isFailure } from '@arki/failure';
import { parse } from '@arki/schema';
 
const age = parse(z.string().transform(Number), '42');
if (isFailure(age)) throw new Error(age.message);
const output: number = age;
if (output !== 42) throw new Error('unexpected output');

For a form adapter that reports field errors:

import * as v from 'valibot';
 
import { InvalidInput, orThrow } from '@arki/failure';
import { parse, pathOf } from '@arki/schema';
 
const Signup = v.object({ name: v.string(), age: v.number() });
 
/** Turn invalid form input into field messages; schema defects cross this throwing form adapter explicitly. */
export function fieldErrors(input: unknown): Record<string, string> {
  const result = parse(Signup, input);
  if (!InvalidInput.is(result)) {
    orThrow(result);
    return {};
  }
  const errors: Record<string, string> = {};
  for (const issue of result.data.issues) errors[pathOf(issue).map(String).join('.')] = issue.message;
  return errors;
}

Async validation

parseAsync resolves to output or InvalidInput / ValidatorDefect. parse additionally returns AsyncSchema when a validator requires awaiting. Rejected promises received by sync parsing are observed.

import { z } from 'zod';
 
import { AsyncSchema, isFailure } from '@arki/failure';
import { parse, parseAsync } from '@arki/schema';
 
const Handle = z.string().refine(value => Promise.resolve(value.length > 2));
if (!AsyncSchema.is(parse(Handle, 'ada'))) throw new Error('expected async mismatch');
const handle = await parseAsync(Handle, 'ada');
if (isFailure(handle)) throw new Error(handle.message);
if (handle !== 'ada') throw new Error('unexpected handle');

Failure behavior

ResultMeaningHandle with
OutputValidated, possibly transformed valueUse after narrowing
schema.invalid_inputInvalid dataInvalidInput.is(result); read result.data.issues
schema.async_requiredSync parse received async validationUse parseAsync
schema.validator_defectSchema access, invocation or rejection failedFix the validator; never map to HTTP 400

Definitions are exported from @arki/failure. Their .is guards work across package copies. orThrow(result) explicitly bridges into a foreign throwing API through UnexpectedFailure; parsing itself returns failures.

Throwing channel: is, assert, ensure

parse is for expected failure: bad user data is returned. assert and ensure are for bugs: a value the code already trusted is wrong, so they throw AssertError (ARKI_SCHEMA_E004). Both report the same issues.

  • is(value, schema) is a guard. A rejection is false.
  • assert(value, schema, options?) narrows the variable to the schema's input type. It never transforms.
  • ensure(value, schema, options?) returns the schema's output: a throwing parse.
  • options.at labels the value ("PORT"). options.message is a string or a function built only on failure.

The error message lists the issues with paths. It never contains the value, because asserted values are often secrets: the offending value is redacted out of each issue message. An async schema throws ARKI_SCHEMA_E005 at once. is throws too, because false would silently mean "invalid" for data that may be fine.

import { z } from 'zod';
 
import { AssertError, ensure } from '@arki/schema';
 
const port = ensure('8080', z.coerce.number(), { at: 'PORT' });
if (port !== 8080) throw new Error('unexpected port');
try {
  ensure('x', z.coerce.number().int(), { at: 'PORT' });
} catch (error) {
  if (!(error instanceof AssertError)) throw error;
}

Every check of an unknown value is a schema. recordSchema accepts a non-null object that is not an array. plainObjectSchema also needs an Object.prototype or null prototype, so class instances and dates are out. Use them as is(value, recordSchema) or assert(value, plainObjectSchema); each failure is one fixed issue with no value in it.

JSON Schema

withJsonSchema(schema, input, output?) wraps a schema with JSON Schema converters. The output description defaults to input. The wrapper preserves validation receiver binding and answers only draft-2020-12; another target throws SchemaRunError with ARKI_SCHEMA_E003. This converter error is separate from validation failures.

import * as v from 'valibot';
 
import { hasJsonSchema, parse, withJsonSchema } from '@arki/schema';
 
const Name = withJsonSchema(v.string(), { type: 'string' });
if (!hasJsonSchema(Name)) throw new Error('expected JSON Schema');
if (parse(Name, 'Ada') !== 'Ada') throw new Error('validation changed');

API

ExportPurpose
StandardSchemaV1, StandardJSONSchemaV1Canonical spec types
SchemaInput<S>, SchemaOutput<S>Infer input and output
SchemaWithJson<I, O>Validation and JSON Schema in one schema
parse, parseAsyncOutput or exact canonical failures
is, assert, ensure, AssertOptionsThrowing channel for bugs
AssertError, AssertErrorCodeCoded error with issues; no raw value
recordSchema, plainObjectSchemaObject-shape checks as schemas
pathOf(issue)Path as plain keys
formatIssues(issues)All issue messages with paths
isStandardSchema(value)Recognize object and callable schemas
hasJsonSchema(schema)Narrow to a schema with converters
withJsonSchemaAdd draft-2020-12 converters
SchemaRunError, SCHEMA_ERROR_CODES, SchemaRunErrorCodeUnsupported JSON Schema target error

Runtime support

No Node or Bun built-ins are used. The table records the previous smoke run; rerun test:runtimes after building to verify the current tree.

RuntimeResultVersion testedDate (UTC)
nodepassv26.11.12026-10-17
bunpass1.4.22026-10-17
denopass2.9.72026-10-17
browserpassChromium 156.0.8078.42026-10-17
hermesnot run-2026-10-17

Limits

  • This package executes validators; it does not define one.
  • Sync parse cannot await async checks.
  • JSON Schema converters only support draft-2020-12.
  • The wrapper keeps Standard Schema behavior, not the original validator's extra methods.
  • pathOf returns keys, so a field name containing a dot remains one segment.

Documentation

Docs 2 pages in 0.2.0

Public imports 1 path · 23 exports

Import pathExportsFirst names
@arki/schema23 exportsassert, AssertError, AssertErrorCode, AssertOptions, …
All 23 names
  • assert function
  • AssertError class
  • AssertErrorCode type
  • AssertOptions type
  • ensure function
  • formatIssues function
  • hasJsonSchema function
  • is function
  • isStandardSchema function
  • parse function
  • parseAsync function
  • pathOf function
  • plainObjectSchema variable
  • recordSchema variable
  • SCHEMA_ERROR_CODES variable
  • SchemaInput type
  • SchemaOutput type
  • SchemaRunError class
  • SchemaRunErrorCode type
  • SchemaWithJson type
  • StandardJSONSchemaV1 interface
  • StandardSchemaV1 interface
  • withJsonSchema function

Every export with its signature, as JSON