Docs/Getting startedv1.0.0-rc.1

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

From the canonical UDIOT public documentation.Try it in the playground ↗