@kood/claude-code 0.3.7 → 0.3.9
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 +138 -123
- package/templates/.claude/agents/dependency-manager.md +99 -84
- package/templates/.claude/agents/deployment-validator.md +70 -55
- package/templates/.claude/agents/git-operator.md +78 -63
- package/templates/.claude/agents/implementation-executor.md +109 -94
- package/templates/.claude/agents/ko-to-en-translator.md +74 -0
- package/templates/.claude/agents/lint-fixer.md +93 -78
- package/templates/.claude/agents/refactor-advisor.md +136 -121
- package/templates/.claude/commands/agent-creator.md +199 -184
- package/templates/.claude/commands/bug-fix.md +207 -192
- package/templates/.claude/commands/command-creator.md +69 -53
- package/templates/.claude/commands/docs-creator.md +72 -56
- package/templates/.claude/commands/docs-refactor.md +41 -25
- package/templates/.claude/commands/execute.md +27 -11
- package/templates/.claude/commands/git-all.md +46 -31
- package/templates/.claude/commands/git-session.md +57 -41
- package/templates/.claude/commands/git.md +49 -33
- package/templates/.claude/commands/lint-fix.md +153 -137
- package/templates/.claude/commands/lint-init.md +76 -60
- package/templates/.claude/commands/plan.md +275 -259
- package/templates/.claude/commands/prd.md +39 -23
- package/templates/.claude/commands/pre-deploy.md +124 -108
- package/templates/.claude/commands/refactor.md +162 -146
- package/templates/.claude/commands/version-update.md +32 -16
- package/templates/hono/CLAUDE.md +28 -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 +54 -51
- package/templates/nextjs/docs/architecture.md +812 -0
- 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 +38 -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 +54 -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,6 +1,6 @@
|
|
|
1
|
-
# Prisma -
|
|
1
|
+
# Prisma - Relation Queries
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Nested Create
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
const user = await prisma.user.create({
|
|
@@ -12,53 +12,53 @@ const user = await prisma.user.create({
|
|
|
12
12
|
})
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Relation Operations
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
// connect -
|
|
18
|
+
// connect - Link existing record
|
|
19
19
|
author: { connect: { id: 1 } }
|
|
20
20
|
|
|
21
|
-
// connectOrCreate -
|
|
21
|
+
// connectOrCreate - Connect if exists, create otherwise
|
|
22
22
|
categories: { connectOrCreate: { where: { name: 'Tech' }, create: { name: 'Tech' } } }
|
|
23
23
|
|
|
24
|
-
// disconnect -
|
|
24
|
+
// disconnect - Remove relation
|
|
25
25
|
author: { disconnect: true }
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Include Relations
|
|
29
29
|
|
|
30
30
|
```typescript
|
|
31
31
|
// include
|
|
32
32
|
const users = await prisma.user.findMany({ include: { posts: true, profile: true } })
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// Nested
|
|
35
35
|
include: { posts: { include: { categories: true } } }
|
|
36
36
|
|
|
37
|
-
//
|
|
37
|
+
// Filter + Sort
|
|
38
38
|
include: { posts: { where: { published: true }, orderBy: { createdAt: 'desc' }, take: 5 } }
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## Filter by Relations
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
|
-
// some -
|
|
44
|
+
// some - At least one matches
|
|
45
45
|
where: { posts: { some: { published: true } } }
|
|
46
46
|
|
|
47
|
-
// every -
|
|
47
|
+
// every - All match
|
|
48
48
|
where: { posts: { every: { published: true } } }
|
|
49
49
|
|
|
50
|
-
// none -
|
|
50
|
+
// none - None match
|
|
51
51
|
where: { posts: { none: { published: false } } }
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
##
|
|
54
|
+
## Count
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
57
|
include: { _count: { select: { posts: true } } }
|
|
58
|
-
//
|
|
58
|
+
// Result: { _count: { posts: 5 } }
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
##
|
|
61
|
+
## Nested Update/Delete
|
|
62
62
|
|
|
63
63
|
```typescript
|
|
64
64
|
// updateMany
|
|
@@ -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. **Multi-File structure** required
|
|
6
|
+
2. **Korean comments on 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
|
+
## Examples
|
|
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[] // Author posts (1:N)
|
|
45
|
+
profile Profile? // 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
|
+
## Other Features
|
|
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
|
+
// Indexes
|
|
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 Transactions
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
All operations rollback if any one 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 Transactions
|
|
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, // Max 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
|
```
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# t3-env - Type-Safe Environment Variables
|
|
2
2
|
|
|
3
|
-
> Zod
|
|
3
|
+
> Zod-based type-safe environment variable management
|
|
4
4
|
|
|
5
5
|
<context>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Purpose:** Server/client environment variable separation, runtime validation, type safety
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Zod
|
|
11
|
-
-
|
|
12
|
-
- Transform &
|
|
13
|
-
-
|
|
9
|
+
**Features:**
|
|
10
|
+
- Zod schema validation + type inference
|
|
11
|
+
- Prevent server variables from being exposed to client
|
|
12
|
+
- Transform & default value support
|
|
13
|
+
- Framework-agnostic
|
|
14
14
|
|
|
15
15
|
</context>
|
|
16
16
|
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
|
|
19
19
|
<forbidden>
|
|
20
20
|
|
|
21
|
-
|
|
|
21
|
+
| Category | Forbidden |
|
|
22
22
|
|------|------|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
23
|
+
| **Exposure** | Exposing server variables to client |
|
|
24
|
+
| **Prefix** | Using client variables without `PUBLIC_` |
|
|
25
|
+
| **Direct Access** | Direct `process.env` access (use env object) |
|
|
26
|
+
| **Type** | Accessing env variables with any type |
|
|
27
27
|
|
|
28
28
|
</forbidden>
|
|
29
29
|
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
|
|
32
32
|
<required>
|
|
33
33
|
|
|
34
|
-
|
|
|
34
|
+
| Category | Required |
|
|
35
35
|
|------|------|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
36
|
+
| **Install** | `@t3-oss/env-core zod` |
|
|
37
|
+
| **Structure** | Create `src/env.ts` file |
|
|
38
|
+
| **Prefix** | Client variables: Start with `PUBLIC_` |
|
|
39
39
|
| **Import** | `import { env } from '@/env'` |
|
|
40
40
|
|
|
41
41
|
</required>
|
|
@@ -104,7 +104,7 @@ import { env } from '@/env'
|
|
|
104
104
|
|
|
105
105
|
export const getUsers = createServerFn({ method: 'GET' }).handler(async () => {
|
|
106
106
|
const db = await prisma.$connect(env.DATABASE_URL)
|
|
107
|
-
// ^? string (
|
|
107
|
+
// ^? string (type-safe)
|
|
108
108
|
return db.user.findMany()
|
|
109
109
|
})
|
|
110
110
|
```
|
|
@@ -116,9 +116,9 @@ import { env } from '@/env'
|
|
|
116
116
|
|
|
117
117
|
export const ApiClient = () => {
|
|
118
118
|
const apiUrl = env.PUBLIC_API_URL
|
|
119
|
-
// ^? string (
|
|
119
|
+
// ^? string (type-safe)
|
|
120
120
|
|
|
121
|
-
// ❌ Error: server
|
|
121
|
+
// ❌ Error: server variables cannot be accessed in client
|
|
122
122
|
// const dbUrl = env.DATABASE_URL
|
|
123
123
|
}
|
|
124
124
|
```
|
|
@@ -154,153 +154,14 @@ client: {
|
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
-
<examples>
|
|
158
|
-
|
|
159
|
-
## Real-World Examples
|
|
160
|
-
|
|
161
|
-
### Database + Auth
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
// src/env.ts
|
|
165
|
-
export const env = createEnv({
|
|
166
|
-
server: {
|
|
167
|
-
DATABASE_URL: z.url(),
|
|
168
|
-
DIRECT_URL: z.url().optional(), // Prisma connection pooling
|
|
169
|
-
CLERK_SECRET_KEY: z.string().min(1),
|
|
170
|
-
RESEND_API_KEY: z.string().min(1),
|
|
171
|
-
},
|
|
172
|
-
clientPrefix: 'PUBLIC_',
|
|
173
|
-
client: {
|
|
174
|
-
PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
|
|
175
|
-
},
|
|
176
|
-
runtimeEnv: {
|
|
177
|
-
DATABASE_URL: process.env.DATABASE_URL,
|
|
178
|
-
DIRECT_URL: process.env.DIRECT_URL,
|
|
179
|
-
CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
|
|
180
|
-
RESEND_API_KEY: process.env.RESEND_API_KEY,
|
|
181
|
-
PUBLIC_CLERK_PUBLISHABLE_KEY: import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY,
|
|
182
|
-
},
|
|
183
|
-
emptyStringAsUndefined: true,
|
|
184
|
-
})
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### API Integration
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
// src/env.ts
|
|
191
|
-
export const env = createEnv({
|
|
192
|
-
server: {
|
|
193
|
-
OPENAI_API_KEY: z.string().min(1),
|
|
194
|
-
STRIPE_SECRET_KEY: z.string().min(1),
|
|
195
|
-
STRIPE_WEBHOOK_SECRET: z.string().min(1),
|
|
196
|
-
},
|
|
197
|
-
clientPrefix: 'PUBLIC_',
|
|
198
|
-
client: {
|
|
199
|
-
PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
|
|
200
|
-
PUBLIC_APP_URL: z.url(),
|
|
201
|
-
},
|
|
202
|
-
runtimeEnv: {
|
|
203
|
-
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
|
204
|
-
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
|
|
205
|
-
STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
|
|
206
|
-
PUBLIC_STRIPE_PUBLISHABLE_KEY: import.meta.env.PUBLIC_STRIPE_PUBLISHABLE_KEY,
|
|
207
|
-
PUBLIC_APP_URL: import.meta.env.PUBLIC_APP_URL,
|
|
208
|
-
},
|
|
209
|
-
emptyStringAsUndefined: true,
|
|
210
|
-
})
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Multi-Environment
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
// src/env.ts
|
|
217
|
-
export const env = createEnv({
|
|
218
|
-
server: {
|
|
219
|
-
NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
220
|
-
DATABASE_URL: z.url(),
|
|
221
|
-
REDIS_URL: z.url().optional(), // Production only
|
|
222
|
-
},
|
|
223
|
-
clientPrefix: 'PUBLIC_',
|
|
224
|
-
client: {
|
|
225
|
-
PUBLIC_API_URL: z.url(),
|
|
226
|
-
PUBLIC_SENTRY_DSN: z.string().optional(), // Production only
|
|
227
|
-
},
|
|
228
|
-
runtimeEnv: {
|
|
229
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
230
|
-
DATABASE_URL: process.env.DATABASE_URL,
|
|
231
|
-
REDIS_URL: process.env.REDIS_URL,
|
|
232
|
-
PUBLIC_API_URL: import.meta.env.PUBLIC_API_URL,
|
|
233
|
-
PUBLIC_SENTRY_DSN: import.meta.env.PUBLIC_SENTRY_DSN,
|
|
234
|
-
},
|
|
235
|
-
emptyStringAsUndefined: true,
|
|
236
|
-
})
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
</examples>
|
|
240
|
-
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
<validation>
|
|
244
|
-
|
|
245
|
-
## Validation Patterns
|
|
246
|
-
|
|
247
|
-
### Email
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
server: {
|
|
251
|
-
ADMIN_EMAIL: z.email(),
|
|
252
|
-
SUPPORT_EMAIL: z.email().default('support@example.com'),
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### URL
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
server: {
|
|
260
|
-
API_URL: z.url(),
|
|
261
|
-
WEBHOOK_URL: z.url().optional(),
|
|
262
|
-
}
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Enum
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
server: {
|
|
269
|
-
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']),
|
|
270
|
-
DATABASE_PROVIDER: z.enum(['postgresql', 'mysql', 'sqlite']),
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Number
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
server: {
|
|
278
|
-
PORT: z.coerce.number().positive().default(3000),
|
|
279
|
-
MAX_UPLOAD_SIZE: z.coerce.number().max(10485760), // 10MB
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### Boolean
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
server: {
|
|
287
|
-
ENABLE_CACHE: z.coerce.boolean().default(true),
|
|
288
|
-
DEBUG_MODE: z.coerce.boolean().default(false),
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
</validation>
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
157
|
<tips>
|
|
297
158
|
|
|
298
159
|
## Tips
|
|
299
160
|
|
|
300
|
-
|
|
|
161
|
+
| Situation | Method |
|
|
301
162
|
|------|------|
|
|
302
163
|
| **Vercel** | `process.env.VERCEL_URL` → PUBLIC_APP_URL |
|
|
303
|
-
| **Monorepo** |
|
|
164
|
+
| **Monorepo** | Separate `env.ts` per package |
|
|
304
165
|
| **Testing** | `.env.test` + `NODE_ENV=test` |
|
|
305
166
|
| **CI/CD** | GitHub Secrets → Environment Variables |
|
|
306
167
|
|
|
@@ -40,12 +40,12 @@ const mutation = useMutation({
|
|
|
40
40
|
},
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Configuration
|
|
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 params
|
|
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 Key
|
|
28
|
-
queryClient.invalidateQueries({ queryKey: ['todos'] }) //
|
|
29
|
-
queryClient.invalidateQueries({ queryKey: ['todos', 'list'], exact: true }) //
|
|
27
|
+
// Query Key matching
|
|
28
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] }) // Prefix match
|
|
29
|
+
queryClient.invalidateQueries({ queryKey: ['todos', 'list'], exact: true }) // Exact match
|
|
30
30
|
|
|
31
|
-
// Mutation
|
|
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 |
|
|
47
|
+
| refetchType | Description |
|
|
48
48
|
|-------------|------|
|
|
49
|
-
| active |
|
|
50
|
-
| inactive |
|
|
51
|
-
| all |
|
|
52
|
-
| none |
|
|
49
|
+
| active | Refetch only active queries (default) |
|
|
50
|
+
| inactive | Only inactive queries |
|
|
51
|
+
| all | 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) => {
|