This repository has been archived on 2026-06-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
xiaoju ca4fe8c3ac feat: P3 JSON Schema support — not, contains, propertyNames, metadata (#82)
Add 8 new schema keywords:

Combinators (with collectRefs support):
- not: negation schema
- contains: array must contain matching item

Constraints:
- propertyNames: constrain object key names

Metadata (no collectRefs impact):
- examples, readOnly, writeOnly, deprecated, $comment

Total supported keywords: 40 (of ~45 commonly used).
Only $ref/$defs/$id/$schema remain unsupported (P4, deferred).

516 tests, 0 fail.

Closes #82
2026-06-01 02:31:59 +00:00

json-cas

Self-describing content-addressable storage with JSON Schema typed nodes.

Overview

json-cas is a monorepo for storing and validating JSON data in a content-addressable store (CAS). Each node has a typed payload: its type field is the hash of a JSON Schema node that describes the payload shape. Hashes are 13-character Crockford Base32 strings derived from XXH64 over deterministic CBOR encoding.

A bootstrap meta-schema is stored as a self-referencing seed node (type === hash). All other schemas are registered as nodes typed by that meta-schema. Payloads can reference other nodes via format: "cas_ref" fields; the library provides traversal, reference extraction, and integrity verification.

Use the in-memory store for tests and embedded apps, the filesystem store for persistence, and the CLI for local store management.

Architecture

     ┌─────────────────┐
     │  cli-json-cas   │
     └────────┬────────┘
              │
              ▼
     ┌─────────────────┐
     │  json-cas-fs    │
     └────────┬────────┘
              │
              ▼
     ┌─────────────────┐
     │    json-cas     │  (core)
     └─────────────────┘
Layer Package Role
Core @uncaged/json-cas Hashing, schemas, stores, verify, bootstrap
Storage @uncaged/json-cas-fs Filesystem-backed Store
CLI @uncaged/cli-json-cas json-cas command-line tool

Packages

Package Description Type
@uncaged/json-cas Core CAS engine — hashing, schema, store, verify, bootstrap lib
@uncaged/json-cas-fs Filesystem-backed CAS store lib
@uncaged/cli-json-cas CLI tool (json-cas binary) cli

Quick Start

git clone <repo-url>
cd json-cas
bun install --no-cache
bun run build
import {
  bootstrap,
  createMemoryStore,
  putSchema,
  validate,
} from "@uncaged/json-cas";

const store = createMemoryStore();
await bootstrap(store);

const typeHash = await putSchema(store, {
  type: "object",
  properties: { message: { type: "string" } },
  required: ["message"],
  additionalProperties: false,
});

const hash = await store.put(typeHash, { message: "hello" });
const node = store.get(hash);
console.log(validate(store, node!)); // true

For a persistent store:

import { createFsStore } from "@uncaged/json-cas-fs";
import { bootstrap } from "@uncaged/json-cas";

const store = createFsStore("/path/to/store");
await bootstrap(store);

Or use the CLI (see CLI Reference and packages/cli-json-cas/README.md).

CLI Reference

Binary: json-cas (also aliased ucas, from @uncaged/cli-json-cas). Default store: ~/.uncaged/json-cas. The store is auto-created and bootstrapped on first use — there is no init/bootstrap command, and schemas are ordinary @schema-typed nodes (ucas put @schema file.json), so there is no schema subcommand.

Envelope format

Every JSON-emitting command prints a uniform { type, value } envelope. type is the hash of the command's @output/* result schema and value is the command payload. This makes output self-describing and pipeable: feed any envelope into render -p to render its value (embedded cas_ref hashes are expanded). render is the only command that emits raw (non-envelope) text.

// ucas has <hash>
{ "type": "AYHQD2YA9G667", "value": true }
Usage: json-cas [--store <path>] [--json] <command> [args]

Commands (all emit a { type, value } envelope unless noted):
  put <type-hash> <file.json>       Store node (value = hash)          (@output/put)
  get <hash>                        Node payload + metadata            (@output/get)
  has <hash>                        Existence boolean                  (@output/has)
  verify <hash>                     ok / corrupted / invalid           (@output/verify)
  refs <hash>                       Direct cas_ref edges               (@output/refs)
  walk <hash> [--format tree]       Recursive traversal                (@output/walk)
  hash <type-hash> <file.json>      Compute hash without storing       (@output/hash)
  render <hash> [options]           Render node as text (raw output)
  render --pipe/-p [options]        Render a piped envelope (raw output)
  list --type <hash-or-alias>       Hashes for a type (value = list)   (@output/list)
  var set|get|delete|tag|list ...   Variable CRUD                      (@output/var-*)
  template set|get|list|delete ...  Output-template CRUD               (@output/template-*)
  gc                                Garbage collection                 (@output/gc)

Flags:
  --store <path>   Store directory (default: ~/.uncaged/json-cas)
  --json           Compact JSON output
  --pipe, -p       Read a { type, value } envelope from stdin for render

Pipe examples

# Store a node, then render the stored content (the put envelope's hash is
# a cas_ref, so render -p dereferences and renders it):
ucas put @schema ./schemas/item.json | ucas render -p

# Render garbage-collection stats:
ucas gc | ucas render -p

# List every schema, then consume the envelope's value array with jq:
ucas list --type @schema | jq -r '.value[]'

Development

bun install --no-cache   # install workspace dependencies
bun run build            # tsc --build (libs)
bun run check            # biome check
bun run format           # biome format --write
bun test                 # run all package tests

Publishing

Releases use Changesets. From the repo root:

bun run release   # changeset version → build → publish to npm (@uncaged/*)

Individual packages block prepublishOnly and expect releases via the workspace release script.

S
Description
Self-describing content-addressable storage with JSON Schema typed nodes
Readme 1.5 MiB
Languages
TypeScript 99.9%