Skip to content

merge dev to main (v3.6.0)#2593

Merged
ymc9 merged 23 commits intomainfrom
dev
Apr 20, 2026
Merged

merge dev to main (v3.6.0)#2593
ymc9 merged 23 commits intomainfrom
dev

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented Apr 19, 2026

Summary by CodeRabbit

  • New Features

    • RPC OpenAPI spec generation.
    • Zod model schemas: new optionality to control field optionality.
    • Improved DB Date/Time handling for MySQL and PostgreSQL.
  • Breaking Changes

    • makeModelSchema() excludes relation fields by default; opt in via include/select.
  • Bug Fixes

    • Corrected to-one relation filtering (EXISTS-based).
    • Fixed TIME/Timetz parsing and MySQL TIME handling.
  • Chores

    • Version bumped to 3.6.0; build/tooling and package exports updated.
  • Tests

    • Added extensive OpenAPI and regression/e2e test coverage.

ymc9 and others added 20 commits April 3, 2026 10:50
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: ymc9 <104139426+ymc9@users.noreply.github.com>
Co-authored-by: ymc9 <104139426+ymc9@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…-auth/core instance

Without an explicit kysely devDependency, pnpm resolved @better-auth/core's
kysely peer dep to 0.28.8 (from better-auth's bundled copy) instead of the
workspace-catalog 0.28.16, creating two incompatible @better-auth/core
instances and causing TypeScript type errors at build time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…xist` error when the model is explicitly included (#2539)

Co-authored-by: ymc9 <104139426+ymc9@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lude relation fields from makeModelSchema by default + add "optionality" setting to control runtime optionality of fields (#2525)
…ilters (#2579)

Co-authored-by: evgenovalov <evgenii@flowlity.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…use cases (#2583)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 19, 2026

Claude finished @ymc9's task —— View job


Code Review for v3.6.0 Release (dev → main)

I've completed my comprehensive code review of this major release. Here are my findings:

Review Checklist:

  • Analyze build system migration (tsup → tsdown)
  • Review dependency updates and package.json changes
  • Check new configuration files
  • Assess code quality and best practices
  • Look for potential bugs or issues
  • Evaluate performance considerations
  • Check for security concerns
  • Review test coverage implications

🏗️ Build System Migration Analysis ✅

Positive Changes:

  • Standardized Build Config: The new @zenstackhq/tsdown-config package provides centralized, consistent build configuration
  • Multi-Entry Support: ORM package now supports multiple entry points for better tree-shaking (packages/orm/tsdown.config.ts:4-12)
  • Enhanced Export Maps: Comprehensive export maps for all dialects in ORM package (packages/orm/package.json:27-102)

📦 Dependency Updates & Package Changes ✅

Key Observations:

  • Breaking Change: CLI now requires Node 20+ (packages/cli/package.json:98) - ensure this is documented
  • Enhanced AST Processing: Language package includes new AST patching script (packages/language/scripts/patch-generated-ast.ts:1-31) for runtime field injection
  • Dependency Consistency: Proper use of workspace:* notation throughout

🔧 Code Quality & Best Practices ✅

Strengths:

  • Type Safety: Strong TypeScript usage with comprehensive type definitions in packages/orm/src/client/options.ts
  • Validation Architecture: Robust input validation system with proper error handling (packages/language/src/validators/datamodel-validator.ts:200-210)
  • Clean Abstractions: Well-structured dialect system for database-specific handling (packages/orm/src/client/crud/dialects/postgresql.ts:20-50)

🐛 Potential Issues & Bugs ⚠️

Concerns:

  1. Node Version Breaking Change: The Node 20+ requirement should be prominently documented in migration guides
  2. AST Patching: The post-generation AST patching approach (packages/language/scripts/patch-generated-ast.ts) is clever but fragile - consider more robust alternatives
  3. Large-Scale Migration: 100+ files changed - ensure comprehensive testing across all supported environments

🚀 Performance Considerations ✅

Positive Features:

  • Query Diagnostics: New slow query monitoring capabilities (packages/orm/src/client/options.ts:222-233)
  • Tree-Shaking: Improved with multi-entry build system and better export maps
  • Zod Schema Optimization: Enhanced schema generation with better field ordering preservation (packages/orm/src/client/zod/factory.ts:397-409)

🔒 Security Assessment ✅

Security Posture:

  • Input Validation: Comprehensive validation system remains intact with configurable options (packages/orm/src/client/options.ts:197-203)
  • SQL Injection Prevention: Kysely-based query building provides protection through parameterized queries
  • Type Safety: Strong TypeScript typing prevents many classes of runtime errors

No Critical Security Issues Identified

🧪 Test Coverage Implications ✅

Test Strategy:

  • Mixin System: Enhanced test coverage for type mixins (packages/language/test/mixin.test.ts:92-104)
  • Regression Testing: Comprehensive regression test suite remains intact
  • Breaking Changes: Tests should cover the documented breaking changes in BREAKINGCHANGES.md

📋 Final Recommendations

✅ Approve with Notes:

  1. Document Breaking Changes: Ensure Node 20+ requirement is clearly communicated
  2. Migration Testing: Run comprehensive tests across all supported databases and Node versions
  3. Monitor AST Patching: Consider more robust alternatives to string replacement in future releases

Summary: This is a well-executed major release with significant architectural improvements. The build system migration is clean, type safety is maintained, and no critical security issues were identified. The main concern is ensuring proper documentation of breaking changes, particularly the Node version requirement.


@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 19, 2026

📝 Walkthrough

Walkthrough

The PR migrates build tooling from tsup to tsdown (new @zenstackhq/tsdown-config), switches ESM outputs to .mjs/.d.mts, centralizes schema types to @zenstackhq/schema, changes Zod defaults (exclude relation fields, add optionality modes), refactors ORM relation filters to EXISTS, and adds an RPC OpenAPI generator plus many tests and config updates.

Changes

Cohort / File(s) Summary
Build tooling & config
package.json, packages/*/package.json, packages/config/tsdown-config/*, packages/*/tsdown.config.ts, packages/*/tsup.config.ts
Introduce @zenstackhq/tsdown-config, add per-package tsdown.config.ts, remove many tsup.config.ts files, update build scripts from tsup/tsup-nodetsdown, bump package versions and packageManager.
ESM artifact & CLI entry updates
packages/cli/bin/cli, packages/create-zenstack/bin/cli, packages/cli/scripts/post-build.ts, .vscode/launch.json, scripts/test-generate.ts, samples/orm/...
Change runtime entrypoints and post-build targets from *.js to *.mjs and update CLI/test launch references accordingly.
Schema type sourcing
packages/orm/src/**, packages/orm/src/client/**, packages/orm/src/client/crud/**
Replace many local ../schema type imports with package-scoped @zenstackhq/schema imports across ORM client/dialects/operations.
ORM dialects & SQL logic
packages/orm/src/client/crud/dialects/base-dialect.ts, .../mysql.ts, .../postgresql.ts, sqlite.ts, related tests`
Change cursor handling for delegated fields; replace count-based relation filters with EXISTS-based queries; improve MySQL/Postgres time parsing and related SQL formatting.
Zod library & schema behavior
packages/zod/src/types.ts, packages/zod/src/factory.ts, packages/zod/src/utils.ts, packages/zod/test/*
Default exclusion of relation fields from model schemas, add optionality ('all'
RPC OpenAPI generation
packages/server/src/api/rpc/openapi.ts, packages/server/src/api/rpc/index.ts, packages/server/test/openapi/rpc-openapi.test.ts
Add RPCApiSpecGenerator with OpenAPI 3.1 generation from Zod schemas, component rewriting, tags/paths generation, and comprehensive tests.
OpenAPI utilities & REST integration
packages/server/src/api/common/spec-utils.ts, packages/server/src/api/rest/openapi.ts
Extract mayDenyAccess util, add DEFAULT_SPEC_* constants, refactor REST OpenAPI to use extracted utility and respect access flag.
Language package & AST
packages/language/src/*, packages/language/scripts/patch-generated-ast.ts, packages/language/test/*
Remove local AST augmentation, add AST patch script injecting fields, add validator change disallowing model fields inside typedef JSON usage, add JSDoc and mixin test updates.
SDK & ts-schema generation
packages/sdk/src/ts-schema-generator.ts, packages/sdk/tsdown.config.ts
Context-aware relation/foreign-key generation for delegates/mixins; safer param access and related internal schema generation tweaks.
Tests & regression suites
tests/e2e/**, tests/regression/**, packages/server/test/**, packages/*/test/**
Add/modify many tests: RPC OpenAPI, mixin behavior, timezone handling, to-one relation filters, regression cases, and zod optionality tests.
Monorepo/editor docs
.vscode/settings.json, .vscode/launch.json, BREAKINGCHANGES.md, CLAUDE.md, README.md, pnpm-workspace.yaml
Add TS SDK path setting, update launch config, document breaking change (makeModelSchema relation exclusion), update README install command, bump catalog kysely range.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 I swapped the hops from tsup to tsdown,
ESM ears twitch—.mjs in town.
Relations hide unless you say please,
EXISTS nibble through SQL trees.
OpenAPI blooms, tests multiply—hop, hop, hooray!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/zod/src/utils.ts (1)

447-466: ⚠️ Potential issue | 🟠 Major

Skip ABSENT for membership predicates too.

Line 439 skips omitted fields for ordered comparisons, but ?, !, ^, and in still treat ABSENT as a real operand and return false. A partial payload can therefore fail rules like @@validate(tags ? "x") or @@validate(status in ["A"]) even when the field was not provided.

🐛 Proposed fix
         case '?':
+            if (left === ABSENT || right === ABSENT) return true;
             if (!Array.isArray(left)) {
                 return false;
             }
             return left.some((item) => item === right);
         case '!':
+            if (left === ABSENT || right === ABSENT) return true;
             if (!Array.isArray(left)) {
                 return false;
             }
             return left.every((item) => item === right);
         case '^':
+            if (left === ABSENT || right === ABSENT) return true;
             if (!Array.isArray(left)) {
                 return false;
             }
             return !left.some((item) => item === right);
         case 'in':
+            if (left === ABSENT || right === ABSENT) return true;
             if (!Array.isArray(right)) {
                 return false;
             }
             return right.includes(left);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/zod/src/utils.ts` around lines 447 - 466, The membership predicate
cases ('?', '!', '^', 'in') currently treat the ABSENT sentinel as a real value
and fail; update each case to early-return true when the relevant operand is
ABSENT (i.e., for '?', '!', '^' if left === ABSENT return true; for 'in' if left
=== ABSENT or right === ABSENT return true / or at minimum if the operand you
expect to be omitted equals ABSENT return true) so omitted fields are skipped
like the ordered-comparison branch does; use the existing ABSENT constant and
modify the switch cases for '?', '!', '^', and 'in' accordingly.
packages/zod/src/factory.ts (1)

135-166: ⚠️ Potential issue | 🟠 Major

Don’t deprecate these helpers to a non-equivalent replacement.

Line 136 and Line 165 point users to makeModelSchema(...), but that path still includes computed and discriminator fields, while makeModelCreateSchema/makeModelUpdateSchema explicitly exclude them. Following this deprecation would make create/update validators reject valid payloads or require output-only fields.

Proposed fix
 /**
- * `@deprecated` Use `makeModelSchema(model, { optionality: 'defaults' })` instead.
+ * Creates a schema for create-input payloads. This is not equivalent to
+ * `makeModelSchema(model, { optionality: 'defaults' })` because create inputs
+ * exclude computed and discriminator fields.
  */
 makeModelCreateSchema<Model extends GetModels<Schema>>(

 /**
- * `@deprecated` Use `makeModelSchema(model, { optionality: 'all' })` instead.
+ * Creates a schema for update-input payloads. This is not equivalent to
+ * `makeModelSchema(model, { optionality: 'all' })` because update inputs
+ * exclude computed and discriminator fields.
  */
 makeModelUpdateSchema<Model extends GetModels<Schema>>(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/zod/src/factory.ts` around lines 135 - 166, The deprecation note
incorrectly points users to makeModelSchema(...) which still includes computed
and discriminator fields, unlike makeModelCreateSchema and makeModelUpdateSchema
that explicitly exclude them; update the API or docs so behavior is preserved:
either stop deprecating makeModelCreateSchema/makeModelUpdateSchema or change
makeModelSchema signature to accept flags (e.g.,
excludeComputed/excludeDiscriminator or a mode for create/update) and update
callers to call makeModelSchema(model, { optionality: 'defaults',
excludeComputed: true, excludeDiscriminator: true }) (or equivalent) so computed
and isDiscriminator fields are omitted, and adjust
applyDescription/addCustomValidation usage in
makeModelCreateSchema/makeModelUpdateSchema to delegate to the new option-based
makeModelSchema implementation; reference the functions makeModelCreateSchema,
makeModelUpdateSchema, and makeModelSchema and the field properties computed and
isDiscriminator when making the change.
packages/zod/src/types.ts (1)

318-332: ⚠️ Potential issue | 🟡 Minor

Keep select typing aligned with true-only runtime validation.

ModelSchemaOptions now rejects false, but SelectEntryToZod still maps any boolean to an included field. If a caller’s option type is widened or passed through a generic, false can produce a selected field at the type level while runtime validation rejects it.

Proposed type tightening
-> = Value extends boolean
-    ? // `true` or widened `boolean` — use the default shape for this field.
-      // Handling `boolean` (not just literal `true`) prevents the type from
-      // collapsing to `never` when callers use a boolean variable instead of
-      // a literal (e.g. `const pick: boolean = true`).
+> = Value extends true
+    ?
       GetAllModelFieldsShape<Schema, Model>[FieldInShape<Schema, Model, Field>]

Also applies to: 338-340

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/zod/src/types.ts` around lines 318 - 332, SelectEntryToZod currently
treats any boolean as a truthy selection which can type-select fields even when
runtime accepts only literal true; change the boolean branch to require the
literal true (i.e. use Value extends true) so only explicit true maps to
GetAllModelFieldsShape via FieldInShape, and similarly tighten the analogous
type(s) around lines 338-340 to use Value extends true instead of Value extends
boolean; keep RelationFieldZodWithOptions handling for object values unchanged.
packages/orm/src/client/zod/factory.ts (1)

1367-1377: ⚠️ Potential issue | 🟠 Major

Don’t make createManyAndReturn args optional.

Line 1375 makes the schema accept undefined, but createManyAndReturn requires a data payload and the return type is not | undefined. This can let an invalid mutation through validation.

Proposed fix
-        const schema = this.refineForSelectHasTruthyField(
-            this.refineForSelectOmitMutuallyExclusive(result),
-        ).optional() as ZodType<CreateManyAndReturnArgs<Schema, Model, Options, ExtQueryArgs>>;
+        const schema = this.refineForSelectHasTruthyField(
+            this.refineForSelectOmitMutuallyExclusive(result),
+        ) as ZodType<CreateManyAndReturnArgs<Schema, Model, Options, ExtQueryArgs>>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/zod/factory.ts` around lines 1367 - 1377, The
generated schema for createManyAndReturn (registered as
`${model}CreateManyAndReturnArgs`) is being marked optional, allowing undefined
through validation; remove the .optional() call so the final schema produced by
makeCreateManyPayloadSchema / mergePluginArgsSchema and then refined by
refineForSelectOmitMutuallyExclusive and refineForSelectHasTruthyField is
required, ensuring the required data payload is validated for
createManyAndReturn; update the construction where result is refined and
registered (the code calling refineForSelectHasTruthyField(...).optional()) to
drop .optional() so registerSchema and the exported CreateManyAndReturnArgs type
no longer accept undefined.
🧹 Nitpick comments (9)
tests/e2e/orm/client-api/timezone/pg-timezone.test.ts (1)

634-642: Tighten direct-select assertions for all time fields.

The direct-select path should validate close and openTz normalization, not just their Date instance type. Keep the looser effectiveOn check as-is.

Proposed assertions
             expect(windows[0].open).toBeInstanceOf(Date);
             expect(windows[0].open.toISOString()).toBe('1970-01-01T09:30:00.000Z');
             expect(windows[0].close).toBeInstanceOf(Date);
+            expect(windows[0].close.toISOString()).toBe('1970-01-01T16:00:00.000Z');
             expect(windows[0].openTz).toBeInstanceOf(Date);
+            expect(windows[0].openTz.toISOString()).toBe('1970-01-01T09:30:00.000Z');
             // On direct select pg's default DATE parser returns a Date anchored in local
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/orm/client-api/timezone/pg-timezone.test.ts` around lines 634 -
642, The direct-select assertions are too loose for the time fields — tighten
them by asserting that windows[0].close and windows[0].openTz are Date instances
and that their ISO strings match the expected normalized UTC values (similar to
the existing check for open.toISOString()), while keeping windows[0].effectiveOn
only asserted as a Date; update the assertions referring to windows[0].close and
windows[0].openTz in the pg-timezone.test.ts block so they validate both
instance type and toISOString equality.
tests/e2e/orm/client-api/timezone/mysql-timezone.test.ts (1)

80-84: Assert the direct-select close value too.

Date instance checks can still pass for invalid dates. The nested test asserts close.toISOString(), so the direct-select path should do the same to fully cover the regression.

Proposed assertion
             expect(windows[0].open).toBeInstanceOf(Date);
             expect(windows[0].open.toISOString()).toBe('1970-01-01T09:30:00.000Z');
             expect(windows[0].close).toBeInstanceOf(Date);
+            expect(windows[0].close.toISOString()).toBe('1970-01-01T16:00:00.000Z');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/orm/client-api/timezone/mysql-timezone.test.ts` around lines 80 -
84, The test currently only asserts that windows[0].close is a Date instance;
update the assertion for the direct-select path to assert the actual ISO string
as well by calling windows[0].close.toISOString() and comparing it to the
expected value '1970-01-01T16:00:00.000Z' (matching the nested test's check), so
the variable windows and its element windows[0].close are validated for the
correct timestamp rather than just Date validity.
tests/regression/test/issue-2578.test.ts (1)

50-51: Nit: trivial sanity assertions can be dropped.

Lines 50-51 and 71 just re-assert ids exist after create already returned them. They don't strengthen the test and only make intent slightly noisier — consider removing if not needed for readability.

🧹 Proposed trim
-        // keep references live so the test intent is readable
-        expect([p1.id, p2.id, p3.id].length).toBe(3);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/regression/test/issue-2578.test.ts` around lines 50 - 51, Remove the
trivial sanity assertions that only re-check created ids (e.g., the
expect([p1.id, p2.id, p3.id].length).toBe(3) line and the similar assertion
around line 71); locate the assertions referencing p1.id, p2.id, p3.id (and the
analogous id-check later) in the test and delete those expect(...) lines so the
test reads cleaner while preserving the meaningful assertions that follow
create.
packages/clients/client-helpers/tsdown.config.ts (1)

8-8: Minor: explicit format: ['esm'] may be redundant.

Most other packages in this PR (e.g., packages/sdk, packages/orm, packages/auth-adapters/better-auth) rely on the default from @zenstackhq/tsdown-config without overriding format. If the shared config already defaults to ESM, consider dropping this override for consistency; if ESM-only is intentional here (vs. other packages that also emit CJS), a short comment would help readers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/clients/client-helpers/tsdown.config.ts` at line 8, The explicit
format: ['esm'] setting in tsdown.config.ts appears redundant with the shared
`@zenstackhq/tsdown-config` default; either remove the override to align with
other packages (delete the format property) or, if you intentionally require
ESM-only output for this package, keep the format: ['esm'] entry and add a
one-line comment explaining why ESM-only is required so readers understand the
deviation from the shared config.
packages/config/tsdown-config/src/index.ts (1)

9-17: Shallow merge may silently drop array defaults when overriding.

...overrides shallow-merges over the defaults, so a caller passing format: ['esm'] replaces the default ['cjs','esm'] (probably intended), but passing a partial config object like { dts: { ... } } also wholly replaces dts: true. This is fine for the current usage pattern, but worth documenting that overrides are shallow. Also, since defineConfig accepts an array/function form, typing Config = Parameters<typeof defineConfig>[0] permits non-object inputs that would break the spread — constraining overrides to the object variant would be safer.

Proposed tightening
-type Config = Parameters<typeof defineConfig>[0];
+type Config = Extract<Parameters<typeof defineConfig>[0], Record<string, unknown>>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/config/tsdown-config/src/index.ts` around lines 9 - 17, The
createConfig function currently accepts a broad Config type derived from
Parameters<typeof defineConfig>[0], which can include non-object forms and makes
the spread merge unsafe and shallow; tighten the overrides parameter to only
accept the object form of defineConfig's parameter (so callers can’t pass an
array/function) and either document that the merge is shallow (so keys like
format/dts are replaced entirely) or implement a deep-merge if true merging is
required; update the signature and add a short comment above createConfig
mentioning "shallow merge: overrides replace defaults" and reference the
overrides parameter, createConfig function, defineConfig, and keys like format
and dts when making the change.
packages/config/tsdown-config/package.json (1)

1-19: Missing tsdown as a dependency.

src/index.ts imports defineConfig from tsdown and re-exports a wrapper, but tsdown is not declared in dependencies or peerDependencies here. Since this is a private workspace package and consumers always depend on tsdown themselves, it works in practice, but declaring it (likely as a peerDependency) would make the contract explicit and avoid hoisting surprises.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/config/tsdown-config/package.json` around lines 1 - 19, The
package.json for `@zenstackhq/tsdown-config` is missing the tsdown runtime
contract; update package.json to declare "tsdown" as a peerDependency (so
consumers must provide it) and also add it to devDependencies for local
development/testing; ensure the version spec matches the project's tsdown range
and keep the existing "exports" and scripts intact. Locate src/index.ts which
imports defineConfig from "tsdown" to confirm the symbol and to validate the
version chosen.
packages/server/src/api/rest/openapi.ts (1)

186-186: Optional: minor consistency/readability nits in refactored path builders.

Two small things while this area is being reshaped:

  1. buildCollectionPath(modelName, modelDef, tag) takes both modelName and modelDef, whereas buildSinglePath(modelDef, tag) derives modelName from modelDef.name. Aligning them (drop modelName, use modelDef.name) reduces the risk of the two going out of sync.
  2. In buildNestedSinglePath, mayDenyUpdate / mayDenyDelete are computed up-front regardless of whether the corresponding operations end up being included. Not a correctness issue; you could move each computation inside its respective if (isOperationIncluded(...)) branch for clarity and to avoid unnecessary work when ops are filtered out.

Neither is blocking — purely optional polish.

Also applies to: 431-441

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/server/src/api/rest/openapi.ts` at line 186, Change
buildCollectionPath to derive the model name from modelDef.name instead of
accepting a separate modelName parameter (aligning its signature with
buildSinglePath) to avoid divergence between the two values; in
buildNestedSinglePath, defer computing mayDenyUpdate and mayDenyDelete by moving
their evaluations inside the respective if (isOperationIncluded(...)) branches
so they are only computed when the update/delete operations will actually be
included; update any callers to stop passing modelName into buildCollectionPath
and rely on modelDef.name instead.
packages/language/src/ast.ts (1)

1-2: Make generated AST imports type-only.

These symbols are only used in type positions in this file. Converting them to type-only imports improves clarity. The const values remain available to consumers via the export * from './generated/ast' wildcard export.

♻️ Proposed refinement
 import type { AstNode } from 'langium';
-import { AbstractDeclaration, BinaryExpr, DataModel, type ExpressionType } from './generated/ast';
+import type { AbstractDeclaration, BinaryExpr, DataModel, ExpressionType } from './generated/ast';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/language/src/ast.ts` around lines 1 - 2, The imported generated AST
symbols (AbstractDeclaration, BinaryExpr, DataModel, ExpressionType) are only
used as types and should be imported as type-only; update the import so those
names are brought in via a type-only import (e.g., use an import type for
AbstractDeclaration, BinaryExpr, DataModel, and ExpressionType) while leaving
the existing type import for AstNode unchanged so runtime exports remain
available via the wildcard export.
packages/orm/src/client/zod/factory.ts (1)

758-760: Remove the duplicate cache decorator.

makeArrayFilterSchema is decorated with @cache() twice. That is easy to miss and can wrap/cache the method redundantly.

Proposed cleanup
-    `@cache`()
     `@cache`()
     private makeArrayFilterSchema(fieldType: string, allowedFilterKinds: string[] | undefined) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/zod/factory.ts` around lines 758 - 760, The method
makeArrayFilterSchema is decorated twice with `@cache`(), causing redundant
decoration; remove the duplicated `@cache`() so the method has a single `@cache`()
decorator applied to it (locate the makeArrayFilterSchema declaration and delete
the extra decorator instance), verifying there are no other accidental duplicate
decorators nearby and that imports/usages remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Line 17: The packageManager field was changed to "pnpm@10.33.0" but CLAUDE.md
documents pinning to "pnpm@10.12.1"; update either the package.json or the
documentation so they agree. Restore the packageManager value to "pnpm@10.12.1"
in package.json if you want to follow the existing policy, or edit CLAUDE.md to
document the intentional bump to "pnpm@10.33.0" and update any subpackage notes
(e.g., VSCode subpackage) so all references to the pnpm pin are consistent.
Ensure the change mentions the packageManager key and the specific pnpm version
string you choose.

In `@packages/language/scripts/patch-generated-ast.ts`:
- Around line 14-27: The patch currently does blind includes/replace for
AttributeArg/$resolvedParam and DataModel/$allFields which can silently fail;
after attempting each replace (the blocks modifying content for 'AttributeArg'
and 'DataModel'), validate that the replacement actually occurred (e.g., check
that content now includes '$resolvedParam' and '$allFields' or that the original
pattern was removed) and if not throw an explicit Error (or exit non-zero) with
a clear message referencing the affected symbols (AttributeArg, $resolvedParam,
DataModel, $allFields) so the script fails fast when the AST patch target is
missing.

In `@packages/orm/src/client/crud/dialects/mysql.ts`:
- Around line 180-182: The MySQL transformOutputDate currently returns new
Date(...) directly which can produce an unhelpful "Invalid Date" object; update
the code in transformOutputDate to construct the Date from anchored (append 'Z'
if missing), store it in a local variable (e.g., const d = new Date(...)), then
check if the date is invalid (Number.isNaN(d.getTime())) and return null in that
case, otherwise return the valid Date instance — matching the PostgreSQL
dialect's invalid-date guard.

In `@packages/orm/src/client/zod/factory.ts`:
- Around line 223-226: The toJSONSchema() path eagerly builds args schemas for
every procedure by calling makeProcedureArgsSchema for each key in
this.schema.procedures, which can register `${procName}ProcArgs` components for
procedures that should be hidden; add an isProcedureAllowed check (reusing the
same QueryOptions slicing logic used by server spec path generation) and only
call makeProcedureArgsSchema(procName) when isProcedureAllowed(procName,
queryOptions) returns true so that args components for excluded procedures are
not registered in the JSON-schema components.

In `@packages/orm/src/common-types.ts`:
- Line 3: The JsonArray type must accept readonly arrays to avoid breaking
assignability to JsonValue; update the definition of JsonArray (in
common-types.ts) from Array<JsonValue | null> to ReadonlyArray<JsonValue | null>
so readonly JSON arrays remain compatible (mutable arrays will still be
assignable to this readonly type).

In `@packages/server/src/api/rpc/openapi.ts`:
- Around line 531-546: The response-side model schemas can reference enum
components that aren't being emitted, causing dangling $refs; in
generateSharedSchemas() include enum schemas as well (e.g. build each enum from
this.schema.enums via a buildEnumSchema(enumDef) and merge them into the
returned object alongside typeDefSchemas and modelEntitySchemas) so
buildModelEntitySchema() refs resolve; apply the same change in the analogous
block around the other occurrence (the similar function at lines ~684-691) so
enums are always present for response and procedure return types.
- Around line 469-475: The OpenAPI operation currently sets op['requestBody']
with content when hasParams is true but does not mark the request body as
required; update the code that builds the requestBody (the block that references
op, hasParams, JSON_CT, and envelopeSchema) to set requestBody.required = true
whenever hasParams is true so clients will be forced to include the envelope
(with args) for mutation procedures. Ensure you only change the requestBody
creation for the branch that uses envelopeSchema/JSON_CT and leave other
branches untouched.

In `@tests/regression/test/issue-2550/regression.test.ts`:
- Around line 1-6: The test file is in the wrong path/name; rename
tests/regression/test/issue-2550/regression.test.ts to
tests/regression/test/issue-2550.test.ts and update the schema import so it
points to the fixture directory (change the import of './schema' to
'./issue-2550/schema' or the correct relative path to the moved fixture
directory); ensure the test still imports createTestClient, createSchemaFactory,
and schema from their updated locations and run the tests.

---

Outside diff comments:
In `@packages/orm/src/client/zod/factory.ts`:
- Around line 1367-1377: The generated schema for createManyAndReturn
(registered as `${model}CreateManyAndReturnArgs`) is being marked optional,
allowing undefined through validation; remove the .optional() call so the final
schema produced by makeCreateManyPayloadSchema / mergePluginArgsSchema and then
refined by refineForSelectOmitMutuallyExclusive and
refineForSelectHasTruthyField is required, ensuring the required data payload is
validated for createManyAndReturn; update the construction where result is
refined and registered (the code calling
refineForSelectHasTruthyField(...).optional()) to drop .optional() so
registerSchema and the exported CreateManyAndReturnArgs type no longer accept
undefined.

In `@packages/zod/src/factory.ts`:
- Around line 135-166: The deprecation note incorrectly points users to
makeModelSchema(...) which still includes computed and discriminator fields,
unlike makeModelCreateSchema and makeModelUpdateSchema that explicitly exclude
them; update the API or docs so behavior is preserved: either stop deprecating
makeModelCreateSchema/makeModelUpdateSchema or change makeModelSchema signature
to accept flags (e.g., excludeComputed/excludeDiscriminator or a mode for
create/update) and update callers to call makeModelSchema(model, { optionality:
'defaults', excludeComputed: true, excludeDiscriminator: true }) (or equivalent)
so computed and isDiscriminator fields are omitted, and adjust
applyDescription/addCustomValidation usage in
makeModelCreateSchema/makeModelUpdateSchema to delegate to the new option-based
makeModelSchema implementation; reference the functions makeModelCreateSchema,
makeModelUpdateSchema, and makeModelSchema and the field properties computed and
isDiscriminator when making the change.

In `@packages/zod/src/types.ts`:
- Around line 318-332: SelectEntryToZod currently treats any boolean as a truthy
selection which can type-select fields even when runtime accepts only literal
true; change the boolean branch to require the literal true (i.e. use Value
extends true) so only explicit true maps to GetAllModelFieldsShape via
FieldInShape, and similarly tighten the analogous type(s) around lines 338-340
to use Value extends true instead of Value extends boolean; keep
RelationFieldZodWithOptions handling for object values unchanged.

In `@packages/zod/src/utils.ts`:
- Around line 447-466: The membership predicate cases ('?', '!', '^', 'in')
currently treat the ABSENT sentinel as a real value and fail; update each case
to early-return true when the relevant operand is ABSENT (i.e., for '?', '!',
'^' if left === ABSENT return true; for 'in' if left === ABSENT or right ===
ABSENT return true / or at minimum if the operand you expect to be omitted
equals ABSENT return true) so omitted fields are skipped like the
ordered-comparison branch does; use the existing ABSENT constant and modify the
switch cases for '?', '!', '^', and 'in' accordingly.

---

Nitpick comments:
In `@packages/clients/client-helpers/tsdown.config.ts`:
- Line 8: The explicit format: ['esm'] setting in tsdown.config.ts appears
redundant with the shared `@zenstackhq/tsdown-config` default; either remove the
override to align with other packages (delete the format property) or, if you
intentionally require ESM-only output for this package, keep the format: ['esm']
entry and add a one-line comment explaining why ESM-only is required so readers
understand the deviation from the shared config.

In `@packages/config/tsdown-config/package.json`:
- Around line 1-19: The package.json for `@zenstackhq/tsdown-config` is missing
the tsdown runtime contract; update package.json to declare "tsdown" as a
peerDependency (so consumers must provide it) and also add it to devDependencies
for local development/testing; ensure the version spec matches the project's
tsdown range and keep the existing "exports" and scripts intact. Locate
src/index.ts which imports defineConfig from "tsdown" to confirm the symbol and
to validate the version chosen.

In `@packages/config/tsdown-config/src/index.ts`:
- Around line 9-17: The createConfig function currently accepts a broad Config
type derived from Parameters<typeof defineConfig>[0], which can include
non-object forms and makes the spread merge unsafe and shallow; tighten the
overrides parameter to only accept the object form of defineConfig's parameter
(so callers can’t pass an array/function) and either document that the merge is
shallow (so keys like format/dts are replaced entirely) or implement a
deep-merge if true merging is required; update the signature and add a short
comment above createConfig mentioning "shallow merge: overrides replace
defaults" and reference the overrides parameter, createConfig function,
defineConfig, and keys like format and dts when making the change.

In `@packages/language/src/ast.ts`:
- Around line 1-2: The imported generated AST symbols (AbstractDeclaration,
BinaryExpr, DataModel, ExpressionType) are only used as types and should be
imported as type-only; update the import so those names are brought in via a
type-only import (e.g., use an import type for AbstractDeclaration, BinaryExpr,
DataModel, and ExpressionType) while leaving the existing type import for
AstNode unchanged so runtime exports remain available via the wildcard export.

In `@packages/orm/src/client/zod/factory.ts`:
- Around line 758-760: The method makeArrayFilterSchema is decorated twice with
`@cache`(), causing redundant decoration; remove the duplicated `@cache`() so the
method has a single `@cache`() decorator applied to it (locate the
makeArrayFilterSchema declaration and delete the extra decorator instance),
verifying there are no other accidental duplicate decorators nearby and that
imports/usages remain unchanged.

In `@packages/server/src/api/rest/openapi.ts`:
- Line 186: Change buildCollectionPath to derive the model name from
modelDef.name instead of accepting a separate modelName parameter (aligning its
signature with buildSinglePath) to avoid divergence between the two values; in
buildNestedSinglePath, defer computing mayDenyUpdate and mayDenyDelete by moving
their evaluations inside the respective if (isOperationIncluded(...)) branches
so they are only computed when the update/delete operations will actually be
included; update any callers to stop passing modelName into buildCollectionPath
and rely on modelDef.name instead.

In `@tests/e2e/orm/client-api/timezone/mysql-timezone.test.ts`:
- Around line 80-84: The test currently only asserts that windows[0].close is a
Date instance; update the assertion for the direct-select path to assert the
actual ISO string as well by calling windows[0].close.toISOString() and
comparing it to the expected value '1970-01-01T16:00:00.000Z' (matching the
nested test's check), so the variable windows and its element windows[0].close
are validated for the correct timestamp rather than just Date validity.

In `@tests/e2e/orm/client-api/timezone/pg-timezone.test.ts`:
- Around line 634-642: The direct-select assertions are too loose for the time
fields — tighten them by asserting that windows[0].close and windows[0].openTz
are Date instances and that their ISO strings match the expected normalized UTC
values (similar to the existing check for open.toISOString()), while keeping
windows[0].effectiveOn only asserted as a Date; update the assertions referring
to windows[0].close and windows[0].openTz in the pg-timezone.test.ts block so
they validate both instance type and toISOString equality.

In `@tests/regression/test/issue-2578.test.ts`:
- Around line 50-51: Remove the trivial sanity assertions that only re-check
created ids (e.g., the expect([p1.id, p2.id, p3.id].length).toBe(3) line and the
similar assertion around line 71); locate the assertions referencing p1.id,
p2.id, p3.id (and the analogous id-check later) in the test and delete those
expect(...) lines so the test reads cleaner while preserving the meaningful
assertions that follow create.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 234cd176-0c10-422d-9853-b9fe001579c1

📥 Commits

Reviewing files that changed from the base of the PR and between ddc1b14 and 3398c87.

⛔ Files ignored due to path filters (2)
  • packages/language/src/generated/ast.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (137)
  • .vscode/launch.json
  • .vscode/settings.json
  • BREAKINGCHANGES.md
  • CLAUDE.md
  • README.md
  • package.json
  • packages/auth-adapters/better-auth/package.json
  • packages/auth-adapters/better-auth/test/cli-generate.test.ts
  • packages/auth-adapters/better-auth/tsdown.config.ts
  • packages/auth-adapters/better-auth/tsup.config.ts
  • packages/cli/bin/cli
  • packages/cli/package.json
  • packages/cli/scripts/post-build.ts
  • packages/cli/test/utils.ts
  • packages/cli/tsdown.config.ts
  • packages/cli/tsup.config.ts
  • packages/clients/client-helpers/package.json
  • packages/clients/client-helpers/tsconfig.json
  • packages/clients/client-helpers/tsconfig.test.json
  • packages/clients/client-helpers/tsdown.config.ts
  • packages/clients/client-helpers/tsup.config.ts
  • packages/clients/tanstack-query/package.json
  • packages/clients/tanstack-query/tsconfig.general.json
  • packages/clients/tanstack-query/tsconfig.svelte.json
  • packages/clients/tanstack-query/tsconfig.test.json
  • packages/common-helpers/package.json
  • packages/common-helpers/tsconfig.json
  • packages/common-helpers/tsdown.config.ts
  • packages/common-helpers/tsup.config.ts
  • packages/config/eslint-config/package.json
  • packages/config/tsdown-config/package.json
  • packages/config/tsdown-config/src/index.ts
  • packages/config/tsdown-config/tsconfig.json
  • packages/config/typescript-config/package.json
  • packages/config/vitest-config/package.json
  • packages/create-zenstack/bin/cli
  • packages/create-zenstack/package.json
  • packages/create-zenstack/tsconfig.json
  • packages/create-zenstack/tsdown.config.ts
  • packages/create-zenstack/tsup.config.ts
  • packages/ide/vscode/package.json
  • packages/ide/vscode/scripts/post-build.ts
  • packages/ide/vscode/tsdown.config.ts
  • packages/ide/vscode/tsup.config.ts
  • packages/language/package.json
  • packages/language/scripts/patch-generated-ast.ts
  • packages/language/src/ast.ts
  • packages/language/src/utils.ts
  • packages/language/src/validators/datamodel-validator.ts
  • packages/language/src/validators/typedef-validator.ts
  • packages/language/test/mixin.test.ts
  • packages/language/tsdown.config.ts
  • packages/language/tsup.config.ts
  • packages/orm/package.json
  • packages/orm/src/client/client-impl.ts
  • packages/orm/src/client/contract.ts
  • packages/orm/src/client/crud-types.ts
  • packages/orm/src/client/crud/dialects/base-dialect.ts
  • packages/orm/src/client/crud/dialects/index.ts
  • packages/orm/src/client/crud/dialects/lateral-join-dialect-base.ts
  • packages/orm/src/client/crud/dialects/mysql.ts
  • packages/orm/src/client/crud/dialects/postgresql.ts
  • packages/orm/src/client/crud/dialects/sqlite.ts
  • packages/orm/src/client/crud/operations/aggregate.ts
  • packages/orm/src/client/crud/operations/base.ts
  • packages/orm/src/client/crud/operations/count.ts
  • packages/orm/src/client/crud/operations/create.ts
  • packages/orm/src/client/crud/operations/delete.ts
  • packages/orm/src/client/crud/operations/exists.ts
  • packages/orm/src/client/crud/operations/find.ts
  • packages/orm/src/client/crud/operations/group-by.ts
  • packages/orm/src/client/crud/operations/update.ts
  • packages/orm/src/client/crud/validator/validator.ts
  • packages/orm/src/client/executor/name-mapper.ts
  • packages/orm/src/client/executor/zenstack-query-executor.ts
  • packages/orm/src/client/helpers/schema-db-pusher.ts
  • packages/orm/src/client/index.ts
  • packages/orm/src/client/options.ts
  • packages/orm/src/client/plugin.ts
  • packages/orm/src/client/promise.ts
  • packages/orm/src/client/query-builder.ts
  • packages/orm/src/client/query-utils.ts
  • packages/orm/src/client/result-processor.ts
  • packages/orm/src/client/zod/factory.ts
  • packages/orm/src/client/zod/index.ts
  • packages/orm/src/common-types.ts
  • packages/orm/src/utils/schema-utils.ts
  • packages/orm/tsdown.config.ts
  • packages/plugins/policy/package.json
  • packages/plugins/policy/tsdown.config.ts
  • packages/plugins/policy/tsup.config.ts
  • packages/schema/package.json
  • packages/schema/tsdown.config.ts
  • packages/schema/tsup.config.ts
  • packages/sdk/package.json
  • packages/sdk/src/ts-schema-generator.ts
  • packages/sdk/tsconfig.json
  • packages/sdk/tsdown.config.ts
  • packages/sdk/tsup.config.ts
  • packages/server/package.json
  • packages/server/src/api/common/spec-utils.ts
  • packages/server/src/api/rest/openapi.ts
  • packages/server/src/api/rpc/index.ts
  • packages/server/src/api/rpc/openapi.ts
  • packages/server/test/openapi/baseline/rpc.baseline.yaml
  • packages/server/test/openapi/rest-openapi.test.ts
  • packages/server/test/openapi/rpc-openapi.test.ts
  • packages/server/tsdown.config.ts
  • packages/testtools/package.json
  • packages/testtools/tsdown.config.ts
  • packages/testtools/tsup.config.ts
  • packages/zod/package.json
  • packages/zod/src/factory.ts
  • packages/zod/src/types.ts
  • packages/zod/src/utils.ts
  • packages/zod/test/factory.test.ts
  • packages/zod/tsdown.config.ts
  • packages/zod/tsup.config.ts
  • pnpm-workspace.yaml
  • samples/orm/package.json
  • samples/orm/zenstack/schema.zmodel
  • scripts/test-generate.ts
  • tests/e2e/orm/client-api/mixin.test.ts
  • tests/e2e/orm/client-api/timezone/mysql-timezone.test.ts
  • tests/e2e/orm/client-api/timezone/pg-timezone.test.ts
  • tests/e2e/orm/client-api/zod.test.ts
  • tests/e2e/package.json
  • tests/regression/package.json
  • tests/regression/test/issue-2540.test.ts
  • tests/regression/test/issue-2550/regression.test.ts
  • tests/regression/test/issue-2550/schema.ts
  • tests/regression/test/issue-2550/schema.zmodel
  • tests/regression/test/issue-2578.test.ts
  • tests/regression/test/issue-2588.test.ts
  • tests/regression/test/issue-274/regression.test.ts
  • tests/runtimes/bun/package.json
  • tests/runtimes/edge-runtime/package.json
💤 Files with no reviewable changes (13)
  • packages/auth-adapters/better-auth/tsup.config.ts
  • packages/cli/tsup.config.ts
  • packages/clients/client-helpers/tsup.config.ts
  • packages/create-zenstack/tsup.config.ts
  • packages/ide/vscode/tsup.config.ts
  • packages/schema/tsup.config.ts
  • packages/plugins/policy/tsup.config.ts
  • packages/testtools/tsup.config.ts
  • packages/zod/tsup.config.ts
  • tests/e2e/orm/client-api/zod.test.ts
  • packages/language/tsup.config.ts
  • packages/sdk/tsup.config.ts
  • packages/common-helpers/tsup.config.ts

Comment thread package.json
Comment thread packages/language/scripts/patch-generated-ast.ts
Comment thread packages/orm/src/client/crud/dialects/mysql.ts
Comment thread packages/orm/src/client/zod/factory.ts Outdated
Comment thread packages/orm/src/common-types.ts
Comment thread packages/server/src/api/rpc/openapi.ts
Comment thread packages/server/src/api/rpc/openapi.ts
Comment thread tests/regression/test/issue-2550/regression.test.ts
ymc9 and others added 3 commits April 20, 2026 11:39
…I spec

- ZodSchemaFactory.toJSONSchema() now skips makeProcedureArgsSchema for
  procedures excluded by slicing (includedProcedures / excludedProcedures),
  preventing dangling component registrations for hidden procedures
- RPCApiSpecGenerator.generateSharedSchemas() now emits enum schemas so
  $ref pointers from model entity schemas and typedef schemas resolve correctly
- RPCApiSpecGenerator requestBody.required is now only set when at least one
  procedure param is non-optional, matching the existing GET q-param behavior
- Add tests covering all three fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 20, 2026

Claude finished @ymc9's task —— View job


Code Review for v3.6.0 Release (dev → main)

I've completed my comprehensive code review of this major release. Here are my findings:

Review Checklist:

  • Analyze build system migration (tsup → tsdown)
  • Review dependency updates and package.json changes
  • Check new configuration files
  • Assess code quality and best practices
  • Look for potential bugs or issues
  • Evaluate performance considerations
  • Check for security concerns
  • Review test coverage implications

🏗️ Build System Migration Analysis ✅

Positive Changes:

  • Standardized Build Config: The new @zenstackhq/tsdown-config package provides centralized, consistent build configuration
  • Multi-Entry Support: ORM package now supports multiple entry points for better tree-shaking (packages/orm/tsdown.config.ts:4-12)
  • Enhanced Export Maps: Comprehensive export maps for all dialects in ORM package (packages/orm/package.json:27-102)

📦 Dependency Updates & Package Changes ✅

Key Observations:

  • Breaking Change: CLI now requires Node 20+ (packages/cli/package.json:98) - ensure this is documented
  • Enhanced AST Processing: Language package includes new AST patching script (packages/language/scripts/patch-generated-ast.ts:1-31) for runtime field injection
  • Dependency Consistency: Proper use of workspace:* notation throughout

🔧 Code Quality & Best Practices ✅

Strengths:

  • Type Safety: Strong TypeScript usage with comprehensive type definitions in packages/orm/src/client/options.ts
  • Validation Architecture: Robust input validation system with proper error handling (packages/language/src/validators/datamodel-validator.ts:200-210)
  • Clean Abstractions: Well-structured dialect system for database-specific handling (packages/orm/src/client/crud/dialects/postgresql.ts:20-50)

🐛 Potential Issues & Bugs ⚠️

Concerns:

  1. Node Version Breaking Change: The Node 20+ requirement should be prominently documented in migration guides
  2. AST Patching: The post-generation AST patching approach (packages/language/scripts/patch-generated-ast.ts) is clever but fragile - consider more robust alternatives
  3. Large-Scale Migration: 100+ files changed - ensure comprehensive testing across all supported environments

🚀 Performance Considerations ✅

Positive Features:

  • Query Diagnostics: New slow query monitoring capabilities (packages/orm/src/client/options.ts:222-233)
  • Tree-Shaking: Improved with multi-entry build system and better export maps
  • Zod Schema Optimization: Enhanced schema generation with better field ordering preservation (packages/orm/src/client/zod/factory.ts:397-409)

🔒 Security Assessment ✅

Security Posture:

  • Input Validation: Comprehensive validation system remains intact with configurable options (packages/orm/src/client/options.ts:197-203)
  • SQL Injection Prevention: Kysely-based query building provides protection through parameterized queries
  • Type Safety: Strong TypeScript typing prevents many classes of runtime errors

No Critical Security Issues Identified

🧪 Test Coverage Implications ✅

Test Strategy:

  • Mixin System: Enhanced test coverage for type mixins (packages/language/test/mixin.test.ts:92-104)
  • Regression Testing: Comprehensive regression test suite remains intact
  • Breaking Changes: Tests should cover the documented breaking changes in BREAKINGCHANGES.md

📋 Final Recommendations

✅ Approve with Notes:

  1. Document Breaking Changes: Ensure Node 20+ requirement is clearly communicated
  2. Migration Testing: Run comprehensive tests across all supported databases and Node versions
  3. Monitor AST Patching: Consider more robust alternatives to string replacement in future releases

Summary: This is a well-executed major release with significant architectural improvements. The build system migration is clean, type safety is maintained, and no critical security issues were identified. The main concern is ensuring proper documentation of breaking changes, particularly the Node version requirement.


Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/server/src/api/rpc/openapi.ts`:
- Around line 720-727: The unknown-type fallback in buildModelEntitySchema
currently creates a typed SchemaObject and blindly marks the field as required;
update that block to respect fieldDef.optional by wrapping the typed schema with
an anyOf including { type: 'null' } when fieldDef.optional is true (i.e.,
produce either typed or nullable typed), and keep the same
required.push(fieldName) behavior as the other branches so the field is emitted
as required-but-nullable consistent with scalar/enum/typedef handling; modify
the logic around variables typed, properties[fieldName], and
required.push(fieldName) accordingly.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fcf5367d-41d8-4315-8598-51330481a6fa

📥 Commits

Reviewing files that changed from the base of the PR and between 3398c87 and 31f4c49.

📒 Files selected for processing (4)
  • packages/orm/src/client/zod/factory.ts
  • packages/server/src/api/rpc/openapi.ts
  • packages/server/test/openapi/baseline/rpc.baseline.yaml
  • packages/server/test/openapi/rpc-openapi.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/orm/src/client/zod/factory.ts

Comment thread packages/server/src/api/rpc/openapi.ts
@ymc9 ymc9 merged commit 03f6dfa into main Apr 20, 2026
12 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.

8 participants