domwires
v5.0.1
Published
Flexible and extensible MVC framework
Readme
DomWires 5.0
Typed messages. Explicit state changes. Components with clear lifetimes.
DomWires is a dependency-free TypeScript framework for composing applications from models, mediators, commands and contexts. It works in browsers and Node.js, alongside your UI or rendering library.
A context connects components through messages and contracts. Commands change model state. Views capture input and render data. Mediators translate view callbacks into messages and read live state through Immutable interfaces. Context boundaries make dependencies, routing and cleanup explicit.
Get started · Documentation · API reference · Examples
5.0 introduces a new API. The previous implementation is preserved on
v2.x. See the changelog and release guide.
How it fits together
This is one real route from the scene lab. Each context creates its mediators; each mediator creates and disposes its view. The walkthrough expands it to nested contexts, level loading, cancellation and HUD updates.
| Component | Responsibility | | --- | --- | | Model | Owns state and emits change notifications. | | Immutable interface | Exposes the same live model without its mutation methods. It does not freeze or clone the object. | | View | Captures input, reports callbacks or UI events, and renders data. | | Mediator | Creates and owns its view, translates input into messages, reads model state and updates the view. | | Command | Performs an application action, synchronously or asynchronously. | | Context | Composes components, maps messages, controls boundaries and owns lifetimes. | | Adapter | Ordinary infrastructure object used by commands; no required Service base class. |
Quick start
Install DomWires in your application:
npm install domwires@^5.0.0To build this repository and run the examples:
npm ci
npm run build
npm run exampleOpen the printed localhost URL for the counter and scene lab. To test local changes in another application, run npm pack and install the resulting tarball. Import from domwires.
A complete message-to-command program:
import {AbstractCommand, AbstractContext, Factory, MessageType} from "domwires";
const GREET = new MessageType<{name: string}>("greet");
class Greet extends AbstractCommand<{name: string}>
{
public override execute(input: {name: string}): void
{
console.log("Hello, " + input.name + "!");
}
}
class AppContext extends AbstractContext
{
protected override init(): void
{
super.init();
this.map(GREET, Greet);
}
}
async function main(): Promise<void>
{
const factory = new Factory();
const app = factory.getInstance(AppContext);
try
{
app.dispatchMessage(GREET, {name: "DomWires"});
await app.settle();
}
finally
{
await app.close();
factory.dispose();
}
}
void main();Create contexts through the factory so their initialization hook runs. dispatchMessage() delivers synchronously; settle() drains command work; close() cancels and awaits teardown. Continue with the counter model and mediator.
What 5.0 brings
- Typed contracts: payloads, command input, model access and dependency tokens checked together.
- Scoped composition: separate roles for commands, models, mediators and adapters; explicit child-context imports.
- Native async commands: invocation-local state, cooperative cancellation and guarded model commits.
- Per-mapping concurrency: parallel, serial, latest and drop policies; disposable registrations and guards.
- Owned resources: startup, reverse-order cleanup and an awaitable close boundary.
- Observable execution: optional trace callbacks with correlated IDs, isolated observer failures and no built-in history buffer.
- Flexible construction: constructor/provider injection or optional legacy property decorators; no reflection-metadata dependency.
Explore the examples
| Example | Focus |
| --- | --- |
| Counter | Basic model/mediator flow, read/write tokens, guards and remounting |
| Scene lab | Nested contexts, tick, projectile reuse, async loading, scene switching and trace |
| Concurrent requests | Scoped injection and cancellation before committing a result |
| Node config | Platform-specific JSON loading through domwires/node |
Runtime and development
Built with TypeScript 7, targeting ES2022. The package declares Node 20+ and the CI workflow checks Node 20/22/24. The root entry point is browser-compatible; Node-specific loading is a separate export. Node ESM and CommonJS entry points share the same classes, tokens and registries, so mixing import and require preserves identity. Browser bundlers select one native ESM implementation for both import styles. Both formats include declarations and source maps; application types are checked with TypeScript 6 and 7.
Property decorators use experimentalDecorators; constructor and provider injection need no decorator syntax. Runtime dependencies are empty.
See contributing for the complete verification commands, source organization and generated API documentation. Public method contracts live in source comments and are carried into declaration files.
License and origins
MIT. DomWires grew from ActionScript 3 and Haxe implementations; 5.0 keeps the component model while making TypeScript contracts and lifetimes explicit. Visual identity and logo references.
