npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nzelajs/persistence-prisma

v0.1.0

Published

Prisma/Postgres persistence adapter for the Nzela engine: tenant-scoped unit of work with PostgreSQL row-level security, optimistic-locked instances, append-only event log, versioned immutable blueprint installs, approval and org-chart stores. Narrow Pris

Downloads

51

Readme

@nzelajs/persistence-prisma

English below - Version francaise plus bas.

The Prisma/Postgres persistence adapter for the Nzela engine: the single adapter that knows the database. It binds PostgreSQL row-level security per transaction, optimistic-locks instances, keeps an append-only event log, stores versioned immutable blueprint installs and the approval/org-chart companion stores. It depends on a NARROW PrismaLike surface: no client is generated here and nothing is imported from @prisma/client at runtime. Vendor-free by the Nzela doctrine.

English

Install

npm add @nzelajs/persistence-prisma @nzelajs/ports
# and, in your app, the real client generated from your schema:
npm add prisma @prisma/client

prisma and @prisma/client are OPTIONAL peer dependencies: this package never imports them. You generate your own client from a schema shaped like prisma/schema.reference.prisma, and it is structurally assignable to PrismaLike.

What it provides

  • PrismaUnitOfWork implements UnitOfWork. withTenant(tenantId, fn) opens an interactive Prisma transaction and, as its FIRST statement, binds the tenant context with SELECT set_config('app.tenant_id', $1, true) so every subsequent query is tenant-isolated at the database level. It hands fn a RepositoryRegistry scoped to that transaction. Fail-closed: an empty tenant id is refused before any connection is used.
  • All repositories of the registry, on the transaction:
    • WorkflowInstanceRepo: optimistic locking via a conditional updateMany on { id, version } (a zero count raises ConcurrencyConflictError); every write bumps version.
    • EventLog: append + listByInstance in createdAt order (append-only history).
    • TimerStore, ExternalWaitStore, DependencyStore.
    • BlueprintInstallStore: publish validates the graph with parseBlueprint BEFORE writing (fail-closed), computes the next version, archives the previous ACTIVE and inserts the new ACTIVE, all inside the same transaction (atomic). In-flight instances stay pinned via installId.
    • OutboxRepository: transactional outbox append.
    • ApprovalTaskStore, DeskRuleStore (decreasing-specificity resolution), TenantSettingsStore, OrgStore, DirectoryStore, AuthzStore (loadGrantsForUser, fail-closed provenance).
  • A NARROW PrismaLike / PrismaTx surface (prisma-like.ts) plus fail-closed row mappers (mapping.ts): union columns stay String in the database and are narrowed to the domain literals here; an unreadable value is dropped or defaulted, never widened.
  • prisma/schema.reference.prisma: a generic Postgres reference schema (every model carries tenantId plus indexes) with a documented RLS policy. Not generated by this package.

Row-level security (the convention this adapter requires)

Security is enforced by the database, not by application filters. The host materializes, once (a raw SQL migration, not Prisma-managed):

-- Reads the transaction-local tenant, fail-closed (NULL when unset).
CREATE OR REPLACE FUNCTION current_tenant_id() RETURNS text
  LANGUAGE sql STABLE AS $$ SELECT current_setting('app.tenant_id', true) $$;

-- For every table (example on "WorkflowInstance"): RESTRICTIVE + FORCE, gating reads and writes.
ALTER TABLE "WorkflowInstance" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "WorkflowInstance" FORCE  ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON "WorkflowInstance"
  AS RESTRICTIVE
  USING ("tenantId" = current_tenant_id())
  WITH CHECK ("tenantId" = current_tenant_id());

PrismaUnitOfWork sets app.tenant_id (transaction-local, is_local = true) before any query, so a transaction can neither read nor write another tenant's rows. When the setting is unset, current_tenant_id() is NULL and the predicate is false: the transaction sees nothing (fail-closed).

