@kood/claude-code 0.1.7 → 0.1.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 +118 -3
- package/package.json +8 -2
- package/templates/hono/CLAUDE.md +53 -326
- package/templates/hono/docs/architecture/architecture.md +93 -747
- package/templates/hono/docs/deployment/cloudflare.md +59 -513
- package/templates/hono/docs/deployment/docker.md +41 -356
- package/templates/hono/docs/deployment/index.md +49 -190
- package/templates/hono/docs/deployment/railway.md +36 -306
- package/templates/hono/docs/deployment/vercel.md +49 -434
- package/templates/hono/docs/library/ai-sdk/index.md +53 -290
- package/templates/hono/docs/library/ai-sdk/openrouter.md +19 -387
- package/templates/hono/docs/library/ai-sdk/providers.md +28 -394
- package/templates/hono/docs/library/ai-sdk/streaming.md +52 -353
- package/templates/hono/docs/library/ai-sdk/structured-output.md +63 -395
- package/templates/hono/docs/library/ai-sdk/tools.md +62 -431
- package/templates/hono/docs/library/hono/env-setup.md +24 -313
- package/templates/hono/docs/library/hono/error-handling.md +34 -295
- package/templates/hono/docs/library/hono/index.md +24 -122
- package/templates/hono/docs/library/hono/middleware.md +21 -188
- package/templates/hono/docs/library/hono/rpc.md +40 -341
- package/templates/hono/docs/library/hono/validation.md +35 -195
- package/templates/hono/docs/library/pino/index.md +42 -333
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +64 -367
- package/templates/hono/docs/library/prisma/config.md +19 -260
- package/templates/hono/docs/library/prisma/index.md +64 -320
- package/templates/hono/docs/library/zod/index.md +53 -257
- package/templates/npx/CLAUDE.md +58 -276
- package/templates/npx/docs/references/patterns.md +160 -0
- package/templates/tanstack-start/CLAUDE.md +0 -4
- package/templates/tanstack-start/docs/architecture/architecture.md +44 -589
- package/templates/tanstack-start/docs/design/index.md +119 -12
- package/templates/tanstack-start/docs/guides/conventions.md +103 -0
- package/templates/tanstack-start/docs/guides/env-setup.md +34 -340
- package/templates/tanstack-start/docs/guides/getting-started.md +22 -209
- package/templates/tanstack-start/docs/guides/hooks.md +166 -0
- package/templates/tanstack-start/docs/guides/routes.md +166 -0
- package/templates/tanstack-start/docs/guides/services.md +143 -0
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +18 -2
- package/templates/tanstack-start/docs/library/zod/index.md +16 -1
- package/templates/tanstack-start/docs/design/accessibility.md +0 -163
- package/templates/tanstack-start/docs/design/color.md +0 -93
- package/templates/tanstack-start/docs/design/spacing.md +0 -122
- package/templates/tanstack-start/docs/design/typography.md +0 -80
- package/templates/tanstack-start/docs/guides/best-practices.md +0 -950
- package/templates/tanstack-start/docs/guides/husky-lint-staged.md +0 -303
- package/templates/tanstack-start/docs/guides/prettier.md +0 -189
- package/templates/tanstack-start/docs/guides/project-templates.md +0 -710
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +0 -48
- package/templates/tanstack-start/docs/library/zod/basic-types.md +0 -74
|
@@ -1,37 +1,30 @@
|
|
|
1
1
|
# Hono + Zod 검증
|
|
2
2
|
|
|
3
|
-
> @hono/zod-validator
|
|
3
|
+
> @hono/zod-validator로 타입 안전 요청 검증
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## 설치
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
11
|
-
npm install zod
|
|
12
|
-
|
|
13
|
-
# Zod Validator Middleware
|
|
14
|
-
npm install @hono/zod-validator
|
|
10
|
+
npm install zod @hono/zod-validator
|
|
15
11
|
```
|
|
16
12
|
|
|
17
13
|
---
|
|
18
14
|
|
|
19
15
|
## 기본 사용법
|
|
20
16
|
|
|
21
|
-
### JSON Body
|
|
17
|
+
### JSON Body
|
|
22
18
|
|
|
23
19
|
```typescript
|
|
24
|
-
import { Hono } from 'hono'
|
|
25
20
|
import { zValidator } from '@hono/zod-validator'
|
|
26
21
|
import { z } from 'zod'
|
|
27
22
|
|
|
28
|
-
const app = new Hono()
|
|
29
|
-
|
|
30
23
|
// ✅ Zod v4 문법
|
|
31
24
|
const createUserSchema = z.object({
|
|
32
|
-
email: z.email(), //
|
|
25
|
+
email: z.email(), // v4
|
|
33
26
|
name: z.string().min(1).trim(),
|
|
34
|
-
website: z.url().optional(), //
|
|
27
|
+
website: z.url().optional(), // v4
|
|
35
28
|
})
|
|
36
29
|
|
|
37
30
|
app.post('/users', zValidator('json', createUserSchema), (c) => {
|
|
@@ -40,7 +33,7 @@ app.post('/users', zValidator('json', createUserSchema), (c) => {
|
|
|
40
33
|
})
|
|
41
34
|
```
|
|
42
35
|
|
|
43
|
-
### Query Parameter
|
|
36
|
+
### Query Parameter
|
|
44
37
|
|
|
45
38
|
```typescript
|
|
46
39
|
const searchSchema = z.object({
|
|
@@ -51,49 +44,32 @@ const searchSchema = z.object({
|
|
|
51
44
|
|
|
52
45
|
app.get('/search', zValidator('query', searchSchema), (c) => {
|
|
53
46
|
const { q, page = 1, limit = 10 } = c.req.valid('query')
|
|
54
|
-
return c.json({ query: q, page, limit
|
|
47
|
+
return c.json({ query: q, page, limit })
|
|
55
48
|
})
|
|
56
49
|
```
|
|
57
50
|
|
|
58
|
-
### Path Parameter
|
|
51
|
+
### Path Parameter
|
|
59
52
|
|
|
60
53
|
```typescript
|
|
61
|
-
|
|
62
|
-
id: z.string().uuid(),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
})
|
|
54
|
+
app.get('/users/:id',
|
|
55
|
+
zValidator('param', z.object({ id: z.string().uuid() })),
|
|
56
|
+
(c) => {
|
|
57
|
+
const { id } = c.req.valid('param')
|
|
58
|
+
return c.json({ id })
|
|
59
|
+
}
|
|
60
|
+
)
|
|
69
61
|
```
|
|
70
62
|
|
|
71
|
-
### Header
|
|
63
|
+
### Header
|
|
72
64
|
|
|
73
65
|
```typescript
|
|
74
|
-
//
|
|
66
|
+
// 헤더 이름은 소문자
|
|
75
67
|
const headerSchema = z.object({
|
|
76
68
|
'x-api-key': z.string().uuid(),
|
|
77
|
-
'x-request-id': z.string().optional(),
|
|
78
69
|
})
|
|
79
70
|
|
|
80
71
|
app.get('/api/protected', zValidator('header', headerSchema), (c) => {
|
|
81
|
-
|
|
82
|
-
return c.json({ apiKey: headers['x-api-key'] })
|
|
83
|
-
})
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Form Data 검증
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
const formSchema = z.object({
|
|
90
|
-
title: z.string().min(1).max(100),
|
|
91
|
-
content: z.string().min(10),
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
app.post('/posts', zValidator('form', formSchema), (c) => {
|
|
95
|
-
const data = c.req.valid('form')
|
|
96
|
-
return c.json({ post: data }, 201)
|
|
72
|
+
return c.json({ apiKey: c.req.valid('header')['x-api-key'] })
|
|
97
73
|
})
|
|
98
74
|
```
|
|
99
75
|
|
|
@@ -101,24 +77,16 @@ app.post('/posts', zValidator('form', formSchema), (c) => {
|
|
|
101
77
|
|
|
102
78
|
## 복합 검증
|
|
103
79
|
|
|
104
|
-
### 여러 소스 검증
|
|
105
|
-
|
|
106
80
|
```typescript
|
|
107
|
-
const postSchema = z.object({
|
|
108
|
-
title: z.string().min(1).max(100),
|
|
109
|
-
body: z.string().min(10),
|
|
110
|
-
})
|
|
111
|
-
|
|
112
81
|
app.post(
|
|
113
82
|
'/posts/:id',
|
|
114
83
|
zValidator('param', z.object({ id: z.string().uuid() })),
|
|
115
84
|
zValidator('query', z.object({ draft: z.coerce.boolean().optional() })),
|
|
116
|
-
zValidator('json',
|
|
85
|
+
zValidator('json', z.object({ title: z.string(), body: z.string() })),
|
|
117
86
|
(c) => {
|
|
118
87
|
const { id } = c.req.valid('param')
|
|
119
88
|
const { draft } = c.req.valid('query')
|
|
120
89
|
const postData = c.req.valid('json')
|
|
121
|
-
|
|
122
90
|
return c.json({ id, draft: draft ?? false, ...postData })
|
|
123
91
|
}
|
|
124
92
|
)
|
|
@@ -128,45 +96,15 @@ app.post(
|
|
|
128
96
|
|
|
129
97
|
## 커스텀 에러 처리
|
|
130
98
|
|
|
131
|
-
### 기본 에러 응답
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
app.post(
|
|
135
|
-
'/users',
|
|
136
|
-
zValidator('json', createUserSchema, (result, c) => {
|
|
137
|
-
if (!result.success) {
|
|
138
|
-
return c.json(
|
|
139
|
-
{
|
|
140
|
-
error: 'Validation failed',
|
|
141
|
-
issues: result.error.flatten(),
|
|
142
|
-
},
|
|
143
|
-
400
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
}),
|
|
147
|
-
(c) => {
|
|
148
|
-
const data = c.req.valid('json')
|
|
149
|
-
return c.json({ user: data }, 201)
|
|
150
|
-
}
|
|
151
|
-
)
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### 상세 에러 응답
|
|
155
|
-
|
|
156
99
|
```typescript
|
|
157
100
|
app.post(
|
|
158
101
|
'/users',
|
|
159
102
|
zValidator('json', createUserSchema, (result, c) => {
|
|
160
103
|
if (!result.success) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
fieldErrors: errors.fieldErrors,
|
|
166
|
-
formErrors: errors.formErrors,
|
|
167
|
-
},
|
|
168
|
-
400
|
|
169
|
-
)
|
|
104
|
+
return c.json({
|
|
105
|
+
error: 'Validation failed',
|
|
106
|
+
fieldErrors: result.error.flatten().fieldErrors,
|
|
107
|
+
}, 400)
|
|
170
108
|
}
|
|
171
109
|
}),
|
|
172
110
|
(c) => {
|
|
@@ -185,7 +123,6 @@ app.post(
|
|
|
185
123
|
```typescript
|
|
186
124
|
import { z } from 'zod'
|
|
187
125
|
|
|
188
|
-
// ✅ Zod v4 문법
|
|
189
126
|
export const createUserSchema = z.object({
|
|
190
127
|
email: z.email(),
|
|
191
128
|
name: z.string().min(1).max(100).trim(),
|
|
@@ -194,92 +131,27 @@ export const createUserSchema = z.object({
|
|
|
194
131
|
|
|
195
132
|
export const updateUserSchema = createUserSchema.partial()
|
|
196
133
|
|
|
197
|
-
export const userIdSchema = z.object({
|
|
198
|
-
id: z.string().uuid(),
|
|
199
|
-
})
|
|
200
|
-
|
|
201
134
|
export type CreateUserInput = z.infer<typeof createUserSchema>
|
|
202
|
-
export type UpdateUserInput = z.infer<typeof updateUserSchema>
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### routes/users.ts
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
import { Hono } from 'hono'
|
|
209
|
-
import { zValidator } from '@hono/zod-validator'
|
|
210
|
-
import {
|
|
211
|
-
createUserSchema,
|
|
212
|
-
updateUserSchema,
|
|
213
|
-
userIdSchema,
|
|
214
|
-
} from '../validators/user'
|
|
215
|
-
|
|
216
|
-
const users = new Hono()
|
|
217
|
-
|
|
218
|
-
users.post('/', zValidator('json', createUserSchema), (c) => {
|
|
219
|
-
const data = c.req.valid('json')
|
|
220
|
-
return c.json({ user: data }, 201)
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
users.put(
|
|
224
|
-
'/:id',
|
|
225
|
-
zValidator('param', userIdSchema),
|
|
226
|
-
zValidator('json', updateUserSchema),
|
|
227
|
-
(c) => {
|
|
228
|
-
const { id } = c.req.valid('param')
|
|
229
|
-
const data = c.req.valid('json')
|
|
230
|
-
return c.json({ id, ...data })
|
|
231
|
-
}
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
export default users
|
|
235
135
|
```
|
|
236
136
|
|
|
237
137
|
---
|
|
238
138
|
|
|
239
|
-
## 고급
|
|
240
|
-
|
|
241
|
-
### Coerce (타입 변환)
|
|
139
|
+
## 고급 패턴
|
|
242
140
|
|
|
243
141
|
```typescript
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
active: z.coerce.boolean(),
|
|
249
|
-
// string → Date 변환
|
|
250
|
-
since: z.coerce.date(),
|
|
251
|
-
})
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### Enum
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
const statusSchema = z.object({
|
|
258
|
-
status: z.enum(['pending', 'active', 'completed']),
|
|
259
|
-
})
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Array
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
const tagsSchema = z.object({
|
|
266
|
-
tags: z.array(z.string()).min(1).max(10),
|
|
267
|
-
})
|
|
268
|
-
```
|
|
142
|
+
// Coerce (타입 변환)
|
|
143
|
+
z.coerce.number() // string → number
|
|
144
|
+
z.coerce.boolean() // 'true' → boolean
|
|
145
|
+
z.coerce.date() // string → Date
|
|
269
146
|
|
|
270
|
-
|
|
147
|
+
// Enum
|
|
148
|
+
z.enum(['pending', 'active', 'completed'])
|
|
271
149
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
z.string().uuid(),
|
|
275
|
-
z.coerce.number().positive(),
|
|
276
|
-
])
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
### Refinement
|
|
150
|
+
// Transform
|
|
151
|
+
z.email().transform((e) => e.toLowerCase())
|
|
280
152
|
|
|
281
|
-
|
|
282
|
-
|
|
153
|
+
// Refinement
|
|
154
|
+
z.object({
|
|
283
155
|
password: z.string().min(8),
|
|
284
156
|
confirmPassword: z.string(),
|
|
285
157
|
}).refine((data) => data.password === data.confirmPassword, {
|
|
@@ -288,41 +160,9 @@ const passwordSchema = z.object({
|
|
|
288
160
|
})
|
|
289
161
|
```
|
|
290
162
|
|
|
291
|
-
### Transform
|
|
292
|
-
|
|
293
|
-
```typescript
|
|
294
|
-
const userSchema = z.object({
|
|
295
|
-
email: z.email().transform((email) => email.toLowerCase()),
|
|
296
|
-
name: z.string().transform((name) => name.trim()),
|
|
297
|
-
})
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
---
|
|
301
|
-
|
|
302
|
-
## Standard Schema Validator
|
|
303
|
-
|
|
304
|
-
Zod 외에도 다양한 검증 라이브러리 지원:
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
import { sValidator } from '@hono/standard-validator'
|
|
308
|
-
import { z } from 'zod'
|
|
309
|
-
|
|
310
|
-
const schema = z.object({
|
|
311
|
-
name: z.string(),
|
|
312
|
-
age: z.number(),
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
app.post('/author', sValidator('json', schema), (c) => {
|
|
316
|
-
const data = c.req.valid('json')
|
|
317
|
-
return c.json({ success: true, message: `${data.name} is ${data.age}` })
|
|
318
|
-
})
|
|
319
|
-
```
|
|
320
|
-
|
|
321
163
|
---
|
|
322
164
|
|
|
323
165
|
## 관련 문서
|
|
324
166
|
|
|
325
|
-
- [기본 사용법](./index.md)
|
|
326
|
-
- [미들웨어](./middleware.md)
|
|
327
|
-
- [에러 처리](./error-handling.md)
|
|
328
167
|
- [Zod 가이드](../zod/index.md)
|
|
168
|
+
- [에러 처리](./error-handling.md)
|