<< All versions
Skill v1.0.0
currentLLM-judged scan90/100senrecep/tsentials/tsentials-mediator
──Details
PublishedOctober 23, 2026 at 07:20 PM
Content Hashsha256:4f28297cdda016c1...
Git SHA5ba4e1ccd239
──Files
Files (1 file, 4.0 KB)
SKILL.md4.0 KBactive
SKILL.md · 93 lines · 4.0 KB
version: "1.0.0" name: tsentials-mediator description: Use when you need typed in-process request/response dispatch with cross-cutting behaviors — createMediator<RequestMap>() with register/send, handlers returning Result<T>, pipeline behaviors for exception handling, validation, logging, caching, locking and transactions, and AbortSignal propagation.
tsentials/mediator
Typed in-process mediator without a DI container. Handlers return Result; behaviors wrap them as a pipeline. Subpath-only: not exported from the root tsentials entry.
Installation
bash
npm install tsentials
Import
typescript
import {createMediator, pipeline,exceptionHandlingBehavior, validationBehavior, loggingBehavior,cachingBehavior, lockBehavior, transactionBehavior, InProcessResourceLock,} from 'tsentials/mediator';import type { Behavior, GenericBehavior, RequestHandler, RequestContext } from 'tsentials/mediator';
Register and send
typescript
import { Result } from 'tsentials/result';import { Err } from 'tsentials/errors';type Requests = {GetUser: { request: { id: number }; response: User };};const mediator = createMediator<Requests>({ behaviors: [exceptionHandlingBehavior()] }).register('GetUser',({ id }, ctx) =>id > 0 ? Result.success(loadUser(id)) : Result.failure(Err.notFound('User.NotFound', 'No user')),validationBehavior<{ id: number }>([(req) => (req.id > 0 ? Result.ok() : Result.failure(Err.validation('Id.Invalid', 'bad'))),]),);const result = await mediator.send('GetUser', { id: 1 }, { signal }); // Promise<Result<User>>mediator.has('GetUser'); // true
- The
RequestMaptype maps request names to{ request; response };sendandregisterare fully typed from it. - Handlers may be sync or async and receive
(request, { requestName, signal }). registerreturns the mediator (chainable). Pipeline order, outermost first: mediator-wide behaviors, then the per-handler behaviors passed toregister, then the handler.
Behaviors
| Behavior | Purpose | |||
|---|---|---|---|---|
exceptionHandlingBehavior() | thrown handler error becomes Err.fromException(e) (type Failure) | |||
validationBehavior(validators, { defaultMode, observers }) | run validators before the handler; modes `'enforce' \ | 'logOnly' \ | 'off' (from request.validationMode); a Rule<T>` is a valid validator | |
loggingBehavior({ logger }) | log request/response via a MediatorLogger | |||
cachingBehavior({ cache }) | cache results by request.cacheKey (CacheStore get/set of strings); the key is caller-supplied, so include tenant/user in it for per-user data | |||
lockBehavior(new InProcessResourceLock()) | serialize requests with the same request.lockKey | |||
transactionBehavior(runner) | run requests with transactional: true in a TransactionRunner; commits unless the result fails |
Custom behavior (a function; call next() to continue):
typescript
const timing: GenericBehavior = async (request, next, ctx) => {const start = Date.now();const result = await next();console.log(ctx.requestName, Date.now() - start);return result;};
pipeline(handler, ...behaviors) composes a handler with behaviors without a mediator.
Patterns and pitfalls
- Import from
tsentials/mediator— never from the roottsentialsentry. sendrejects when no handler is registered for the name;registerthrowsTypeErroron a duplicate name.- AbortSignal convention: pass
{ signal }tosend; the caller's abort rejects withsignal.reason.exceptionHandlingBehavior()never turns an abort-like error into a failure result. - Put
exceptionHandlingBehavior()outermost in the global behaviors so it also covers other behaviors. - Place
lockBehaviorbeforetransactionBehaviorfor process-wide locks, after it for transaction-scoped locks. - A failed lock acquisition throws
LockTimeoutError(not a failure result). - Handlers return
Result<T>; do not return bare values.