@cqrs-ddd/pipeline-tenant
Keeps the current tenant of an execution in AsyncLocalStorage. runWithTenant(id, fn)
sets it for everything fn calls, synchronously or asynchronously; currentTenantId()
reads it; and tenantSource hands it to a pipeline, so every pipeline runs in the tenant of
the work that started it. The package has no dependencies.
Installation
Section titled “Installation”pnpm add @cqrs-ddd/pipeline-tenantimport { createPipeline } from '@cqrs-ddd/pipeline';import { currentTenantId, runWithTenant, tenantSource } from '@cqrs-ddd/pipeline-tenant';
const pipeline = createPipeline({ sources: { tenantId: tenantSource } });
const listOrders = pipeline.wrap({ name: 'listOrders', kind: 'query' })(async () => orders.findByTenant(currentTenantId()),);
await runWithTenant('acme', () => listOrders());An HTTP middleware or a queue consumer sets the tenant once, at the edge:
app.use((req, res, next) => runWithTenant(req.auth.tenantId, next));Semantics
Section titled “Semantics”runWithTenant(tenantId, fn)returns whatfnreturns. A nested call replaces the tenant for its own callback only;undefinedrunsfnwith no tenant.currentTenantId()returns the tenant of the innermostrunWithTenantcall or running pipeline, orundefinedoutside both.- Inside a pipeline,
context.tenantIdis the tenant the execution took from the source when it started.
The cache, idempotency and rate-limit behaviors partition their keys by this tenant and fail closed when they need one and the execution has none. See The pipeline context.