The Arc CQRS server for TypeScript: define commands and queries and serve them over the same HTTP contract as Arc on .NET.
Important
Early source preview; npm packages are not published. This repository contains the server core, adapters for Express, Fastify, and Hono, optional tenant-scoped MongoDB collections and Drizzle SQL queries, a bounded source-based client generator, and an experimental Chronicle integration. No package is published to npm, and Arc for TypeScript does not have full parity with Arc on .NET. APIs and package names can still change. Check the capability reference before you design around a feature.
Arc is an opinionated CQRS application framework. You declare what your backend can do as commands and queries, and Arc handles routing, input binding, validation, authorization, correlation, tenancy, and the result envelope that Arc clients expect. Arc for TypeScript brings that model to Node.js and Fetch API hosts as idiomatic TypeScript, not as a line-by-line port.
In the Tasks sample, a command is a class with fields and a handle method; a query is a static method on a read model. These excerpts use TaskId, TaskTitle, and Tasks from that sample:
@command()
export class RegisterTask {
@field(TaskId) id!: TaskId;
@field(TaskTitle) title!: TaskTitle;
handle(tasks: Tasks): TaskId {
tasks.register(this.id, this.title);
return this.id;
}
}
@readModel()
export class TaskItem {
@field(TaskId) id!: TaskId;
@field(TaskTitle) title!: TaskTitle;
@query(service(Tasks))
static allTasks(tasks: Tasks): TaskItem[] { return tasks.all(); }
}@field comes from @cratis/fundamentals; the other decorators come from @cratis/arc.core. With generated artifact metadata installed, Arc binds typed parameters without repeated service tokens. Arc decodes the fields into concepts, runs the command or query in a service scope, and uses the field metadata for JSON Schema. The sample discovers artifacts under Features/, so these routes are POST /api/tasks/registration/register-task and GET /api/tasks/listing/all-tasks. Start with Get started for a complete build and two HTTP calls. If you need explicit Zod schemas and low-level handler callbacks instead, use the existing defineCommand and defineQuery APIs; they remain supported.
| Package | Folder | Contents |
|---|---|---|
@cratis/arc.core |
Source/Core |
Node's ArcApplication (the unchanged root import) and the separate @cratis/arc.core/fetch entry for explicitly registered artifacts on Fetch hosts; the @command, @readModel, @query and authorization decorators, CommandValidator, QueryValidator, ConceptValidator and ModelValidator, ArcServer, defineCommand, defineQuery, the command and query pipelines, explicit services, authentication handlers, identity details, tenancy, results, introspection, OpenAPI, exportClientManifest, and the standalone Node host (createArcNodeHandler, runArc) with public static files and SPA fallback. |
@cratis/arc.express |
Source/Express |
cratisArc(arc) Express middleware with .injectWebSocket(listener) for WebSockets |
@cratis/arc.fastify |
Source/Fastify |
app.register(cratisArc, { arc }) (WebSockets by default) for Fastify 5 |
@cratis/arc.hono |
Source/Hono |
app.use(cratisArc(arc)) for Hono 4; serveCratisArc for Node WebSockets |
@cratis/arc.testing |
Source/Testing |
CommandScenario, QueryScenario, and ObservableQueryScenario for decorated artifacts; ArcScenario for low-level definitions and HTTP |
@cratis/arc.proxygenerator |
Source/Tools/ProxyGenerator |
analyzeSource, renderSource, renderGeneratedMetadata, generateFromSource, and the arc-proxygenerator CLI generate published-client proxies and optional server artifact metadata from decorated source. The original renderClientManifest/generateClient JSON path remains available for low-level definitions. See Proxy generation. |
@cratis/eslint-plugin-arc-core |
Source/CodeAnalysis |
ESLint 10 flat-config diagnostics for model-bound server artifacts, with an untyped-safe recommended config and an optional type-checked preset. See Code analysis. |
@cratis/arc.mongodb |
Source/MongoDB |
builder.withMongoDB, tenant-scoped model collections with BSON mapping and replica-set observation, plus the existing MongoReadModels helper; uses the mongodb 6 driver |
@cratis/arc.drizzle |
Source/Drizzle |
builder.withDrizzle, tenant-scoped SQL handles, explicit column codecs and provider-owned paging; SQLite and PostgreSQL tested, MySQL and observation unverified |
@cratis/arc.chronicle |
Source/Chronicle |
Experimental. builder.withChronicle appends returned events and resolves registered read models by command key; nested command returns join one event-log batch. In-memory command assertions are available under @cratis/arc.chronicle/testing. SDK 6.10.0 imports natively and infers read models from projections/reducers; an opt-in kernel suite covers aggregate replay and reactor commands. Full .NET transaction parity remains unverified. |
@cratis/cratis |
Source/Cratis |
Experimental source preview. CratisApplication.createBuilder() and builder.addCratis() compose Arc and a Chronicle client without installing authentication; not yet published to npm. |
Every package manifest is at version 0.30.4. That is the version of this source preview, not an npm release, and the Chronicle package is experimental. The packages ship ES modules only, and schemas use Zod 4. The default core entry, host adapters, MongoDB, and Drizzle packages need Node.js 22 or later. The Fetch entry has a neutral bundle with node:async_hooks as its only Node import; its command, query, and SSE paths ran in Deno 2.9.7, while Bun, Cloudflare Workers, and Next.js deployments remain unverified. The root workspace needs Node.js 22.19 or later, because it installs the Chronicle SDK; Node.js 24 LTS is recommended.
Until the packages are published, run the sample from a clone:
git clone https://github.com/Cratis/Arc.TypeScript.git
cd Arc.TypeScript
corepack enable
yarn install
yarn build
yarn workspace @cratis/arc.core.sample.tasks startThe sample listens on port 3000 on loopback by default; Ctrl+C gracefully stops its app.run() lifecycle. Get started walks through calling it, and Your first command explains every line. The Library sample adds Chronicle event sourcing, projected read models, and a React client; it requires an owned development kernel. See Vertical slices for its file layout.
If corepack enable reports that the command is missing, as on Node.js 25 and later, run npm install --global corepack first. To start your own application instead of the sample, follow Create an application.
Supported, with specs in this repository: commands and queries with Zod schemas, observable queries (HTTP snapshots, direct SSE and WebSocket, and the multiplexed WebSocket and SSE hubs used by the @cratis/arc client), validation-only requests, validators and filters, declared and per-request authorization, authentication handlers, correlation IDs, execution scopes, in-memory and provider paging, exception redaction, introspection, OpenAPI, the three host adapters, tenant-scoped MongoDB collections with live replica-set specs, and SQL paging with SQLite and PostgreSQL specs.
Also supported, each one explicit or opt-in:
- Services. Use
builder.services.addSingleton(Tasks)for class self-binding, or register a factory orserviceToken;@injectable(...)andstatic injectdeclare constructor dependencies. Model-bound methods use generated metadata or explicit@inject(...)and orderedservice(...)query descriptors. The olderdefine*definitions retainhandlerDependenciesandvalidatorDependencies. Execution scopes dispose their services;await app.dispose()closes the app and its registry. - Identity.
identityDetails(Zod schema or model-bound details type) or a discovered@identityDetailsProvider()registersGET /.cratis/meand sets a client-readable display cookie. The cookie is for display only; it is not a credential. Authentication describes opt-in EasyAuth headers and signed JWT verification, and Identity the details endpoint. - Host principals.
nativePrincipal: trueaccepts a principal your host framework has already verified, passed through an explicit adapter callback. It cannot be combined with Arc authentication handlers. - Tenancy.
tenancy.resolveselects a tenant in application code;tenancy.resolverTypeselects one built-in source, ortenancy.sourcestries ordered header, query, claim, fixed/development, or subdomain sources, with optionalrequiredand membership-claim checks. Tenant resolvers describe the trust boundary. - Testing.
@cratis/arc.testingruns decorated commands, queries, and observable queries through real pipelines with scoped services and JSON wire round trips;ArcScenariostill covers low-level definitions and HTTP. See Testing. - Generated clients and metadata, bounded. Run
arc-proxygenerator --project <tsconfig> --artifacts <folder> --output <existing-folder> [--metadata <file>]against decorated commands and read models. It reads the TypeScript program, not application startup, and generates command/query/observable classes, nested models and hooks. These compile with the published@cratis/arcand@cratis/arc.react22.19.1 in strict Bundler mode withskipLibCheck: false; the model-bound command, query, paging, sorting and observable hub run against all three adapters. Extensionless imports are the default for Vite/Bundler; use--js-import-specifiersfor compiled native Node ESM. The Tasks sample's cross-platformgenerate-proxiesscript generates and compiles this output in CI.NodeNextconsumer compilation is not supported by those published declarations. For low-leveldefine*definitions, keep usingexportClientManifestand the positional JSON CLI, whose narrower contract excludes nested DTOs, React hooks and shared validation rules. See Proxy generation.
A paired suite checks bounded HTTP cases, including named-policy authorization, observable snapshots, model-bound validation, acronym naming, enum and named-float JSON output, against Arc on .NET 22.23.0 and pins the known differences. That is not full parity. How parity is checked lists what it covers.
Not implemented:
- Complete .NET proxy parity. The source analyzer emits bounded client proxies and optional server metadata, but identity-only models and some .NET template options are not yet emitted. Literal client-safe
@validator(Target)constructor rules and decorated derived classes are emitted, while server-only validation rules report diagnostics. - SQL observation and automatic migration execution. Drizzle SQL supports explicit conversions and SQL paging but not EF change tracking or cross-process notifications. Named policies and guarded identity handlers are supported; see authorization policies. Command operations and effects have a bounded implementation, not a distributed transaction.
The Chronicle integration stays experimental despite passing a bounded live-kernel suite. SDK 6.10.0 handles literal JSON null for a missing model, which the suite checks across all three adapters. Command-key read-model injection and a single-event-log nested returned-event batch exist; returned events and command operations cannot be combined. Immediate appends, aggregates, and reactor command effects do not join that batch.
The capability reference lists every Arc feature family, its status, and the deliberate differences from Arc on .NET.
The documentation is published on the Cratis site and lives in Documentation, organized like Arc's C# backend documentation:
- Get started and Your first command: run the Tasks sample and read it file by file.
- Coming from Express and NestJS: map the code you write today to Arc.
- Hosting overview, Arc.Core and the standalone host, host adapters, and Fetch API runtimes for Bun, Deno, Cloudflare Workers, and Next.js route handlers.
- Commands and Queries, including validation, outcomes, operations, paging, and observable queries.
- Authorizing commands and queries, authentication, identity, and tenancy.
- Concepts, dependency injection, and configuration.
- MongoDB, SQL with Drizzle, and the experimental Chronicle integration.
- Proxy generation and generated artifact metadata, code analysis, OpenAPI, and introspection.
- Testing, observability, the decorator reference, and troubleshooting.
- Architecture and the capability reference.
- Arc HTTP contract: the wire protocol every Arc backend speaks.
@cratis/arc is Arc's existing TypeScript client runtime, used by generated proxies and @cratis/arc.react to call an Arc backend. It is built and released from the Arc repository.
This repository builds the server side under its own @cratis/arc.core package names. It does not replace, rename, or republish @cratis/arc or any other Arc package. The existing client is the compatibility target for this server's wire behavior. The server core does not depend on @cratis/arc or on browser code; only the proxies that @cratis/arc.proxygenerator writes import it, in your frontend.
Arc is a CQRS framework first. A command can validate input, call a service, write to current-state storage, and return a response without an event log, and the server core has no dependency on event sourcing or a database. Event sourcing comes from Chronicle as an optional integration. Here that integration is experimental: the pinned Chronicle TypeScript client 6.10.0 loads in native Node.js and a bounded suite passes against a live kernel for read-model resolution, returned-event batches, aggregate replay, and reactor commands. The integration still does not match Arc on .NET's full transaction behavior.
Arc for TypeScript is a framework library, not an application. Read CONTRIBUTING.md before opening a pull request, and start with an issue or a conversation on Discord for anything larger than a small fix.
Report security issues privately, as described in SECURITY.md.
| Path | Destination |
|---|---|
| Questions and discussion | Cratis Discord |
| Bugs and feature requests | GitHub Issues |
| Arc documentation | www.cratis.io/arc |
| Security reports | SECURITY.md |
| License | MIT |
This project is part of Cratis: free, MIT-licensed tools for building event-sourced and CQRS applications.
- Arc: the CQRS framework for ASP.NET Core, and home of the TypeScript client and React packages. Docs
- Arc for Kotlin and Java: Arc on Spring Boot.
- Chronicle: the event-sourcing database and runtime, with a TypeScript client. Docs
- Components: React components aligned with Arc patterns. Docs
- Fundamentals: shared primitives for .NET and TypeScript.
- Samples: runnable event sourcing and CQRS samples.
- AI: free AI skills and rules for building with the stack.