Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Aug 14, 2025

Summary by CodeRabbit

  • New Features

    • Unified plugin API: single onQuery callback replaces nested handlers.
    • Consolidated entity-mutation hooks under onEntityMutation with richer hook context.
    • Added onKyselyQuery hook for Kysely query interception.
  • Documentation

    • README updated to document the new plugin hook shapes and usage.
  • Refactor

    • Streamlined runtime plugin architecture and public plugin descriptors.
  • Tests

    • Tests added/updated for new onQuery and onEntityMutation shapes; one legacy suite removed.
  • Chores

    • Version bumped to 3.0.0-alpha.24 across packages.
    • Debug configuration: working directory behavior adjusted.

Copilot AI review requested due to automatic review settings August 14, 2025 04:27
@coderabbitai
Copy link

coderabbitai bot commented Aug 14, 2025

Walkthrough

Consolidates the runtime plugin model: replaces nested per-model/per-operation onQuery hooks with a single onQuery callback; nests entity-mutation hooks under onEntityMutation; adds AllModelOperations type; updates executor/client/plugin code and tests; bumps many package versions to 3.0.0-alpha.24; minor VSCode launch tweak and a TODO entry.

Changes

Cohort / File(s) Summary
Runtime plugin API & types
packages/runtime/src/client/plugin.ts, packages/runtime/src/client/contract.ts
Introduces RuntimePlugin and definePlugin; centralizes onQuery as a single callback; adds AllModelOperations and refactors ModelOperations; reorganizes plugin-related public types and removes old scaffolding.
Client implementation
packages/runtime/src/client/client-impl.ts
Replaces nested onQuery traversal with single-function onQuery handling; updates proceed wrapper semantics and removes lowerCaseFirst.
Query executor / mutation hooks
packages/runtime/src/client/executor/zenstack-query-executor.ts
Moves beforeEntityMutation, afterEntityMutation, and mutationInterceptionFilter under plugin.onEntityMutation; updates detection, invocation, and interception result shapes.
Plugin runtime exports
packages/runtime/src/client/plugin.ts
Adds public types for onQuery, onEntityMutation, onKyselyQuery; exports definePlugin and CrudOperation; removes older exported hook types.
Tests — add/modify/remove
packages/runtime/test/plugin/on-query-hooks.test.ts (added), packages/runtime/test/plugin/entity-mutation-hooks.test.ts (modified), packages/runtime/test/plugin/on-kysely-query.test.ts (modified), packages/runtime/test/plugin/query-lifecycle.test.ts (removed), packages/runtime/test/policy/client-extensions.test.ts (modified)
Adapts tests to unified onQuery signature and onEntityMutation container; adds new on-query suite; removes legacy query-lifecycle tests; updates descriptions and assertions to use proceed.
Docs & samples
README.md, samples/blog/main.ts
README and sample plugin updated to use single onQuery callback and onEntityMutation nesting; query(args) replaced with proceed(args).
Version bumps (many packages & samples)
Root & packages: package.json, packages/*/package.json (cli, common-helpers, create-zenstack, dialects/sql.js, eslint-config, ide/vscode, language, runtime, sdk, tanstack-query, testtools, typescript-config, vitest-config, zod), samples/blog/package.json, tests/e2e/package.json
Bumps package versions from 3.0.0-alpha.233.0.0-alpha.24 (metadata-only).
VSCode launch config
.vscode/launch.json
Collapses multi-line arg arrays to single-line and sets TSX debug cwd to "${fileDirname}".
Project TODO
TODO.md
Adds task: Inject "insert into select from".

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

I nibble code at break of day,
One hook now hops along the way.
Mutations nested, tidy, neat,
Queries proceed with steady feet.
A carrot for each shaped type bite 🥕

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddd5b4d and ffbaace.

📒 Files selected for processing (2)
  • packages/runtime/src/client/client-impl.ts (3 hunks)
  • packages/runtime/test/plugin/on-query-hooks.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/runtime/test/plugin/on-query-hooks.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
{packages,samples,tests}/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Packages are located in packages/, samples/, and tests/

Files:

  • packages/runtime/src/client/client-impl.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: Plugin Architecture: Runtime plugins for query interception and entity mutation hooks
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: claude-review
  • GitHub Check: build-test (20.x)
🔇 Additional comments (1)
packages/runtime/src/client/client-impl.ts (1)

1-1: LGTM: import usage

The invariant import is appropriate and consistent with usage below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@claude
Copy link

claude bot commented Aug 14, 2025

Claude finished @ymc9's task —— View job


Pull Request Review Complete ✅

Reviewing PR #166: merge dev to main (3.0.0-alpha.24 release)

Review Checklist:

  • Analyze overall PR structure and scope
  • Review version bump changes across packages
  • Examine runtime plugin system refactoring
  • Analyze client implementation changes
  • Review test file reorganization and coverage
  • Check for potential bugs or breaking changes
  • Assess performance and security considerations
  • Provide comprehensive feedback summary

📋 Summary

This is a significant alpha release that includes major plugin system refactoring for TypeScript performance improvements. While the changes are well-structured, there are some important considerations for the team.

⚠️ Critical Issues

1. Breaking Changes in Plugin API

  • Issue: The plugin system underwent major refactoring - the old QueryContext pattern was replaced with simpler hook callbacks
  • Evidence: query-lifecycle.test.ts was deleted and replaced with on-query-hooks.test.ts with completely different API structure
  • Impact: This is a breaking change that will affect any existing plugins
  • Recommendation: Ensure migration guide is available and version is properly marked as alpha

2. Plugin System Complexity Reduction

  • Old API: Model-specific query hooks like onQuery: { user: { findFirst: (ctx) => ... } }
  • New API: Universal hooks like onQuery: (ctx) => ...
  • Assessment: Simpler but potentially less granular control

Positive Aspects

1. TypeScript Performance Improvements

  • Plugin contract simplified (~1,100 lines changed in contract.ts)
  • Should significantly improve TypeScript compilation times
  • Well-executed refactoring for developer experience

2. Test Coverage Maintained

  • Comprehensive test reorganization with better separation
  • All plugin functionality appears to have test coverage
  • Entity mutation hooks properly tested

3. Release Management

  • All packages consistently bumped to 3.0.0-alpha.24
  • Proper monorepo version synchronization

🔍 Code Quality Assessment

Security: ✅ No security concerns identified

  • No secrets or sensitive data exposed
  • Input validation patterns maintained
  • Database query patterns are safe

Performance: ✅ Improved

  • Plugin system streamlined for better TypeScript performance
  • Query execution path simplified
  • Transaction handling looks efficient

Bugs: ⚠️ Low risk

  • Code appears well-tested but breaking changes require careful validation
  • Recommend testing with real-world plugin usage

📝 Recommendations

  1. Documentation: Update plugin development docs to reflect new API
  2. Migration: Provide clear migration examples for V2 → V3 plugin upgrade
  3. Testing: Run integration tests with existing plugins to catch edge cases
  4. Changelog: Document the breaking changes clearly for users

🎯 Verdict

Approved for Alpha Release - The changes are well-executed and improve the overall developer experience. The breaking changes are acceptable for an alpha version, but ensure proper communication to users.


Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR merges development branch to main, implementing a significant API refactoring for ZenStack runtime plugins along with version bumping from alpha.23 to alpha.24. The main changes simplify the plugin API structure by flattening nested hook configurations and reorganizing entity mutation hooks.

Key changes:

  • Simplifies onQuery plugin API from nested model/operation structure to a single callback function
  • Reorganizes entity mutation hooks under an onEntityMutation property
  • Updates all package versions from 3.0.0-alpha.23 to 3.0.0-alpha.24

Reviewed Changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Multiple package.json files Version bump from alpha.23 to alpha.24 across all packages
samples/blog/main.ts Updates plugin usage to use simplified onQuery API
packages/runtime/src/client/plugin.ts Major API refactor: flattens onQuery structure and moves entity mutation hooks
packages/runtime/test/ files Updates test files to use new plugin API and adds new test structure
packages/runtime/src/client/ files Implementation updates to support new plugin API structure
README.md Documentation updates reflecting the new plugin API

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (12)
TODO.md (1)

102-102: Clarify SQL phrasing/casing for consistency

Consider using the canonical SQL form and consistent casing with other entries.

Apply this diff:

-    - [ ] Inject "insert into select from"
+    - [ ] Inject "INSERT INTO ... SELECT ..."
packages/runtime/src/client/plugin.ts (5)

96-112: Fix JSDoc: references to old API and singular/plural names.

  • “return value of {@link RuntimePlugin.mutationInterceptionFilter}” is outdated; it should refer to onEntityMutation.mutationInterceptionFilter.
  • “args.entity” should be “args.entities”.

Apply this diff:

-     * @param args.entity Only available if `loadBeforeMutationEntities` is set to true in the
-     * return value of {@link RuntimePlugin.mutationInterceptionFilter}.
+     * @param args.entities Only available if `loadBeforeMutationEntities` is set to true in the
+     * return value of {@link EntityMutationHooksDef.mutationInterceptionFilter}.

And here:

-     * @param args.beforeMutationEntity Only available if `loadBeforeMutationEntities` is set to true in the
-     * return value of {@link RuntimePlugin.mutationInterceptionFilter}.
-     * @param args.afterMutationEntity Only available if `loadAfterMutationEntities` is set to true in the
-     * return value of {@link RuntimePlugin.mutationInterceptionFilter}.
+     * @param args.beforeMutationEntities Only available if `loadBeforeMutationEntities` is set to true in the
+     * return value of {@link EntityMutationHooksDef.mutationInterceptionFilter}.
+     * @param args.afterMutationEntities Only available if `loadAfterMutationEntities` is set to true in the
+     * return value of {@link EntityMutationHooksDef.mutationInterceptionFilter}.

113-129: Fix JSDoc: clarify queryNode description.

The comment says “The mutation data. Only available for create and update actions.” but the field is queryNode: OperationNode and is always present. Reword to avoid confusion.

Apply this diff:

-    /**
-     * The mutation data. Only available for create and update actions.
-     */
+    /**
+     * The raw Kysely operation node for the mutation (Insert/Update/Delete).
+     */

