@nzelajs/nestjs
v0.1.0
Published
Nzela NestJS integration: a thin dependency-injection wrapper that wires the workflow engine as an injectable provider. Adapter-agnostic (the app supplies uow, guards, effects, authorizer, ...).
Maintainers
Readme
@nzelajs/nestjs
English below - Version francaise plus bas.
A thin NestJS dependency-injection wrapper for the Nzela workflow engine. It builds a
WorkflowEngine from the adapters you supply and provides it under one injection token. It stays
adapter-agnostic: it depends on no concrete persistence, guard, or authorizer. Your app declares
its adapters (doctrine: explicit wiring, zero magic).
English
Install
npm add @nzelajs/nestjs @nzelajs/core @nzelajs/ports
# plus the adapters your app chooses, e.g.
npm add @nzelajs/persistence-prisma @nzelajs/adapter-expr-cel@nestjs/common (>=11) and reflect-metadata are peer dependencies (your Nest app already has
them).
What it provides
NzelaModule.forRoot(options): synchronous wiring. Builds aNzelaEnginefrom the options and provides it underNZELA_ENGINE.NzelaModule.forRootAsync(options):useFactory+inject, so adapters come from other modules' DI (a config service, a Prisma unit of work, a Kengela authorizer).NZELA_ENGINE: the injection token for theWorkflowEngine.@InjectNzelaEngine(): sugar for@Inject(NZELA_ENGINE).createNzelaEngine(options): build the same engine outside NestJS (scripts, tests).
Options
NzelaModuleOptions carries the engine dependencies (all adapters, supplied by your app):
- required:
uow,blueprints,guards,effects,outboxSigner. - optional:
clock(defaults tosystemClock),authorizer,resolverFactory,tenantContext. - node behaviors, two ways:
handlers: aNodeHandlerRegistryyou have already filled (takes precedence).nodeHandlers: { generic?, approval?, advanced? }: the module builds anInMemoryNodeHandlerRegistryand registers the selected built-in bundles. Default when neither is set:{ generic: true }(thestateandautohandlers).
Fail-closed: nodeHandlers.approval: true REQUIRES a resolverFactory. Without it the module
throws at construction: an approval node with no approver resolver could create no task and let a
case slip past an approval gate, so the misconfiguration is refused up front.
forRoot
import { Module } from "@nestjs/common";
import { NzelaModule } from "@nzelajs/nestjs";
import { systemClock } from "@nzelajs/ports";
// concrete adapters chosen by your app:
import {
PrismaUnitOfWork,
PrismaBlueprintProvider,
} from "@nzelajs/persistence-prisma";
import { CelGuardRunner } from "@nzelajs/adapter-expr-cel";
@Module({
imports: [
NzelaModule.forRoot({
uow: new PrismaUnitOfWork(prisma),
blueprints: new PrismaBlueprintProvider(),
guards: new CelGuardRunner(),
effects: myEffectRunner,
outboxSigner: myOutboxSigner,
clock: systemClock,
nodeHandlers: { generic: true, advanced: true },
}),
],
})
export class AppModule {}forRootAsync
import { NzelaModule } from "@nzelajs/nestjs";
import type { NzelaModuleOptions } from "@nzelajs/nestjs";
NzelaModule.forRootAsync({
imports: [InfraModule],
inject: [UNIT_OF_WORK, BLUEPRINTS, GUARDS, EFFECTS, OUTBOX_SIGNER],
useFactory: (
uow,
blueprints,
guards,
effects,
outboxSigner,
): NzelaModuleOptions => ({
uow,
blueprints,
guards,
effects,
outboxSigner,
nodeHandlers: { generic: true },
}),
});Injecting the engine
import { Injectable } from "@nestjs/common";
import { InjectNzelaEngine } from "@nzelajs/nestjs";
import type { WorkflowEngine } from "@nzelajs/ports";
@Injectable()
export class LeaveService {
constructor(@InjectNzelaEngine() private readonly engine: WorkflowEngine) {}
submit(tenantId: string, caseId: string, actorId: string) {
return this.engine.dispatch({
tenantId,
caseId,
actorId,
action: "submit",
idempotencyKey: `submit:${caseId}`,
});
}
}Francais
Un fin wrapper d'injection de dependances NestJS pour le moteur de workflow Nzela. Il construit un
WorkflowEngine a partir des adapters que vous fournissez et l'expose sous un seul jeton
d'injection. Il reste agnostique : il ne depend d'aucune persistance, garde ou authorizer concret.
Votre app declare ses adapters (doctrine : cablage explicite, zero magie).
Installation
npm add @nzelajs/nestjs @nzelajs/core @nzelajs/ports
# plus les adapters choisis par votre app, ex.
npm add @nzelajs/persistence-prisma @nzelajs/adapter-expr-cel@nestjs/common (>=11) et reflect-metadata sont des peer dependencies (votre app Nest les a
deja).
Ce que ca fournit
NzelaModule.forRoot(options): cablage synchrone. Construit unNzelaEnginea partir des options et l'expose sousNZELA_ENGINE.NzelaModule.forRootAsync(options):useFactory+inject, pour recuperer les adapters depuis la DI d'autres modules (service de config, unit of work Prisma, authorizer Kengela).NZELA_ENGINE: le jeton d'injection duWorkflowEngine.@InjectNzelaEngine(): sucre pour@Inject(NZELA_ENGINE).createNzelaEngine(options): construit le meme moteur hors NestJS (scripts, tests).
Options
NzelaModuleOptions porte les dependances du moteur (tous les adapters, fournis par votre app) :
- requis :
uow,blueprints,guards,effects,outboxSigner. - optionnels :
clock(defautsystemClock),authorizer,resolverFactory,tenantContext. - comportements de noeud, deux voies :
handlers: unNodeHandlerRegistrydeja rempli (prioritaire).nodeHandlers: { generic?, approval?, advanced? }: le module construit unInMemoryNodeHandlerRegistryet enregistre les briques demandees. Defaut si aucun des deux n'est fourni :{ generic: true }(les handlersstateetauto).
Fail-closed : nodeHandlers.approval: true EXIGE un resolverFactory. Sans lui, le module leve
une erreur a la construction : un noeud d'approbation sans resolveur d'approbateurs ne creerait
aucune tache et laisserait un dossier franchir une porte d'approbation ; la mauvaise configuration
est donc refusee d'emblee.
forRoot
Voir l'exemple forRoot ci-dessus (section anglaise) : les adapters concrets sont choisis par votre
app et passes tels quels dans les options.
forRootAsync
Voir l'exemple forRootAsync ci-dessus : imports + inject recuperent les adapters depuis la DI,
et useFactory renvoie les NzelaModuleOptions.
Injecter le moteur
Utilisez @InjectNzelaEngine() sur un parametre du constructeur pour recevoir le WorkflowEngine
(voir l'exemple LeaveService ci-dessus).
License
Apache-2.0
