-
-
Notifications
You must be signed in to change notification settings - Fork 11
merge dev to main #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* chore: set up turborepo * fix build * fix * update lock file
* feat: make plugins compatible with prisma client extensions * chore: bump version, fix lint * update
* fix: incorrect computed field typing for optional fields fixes #33 * fix tests
* chore: remove unused spaces * chore(sdk): move libraries from v2 * chore: remove some libraries, use local-helpers from sdk --------- Co-authored-by: Yiming Cao <yiming@whimslab.io>
* chore: remove unused spaces * chore(sdk): move libraries from v2 * chore: remove some libraries, use local-helpers from sdk * fix: PR merge issues * update * update * update * update --------- Co-authored-by: FTB_lag <tabolskyy.git@gmail.com>
* chore: add script for bumping version * update lock file * update packages
WalkthroughThis update introduces a comprehensive refactor and enhancement across the codebase. It adds new utility packages, restructures ESLint and TypeScript configurations, updates build and test workflows, and reformats code for consistency. Major improvements are made to the runtime client contract, plugin system, and CRUD operation typings, with expanded documentation, new scripts, and enhanced package management for better modularity and maintainability. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Client
participant Plugin
participant DB
User->>Client: Call Model CRUD Operation (e.g., create, findMany)
Client->>Plugin: (If present) Run onQuery hooks per model/operation
Plugin-->>Client: Optionally intercept/modify query
Client->>DB: Execute query (possibly via plugin chain)
DB-->>Client: Return result
Client-->>User: Return processed result
sequenceDiagram
participant Dev
participant GitHub Actions
Dev->>GitHub Actions: Trigger "Bump Version" workflow (manual)
GitHub Actions->>Repo: Checkout dev branch
GitHub Actions->>Node: Setup Node.js and pnpm
GitHub Actions->>Repo: Install dependencies
GitHub Actions->>Repo: Run custom bump-version script
GitHub Actions->>Repo: Create PR with version bump
Possibly related PRs
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
packages/cli/eslint.config.jsOops! Something went wrong! :( ESLint: 9.29.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by packages/cli/src/actions/db.tsOops! Something went wrong! :( ESLint: 9.29.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by packages/cli/src/actions/action-utils.tsOops! Something went wrong! :( ESLint: 9.29.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
🔭 Outside diff range comments (11)
packages/language/src/validators/function-invocation-validator.ts (1)
106-127: Validate both missing and extra arguments & point diagnostics to the right node
validateArgscorrectly flags missing parameters, but:
- The diagnostic is associated with
funcDecl, not the offendingparam, making the error highlight less helpful.- Extra arguments are silently ignored (see the TODO). This can hide bugs in author-supplied code.
- accept('error', `missing argument for parameter "${param.name}"`, { node: funcDecl }); + accept('error', `missing argument for parameter "${param.name}"`, { node: param }); @@ - // TODO: do we need to complain for extra arguments? - return success; + if (args.length > funcDecl.params.length) { + accept( + 'error', + 'too many arguments supplied to function', + { node: args[funcDecl.params.length] } + ); + success = false; + } + return success;This keeps authors honest about a function’s arity and produces focused diagnostics.
packages/cli/src/actions/db.ts (1)
23-35: Guard against shell‐injection & quoting issues in runPush
runPushinpackages/cli/src/actions/db.tsbuilds a single command string that’s passed directly intoexecPackage(which useschild_process.execSync). IfprismaSchemaFilecontains spaces, quotes or shell metacharacters, the command will break or—worse—open injection vectors.Recommendations:
• Properly quote/escape the schema path before interpolation:
function quoteArg(arg: string): string { return `'${arg.replace(/'/g, `'\\"'`)}'`; } const cmd = `prisma db push --schema ${quoteArg(prismaSchemaFile)}${ options.acceptDataLoss ? ' --accept-data-loss' : '' }${options.forceReset ? ' --force-reset' : ''} --skip-generate`;• Better: refactor
execPackageto acceptargs: string[]and usechild_process.spawnSync(orexecFileSync) instead ofexecSync(command). For example:// exec-utils.ts export function execPackage( bin: string, args: string[], options?: SpawnSyncOptions, ) { return spawnSync(bin, args, { stdio: 'inherit', ...options }); } // db.ts await execPackage( process.versions.bun ? 'bunx' : 'npx', [ 'prisma', 'db', 'push', '--schema', prismaSchemaFile, ...(options.acceptDataLoss ? ['--accept-data-loss'] : []), ...(options.forceReset ? ['--force-reset'] : []), '--skip-generate', ], );• Audit and apply the same fix in
packages/cli/src/actions/migrate.ts, where identical patterns exist.packages/language/src/ast.ts (1)
70-76: Remove the duplicatedInheritableNodedeclarationThe interface is declared twice back-to-back with identical content. Although TypeScript will merge them, it’s redundant noise.
-export interface InheritableNode extends AstNode { - $inheritedFrom?: DataModel; -}packages/runtime/src/client/crud/operations/aggregate.ts (1)
70-82: Precision loss for Decimal_avg/_sumresults
parseFloatconverts high-precision decimals to IEEE-754, losing accuracy.
When the Prisma schema field isDecimal, return aDecimalinstance instead.- .with('Decimal', () => parseFloat(value)) + .with('Decimal', () => new Decimal(value))packages/runtime/src/client/crud/operations/delete.ts (1)
15-26: Deletion & read should be wrapped in a single transaction
existingis read first and then the actualDELETEis executed outside of the same DB transaction. A concurrent delete between the two calls can lead to a race where:
existingis found and returned.- Another session deletes the row.
this.deletereturnscount === 0, causing a secondNotFoundError, which masks the real concurrency issue.Wrapping the read + delete in a single transaction (or using
DELETE … RETURNING *) removes the race completely and saves one round‐trip.-const existing = await this.readUnique(this.kysely, this.model, { ... }); -... -const result = await this.delete(this.kysely, this.model, args.where, undefined, false); +const existing = await this.safeTransaction(async (tx) => { + const row = await this.readUnique(tx, this.model, { ... }); + if (!row) throw new NotFoundError(this.model); + const { count } = await this.delete(tx, this.model, args.where, undefined, false); + if (count === 0) throw new NotFoundError(this.model); + return row; +});packages/cli/src/actions/generate.ts (1)
50-63: Harden dynamic plugin loading
await import(useProvider)will throw an unhandled exception if the module is missing or has no default export, aborting the whole generation pipeline.- const generator = (await import(useProvider)).default as CliGenerator; - console.log('Running generator:', provider); - await generator({ model, outputPath, tsSchemaFile }); + let mod: unknown; + try { + mod = await import(useProvider); + } catch (e) { + throw new Error(`Failed to load generator "${provider}": ${String(e)}`); + } + + const generator = (mod as { default?: unknown }).default; + invariant(typeof generator === 'function', `Generator "${provider}" does not export a default function`); + + console.log('Running generator:', provider); + await (generator as CliGenerator)({ model, outputPath, tsSchemaFile });Provides clearer error messages and guards against incorrect plugin shapes.
packages/language/src/utils.ts (1)
464-474:require.resolvewill explode under ESM – usecreateRequire
requireis undefined when the package is published as pure ESM.
Consider delegating toimport.meta.resolve(Node ≥20) or create a scopedrequire:- const resolvedPath = require.resolve(name, { paths: [cwd] }); + /* eslint-disable @typescript-eslint/no-var-requires */ + const { createRequire } = await import('node:module'); + const resolvedPath = createRequire(import.meta.url).resolve(name, { paths: [cwd] });This keeps the function working regardless of the module system.
packages/language/src/zmodel-linker.ts (1)
270-278:resolveArrayinfers element type from index 0 onlyIf an array literal mixes element types (
[1, 'two']) the resolver silently assigns the first element’s type to the whole array. This may hide errors that should be surfaced during validation.Consider detecting heterogeneous arrays:
- if (node.items.length > 0) { - const itemType = node.items[0]!.$resolvedType; - if (itemType?.decl) { - this.resolveToBuiltinTypeOrDecl(node, itemType.decl, true); - } - } else { + if (node.items.length === 0) { this.resolveToBuiltinTypeOrDecl(node, 'Any', true); + return; + } + + const first = node.items[0]!.$resolvedType; + const homogeneous = node.items.every( + (it) => it.$resolvedType?.decl === first?.decl && it.$resolvedType?.array === first?.array, + ); + if (!homogeneous) { + // Mark as error – validation pass can surface it + this.resolveToBuiltinTypeOrDecl(node, 'Any', true); + } else if (first?.decl) { + this.resolveToBuiltinTypeOrDecl(node, first.decl, true); }packages/runtime/src/client/crud/dialects/postgresql.ts (1)
289-295: Possible SQL-injection / escaping bug inbuildArrayLiteralSQLString elements are embedded directly into the SQL string with template-interpolation:
return `ARRAY[${values.map((v) => (typeof v === 'string' ? `'${v}'` : v))}]`;If
vcontains a single quote or backslash the generated SQL becomes invalid or exploitable.
Prefer parameterised builders or at leastpg-format-style escaping.-import { sql } from 'kysely'; +import { sql } from 'kysely'; ... -return `ARRAY[${values.map((v) => (typeof v === 'string' ? `'${v}'` : v))}]`; +return sql`ARRAY[${sql.join(values.map((v) => sql`${v}`))}]`.toOperationNode().toString();(or expose a helper in the dialect that safely serialises each element).
packages/runtime/src/client/crud/operations/base.ts (1)
432-440: Performance: Avoid spread syntax in reduce accumulators.The spread syntax in
.reduce()creates a new object on each iteration, resulting in O(n²) time complexity. Consider using direct property assignment instead.Apply this pattern to fix the performance issues:
- .set( - keyPairs.reduce( - (acc, { fk, pk }) => ({ - ...acc, - [fk]: entity[pk], - }), - {} as any, - ), - ) + .set( + keyPairs.reduce( + (acc, { fk, pk }) => { + acc[fk] = entity[pk]; + return acc; + }, + {} as any, + ), + )This applies to all similar occurrences in the file at lines 434-438, 1383-1387, 1422-1425, 1545, 1560, 1565, 1627-1629, 1644, and 1661-1663.
Also applies to: 1381-1389, 1420-1427, 1545-1545, 1560-1560, 1565-1565, 1625-1631, 1644-1644, 1659-1666
packages/runtime/src/plugins/policy/policy-handler.ts (1)
86-109: Read-back policy violations are surfaced after the transaction commits
readBackErroris populated inside the transaction callback, but the thrownRejectedByPolicyErrorhappens after the callback has resolved.
With both Kysely and most SQL drivers, a callback’s successful resolution commits the transaction.
Consequently, if the read-back check fails the mutation is still persisted even though the client receives an error – an integrity/UX nightmare.- const result = await transaction(async (txProceed) => { + const result = await transaction(async (txProceed) => { … if (!this.onlyReturningId(node)) { const readBackResult = await this.processReadBack(node, result, txProceed); if (readBackResult.rows.length !== result.rows.length) { - readBackError = true; + // abort the tx immediately + throw new RejectedByPolicyError(mutationModel, 'result is not allowed to be read back'); } return readBackResult; } else { return result; } }); - - if (readBackError) { - throw new RejectedByPolicyError(mutationModel, 'result is not allowed to be read back'); - }Throwing inside the callback guarantees an automatic rollback.
If a rollback is not desired, please clarify the intent and add a compensating mechanism.
♻️ Duplicate comments (2)
packages/create-zenstack/tsconfig.json (1)
2-2: Same note as above – confirm resolver can find the shared configNothing else to flag here.
Marking as duplicate of the previous remark.packages/language/tsconfig.json (1)
2-2: Extends path change – see earlier commentThe comment on ensuring the shared config package is reachable applies here as well.
🧹 Nitpick comments (40)
packages/language/src/constants.ts (1)
16-16: Consider adding a trailing comma andas constfor safer, cleaner maintenanceTrailing commas make diffs cleaner when new scalars are appended, and
as constpreserves literal types:-export const SCALAR_TYPES = ['String', 'Int', 'Float', 'Decimal', 'BigInt', 'Boolean', 'Bytes', 'DateTime']; +export const SCALAR_TYPES = [ + 'String', + 'Int', + 'Float', + 'Decimal', + 'BigInt', + 'Boolean', + 'Bytes', + 'DateTime', +] as const;packages/language/src/validators/typedef-validator.ts (1)
24-26: Minor naming nitpick
attris perfectly valid, but a more specific name (e.g.fieldAttr) would avoid overload with otherattrvariables in nearby scopes and aid quick grepping.packages/language/src/validators/attribute-validator.ts (1)
11-12: Shadowed parameter may impair readabilityThe inner arrow parameter
attrshadows the outer method parameterattr. Consider renaming the inner one:-attr.attributes.forEach((attr) => validateAttributeApplication(attr, accept)); +attr.attributes.forEach((childAttr) => validateAttributeApplication(childAttr, accept));packages/language/src/validators/enum-validator.ts (1)
19-24: Consistent namingSame shadowing pattern as in
AttributeValidator. Renaming the arrow arg (e.g.enumAttr/fieldAttr) would improve clarity.packages/ide/vscode/README.md (2)
9-33: Fix markdown list indentation to satisfy MD007Current four-space indentation trips markdownlint. Two spaces is the conventional level for nested lists:
- - In case the schema file is not recognized automatically, add the following to your settings.json file: + - In case the schema file is not recognized automatically, add the following to your settings.json file: ... - - To automatically format on save, add the following to your settings.json file: + - To automatically format on save, add the following to your settings.json file: ... - - To enable formatting in combination with prettier, add the following to your settings.json file: + - To enable formatting in combination with prettier, add the following to your settings.json file:This satisfies
markdownlint(MD007) and keeps the list structure intact.
41-45: Optional: alphabetise external linksPutting the links in alpha order (
Blog,Community chat,Documentation,Home,packages/language/src/validators/datasource-validator.ts (2)
57-61: Minor readability gain; consider extracting ‘env’ check.Current predicate is fine, but a helper like
isEnvCall(value)could improve reuse across validators.
70-71: Hard-coded literals: candidate for enum/const.
'foreignKeys' | 'prisma'appears in multiple places; elevating toconst ALLOWED_RELATION_MODESavoids drift.packages/language/src/validators/function-invocation-validator.ts (1)
88-96: Reuse immutable data instead of reallocating it
allCasingis recreated on every validation run, even though its value never changes. Hoist it once at module scope:- const allCasing = ['original', 'upper', 'lower', 'capitalize', 'uncapitalize']; +const ALL_CASING = ['original', 'upper', 'lower', 'capitalize', 'uncapitalize'] as const; ... - const arg = getLiteral<string>(expr.args[0]?.value); - if (arg && !allCasing.includes(arg)) { + const arg = getLiteral<string>(expr.args[0]?.value); + if (arg && !ALL_CASING.includes(arg)) {Saves a tiny amount of work in large ASTs and communicates intent (constant set).
packages/common-helpers/tsconfig.json (1)
1-7: Good first cut – consider emitting declaration mapsSince this package will likely be consumed by many others, adding
"declarationMap": trueunder
compilerOptionsimproves DX when debugging into the helpers.packages/common-helpers/src/sleep.ts (1)
1-5: Add explicit return type & optional abort-signal
sleepis tiny but widely reused; a couple of small improvements increase safety:
- Declare the return type explicitly for stronger typing.
- Accept an optional
AbortSignalso callers can cancel the delay (handy in tests and long-running tasks).-export function sleep(timeout: number) { - return new Promise<void>((resolve) => { - setTimeout(() => resolve(), timeout); - }); +export function sleep(timeout: number, signal?: AbortSignal): Promise<void> { + return new Promise<void>((resolve, reject) => { + if (signal?.aborted) { + return reject(new DOMException('Aborted', 'AbortError')); + } + const timer = setTimeout(resolve, timeout); + signal?.addEventListener( + 'abort', + () => { + clearTimeout(timer); + reject(new DOMException('Aborted', 'AbortError')); + }, + { once: true } + ); + }); }If the extra complexity isn’t necessary right now, at minimum add
: Promise<void>to the signature..github/workflows/build-test.yml (2)
17-22: Pin the Postgres image version
image: postgrespulls the latest tag on every run, which can introduce breaking changes overnight.
Recommend pinning to an explicit major/minor version (e.g.postgres:15-alpine) to keep CI deterministic.- image: postgres + image: postgres:15-alpine
30-34: Consider adding the current LTS Node release to the matrixOnly testing
20.xskips the active LTS (18.x) that many users still rely on.
Expanding the matrix costs little thanks to caching and guards against unexpected breakage.- node-version: [20.x] + node-version: [18.x, 20.x]packages/runtime/src/plugins/policy/errors.ts (1)
5-10: Minor clarity tweak: usethis.modelinside the messageUsing the parameter shadow (
model) works, but referencing the property makes the intent clearer after the parameter is assigned.- super(reason ?? `Operation rejected by policy${model ? ': ' + model : ''}`); + super(reason ?? `Operation rejected by policy${this.model ? ': ' + this.model : ''}`);packages/language/src/ast.ts (1)
21-38: Optional: tighten the operator-priority map typingUsing the new TS5
satisfiesoperator (plusas const) preserves literal keys and prevents drift without widening the type:-export const BinaryExprOperatorPriority: Record<BinaryExpr['operator'], number> = { +export const BinaryExprOperatorPriority satisfies Record<BinaryExpr['operator'], number> = { /* … */ -}; +} as const;packages/runtime/eslint.config.js (1)
5-9: Confirm rule override necessityDisabling
@typescript-eslint/no-unused-expressionsis common for chai/should style assertions.
Double-check that it’s really required; if not, consider keeping the rule on and adding selective// eslint-disable-next-linecomments where necessary to avoid masking genuine issues.packages/ide/vscode/src/extension/main.ts (1)
49-51: Avoid shadowing the outerclientvariableInside
startLanguageClientaconst clientshadows the module-levellet client.
Renaming prevents cognitive overhead and accidental misuse.- const client = new LanguageClient('zmodel', 'ZModel', serverOptions, clientOptions); + const languageClient = new LanguageClient('zmodel', 'ZModel', serverOptions, clientOptions); ... - client.start(); - return client; + languageClient.start(); + return languageClient;packages/runtime/src/client/result-processor.ts (2)
99-104: Invariant message can mislead – Decimal is filtered out alreadyThe
instanceof Decimalguard above guarantees theinvariantblock never receives aDecimal, yet the error talks about it.
Trim the message to avoid confusion and shorten the critical path:-invariant( - typeof value === 'string' || typeof value === 'number' || value instanceof Decimal, - `Expected string, number or Decimal, got ${typeof value}`, -); +invariant( + typeof value === 'string' || typeof value === 'number', + `Expected string or number, got ${typeof value}`, +);
135-140: Micro-opt: early-exit beforereversetraversalYou already calculate the need to reverse. Re-ordering the checks avoids the cost of
Array.isArrayon non-arrays and short-circuits faster:-if (Array.isArray(data) && typeof args === 'object' && args && args.take !== undefined && args.take < 0) { +if (typeof args === 'object' && args?.take !== undefined && args.take < 0 && Array.isArray(data)) { data.reverse(); }packages/common-helpers/tsup.config.ts (1)
3-13: Consider enabling minification for published bundles
tsup’s default leaves code un-minified. For helpers that ship to npm,minify: true(and maybetarget: 'es2019') trims bundle size without affecting DX.dts: true, - format: ['cjs', 'esm'], + format: ['cjs', 'esm'], + minify: true,packages/runtime/src/client/crud/operations/find.ts (1)
18-21: Minor: avoid double allocation for single-row queriesFor
findUnique/findFirstwe read the whole array just to keep[0].
A tiny tweak in the reader to requesttake 1and skip array wrapping would save allocations, but it’s purely micro-perf – feel free to ignore..vscode/tasks.json (2)
19-30: Background task lacksisBackground& problem-matcher
turbo watch buildnever exits, so VSCode treats the task as hanging unlessisBackground: trueand a simple problem-matcher are provided.
Sample patch:"type": "shell", +"isBackground": true, "group": { "kind": "build" }, "problemMatcher": "$tsc-watch"
31-41:Lint alltask could surface diagnostics inlineAttaching the default ESLint matcher lets VSCode underline issues without running the separate Problems panel.
-"problemMatcher": [] +"problemMatcher": ["$eslint-stylish"]packages/runtime/src/client/crud/operations/delete.ts (1)
32-34: Optional: remove the| undefinedin the argument type
validateDeleteManyArgsalways returns a defined object (empty object when no args are provided). ThereforerunDeleteManynever receivesundefined. Narrowing the type simplifies downstream null-checks.-async runDeleteMany(args: DeleteManyArgs<Schema, Extract<keyof Schema['models'], string>> | undefined) { +async runDeleteMany(args: DeleteManyArgs<Schema, Extract<keyof Schema['models'], string>>) {packages/cli/src/utils/version-utils.ts (1)
10-12: Consider logging the error for debugging purposes.While the simplified error handling works, consider logging the actual error to help with debugging in development environments.
} catch { - return undefined; + return undefined; }You could optionally log the error:
- } catch { + } catch (error) { + // Optional: log error in development + if (process.env.NODE_ENV === 'development') { + console.warn('Failed to read package.json version:', error); + } return undefined; }packages/runtime/src/client/query-utils.ts (2)
160-166: Replace bannedFunctiontype with explicit signature
Functionis too permissive and flagged by Biome. Narrow the type to the expected callable shape.- let computer: Function | undefined; + let computer: ((eb: ExpressionBuilder<any, any>) => unknown) | undefined;
205-208: Guard against missing ID fields
getIdFieldsmay returnundefined;mapwill then crash.
Either reuserequireIdFieldsor add an explicit check.- const idFields = getIdFields(schema, model); - return idFields.map((f) => ({ [f]: 'asc' }) as OrderBy<Schema, GetModels<Schema>, true, false>); + const idFields = requireIdFields(schema, model); + return idFields.map((f) => ({ [f]: 'asc' }) as OrderBy<Schema, GetModels<Schema>, true, false>);packages/runtime/src/plugins/policy/expression-evaluator.ts (1)
40-46: Unsupported call paths throw genericErrorConsider throwing a domain-specific error (
QueryErroror custom) to keep error handling consistent across the runtime.packages/runtime/src/client/executor/zenstack-driver.ts (1)
181-186: Time precision fallback may skew latency metrics
Date.now()only has millisecond precision whereasperformance.now()provides sub-ms. If high-resolution timing is critical, consider importingperf_hooks’sperformancepolyfill when running under Node:export function performanceNow() { - if (typeof performance !== 'undefined' && typeof performance.now === 'function') { - return performance.now(); - } else { - return Date.now(); - } + if (typeof performance !== 'undefined' && typeof performance.now === 'function') + return performance.now(); + return (await import('node:perf_hooks')).performance.timeOrigin + ? (await import('node:perf_hooks')).performance.now() + : Date.now(); }Optional, depending on accuracy requirements.
packages/language/src/utils.ts (2)
64-67:isFromStdlibis case-sensitive – may mis-detect on Windows / macOS
model.$document.uri.path.endsWith(STD_LIB_MODULE_NAME)will fail if the file-system is case-insensitive and the path casing differs (e.g.stdlib.zmodelvsSTD_LIB.zmodel).
A small normalisation avoids surprising false negatives:- return !!model && !!model.$document && model.$document.uri.path.endsWith(STD_LIB_MODULE_NAME); + return ( + !!model && + !!model.$document && + model.$document.uri.path.toLowerCase().endsWith(STD_LIB_MODULE_NAME.toLowerCase()) + );
59-61: Guard against nodes that don’t carryattributes
getAttributeunconditionally castsdecltoDataModelAttribute | DataModelFieldAttributeand then accesses.attributes.
If the helper is (mis)used on a declaration that does not own anattributesarray this will throw at runtime. A cheap type-guard prevents accidental crashes:- return (decl.attributes as (DataModelAttribute | DataModelFieldAttribute)[]).find( + if (!('attributes' in decl)) return undefined; + return (decl.attributes as (DataModelAttribute | DataModelFieldAttribute)[]).find(packages/language/src/validators/datamodel-validator.ts (1)
60-62: Grammar nit: “criterion” vs “criteria”
"Model must have at least one unique criteria"– “criteria” is plural; here you’re referring to a single requirement.- 'Model must have at least one unique criteria. Either mark a single field with `@id`, `@unique` or add a multi field criterion with `@@id([])` or `@@unique([])` to the model.', + 'Model must have at least one unique criterion. Either mark a single field with `@id`, `@unique`, or add a multi-field criterion with `@@id([])` or `@@unique([])`.',packages/language/src/validators/attribute-application-validator.ts (1)
342-345: Redundant comparison againstdstType === 'Any'Inside the final
elsebranchdstTypeis guaranteed to beundefined, sodstType === 'Any'is always
falseand can be removed to reduce cognitive load:- return (dstRef?.ref === argResolvedType.decl || dstType === 'Any') && dstIsArray === argResolvedType.array; + return dstRef?.ref === argResolvedType.decl && dstIsArray === argResolvedType.array;README.md (1)
27-34: Bullet markers removed – Markdown list is now plain textThe leading dashes were dropped, so GitHub no longer renders a bullet list. If that was unintentional, restore the markers:
- A modern schema-first ORM ... + - A modern schema-first ORM ...Same applies to the later “Writing ZModel schema” and “Database migration” sections.
packages/runtime/src/plugins/policy/expression-transformer.ts (1)
102-107: Numeric literals are always coerced toInt– widen mapping
_literalmaps every non-string/boolean literal to'Int'.
This silently mis-types floats, bigints, decimals, etc., which will later reach the dialect layer with the wrong Prisma/ZenStack built-in type.- typeof expr.value === 'string' ? 'String' : typeof expr.value === 'boolean' ? 'Boolean' : 'Int', + typeof expr.value === 'string' + ? 'String' + : typeof expr.value === 'boolean' + ? 'Boolean' + : Number.isInteger(expr.value) + ? 'Int' + : 'Float',(You could further refine for
bigint,Decimal, etc.)
Leaving it as-is risks precision loss and wrong query plans when the DB column is non-integer.packages/runtime/src/client/crud/dialects/postgresql.ts (1)
197-205: Minor: replaceflatMap(...=>v)with plainflat()Both locations build an array of tuples and immediately flatten it:
...map(...).flatMap((v) => v)Using
flat()is clearer and avoids an unnecessary callback.- .map(/* ... */).flatMap((v) => v) + .map(/* ... */).flat()Also applies to: 222-225
packages/language/src/zmodel-workspace-manager.ts (1)
48-52: Use a logger instead ofconsole.loginside library codeRaw
console.logcalls pollute user terminals and cannot be silenced/redirected easily.
Consider injecting a logger or using VS Code’s output channel so consumers can control verbosity.packages/runtime/src/client/client-impl.ts (1)
271-291: Enhanced plugin architecture looks good.The nested plugin hook structure with model and operation-specific handlers provides better granularity. The case-insensitive model matching and wildcard support ($allModels, $allOperations) are useful additions.
Would you like me to generate documentation or examples for the new plugin hook structure to help developers understand how to use these enhanced capabilities?
packages/runtime/src/plugins/policy/policy-handler.ts (1)
178-205: Possible SQL-injection when serialising array literals
unwrapCreateValueRowinjects user-provided arrays viaRawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)).
UnlessbuildArrayLiteralSQLfully escapes every element, malicious content could reach the DB un-parametrised.Consider:
- node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)), + node: ValueNode.create( + this.dialect.transformPrimitive( + value, + fieldDef.type as BuiltinType, + ), + ),or add a dedicated, well-tested helper that returns a
ValueNode/bind parameter rather than raw SQL.packages/runtime/src/client/crud-types.ts (1)
895-901: Avoid banned{}type – replace with a shaped objectBiome flags the use of
{}(lines 898-900).
A safer, more precise alternative keeps the intent (object ≠true) while silencing the linter:-type AggCommonOutput<Input> = Input extends true - ? number - : Input extends {} +type AggCommonOutput<Input> = Input extends true + ? number + : Input extends Record<string, unknown> ? { [Key in keyof Input]: number; } : never;This keeps the conditional logic unchanged and eliminates the
noBannedTypeserror.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
packages/language/src/generated/ast.tsis excluded by!**/generated/**packages/language/src/generated/grammar.tsis excluded by!**/generated/**packages/language/src/generated/module.tsis excluded by!**/generated/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (107)
.eslintignore(0 hunks).eslintrc.json(0 hunks).github/workflows/build-test.yml(1 hunks).github/workflows/bump-version.yml(1 hunks).prettierrc(1 hunks).vscode/tasks.json(1 hunks)NEW-FEATURES.md(0 hunks)README.md(4 hunks)TODO.md(1 hunks)package.json(2 hunks)packages/cli/eslint.config.js(1 hunks)packages/cli/package.json(2 hunks)packages/cli/src/actions/action-utils.ts(2 hunks)packages/cli/src/actions/db.ts(1 hunks)packages/cli/src/actions/generate.ts(2 hunks)packages/cli/src/actions/info.ts(4 hunks)packages/cli/src/actions/init.ts(2 hunks)packages/cli/src/actions/migrate.ts(2 hunks)packages/cli/src/index.ts(3 hunks)packages/cli/src/utils/exec-utils.ts(2 hunks)packages/cli/src/utils/version-utils.ts(1 hunks)packages/cli/tsconfig.json(1 hunks)packages/common-helpers/eslint.config.js(1 hunks)packages/common-helpers/package.json(1 hunks)packages/common-helpers/src/index.ts(1 hunks)packages/common-helpers/src/is-plain-object.ts(1 hunks)packages/common-helpers/src/lower-case-first.ts(1 hunks)packages/common-helpers/src/param-case.ts(1 hunks)packages/common-helpers/src/sleep.ts(1 hunks)packages/common-helpers/src/tiny-invariant.ts(1 hunks)packages/common-helpers/src/upper-case-first.ts(1 hunks)packages/common-helpers/tsconfig.json(1 hunks)packages/common-helpers/tsup.config.ts(1 hunks)packages/create-zenstack/eslint.config.js(1 hunks)packages/create-zenstack/package.json(2 hunks)packages/create-zenstack/src/index.ts(3 hunks)packages/create-zenstack/tsconfig.json(1 hunks)packages/eslint-config/base.js(1 hunks)packages/eslint-config/package.json(1 hunks)packages/ide/vscode/README.md(1 hunks)packages/ide/vscode/eslint.config.mjs(1 hunks)packages/ide/vscode/package.json(1 hunks)packages/ide/vscode/src/extension/main.ts(3 hunks)packages/ide/vscode/src/language-server/main.ts(1 hunks)packages/ide/vscode/tsconfig.json(1 hunks)packages/language/eslint.config.js(1 hunks)packages/language/langium-quickstart.md(0 hunks)packages/language/package.json(2 hunks)packages/language/res/stdlib.zmodel(7 hunks)packages/language/src/ast.ts(2 hunks)packages/language/src/constants.ts(1 hunks)packages/language/src/index.ts(2 hunks)packages/language/src/module.ts(4 hunks)packages/language/src/utils.ts(24 hunks)packages/language/src/validator.ts(3 hunks)packages/language/src/validators/attribute-application-validator.ts(15 hunks)packages/language/src/validators/attribute-validator.ts(1 hunks)packages/language/src/validators/common.ts(2 hunks)packages/language/src/validators/datamodel-validator.ts(17 hunks)packages/language/src/validators/datasource-validator.ts(3 hunks)packages/language/src/validators/enum-validator.ts(1 hunks)packages/language/src/validators/expression-validator.ts(8 hunks)packages/language/src/validators/function-decl-validator.ts(1 hunks)packages/language/src/validators/function-invocation-validator.ts(13 hunks)packages/language/src/validators/schema-validator.ts(3 hunks)packages/language/src/validators/typedef-validator.ts(1 hunks)packages/language/src/zmodel-linker.ts(19 hunks)packages/language/src/zmodel-scope.ts(8 hunks)packages/language/src/zmodel-workspace-manager.ts(3 hunks)packages/language/src/zmodel.langium(3 hunks)packages/language/tsconfig.json(1 hunks)packages/runtime/eslint.config.js(1 hunks)packages/runtime/package.json(3 hunks)packages/runtime/src/client/client-impl.ts(17 hunks)packages/runtime/src/client/contract.ts(3 hunks)packages/runtime/src/client/crud-types.ts(34 hunks)packages/runtime/src/client/crud/dialects/base.ts(40 hunks)packages/runtime/src/client/crud/dialects/index.ts(1 hunks)packages/runtime/src/client/crud/dialects/postgresql.ts(15 hunks)packages/runtime/src/client/crud/dialects/sqlite.ts(11 hunks)packages/runtime/src/client/crud/operations/aggregate.ts(5 hunks)packages/runtime/src/client/crud/operations/base.ts(80 hunks)packages/runtime/src/client/crud/operations/count.ts(2 hunks)packages/runtime/src/client/crud/operations/create.ts(3 hunks)packages/runtime/src/client/crud/operations/delete.ts(2 hunks)packages/runtime/src/client/crud/operations/find.ts(1 hunks)packages/runtime/src/client/crud/operations/group-by.ts(5 hunks)packages/runtime/src/client/crud/operations/update.ts(3 hunks)packages/runtime/src/client/crud/validator.ts(46 hunks)packages/runtime/src/client/executor/name-mapper.ts(11 hunks)packages/runtime/src/client/executor/zenstack-driver.ts(8 hunks)packages/runtime/src/client/executor/zenstack-query-executor.ts(17 hunks)packages/runtime/src/client/functions.ts(11 hunks)packages/runtime/src/client/helpers/schema-db-pusher.ts(9 hunks)packages/runtime/src/client/index.ts(1 hunks)packages/runtime/src/client/options.ts(4 hunks)packages/runtime/src/client/plugin.ts(5 hunks)packages/runtime/src/client/promise.ts(1 hunks)packages/runtime/src/client/query-builder.ts(2 hunks)packages/runtime/src/client/query-utils.ts(12 hunks)packages/runtime/src/client/result-processor.ts(7 hunks)packages/runtime/src/plugins/policy/errors.ts(1 hunks)packages/runtime/src/plugins/policy/expression-evaluator.ts(5 hunks)packages/runtime/src/plugins/policy/expression-transformer.ts(20 hunks)packages/runtime/src/plugins/policy/plugin.ts(2 hunks)packages/runtime/src/plugins/policy/plugin.zmodel(2 hunks)packages/runtime/src/plugins/policy/policy-handler.ts(22 hunks)
⛔ Files not processed due to max files limit (18)
- packages/runtime/src/plugins/policy/utils.ts
- packages/runtime/src/schema/auth.ts
- packages/runtime/src/schema/expression.ts
- packages/runtime/src/utils/clone.ts
- packages/runtime/src/utils/default-operation-node-visitor.ts
- packages/runtime/src/utils/object-utils.ts
- packages/runtime/src/utils/type-utils.ts
- packages/runtime/test/client-api/aggregate.test.ts
- packages/runtime/test/client-api/client-specs.ts
- packages/runtime/test/client-api/compound-id.test.ts
- packages/runtime/test/client-api/computed-fields.test.ts
- packages/runtime/test/client-api/count.test.ts
- packages/runtime/test/client-api/create-many-and-return.test.ts
- packages/runtime/test/client-api/create-many.test.ts
- packages/runtime/test/client-api/create.test.ts
- packages/runtime/test/client-api/default-values.test.ts
- packages/runtime/test/client-api/delete-many.test.ts
- packages/runtime/test/client-api/delete.test.ts
💤 Files with no reviewable changes (4)
- NEW-FEATURES.md
- .eslintignore
- packages/language/langium-quickstart.md
- .eslintrc.json
🧰 Additional context used
🧬 Code Graph Analysis (34)
packages/language/src/validators/attribute-validator.ts (1)
packages/language/src/validators/attribute-application-validator.ts (1)
validateAttributeApplication(406-408)
packages/language/src/validators/enum-validator.ts (2)
packages/language/src/validators/attribute-application-validator.ts (1)
validateAttributeApplication(406-408)packages/language/src/generated/ast.ts (2)
EnumField(444-450)EnumField(452-452)
packages/language/src/ast.ts (1)
packages/language/src/generated/ast.ts (2)
BinaryExpr(264-270)BinaryExpr(272-272)
packages/language/src/validators/datasource-validator.ts (2)
packages/language/src/constants.ts (1)
SUPPORTED_PROVIDERS(4-11)packages/language/src/generated/ast.ts (1)
isInvocationExpr(550-552)
packages/cli/src/actions/init.ts (2)
packages/cli/src/cli-error.ts (1)
CliError(4-4)packages/cli/src/actions/templates.ts (1)
STARTER_ZMODEL(1-27)
packages/runtime/src/client/crud/dialects/index.ts (1)
packages/runtime/src/client/options.ts (1)
ClientOptions(30-65)
packages/language/src/validators/function-decl-validator.ts (3)
packages/language/src/validators/common.ts (1)
AstValidator(7-12)packages/language/src/generated/ast.ts (2)
FunctionDecl(471-479)FunctionDecl(481-481)packages/language/src/validators/attribute-application-validator.ts (1)
validateAttributeApplication(406-408)
packages/language/src/validators/common.ts (2)
packages/language/src/ast.ts (2)
AstNode(4-4)AstNode(79-84)packages/language/src/generated/ast.ts (1)
isDataModelField(383-385)
packages/language/src/validators/typedef-validator.ts (2)
packages/language/src/validators/attribute-application-validator.ts (1)
validateAttributeApplication(406-408)packages/language/src/generated/ast.ts (4)
TypeDef(733-740)TypeDef(742-742)TypeDefField(748-755)TypeDefField(757-757)
packages/runtime/src/plugins/policy/plugin.ts (2)
packages/sdk/src/schema/schema.ts (1)
SchemaDef(10-17)packages/runtime/src/client/plugin.ts (2)
RuntimePlugin(108-155)OnKyselyQueryArgs(94-101)
packages/runtime/src/client/result-processor.ts (1)
packages/sdk/src/schema/schema.ts (1)
GetModels(84-84)
packages/runtime/src/client/crud/operations/aggregate.ts (1)
packages/sdk/src/schema/schema.ts (1)
SchemaDef(10-17)
packages/runtime/src/client/executor/name-mapper.ts (3)
packages/runtime/src/client/errors.ts (1)
InternalError(7-11)packages/runtime/src/client/crud/operations/base.ts (1)
requireModel(109-111)packages/runtime/src/client/query-utils.ts (1)
requireModel(17-23)
packages/runtime/src/client/crud/operations/count.ts (1)
packages/sdk/src/schema/schema.ts (1)
SchemaDef(10-17)
packages/language/src/module.ts (1)
packages/language/src/generated/module.ts (2)
ZModelGeneratedSharedModule(17-19)ZModelGeneratedModule(21-25)
packages/runtime/src/client/crud/operations/find.ts (3)
packages/sdk/src/schema/schema.ts (2)
SchemaDef(10-17)GetModels(84-84)packages/runtime/src/client/crud/operations/base.ts (1)
CrudOperation(52-67)packages/runtime/src/client/crud-types.ts (1)
FindArgs(495-514)
packages/runtime/src/client/query-utils.ts (5)
packages/runtime/test/test-schema.ts (1)
schema(3-310)samples/blog/zenstack/schema.ts (1)
schema(9-166)packages/sdk/src/schema/schema.ts (2)
SchemaDef(10-17)GetModels(84-84)packages/runtime/src/client/errors.ts (2)
InternalError(7-11)QueryError(1-5)packages/runtime/src/client/crud-types.ts (1)
OrderBy(260-294)
packages/runtime/src/client/crud/operations/delete.ts (3)
packages/sdk/src/schema/schema.ts (1)
SchemaDef(10-17)packages/runtime/src/client/crud-types.ts (2)
DeleteArgs(786-791)DeleteManyArgs(793-796)packages/runtime/src/client/errors.ts (1)
NotFoundError(13-17)
packages/language/src/validators/expression-validator.ts (3)
packages/language/src/generated/ast.ts (7)
isEnum(440-442)isNullExpr(599-601)isThisExpr(729-731)BinaryExpr(264-270)BinaryExpr(272-272)isDataModelAttribute(368-370)isArrayExpr(201-203)packages/runtime/src/client/query-utils.ts (1)
isEnum(177-179)packages/language/src/utils.ts (3)
isDataModelFieldReference(142-144)typeAssignable(85-103)findUpAst(284-293)
packages/language/src/index.ts (1)
packages/language/src/constants.ts (1)
STD_LIB_MODULE_NAME(21-21)
packages/language/src/validators/datamodel-validator.ts (4)
packages/language/src/constants.ts (1)
SCALAR_TYPES(16-16)packages/language/src/generated/ast.ts (8)
isEnum(440-442)DataModelField(372-379)DataModelField(381-381)isStringLiteral(717-719)isDataModel(355-357)isTypeDef(744-746)DataModel(341-351)DataModel(353-353)packages/language/src/validators/attribute-application-validator.ts (1)
validateAttributeApplication(406-408)packages/language/src/utils.ts (4)
hasAttribute(54-56)getModelFieldsWithBases(184-190)findUpInheritance(171-182)isDelegateModel(157-159)
packages/cli/src/actions/generate.ts (2)
packages/language/src/generated/ast.ts (1)
isPlugin(636-638)packages/common-helpers/src/tiny-invariant.ts (1)
invariant(4-14)
packages/language/src/validators/attribute-application-validator.ts (3)
packages/language/src/generated/ast.ts (25)
DataModelAttribute(359-364)DataModelAttribute(366-366)DataModelFieldAttribute(387-392)DataModelFieldAttribute(394-394)InternalAttribute(528-533)InternalAttribute(535-535)isDataModelField(383-385)isTypeDefField(759-761)isTypeDef(744-746)AttributeParam(233-241)AttributeParam(243-243)isDataModel(355-357)DataModelField(372-379)DataModelField(381-381)AttributeArg(220-225)AttributeArg(227-227)isArrayExpr(201-203)isReferenceExpr(705-707)isEnum(440-442)Attribute(205-212)Attribute(214-214)ArrayExpr(193-197)ArrayExpr(199-199)ReferenceExpr(696-701)ReferenceExpr(703-703)packages/language/src/validators/common.ts (1)
AstValidator(7-12)packages/language/src/utils.ts (8)
hasAttribute(54-56)getStringLiteral(76-78)isFutureExpr(153-155)isDataModelFieldReference(142-144)isDelegateModel(157-159)resolved(161-166)mapBuiltinTypeToExpressionType(108-132)typeAssignable(85-103)
packages/runtime/src/client/query-builder.ts (2)
packages/sdk/src/schema/schema.ts (8)
SchemaDef(10-17)GetModels(84-84)ScalarFields(109-123)ForeignKeyFields(125-129)GetFields(92-95)GetFieldType(103-107)FieldIsOptional(151-155)FieldHasDefault(175-183)packages/runtime/src/utils/type-utils.ts (1)
MapBaseType(15-29)
packages/runtime/src/plugins/policy/expression-evaluator.ts (3)
packages/runtime/src/schema/expression.ts (1)
ExpressionUtils(16-112)packages/sdk/src/schema/expression.ts (6)
CallExpression(46-50)UnaryExpression(33-37)MemberExpression(27-31)FieldExpression(22-25)ArrayExpression(17-20)BinaryExpression(39-44)packages/common-helpers/src/tiny-invariant.ts (1)
invariant(4-14)
packages/language/src/zmodel-workspace-manager.ts (1)
packages/language/src/constants.ts (1)
STD_LIB_MODULE_NAME(21-21)
packages/runtime/src/client/crud/operations/group-by.ts (1)
packages/sdk/src/schema/schema.ts (1)
SchemaDef(10-17)
packages/language/src/validator.ts (8)
packages/language/src/generated/ast.ts (12)
Model(567-571)Model(573-573)DataSource(416-421)DataSource(423-423)DataModel(341-351)DataModel(353-353)Expression(115-115)Expression(117-117)InvocationExpr(541-546)InvocationExpr(548-548)FunctionDecl(471-479)FunctionDecl(481-481)packages/language/src/validators/schema-validator.ts (1)
SchemaValidator(10-58)packages/language/src/validators/datasource-validator.ts (1)
DataSourceValidator(10-74)packages/language/src/validators/datamodel-validator.ts (1)
DataModelValidator(32-464)packages/language/src/validators/attribute-validator.ts (1)
AttributeValidator(9-13)packages/language/src/validators/expression-validator.ts (1)
ExpressionValidator(30-262)packages/language/src/validators/function-invocation-validator.ts (1)
FunctionInvocationValidator(42-249)packages/language/src/validators/function-decl-validator.ts (1)
FunctionDeclValidator(9-13)
packages/language/src/validators/schema-validator.ts (3)
packages/language/src/generated/ast.ts (3)
Model(567-571)Model(573-573)isDataSource(425-427)packages/language/src/validators/common.ts (1)
validateDuplicatedDeclarations(17-43)packages/language/src/utils.ts (3)
resolveTransitiveImports(390-392)getAllDeclarationsIncludingImports(488-491)resolveImport(421-439)
packages/runtime/src/client/functions.ts (4)
packages/runtime/src/client/options.ts (2)
ZModelFunction(21-25)ZModelFunctionContext(15-19)packages/common-helpers/src/tiny-invariant.ts (1)
invariant(4-14)packages/common-helpers/src/upper-case-first.ts (1)
upperCaseFirst(1-3)packages/common-helpers/src/lower-case-first.ts (1)
lowerCaseFirst(1-3)
packages/runtime/src/client/plugin.ts (4)
packages/sdk/src/schema/schema.ts (2)
SchemaDef(10-17)GetModels(84-84)packages/runtime/src/client/contract.ts (2)
ClientContract(35-95)ModelOperations(146-698)packages/runtime/src/utils/type-utils.ts (1)
MaybePromise(64-64)packages/runtime/src/client/crud/operations/base.ts (1)
CrudOperation(52-67)
packages/runtime/src/client/crud-types.ts (5)
packages/sdk/src/schema/schema.ts (22)
SchemaDef(10-17)GetModels(84-84)NonRelationFields(131-133)RelationFields(135-137)RelationFieldType(145-149)FieldIsArray(163-167)FieldIsOptional(151-155)GetFieldType(103-107)GetEnums(88-88)BuiltinType(76-76)GetModel(86-86)FieldDef(54-66)GetFields(92-95)GetField(97-101)GetEnum(90-90)FieldHasDefault(175-183)FieldIsRelationArray(185-189)FieldType(139-143)RelationInfo(45-52)ScalarFields(109-123)ForeignKeyFields(125-129)FieldIsRelation(157-161)packages/language/src/generated/ast.ts (3)
Model(567-571)Model(573-573)BuiltinType(101-101)packages/sdk/src/prisma/prisma-builder.ts (1)
Model(115-164)packages/runtime/src/utils/type-utils.ts (8)
Optional(3-3)WrapType(9-13)OrArray(42-42)AtLeast(52-56)MapBaseType(15-29)XOR(60-60)NonEmptyArray(44-44)ValueOfPotentialTuple(46-46)packages/runtime/src/client/query-builder.ts (2)
ToKyselySchema(14-16)MapBaseType(28-40)
packages/runtime/src/client/crud/operations/create.ts (3)
packages/runtime/src/client/query-utils.ts (1)
getIdValues(141-147)packages/runtime/src/client/crud-types.ts (2)
WhereInput(158-183)CreateManyAndReturnArgs(536-542)packages/runtime/src/plugins/policy/errors.ts (1)
RejectedByPolicyError(4-11)
packages/language/src/zmodel-scope.ts (3)
packages/language/src/generated/ast.ts (8)
isEnumField(454-456)isModel(575-577)isMemberAccessExpr(563-565)isReferenceExpr(705-707)isDataModelField(383-385)isTypeDefField(759-761)isInvocationExpr(550-552)isDataModel(355-357)packages/language/src/utils.ts (3)
resolveImportUri(441-462)getModelFieldsWithBases(184-190)isCollectionPredicate(505-507)packages/language/src/constants.ts (2)
STD_LIB_MODULE_NAME(21-21)PLUGIN_MODULE_NAME(26-26)
🪛 LanguageTool
packages/ide/vscode/README.md
[uncategorized] ~19-~19: It appears that a hyphen is missing (if ‘auto’ is not used in the context of ‘cars’).
Context: ... "*.zmodel": "zmodel" }, ``` - Auto formatting - To automatically format on save,...
(AUTO_HYPHEN)
🪛 markdownlint-cli2 (0.17.2)
packages/ide/vscode/README.md
11-11: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
21-21: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
27-27: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
🪛 Biome (1.9.4)
packages/runtime/src/client/executor/name-mapper.ts
[error] 160-160: Unnecessary continue statement
Unsafe fix: Delete the unnecessary continue statement
(lint/correctness/noUnnecessaryContinue)
packages/runtime/src/client/crud/dialects/sqlite.ts
[error] 143-150: Avoid unnecessary callback in flatMap call.
You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.
(lint/correctness/noFlatMapIdentity)
[error] 155-175: Avoid unnecessary callback in flatMap call.
You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.
(lint/correctness/noFlatMapIdentity)
packages/runtime/src/client/query-utils.ts
[error] 146-146: Avoid the use of spread (...) syntax on accumulators.
Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.
(lint/performance/noAccumulatingSpread)
[error] 161-161: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
packages/language/src/validators/datamodel-validator.ts
[error] 411-411: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
packages/runtime/src/client/crud-types.ts
[error] 109-109: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
[error] 383-383: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
packages/runtime/src/client/client-impl.ts
[error] 110-110: The constructor should not return a value.
The constructor is here:
Returning a value from a constructor is ignored.
(lint/correctness/noConstructorReturn)
packages/runtime/src/plugins/policy/expression-transformer.ts
[error] 109-109: This parameter is used before its declaration.
The parameter is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 115-115: This parameter is used before its declaration.
The parameter is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 281-281: This parameter is used before its declaration.
The parameter is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
packages/runtime/src/client/crud/dialects/postgresql.ts
[error] 197-204: Avoid unnecessary callback in flatMap call.
You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.
(lint/correctness/noFlatMapIdentity)
[error] 222-225: Avoid unnecessary callback in flatMap call.
You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.
(lint/correctness/noFlatMapIdentity)
packages/runtime/src/client/contract.ts
[error] 120-120: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
packages/runtime/src/client/crud/operations/base.ts
[error] 1405-1405: Avoid the use of spread (...) syntax on accumulators.
Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.
(lint/performance/noAccumulatingSpread)
[error] 1545-1545: Avoid the use of spread (...) syntax on accumulators.
Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.
(lint/performance/noAccumulatingSpread)
[error] 1565-1565: Avoid the use of spread (...) syntax on accumulators.
Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.
(lint/performance/noAccumulatingSpread)
[error] 1627-1627: Avoid the use of spread (...) syntax on accumulators.
Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.
(lint/performance/noAccumulatingSpread)
[error] 1644-1644: Avoid the use of spread (...) syntax on accumulators.
Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.
(lint/performance/noAccumulatingSpread)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build-test (20.x)
🔇 Additional comments (96)
packages/runtime/src/client/crud/dialects/index.ts (1)
8-11: Consistent trailing-comma style looks goodThe only modification is the trailing comma after
options, aligning this file with the updated lint/format rules. No functional impact detected. 👍packages/language/src/validators/typedef-validator.ts (1)
17-17: LGTM – readability improvedSwitching to single-line arrows keeps the validator concise without altering behaviour.
packages/cli/src/actions/action-utils.ts (2)
20-21: LGTM – purely cosmetic change.Message text and runtime semantics remain untouched; adding the trailing comma is innocuous.
38-38: Single-lineifkeeps semantics intact.No objection—readability is arguably better and branch count unchanged.
packages/language/src/validators/function-decl-validator.ts (1)
9-12: No functional delta – validator still iterates attributes.The arrow-function re-format is safe; no side-effects introduced.
packages/language/res/stdlib.zmodel (1)
28-28: Whitespace / comment tidy-up acknowledged.All edits are confined to comments or blank lines; DSL semantics stay intact.
Also applies to: 106-110, 174-180, 189-195, 526-533, 541-543, 666-671
packages/language/src/zmodel.langium (1)
167-168: Whitespace trim only – grammar unaffected.No grammar tokens or rules changed; parser behavior unchanged.
Also applies to: 196-198, 211-212
packages/language/src/validators/datasource-validator.ts (1)
35-38: String interpolation compacted – still correct.Template-literal remains accurate; no injection vectors introduced.
TODO.md (1)
1-83: LGTM! Well-organized TODO list updates.The reformatting improves readability with consistent indentation, and the new TODO items reflect ongoing development priorities. Moving "Prisma client extension" to completed status aligns with recent runtime enhancements.
packages/common-helpers/src/tiny-invariant.ts (1)
1-14: LGTM! Clean invariant utility implementation.The implementation correctly handles environment-based error messaging and uses TypeScript's
assertskeyword appropriately for type narrowing. This provides a good internal replacement for the externaltiny-invariantdependency.packages/language/src/validators/common.ts (1)
20-32: LGTM! Clean stylistic improvements.The formatting changes improve code consistency with trailing commas and single-line expressions while preserving the validation logic.
packages/language/src/validators/expression-validator.ts (1)
39-259: LGTM! Consistent formatting improvements.The stylistic changes improve code readability by consolidating multiline statements and removing redundant syntax while preserving all validation logic and error handling.
packages/eslint-config/base.js (1)
1-17: LGTM! Well-structured shared ESLint configuration.The configuration follows current best practices with the flat config format and makes reasonable rule customizations for a TypeScript monorepo. The rule choices balance code quality with development practicality.
.prettierrc (1)
1-6: Prettier baseline looks goodThe new configuration matches the formatting observed in the refactor. No concerns.
packages/ide/vscode/src/language-server/main.ts (1)
4-4: Import consolidation LGTMPurely stylistic; logic untouched.
packages/eslint-config/package.json (1)
1-7: Config package scaffold acceptedPackage json is minimal yet sufficient for an internal shared config.
packages/ide/vscode/tsconfig.json (1)
2-2: Centralized base config looks good – double-check package availabilityMigrating to
@zenstackhq/typescript-config/base.jsonis beneficial for consistency.
Please verify that the package is published/linked in every CI job and local dev environment; otherwisetscwill fail to resolve the path.packages/runtime/src/plugins/policy/plugin.zmodel (1)
3-3: Formatting cleanup looks goodWhitespace normalisation improves doc-comment readability without altering semantics.
packages/create-zenstack/src/index.ts (1)
60-61: LGTM on JSON formattingTrailing-comma adjustment matches Prettier defaults and reduces future diff noise.
Also applies to: 95-96
packages/cli/tsconfig.json (1)
2-2: Config update approvedExtending the shared base config promotes consistency across packages.
packages/cli/eslint.config.js (1)
1-4: LGTM! Clean implementation of centralized ESLint config.The implementation correctly imports and re-exports the base ESLint configuration with proper type annotation. This aligns well with the centralized configuration strategy across packages.
packages/runtime/src/client/index.ts (1)
6-6: LGTM! Appropriate addition to the public API.The export of
definePluginenhances the plugin system's public interface and follows the established export pattern in this module.packages/common-helpers/eslint.config.js (1)
1-4: LGTM! Consistent with centralized ESLint configuration strategy.The implementation correctly follows the same pattern as other packages, importing and re-exporting the base ESLint configuration with proper type annotation.
packages/common-helpers/src/lower-case-first.ts (1)
1-3: LGTM! Simple and correct utility implementation.The function correctly converts the first character to lowercase. The implementation handles edge cases appropriately (empty strings return empty strings).
packages/common-helpers/src/upper-case-first.ts (1)
1-3: LGTM! Consistent and correct utility implementation.The function correctly converts the first character to uppercase and follows the same implementation pattern as
lowerCaseFirst, ensuring consistency across the utility functions.packages/ide/vscode/eslint.config.mjs (1)
1-4: Minimal pass-through config looks goodStraightforward re-export of the shared ESLint rules for the VS Code extension. No concerns.
packages/create-zenstack/package.json (1)
38-40: Good move to workspace-scoped tooling depsPicking up
@zenstackhq/*-configviaworkspace:*keeps the versions in lock-step across the monorepo. 👍packages/runtime/src/plugins/policy/plugin.ts (1)
18-21: Method signature complies with the runtime contract
onKyselyQueryforwards toPolicyHandlerand returns its promise; interface implementation still matches. No action needed.packages/create-zenstack/eslint.config.js (1)
1-4: Consistent lint config re-export – looks goodMatches the pattern used in other packages; keeps tooling simple.
packages/language/eslint.config.js (1)
5-7: ESLint flat-config looks good
tseslint.configis used correctly andignoresis the proper top-level key for flat configs in ESLint ≥ 9. No issues spotted.packages/common-helpers/src/index.ts (1)
1-6: Simple barrel file – LGTMStraightforward re-exports with no side effects; fine as-is.
packages/language/package.json (1)
46-49: Verify the custom version specifiercatalog:The
catalog:protocol isn’t recognised by npm/Yarn/PNPM out of the box.
Ensure your package-manager plugins (e.g. pnpm-catalog) are present in CI/CD; otherwise installs will fail."langium": "catalog:", "ts-pattern": "catalog:"If this is intentional and tooling is in place, feel free to ignore.
packages/runtime/src/client/promise.ts (1)
5-6: LGTM – signature compression onlyNo behavioural change; the promise remains a thenable and still satisfies
PromiseLike<T>.packages/cli/src/actions/migrate.ts (1)
55-58:runResetexpects{ force: boolean }but receivesCommonOptions
runReset(prismaSchemaFile, options as any)bypasses type-checking and may sendundefinedforforce, resulting in the CLI prompting the user even when--forcewas intended.Consider narrowing the type upfront:
-case 'reset': - await runReset(prismaSchemaFile, options as any); +case 'reset': { + const { force = false } = options as { force?: boolean }; + await runReset(prismaSchemaFile, { force }); + break; +}Likely an incorrect or invalid review comment.
packages/runtime/src/client/crud/operations/update.ts (1)
41-43: Confirm policy checks forupdateManyUnlike
runUpdate/runUpsert, therunUpdateManypath doesn’t re-check the read result against policies. If policies can deny reading updated rows, this could leak data through the count returned here.If policy enforcement is handled elsewhere, please ignore; otherwise consider mirroring the pattern used in
runUpdate.packages/cli/src/utils/version-utils.ts (2)
1-3: Good modernization to native Node.js modules.The migration from
requireto native Node.js modules (fs,path,url) is a positive improvement for future compatibility and consistency.
7-9: Isomorphic __dirname implementation is correct.The implementation correctly handles both CommonJS (
__dirnameavailable) and ES modules (import.meta.urlavailable) contexts. The path resolution logic is sound.packages/cli/src/actions/init.ts (3)
31-31: Good formatting improvement for error handling.Consolidating the multi-line error throw to a single line improves readability while maintaining the same functionality.
52-56: Consistent formatting for file operations and logging.The consolidation of the file existence check, write operation, and console logging into single-line statements improves code consistency and readability.
59-60: Well-formatted console output messages.The single-line formatting of console messages is more readable and maintains consistent styling with the rest of the codebase.
packages/ide/vscode/package.json (3)
12-17: Script simplification aligns with build system modernization.The removal of watch-related scripts (
watch,watch:tsc,watch:tsup) aligns with the migration to Turbo for task running mentioned in the AI summary. This consolidation should improve build consistency across the monorepo.
33-37: Good dependency management improvements.The updates demonstrate better monorepo dependency management:
- Using
workspace:*for internal packages- Using
catalog:for external dependencies- Removing duplicate entries
These changes should improve dependency resolution and version consistency.
39-42: Addition of shared configuration packages.Adding
@zenstackhq/eslint-configand@zenstackhq/typescript-configas workspace dependencies supports the standardization of linting and TypeScript configurations across the monorepo.packages/cli/src/utils/exec-utils.ts (2)
6-6: Good formatting improvement for function signature.Consolidating the multi-line function signature to a single line improves readability while maintaining the same type safety and functionality.
22-22: Good addition of trailing comma.Adding the trailing comma is a good practice that makes future parameter additions cleaner and reduces diff noise.
packages/cli/src/index.ts (4)
7-9: Clean formatting for action function.The single-line arrow function format improves readability while maintaining the same async functionality.
37-39: Improved formatting for program description.The consolidated description formatting makes the CLI help text more readable while preserving the same functionality and styling.
45-46: Consistent single-line option descriptions.The formatting improvements for option descriptions enhance code readability and maintain consistency across the CLI interface.
52-53: Excellent formatting consistency across command definitions.The consolidation of multi-line command descriptions and option additions into single-line statements creates a much more readable and consistent command definition structure throughout the CLI.
Also applies to: 61-62, 69-70, 75-76, 90-92, 96-97
packages/runtime/src/client/executor/name-mapper.ts (1)
35-38: LGTM: Formatting improvements enhance readability.The consolidation of multi-line statements into single lines improves code readability while preserving all original logic and functionality.
Also applies to: 71-71, 89-91, 116-116, 129-129, 143-143, 153-155, 162-177, 188-194, 197-204, 233-233, 247-247, 261-261
packages/common-helpers/src/is-plain-object.ts (1)
1-23: LGTM: Solid implementation of plain object detection.The function correctly implements the standard approach for detecting plain JavaScript objects by checking the object's internal class string, constructor, prototype, and built-in methods. This is a well-established pattern that handles edge cases properly.
packages/runtime/src/client/crud/operations/create.ts (1)
4-4: LGTM: Formatting improvements enhance code readability.The consolidation of import statements, method signatures, and type annotations improves code readability while maintaining all original functionality and type safety.
Also applies to: 8-9, 11-11, 13-13, 17-17, 31-35, 40-40, 53-53, 60-60, 65-65
packages/common-helpers/src/param-case.ts (1)
1-18: LGTM: Efficient param-case conversion implementation.The function correctly handles camelCase and PascalCase boundaries using well-designed regex patterns. The use of null character delimiters and proper trimming ensures clean output for various input formats.
packages/runtime/src/client/crud/operations/count.ts (1)
5-5: LGTM: Formatting improvements enhance readability.The consolidation of method calls and query building expressions improves code readability while preserving all counting logic and functionality.
Also applies to: 7-7, 14-15, 25-27, 32-32
packages/language/src/module.ts (1)
37-76: Reformat looks goodOnly stylistic consolidation; no issues spotted with typing or DI wiring.
packages/language/src/index.ts (1)
48-52: LGTM – robust std-lib resolutionCross-platform
__dirnamefallback andURIresolution look solid.packages/runtime/src/client/query-builder.ts (2)
20-26: Use PascalCase for type aliases to stay consistent with TS conventions
toKyselyFieldTypestarts with a lowercase letter, which is counter-intuitive for a type alias and inconsistent with the rest of this file (ToKyselySchema,ToKyselyTable, …).
Renaming makes the API clearer and avoids the impression that this is a value-level helper.-type ToKyselyTable<Schema extends SchemaDef, Model extends GetModels<Schema>> = { - [Field in ScalarFields<Schema, Model, false> | ForeignKeyFields<Schema, Model>]: toKyselyFieldType< +type ToKyselyTable<Schema extends SchemaDef, Model extends GetModels<Schema>> = { + [Field in ScalarFields<Schema, Model, false> | ForeignKeyFields<Schema, Model>]: ToKyselyFieldType< Schema, Model, Field >; }; @@ -type toKyselyFieldType< +type ToKyselyFieldType<[ suggest_nitpick ]
28-40: DuplicatedMapBaseTypediverges from the canonical definition – risk of inconsistent typingA
MapBaseTypewith the same name already exists inpackages/runtime/src/utils/type-utils.ts, but:
- That canonical version maps
'DateTime'→Date(here it isstring).- The canonical version also maps
'Json'→JsonValue(missing here).Maintaining two differing definitions will silently break assignability checks across the codebase.
Action items:
- Delete the local alias and re-export the one from
type-utils, or- Bring this copy in sync with the canonical mapping.
Failing to do so can introduce subtle type mismatches between query-builder code and the rest of the runtime.
[ raise_critical_issue ][ request_verification ]packages/runtime/src/client/options.ts (1)
9-14: LGTM – type-only formatting, no functional changeThe refactor is purely cosmetic; typings still evaluate correctly.
[ approve_code_changes ]packages/runtime/src/client/crud/dialects/sqlite.ts (2)
1-1: Verify behavioural parity of the new@zenstackhq/common-helpersinvariant
invariantwas switched fromtiny-invariantto a workspace helper.
Please confirm that the new helper:
- throws Error (or a compatible subclass) with the same message
- keeps the assertion-signature (
asserts condition).A silent semantic drift here will surface only at runtime.
[ request_verification ]
136-152: Drop identityflatMap– useflat()for clarity and micro-perf
flatMap((v) => v)allocates an unnecessary callback. Static analysis already flags this.- objArgs.push(...someArray.flatMap((v) => v)); + objArgs.push(...someArray.flat());Apply the same change to the two other occurrences in this method.
No behaviour change, but the intent is clearer and marginally faster.
[ suggest_optional_refactor ]Also applies to: 155-176, 179-195
packages/language/src/validator.ts (1)
67-102:expr && side-effect()pattern hurts debuggabilityUsing
this.shouldCheck(node) && new X().validate(node, accept)relies on short-circuit side effects and required the globalno-unused-expressionsoverride.Pros:
- Fewer lines.
Cons:
- Harder to set break-points.
- Lint rule suppression hints at reduced readability.
Consider reverting to explicit
ifstatements – especially inside a validator that is expected to be maintained by multiple contributors.
[ suggest_nitpick ]packages/runtime/package.json (1)
68-76:catalog:/workspace:version specifiers may break external consumersDependencies such as
"kysely": "catalog:"and"ts-pattern": "catalog:"are understood only inside your monorepo tooling.
If@zenstackhq/runtimeis published to npm, these placeholders will be preserved in the publishedpackage.json, causing install failures for end-users.Please ensure that the publish pipeline rewrites these specifiers to semver ranges (or mark the package
private).
[ request_verification ]packages/runtime/src/client/executor/zenstack-driver.ts (5)
108-109: Logging condition looks goodSwitching to a single boolean expression keeps the intent clear and yields identical behaviour.
No further action required.
120-135: Defensive note: double-patching guard already handled
#addLoggingcaptures the originalexecuteQuerybefore monkey-patching, avoiding recursion – good. The WeakSet guard earlier prevents double patching, so the change here is safe.No issues spotted.
137-154: Stream patch matches the sync variant – LGTMMirrors the error/latency logging pattern from
executeQuery. Implementation is correct and preservesthisbinding via.call.
157-164: Good: structured error payloadThe error logger now includes
errorand timing – useful for observability.
166-173: Good: optionalisStreamflagAdds clarity in query logs without changing public surface area.
packages/cli/src/actions/generate.ts (2)
1-3: Consolidated imports – looks fineMoving
invariantinto the new shared helper package and updating generator typings keeps the dependency graph clean.
43-44: Minor formatting onlyWhitespace tweak in the template string – no functional impact.
packages/cli/package.json (1)
6-50: Verify unconventional version specifiers and build prerequisites
"langium": "catalog:","ts-pattern": "catalog:", and peer"prisma": "catalog:"are not standard semver ranges. Ensure your private registry or pnpm “catalog” resolver is configured on all CI/consumer environments; otherwise installs will fail.typescriptis no longer a devDependency, buttsup-noderelies on the compiler at build time. Confirm that the workspace root provides it transitively or add it back locally.packages/common-helpers/package.json (1)
1-34: Initial package scaffold looks solidExports map covers both ESM and CJS, scripts align with other workspace packages. No critical issues spotted.
.github/workflows/bump-version.yml (1)
1-45: Workflow LGTM – remember to protect against stale lockfilesThe job is straightforward and targets the
devbranch correctly. Consider addingpnpm install --frozen-lockfile --prefer-offlineto speed up caching, but not required.packages/language/src/validators/datamodel-validator.ts (1)
228-233:$resolvedTypeequality check can be simplified with optional chainingBiome flagged this – the verbose comparison can be condensed:
- if ( - fieldRef.$resolvedType?.decl !== references[i]?.$resolvedType?.decl || - fieldRef.$resolvedType?.array !== references[i]?.$resolvedType?.array - ) { + if ( + fieldRef.$resolvedType?.decl !== references[i]?.$resolvedType?.decl || + fieldRef.$resolvedType?.array !== references[i]?.$resolvedType?.array + ) {(No functional change – purely readability.)
packages/language/src/validators/attribute-application-validator.ts (1)
298-305:FieldReference/TransitiveFieldReferencearray check misses heterogeneous arraysThe predicate only verifies that every item is a reference to a
DataModelField, but it doesn’t check that all referenced fields share the same type – an attribute argument like[userId, createdAt]would pass even if the fields areStringandDateTime.If that type-safety is desired, extend the check:
const firstType = (arg.value.items[0] as ReferenceExpr).target.ref?.type; if ( arg.value.items.some( (item) => !isReferenceExpr(item) || !isDataModelField(item.target.ref) || item.target.ref.type.type !== firstType?.type ) ) { return false; }packages/runtime/src/client/helpers/schema-db-pusher.ts (3)
1-1: LGTM: Import migration aligns with project-wide consolidation.The migration from
tiny-invariantto@zenstackhq/common-helpersis consistent with the broader effort to consolidate common utilities across the codebase.
45-48: Well-implemented computed field handling.The logic correctly identifies and skips computed fields during table column creation. The
isComputedFieldmethod properly checks for the@computedattribute, which aligns with the expected behavior for derived fields that shouldn't be persisted in the database.Also applies to: 57-60
103-136: Clean refactoring of createModelField method.The reformatting improves code readability while maintaining the same logic. The simplified default value handling by combining conditions is a nice improvement.
packages/language/src/validators/schema-validator.ts (1)
13-18: All operations are synchronous
Both resolveTransitiveImports (packages/language/src/utils.ts:390) and resolveImport (packages/language/src/utils.ts:421) contain no async/await or Promise usage. Removing async/await from validate is safe.packages/runtime/src/client/functions.ts (1)
10-18: Excellent addition of parameter validation.The explicit parameter checks with clear error messages significantly improve the developer experience by catching missing parameters early and providing helpful error messages.
Also applies to: 26-33, 37-44, 48-55, 59-66, 71-77
packages/runtime/src/client/executor/zenstack-query-executor.ts (1)
60-60: Good use of TypeScript's native Awaited utility type.Replacing the custom
PromiseTypewith TypeScript's nativeAwaitedutility improves code maintainability and leverages standard language features.packages/runtime/src/client/plugin.ts (2)
157-174: Excellent plugin hook architecture design.The new
OnQueryHooksstructure provides a flexible and type-safe way to intercept queries at different granularities:
- Model-specific hooks with uncapitalized model names
- Operation-specific hooks per model
$allModelsand$allOperationscatch-alls for general interceptionThis design significantly improves the plugin system's extensibility and type safety.
217-219: Nice addition of the definePlugin helper.The
definePluginhelper function provides a clean API for plugin authors with proper TypeScript typing, improving the developer experience.packages/language/src/zmodel-scope.ts (1)
52-121: Code formatting looks clean and consistent.The formatting improvements enhance readability without altering functionality. Method signatures and filtering logic have been properly condensed.
packages/runtime/src/client/client-impl.ts (1)
184-189: Good addition for plugin management.The
$unusemethod provides a clean way to remove specific plugins by ID while maintaining immutability.packages/runtime/src/client/crud/validator.ts (2)
25-1180: Zod type migration looks correct.The systematic replacement of
ZodSchemawithZodTypethroughout the file is appropriate for Zod v4 compatibility. The validation logic remains unchanged.
4-4: All Zod imports consistently usezod/v4
Verification shows no occurrences ofimport { … } from 'zod'; all imports referencezod/v4, and package definitions don’t pull in conflicting Zod versions. No further action required.package.json (1)
1-39: Build tooling modernization looks good.The migration to Turbo for task orchestration and the addition of formatting/version management scripts improve the development workflow. The dependency updates align well with modern tooling standards.
packages/runtime/src/client/crud/dialects/base.ts (1)
1-1: Good consolidation of helper imports.Using the internal
@zenstackhq/common-helperspackage reduces external dependencies and improves maintainability.packages/runtime/src/client/crud/operations/base.ts (2)
2-2: LGTM! Good consolidation of common utilities.The migration from
tiny-invariantto the centralized@zenstackhq/common-helperspackage aligns well with the broader effort to consolidate common utilities.
125-1903: Excellent formatting improvements throughout the file.The consistent formatting changes (multi-line to single-line conversions, trailing commas) improve code readability and maintainability without altering the core functionality.
packages/runtime/src/client/contract.ts (5)
5-28: LGTM! Well-organized imports for CRUD types.The detailed import list provides better clarity on the specific types being used.
73-77: Excellent addition of the$unusemethod.This complements the existing
$useand$unuseAllmethods, providing fine-grained control over plugin management.
97-112: Clean redesign of the MapType utility.The
_TypeMapobject provides a clear and maintainable mapping between schema primitive types and TypeScript types.
146-698: Outstanding addition of theModelOperationsinterface!This is an exceptional improvement to the client contract:
- Comprehensive coverage of all CRUD operations
- Excellent JSDoc documentation with practical examples
- Strong typing for all operation arguments and return types
- Clear parameter explanations and usage patterns
The extensive examples for each method will greatly help developers understand the API.
136-136: Good simplification of the ClientConstructor interface.Removing the constructor overloads in favor of a single, clear signature improves API clarity.
| function installPackage(pkg: { name: string; dev: boolean }) { | ||
| runCommand( | ||
| `${agent} install ${pkg.name} ${pkg.dev ? saveDev : ''}`, | ||
| `Installing "${pkg.name}"` | ||
| ); | ||
| runCommand(`${agent} install ${pkg.name} ${pkg.dev ? saveDev : ''}`, `Installing "${pkg.name}"`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
install vs add: Yarn/PNPM/Bun will ignore the package name
yarn install foo (and likewise for pnpm/bun) installs nothing; it merely runs the install step.
Use the ecosystem-specific sub-command (add) to ensure dependencies are actually added.
-function installPackage(pkg: { name: string; dev: boolean }) {
- runCommand(`${agent} install ${pkg.name} ${pkg.dev ? saveDev : ''}`, `Installing "${pkg.name}"`);
+function installPackage(pkg: { name: string; dev: boolean }) {
+ const subCmd = agent === 'npm' ? 'install' : 'add';
+ const devFlag = pkg.dev ? saveDev : '';
+ runCommand(`${agent} ${subCmd} ${pkg.name} ${devFlag}`.trim(), `Installing "${pkg.name}"`);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function installPackage(pkg: { name: string; dev: boolean }) { | |
| runCommand( | |
| `${agent} install ${pkg.name} ${pkg.dev ? saveDev : ''}`, | |
| `Installing "${pkg.name}"` | |
| ); | |
| runCommand(`${agent} install ${pkg.name} ${pkg.dev ? saveDev : ''}`, `Installing "${pkg.name}"`); | |
| } | |
| function installPackage(pkg: { name: string; dev: boolean }) { | |
| const subCmd = agent === 'npm' ? 'install' : 'add'; | |
| const devFlag = pkg.dev ? saveDev : ''; | |
| runCommand(`${agent} ${subCmd} ${pkg.name} ${devFlag}`.trim(), `Installing "${pkg.name}"`); | |
| } |
🤖 Prompt for AI Agents
In packages/create-zenstack/src/index.ts around lines 113 to 115, the command
uses 'install' to add packages, but for Yarn, PNPM, and Bun, 'install' does not
add packages and only runs the install step. Replace the 'install' sub-command
with the appropriate 'add' sub-command to ensure the package is actually added
as a dependency.
|
|
||
| if (key === '_count') { | ||
| // underlying database provider may return string for count | ||
| data[key] = | ||
| typeof value === 'string' ? JSON.parse(value) : value; | ||
| data[key] = typeof value === 'string' ? JSON.parse(value) : value; | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
JSON.parse on un-validated _count strings can blow up at runtime
If the provider ever returns a malformed string (or simply "NaN"), JSON.parse will throw and bring down the whole request.
A safer conversion does the minimal work needed (number or object) and falls back gracefully:
-data[key] = typeof value === 'string' ? JSON.parse(value) : value;
+if (typeof value === 'string') {
+ try {
+ data[key] = JSON.parse(value);
+ } catch {
+ // most providers just send numeric strings; convert them silently
+ const num = Number(value);
+ data[key] = Number.isNaN(num) ? value : num;
+ }
+}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/runtime/src/client/result-processor.ts around lines 34 to 39, the
use of JSON.parse on the _count string value can throw an error if the string is
malformed or not valid JSON. Replace JSON.parse with a safer conversion that
attempts to parse the string as a number or object but falls back gracefully
without throwing, ensuring the request does not fail due to invalid _count
strings.
| case '_count': { | ||
| if (value === true) { | ||
| query = query.select((eb) => | ||
| eb.cast(eb.fn.countAll(), 'integer').as('_count') | ||
| ); | ||
| query = query.select((eb) => eb.cast(eb.fn.countAll(), 'integer').as('_count')); | ||
| } else { | ||
| Object.entries(value).forEach(([field, val]) => { | ||
| if (val === true) { | ||
| if (field === '_all') { | ||
| query = query.select((eb) => | ||
| eb | ||
| .cast(eb.fn.countAll(), 'integer') | ||
| .as(`_count._all`) | ||
| eb.cast(eb.fn.countAll(), 'integer').as(`_count._all`), | ||
| ); | ||
| } else { | ||
| query = query.select((eb) => | ||
| eb | ||
| .cast( | ||
| eb.fn.count( | ||
| sql.ref(`$sub.${field}`) | ||
| ), | ||
| 'integer' | ||
| ) | ||
| .as(`${key}.${field}`) | ||
| eb.cast(eb.fn.count(sql.ref(`$sub.${field}`)), 'integer').as(`${key}.${field}`), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SQL alias contains dots – breaks MySQL & quoted identifiers
Aliases like '_count._all' and ${key}.${field} are invalid in MySQL and need quoting in Postgres.
Use an underscore delimiter (or quote) to stay portable:
- .as(`_count._all`)
+ .as(`_count__all`)
...
- .as(`${key}.${field}`)
+ .as(`${key}__${field}`)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case '_count': { | |
| if (value === true) { | |
| query = query.select((eb) => | |
| eb.cast(eb.fn.countAll(), 'integer').as('_count') | |
| ); | |
| query = query.select((eb) => eb.cast(eb.fn.countAll(), 'integer').as('_count')); | |
| } else { | |
| Object.entries(value).forEach(([field, val]) => { | |
| if (val === true) { | |
| if (field === '_all') { | |
| query = query.select((eb) => | |
| eb | |
| .cast(eb.fn.countAll(), 'integer') | |
| .as(`_count._all`) | |
| eb.cast(eb.fn.countAll(), 'integer').as(`_count._all`), | |
| ); | |
| } else { | |
| query = query.select((eb) => | |
| eb | |
| .cast( | |
| eb.fn.count( | |
| sql.ref(`$sub.${field}`) | |
| ), | |
| 'integer' | |
| ) | |
| .as(`${key}.${field}`) | |
| eb.cast(eb.fn.count(sql.ref(`$sub.${field}`)), 'integer').as(`${key}.${field}`), | |
| ); | |
| } | |
| case '_count': { | |
| if (value === true) { | |
| query = query.select((eb) => eb.cast(eb.fn.countAll(), 'integer').as('_count')); | |
| } else { | |
| Object.entries(value).forEach(([field, val]) => { | |
| if (val === true) { | |
| if (field === '_all') { | |
| query = query.select((eb) => | |
| eb.cast(eb.fn.countAll(), 'integer').as(`_count__all`), | |
| ); | |
| } else { | |
| query = query.select((eb) => | |
| eb.cast(eb.fn.count(sql.ref(`$sub.${field}`)), 'integer').as(`${key}__${field}`), | |
| ); | |
| } | |
| } | |
| }); | |
| } | |
| break; | |
| } |
🤖 Prompt for AI Agents
In packages/runtime/src/client/crud/operations/aggregate.ts between lines 46 and
60, the SQL aliases use dots (e.g., '_count._all' and `${key}.${field}`), which
are invalid in MySQL and cause issues with quoted identifiers in Postgres. To
fix this, replace the dots in the alias names with underscores or another
delimiter that is compatible across databases to ensure portability and prevent
SQL errors.
| const packages = await getZenStackPackages(projectPath); | ||
| if (!packages) { | ||
| console.error( | ||
| 'Unable to locate package.json. Are you in a valid project directory?' | ||
| ); | ||
| console.error('Unable to locate package.json. Are you in a valid project directory?'); | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getZenStackPackages now returns [], breaking the “no package.json” guard
run() still relies on a falsy value to detect the absence of package.json, but getZenStackPackages was changed to return an empty array instead of undefined.
As a result, the error message is never printed and the user just sees an empty list.
-const packages = await getZenStackPackages(projectPath);
-if (!packages) {
+const packages = await getZenStackPackages(projectPath);
+if (packages.length === 0) {
console.error('Unable to locate package.json. Are you in a valid project directory?');
return;
}…and keep getZenStackPackages’s catch branch returning [] as it is.
This restores the intended UX and avoids changing the public contract of getZenStackPackages.
Also applies to: 40-41
🤖 Prompt for AI Agents
In packages/cli/src/actions/info.ts around lines 8 to 13 and also lines 40 to
41, the check for the absence of package.json incorrectly relies on a falsy
value from getZenStackPackages, but it now returns an empty array instead of
undefined. Update the condition to check if the returned packages array is empty
(length === 0) to detect the missing package.json and print the error message
accordingly, preserving the existing behavior of getZenStackPackages returning
an empty array on errors.
| if (isSelectAll) { | ||
| if (!selectAllFromModel) { | ||
| continue; | ||
| } else { | ||
| const scalarFields = this.getModelScalarFields( | ||
| contextNode, | ||
| selectAllFromModel | ||
| ); | ||
| const fromModelDef = requireModel( | ||
| this.schema, | ||
| selectAllFromModel | ||
| ); | ||
| const mappedTableName = | ||
| this.getMappedName(fromModelDef) ?? selectAllFromModel; | ||
| const scalarFields = this.getModelScalarFields(contextNode, selectAllFromModel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unnecessary continue statement.
The continue statement is redundant since the else block won't execute when !selectAllFromModel is true, and the loop will naturally continue to the next iteration.
if (isSelectAll) {
if (!selectAllFromModel) {
- continue;
+ // Skip processing when no model context
} else {
const scalarFields = this.getModelScalarFields(contextNode, selectAllFromModel);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (isSelectAll) { | |
| if (!selectAllFromModel) { | |
| continue; | |
| } else { | |
| const scalarFields = this.getModelScalarFields( | |
| contextNode, | |
| selectAllFromModel | |
| ); | |
| const fromModelDef = requireModel( | |
| this.schema, | |
| selectAllFromModel | |
| ); | |
| const mappedTableName = | |
| this.getMappedName(fromModelDef) ?? selectAllFromModel; | |
| const scalarFields = this.getModelScalarFields(contextNode, selectAllFromModel); | |
| if (isSelectAll) { | |
| if (!selectAllFromModel) { | |
| // Skip processing when no model context | |
| } else { | |
| const scalarFields = this.getModelScalarFields(contextNode, selectAllFromModel); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 160-160: Unnecessary continue statement
Unsafe fix: Delete the unnecessary continue statement
(lint/correctness/noUnnecessaryContinue)
🤖 Prompt for AI Agents
In packages/runtime/src/client/executor/name-mapper.ts around lines 158 to 162,
remove the unnecessary continue statement inside the if (isSelectAll) block.
Since the else block only executes when selectAllFromModel is truthy, the
continue is redundant and can be safely deleted to simplify the code flow.
| async beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void> { | ||
| const result = await this.#driver.beginTransaction(connection, settings); | ||
| this.txConnection = connection; | ||
| return result; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Potential race condition & incorrect return type in beginTransaction
txConnection is a single shared property. If the same ZenStackDriver instance is used for concurrent transactions (a realistic scenario for pooled drivers), this will be overwritten by whichever transaction starts last, breaking the “active-transaction” invariant for the earlier one.
In addition, the method is declared to return Promise<void> but currently propagates the (void) result of the underlying driver – the extra return result; is redundant and may mis-lead future refactors.
- async beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void> {
- const result = await this.#driver.beginTransaction(connection, settings);
- this.txConnection = connection;
- return result;
+ async beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void> {
+ await this.#driver.beginTransaction(connection, settings);
+
+ // Track multiple concurrent transactions safely
+ (this.#activeTxConnections ??= new WeakSet()).add(connection);
+ this.txConnection = connection; // keep the shortcut for backwards-compat if really needed
+ }You’ll also need to:
#activeTxConnections?: WeakSet<DatabaseConnection>;and clean the set in commitTransaction/rollbackTransaction.
🤖 Prompt for AI Agents
In packages/runtime/src/client/executor/zenstack-driver.ts around lines 68 to
72, the beginTransaction method incorrectly uses a single shared property
txConnection for all transactions, causing race conditions in concurrent
scenarios, and it returns a redundant result despite being declared as
Promise<void>. To fix this, remove the txConnection assignment and the return
statement from beginTransaction, declare a private WeakSet named
#activeTxConnections to track active connections, and update commitTransaction
and rollbackTransaction methods to remove connections from this set to properly
manage transaction state without conflicts.
| const provider = this.getDataSourceProvider(AstUtils.getContainerOfType(field, isModel)!); | ||
| if (provider === 'sqlite') { | ||
| accept( | ||
| 'error', | ||
| `Array type is not supported for "${provider}" provider.`, | ||
| { node: field.type } | ||
| ); | ||
| accept('error', `Array type is not supported for "${provider}" provider.`, { node: field.type }); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Hard-coding provider check to 'sqlite' is brittle
You only guard array types for sqlite, but MySQL & MariaDB share the same limitation.
Either compare against a set or reuse Prisma’s allowed list:
- const provider = this.getDataSourceProvider(AstUtils.getContainerOfType(field, isModel)!);
- if (provider === 'sqlite') {
+ const provider = this.getDataSourceProvider(AstUtils.getContainerOfType(field, isModel)!);
+ if (provider === 'sqlite' || provider === 'mysql' || provider === 'mariadb') {Alternatively extract to const ARRAY_UNSUPPORTED = new Set(['sqlite', 'mysql', 'mariadb']).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const provider = this.getDataSourceProvider(AstUtils.getContainerOfType(field, isModel)!); | |
| if (provider === 'sqlite') { | |
| accept( | |
| 'error', | |
| `Array type is not supported for "${provider}" provider.`, | |
| { node: field.type } | |
| ); | |
| accept('error', `Array type is not supported for "${provider}" provider.`, { node: field.type }); | |
| } | |
| } | |
| const provider = this.getDataSourceProvider(AstUtils.getContainerOfType(field, isModel)!); | |
| if (provider === 'sqlite' || provider === 'mysql' || provider === 'mariadb') { | |
| accept('error', `Array type is not supported for "${provider}" provider.`, { node: field.type }); | |
| } |
🤖 Prompt for AI Agents
In packages/language/src/validators/datamodel-validator.ts around lines 112 to
116, the code currently checks only for 'sqlite' when validating array type
support, which is brittle because MySQL and MariaDB also do not support array
types. To fix this, replace the single string comparison with a check against a
set of unsupported providers, for example by defining a constant set like
ARRAY_UNSUPPORTED containing 'sqlite', 'mysql', and 'mariadb', and then check if
the provider is in this set before raising the error.
| eb: ExpressionBuilder<any, any>, | ||
| array: Expression<unknown> | ||
| array: Expression<unknown>, | ||
| ): ExpressionWrapper<any, any, number> { | ||
| return eb.fn('array_length', [array]); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
array_length is called with a single argument – this will fail on PostgreSQL
PostgreSQL requires the dimension parameter: array_length(anyarray, int).
Current call produces ERROR: function array_length(anyarray) does not exist.
-return eb.fn('array_length', [array]);
+// 1 = first dimension
+return eb.fn('array_length', [array, eb.val(1)]);Please add the dimension literal (usually 1).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| eb: ExpressionBuilder<any, any>, | |
| array: Expression<unknown> | |
| array: Expression<unknown>, | |
| ): ExpressionWrapper<any, any, number> { | |
| return eb.fn('array_length', [array]); | |
| } | |
| eb: ExpressionBuilder<any, any>, | |
| array: Expression<unknown>, | |
| ): ExpressionWrapper<any, any, number> { | |
| // 1 = first dimension | |
| return eb.fn('array_length', [array, eb.val(1)]); | |
| } |
🤖 Prompt for AI Agents
In packages/runtime/src/client/crud/dialects/postgresql.ts around lines 283 to
287, the call to the PostgreSQL function array_length is missing the required
second argument for the array dimension. Fix this by adding the dimension
literal 1 as the second argument in the eb.fn call, so it correctly calls
array_length with two parameters: the array and the dimension.
| private async validateDataSources(model: Model, accept: ValidationAcceptor) { | ||
| const dataSources = (await getAllDeclarationsIncludingImports(this.documents, model)).filter((d) => | ||
| isDataSource(d), | ||
| ); | ||
| if (dataSources.length > 1) { | ||
| accept( | ||
| 'error', | ||
| 'Multiple datasource declarations are not allowed', | ||
| { node: dataSources[1]! } | ||
| ); | ||
| accept('error', 'Multiple datasource declarations are not allowed', { node: dataSources[1]! }); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistency: async validateDataSources called from sync validate method.
The validateDataSources method remains async and uses await, but it's called from the now-synchronous validate method without await. This will result in an unhandled promise and the validation won't complete properly.
Apply this diff to fix the issue:
- private async validateDataSources(model: Model, accept: ValidationAcceptor) {
- const dataSources = (await getAllDeclarationsIncludingImports(this.documents, model)).filter((d) =>
- isDataSource(d),
- );
+ private validateDataSources(model: Model, accept: ValidationAcceptor) {
+ const dataSources = getAllDeclarationsIncludingImports(this.documents, model).filter((d) =>
+ isDataSource(d),
+ );Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/language/src/validators/schema-validator.ts around lines 38 to 45,
the async method validateDataSources is called from a synchronous validate
method without awaiting, causing unhandled promises and incomplete validation.
To fix this, make the validate method async and await the call to
validateDataSources, ensuring proper asynchronous flow and completion of
validation.
| this.kysely = new Kysely(this.kyselyProps); | ||
|
|
||
| return createClientProxy(this as unknown as ClientContract<Schema>); | ||
| return createClientProxy(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the return statement from the constructor.
Constructors should not return values in JavaScript/TypeScript. The return value will be ignored, which could lead to confusion. The proxy wrapping should be handled differently.
Consider refactoring to use a factory pattern instead:
-export const ZenStackClient = function <Schema extends SchemaDef>(
+export function createZenStackClient<Schema extends SchemaDef>(
+ schema: Schema,
+ options: ClientOptions<Schema>,
+) {
+ const client = new ClientImpl<Schema>(schema, options);
+ return createClientProxy(client);
+}
+
+export const ZenStackClient = createZenStackClient as unknown as ClientConstructor;And remove the return statement from the constructor:
- return createClientProxy(this);
+ // Remove this line📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return createClientProxy(this); | |
| // Replace the original `export const ZenStackClient = function…` definition | |
| export function createZenStackClient<Schema extends SchemaDef>( | |
| schema: Schema, | |
| options: ClientOptions<Schema>, | |
| ) { | |
| const client = new ClientImpl<Schema>(schema, options); | |
| return createClientProxy(client); | |
| } | |
| export const ZenStackClient = createZenStackClient as unknown as ClientConstructor; | |
| // Inside ClientImpl (packages/runtime/src/client/client-impl.ts) | |
| class ClientImpl<Schema extends SchemaDef> { | |
| constructor(schema: Schema, options: ClientOptions<Schema>) { | |
| // …existing initialization logic… | |
| // Note: we no longer return from the constructor—proxying happens in the factory. | |
| } | |
| // …other methods… | |
| } |
🧰 Tools
🪛 Biome (1.9.4)
[error] 110-110: The constructor should not return a value.
The constructor is here:
Returning a value from a constructor is ignored.
(lint/correctness/noConstructorReturn)
🤖 Prompt for AI Agents
In packages/runtime/src/client/client-impl.ts at line 110, remove the return
statement from the constructor because constructors should not return values in
JavaScript/TypeScript. Instead, refactor the code to implement a factory
function that creates and returns the proxy-wrapped client instance, and keep
the constructor solely for initializing the instance without returning anything.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Chores
Documentation