Quick start
These complete examples target the Node ESM configuration in
TypeScript setup and @tagna/udiot@1.0.0-rc.1.
Save one example at a time as src/main.ts, then compile and run it.
The marked examples are compiled and executed by the documentation check.
1. A middleware pipeline
Every pipeline context needs metadata and timestamp. Execution returns a
result envelope; check success and error rather than assuming every failure
throws. Middleware is ordered by priority (lower first), then insertion order
for equal priorities.
import assert from 'node:assert/strict';
import { MiddlewarePipeline, type BaseContext } from '@tagna/udiot';
interface GreetingContext extends BaseContext {
name: string;
}
const pipeline = new MiddlewarePipeline<GreetingContext>();
pipeline.use(async (context, next) => {
context.result = `Hello, ${context.name}!`;
await next();
});
const result = await pipeline.execute({
name: 'UDIOT',
metadata: new Map(),
timestamp: Date.now(),
});
assert.equal(result.success, true);
assert.equal(result.result, 'Hello, UDIOT!');
console.log(result.result);
Call next() to continue. Omitting it short-circuits the pipeline.
See pipeline semantics and
context builders.
2. Dependency injection
Use an explicit generic on resolve<T>() for the returned service type.
import 'reflect-metadata';
import assert from 'node:assert/strict';
import { Container, Injectable } from '@tagna/udiot';
@Injectable()
class GreetingService {
greet(name: string): string {
return `Hello, ${name}!`;
}
}
const container = new Container();
container.register(GreetingService);
const service = container.resolve<GreetingService>(GreetingService);
assert.equal(service.greet('UDIOT'), 'Hello, UDIOT!');
assert.equal(container.resolve<GreetingService>(GreetingService), service);
Class registration is singleton by default. Use explicit providers/scopes when you need different lifetimes; a child container is not an authorization boundary. See providers and request/tenant isolation.
3. State management
A reducer can implement application actions without decorator magic. Await dispatch before reading the updated state, and unsubscribe when finished.
import assert from 'node:assert/strict';
import { Store, type StoreAction } from '@tagna/udiot';
interface CounterState { count: number }
class CounterStore extends Store<CounterState> {
constructor() { super({ count: 0 }); }
protected reduce(state: CounterState, action: StoreAction): CounterState {
return action.type === 'increment' ? { count: state.count + 1 } : state;
}
}
const store = new CounterStore();
let observed = 0;
const unsubscribe = store.subscribe(state => { observed = state.count; });
await store.dispatch({ type: 'increment' });
assert.equal(store.getState().count, 1);
assert.equal(observed, 1);
unsubscribe();
See state, selectors and persistence. Browser apps should use the browser entry point and test their own storage and lifecycle behavior.
Next steps
- API entry points and support levels
- Express/server helpers
- Web application composition
- Agents, telemetry and databases
- Testing and deployment