feat(prisma): add experimental @aura-stack/prisma package - #239
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
📝 WalkthroughWalkthroughThis PR adds a Prisma package with authentication schemas, domain mappers, and a database adapter. It integrates Prisma-backed stateful authentication and stateless Elysia endpoint tests, adds shared adapter conformance tests, and expands device and OAuth transaction entity types. ChangesPrisma adapter integration
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (3)
packages/prisma/src/client.ts (1)
1-1: 📐 Maintainability & Code Quality | 🔵 TrivialUnconditional
dotenv/configside-effect import in a library entrypoint.Loading
.envautomatically on import is typically an application-level concern, not a library one. Consumers of@aura-stack/prismathat already manage their own env loading (or run in environments where.envfiles shouldn't be read, e.g. production containers) get this side effect forced on them just by importing the package's client module.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/client.ts` at line 1, Remove the unconditional dotenv/config side-effect import from the library entrypoint in client.ts, ensuring importing the Prisma client no longer automatically loads .env files. Leave environment configuration responsibility to the consuming application.packages/prisma/src/adapter.ts (1)
39-50: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
createUserspreads raw domain input into Prisma's typeddata, inconsistent withupdateUser's explicit-field style.Spreading
...inputbypasses TypeScript's excess-property checking (which only applies to literal properties, not spread ones), so any field on the domainCreateUserInputtype that doesn't exist on Prisma'sUserCreateInputwould be silently forwarded and could trigger a runtimePrismaClientValidationError("Unknown argument").updateUserright below (lines 62-82) builds thedataobject explicitly field-by-field — recommend the same pattern here for consistency and type safety.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/adapter.ts` around lines 39 - 50, Update createUser to construct Prisma’s data object explicitly from supported CreateUserInput fields instead of spreading ...input, matching updateUser’s field-by-field pattern. Preserve the existing conversions for emailVerifiedAt, status, mfaPreferredMethod, and attributes while excluding unsupported domain-only fields.packages/prisma/src/index.ts (1)
1-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExporting a pre-built
prismaClientsingleton from the package's public entrypoint forces an eager DB connection on import.
prismaAdapteris a flexible factory that takes a caller-suppliedPrismaClient, butindex.tsalso re-exports the concreteprismaClientinstance fromclient.ts, which eagerly constructs aPrismaPgadapter (and thus a connection pool) at module-load time, gated onprocess.env.DATABASE_URLbeing set. Any consumer importing@aura-stack/prisma— even just forprismaAdapteror types — pays this side effect and env-var dependency. Consider keepingprismaClientas an internal test-only convenience (as used inpackages/prisma/test/setup/prisma.ts) rather than part of the public package surface, letting consumers construct/own their ownPrismaClient.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/index.ts` around lines 1 - 6, Remove the public prismaClient re-export from the package entrypoint in index.ts, while preserving the prismaAdapter and PrismaAdapterOptions exports and PrismaClient type export. Keep prismaClient available only through its internal test setup usage, so importing the package does not eagerly construct a database client or require DATABASE_URL.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/prisma/package.json`:
- Line 4: Remove the "private": true declaration from the packages/prisma
package manifest so the package can be published, while preserving its existing
publishConfig and prepublishOnly settings.
- Line 10: Update the build script in package.json to invoke Prisma through the
workspace-installed CLI using pnpm exec prisma generate, then preserve the
existing tsdown step.
In `@packages/prisma/README.md`:
- Line 8: Update the JSR badge link in the README to point to the
`@aura-stack/prisma` package page instead of `@aura-stack/integration`, while
leaving the badge image URL unchanged.
In `@packages/prisma/src/adapter.ts`:
- Around line 153-168: The createOAuthAccount method should reject missing OAuth
access tokens instead of persisting an empty string. Validate input.accessToken
before client.oAuthAccount.create and fail clearly when it is absent, while
preserving the existing token value and account creation flow for valid input.
- Around line 96-108: Validate the required fields in createAccount,
createOAuthAccount, and createCredentialAccount before calling Prisma: userId,
provider, providerUserId, type, accountId, and passwordHash as applicable.
Replace the non-null assertions with explicit checks that throw a clear domain
error when any required value is missing, while preserving the existing
persistence and conversion flow for valid inputs.
- Around line 497-507: Update consumeOAuthTransaction to handle a concurrently
consumed OAuth state without propagating Prisma P2025: prefer an atomic
deleteMany-style operation that checks the affected count and returns null when
no row was deleted, while preserving transaction conversion for a successful
deletion; alternatively catch only P2025 from the existing delete and return
null.
In `@packages/prisma/src/client.ts`:
- Around line 5-7: Validate process.env.DATABASE_URL before constructing
PrismaPg in the module initialization around adapter. If it is unset, fail
immediately with a clear message that DATABASE_URL is required; otherwise pass
the validated value as connectionString.
In `@packages/prisma/src/mappers.ts`:
- Around line 335-339: Update appendRevokeReason to accept a revokedAt timestamp
parameter and use it for metadata instead of creating a new timestamp. Modify
both revokeSession and revokeAllSessions call sites in adapter.ts to pass the
same revokedAt Date value used for the session column update, preserving
consistency between session.revokedAt and session.metadata.revokedAt.
- Around line 146-157: Rename the exported mapper function toMFAStatus and
update every reference to it, especially the call sites in adapter.ts, while
preserving the existing MFAState-to-PrismaMfaState mappings.
- Around line 41-43: Update toJson in packages/prisma/src/mappers.ts to preserve
explicit null semantics for nullable JSON fields: map JSON null to
Prisma.JsonNull, SQL null to Prisma.DbNull where applicable, and leave undefined
as undefined. Replace the current as never coercion with the appropriate Prisma
sentinel-aware return type, while keeping fromJson unchanged.
In `@packages/prisma/test/setup/prisma.ts`:
- Around line 7-8: Add package-level Vitest teardown in the setup module
containing prismaClient so it calls prismaClient.$disconnect() after the test
suite completes, ensuring the PostgreSQL connection pool is closed.
---
Nitpick comments:
In `@packages/prisma/src/adapter.ts`:
- Around line 39-50: Update createUser to construct Prisma’s data object
explicitly from supported CreateUserInput fields instead of spreading ...input,
matching updateUser’s field-by-field pattern. Preserve the existing conversions
for emailVerifiedAt, status, mfaPreferredMethod, and attributes while excluding
unsupported domain-only fields.
In `@packages/prisma/src/client.ts`:
- Line 1: Remove the unconditional dotenv/config side-effect import from the
library entrypoint in client.ts, ensuring importing the Prisma client no longer
automatically loads .env files. Leave environment configuration responsibility
to the consuming application.
In `@packages/prisma/src/index.ts`:
- Around line 1-6: Remove the public prismaClient re-export from the package
entrypoint in index.ts, while preserving the prismaAdapter and
PrismaAdapterOptions exports and PrismaClient type export. Keep prismaClient
available only through its internal test setup usage, so importing the package
does not eagerly construct a database client or require DATABASE_URL.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1f5fb147-816a-44f4-aeee-0afb34701940
⛔ Files ignored due to path filters (3)
bun.lockis excluded by!**/*.lockdeno.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
package.jsonpackages/core/src/@types/entities.tspackages/prisma/.env.examplepackages/prisma/.gitignorepackages/prisma/.vscode/extensions.jsonpackages/prisma/CHANGELOG.mdpackages/prisma/README.mdpackages/prisma/deno.jsonpackages/prisma/package.jsonpackages/prisma/prisma.config.tspackages/prisma/prisma/schema.prismapackages/prisma/src/adapter.tspackages/prisma/src/client.tspackages/prisma/src/index.tspackages/prisma/src/mappers.tspackages/prisma/src/model.mdpackages/prisma/test/index.test.tspackages/prisma/test/setup/prisma.tspackages/prisma/tsconfig.jsonpackages/prisma/tsdown.config.tspackages/prisma/vitest.config.ts
| createAccount: async (input) => { | ||
| const account = await client.account.create({ | ||
| data: { | ||
| id: input.id, | ||
| userId: input.userId!, | ||
| provider: input.provider!, | ||
| providerUserId: input.providerUserId!, | ||
| type: toAccountType(input.type!), | ||
| status: input.status ? toAccountStatus(input.status) : undefined, | ||
| }, | ||
| }) | ||
| return toAccount(account) | ||
| }, |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the domain create-input types referenced by these adapter functions.
fd entities.ts packages/core/src --exec cat -n {}
rg -n 'CreateAccountInput|CreateOAuthAccountInput|CreateCredentialAccountInput' -C5 packages/core/srcRepository: aura-stack-ts/auth
Length of output: 5513
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== location files =="
fd 'adapter\.ts|types|entities' packages -e ts -e tsx | rg 'packages/.*(adapter\.ts|types|entities)' | sed -n '1,200p'
echo "== target adapter relevant sections =="
if [ -f packages/prisma/src/adapter.ts ]; then
wc -l packages/prisma/src/adapter.ts
sed -n '1,230p' packages/prisma/src/adapter.ts | cat -n
fi
echo "== package names and references =="
rg -n '"`@aura-stack/auth`|aura-stack/auth|CreateAccountInput|CreateOAuthAccountInput|CreateCredentialAccountInput|createAccount|createOAuthAccount|createCredentialAccount' packages -g '*.{ts,tsx,js,jsx,json}' -C 3Repository: aura-stack-ts/auth
Length of output: 32435
Validate required account-creation fields before persisting.
createAccount, createOAuthAccount, and createCredentialAccount consume Partial<...> inputs, but userId, provider, providerUserId, type, accountId, and passwordHash are still required account data. The ! assertions can silently ship undefined into Prisma; validate these fields and throw a clear domain error instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/prisma/src/adapter.ts` around lines 96 - 108, Validate the required
fields in createAccount, createOAuthAccount, and createCredentialAccount before
calling Prisma: userId, provider, providerUserId, type, accountId, and
passwordHash as applicable. Replace the non-null assertions with explicit checks
that throw a clear domain error when any required value is missing, while
preserving the existing persistence and conversion flow for valid inputs.
| export const toJson = (value: Record<string, unknown> | null | undefined) => (value ?? undefined) as never | ||
|
|
||
| export const fromJson = (value: unknown): Record<string, unknown> | null => (isRecord(value) ? value : null) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## locate mappers and prisma files"
fd -a 'mappers\.ts$|schema\.prisma$|client\.ts$|\.prisma$' . | sed 's#^\./##' | head -100
echo
echo "## packages/prisma/src/mappers.ts"
if [ -f packages/prisma/src/mappers.ts ]; then
cat -n packages/prisma/src/mappers.ts
else
fd 'mappers\.ts$' . -x sh -c 'echo "--- $1"; cat -n "$1"' sh {}
fi
echo
echo "## search toJson usages/updater"
rg -n "toJson\(|fromJson\(|attributes === undefined|metadata: toJson|Prisma\.JsonNull|typeJsonValue|InputJsonValue" packages/prisma . --glob '!node_modules' --glob '!dist' --glob '!build' || true
echo
echo "## prisma schema json fields"
if [ -f packages/prisma/prisma/schema.prisma ]; then
rg -n "Json|json|attributes|metadata|JsonNull|DbNull" packages/prisma/prisma/schema.prisma -C 2
fi
if [ -f prisma/schema.prisma ]; then
rg -n "Json|json|attributes|metadata|JsonNull|DbNull" prisma/schema.prisma -C 2
fiRepository: aura-stack-ts/auth
Length of output: 17611
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p=Path('packages/prisma/src/mappers.ts')
text=p.read_text() if p.exists() else ''
lines=text.splitlines()
for i,l in enumerate(lines,1):
if 'toJson' in l or 'fromJson' in l or 'isRecord' in l:
print(f'{i}: {l}')
PYRepository: aura-stack-ts/auth
Length of output: 765
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## adapter relevant sections"
sed -n '1,110p' packages/prisma/src/adapter | cat -n
echo "---"
sed -n '210,290p' packages/prisma/src/adapter | cat -n
echo "---"
sed -n '290,370p' packages/prisma/src/adapter | cat -n
echo("---" )
sed -n '380,470p' packages/prisma/src/adapter | cat -n
echo
echo "## package/prisma imports and Prisma client availability"
sed -n '1,60p' packages/prisma/src/adapter.ts | cat -n
lc=$LC_ALL
export LC_ALL=C
npm list `@prisma/client` 2>/dev/null | rg '`@prisma/client`|missing' || true
if command -v pg_typescript 2>/dev/null || command -v tsc 2>/dev/null; then
echo "compiler available"
else
echo "compiler unavailable"
fi
echo
echo "## behavioral probe of mapper coercion"
node - <<'JS'
function isRecord(value) { return typeof value === "object" && value !== null && !Array.isArray(value); }
function toJson(value) { return value ?? undefined; }
function fromJson(value) { return isRecord(value) ? value : null; }
for (const input of [undefined, null, {}, {a:1}, []]) {
console.log(JSON.stringify(input), "=>", toJson(input));
}
console.log("fromJson null =>", fromJson(null));
console.log("fromJson object =>", fromJson({}));
JSRepository: aura-stack-ts/auth
Length of output: 256
🌐 Web query:
Prisma input JSON null JsonNull DbNull update null field undefined skip unchanged
💡 Result:
In Prisma Client, null and undefined are treated as distinct concepts with different behaviors in update operations [1][2]. For standard fields, passing undefined to an update operation instructs Prisma to ignore that field and perform no change to its value in the database [1][3]. In contrast, passing null explicitly instructs Prisma to update the database column to NULL (provided the field is nullable) [1][4]. For Json fields, which require special handling due to their unique nature in SQL, Prisma provides specific enums to differentiate between intended values [5][6]: - Prisma.JsonNull: Updates the database field to the JSON null value [5][6]. - Prisma.DbNull: Updates the database field to the SQL NULL value [5][6]. To skip updating a field entirely (the equivalent of passing undefined for standard fields), Prisma provides the Prisma.skip symbol [1][2]. The use of Prisma.skip is recommended over undefined when dealing with dynamic update objects, especially if you have enabled the strictUndefinedChecks preview feature, which is designed to prevent accidental data loss or unintended query behavior by strictly managing how undefined values are handled [1][2]. If you are programmatically constructing an update payload, you should ensure that fields you wish to remain unchanged are either omitted from the data object or explicitly set to Prisma.skip [3][7][2]. Using undefined as a fallback (e.g., value ?? undefined) is a common pattern to ensure that falsy values do not incorrectly trigger an update to null [1][3][2].
Citations:
- 1: https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/null-and-undefined
- 2: https://www.prisma.io/docs/orm/v6/prisma-client/special-fields-and-types/null-and-undefined
- 3: https://stackoverflow.com/questions/69526209/prisma-how-can-i-update-only-some-of-the-models-fields-in-update
- 4: Null vs undefined for optional values prisma/prisma-client-js#572
- 5: https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/working-with-json-fields
- 6: https://www.prisma.io/docs/orm/v6/prisma-client/special-fields-and-types/working-with-json-fields
- 7: How to not update some field if the value is null / '' / undefined ? prisma/prisma#5592
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## adapter relevant sections"
sed -n '1,110p' packages/prisma/src/adapter.ts | cat -n
echo "---"
sed -n '210,290p' packages/prisma/src/adapter.ts | cat -n
echo "---"
sed -n '290,370p' packages/prisma/src/adapter.ts | cat -n
echo "---"
sed -n '380,470p' packages/prisma/src/adapter.ts | cat -n
echo
echo "## adapter imports"
sed -n '1,45p' packages/prisma/src/adapter.ts | cat -n
echo
echo "## behavioral probe of mapper coercion"
node - <<'JS'
function isRecord(value) { return typeof value === "object" && value !== null && !Array.isArray(value); }
function toJson(value) { return value ?? undefined; }
function fromJson(value) { return isRecord(value) ? value : null; }
for (const input of [undefined, null, {}, {a:1}, []]) {
console.log(JSON.stringify(input), "=>", toJson(input));
}
console.log("fromJson null =>", fromJson(null));
console.log("fromJson object =>", fromJson({}));
JSRepository: aura-stack-ts/auth
Length of output: 17485
🌐 Web query:
site:prisma.io/docs working with JSON fields Prisma.JsonNull Prisma.DbNull JsonNull value null column sql null update
💡 Result:
When working with JSON fields in Prisma ORM, it is important to distinguish between a database NULL value and a JSON null value [1][2]. Prisma provides specialized enums to handle these cases explicitly, as standard null values can be ambiguous [1][3]. The available Prisma null types are: - Prisma.JsonNull: Represents a JSON null value stored within the JSON field [1][2]. - Prisma.DbNull: Represents a database NULL value (the absence of a value) in the JSON column [1][2]. - Prisma.AnyNull: Used only for filtering, this matches either a JSON null or a database NULL [1][2]. These enums are necessary because, in many SQL databases, there is a technical difference between a column being explicitly set to the JSON value null and the column having no value at all (database NULL) [1][2]. Note that these distinctions do not apply to MongoDB, which does not differentiate between the two [1][2]. Inserting or Updating JSON Fields To explicitly set a JSON field to one of these states during a create, update, or upsert operation, import Prisma from @prisma/client and pass the appropriate enum [1][2]: import { Prisma } from "@prisma/client"; // Setting to a JSON null value await prisma.log.update({ where: { id: 1 }, data: { meta: Prisma.JsonNull, }, }); // Setting to a database NULL await prisma.log.update({ where: { id: 1 }, data: { meta: Prisma.DbNull, }, }); Filtering JSON Fields When filtering for these values, you must explicitly use the equals operator with the desired enum [1][2]. You cannot use standard null shorthand [1][2]. // Filtering for JSON null await prisma.log.findMany({ where: { meta: { equals: Prisma.JsonNull }, }, }); Important Considerations - Versioning: Since Prisma ORM 4.0.0, these null handlers are implemented as objects rather than strings [2][4]. - Ambiguity: If you simply pass null to a JSON field in a query without these enums, the behavior may be ambiguous or result in errors, depending on your Prisma version and configuration [1][3]. - MongoDB: These distinctions are not applicable when using MongoDB, as it does not distinguish between JSON null and database NULL [1][2].
Citations:
- 1: https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/working-with-json-fields
- 2: https://www.prisma.io/docs/orm/v6/prisma-client/special-fields-and-types/working-with-json-fields
- 3: https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3
- 4: https://www.prisma.io/docs/v6/orm/more/upgrades/older-versions
Map explicit JSON null to Prisma’s null sentinels.
toJson collapses null and undefined to undefined, so the adapter cannot distinguish “write this to the JSON field” from “leave the field unchanged” for nullable Json columns. Use Prisma sentinels (Prisma.JsonNull for JSON null, Prisma.DbNull for SQL NULL) instead of the as never coercion, or update the returned type to Prisma.InputJsonValue | typeof Prisma.JsonNull | typeof Prisma.DbNull | undefined.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/prisma/src/mappers.ts` around lines 41 - 43, Update toJson in
packages/prisma/src/mappers.ts to preserve explicit null semantics for nullable
JSON fields: map JSON null to Prisma.JsonNull, SQL null to Prisma.DbNull where
applicable, and leave undefined as undefined. Replace the current as never
coercion with the appropriate Prisma sentinel-aware return type, while keeping
fromJson unchanged.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/prisma/src/adapter.ts (1)
267-281: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winTwo independent
new Date()calls can desync therevokedAtcolumn from the metadata timestamp.
revokedAt: new Date()and thenew Date()passed intoappendRevokeReasonon the next line are two separate calls that can differ by milliseconds.revokeAllSessionsright below gets this correct by computingrevokedAtonce and reusing it — this single-session path should follow the same pattern.🐛 Proposed fix
await client.session.update({ where: { id }, data: { status: "REVOKED", - revokedAt: new Date(), - metadata: toJson(appendRevokeReason(existing.metadata as Record<string, unknown> | null, reason, new Date())), + revokedAt, + metadata: toJson(appendRevokeReason(existing.metadata as Record<string, unknown> | null, reason, revokedAt)), }, })(with
const revokedAt = new Date()declared before the update call.)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/adapter.ts` around lines 267 - 281, Update revokeSession to create one revokedAt timestamp before client.session.update, then reuse that same value for both the revokedAt field and the timestamp argument to appendRevokeReason, matching the existing revokeAllSessions pattern.
♻️ Duplicate comments (3)
packages/prisma/src/adapter.ts (2)
437-446: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
consumeOAuthTransactionstill races on concurrent consumption (unresolved from a previous review).
findUniquethendeleteinside$transactioncan still throwP2025if two concurrent calls consume the samestate, since the interactive transaction doesn't serialize against the other transaction's delete between these two statements. NoP2025handling was added.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/adapter.ts` around lines 437 - 446, Update consumeOAuthTransaction to handle concurrent consumption safely: catch Prisma P2025 from the delete or transaction, and return null when another caller has already consumed the OAuth transaction while preserving normal errors and successful conversion via toOAuthTransaction.
101-113: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winRequired account fields still rely on unchecked
!assertions (unresolved from a previous review).
createAccount(input.userId!,input.provider!,input.providerUserId!,input.type!) andcreateCredentialAccount(input.accountId!,input.passwordHash!) still bypass validation with non-null assertions instead of throwing a clear domain error when these required fields are missing.Also applies to: 187-195
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/adapter.ts` around lines 101 - 113, Remove the non-null assertions from required fields in createAccount and createCredentialAccount, validate each required input before the Prisma calls, and throw the established domain error when any is missing. Preserve the existing field mappings and conversions after validation, including userId, provider, providerUserId, type, accountId, and passwordHash.packages/prisma/src/lib/mappers.ts (1)
41-43: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
toJsonstill collapses explicit JSONnullintoundefined(unresolved from a previous review round).
toJsonis unchanged from the earlier flagged version:(value ?? undefined) as nevermakes it impossible to distinguish "clear this JSON field" from "leave it unchanged" for nullableJsoncolumns. UsePrisma.JsonNull/Prisma.DbNullsentinels instead of theas nevercoercion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/src/lib/mappers.ts` around lines 41 - 43, Update toJson in packages/prisma/src/lib/mappers.ts to preserve explicit null semantics for nullable JSON fields: map null to the appropriate Prisma.JsonNull or Prisma.DbNull sentinel and map undefined to the unchanged-field behavior, removing the current nullish-coalescing expression and as never coercion. Keep fromJson unchanged.
🧹 Nitpick comments (1)
packages/elysia/prisma/schema.prisma (1)
1-234: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftDuplicate Prisma schema across
packages/prismaandpackages/elysia.This schema mirrors the models/enums already defined in
packages/prisma/prisma/schema.prisma(sameUser/Account/Session/Device/MfaCredential/OAuthTransactionshapes, same enum value sets consumed bypackages/prisma/src/lib/mappers.ts). Maintaining two independent copies means every future migration (new field, renamed enum value, etc.) must be hand-applied twice, and any drift silently breaks one of the two packages' Prisma clients without a compile-time signal.Consider having
packages/elysia's test harness consume the schema from@aura-stack/prismadirectly (e.g. pointprisma.config.ts'sschemaat the shared file, or use Prisma'sprismaSchemaFolder/multi-file schema support) instead of duplicating it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/elysia/prisma/schema.prisma` around lines 1 - 234, Remove the duplicated Prisma schema from the Elysia package and configure its test harness to consume the canonical schema from `@aura-stack/prisma`. Update the relevant Prisma configuration, such as prisma.config.ts, to reference the shared schema while preserving the existing generated-client setup and schema behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.gitignore:
- Around line 202-203: Update the generated Prisma ignore patterns in .gitignore
to match src/generated/prisma and generated/prisma directories at any repository
depth, including package-specific paths. Preserve the existing ignore coverage
while removing root-only anchoring that prevents nested generated clients from
being ignored.
In `@packages/elysia/test/stateful/app.ts`:
- Around line 1-17: Update the PrismaClient import in the stateful test setup
around prismaClient to use the generated client exposed by `@aura-stack/prisma`
instead of the unresolved `@/generated/prisma/client.ts` path. Ensure both app.ts
and its related setup flow resolve the same generated client before tests run.
- Around line 21-34: Update the credentials authorize handler to return a stable
sub for each username instead of calling createSecretValue(16) on every login.
Derive or reuse the identifier consistently for the same credentials identity,
while preserving the existing invalid-password rejection and returned user
fields; leave signUp.onCreateUser’s fresh sub generation unchanged.
In `@packages/elysia/test/stateful/setup.ts`:
- Around line 5-16: Update resetDatabase so dependent records are deleted before
user records, preserving the transaction. Reorder the deleteMany calls to clear
credentialAccount, oAuthAccount, account, mfaCredential, oAuthTransaction,
session, device, and finally user, ensuring cascade targets are explicitly
removed before their parents.
In `@packages/prisma/src/adapter.ts`:
- Around line 43-61: Remove the debug console.log of the raw input and output
from createUser, and remove its redundant try/catch wrapper that only logs
before rethrowing. Preserve the existing client.user.create data mapping and
toUser return behavior.
- Around line 88-97: Update the soft-delete branch of deleteUser to write the
Prisma UserStatus value for DELETED, using the forward status mapper or the
schema enum literal; remove the incorrect fromUserStatus conversion and
unnecessary cast while preserving the hard-delete path.
In `@packages/prisma/src/lib/utils.ts`:
- Around line 1-3: Update stripNullishValues to filter out only undefined values
while preserving explicit null entries, so Prisma update callers such as
updateUser, updateOAuthTokens, updateSession, updateDevice, and
updateMfaCredential can clear nullable fields.
---
Outside diff comments:
In `@packages/prisma/src/adapter.ts`:
- Around line 267-281: Update revokeSession to create one revokedAt timestamp
before client.session.update, then reuse that same value for both the revokedAt
field and the timestamp argument to appendRevokeReason, matching the existing
revokeAllSessions pattern.
---
Duplicate comments:
In `@packages/prisma/src/adapter.ts`:
- Around line 437-446: Update consumeOAuthTransaction to handle concurrent
consumption safely: catch Prisma P2025 from the delete or transaction, and
return null when another caller has already consumed the OAuth transaction while
preserving normal errors and successful conversion via toOAuthTransaction.
- Around line 101-113: Remove the non-null assertions from required fields in
createAccount and createCredentialAccount, validate each required input before
the Prisma calls, and throw the established domain error when any is missing.
Preserve the existing field mappings and conversions after validation, including
userId, provider, providerUserId, type, accountId, and passwordHash.
In `@packages/prisma/src/lib/mappers.ts`:
- Around line 41-43: Update toJson in packages/prisma/src/lib/mappers.ts to
preserve explicit null semantics for nullable JSON fields: map null to the
appropriate Prisma.JsonNull or Prisma.DbNull sentinel and map undefined to the
unchanged-field behavior, removing the current nullish-coalescing expression and
as never coercion. Keep fromJson unchanged.
---
Nitpick comments:
In `@packages/elysia/prisma/schema.prisma`:
- Around line 1-234: Remove the duplicated Prisma schema from the Elysia package
and configure its test harness to consume the canonical schema from
`@aura-stack/prisma`. Update the relevant Prisma configuration, such as
prisma.config.ts, to reference the shared schema while preserving the existing
generated-client setup and schema behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f5a294c6-f57c-4696-98f6-3964236f3029
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (22)
.gitignore.vscode/settings.jsonpackages/elysia/.env.examplepackages/elysia/package.jsonpackages/elysia/prisma.config.tspackages/elysia/prisma/schema.prismapackages/elysia/test/stateful/app.tspackages/elysia/test/stateful/index.test.tspackages/elysia/test/stateful/setup.tspackages/elysia/test/stateless/app.tspackages/elysia/test/stateless/index.test.tspackages/elysia/vitest.config.tspackages/prisma/.env.examplepackages/prisma/.vscode/settings.jsonpackages/prisma/README.mdpackages/prisma/package.jsonpackages/prisma/prisma/schema.prismapackages/prisma/src/adapter.tspackages/prisma/src/index.tspackages/prisma/src/lib/mappers.tspackages/prisma/src/lib/utils.tspackages/prisma/test/setup/prisma.ts
💤 Files with no reviewable changes (1)
- packages/prisma/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/prisma/.env.example
- packages/prisma/README.md
- packages/prisma/test/setup/prisma.ts
- packages/prisma/prisma/schema.prisma
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/elysia/test/stateful/app.ts (1)
31-35: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winUse one canonical subject for signup and credential login.
authorizeusescredentials:${username}, whileonCreateUserusescredentials:${email}even thoughauthorizeconstructs the email as${username}@example.com``. For example, the same user can receivecredentials:aliceduring login and `credentials:alice@example.com` during signup. Derive both values through a shared canonical email/subject helper.💡 Proposed fix
authorize: ({ credentials }) => { const { username, password } = credentials if (password === "invalid") { return null } - const sub = `credentials:${username}` + const email = `${username}`@example.com`` + const sub = `credentials:${email}` return { sub, name: username, - email: `${username}`@example.com``, + email,Also applies to: 48-52
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/elysia/test/stateful/app.ts` around lines 31 - 35, Use a shared canonical email/subject derivation for the authorize and onCreateUser flows in the stateful app. Update the credentials subject currently built from username and the one built from email so both resolve to the same value, preserving the `${username}`@example.com`` convention and ensuring signup and credential login identify the user consistently.
🧹 Nitpick comments (2)
packages/prisma/package.json (1)
50-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove
@aura-stack/tsdown-configtodevDependencies.It is only imported by
packages/prisma/tsdown.config.ts, which is a tsdown build config, so consumers do not need this package resolved at runtime.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/prisma/package.json` at line 50, Move `@aura-stack/tsdown-config` from dependencies to devDependencies in packages/prisma/package.json, keeping its existing workspace version and ensuring it is not listed in runtime dependencies.packages/shared/src/adapter-suite.js (1)
404-422: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
listSessions with filtersdoesn't actually exercise filtering.It passes the same
{ status: "active", deviceId: null }as the previous test and asserts the single created session comes back — an unfiltered query would pass identically. Add a negative case (e.g.status: "revoked", or adeviceIdthat doesn't match) so thewhereconstruction inlistSessionsis really covered.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/shared/src/adapter-suite.js` around lines 404 - 422, Update the “listSessions with filters” test to include a negative filter case that cannot match the created active session, such as status “revoked” or a different deviceId, and assert that no sessions are returned. Keep the existing matching filter assertion so both matching and filtering behavior exercise listSessions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/elysia/package.json`:
- Line 12: Update the package test scripts so the default test command runs both
stateless and stateful Vitest suites instead of limiting execution to the
stateless project. Remove the --project stateless restriction from test, or
define and invoke a dedicated test:stateful command alongside the existing test
flow, ensuring Prisma-backed authentication tests run by default.
In `@packages/prisma/prisma/migrations/20260729162431_schema/migration.sql`:
- Around line 55-65: Update the OAuthAccount persistence adapter responsible for
the OAuthAccount columns so accessToken, refreshToken, and idToken are
envelope-encrypted before database writes, using encryption keys managed outside
the database. Decrypt these fields when reading records so token renewal can
recover the original values; preserve nullable handling for refreshToken and
idToken, and do not hash reusable tokens.
In `@packages/prisma/src/adapter.ts`:
- Around line 84-92: Make the soft-delete operation atomic by wrapping the user
status update and session revocation in a single client.$transaction. Within
that transaction, replace updateManyAndReturn with updateMany because the
returned sessions are unused, while preserving the existing filters and update
data.
In `@packages/shared/src/adapter-suite.ts`:
- Around line 1-2: Consolidate createAdapterSuite into one source of truth by
deleting the empty TypeScript stub or moving the real implementation into it and
removing the duplicate JavaScript suite; update packages/shared/package.json
lines 36-38 to export the surviving file with a types condition, and verify
packages/prisma/test/index.test.ts lines 2-4 resolves
createAdapterSuite(adapter) and registers a non-zero test suite.
---
Outside diff comments:
In `@packages/elysia/test/stateful/app.ts`:
- Around line 31-35: Use a shared canonical email/subject derivation for the
authorize and onCreateUser flows in the stateful app. Update the credentials
subject currently built from username and the one built from email so both
resolve to the same value, preserving the `${username}`@example.com`` convention
and ensuring signup and credential login identify the user consistently.
---
Nitpick comments:
In `@packages/prisma/package.json`:
- Line 50: Move `@aura-stack/tsdown-config` from dependencies to devDependencies
in packages/prisma/package.json, keeping its existing workspace version and
ensuring it is not listed in runtime dependencies.
In `@packages/shared/src/adapter-suite.js`:
- Around line 404-422: Update the “listSessions with filters” test to include a
negative filter case that cannot match the created active session, such as
status “revoked” or a different deviceId, and assert that no sessions are
returned. Keep the existing matching filter assertion so both matching and
filtering behavior exercise listSessions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 7d9a2d35-3930-4c36-aa4f-02a671c0e650
⛔ Files ignored due to path filters (3)
bun.lockis excluded by!**/*.lockdeno.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
.gitignorepackages/core/src/shared/index.tspackages/elysia/.gitignorepackages/elysia/package.jsonpackages/elysia/test/stateful/app.tspackages/elysia/test/stateful/index.test.tspackages/elysia/test/stateful/setup.tspackages/prisma/package.jsonpackages/prisma/prisma/migrations/20260729162431_schema/migration.sqlpackages/prisma/prisma/migrations/migration_lock.tomlpackages/prisma/src/adapter.tspackages/prisma/src/lib/utils.tspackages/prisma/test/index.test.tspackages/prisma/test/setup/prisma.tspackages/shared/package.jsonpackages/shared/src/adapter-suite.jspackages/shared/src/adapter-suite.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/elysia/test/stateful/index.test.ts
- packages/prisma/src/lib/utils.ts
- packages/prisma/test/setup/prisma.ts
- .gitignore
- packages/elysia/test/stateful/setup.ts
Description
This pull request introduces the experimental
@aura-stack/prismapackage, which provides a built-in Prisma ORM adapter for the Stateful session strategy in@aura-stack/auth.The package implements the database adapter interface required by the Stateful session strategy, allowing applications to persist users, sessions, OAuth accounts, devices, and other authentication-related entities using Prisma.
The adapter has been tested against the supported authentication methods and common authentication flows to verify its correctness and compatibility with the current Stateful implementation.
Key Changes
@aura-stack/prismapackage.DatabaseAdapterinterface.Note
Documentation for
@aura-stack/prismais intentionally omitted from this PR. The package is still experimental and under active development, and its API may change before it is considered stable. Documentation will be added in a future PR once the adapter reaches a more mature state.@coderabbitai ignore