@kood/claude-code 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/agents/code-reviewer.md +124 -124
- package/templates/.claude/agents/dependency-manager.md +85 -85
- package/templates/.claude/agents/deployment-validator.md +56 -56
- package/templates/.claude/agents/git-operator.md +64 -64
- package/templates/.claude/agents/implementation-executor.md +95 -95
- package/templates/.claude/agents/ko-to-en-translator.md +74 -0
- package/templates/.claude/agents/lint-fixer.md +78 -78
- package/templates/.claude/agents/refactor-advisor.md +122 -122
- package/templates/.claude/commands/agent-creator.md +185 -185
- package/templates/.claude/commands/bug-fix.md +193 -193
- package/templates/.claude/commands/command-creator.md +54 -54
- package/templates/.claude/commands/docs-creator.md +57 -57
- package/templates/.claude/commands/docs-refactor.md +26 -26
- package/templates/.claude/commands/execute.md +12 -12
- package/templates/.claude/commands/git-all.md +32 -32
- package/templates/.claude/commands/git-session.md +42 -42
- package/templates/.claude/commands/git.md +34 -34
- package/templates/.claude/commands/lint-fix.md +138 -138
- package/templates/.claude/commands/lint-init.md +61 -61
- package/templates/.claude/commands/plan.md +260 -260
- package/templates/.claude/commands/prd.md +24 -24
- package/templates/.claude/commands/pre-deploy.md +109 -109
- package/templates/.claude/commands/refactor.md +147 -147
- package/templates/.claude/commands/version-update.md +17 -17
- package/templates/hono/CLAUDE.md +27 -27
- package/templates/hono/docs/architecture.md +24 -24
- package/templates/hono/docs/deployment/cloudflare.md +18 -18
- package/templates/hono/docs/deployment/docker.md +13 -13
- package/templates/hono/docs/deployment/index.md +19 -19
- package/templates/hono/docs/deployment/railway.md +32 -32
- package/templates/hono/docs/deployment/vercel.md +29 -29
- package/templates/hono/docs/guides/conventions.md +57 -57
- package/templates/hono/docs/guides/env-setup.md +47 -47
- package/templates/hono/docs/guides/getting-started.md +27 -27
- package/templates/hono/docs/library/hono/error-handling.md +11 -11
- package/templates/hono/docs/library/hono/index.md +4 -4
- package/templates/hono/docs/library/hono/middleware.md +18 -18
- package/templates/hono/docs/library/hono/rpc.md +7 -7
- package/templates/hono/docs/library/hono/validation.md +6 -6
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +29 -29
- package/templates/hono/docs/library/prisma/config.md +16 -16
- package/templates/hono/docs/library/prisma/index.md +32 -32
- package/templates/hono/docs/library/t3-env/index.md +22 -22
- package/templates/hono/docs/library/zod/index.md +31 -31
- package/templates/nextjs/CLAUDE.md +51 -51
- package/templates/nextjs/docs/design.md +183 -183
- package/templates/nextjs/docs/guides/conventions.md +86 -86
- package/templates/nextjs/docs/guides/getting-started.md +28 -28
- package/templates/nextjs/docs/guides/routes.md +32 -32
- package/templates/nextjs/docs/library/better-auth/index.md +70 -70
- package/templates/nextjs/docs/library/nextjs/app-router.md +43 -43
- package/templates/nextjs/docs/library/nextjs/caching.md +73 -73
- package/templates/nextjs/docs/library/nextjs/index.md +51 -51
- package/templates/nextjs/docs/library/nextjs/middleware.md +41 -41
- package/templates/nextjs/docs/library/nextjs/route-handlers.md +31 -31
- package/templates/nextjs/docs/library/nextjs/server-actions.md +34 -34
- package/templates/nextjs/docs/library/prisma/cloudflare-d1.md +20 -20
- package/templates/nextjs/docs/library/prisma/config.md +18 -18
- package/templates/nextjs/docs/library/prisma/crud.md +17 -17
- package/templates/nextjs/docs/library/prisma/index.md +18 -18
- package/templates/nextjs/docs/library/prisma/relations.md +16 -16
- package/templates/nextjs/docs/library/prisma/schema.md +23 -23
- package/templates/nextjs/docs/library/prisma/setup.md +6 -6
- package/templates/nextjs/docs/library/prisma/transactions.md +10 -10
- package/templates/nextjs/docs/library/tanstack-query/index.md +6 -6
- package/templates/nextjs/docs/library/tanstack-query/invalidation.md +20 -20
- package/templates/nextjs/docs/library/tanstack-query/optimistic-updates.md +4 -4
- package/templates/nextjs/docs/library/tanstack-query/use-mutation.md +15 -15
- package/templates/nextjs/docs/library/tanstack-query/use-query.md +22 -22
- package/templates/nextjs/docs/library/zod/complex-types.md +11 -11
- package/templates/nextjs/docs/library/zod/index.md +8 -8
- package/templates/nextjs/docs/library/zod/transforms.md +11 -11
- package/templates/nextjs/docs/library/zod/validation.md +9 -9
- package/templates/npx/CLAUDE.md +37 -37
- package/templates/npx/docs/library/commander/index.md +12 -12
- package/templates/npx/docs/library/fs-extra/index.md +9 -9
- package/templates/npx/docs/library/prompts/index.md +3 -3
- package/templates/npx/docs/references/patterns.md +12 -12
- package/templates/tanstack-start/CLAUDE.md +53 -53
- package/templates/tanstack-start/docs/architecture.md +128 -128
- package/templates/tanstack-start/docs/design.md +169 -169
- package/templates/tanstack-start/docs/guides/conventions.md +43 -43
- package/templates/tanstack-start/docs/guides/env-setup.md +35 -35
- package/templates/tanstack-start/docs/guides/getting-started.md +19 -19
- package/templates/tanstack-start/docs/guides/hooks.md +45 -45
- package/templates/tanstack-start/docs/guides/routes.md +54 -54
- package/templates/tanstack-start/docs/guides/services.md +45 -45
- package/templates/tanstack-start/docs/library/better-auth/index.md +68 -68
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +19 -19
- package/templates/tanstack-start/docs/library/prisma/config.md +16 -16
- package/templates/tanstack-start/docs/library/prisma/crud.md +17 -17
- package/templates/tanstack-start/docs/library/prisma/index.md +17 -17
- package/templates/tanstack-start/docs/library/prisma/relations.md +16 -16
- package/templates/tanstack-start/docs/library/prisma/schema.md +23 -23
- package/templates/tanstack-start/docs/library/prisma/setup.md +6 -6
- package/templates/tanstack-start/docs/library/prisma/transactions.md +10 -10
- package/templates/tanstack-start/docs/library/t3-env/index.md +21 -160
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +6 -6
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +19 -19
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +4 -4
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +14 -14
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +21 -21
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +9 -9
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +11 -11
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +18 -18
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +17 -17
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +5 -5
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +10 -10
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +8 -8
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +15 -15
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +9 -9
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +6 -6
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +18 -18
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +4 -4
- package/templates/tanstack-start/docs/library/zod/complex-types.md +11 -11
- package/templates/tanstack-start/docs/library/zod/index.md +8 -8
- package/templates/tanstack-start/docs/library/zod/transforms.md +11 -11
- package/templates/tanstack-start/docs/library/zod/validation.md +9 -9
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# Prisma -
|
|
1
|
+
# Prisma - Schema Definition (Multi-File)
|
|
2
2
|
|
|
3
|
-
## ⚠️
|
|
3
|
+
## ⚠️ Required Rules
|
|
4
4
|
|
|
5
|
-
1. **Multi-File
|
|
6
|
-
2.
|
|
5
|
+
1. **Use Multi-File structure**
|
|
6
|
+
2. **Add comments to all elements** (files, models, fields, enums)
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Structure
|
|
9
9
|
|
|
10
10
|
```
|
|
11
11
|
prisma/schema/
|
|
12
12
|
├── +base.prisma # datasource, generator
|
|
13
|
-
├── +enum.prisma #
|
|
14
|
-
├── user.prisma # User
|
|
15
|
-
└── post.prisma # Post
|
|
13
|
+
├── +enum.prisma # all enums
|
|
14
|
+
├── user.prisma # User model
|
|
15
|
+
└── post.prisma # Post model
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Example
|
|
19
19
|
|
|
20
20
|
```prisma
|
|
21
21
|
// +base.prisma
|
|
@@ -31,24 +31,24 @@ generator client {
|
|
|
31
31
|
|
|
32
32
|
// +enum.prisma
|
|
33
33
|
enum Role {
|
|
34
|
-
USER //
|
|
35
|
-
ADMIN //
|
|
34
|
+
USER // regular user
|
|
35
|
+
ADMIN // administrator
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// user.prisma
|
|
39
39
|
model User {
|
|
40
40
|
id Int @id @default(autoincrement())
|
|
41
|
-
email String @unique //
|
|
42
|
-
name String? //
|
|
41
|
+
email String @unique // login email
|
|
42
|
+
name String? // display name
|
|
43
43
|
role Role @default(USER)
|
|
44
|
-
posts Post[] //
|
|
45
|
-
profile Profile? //
|
|
44
|
+
posts Post[] // authored posts (1:N)
|
|
45
|
+
profile Profile? // user profile (1:1)
|
|
46
46
|
createdAt DateTime @default(now())
|
|
47
47
|
updatedAt DateTime @updatedAt
|
|
48
48
|
}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
##
|
|
51
|
+
## Relation Types
|
|
52
52
|
|
|
53
53
|
```prisma
|
|
54
54
|
// 1:1
|
|
@@ -64,11 +64,11 @@ model Post {
|
|
|
64
64
|
authorId Int
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// M:N (
|
|
67
|
+
// M:N (implicit)
|
|
68
68
|
model Post { categories Category[] }
|
|
69
69
|
model Category { posts Post[] }
|
|
70
70
|
|
|
71
|
-
// M:N (
|
|
71
|
+
// M:N (explicit)
|
|
72
72
|
model CategoriesOnPosts {
|
|
73
73
|
post Post @relation(fields: [postId], references: [id])
|
|
74
74
|
postId Int
|
|
@@ -78,21 +78,21 @@ model CategoriesOnPosts {
|
|
|
78
78
|
}
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
##
|
|
81
|
+
## Others
|
|
82
82
|
|
|
83
83
|
```prisma
|
|
84
|
-
//
|
|
84
|
+
// Optional relation
|
|
85
85
|
author User? @relation(fields: [authorId], references: [id])
|
|
86
86
|
authorId Int?
|
|
87
87
|
|
|
88
|
-
//
|
|
88
|
+
// Index
|
|
89
89
|
@@index([authorId])
|
|
90
90
|
@@index([createdAt])
|
|
91
91
|
|
|
92
|
-
//
|
|
92
|
+
// Composite key
|
|
93
93
|
@@id([postId, tagId])
|
|
94
94
|
|
|
95
|
-
//
|
|
95
|
+
// Mapping
|
|
96
96
|
@map("user_id")
|
|
97
97
|
@@map("users")
|
|
98
98
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Prisma -
|
|
1
|
+
# Prisma - Installation and Setup
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Installation
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
yarn add @prisma/client@7
|
|
@@ -8,15 +8,15 @@ yarn add -D prisma@7
|
|
|
8
8
|
npx prisma init
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## v6 → v7
|
|
11
|
+
## v6 → v7 Upgrade
|
|
12
12
|
|
|
13
13
|
```prisma
|
|
14
|
-
// v6 (
|
|
14
|
+
// v6 (old)
|
|
15
15
|
generator client {
|
|
16
16
|
provider = "prisma-client-js"
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// v7 (
|
|
19
|
+
// v7 (required)
|
|
20
20
|
generator client {
|
|
21
21
|
provider = "prisma-client"
|
|
22
22
|
output = "../generated/prisma"
|
|
@@ -34,7 +34,7 @@ export const prisma = globalForPrisma.prisma ?? new PrismaClient({ log: ['query'
|
|
|
34
34
|
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
## TanStack Start
|
|
37
|
+
## TanStack Start Integration
|
|
38
38
|
|
|
39
39
|
```typescript
|
|
40
40
|
import { createServerFn } from '@tanstack/react-start'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Prisma -
|
|
1
|
+
# Prisma - Transactions
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Array-based Transaction
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Rolls back all if any operation fails.
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
const deletePosts = prisma.post.deleteMany({ where: { authorId: 7 } })
|
|
@@ -10,9 +10,9 @@ const deleteUser = prisma.user.delete({ where: { id: 7 } })
|
|
|
10
10
|
await prisma.$transaction([deletePosts, deleteUser])
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Interactive Transaction
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
For complex logic and conditional processing.
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
18
|
const result = await prisma.$transaction(async (tx) => {
|
|
@@ -26,17 +26,17 @@ const result = await prisma.$transaction(async (tx) => {
|
|
|
26
26
|
})
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Options
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
32
|
await prisma.$transaction(async (tx) => { ... }, {
|
|
33
|
-
maxWait: 5000, //
|
|
34
|
-
timeout: 10000, //
|
|
33
|
+
maxWait: 5000, // maximum wait time (ms)
|
|
34
|
+
timeout: 10000, // timeout (ms)
|
|
35
35
|
isolationLevel: 'Serializable', // ReadUncommitted | ReadCommitted | RepeatableRead | Serializable
|
|
36
36
|
})
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Error Handling
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
try {
|
|
@@ -45,6 +45,6 @@ try {
|
|
|
45
45
|
if (someCondition) throw new Error('Rollback')
|
|
46
46
|
})
|
|
47
47
|
} catch (error) {
|
|
48
|
-
//
|
|
48
|
+
// entire transaction rolled back
|
|
49
49
|
}
|
|
50
50
|
```
|
|
@@ -40,12 +40,12 @@ const mutation = useMutation({
|
|
|
40
40
|
},
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Setup
|
|
44
44
|
const queryClient = new QueryClient({
|
|
45
45
|
defaultOptions: {
|
|
46
46
|
queries: {
|
|
47
|
-
staleTime: 1000 * 60 * 5, // 5
|
|
48
|
-
gcTime: 1000 * 60 * 30, // 30
|
|
47
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
48
|
+
gcTime: 1000 * 60 * 30, // 30 minutes
|
|
49
49
|
retry: 3,
|
|
50
50
|
},
|
|
51
51
|
},
|
|
@@ -58,9 +58,9 @@ const App = () => (
|
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
// Query Keys
|
|
61
|
-
['todos'] //
|
|
62
|
-
['todo', { id: 5 }] //
|
|
63
|
-
['todos', 'list', { filters }] //
|
|
61
|
+
['todos'] // simple
|
|
62
|
+
['todo', { id: 5 }] // with parameter
|
|
63
|
+
['todos', 'list', { filters }] // hierarchical
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
</quick_reference>
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
# TanStack Query - Query
|
|
1
|
+
# TanStack Query - Query Invalidation
|
|
2
2
|
|
|
3
3
|
<patterns>
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
const queryClient = useQueryClient()
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// Single
|
|
9
9
|
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// Multiple
|
|
12
12
|
await Promise.all([
|
|
13
13
|
queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
14
14
|
queryClient.invalidateQueries({ queryKey: ['reminders'] }),
|
|
15
15
|
])
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// All
|
|
18
18
|
queryClient.invalidateQueries()
|
|
19
19
|
|
|
20
|
-
//
|
|
20
|
+
// Options
|
|
21
21
|
queryClient.invalidateQueries({
|
|
22
22
|
queryKey: ['posts'],
|
|
23
|
-
exact: true, //
|
|
23
|
+
exact: true, // exact key match only
|
|
24
24
|
refetchType: 'active', // 'active' | 'inactive' | 'all' | 'none'
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
-
// Query
|
|
28
|
-
queryClient.invalidateQueries({ queryKey: ['todos'] }) // prefix
|
|
29
|
-
queryClient.invalidateQueries({ queryKey: ['todos', 'list'], exact: true }) //
|
|
27
|
+
// Query key matching
|
|
28
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] }) // prefix matching
|
|
29
|
+
queryClient.invalidateQueries({ queryKey: ['todos', 'list'], exact: true }) // exact matching
|
|
30
30
|
|
|
31
|
-
//
|
|
31
|
+
// With mutation
|
|
32
32
|
useMutation({
|
|
33
33
|
mutationFn: addTodo,
|
|
34
34
|
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
35
|
-
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }), //
|
|
35
|
+
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }), // regardless of success/failure
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
queryClient.setQueryData(['todos'], (old) => [...old, newTodo]) //
|
|
40
|
-
queryClient.invalidateQueries({ queryKey: ['todos'] }) //
|
|
38
|
+
// Direct update vs invalidation
|
|
39
|
+
queryClient.setQueryData(['todos'], (old) => [...old, newTodo]) // faster
|
|
40
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] }) // guarantees server data
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
</patterns>
|
|
44
44
|
|
|
45
45
|
<options>
|
|
46
46
|
|
|
47
|
-
| refetchType |
|
|
48
|
-
|
|
49
|
-
| active |
|
|
50
|
-
| inactive |
|
|
51
|
-
| all |
|
|
52
|
-
| none |
|
|
47
|
+
| refetchType | Description |
|
|
48
|
+
|-------------|-------------|
|
|
49
|
+
| active | Refetch only queries currently being rendered (default) |
|
|
50
|
+
| inactive | Refetch only inactive queries |
|
|
51
|
+
| all | Refetch all matching queries |
|
|
52
|
+
| none | Invalidate only, no refetch |
|
|
53
53
|
|
|
54
54
|
</options>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<patterns>
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
|
-
//
|
|
6
|
+
// Add
|
|
7
7
|
useMutation({
|
|
8
8
|
mutationFn: addTodo,
|
|
9
9
|
onMutate: async (newTodo) => {
|
|
@@ -20,7 +20,7 @@ useMutation({
|
|
|
20
20
|
},
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// Delete
|
|
24
24
|
useMutation({
|
|
25
25
|
mutationFn: deleteTodo,
|
|
26
26
|
onMutate: async (todoId) => {
|
|
@@ -37,7 +37,7 @@ useMutation({
|
|
|
37
37
|
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
//
|
|
40
|
+
// Toggle
|
|
41
41
|
useMutation({
|
|
42
42
|
mutationFn: toggleTodo,
|
|
43
43
|
onMutate: async (todoId) => {
|
|
@@ -56,7 +56,7 @@ useMutation({
|
|
|
56
56
|
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
//
|
|
59
|
+
// Single item
|
|
60
60
|
useMutation({
|
|
61
61
|
mutationFn: updateTodo,
|
|
62
62
|
onMutate: async (newTodo) => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<patterns>
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
|
-
//
|
|
6
|
+
// Basic
|
|
7
7
|
const queryClient = useQueryClient()
|
|
8
8
|
const mutation = useMutation({
|
|
9
9
|
mutationFn: postTodo,
|
|
@@ -11,12 +11,12 @@ const mutation = useMutation({
|
|
|
11
11
|
})
|
|
12
12
|
mutation.mutate({ title: 'New Todo' })
|
|
13
13
|
|
|
14
|
-
//
|
|
14
|
+
// Callbacks
|
|
15
15
|
useMutation({
|
|
16
16
|
mutationFn: updateTodo,
|
|
17
17
|
onMutate: async (newTodo) => {
|
|
18
|
-
// mutation
|
|
19
|
-
return { previousData } // context
|
|
18
|
+
// before mutation starts (for optimistic updates)
|
|
19
|
+
return { previousData } // passed to context
|
|
20
20
|
},
|
|
21
21
|
onSuccess: (data, variables, context) => {},
|
|
22
22
|
onError: (error, variables, context) => {},
|
|
@@ -35,7 +35,7 @@ try {
|
|
|
35
35
|
const result = await mutation.mutateAsync(data)
|
|
36
36
|
} catch (error) { ... }
|
|
37
37
|
|
|
38
|
-
//
|
|
38
|
+
// Cache update
|
|
39
39
|
useMutation({
|
|
40
40
|
mutationFn: patchTodo,
|
|
41
41
|
onSuccess: (data) => {
|
|
@@ -49,15 +49,15 @@ useMutation({
|
|
|
49
49
|
|
|
50
50
|
<returns>
|
|
51
51
|
|
|
52
|
-
|
|
|
53
|
-
|
|
54
|
-
| data |
|
|
55
|
-
| error |
|
|
56
|
-
| isPending |
|
|
57
|
-
| isSuccess/isError |
|
|
58
|
-
| mutate |
|
|
59
|
-
| mutateAsync |
|
|
60
|
-
| reset |
|
|
61
|
-
| variables |
|
|
52
|
+
| Property | Description |
|
|
53
|
+
|----------|-------------|
|
|
54
|
+
| data | Mutation result |
|
|
55
|
+
| error | Error object |
|
|
56
|
+
| isPending | Execution in progress |
|
|
57
|
+
| isSuccess/isError | Status flags |
|
|
58
|
+
| mutate | Execute (async) |
|
|
59
|
+
| mutateAsync | Execute (Promise) |
|
|
60
|
+
| reset | Reset state |
|
|
61
|
+
| variables | Passed variables |
|
|
62
62
|
|
|
63
63
|
</returns>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<patterns>
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
|
-
//
|
|
6
|
+
// Basic
|
|
7
7
|
const { data, isLoading, error } = useQuery({
|
|
8
8
|
queryKey: ['todos'],
|
|
9
9
|
queryFn: getTodos,
|
|
@@ -11,28 +11,28 @@ const { data, isLoading, error } = useQuery({
|
|
|
11
11
|
if (isLoading) return <div>Loading...</div>
|
|
12
12
|
if (error) return <div>Error: {error.message}</div>
|
|
13
13
|
|
|
14
|
-
//
|
|
14
|
+
// Options
|
|
15
15
|
useQuery({
|
|
16
16
|
queryKey: ['todos'],
|
|
17
17
|
queryFn: fetchTodos,
|
|
18
|
-
staleTime: 1000 * 60 * 5, //
|
|
19
|
-
gcTime: 1000 * 60 * 30, //
|
|
20
|
-
refetchOnWindowFocus: true, //
|
|
21
|
-
refetchInterval: 1000 * 60, //
|
|
22
|
-
retry: 3, //
|
|
23
|
-
enabled: !!userId, //
|
|
24
|
-
initialData: [], //
|
|
25
|
-
select: (data) => data.filter(t => t.done), //
|
|
18
|
+
staleTime: 1000 * 60 * 5, // time to keep data fresh
|
|
19
|
+
gcTime: 1000 * 60 * 30, // garbage collection time
|
|
20
|
+
refetchOnWindowFocus: true, // refetch on window focus
|
|
21
|
+
refetchInterval: 1000 * 60, // auto-refetch interval
|
|
22
|
+
retry: 3, // retry attempts
|
|
23
|
+
enabled: !!userId, // conditional execution
|
|
24
|
+
initialData: [], // initial data
|
|
25
|
+
select: (data) => data.filter(t => t.done), // data transformation
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// With parameter
|
|
29
29
|
useQuery({
|
|
30
30
|
queryKey: ['todo', todoId],
|
|
31
31
|
queryFn: () => fetchTodoById(todoId),
|
|
32
32
|
enabled: !!todoId,
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// Dependent queries
|
|
36
36
|
const { data: user } = useQuery({ queryKey: ['user', userId], queryFn: ... })
|
|
37
37
|
const { data: posts } = useQuery({
|
|
38
38
|
queryKey: ['posts', user?.id],
|
|
@@ -40,11 +40,11 @@ const { data: posts } = useQuery({
|
|
|
40
40
|
enabled: !!user?.id,
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Parallel
|
|
44
44
|
const usersQuery = useQuery({ queryKey: ['users'], queryFn: fetchUsers })
|
|
45
45
|
const postsQuery = useQuery({ queryKey: ['posts'], queryFn: fetchPosts })
|
|
46
46
|
|
|
47
|
-
//
|
|
47
|
+
// Dynamic parallel
|
|
48
48
|
const userQueries = useQueries({
|
|
49
49
|
queries: userIds.map((id) => ({
|
|
50
50
|
queryKey: ['user', id],
|
|
@@ -57,14 +57,14 @@ const userQueries = useQueries({
|
|
|
57
57
|
|
|
58
58
|
<returns>
|
|
59
59
|
|
|
60
|
-
|
|
|
61
|
-
|
|
62
|
-
| data |
|
|
63
|
-
| error |
|
|
64
|
-
| isLoading |
|
|
65
|
-
| isFetching |
|
|
66
|
-
| isError/isSuccess |
|
|
67
|
-
| refetch |
|
|
60
|
+
| Property | Description |
|
|
61
|
+
|----------|-------------|
|
|
62
|
+
| data | Query result |
|
|
63
|
+
| error | Error object |
|
|
64
|
+
| isLoading | First loading state |
|
|
65
|
+
| isFetching | Background fetching state |
|
|
66
|
+
| isError/isSuccess | Status flags |
|
|
67
|
+
| refetch | Manual refetch function |
|
|
68
68
|
| status | 'pending' \| 'error' \| 'success' |
|
|
69
69
|
|
|
70
70
|
</returns>
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
# Zod -
|
|
1
|
+
# Zod - Complex Types
|
|
2
2
|
|
|
3
3
|
<patterns>
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
//
|
|
6
|
+
// Object
|
|
7
7
|
const UserSchema = z.object({
|
|
8
8
|
name: z.string(),
|
|
9
9
|
email: z.email(),
|
|
10
10
|
age: z.number().optional(),
|
|
11
11
|
})
|
|
12
12
|
|
|
13
|
-
UserSchema.partial() //
|
|
14
|
-
UserSchema.required() //
|
|
15
|
-
UserSchema.pick({ name: true }) //
|
|
16
|
-
UserSchema.omit({ email: true }) //
|
|
13
|
+
UserSchema.partial() // all fields optional
|
|
14
|
+
UserSchema.required() // all fields required
|
|
15
|
+
UserSchema.pick({ name: true }) // specific fields only
|
|
16
|
+
UserSchema.omit({ email: true }) // exclude specific fields
|
|
17
17
|
UserSchema.extend({ role: z.enum(['admin', 'user']) })
|
|
18
18
|
UserSchema.merge(AnotherSchema)
|
|
19
19
|
|
|
20
|
-
z.strictObject({ name: z.string() }) // v4:
|
|
21
|
-
z.looseObject({ name: z.string() }) // v4:
|
|
20
|
+
z.strictObject({ name: z.string() }) // v4: additional keys throw error
|
|
21
|
+
z.looseObject({ name: z.string() }) // v4: additional keys pass through
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// Array/Tuple
|
|
24
24
|
z.array(z.string())
|
|
25
25
|
z.array(z.number()).min(1).max(10).length(5).nonempty()
|
|
26
26
|
z.tuple([z.string(), z.number()]) // [string, number]
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// Union
|
|
29
29
|
z.union([z.string(), z.number()])
|
|
30
30
|
z.string().or(z.number())
|
|
31
31
|
|
|
@@ -46,7 +46,7 @@ z.record(z.string(), z.object({ name: z.string() })) // { [key: string]: { name
|
|
|
46
46
|
z.map(z.string(), z.number()) // Map<string, number>
|
|
47
47
|
z.set(z.number()) // Set<number>
|
|
48
48
|
|
|
49
|
-
//
|
|
49
|
+
// Recursive
|
|
50
50
|
type Json = string | number | boolean | null | { [key: string]: Json } | Json[]
|
|
51
51
|
|
|
52
52
|
const jsonSchema: z.ZodType<Json> = z.lazy(() =>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<quick_reference>
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
//
|
|
14
|
+
// Basic
|
|
15
15
|
const schema = z.object({
|
|
16
16
|
email: z.email(), // v4!
|
|
17
17
|
name: z.string().min(1).trim(),
|
|
@@ -20,7 +20,7 @@ const schema = z.object({
|
|
|
20
20
|
})
|
|
21
21
|
type Input = z.infer<typeof schema>
|
|
22
22
|
|
|
23
|
-
schema.parse(data) //
|
|
23
|
+
schema.parse(data) // throws on failure
|
|
24
24
|
schema.safeParse(data) // { success, data/error }
|
|
25
25
|
|
|
26
26
|
// TanStack Start
|
|
@@ -34,7 +34,7 @@ export const createUser = createServerFn({ method: 'POST' })
|
|
|
34
34
|
<v4_changes>
|
|
35
35
|
|
|
36
36
|
```typescript
|
|
37
|
-
// ✅ v4
|
|
37
|
+
// ✅ v4 new APIs
|
|
38
38
|
z.email() z.url() z.uuid()
|
|
39
39
|
z.iso.date() z.iso.datetime() z.iso.duration()
|
|
40
40
|
z.stringbool() // "true"/"yes"/"1" → true
|
|
@@ -42,13 +42,13 @@ z.stringbool() // "true"/"yes"/"1" → true
|
|
|
42
42
|
// ❌ v3 deprecated
|
|
43
43
|
z.string().email() z.string().url()
|
|
44
44
|
|
|
45
|
-
//
|
|
45
|
+
// Changes
|
|
46
46
|
z.string().min(5, { error: "Too short." }) // message → error
|
|
47
|
-
z.strictObject({ name: z.string() }) //
|
|
48
|
-
z.looseObject({ name: z.string() }) //
|
|
49
|
-
z.string().refine(val => val.includes("@")).min(5) // refinement
|
|
47
|
+
z.strictObject({ name: z.string() }) // additional keys throw error
|
|
48
|
+
z.looseObject({ name: z.string() }) // additional keys pass through
|
|
49
|
+
z.string().refine(val => val.includes("@")).min(5) // refinement chaining
|
|
50
50
|
|
|
51
|
-
//
|
|
51
|
+
// Template literals
|
|
52
52
|
const css = z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])])
|
|
53
53
|
// `${number}px` | `${number}em` | `${number}rem`
|
|
54
54
|
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Zod -
|
|
1
|
+
# Zod - Transforms
|
|
2
2
|
|
|
3
3
|
<patterns>
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ stringToLength.parse('hello') // => 5
|
|
|
10
10
|
type In = z.input<typeof stringToLength> // string
|
|
11
11
|
type Out = z.output<typeof stringToLength> // number
|
|
12
12
|
|
|
13
|
-
// Pipe (
|
|
13
|
+
// Pipe (validate then transform)
|
|
14
14
|
const stringToNumber = z.string()
|
|
15
15
|
.transform((val) => parseInt(val, 10))
|
|
16
16
|
.pipe(z.number().min(0).max(100))
|
|
@@ -18,20 +18,20 @@ const stringToNumber = z.string()
|
|
|
18
18
|
stringToNumber.parse('50') // => 50
|
|
19
19
|
stringToNumber.parse('150') // throws
|
|
20
20
|
|
|
21
|
-
// Coerce (
|
|
22
|
-
z.coerce.string() //
|
|
23
|
-
z.coerce.number() //
|
|
24
|
-
z.coerce.boolean() //
|
|
25
|
-
z.coerce.date() //
|
|
26
|
-
z.coerce.bigint() //
|
|
21
|
+
// Coerce (force conversion)
|
|
22
|
+
z.coerce.string() // any value → string
|
|
23
|
+
z.coerce.number() // any value → number
|
|
24
|
+
z.coerce.boolean() // any value → boolean
|
|
25
|
+
z.coerce.date() // any value → date
|
|
26
|
+
z.coerce.bigint() // any value → BigInt
|
|
27
27
|
|
|
28
28
|
z.coerce.number().parse("42") // => 42
|
|
29
29
|
z.coerce.date().parse("2021-01-01") // => Date
|
|
30
30
|
|
|
31
|
-
// v4:
|
|
31
|
+
// v4: input type changed to unknown
|
|
32
32
|
type In = z.input<typeof z.coerce.string()> // unknown
|
|
33
33
|
|
|
34
|
-
// v4
|
|
34
|
+
// v4 environment variable boolean
|
|
35
35
|
z.stringbool() // "true"/"yes"/"1" → true, "false"/"no"/"0" → false
|
|
36
36
|
|
|
37
37
|
// Preprocess
|
|
@@ -40,7 +40,7 @@ const trimmed = z.preprocess(
|
|
|
40
40
|
z.string()
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Separate input/output types
|
|
44
44
|
const Schema = z.object({
|
|
45
45
|
createdAt: z.string().transform((str) => new Date(str)),
|
|
46
46
|
})
|