162-169: Fix JSDoc: update link target and plural form.

Apply this diff:

-     * Entities that are about to be mutated. Only available if `loadBeforeMutationEntities` is set to
-     * true in the return value of {@link RuntimePlugin.mutationInterceptionFilter}.
+     * Entities that are about to be mutated. Only available if `loadBeforeMutationEntities` is set to
+     * true in the return value of {@link EntityMutationHooksDef.mutationInterceptionFilter}.

170-182: Fix JSDoc: update link targets to new API.

Apply this diff:

-     * Entities that are about to be mutated. Only available if `loadBeforeMutationEntities` is set to
-     * true in the return value of {@link RuntimePlugin.mutationInterceptionFilter}.
+     * Entities that are about to be mutated. Only available if `loadBeforeMutationEntities` is set to
+     * true in the return value of {@link EntityMutationHooksDef.mutationInterceptionFilter}.
@@
-     * Entities mutated. Only available if `loadAfterMutationEntities` is set to true in the return
-     * value of {@link RuntimePlugin.mutationInterceptionFilter}.
+     * Entities mutated. Only available if `loadAfterMutationEntities` is set to true in the return
+     * value of {@link EntityMutationHooksDef.mutationInterceptionFilter}.

188-194: Tighten schema typing in OnKyselyQueryArgs.

