-
-
Notifications
You must be signed in to change notification settings - Fork 16
feat(cli): implement watch mode for generate #573
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
merge dev to main (v3.0.0-beta.28)
merge dev to main (v3.0.0-beta.29)
merge dev to main (v3.0.0-beta.30)
merge dev to main (v3.0.0-beta.31)
merge dev to main (v3.0.0-beta.32)
merge dev to main (v3.0.0-beta.33)
merge dev to main (v3.0.0-beta.34)
merge dev to main (v3.0.0)
chore: update CI sample update script (#531)
merge dev to main
|
Claude encountered an error —— View job Reviewing PR: feat(cli): implement watch mode for generate
|
📝 WalkthroughWalkthroughCentralizes procedure routing in the TanStack Query clients by adding Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (1)📓 Common learnings⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
🔇 Additional comments (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
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.
Pull request overview
This pull request adds custom procedure support to the ZenStack ORM framework and updates sample applications to demonstrate this feature. Despite the title mentioning "watch mode for generate", the changes actually focus on implementing and showcasing custom procedures across different framework integrations (Next.js, Nuxt, SvelteKit).
Key Changes:
- Added
proceduresdefinition support to schema files (signUp mutation and listPublicPosts query) - Implemented procedure hooks in TanStack Query clients for React, Vue, and Svelte
- Updated sample applications with new pages demonstrating procedure usage (/signup and /feeds routes)
- Introduced
CUSTOM_PROC_ROUTE_NAMEconstant for consistent procedure routing - Modified dialect imports to use
@zenstackhq/orm/dialects/sqlite(partially - not in SvelteKit)
Reviewed changes
Copilot reviewed 40 out of 44 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| samples/shared/schema.zmodel | Added shared schema with procedure definitions (signUp, listPublicPosts) |
| samples/*/zenstack/schema.ts | Generated schema files with procedures metadata |
| samples/*/zenstack/schema-lite.ts | Generated lite schema files with procedures metadata |
| samples/*/zenstack/input.ts | Added ExistsArgs type exports with formatting improvements |
| samples/*/lib/db.ts or server/utils/db.ts | Added procedure implementations |
| samples//app/pages/signup. or routes/signup/* | New signup pages using procedure mutations |
| samples//app/pages/feeds. or routes/feeds/* | New feeds pages using procedure queries |
| samples//app/layout. or routes/+layout.svelte | Restructured layout to wrap all pages |
| packages/server/src/api/common/procedures.ts | Changed PROCEDURE_ROUTE_PREFIXES from array to string constant |
| packages/orm/src/client/crud/operations/base.ts | Modified error message formatting and code formatting |
| packages/clients/tanstack-query/src/*.ts | Added CUSTOM_PROC_ROUTE_NAME constant and conditional optimistic update logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
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: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/orm/src/client/crud/operations/base.ts (1)
150-174: Error message includes stringified database error which may leak sensitive information to clients.The error message
Failed to execute query: ${err}is exposed via API responses (in both RPC and REST endpoints). The stringified error${err}could contain database-specific details such as connection strings, schema names, or constraint violations. Instead, use a generic message and reserve detailed error information for server-side logging only.
🤖 Fix all issues with AI agents
In @packages/clients/tanstack-query/src/svelte/index.svelte.ts:
- Around line 579-580: The @ts-ignore comments are hiding a type mismatch
between useQueryClient() and the functions
invalidateQueriesMatchingPredicate/getAllQueries; fix by giving useQueryClient()
(or the local queryClient variable) the correct QueryClient generic type from
TanStack (or import the QueryClient type from
'@tanstack/query-core'/@tanstack/query-core/build/lib/types as used in Vue)
and/or narrow queryClient via an explicit typed cast to QueryClient before
calling invalidateQueriesMatchingPredicate and getAllQueries, and update the
predicate parameter types to match the Vue signature so you can remove the three
@ts-ignore lines around useQueryClient(), invalidateQueriesMatchingPredicate,
and getAllQueries.
In @samples/next.js/lib/db.ts:
- Around line 10-14: The signUp procedure currently spreads all args into
client.user.create (procedures.signUp using client.user.create and args), which
allows clients to set unintended fields; fix this by validating and whitelisting
fields before creating the user—either add a schema check (e.g., Zod/validation
function) or explicitly destructure only allowed properties (email, password,
name, etc.) from args, reject or strip any extra keys, and use the
validated/whitelisted object in client.user.create. Ensure the validation occurs
inside procedures.signUp and returns a clear error for invalid input.
- Line 3: The sample imports SqliteDialect via an indirect re-export from
@zenstackhq/orm/dialects/sqlite; change the import to pull SqliteDialect
directly from the kysely package instead (replace the import that references
@zenstackhq/orm/dialects/sqlite with one that imports SqliteDialect from
'kysely') so the sample relies on the public Kysely API rather than an
undocumented internal path.
In @samples/nuxt/app/pages/index.vue:
- Around line 149-151: The template accesses post.author.name unguarded which
can throw if author is null; update the rendering to only read name when author
exists (e.g., guard with v-if="post.author && !post.$optimistic" or use optional
chaining / a fallback like post.author?.name || 'Unknown') so the <p> block
referencing post.author.name is skipped or shows a safe fallback when author is
null.
- Around line 36-54: In onCreatePost, remove the console.log call and replace
the non-null assertion when picking a random user with a safety check: first
ensure users.value is an array with length > 0, then pick a random index with
Math.floor(Math.random() * users.value.length) and guard against undefined
before using forUser.id; if no users exist, return early or surface an error
instead of proceeding to createPost.mutate.
In @samples/nuxt/server/utils/db.ts:
- Around line 10-14: The signUp procedure currently spreads args directly into
client.user.create (signUp) which lets callers set arbitrary User fields;
replace this by validating/whitelisting allowed signup fields before calling
client.user.create (e.g., explicitly pick only safe fields like email, password,
name) or run args through a schema validator (e.g., Zod/validator) and pass the
validated object to client.user.create; update the signUp procedure to use the
validated/allowlisted payload instead of spreading args to prevent setting
admin/role/internal fields.
In @samples/sveltekit/src/lib/db.ts:
- Around line 10-14: The signUp procedure currently spreads all args into
client.user.create which can let callers set unintended fields; change
procedures.signUp to whitelist and validate allowed fields (e.g., only accept
email, name, password) rather than spreading args, reject or strip any extra
properties, and perform server-side checks (type/format/required) before calling
client.user.create; reference the signUp procedure and client.user.create to
locate where to implement explicit field selection and validation or integrate a
validation schema (e.g., Zod) to enforce the allowed input shape.
In @samples/sveltekit/src/routes/+layout.svelte:
- Around line 24-33: The img tag for the Svelte logo declares width="100"
height="20" which distorts the portrait 429x513 source; update the <img
src="/svelte.png" ...> attributes to preserve aspect ratio (e.g., width="100"
height="120" or set width="100" and height="auto" / remove the fixed height) so
the rendered dimensions match the source aspect ratio and avoid distortion.
🧹 Nitpick comments (10)
packages/server/src/api/common/procedures.ts (1)
4-4: Naming inconsistency:PROCEDURE_ROUTE_PREFIXES(plural) holds a single string value.The variable name uses the plural form "PREFIXES" but contains a single string
'$procs'. Consider renaming toPROCEDURE_ROUTE_PREFIX(singular) for clarity and consistency with the client-side equivalentCUSTOM_PROC_ROUTE_NAME.samples/next.js/app/api/model/[...path]/route.ts (1)
7-7: Debug logging added for development.The addition of
log: ['debug', 'error']is helpful for debugging during development. For production deployments, you may want to adjust the log level to reduce verbosity (e.g., only 'error' or 'warn').samples/sveltekit/src/lib/db.ts (1)
15-23: Consider adding pagination to prevent performance issues.The
listPublicPostsquery has no limit or pagination, which could return large datasets and cause performance/memory issues as the post count grows.⚡ Proposed fix to add pagination support
- listPublicPosts: ({ client }) => + listPublicPosts: ({ client, args }) => { + const { take = 50, skip = 0 } = args as { take?: number; skip?: number }; return client.post.findMany({ where: { published: true, }, orderBy: { updatedAt: "desc", }, + take, + skip, - }), + }); + },samples/next.js/lib/db.ts (2)
15-23: Consider adding pagination to prevent performance issues.The
listPublicPostsquery has no limit or pagination, which could return large datasets and cause performance/memory issues as the post count grows. This is the same issue present insamples/sveltekit/src/lib/db.ts.⚡ Proposed fix to add pagination support
- listPublicPosts: ({ client }) => + listPublicPosts: ({ client, args }) => { + const { take = 50, skip = 0 } = args as { take?: number; skip?: number }; + return client.post.findMany({ where: { published: true, }, orderBy: { updatedAt: 'desc', }, - }), + take, + skip, + }); + },
10-24: Consider extracting duplicated procedure implementations to a shared utility.The
proceduresblock is duplicated identically across three samples (next.js, sveltekit, nuxt). Consider extracting these common procedure implementations to a shared utility insamples/shared/to reduce duplication and maintain consistency.Example structure:
// samples/shared/procedures.ts export const commonProcedures = { signUp: ({ client, args }: { client: any; args: any }) => { const { email, name } = args as { email: string; name?: string }; return client.user.create({ data: { email, name } }); }, listPublicPosts: ({ client, args }: { client: any; args: any }) => { const { take = 50, skip = 0 } = args as { take?: number; skip?: number }; return client.post.findMany({ where: { published: true }, orderBy: { updatedAt: 'desc' }, take, skip, }); }, };samples/next.js/app/signup/page.tsx (1)
35-84: Well-implemented UI with good accessibility practices.The form rendering is solid with proper semantic HTML, loading states, and dark mode support. Consider adding
aria-live="polite"to the success/error message divs for better screen reader support.♿ Optional: Enhance accessibility with aria-live regions
{successMessage && ( - <div className="w-full p-4 rounded-md bg-green-50 border border-green-200 text-green-800 dark:bg-green-900/20 dark:border-green-800 dark:text-green-400"> + <div role="status" aria-live="polite" className="w-full p-4 rounded-md bg-green-50 border border-green-200 text-green-800 dark:bg-green-900/20 dark:border-green-800 dark:text-green-400"> {successMessage} </div> )} {errorMessage && ( - <div className="w-full p-4 rounded-md bg-red-50 border border-red-200 text-red-800 dark:bg-red-900/20 dark:border-red-800 dark:text-red-400"> + <div role="alert" aria-live="assertive" className="w-full p-4 rounded-md bg-red-50 border border-red-200 text-red-800 dark:bg-red-900/20 dark:border-red-800 dark:text-red-400"> {errorMessage} </div> )}samples/next.js/app/feeds/page.tsx (1)
7-9: Query setup is correct for the demo use case.The
useQuery()call properly destructures the TanStack Query result. For production use with potentially large datasets, consider implementing pagination or infinite scroll patterns.samples/sveltekit/src/routes/+layout.svelte (1)
19-21: Improve formatting and follow Svelte conventions.The
svelte:headtag formatting is unconventional and may cause readability issues. Additionally, thehrefattribute unnecessarily quotes the interpolation expression.♻️ Proposed formatting improvement
-<svelte:head - ><link rel="icon" href="{favicon}" -/></svelte:head> +<svelte:head> + <link rel="icon" href={favicon} /> +</svelte:head>samples/sveltekit/src/routes/feeds/+page.svelte (1)
21-35: Consider using{:else if}for mutually exclusive states.The current implementation uses separate
{#if}blocks for loading, error, and empty states. While functionally correct, using{:else if}would make the mutual exclusivity clearer and prevent potential edge cases where multiple states could render simultaneously.♻️ Suggested refactor for clearer state handling
-{#if isLoading} - <div class="text-gray-600 dark:text-gray-400">Loading public posts...</div> -{/if} - -{#if error} +{#if isLoading} + <div class="text-gray-600 dark:text-gray-400">Loading public posts...</div> +{:else if error} <div class="w-full p-4 rounded-md bg-red-50 border border-red-200 text-red-800 dark:bg-red-900/20 dark:border-red-800 dark:text-red-400" > Error loading posts: {error instanceof Error ? error.message : 'Unknown error'} </div> -{/if} - -{#if !isLoading && !error && posts && posts.length === 0} +{:else if posts && posts.length === 0} <div class="text-gray-600 dark:text-gray-400">No public posts available yet.</div> +{:else if posts && posts.length > 0} + <!-- posts list here --> {/if}samples/sveltekit/src/routes/+page.svelte (1)
147-159: Consider adding accessible labels to action buttons.The Delete and Publish buttons use generic text without context for screen readers. Consider adding
aria-labelattributes to improve accessibility.♻️ Add aria-labels for better accessibility
<button class="rounded-md px-2 py-1 text-white cursor-pointer underline text-xs" onclick={() => onDeletePost(post.id)} + aria-label={`Delete post: ${post.title}`} > Delete </button> <button class="rounded-md px-2 py-1 text-white cursor-pointer underline text-xs" onclick={() => onTogglePublishPost(post)} + aria-label={`${post.published ? 'Unpublish' : 'Publish'} post: ${post.title}`} > {post.published ? 'Unpublish' : 'Publish'} </button>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (44)
packages/clients/tanstack-query/src/common/constants.tspackages/clients/tanstack-query/src/react.tspackages/clients/tanstack-query/src/svelte/index.svelte.tspackages/clients/tanstack-query/src/vue.tspackages/orm/src/client/crud/operations/base.tspackages/server/src/api/common/procedures.tssamples/next.js/app/api/model/[...path]/route.tssamples/next.js/app/feeds/page.tsxsamples/next.js/app/layout.tsxsamples/next.js/app/page.tsxsamples/next.js/app/signup/page.tsxsamples/next.js/lib/db.tssamples/next.js/zenstack/input.tssamples/next.js/zenstack/schema-lite.tssamples/next.js/zenstack/schema.tssamples/next.js/zenstack/schema.zmodelsamples/next.js/zenstack/schema.zmodelsamples/next.js/zenstack/seed.tssamples/nuxt/app/app.vuesamples/nuxt/app/layouts/default.vuesamples/nuxt/app/pages/feeds.vuesamples/nuxt/app/pages/index.vuesamples/nuxt/app/pages/signup.vuesamples/nuxt/app/plugins/tanstack-query.tssamples/nuxt/server/api/model/[...].tssamples/nuxt/server/utils/db.tssamples/nuxt/zenstack/input.tssamples/nuxt/zenstack/schema-lite.tssamples/nuxt/zenstack/schema.tssamples/nuxt/zenstack/schema.zmodelsamples/nuxt/zenstack/schema.zmodelsamples/nuxt/zenstack/seed.tssamples/shared/schema.zmodelsamples/sveltekit/src/app.d.tssamples/sveltekit/src/lib/db.tssamples/sveltekit/src/routes/+layout.sveltesamples/sveltekit/src/routes/+page.sveltesamples/sveltekit/src/routes/feeds/+page.sveltesamples/sveltekit/src/routes/signup/+page.sveltesamples/sveltekit/src/zenstack/input.tssamples/sveltekit/src/zenstack/schema-lite.tssamples/sveltekit/src/zenstack/schema.tssamples/sveltekit/src/zenstack/schema.zmodelsamples/sveltekit/src/zenstack/schema.zmodel
🧰 Additional context used
📓 Path-based instructions (1)
**/*.zmodel
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.zmodel: Always runzenstack generateafter modifying ZModel schemas
ZModel schema files should define database structure and policies that compile to TypeScript viazenstack generate
Files:
samples/nuxt/zenstack/schema.zmodelsamples/sveltekit/src/zenstack/schema.zmodelsamples/next.js/zenstack/schema.zmodelsamples/shared/schema.zmodel
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : Always run `zenstack generate` after modifying ZModel schemas
📚 Learning: 2025-12-30T15:07:06.254Z
Learnt from: mwillbanks
Repo: zenstackhq/zenstack-v3 PR: 550
File: packages/orm/src/client/crud/operations/base.ts:158-159
Timestamp: 2025-12-30T15:07:06.254Z
Learning: Do not use ts-expect-error in production code within the zenstackhq/zenstack-v3 repo (e.g., packages/*). Use explicit type annotations, targeted type assertions, or refactor to resolve the type error. ts-expect-error may be acceptable only in test files for stubbing or temporary silencing. Ensure production code is type-safe and maintainable.
Applied to files:
packages/clients/tanstack-query/src/common/constants.tspackages/orm/src/client/crud/operations/base.tspackages/server/src/api/common/procedures.tspackages/clients/tanstack-query/src/react.tspackages/clients/tanstack-query/src/svelte/index.svelte.tspackages/clients/tanstack-query/src/vue.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`
Applied to files:
samples/nuxt/zenstack/schema.tssamples/next.js/zenstack/schema.tssamples/nuxt/zenstack/schema-lite.tssamples/next.js/lib/db.tssamples/next.js/zenstack/seed.tssamples/next.js/zenstack/schema-lite.tssamples/nuxt/server/utils/db.tssamples/sveltekit/src/zenstack/input.tssamples/nuxt/zenstack/seed.tssamples/nuxt/zenstack/input.tssamples/shared/schema.zmodelsamples/next.js/zenstack/input.tssamples/sveltekit/src/zenstack/schema-lite.tssamples/sveltekit/src/zenstack/schema.ts
📚 Learning: 2025-10-21T16:09:31.218Z
Learnt from: ymc9
Repo: zenstackhq/zenstack-v3 PR: 319
File: packages/runtime/src/client/executor/zenstack-query-executor.ts:63-72
Timestamp: 2025-10-21T16:09:31.218Z
Learning: In ZenStack, TypeDefs can be inherited by models. When a TypeDef contains fields with `map` attributes, those mapped field names need to be processed by the QueryNameMapper since they become part of the inheriting model's schema. Therefore, when checking if a schema has mapped names (e.g., in `schemaHasMappedNames`), both `schema.models` and `schema.typeDefs` must be inspected for `@map` and `map` attributes.
Applied to files:
samples/next.js/zenstack/schema.tssamples/next.js/zenstack/schema-lite.tspackages/clients/tanstack-query/src/svelte/index.svelte.tssamples/sveltekit/src/zenstack/schema-lite.tssamples/sveltekit/src/zenstack/schema.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization
Applied to files:
packages/server/src/api/common/procedures.tssamples/next.js/lib/db.tssamples/next.js/zenstack/seed.tssamples/nuxt/server/utils/db.tssamples/sveltekit/src/zenstack/input.tspackages/clients/tanstack-query/src/react.tssamples/nuxt/zenstack/seed.tssamples/nuxt/zenstack/input.tspackages/clients/tanstack-query/src/svelte/index.svelte.tspackages/clients/tanstack-query/src/vue.tssamples/next.js/zenstack/input.tssamples/sveltekit/src/zenstack/schema-lite.tssamples/nuxt/app/plugins/tanstack-query.tssamples/sveltekit/src/zenstack/schema.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Use Kysely as the query builder interface for low-level database queries, avoiding raw SQL when possible
Applied to files:
samples/next.js/lib/db.tssamples/next.js/zenstack/seed.tssamples/nuxt/server/utils/db.tssamples/sveltekit/src/zenstack/input.tspackages/clients/tanstack-query/src/react.tssamples/nuxt/zenstack/seed.tssamples/nuxt/zenstack/input.tspackages/clients/tanstack-query/src/vue.tssamples/next.js/zenstack/input.tssamples/sveltekit/src/zenstack/schema.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Database migrations should use Prisma CLI under the hood via ZenStack commands
Applied to files:
samples/next.js/lib/db.tssamples/next.js/zenstack/seed.tssamples/nuxt/server/utils/db.tssamples/nuxt/zenstack/seed.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Support only SQLite (better-sqlite3) and PostgreSQL (pg) as database adapters
Applied to files:
samples/next.js/lib/db.ts
📚 Learning: 2025-12-30T15:07:10.092Z
Learnt from: mwillbanks
Repo: zenstackhq/zenstack-v3 PR: 550
File: packages/orm/src/client/crud/operations/base.ts:158-159
Timestamp: 2025-12-30T15:07:10.092Z
Learning: In the zenstackhq/zenstack-v3 codebase, ts-expect-error should be heavily avoided in production code (packages/*). It is acceptable in test files but production code should use proper type annotations, type assertions, or refactoring to resolve type errors instead.
Applied to files:
samples/next.js/zenstack/seed.tssamples/nuxt/zenstack/seed.tssamples/nuxt/zenstack/input.tssamples/next.js/zenstack/input.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests
Applied to files:
samples/next.js/zenstack/seed.tssamples/nuxt/server/utils/db.tssamples/sveltekit/src/zenstack/input.tssamples/nuxt/zenstack/seed.tssamples/nuxt/zenstack/input.tssamples/next.js/zenstack/input.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects
Applied to files:
samples/next.js/zenstack/input.ts
🧬 Code graph analysis (10)
samples/next.js/app/signup/page.tsx (2)
packages/clients/tanstack-query/src/react.ts (1)
useClientQueries(336-397)samples/next.js/zenstack/schema-lite.ts (1)
schema(120-120)
samples/next.js/lib/db.ts (2)
samples/nuxt/server/utils/db.ts (1)
db(6-25)samples/sveltekit/src/lib/db.ts (1)
db(6-25)
samples/nuxt/server/utils/db.ts (4)
samples/next.js/lib/db.ts (1)
db(6-25)samples/sveltekit/src/lib/db.ts (1)
db(6-25)samples/nuxt/zenstack/schema-lite.ts (1)
schema(120-120)samples/nuxt/zenstack/schema.ts (1)
schema(129-129)
samples/sveltekit/src/zenstack/input.ts (2)
samples/next.js/zenstack/input.ts (21)
UserFindManyArgs(11-11)UserFindUniqueArgs(12-12)UserFindFirstArgs(13-13)UserExistsArgs(14-14)UserCreateArgs(15-15)UserCreateManyArgs(16-16)UserCreateManyAndReturnArgs(17-17)UserUpdateArgs(18-18)UserUpdateManyArgs(19-19)UserGetPayload(31-31)PostFindManyArgs(32-32)PostFindUniqueArgs(33-33)PostFindFirstArgs(34-34)PostExistsArgs(35-35)PostCreateArgs(36-36)PostCreateManyArgs(37-37)PostCreateManyAndReturnArgs(38-38)PostUpdateArgs(39-39)PostUpdateManyArgs(40-40)PostUpdateManyAndReturnArgs(41-41)PostGetPayload(52-52)samples/nuxt/zenstack/input.ts (21)
UserFindManyArgs(11-11)UserFindUniqueArgs(12-12)UserFindFirstArgs(13-13)UserExistsArgs(14-14)UserCreateArgs(15-15)UserCreateManyArgs(16-16)UserCreateManyAndReturnArgs(17-17)UserUpdateArgs(18-18)UserUpdateManyArgs(19-19)UserGetPayload(31-31)PostFindManyArgs(32-32)PostFindUniqueArgs(33-33)PostFindFirstArgs(34-34)PostExistsArgs(35-35)PostCreateArgs(36-36)PostCreateManyArgs(37-37)PostCreateManyAndReturnArgs(38-38)PostUpdateArgs(39-39)PostUpdateManyArgs(40-40)PostUpdateManyAndReturnArgs(41-41)PostGetPayload(52-52)
packages/clients/tanstack-query/src/react.ts (3)
packages/clients/tanstack-query/src/common/constants.ts (1)
CUSTOM_PROC_ROUTE_NAME(1-1)packages/clients/tanstack-query/src/common/client.ts (2)
invalidateQueriesMatchingPredicate(5-15)getAllQueries(17-41)packages/clients/client-helpers/src/optimistic.ts (1)
createOptimisticUpdater(68-139)
samples/nuxt/zenstack/input.ts (2)
samples/next.js/zenstack/input.ts (5)
UserFindManyArgs(11-11)UserFindUniqueArgs(12-12)UserFindFirstArgs(13-13)UserExistsArgs(14-14)PostExistsArgs(35-35)samples/sveltekit/src/zenstack/input.ts (5)
UserFindManyArgs(36-36)UserFindUniqueArgs(37-37)UserFindFirstArgs(38-38)UserExistsArgs(39-39)PostExistsArgs(69-69)
samples/next.js/app/feeds/page.tsx (2)
packages/clients/tanstack-query/src/react.ts (1)
useClientQueries(336-397)samples/next.js/zenstack/schema-lite.ts (1)
schema(120-120)
packages/clients/tanstack-query/src/vue.ts (3)
packages/clients/tanstack-query/src/common/constants.ts (1)
CUSTOM_PROC_ROUTE_NAME(1-1)packages/clients/client-helpers/src/invalidation.ts (2)
createInvalidator(26-44)InvalidationPredicate(9-9)packages/clients/tanstack-query/src/common/client.ts (2)
invalidateQueriesMatchingPredicate(5-15)getAllQueries(17-41)
samples/sveltekit/src/zenstack/schema-lite.ts (1)
packages/schema/src/expression-utils.ts (1)
ExpressionUtils(19-123)
samples/sveltekit/src/zenstack/schema.ts (1)
packages/schema/src/expression-utils.ts (1)
ExpressionUtils(19-123)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-test (22.x, sqlite)
- GitHub Check: build-test (22.x, postgresql)
🔇 Additional comments (57)
samples/nuxt/server/api/model/[...].ts (1)
7-7: Remove thelogoption from RPCApiHandler—it's not supported by this component.The
log: ['debug', 'error']option is not accepted byRPCApiHandler. Logging configuration belongs on the ORM client (ZenStackClient / Kysely or Prisma), not the handler. Pass the log settings when creating the database client instead. For a sample application, this is important to demonstrate the correct usage pattern to users.⛔ Skipped due to learnings
Learnt from: CR Repo: zenstackhq/zenstack-v3 PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-11-26T01:55:04.540Z Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy testsLearnt from: CR Repo: zenstackhq/zenstack-v3 PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-11-26T01:55:04.540Z Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Use Kysely as the query builder interface for low-level database queries, avoiding raw SQL when possibleLearnt from: CR Repo: zenstackhq/zenstack-v3 PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-11-26T01:55:04.540Z Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customizationLearnt from: mwillbanks Repo: zenstackhq/zenstack-v3 PR: 550 File: packages/orm/src/client/crud/operations/base.ts:158-159 Timestamp: 2025-12-30T15:07:10.092Z Learning: In the zenstackhq/zenstack-v3 codebase, ts-expect-error should be heavily avoided in production code (packages/*). It is acceptable in test files but production code should use proper type annotations, type assertions, or refactoring to resolve type errors instead.samples/nuxt/app/plugins/tanstack-query.ts (1)
14-16: LGTM! Formatting change only.The trailing comma addition and spacing adjustment are purely cosmetic with no functional impact.
samples/next.js/zenstack/schema.ts (1)
113-126: LGTM! Generated schema procedures.The new
proceduresblock correctly definessignUpandlistPublicPostsoperations as generated by ZenStack CLI. This is expected output from the schema compilation process.samples/sveltekit/src/app.d.ts (1)
4-10: LGTM! Formatting adjustment.Indentation changes to the namespace declaration with no functional impact.
samples/nuxt/zenstack/input.ts (1)
9-9: LGTM! Generated type exports.The addition of
ExistsArgsimport and theUserExistsArgs/PostExistsArgstype exports are consistent with the pattern in other framework samples and are generated by ZenStack CLI as expected.Also applies to: 14-14, 35-35
samples/nuxt/app/app.vue (1)
1-5: LGTM! Clean refactoring to layout composition pattern.The component has been simplified to use Nuxt's layout composition approach, delegating page-specific logic to child routes. This is a cleaner architecture for the sample application.
samples/next.js/app/layout.tsx (1)
2-2: LGTM! Proper Next.js 15 Image usage and layout structure.The Image component is correctly configured with required props (width, height, alt) and the priority flag for above-the-fold content. The responsive layout uses standard Tailwind utilities compatible with the framework version in use.
Also applies to: 24-38
samples/nuxt/zenstack/schema.ts (1)
113-126: Generated code reflects new procedures definition.This file is auto-generated by ZenStack CLI (as indicated in the header). The new
proceduresblock correctly defines thesignUpandlistPublicPostsoperations based on the source schema.Reminder: Based on learnings, ensure you run
zenstack generateafter modifying the source.zmodelschema files to keep this generated code in sync.samples/next.js/zenstack/input.ts (1)
9-9: LGTM! Generated type exports for exists operations.This auto-generated file correctly adds
ExistsArgstype exports for User and Post models, following the established pattern for other operation types (FindMany, Create, Update, etc.).Also applies to: 14-14, 35-35
samples/next.js/zenstack/schema-lite.ts (1)
104-117: Generated code structure looks correct.The procedures definition correctly reflects the schema operations:
signUp: properly configured as a mutation with email parameterlistPublicPosts: properly configured as a query returning an arraySince this is an auto-generated file, ensure that any future modifications are made to the source
.zmodelfile followed by runningzenstack generate.samples/shared/schema.zmodel (5)
1-4: LGTM!The SQLite datasource configuration is appropriate for a sample application.
7-14: LGTM!The User model is well-structured with appropriate constraints and relationships:
- CUID for distributed-friendly IDs
- Unique email constraint
- Proper timestamp tracking
- Correct one-to-many relationship with Post
17-25: LGTM!The Post model is correctly structured with:
- Proper relationship to User with cascade rules ensuring referential integrity
- Sensible default for
published(false for draft state)- Consistent ID generation strategy
27-28: LGTM!The procedure definitions are correct:
signUp: appropriately marked as mutation for user creationlistPublicPosts: read-only query returning Post arrayBoth align with the generated TypeScript in
schema-lite.ts.
1-28: Ensurezenstack generateis executed after schema modifications.As per coding guidelines, after modifying ZModel schemas, you must run the generation command to compile the schema to TypeScript and keep generated files in sync.
Based on coding guidelines: "Always run
zenstack generateafter modifying ZModel schemas"Run the following command to regenerate the TypeScript schema files:
#!/bin/bash # Generate TypeScript from ZModel schema zenstack generatesamples/nuxt/server/utils/db.ts (2)
2-2: Import paths updated correctly.The import paths for
SqliteDialectandschemaare consistent with the project structure and match the patterns used in other sample applications.Also applies to: 4-4
15-23: listPublicPosts procedure implementation looks good.The procedure correctly filters by
published: trueand orders results byupdatedAtdescending, providing a safe public API for fetching posts.samples/next.js/app/page.tsx (2)
77-95: UI restructure improves navigation.The replacement of the image logo with a text heading and navigation buttons (View Public Feeds, Sign Up) provides clear entry points to the new features introduced in this PR. The Link-based navigation is appropriate for client-side routing in Next.js.
97-177: Core functionality preserved correctly.All existing data fetching, mutations, and UI interactions (create post, delete post, toggle publish, filters, optimistic updates) remain intact. The structural reorganization maintains the same user experience while improving the layout.
samples/nuxt/app/layouts/default.vue (1)
1-10: LGTM!The layout component is well-structured with appropriate responsive and dark mode styling. The centered container with constrained width provides a clean chrome for the Nuxt pages.
samples/nuxt/zenstack/seed.ts (2)
3-13: LGTM!The seeding logic correctly uses the centralized db instance to clear and populate test users.
1-1: The centralized db import is correctly set up and properly exported fromserver/utils/db.tsas a ZenStackClient instance.packages/clients/tanstack-query/src/common/constants.ts (1)
1-1: LGTM!Centralizing the custom procedure route name as a constant is excellent practice. This ensures consistency across all framework integrations (React, Svelte, Vue) and makes future updates easier.
samples/sveltekit/src/routes/signup/+page.svelte (2)
1-30: LGTM!The script logic is well-implemented:
- Proper use of Svelte 5 runes for reactive state
- Correct integration with TanStack Query via
useClientQueries- Clean mutation handling with appropriate callbacks
- Error handling includes fallback message for non-Error objects
- Form state is properly cleared on success
32-86: LGTM!The template is well-structured with:
- Semantic HTML form elements
- Proper accessibility (labels, required attributes)
- Disabled states during mutation to prevent double submission
- Clear visual feedback for success and error states
- Responsive design with dark mode support
- Good UX with dynamic button text and form disabling
samples/next.js/zenstack/seed.ts (1)
1-13: LGTM! Clean refactoring to use centralized db instance.The change correctly refactors the seed script to use the centralized database instance from
@/lib/db, eliminating duplicate initialization code. The seeding logic remains unchanged and functional.samples/nuxt/zenstack/schema-lite.ts (1)
1-4: No action needed. The source ZModel schema (samples/shared/schema.zmodel) correctly defines both thesignUpandlistPublicPostsprocedures, which are properly reflected in the generated file at lines 104-117. The file is correctly auto-generated and contains the expected procedures definition.Likely an incorrect or invalid review comment.
samples/next.js/app/signup/page.tsx (3)
1-6: LGTM!The imports and 'use client' directive are correctly configured for a Next.js client component with form handling and TanStack Query integration.
8-14: LGTM!The component setup correctly uses the new
$procsAPI for accessing custom procedures. State management is clean and appropriate for form handling.
16-33: LGTM!The form submission handler is well-structured with proper error handling and user feedback. The mutation callbacks correctly handle success and error states, and the UX is thoughtful (clearing form on success, resetting messages on new submission).
samples/next.js/app/feeds/page.tsx (2)
1-5: LGTM!The imports are correctly configured for a client-side data fetching component using the ZenStack TanStack Query integration.
11-58: Excellent state management and UI implementation.The component properly handles all query states (loading, error, empty, success) with clear user feedback. The date formatting using
toLocaleDateString()is locale-aware, and the pluralization logic is correct. Dark mode support is comprehensive throughout.samples/sveltekit/src/routes/+layout.svelte (1)
2-16: The endpoint configuration is correct.The formatting updates (quote consistency, indentation) look good. The endpoint
/api/modelis appropriate—it's the standard endpoint used consistently across all sample projects (Next.js, Nuxt, SvelteKit) and is the default query endpoint. TheCUSTOM_PROC_ROUTE_NAMEconstant ('$procs') is an internal client-side routing mechanism, not an HTTP endpoint path, and the RPC API handler at/api/modelcorrectly handles both model and custom procedure requests.samples/nuxt/app/pages/signup.vue (2)
1-29: LGTM - Well-structured signup page implementation.The reactive state management, mutation handling with success/error callbacks, and form submission logic are correctly implemented. The use of
isPendingto disable the form during submission prevents double-submissions.Consider adding type annotations for the
useranderrorparameters in the callbacks for improved type safety, though this is acceptable for sample code:onSuccess: (user: { email: string }) => { ... }
32-79: Clean template with proper accessibility and state handling.Good use of:
@submit.preventto handle form submission:disabledbinding for both input and button during pending state- Conditional message rendering with appropriate styling for success/error states
samples/sveltekit/src/routes/feeds/+page.svelte (1)
1-7: LGTM - Clean query setup for public feeds.The destructuring of query results and usage of the
$procsnamespace for custom procedures follows the established pattern.samples/sveltekit/src/routes/+page.svelte (2)
22-29: LGTM - Improved readability with multi-line formatting.The reformatted
useFindManycall clearly separates the query arguments from the options, making the code easier to read and maintain.
79-92: Good addition of navigation links to new features.The links to
/feedsand/signupintegrate well with the new pages added in this PR.samples/sveltekit/src/zenstack/input.ts (1)
1-95: Auto-generated file - no review needed.This file is automatically generated by ZenStack CLI as indicated by the header. The changes (added
ExistsArgstypes and formatting adjustments) are consistent with the generated output in other sample projects (samples/next.js/zenstack/input.ts,samples/nuxt/zenstack/input.ts).samples/nuxt/app/pages/feeds.vue (3)
1-7: LGTM - Clean query setup matching the established pattern.The use of
useClientQueriesand the$procsnamespace for custom procedures is consistent with the Vue integration.
20-31: Same state handling pattern as SvelteKit - consider consistency.The conditional rendering uses separate
v-ifblocks similar to the SvelteKit version. Vue'sv-else-ifcould make state transitions clearer, though the current implementation is functionally correct.
33-46: LGTM - Proper list rendering with key binding.Good use of
:key="post.id"for efficient Vue list rendering.samples/sveltekit/src/zenstack/schema-lite.ts (1)
1-124: Auto-generated file - no review needed.This file is automatically generated by ZenStack CLI from ZModel schema files. The structure follows ZenStack conventions with proper model definitions, relations, and procedure declarations. Based on learnings, always run
zenstack generateafter modifying ZModel schemas to regenerate this file.packages/clients/tanstack-query/src/svelte/index.svelte.ts (6)
59-59: Good use of centralized constant for procedure routing.Importing
CUSTOM_PROC_ROUTE_NAMEfrom a shared constants file ensures consistency across React, Vue, and Svelte integrations.
301-333: LGTM - Clean refactor to parameterless procedure hook builder.The removal of the
endpointModelparameter in favor of directly usingCUSTOM_PROC_ROUTE_NAMEsimplifies the API and ensures consistency across framework integrations.
549-551: Good separation of custom procedure logic.The guard
model !== CUSTOM_PROC_ROUTE_NAMEcorrectly excludes custom procedures from the model-specific optimistic update and invalidation logic, as custom procedures don't follow the standard CRUD model pattern.
584-591: LGTM - Correct onMutate sequencing for optimistic updates.The optimistic updater runs before the user's
onMutate, ensuring the cache is updated optimistically before any user logic executes. The return value fromorigOnMutateis correctly propagated for potential rollback context.
605-616: LGTM - Correct onSettled sequencing for invalidation.Running the invalidator before the user's
onSettledensures the cache is refreshed with server data before user cleanup logic runs, which is the expected behavior for optimistic updates.
565-571: Callback sequencing matches React implementation.The Svelte implementation correctly runs the invalidator before the user's
onSuccesscallback, consistent with React's implementation. Both explicitly wrap the callback to ensure cache invalidation happens first.packages/clients/tanstack-query/src/vue.ts (3)
57-57: LGTM!Clean import of the centralized constant for procedure routing.
313-345: LGTM!The refactored
buildProcedureHookscorrectly routes all procedure queries and mutations throughCUSTOM_PROC_ROUTE_NAME, aligning with the centralized routing approach.
568-630: LGTM - Well-structured mutation handling for custom procedures.The branching logic correctly:
- Skips invalidation/optimistic updates for custom procedures (
CUSTOM_PROC_ROUTE_NAME)- Runs invalidation in
onSuccessfor non-optimistic mutations- Runs optimistic updates in
onMutateand invalidation inonSettledfor optimistic mutations- Ensures internal handlers execute before user-provided callbacks
packages/clients/tanstack-query/src/react.ts (3)
58-58: LGTM!Consistent import of the centralized routing constant.
354-393: LGTM!The React implementation correctly mirrors the Vue pattern while including React-specific hooks (
useSuspenseQuery,useInfiniteQuery,useSuspenseInfiniteQuery). All procedure hooks properly route throughCUSTOM_PROC_ROUTE_NAME.
655-718: LGTM - Consistent with Vue implementation.The React mutation handling correctly implements the same callback sequencing pattern:
- Custom procedures bypass invalidation/optimistic logic
- Non-optimistic: invalidation runs before user
onSuccess- Optimistic: updates run before user
onMutate, invalidation runs before useronSettledThe implementations are functionally consistent across both frameworks, with appropriate framework-specific differences (React doesn't need Vue's
unref()).samples/sveltekit/src/zenstack/schema.ts (2)
1-4: Auto-generated file - no manual modifications needed.This file is automatically generated by ZenStack CLI. The changes here reflect the new procedures (
signUpandlistPublicPosts) that were added to the source schema.
162-175: Procedures definition looks correct.The auto-generated procedures block properly defines:
signUpas a mutation withUserlistPublicPostsas a query (nomutationflag) returningPost[]This aligns with the tanstack-query client implementations that route procedures through
CUSTOM_PROC_ROUTE_NAME.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |

Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.