RLS self-probe (ON by default). On the FIRST withTenant, the unit of work reads current_tenant_id() back and asserts it equals the bound tenant. A host that deployed the adapter but forgot to install prisma/rls.sql gets a clear error at boot instead of silently relying on the belt-and-suspenders tenantId filters. Opt out with new PrismaUnitOfWork(prisma, { verifyRlsOnFirstUse: false }) only when the probe cannot run (e.g. a fake in tests).

Example

import { PrismaClient } from "@prisma/client";
import { PrismaUnitOfWork } from "@nzelajs/persistence-prisma";

const prisma = new PrismaClient();
const uow = new PrismaUnitOfWork(prisma); // structurally a PrismaLike

await uow.withTenant("acme", async (repos) => {
  const c = await repos.instances.create({
    requestTypeId: "leave",
    status: "DRAFT",
    data: {},
  });
  await repos.instances.updateStatus(c.id, {
    fromVersion: 1,
    toStatus: "GATE",
  });
});

Francais

Installation

npm add @nzelajs/persistence-prisma @nzelajs/ports
# et, cote application, le vrai client genere depuis votre schema :
npm add prisma @prisma/client

prisma et @prisma/client sont des peer dependencies OPTIONNELLES : ce paquet ne les importe jamais. Vous generez votre propre client depuis un schema de la forme de prisma/schema.reference.prisma ; il est structurellement assignable a PrismaLike.

Ce que le paquet fournit

  • PrismaUnitOfWork implemente UnitOfWork. withTenant(tenantId, fn) ouvre une transaction Prisma interactive et, en TOUT PREMIER, lie le contexte tenant via SELECT set_config('app.tenant_id', $1, true) : chaque requete suivante est isolee par tenant au niveau base. Il passe a fn un RepositoryRegistry limite a cette transaction. Fail-closed : un tenant vide est refuse avant toute connexion.
  • Tous les depots du registre, sur la transaction : verrou optimiste par version (ConcurrencyConflictError si conflit), journal d'evenements append-only ordonne, installs de blueprint versionnes/immuables/epingles (validation parseBlueprint AVANT ecriture, archivage atomique de l'ACTIVE precedente), outbox transactionnel, stores d'approbation et d'organigramme.
  • Surface NARROW PrismaLike / PrismaTx + mappeurs fail-closed : les colonnes d'union restent String en base et sont retrecies vers les litteraux du domaine ici ; une valeur illisible est ecartee ou ramenee a un defaut sur, jamais elargie.
  • prisma/schema.reference.prisma : schema Postgres de reference (colonne tenantId partout + index) avec la politique RLS documentee. Non genere par ce paquet.

Securite au niveau ligne (la convention exigee)

La securite est portee par la base, pas par des filtres applicatifs. L'hote materialise une fois (une migration SQL brute, hors Prisma) la fonction current_tenant_id() (lecture fail-closed de app.tenant_id) et, pour chaque table, une politique RESTRICTIVE + FORCE portant sur USING et WITH CHECK (voir le bloc SQL de la section anglaise et prisma/schema.reference.prisma). PrismaUnitOfWork pose app.tenant_id (portee transaction, is_local = true) avant toute requete : la transaction ne peut ni lire ni ecrire les lignes d'un autre tenant ; contexte absent = rien de visible (fail-closed).

Sonde RLS (ACTIVEE par defaut). Au PREMIER withTenant, l'unite de travail relit current_tenant_id() et verifie qu'il vaut le tenant lie. Un hote qui a deploye l'adaptateur sans installer prisma/rls.sql obtient une erreur claire au demarrage au lieu de dependre en silence des filtres tenantId de ceinture. Desactivable via new PrismaUnitOfWork(prisma, { verifyRlsOnFirstUse: false }) uniquement quand la sonde ne peut pas s'executer (ex. un fake de test).

License

Apache-2.0. See LICENSE and NOTICE.