schema should carry the generic Schema, not the base SchemaDef, for better type inference in plugins.

Apply this diff:

-export type OnKyselyQueryArgs<Schema extends SchemaDef> = {
-    kysely: ToKysely<Schema>;
-    schema: SchemaDef;
+export type OnKyselyQueryArgs<Schema extends SchemaDef> = {
+    kysely: ToKysely<Schema>;
+    schema: Schema;
samples/blog/main.ts (1)

20-24: Log in finally to capture durations even on errors.

If the query throws, current code skips logging. Wrap with try/finally.

Apply this diff:

-        onQuery: async ({ model, operation, args, query }) => {
-            const start = Date.now();
-            const result = await query(args);
-            console.log(`[cost] ${model} ${operation} took ${Date.now() - start}ms`);
-            return result;
-        },
+        onQuery: async ({ model, operation, args, query }) => {
+            const start = Date.now();
+            try {
+                return await query(args);
+            } finally {
+                console.log(`[cost] ${model} ${operation} took ${Date.now() - start}ms`);
+            }
+        },
packages/runtime/test/plugin/on-query-hooks.test.ts (1)

124-153: Safer result mutation pattern

Directly mutating the result may have side effects if the ORM returns frozen/proxied objects in the future. Prefer a shallow copy when annotating.

-                    const result = await ctx.query(ctx.args);
-                    (result as any).happy = true;
-                    return result;
+                    const result = await ctx.query(ctx.args);
+                    return result ? { ...(result as any), happy: true } : result;
packages/runtime/test/policy/client-extensions.test.ts (2)

33-35: Duplicate assertions offer little additional value

These four tests now exercise the same path (top-level onQuery) with identical logic and repeated duplicate assertions. Consider parameterizing into a single test or differentiating by explicitly filtering on model/operation in the hook to validate scoping.

Also applies to: 64-66, 95-97, 126-128


148-154: Prefer non-mutating result transformation

Using a functional style avoids unintended side effects.

-            onQuery: async ({ args, query }: any) => {
-                const r: any = await query(args);
-                for (let i = 0; i < r.length; i++) {
-                    r[i].value = r[i].value + 1;
-                }
-                return r;
-            },
+            onQuery: async ({ args, query }: any) => {
+                const r: any[] = await query(args);
+                return r.map((item) => ({ ...item, value: item.value + 1 }));
+            },
README.md (2)

281-291: Typo: use db.$use, not ZenStackdb.$use

The instance variable in examples is consistently named db.

-V3 introduces a new runtime plugin mechanism that allows you to tap into the ORM's query execution in various ways. A plugin implements the [RuntimePlugin](./packages/runtime/src/client/plugin.ts#L121) interface, and can be installed with the `ZenStackdb.$use` API.
+V3 introduces a new runtime plugin mechanism that allows you to tap into the ORM's query execution in various ways. A plugin implements the [RuntimePlugin](./packages/runtime/src/client/plugin.ts) interface, and can be installed with the `db.$use` API.

301-303: Wording: refer to the query callback, not proceed

The onQuery examples use query(args) as the continuation. Align the prose.

-Usually a plugin would call the `proceed` callback to trigger the execution of the original query, but you can choose to completely override the query behavior with custom logic.
+Usually a plugin would call the `query` callback to trigger the execution of the original query, but you can choose to completely override the query behavior with custom logic.
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 726b826 and b57827a.

📒 Files selected for processing (30)
  • .vscode/launch.json (2 hunks)
  • README.md (3 hunks)
  • TODO.md (1 hunks)
  • package.json (1 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/common-helpers/package.json (1 hunks)
  • packages/create-zenstack/package.json (1 hunks)
  • packages/dialects/sql.js/package.json (1 hunks)
  • packages/eslint-config/package.json (1 hunks)
  • packages/ide/vscode/package.json (1 hunks)
  • packages/language/package.json (1 hunks)
  • packages/runtime/package.json (1 hunks)
  • packages/runtime/src/client/client-impl.ts (2 hunks)
  • packages/runtime/src/client/contract.ts (1 hunks)
  • packages/runtime/src/client/executor/zenstack-query-executor.ts (4 hunks)
  • packages/runtime/src/client/plugin.ts (2 hunks)
  • packages/runtime/test/plugin/entity-mutation-hooks.test.ts (10 hunks)
  • packages/runtime/test/plugin/on-kysely-query.test.ts (1 hunks)
  • packages/runtime/test/plugin/on-query-hooks.test.ts (1 hunks)
  • packages/runtime/test/plugin/query-lifecycle.test.ts (0 hunks)
  • packages/runtime/test/policy/client-extensions.test.ts (5 hunks)
  • packages/sdk/package.json (1 hunks)
  • packages/tanstack-query/package.json (1 hunks)
  • packages/testtools/package.json (1 hunks)
  • packages/typescript-config/package.json (1 hunks)
  • packages/vitest-config/package.json (1 hunks)
  • packages/zod/package.json (1 hunks)
  • samples/blog/main.ts (1 hunks)
  • samples/blog/package.json (1 hunks)
  • tests/e2e/package.json (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/runtime/test/plugin/query-lifecycle.test.ts
🧰 Additional context used
📓 Path-based instructions (2)
{packages,samples,tests}/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Packages are located in packages/, samples/, and tests/

Files:

  • packages/typescript-config/package.json
  • packages/ide/vscode/package.json
  • packages/create-zenstack/package.json
  • tests/e2e/package.json
  • packages/zod/package.json
  • packages/dialects/sql.js/package.json
  • packages/eslint-config/package.json
  • packages/tanstack-query/package.json
  • packages/common-helpers/package.json
  • packages/testtools/package.json
  • samples/blog/package.json
  • packages/runtime/package.json
  • packages/runtime/test/plugin/on-kysely-query.test.ts
  • packages/language/package.json
  • packages/vitest-config/package.json
  • packages/runtime/src/client/client-impl.ts
  • packages/cli/package.json
  • samples/blog/main.ts
  • packages/sdk/package.json
  • packages/runtime/test/plugin/on-query-hooks.test.ts
  • packages/runtime/src/client/contract.ts
  • packages/runtime/src/client/executor/zenstack-query-executor.ts
  • packages/runtime/test/policy/client-extensions.test.ts
  • packages/runtime/test/plugin/entity-mutation-hooks.test.ts
  • packages/runtime/src/client/plugin.ts
tests/e2e/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

E2E tests are in tests/e2e/ directory

Files:

  • tests/e2e/package.json
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: Plugin Architecture: Runtime plugins for query interception and entity mutation hooks
📚 Learning: 2025-08-04T08:43:33.161Z
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: `zenstack generate` compiles ZModel to TypeScript schema (`schema.ts`)

Applied to files:

  • packages/language/package.json
  • .vscode/launch.json
📚 Learning: 2025-08-04T08:43:33.161Z
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: Plugin Architecture: Runtime plugins for query interception and entity mutation hooks

Applied to files:

  • packages/runtime/src/client/client-impl.ts
  • packages/runtime/test/plugin/on-query-hooks.test.ts
  • packages/runtime/src/client/executor/zenstack-query-executor.ts
  • README.md
  • packages/runtime/src/client/plugin.ts
🧬 Code Graph Analysis (3)
packages/runtime/test/plugin/on-query-hooks.test.ts (3)
packages/runtime/src/client/contract.ts (1)
  • ClientContract (50-159)
packages/runtime/src/client/client-impl.ts (1)
  • ZenStackClient (40-46)
packages/runtime/src/client/plugin.ts (1)
  • definePlugin (45-47)
packages/runtime/src/client/contract.ts (4)
packages/sdk/src/schema/schema.ts (2)
  • SchemaDef (10-18)
  • GetModels (108-108)
packages/runtime/src/client/crud-types.ts (10)
  • FindArgs (624-643)
  • FindUniqueArgs (648-650)
  • UpdateArgs (794-800)
  • UpdateManyArgs (802-805)
  • CountArgs (956-961)
  • CountResult (967-977)
  • AggregateArgs (983-997)
  • AggregateResult (1023-1051)
  • GroupByArgs (1070-1087)
  • GroupByResult (1089-1123)
packages/runtime/src/client/promise.ts (1)
  • ZenStackPromise (7-13)
packages/runtime/src/utils/type-utils.ts (1)
  • Simplify (11-17)
packages/runtime/src/client/plugin.ts (5)
packages/sdk/src/schema/schema.ts (2)
  • SchemaDef (10-18)
  • GetModels (108-108)
packages/runtime/src/client/crud/operations/base.ts (1)
  • CrudOperation (54-69)
packages/runtime/src/client/contract.ts (1)
  • ClientContract (50-159)
packages/runtime/src/utils/type-utils.ts (1)
  • MaybePromise (70-70)
packages/runtime/src/client/query-builder.ts (1)
  • ToKysely (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-test (20.x)
  • GitHub Check: claude-review
🔇 Additional comments (34)
samples/blog/package.json (1)

3-3: Version bump to 3.0.0-alpha.24 looks good

Matches the monorepo release bump context.

tests/e2e/package.json (1)

3-3: All package.json versions are 3.0.0-alpha.24 — no mismatches found

Quick check completed: the repo has 17 package.json files and all are set to 3.0.0-alpha.24.

Files scanned (all matched):

  • package.json
  • packages/cli/package.json
  • packages/common-helpers/package.json
  • packages/create-zenstack/package.json
  • packages/dialects/sql.js/package.json
  • packages/eslint-config/package.json
  • packages/ide/vscode/package.json
  • packages/language/package.json
  • packages/runtime/package.json
  • packages/sdk/package.json
  • packages/tanstack-query/package.json
  • packages/testtools/package.json
  • packages/typescript-config/package.json
  • packages/vitest-config/package.json
  • packages/zod/package.json
  • samples/blog/package.json
  • tests/e2e/package.json

No changes required.

packages/zod/package.json (1)

3-3: LGTM on version bump

No other changes; aligns with the release bump.

packages/eslint-config/package.json (1)

3-3: LGTM on version bump

Package remains private; no functional impact beyond versioning.

packages/sdk/package.json (1)

3-3: Version bump looks good

No manifest inconsistencies spotted. This aligns with the repo-wide alpha.24 release.

package.json (1)

3-3: Root version bump verified — all packages are 3.0.0-alpha.24

Checks run against the repo show:

  • All package.json files (root, packages, samples, tests) report "version": "3.0.0-alpha.24".
  • No occurrences of "alpha.23" remain.
  • All internal @zenstackhq/* dependencies use workspace:*.

Snippet (unchanged):
"version": "3.0.0-alpha.24",

packages/common-helpers/package.json (1)

3-3: Version bump aligned

Manifest remains unchanged otherwise. No issues.

packages/language/package.json (1)

4-4: Version bump acknowledged

No functional/package structure changes here; safe to proceed.

packages/create-zenstack/package.json (1)

3-3: Version bump to 3.0.0-alpha.24: LGTM

Change is metadata-only and consistent with the PR’s release bump.

packages/testtools/package.json (1)

3-3: Version bump to 3.0.0-alpha.24: LGTM

No functional changes; aligns with monorepo versioning.

packages/cli/package.json (1)

6-6: Version bump to 3.0.0-alpha.24: LGTM

CLI manifest change only; consistent with the coordinated prerelease.

packages/vitest-config/package.json (1)

4-4: Version bump to 3.0.0-alpha.24: LGTM

Private package; safe metadata update.

packages/runtime/package.json (1)

3-3: Runtime package version bump verified — monorepo aligned

All package.json files under packages/, samples/, and tests/ are set to 3.0.0-alpha.24 and all internal @zenstackhq/* dependencies use workspace:* — no action required.

  • Primary file checked: packages/runtime/package.json
    "version": "3.0.0-alpha.24",
packages/typescript-config/package.json (1)

3-3: Version bump looks good

Package version updated to 3.0.0-alpha.24 as part of the release sweep. No concerns.

packages/dialects/sql.js/package.json (1)

3-3: Version bump looks good

Package version updated to 3.0.0-alpha.24 in sync with the monorepo. No concerns.

packages/tanstack-query/package.json (1)

3-3: Version bump looks good

Package version updated to 3.0.0-alpha.24; no functional changes. No concerns.

.vscode/launch.json (3)

13-13: No-op formatting change to args

Collapsing the args array to one line is fine; no functional impact.


43-45: Changing cwd for TSX debug could affect runtime behavior

Setting cwd to ${fileDirname} changes process.cwd() and can influence relative path resolution and tsconfig discovery for tsx. If the current file lives deep under the repo, this can be desirable for relative file reads, but it may break code that expects cwd to be the repo root (e.g., reading configs, schema files, or relying on workspace-root-relative paths).

  • If you mainly need per-file relative reads, this is fine.
  • If some scripts expect workspace-root cwd, consider keeping cwd as ${workspaceFolder} and passing explicit paths, or set env vars to reference the workspace root.

Please verify typical debug flows (blog sample, CLI entry points) still work as expected with this change.


50-50: No-op formatting change to args

Collapsing the args array to one line for the extension host is fine; no functional impact.

packages/runtime/src/client/client-impl.ts (1)

1-1: Import cleanup looks good

Using invariant from @zenstackhq/common-helpers is appropriate; no issues.

packages/runtime/src/client/contract.ts (1)

773-777: Deriving ModelOperations from AllModelOperations is a good consolidation.

Using Omit to exclude delegate-inapplicable ops centralizes the surface and removes duplication. This improves maintainability and consistency.

packages/runtime/src/client/executor/zenstack-query-executor.ts (4)

233-234: Correct hook presence check for new API.

Switching hasMutationHooks to detect onEntityMutation aligns with the new plugin shape.


275-293: Confirm default interception semantics when filter is absent.

When a plugin defines onEntityMutation but not mutationInterceptionFilter, the executor defaults to intercept = true (without loading entities). This changes behavior vs “no interception” and will run before/after hooks for every mutation.

If this is intentional for backward-compatibility, consider adding an inline comment explaining the rationale to avoid confusion for future maintainers.

Do the tests cover:

  • a plugin with onEntityMutation but no mutationInterceptionFilter receiving before/after hooks; and
  • a plugin with mutationInterceptionFilter returning intercept: false not receiving hooks?

323-331: Before-mutation hooks: correct routing via onEntityMutation.beforeEntityMutation.

Invocation and payload composition look consistent with the new types.


349-352: After-mutation hooks: collection and binding updated correctly.

Collecting hooks from onEntityMutation.afterEntityMutation and binding to plugin preserves prior semantics.

packages/runtime/src/client/plugin.ts (1)

10-47: New RuntimePlugin contract and definePlugin helper look solid.

The top-level onQuery, nested onEntityMutation, and onKyselyQuery provide a clean, unified plugin API. definePlugin is a small but useful DX improvement.

packages/runtime/test/plugin/on-kysely-query.test.ts (1)

7-7: Test description rename is fine.

Minor wording tweak; no behavioral impact.

packages/runtime/test/plugin/on-query-hooks.test.ts (2)

186-209: LGTM: plugin encapsulation via definePlugin is correct

Good use of definePlugin with schema typing and per-client installation. This validates plugin-scoped behavior as intended.


116-122: Custom matcher present — no change needed

I ran a repo search and found the custom matchers implemented and typed, so .toResolveNull is registered.

  • packages/runtime/test/vitest-ext.ts — expect.extend(...) defines toResolveTruthy, toResolveNull, toResolveWithLength (matcher implementations).
  • packages/runtime/test/vitest.d.ts — type declarations for toResolveTruthy, toResolveFalsy, toResolveNull, toResolveWithLength, etc.
packages/runtime/test/plugin/entity-mutation-hooks.test.ts (1)

313-332: Intentional behavior: afterEntityMutation errors should not affect DB operation

This test asserts that throwing in afterEntityMutation does not propagate nor roll back the operation. It’s a good contract check and complements the onQuery behavior test where you explicitly expect a throw to surface. No change needed.

If the intended contract changes in the future (e.g., surfacing errors), this test must be updated accordingly.

packages/runtime/test/policy/client-extensions.test.ts (1)

26-30: Guard against spreading undefined where clause

Spreading undefined throws at runtime. Use nullish coalescing to default to an empty object.

-            onQuery: async ({ args, query }: any) => {
-                args = args ?? {};
-                args.where = { ...args.where, y: { lt: 300 } };
-                return query(args);
-            },
+            onQuery: async ({ args, query }: any) => {
+                args = args ?? {};
+                args.where = { ...(args.where ?? {}), y: { lt: 300 } };
+                return query(args);
+            },

Likely an incorrect or invalid review comment.

README.md (3)

290-299: Great: onQuery example reflects the new unified signature

The code sample correctly demonstrates the unified top-level onQuery hook with model, operation, args, and query.


346-369: Solid: onEntityMutation examples match the new nested API

The examples clearly illustrate mutationInterceptionFilter, beforeEntityMutation, and afterEntityMutation under onEntityMutation with load-before/after options.


412-413: Potential doc inconsistency: raw SQL API support

Docs state raw SQL APIs are not supported, but the client contract appears to expose $queryRaw/$executeRaw. Please confirm and update the docs or implementation accordingly.

If the APIs are implemented/available behind a feature flag, clarify their current support status here to avoid confusion.

@ymc9 ymc9 changed the title merge dev to main merge dev to main (v3.0.0-alpha.24) Aug 14, 2025
* chore: rename query function to proceed for onquery plugin

* update test
@claude
Copy link

claude bot commented Aug 14, 2025

Claude finished @ymc9's task —— View job


Pull Request Review Complete ✅

Reviewing PR #166: merge dev to main (3.0.0-alpha.24 release)

Review Checklist:

  • Analyze overall PR structure and scope
  • Review version bump changes across packages
  • Examine runtime plugin system refactoring
  • Analyze client implementation changes
  • Review test file reorganization and coverage
  • Check for potential bugs or breaking changes
  • Assess performance and security considerations
  • Provide comprehensive feedback summary

📋 Summary

This is a significant alpha release that includes major plugin system refactoring for TypeScript performance improvements. While the changes are well-structured, there are some important considerations for the team.

⚠️ Critical Issues

1. Breaking Changes in Plugin API

  • Issue: The plugin system underwent major refactoring - the old QueryContext pattern was replaced with simpler hook callbacks
  • Evidence: query-lifecycle.test.ts was deleted and replaced with on-query-hooks.test.ts with completely different API structure
  • Impact: This is a breaking change that will affect any existing plugins
  • Recommendation: Ensure migration guide is available and version is properly marked as alpha

2. Plugin System Complexity Reduction

  • Old API: Model-specific query hooks like onQuery: { user: { findFirst: (ctx) => ... } }
  • New API: Universal hooks like onQuery: (ctx) => ...
  • Assessment: Simpler but potentially less granular control

Positive Aspects

1. TypeScript Performance Improvements

  • Plugin contract simplified (~1,100 lines changed in contract.ts)
  • Should significantly improve TypeScript compilation times
  • Well-executed refactoring for developer experience

2. Test Coverage Maintained

  • Comprehensive test reorganization with better separation
  • All plugin functionality appears to have test coverage
  • Entity mutation hooks properly tested

3. Release Management

  • All packages consistently bumped to 3.0.0-alpha.24
  • Proper monorepo version synchronization

🔍 Code Quality Assessment

Security: ✅ No security concerns identified

  • No secrets or sensitive data exposed
  • Input validation patterns maintained
  • Database query patterns are safe

Performance: ✅ Improved

  • Plugin system streamlined for better TypeScript performance
  • Query execution path simplified
  • Transaction handling looks efficient

Bugs: ⚠️ Low risk

  • Code appears well-tested but breaking changes require careful validation
  • Recommend testing with real-world plugin usage

📝 Recommendations

  1. Documentation: Update plugin development docs to reflect new API
  2. Migration: Provide clear migration examples for V2 → V3 plugin upgrade
  3. Testing: Run integration tests with existing plugins to catch edge cases
  4. Changelog: Document the breaking changes clearly for users

🎯 Verdict

Approved for Alpha Release - The changes are well-executed and improve the overall developer experience. The breaking changes are acceptable for an alpha version, but ensure proper communication to users.


Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
packages/runtime/src/client/client-impl.ts (1)

361-373: Post-processing uses stale args; use effective args after plugin overrides.

If a plugin overrides args, result post-processing should reflect the actual args used for execution. Currently it always uses the original args.

-            let proceed = async (_args?: unknown) => {
-                const _handler = txClient ? handler.withClient(txClient) : handler;
-                const r = await _handler.handle(operation, _args ?? args);
+            let proceed = async (_args?: unknown) => {
+                const effectiveArgs = _args ?? args;
+                const _handler = txClient ? handler.withClient(txClient) : handler;
+                const r = await _handler.handle(operation, effectiveArgs);
                 if (!r && throwIfNoResult) {
                     throw new NotFoundError(model);
                 }
                 let result: unknown;
                 if (r && postProcess) {
-                    result = resultProcessor.processResult(r, model, args);
+                    result = resultProcessor.processResult(r, model, effectiveArgs);
                 } else {
                     result = r ?? null;
                 }
                 return result;
             };
♻️ Duplicate comments (2)
packages/runtime/test/plugin/on-query-hooks.test.ts (1)

3-3: Add afterEach to close the in-memory SQLite connection (duplicate of prior feedback).

Each test opens a new DB; none closes it. Add afterEach and import it from vitest to avoid leaking connections and keep suites consistent.

-import { beforeEach, describe, expect, it } from 'vitest';
+import { afterEach, beforeEach, describe, expect, it } from 'vitest';
@@
     beforeEach(async () => {
         _client = new ZenStackClient(schema, {
             dialect: new SqliteDialect({ database: new SQLite(':memory:') }),
         });
         await _client.$pushSchema();
     });
+
+    afterEach(async () => {
+        await _client?.$disconnect();
+    });

Also applies to: 10-15

packages/runtime/src/client/client-impl.ts (1)

379-383: onQuery wrapper drops overridden args and breaks multi-plugin propagation.

The wrapper replaces proceed with a zero-arg function and passes the original args into onQuery. Later plugins cannot propagate modified args to earlier ones.

-                const onQuery = plugin.onQuery;
-                if (onQuery) {
-                    const _proceed = proceed;
-                    proceed = () => onQuery({ client, model, operation, args, proceed: _proceed }) as Promise<unknown>;
-                }
+                const onQuery = plugin.onQuery;
+                if (onQuery) {
+                    const _proceed = proceed;
+                    // preserve proceed's signature and propagate arg overrides across the chain
+                    proceed = (_args?: unknown) =>
+                        onQuery({
+                            client,
+                            model,
+                            operation,
+                            args: _args ?? args,
+                            proceed: (nextArgs: unknown) => _proceed(nextArgs ?? _args ?? args),
+                        }) as Promise<unknown>;
+                }
🧹 Nitpick comments (3)
packages/runtime/src/client/client-impl.ts (1)

376-384: Document plugin invocation order for predictability.

Clarify that the last registered plugin is invoked first, which matters for composing behaviors.

-            // apply plugins
+            // apply plugins (the last registered plugin is invoked first)
             const plugins = [...(client.$options.plugins ?? [])];
packages/runtime/src/client/plugin.ts (2)

124-128: Fix doc comment for queryNode to reflect actual semantics.

The current comment suggests it's only for create/update, but the type exists for all actions and represents the Kysely AST node.

-    /**
-     * The mutation data. Only available for create and update actions.
-     */
+    /**
+     * Mutation query AST node (Kysely OperationNode).
+     * Note: available for all actions; contents vary by action.
+     */
     queryNode: OperationNode;

188-194: Preserve generic Schema on OnKyselyQueryArgs.schema for stronger typing.

Use Schema instead of SchemaDef to keep the actual schema type.

 export type OnKyselyQueryArgs<Schema extends SchemaDef> = {
     kysely: ToKysely<Schema>;
-    schema: SchemaDef;
+    schema: Schema;
     client: ClientContract<Schema>;
     query: RootOperationNode;
     proceed: ProceedKyselyQueryFunction;
 };
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b57827a and ad704f4.

📒 Files selected for processing (6)
  • README.md (3 hunks)
  • packages/runtime/src/client/client-impl.ts (2 hunks)
  • packages/runtime/src/client/plugin.ts (2 hunks)
  • packages/runtime/test/plugin/on-query-hooks.test.ts (1 hunks)
  • packages/runtime/test/policy/client-extensions.test.ts (5 hunks)
  • samples/blog/main.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • samples/blog/main.ts
  • packages/runtime/test/policy/client-extensions.test.ts
  • README.md
🧰 Additional context used
📓 Path-based instructions (1)
{packages,samples,tests}/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Packages are located in packages/, samples/, and tests/

Files:

  • packages/runtime/src/client/client-impl.ts
  • packages/runtime/test/plugin/on-query-hooks.test.ts
  • packages/runtime/src/client/plugin.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: Plugin Architecture: Runtime plugins for query interception and entity mutation hooks
📚 Learning: 2025-08-04T08:43:33.161Z
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: Plugin Architecture: Runtime plugins for query interception and entity mutation hooks

Applied to files:

  • packages/runtime/src/client/client-impl.ts
  • packages/runtime/test/plugin/on-query-hooks.test.ts
  • packages/runtime/src/client/plugin.ts
🧬 Code Graph Analysis (2)
packages/runtime/test/plugin/on-query-hooks.test.ts (3)
packages/runtime/src/client/contract.ts (1)
  • ClientContract (50-159)
packages/runtime/src/client/client-impl.ts (1)
  • ZenStackClient (40-46)
packages/runtime/src/client/plugin.ts (1)
  • definePlugin (45-47)
packages/runtime/src/client/plugin.ts (5)
packages/sdk/src/schema/schema.ts (2)
  • SchemaDef (10-18)
  • GetModels (108-108)
packages/runtime/src/client/crud/operations/base.ts (1)
  • CrudOperation (54-69)
packages/runtime/src/client/contract.ts (1)
  • ClientContract (50-159)
packages/runtime/src/utils/type-utils.ts (1)
  • MaybePromise (70-70)
packages/runtime/src/client/query-builder.ts (1)
  • ToKysely (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-test (20.x)
  • GitHub Check: claude-review

* fix: result type of `delete` API

* fix test

* update test
@claude
Copy link

claude bot commented Aug 14, 2025

Claude finished @ymc9's task —— View job


Pull Request Review Complete ✅

Reviewing PR #166: merge dev to main (3.0.0-alpha.24 release)

Review Checklist:

  • Analyze overall PR structure and scope
  • Review version bump changes across packages
  • Examine runtime plugin system refactoring
  • Analyze client implementation changes
  • Review test file reorganization and coverage
  • Check for potential bugs or breaking changes
  • Assess performance and security considerations
  • Provide comprehensive feedback summary

📋 Summary

This is a significant alpha release that includes major plugin system refactoring for TypeScript performance improvements. While the changes are well-structured, there are some important considerations for the team.

⚠️ Critical Issues

1. Breaking Changes in Plugin API

  • Issue: The plugin system underwent major refactoring - the old QueryContext pattern was replaced with simpler hook callbacks
  • Evidence: query-lifecycle.test.ts was deleted and replaced with on-query-hooks.test.ts with completely different API structure
  • Impact: This is a breaking change that will affect any existing plugins
  • Recommendation: Ensure migration guide is available and version is properly marked as alpha

2. Plugin System Complexity Reduction

  • Old API: Model-specific query hooks like onQuery: { user: { findFirst: (ctx) => ... } }
  • New API: Universal hooks like onQuery: (ctx) => ...
  • Assessment: Simpler but potentially less granular control

Positive Aspects

1. TypeScript Performance Improvements

  • Plugin contract simplified (~1,100 lines changed in contract.ts)
  • Should significantly improve TypeScript compilation times
  • Well-executed refactoring for developer experience

2. Test Coverage Maintained

  • Comprehensive test reorganization with better separation
  • All plugin functionality appears to have test coverage
  • Entity mutation hooks properly tested

3. Release Management

  • All packages consistently bumped to 3.0.0-alpha.24
  • Proper monorepo version synchronization

🔍 Code Quality Assessment

Security: ✅ No security concerns identified

  • No secrets or sensitive data exposed
  • Input validation patterns maintained
  • Database query patterns are safe

Performance: ✅ Improved

  • Plugin system streamlined for better TypeScript performance
  • Query execution path simplified
  • Transaction handling looks efficient

Bugs: ⚠️ Low risk

  • Code appears well-tested but breaking changes require careful validation
  • Recommend testing with real-world plugin usage

📝 Recommendations

  1. Documentation: Update plugin development docs to reflect new API
  2. Migration: Provide clear migration examples for V2 → V3 plugin upgrade
  3. Testing: Run integration tests with existing plugins to catch edge cases
  4. Changelog: Document the breaking changes clearly for users

🎯 Verdict

Approved for Alpha Release - The changes are well-executed and improve the overall developer experience. The breaking changes are acceptable for an alpha version, but ensure proper communication to users.


@claude
Copy link

claude bot commented Aug 14, 2025

Claude finished @ymc9's task —— View job


Pull Request Review for #166: merge dev to main (v3.0.0-alpha.24) ✅

Review Checklist:

  • Read repository guidelines (CLAUDE.md)
  • Analyze overall PR structure and scope
  • Review version bump changes across packages
  • Examine runtime plugin system refactoring
  • Analyze client implementation changes
  • Review test file reorganization and coverage
  • Check for potential bugs or breaking changes
  • Assess performance and security considerations
  • Provide comprehensive feedback summary

📋 Summary

This is a significant alpha release that includes major plugin system refactoring for TypeScript performance improvements. While the changes are well-structured, there are some important considerations for the team.

⚠️ Critical Issues

1. Breaking Changes in Plugin API

  • Issue: The plugin system underwent major refactoring - the old QueryContext pattern was replaced with simpler hook callbacks
  • Evidence: query-lifecycle.test.ts was deleted and replaced with on-query-hooks.test.ts with completely different API structure
  • Impact: This is a breaking change that will affect any existing plugins
  • Recommendation: Ensure migration guide is available and version is properly marked as alpha

2. Plugin System Complexity Reduction

  • Old API: Model-specific query hooks like onQuery: { user: { findFirst: (ctx) => ... } }
  • New API: Universal hooks like onQuery: (ctx) => ...
  • Assessment: Simpler but potentially less granular control

Positive Aspects

1. TypeScript Performance Improvements

  • Plugin contract simplified (~1,100 lines changed in contract.ts)
  • Should significantly improve TypeScript compilation times
  • Well-executed refactoring for developer experience

2. Test Coverage Maintained

  • Comprehensive test reorganization with better separation
  • All plugin functionality appears to have test coverage
  • Entity mutation hooks properly tested

3. Release Management

  • All packages consistently bumped to 3.0.0-alpha.24
  • Proper monorepo version synchronization

🔍 Code Quality Assessment

Security: ✅ No security concerns identified

  • No secrets or sensitive data exposed
  • Input validation patterns maintained
  • Database query patterns are safe

Performance: ✅ Improved

  • Plugin system streamlined for better TypeScript performance
  • Query execution path simplified
  • Transaction handling looks efficient

Bugs: ⚠️ Low risk

  • Code appears well-tested but breaking changes require careful validation
  • Recommend testing with real-world plugin usage

📝 Recommendations

  1. Documentation: Update plugin development docs to reflect new API
  2. Migration: Provide clear migration examples for V2 → V3 plugin upgrade
  3. Testing: Run integration tests with existing plugins to catch edge cases
  4. Changelog: Document the breaking changes clearly for users

🎯 Verdict

Approved for Alpha Release - The changes are well-executed and improve the overall developer experience. The breaking changes are acceptable for an alpha version, but ensure proper communication to users.


@ymc9 ymc9 added this pull request to the merge queue Aug 14, 2025
Merged via the queue into main with commit a607b46 Aug 14, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants