feat(core): add context.transaction interactive hook-firing transaction#616
Merged
Conversation
Adds `context.transaction(fn, options)` to the stack Context — an interactive transaction whose `txContext.db.*` operations are access-checked and hook-firing (identical to the request context) but persist against one Prisma interactive transaction, so every write in the callback is atomic. This is the secured alternative to raw `prisma.$transaction`, which bypasses access control and hooks. - Reuses the ADR-0010 rebind primitive (buildDbDelegate via getContext) to bind the secured context to the transaction client; plugin runtimes are reused (not re-run) for the tx context. - `options` (isolationLevel/maxWait/timeout) pass through to Prisma; serialization failures (P2034) propagate so the caller owns the retry loop. - Nested context.db writes join the outer transaction via the existing no-$transaction fallback; falls back to running directly when the client has no $transaction. - Exports StackContext, TransactionOptions, TransactionIsolationLevel. - Adds ADR-0012, docs, and a changeset. Closes #614 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHLArNoEjHjGZnHpSxmu5V
🦋 Changeset detectedLatest commit: 4608965 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ite rollback test Addresses review nits on #614: - transaction() docstring + ADR-0012 now explicitly warn that plugin runtime services stay bound to the top-level client, so a writing plugin service would escape the transaction and survive a rollback (use txContext.db). - Adds a test asserting sudo() writes inside a transaction commit on success and roll back with the transaction (confirming sudo binds to the tx client). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHLArNoEjHjGZnHpSxmu5V
Member
Author
Code review (subagent) — verdict: approve-with-nits → nits addressedAn independent review pass checked the implementation adversarially across atomicity, nesting, TDZ, error propagation, sudo binding, and type safety. Summary:
Nits raised (both addressed in
|
Contributor
Coverage Report for Core Package Coverage (./packages/core)
File CoverageNo changed files found. |
Contributor
Coverage Report for UI Package Coverage (./packages/ui)
File CoverageNo changed files found. |
Contributor
Coverage Report for CLI Package Coverage (./packages/cli)
File CoverageNo changed files found. |
Contributor
Coverage Report for Auth Package Coverage (./packages/auth)
File CoverageNo changed files found. |
Contributor
Coverage Report for Storage Package Coverage (./packages/storage)
File CoverageNo changed files found. |
Contributor
Coverage Report for RAG Package Coverage (./packages/rag)
File CoverageNo changed files found. |
Contributor
Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)
File CoverageNo changed files found. |
Contributor
Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)
File CoverageNo changed files found. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
context.transaction(fn, options)to the stackContext— an interactive, hook-firing transaction. ThetxContext.db.*operations are access-checked and run list/field hooks exactly like the request context, but persist against one Prisma interactive transaction, so every write in the callback is atomic (a throw anywhere rolls it all back). This is the secured alternative to rawprisma.$transaction, which bypasses access control and hooks.It enables concurrency-sensitive invariants (e.g. a capacity/quota gate) to be enforced atomically without dropping the access/hook boundary — the gap reported in #614 (Keystone 6's
context.transactionhad no stack equivalent).What changed
context.transaction(fn, options?)added togetContext's returned context.buildDbDelegatevia thegetContextfactory) to bind the secured context to the transaction client — no new persistence logic.options(isolationLevelincl.'Serializable',maxWait,timeout) pass through to Prisma.P2034) propagate to the caller — retry is caller-owned (matching Keystone). Built-in retry is intentionally out of scope.context.dbwrites join the outer transaction via the Write Pipeline's existing "no$transactionon a tx client → run directly" fallback; callingtransaction()on a client with no$transactionrunsfndirectly with identical hook/access semantics._sharedPluginspath).StackContext,TransactionOptions,TransactionIsolationLevelfrom@opensaas/stack-core.CLAUDE.mddocs, and a minor changeset.Test plan
tests/interactive-transaction.test.ts(10 tests): method presence, returns callback result, atomic rollback on throw, isolationLevel passthrough, access control enforced (denied create →null), list hooks fire, serialization-failure propagation, session/sudo()on the tx context, and the no-$transactionfallback.pnpm build(all 11 tasks),pnpm lint(0 errors),pnpm format,pnpm manypkg fix.Closes #614
🤖 Generated with Claude Code
Generated by Claude Code