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

@tenantscale/prisma

v0.1.0

Published

Prisma ORM tenant query guard for TenantScale

Readme

@tenantscale/prisma

Tenant-safe Prisma ORM helpers for TenantScale.

Install

npm install @tenantscale/prisma
# or
pnpm add @tenantscale/prisma

Usage

This package provides two approaches for tenant-scoped Prisma queries:

1. Automatic Query Scoping with withTenantScope

The recommended approach uses Prisma's $extends() API to automatically inject tenant filters into all queries. This prevents cross-tenant data leaks by ensuring every query is scoped to the current tenant.

import { PrismaClient } from '@prisma/client'
import { withTenantScope } from '@tenantscale/prisma'

const prisma = new PrismaClient()

// Create a tenant-scoped client
const tenantPrisma = prisma.$extends(withTenantScope({ tenantId: 'tenant-123' }))

// All queries are automatically scoped to tenant-123
const users = await tenantPrisma.user.findMany()
// Equivalent to: prisma.user.findMany({ where: { tenant_id: 'tenant-123' } })

// Create operations automatically include tenant_id
const user = await tenantPrisma.user.create({
  data: { name: 'John', email: '[email protected]' }
  // tenant_id is automatically added: { name: 'John', email: '[email protected]', tenant_id: 'tenant-123' }
})

// Update operations automatically include tenant filter
const updated = await tenantPrisma.user.update({
  where: { id: 'user-1' },
  data: { name: 'John Updated' }
  // Automatically becomes: { where: { id: 'user-1', tenant_id: 'tenant-123' }, ... }
})

// Delete operations automatically include tenant filter
await tenantPrisma.user.delete({
  where: { id: 'user-1' }
  // Automatically becomes: { where: { id: 'user-1', tenant_id: 'tenant-123' } }
})

Supported Operations:

  • findMany(), findFirst(), findUnique() - auto-adds WHERE tenant_id = ?
  • update(), updateMany() - auto-adds WHERE tenant_id = ?
  • delete(), deleteMany() - auto-adds WHERE tenant_id = ?
  • create(), createMany() - auto-adds tenant_id to data
  • upsert() - auto-adds tenant_id to where, create, and update

2. Manual Filtering with tenantFilter

For explicit control, use the tenantFilter helper to manually add tenant conditions to your queries:

import { tenantFilter } from '@tenantscale/prisma'

// Select with tenant filter
const users = await prisma.user.findMany({
  where: {
    ...tenantFilter('tenant-123'),
    status: 'active'
  }
})

// Update with tenant filter
await prisma.user.update({
  where: {
    id: 'user-1',
    ...tenantFilter('tenant-123')
  },
  data: { status: 'inactive' }
})

// Delete with tenant filter
await prisma.user.deleteMany({
  where: tenantFilter('tenant-123')
})

Custom Tenant Column

If your schema uses a different column name for tenant isolation:

import { withTenantScope } from '@tenantscale/prisma'

const tenantPrisma = prisma.$extends(
  withTenantScope({ 
    tenantId: 'tenant-123', 
    tenantColumn: 'organization_id' 
  })
)

// Or with tenantFilter
import { tenantFilter } from '@tenantscale/prisma'

const filter = tenantFilter('tenant-123', 'organization_id')

Integration with TenantScale

Combine with the TenantScale SDK for complete multi-tenant isolation:

import { PrismaClient } from '@prisma/client'
import { TenantScale } from '@tenantscale/sdk'
import { withTenantScope } from '@tenantscale/prisma'

const ts = new TenantScale({
  supabaseUrl: process.env.SUPABASE_URL!,
  supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
})

const prisma = new PrismaClient()

// In your API route handler
app.post('/api/users', async (req, res) => {
  // Validate API key
  const apiKey = await ts.validateApiKey(req.headers.authorization)
  
  // Create tenant-scoped Prisma client
  const tenantPrisma = prisma.$extends(
    withTenantScope({ tenantId: apiKey.tenant_id })
  )
  
  // All queries are automatically scoped to the authenticated tenant
  const users = await tenantPrisma.user.findMany()
  
  res.json(users)
})

Design

This package leverages Prisma 5+'s native $extends() API for clean, type-safe query modification:

  • Automatic injection: The withTenantScope extension automatically adds tenant filters to all operations, making cross-tenant leaks structurally impossible.
  • No schema modification: Works with your existing Prisma schema - just ensure your tables have a tenant_id column (or custom column name).
  • Type safety: Uses Prisma's extension types for full TypeScript support.
  • Explicit fallback: The tenantFilter helper is available for cases where you need manual control over tenant filtering.

Error Handling

Both helpers throw an error if tenantId is empty or undefined:

withTenantScope({ tenantId: '' }) // Throws: tenantId is required
tenantFilter('') // Throws: tenantId is required

Limitations

  • The extension assumes your tables have a tenant column (default: tenant_id). You must add this column to your schema manually.
  • For findUnique operations, the tenant filter is added to the where clause. Ensure your unique constraints include the tenant column for proper isolation.
  • The extension does not modify raw SQL queries executed via $queryRaw or $executeRaw.

Testing

The package includes comprehensive tests covering all Prisma operations:

pnpm test

License

MIT