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

@noctcore/eslint-plugin-prisma

v0.5.0

Published

Prisma tenancy, data-integrity and transaction guardrails: unscoped-client and raw-SQL fences, tenant and soft-delete filters, single-writer model fences, multi-write transactions, audit placement and audit reachability.

Downloads

395

Readme

@noctcore/eslint-plugin-prisma

Prisma tenancy, data-integrity and transaction guardrails: fence the escape hatches around a tenant-scoping client extension, keep tenant and soft-delete filters on the queries that need them, fence single-writer models to their owners, and keep multi-write code transactional. Flat-config only, ESLint 9+.

Install

bun add -D @noctcore/eslint-plugin-prisma   # or npm i -D / pnpm add -D

Use

// eslint.config.js
import prisma from '@noctcore/eslint-plugin-prisma';

export default [
  prisma.configs.recommended,
];

Or wire rules individually, with your project's conventions:

import prisma from '@noctcore/eslint-plugin-prisma';

export default [
  {
    files: ['apps/api/src/**/*.ts'],
    ignores: ['**/*.{spec,test}.ts'],
    plugins: { 'noctcore-prisma': prisma },
    rules: {
      'noctcore-prisma/no-unscoped-prisma-outside-allowlist': ['error', {
        allowedFiles: ['**/prisma/seed.ts', '**/prisma/migrations/**', '**/common/database/prisma.service.ts'],
        escapeHatchFns: ['runWithoutTenantScope'],
      }],
      'noctcore-prisma/no-raw-sql-outside-allowlist': 'error',
      'noctcore-prisma/prisma-write-in-transaction': ['error', { clientProperties: ['client'] }],
      'noctcore-prisma/prisma-tx-uses-tx-not-client': ['error', { clientProperties: ['client'] }],
      'noctcore-prisma/no-cross-tenant-id-in-where': 'error',
      'noctcore-prisma/no-request-body-in-write': 'error',
      'noctcore-prisma/no-audit-write-in-transaction': 'error',

      // Needs type information: see its docs.
      'noctcore-prisma/mutation-entry-must-reach-audit': ['error', { unauditedModels: ['tourProgress'] }],

      // These need your registry and report nothing without it.
      'noctcore-prisma/tenant-scoped-tables-require-where': ['error', {
        tenantModels: ['invoice', 'customer'],
        handScopedModels: { notification: ['userId'] },
      }],
      'noctcore-prisma/tenant-write-must-carry-tenant-id': ['error', { tenantModels: ['invoice', 'customer'] }],
      'noctcore-prisma/soft-deletable-tables-require-deleted-at': ['error', {
        softDeleteModels: ['user'],
        softDeleteSpreads: ['notDeleted'],
      }],
      'noctcore-prisma/restrict-model-writes': ['error', {
        restrictions: [
          { models: ['payment'], allowedFiles: ['**/billing/payment.service.ts'], owner: 'PaymentService' },
          {
            models: ['invoice'],
            fields: ['status'],
            allowedFiles: ['**/billing/invoice-lifecycle.service.ts'],
            owner: 'InvoiceLifecycleService',
          },
        ],
      }],
    },
  },
];

recommended turns on the seven rules whose defaults hold with no project knowledge. Four more need your model registry (tenantModels, softDeleteModels, restrictions) and are left out of the preset on purpose: an entry that reports nothing would read as coverage you do not have. The last one, mutation-entry-must-reach-audit, needs type information.

No project convention is hardcoded. What a Prisma receiver is called (receiverPattern), the unscoped client's property (unscopedProperty), escape-hatch functions (escapeHatchFns), extra client properties (clientProperties) and transaction-client names (txRootNames) are all options with defaults that fit a conventional Prisma codebase. Which models are tenant-scoped, soft-deletable or single-writer is never guessed: those lists default to empty. The rules are name- and shape-based and need no type information, with one exception: mutation-entry-must-reach-audit follows calls across files through the type checker, refuses to run without it, and is not in recommended for that reason.

Three rules state a limit loudly, because their names could be read as promising more: restrict-model-writes fences WHO writes a model, and does not validate state transitions; no-audit-write-in-transaction polices WHERE an audit write sits, and does not check that mutations are audited. mutation-entry-must-reach-audit is the rule that checks audits exist, and it states its own limit in its name: it proves an audit is reachable from each mutation entry point, not that every mutating method audits.

Rules

| Rule | Description | | --- | --- | | mutation-entry-must-reach-audit | A @Mutation() entry that can reach a Prisma write must be able to reach an audit write, across files. Needs type information. | | no-audit-write-in-transaction | No audit-log write inside a $transaction callback. Does not check that mutations are audited. | | no-cross-tenant-id-in-where | A tenant id in where / data comes from server context, never from client input. | | no-raw-sql-outside-allowlist | Raw SQL that can touch a table only in allowlisted files; *Unsafe never. | | no-request-body-in-write | A write's data or where is never the raw request body (mass assignment, filter injection). | | no-unscoped-prisma-outside-allowlist | The unscoped client and tenant-scope escape hatches only in allowlisted files. | | prisma-tx-uses-tx-not-client | Inside an interactive $transaction, writes go through tx, not the outer client. | | prisma-write-in-transaction | Two or more writes in one function must be wrapped in a $transaction. | | restrict-model-writes | Only a model's owning files may write it (or its fenced columns), nested writes included. Does not check transitions. | | soft-deletable-tables-require-deleted-at | Filtered reads and bulk writes on soft-deletable models exclude deleted rows. | | tenant-scoped-tables-require-where | Unscoped-client queries on tenant models filter by every tenant column; hand-scoped models filter by a scope column on any client. | | tenant-write-must-carry-tenant-id | Unscoped-client creates on tenant models set every tenant column in data. |

Building blocks

The package also exports the pieces its rules are built on, so a project's own tooling reads the same definitions instead of a copy that drifts: the Prisma method sets (PRISMA_WRITE_METHODS, PRISMA_DELEGATE_METHODS, ...), a small schema reader (parsePrismaSchema, loadPrismaSchema, tenantBearingAccessors) and reconcileTenantRegistry, which checks a tenant-scope registry against the schema so a new tenant-bearing table cannot ship with no boundary.