@kood/claude-code 0.1.2 → 0.1.3

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.
Files changed (61) hide show
  1. package/dist/index.js +12 -3
  2. package/package.json +2 -2
  3. package/templates/hono/CLAUDE.md +20 -2
  4. package/templates/hono/docs/architecture/architecture.md +909 -0
  5. package/templates/hono/docs/deployment/cloudflare.md +537 -190
  6. package/templates/hono/docs/deployment/docker.md +517 -0
  7. package/templates/hono/docs/deployment/index.md +181 -213
  8. package/templates/hono/docs/deployment/railway.md +416 -0
  9. package/templates/hono/docs/deployment/vercel.md +572 -0
  10. package/templates/hono/docs/git/git.md +285 -0
  11. package/templates/hono/docs/library/ai-sdk/index.md +427 -0
  12. package/templates/hono/docs/library/ai-sdk/openrouter.md +479 -0
  13. package/templates/hono/docs/library/ai-sdk/providers.md +468 -0
  14. package/templates/hono/docs/library/ai-sdk/streaming.md +447 -0
  15. package/templates/hono/docs/library/ai-sdk/structured-output.md +493 -0
  16. package/templates/hono/docs/library/ai-sdk/tools.md +513 -0
  17. package/templates/hono/docs/library/hono/env-setup.md +458 -0
  18. package/templates/hono/docs/library/hono/index.md +1 -0
  19. package/templates/hono/docs/library/pino/index.md +437 -0
  20. package/templates/hono/docs/library/prisma/cloudflare-d1.md +503 -0
  21. package/templates/hono/docs/library/prisma/config.md +362 -0
  22. package/templates/hono/docs/library/prisma/index.md +86 -13
  23. package/templates/hono/docs/skills/gemini-review/SKILL.md +116 -116
  24. package/templates/hono/docs/skills/gemini-review/references/checklists.md +125 -125
  25. package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +191 -191
  26. package/templates/npx/CLAUDE.md +309 -0
  27. package/templates/npx/docs/git/git.md +307 -0
  28. package/templates/npx/docs/library/commander/index.md +164 -0
  29. package/templates/npx/docs/library/fs-extra/index.md +171 -0
  30. package/templates/npx/docs/library/prompts/index.md +253 -0
  31. package/templates/npx/docs/mcp/index.md +60 -0
  32. package/templates/npx/docs/skills/gemini-review/SKILL.md +220 -0
  33. package/templates/npx/docs/skills/gemini-review/references/checklists.md +134 -0
  34. package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +301 -0
  35. package/templates/tanstack-start/CLAUDE.md +43 -5
  36. package/templates/tanstack-start/docs/architecture/architecture.md +134 -4
  37. package/templates/tanstack-start/docs/deployment/cloudflare.md +234 -51
  38. package/templates/tanstack-start/docs/deployment/index.md +322 -32
  39. package/templates/tanstack-start/docs/deployment/nitro.md +201 -20
  40. package/templates/tanstack-start/docs/deployment/railway.md +305 -153
  41. package/templates/tanstack-start/docs/deployment/vercel.md +353 -78
  42. package/templates/tanstack-start/docs/git/{index.md → git.md} +81 -7
  43. package/templates/tanstack-start/docs/guides/best-practices.md +203 -1
  44. package/templates/tanstack-start/docs/guides/env-setup.md +450 -0
  45. package/templates/tanstack-start/docs/library/ai-sdk/hooks.md +472 -0
  46. package/templates/tanstack-start/docs/library/ai-sdk/index.md +264 -0
  47. package/templates/tanstack-start/docs/library/ai-sdk/openrouter.md +371 -0
  48. package/templates/tanstack-start/docs/library/ai-sdk/providers.md +403 -0
  49. package/templates/tanstack-start/docs/library/ai-sdk/streaming.md +320 -0
  50. package/templates/tanstack-start/docs/library/ai-sdk/structured-output.md +454 -0
  51. package/templates/tanstack-start/docs/library/ai-sdk/tools.md +473 -0
  52. package/templates/tanstack-start/docs/library/pino/index.md +320 -0
  53. package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +404 -0
  54. package/templates/tanstack-start/docs/library/prisma/config.md +377 -0
  55. package/templates/tanstack-start/docs/library/prisma/index.md +3 -1
  56. package/templates/tanstack-start/docs/library/prisma/schema.md +123 -25
  57. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +80 -2
  58. package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +116 -116
  59. package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +138 -144
  60. package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +186 -187
  61. package/templates/hono/docs/git/index.md +0 -180
@@ -0,0 +1,479 @@
1
+ # AI SDK - OpenRouter (Hono)
2
+
3
+ > **상위 문서**: [AI SDK](./index.md) | [프로바이더](./providers.md)
4
+
5
+ ---
6
+
7
+ ## 개요
8
+
9
+ [OpenRouter](https://openrouter.ai/)는 Anthropic, Google, Meta, Mistral 등 주요 AI 프로바이더의 수백 개 모델에 단일 API로 접근할 수 있는 통합 게이트웨이입니다.
10
+
11
+ ### 주요 장점
12
+
13
+ | 장점 | 설명 |
14
+ |------|------|
15
+ | **통합 API** | 하나의 API 키로 수백 개 모델 접근 |
16
+ | **비용 효율** | 월정액 없이 사용량 기반 과금 |
17
+ | **투명한 가격** | 모델별 토큰당 비용 명확히 표시 |
18
+ | **고가용성** | 엔터프라이즈급 인프라와 자동 장애 조치 |
19
+ | **최신 모델** | 새 모델 출시 즉시 사용 가능 |
20
+
21
+ ---
22
+
23
+ ## 설치
24
+
25
+ ```bash
26
+ npm install @openrouter/ai-sdk-provider
27
+ ```
28
+
29
+ ---
30
+
31
+ ## 기본 설정
32
+
33
+ ### Provider 인스턴스 생성
34
+
35
+ ```typescript
36
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
37
+
38
+ const openrouter = createOpenRouter({
39
+ apiKey: process.env.OPENROUTER_API_KEY,
40
+ })
41
+ ```
42
+
43
+ API 키는 [OpenRouter Dashboard](https://openrouter.ai/keys)에서 발급받을 수 있습니다.
44
+
45
+ ---
46
+
47
+ ## Hono 통합
48
+
49
+ ### 기본 채팅 API
50
+
51
+ ```typescript
52
+ import { Hono } from 'hono'
53
+ import { streamText, convertToModelMessages } from 'ai'
54
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
55
+
56
+ const app = new Hono()
57
+
58
+ const openrouter = createOpenRouter({
59
+ apiKey: process.env.OPENROUTER_API_KEY,
60
+ })
61
+
62
+ app.post('/api/chat', async (c) => {
63
+ const { messages } = await c.req.json()
64
+
65
+ const result = streamText({
66
+ model: openrouter.chat('anthropic/claude-3.5-sonnet'),
67
+ messages: convertToModelMessages(messages),
68
+ })
69
+
70
+ return result.toUIMessageStreamResponse()
71
+ })
72
+
73
+ export default app
74
+ ```
75
+
76
+ ### 동적 모델 선택
77
+
78
+ ```typescript
79
+ import { Hono } from 'hono'
80
+ import { streamText, convertToModelMessages } from 'ai'
81
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
82
+ import { HTTPException } from 'hono/http-exception'
83
+
84
+ const app = new Hono()
85
+
86
+ const openrouter = createOpenRouter({
87
+ apiKey: process.env.OPENROUTER_API_KEY,
88
+ })
89
+
90
+ // 허용된 모델 목록
91
+ const ALLOWED_MODELS = [
92
+ 'anthropic/claude-3.5-sonnet',
93
+ 'anthropic/claude-3-opus',
94
+ 'openai/gpt-4o',
95
+ 'openai/gpt-4-turbo',
96
+ 'google/gemini-pro-1.5',
97
+ 'meta-llama/llama-3.1-70b-instruct',
98
+ ]
99
+
100
+ app.post('/api/chat', async (c) => {
101
+ const { messages, model = 'anthropic/claude-3.5-sonnet' } = await c.req.json()
102
+
103
+ // 모델 검증
104
+ if (!ALLOWED_MODELS.includes(model)) {
105
+ throw new HTTPException(400, { message: 'Invalid model' })
106
+ }
107
+
108
+ const result = streamText({
109
+ model: openrouter.chat(model),
110
+ messages: convertToModelMessages(messages),
111
+ })
112
+
113
+ return result.toUIMessageStreamResponse()
114
+ })
115
+
116
+ export default app
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Cloudflare Workers 배포
122
+
123
+ ### 기본 설정
124
+
125
+ ```typescript
126
+ // src/index.ts
127
+ import { Hono } from 'hono'
128
+ import { streamText, convertToModelMessages } from 'ai'
129
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
130
+
131
+ type Bindings = {
132
+ OPENROUTER_API_KEY: string
133
+ }
134
+
135
+ const app = new Hono<{ Bindings: Bindings }>()
136
+
137
+ app.post('/api/chat', async (c) => {
138
+ const openrouter = createOpenRouter({
139
+ apiKey: c.env.OPENROUTER_API_KEY,
140
+ })
141
+
142
+ const { messages, model } = await c.req.json()
143
+
144
+ const result = streamText({
145
+ model: openrouter.chat(model ?? 'anthropic/claude-3.5-sonnet'),
146
+ messages: convertToModelMessages(messages),
147
+ })
148
+
149
+ return result.toUIMessageStreamResponse()
150
+ })
151
+
152
+ export default app
153
+ ```
154
+
155
+ ### wrangler.toml
156
+
157
+ ```toml
158
+ name = "ai-api"
159
+ main = "src/index.ts"
160
+ compatibility_date = "2024-01-01"
161
+
162
+ # API 키는 Cloudflare 대시보드에서 설정
163
+ # Settings > Variables > Environment Variables
164
+ ```
165
+
166
+ ---
167
+
168
+ ## 인기 모델
169
+
170
+ | 모델 ID | 설명 |
171
+ |---------|------|
172
+ | `anthropic/claude-3.5-sonnet` | Claude 3.5 Sonnet |
173
+ | `anthropic/claude-3-opus` | Claude 3 Opus |
174
+ | `openai/gpt-4o` | GPT-4o |
175
+ | `openai/gpt-4-turbo` | GPT-4 Turbo |
176
+ | `google/gemini-pro-1.5` | Gemini Pro 1.5 |
177
+ | `meta-llama/llama-3.1-405b-instruct` | Llama 3.1 405B |
178
+ | `meta-llama/llama-3.1-70b-instruct` | Llama 3.1 70B |
179
+ | `mistralai/mistral-large` | Mistral Large |
180
+
181
+ 전체 모델 목록: [OpenRouter Models](https://openrouter.ai/docs#models)
182
+
183
+ ---
184
+
185
+ ## 도구 사용
186
+
187
+ ```typescript
188
+ import { Hono } from 'hono'
189
+ import { streamText, tool, convertToModelMessages } from 'ai'
190
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
191
+ import { z } from 'zod'
192
+
193
+ type Bindings = {
194
+ OPENROUTER_API_KEY: string
195
+ }
196
+
197
+ const app = new Hono<{ Bindings: Bindings }>()
198
+
199
+ app.post('/api/assistant', async (c) => {
200
+ const openrouter = createOpenRouter({
201
+ apiKey: c.env.OPENROUTER_API_KEY,
202
+ })
203
+
204
+ const { messages } = await c.req.json()
205
+
206
+ const result = streamText({
207
+ model: openrouter.chat('anthropic/claude-3.5-sonnet'),
208
+ messages: convertToModelMessages(messages),
209
+ tools: {
210
+ getWeather: tool({
211
+ description: 'Get weather for a location',
212
+ inputSchema: z.object({
213
+ location: z.string().describe('City name'),
214
+ }),
215
+ execute: async ({ location }) => {
216
+ // 실제 날씨 API 호출
217
+ return { location, temperature: 22, condition: 'Sunny' }
218
+ },
219
+ }),
220
+ searchProducts: tool({
221
+ description: 'Search products in database',
222
+ inputSchema: z.object({
223
+ query: z.string(),
224
+ limit: z.number().optional().default(10),
225
+ }),
226
+ execute: async ({ query, limit }) => {
227
+ // 데이터베이스 검색
228
+ return { products: [], total: 0 }
229
+ },
230
+ }),
231
+ },
232
+ })
233
+
234
+ return result.toUIMessageStreamResponse()
235
+ })
236
+
237
+ export default app
238
+ ```
239
+
240
+ ---
241
+
242
+ ## 구조화된 출력
243
+
244
+ ```typescript
245
+ import { Hono } from 'hono'
246
+ import { generateObject } from 'ai'
247
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
248
+ import { z } from 'zod'
249
+
250
+ type Bindings = {
251
+ OPENROUTER_API_KEY: string
252
+ }
253
+
254
+ const app = new Hono<{ Bindings: Bindings }>()
255
+
256
+ const userSchema = z.object({
257
+ name: z.string(),
258
+ age: z.number(),
259
+ skills: z.array(z.string()),
260
+ })
261
+
262
+ app.post('/api/generate-user', async (c) => {
263
+ const openrouter = createOpenRouter({
264
+ apiKey: c.env.OPENROUTER_API_KEY,
265
+ })
266
+
267
+ const { prompt } = await c.req.json()
268
+
269
+ const { object } = await generateObject({
270
+ model: openrouter.chat('anthropic/claude-3.5-sonnet'),
271
+ schema: userSchema,
272
+ prompt,
273
+ })
274
+
275
+ return c.json(object)
276
+ })
277
+
278
+ export default app
279
+ ```
280
+
281
+ ---
282
+
283
+ ## 미들웨어 패턴
284
+
285
+ ### OpenRouter 미들웨어
286
+
287
+ ```typescript
288
+ import { Hono } from 'hono'
289
+ import { createMiddleware } from 'hono/factory'
290
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
291
+
292
+ type Bindings = {
293
+ OPENROUTER_API_KEY: string
294
+ }
295
+
296
+ type Variables = {
297
+ openrouter: ReturnType<typeof createOpenRouter>
298
+ }
299
+
300
+ const openrouterMiddleware = createMiddleware<{
301
+ Bindings: Bindings
302
+ Variables: Variables
303
+ }>(async (c, next) => {
304
+ const openrouter = createOpenRouter({
305
+ apiKey: c.env.OPENROUTER_API_KEY,
306
+ })
307
+ c.set('openrouter', openrouter)
308
+ await next()
309
+ })
310
+
311
+ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()
312
+
313
+ app.use('/api/*', openrouterMiddleware)
314
+
315
+ app.post('/api/chat', async (c) => {
316
+ const openrouter = c.get('openrouter')
317
+ const { messages } = await c.req.json()
318
+
319
+ const result = streamText({
320
+ model: openrouter.chat('anthropic/claude-3.5-sonnet'),
321
+ messages,
322
+ })
323
+
324
+ return result.toUIMessageStreamResponse()
325
+ })
326
+
327
+ export default app
328
+ ```
329
+
330
+ ### Rate Limiting
331
+
332
+ ```typescript
333
+ import { Hono } from 'hono'
334
+ import { rateLimiter } from 'hono-rate-limiter'
335
+ import { streamText, convertToModelMessages } from 'ai'
336
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
337
+
338
+ type Bindings = {
339
+ OPENROUTER_API_KEY: string
340
+ }
341
+
342
+ const app = new Hono<{ Bindings: Bindings }>()
343
+
344
+ // Rate limiting 적용
345
+ app.use(
346
+ '/api/*',
347
+ rateLimiter({
348
+ windowMs: 60 * 1000, // 1분
349
+ limit: 20, // 최대 20 요청
350
+ standardHeaders: 'draft-6',
351
+ keyGenerator: (c) => c.req.header('x-forwarded-for') ?? 'anonymous',
352
+ })
353
+ )
354
+
355
+ app.post('/api/chat', async (c) => {
356
+ const openrouter = createOpenRouter({
357
+ apiKey: c.env.OPENROUTER_API_KEY,
358
+ })
359
+
360
+ const { messages } = await c.req.json()
361
+
362
+ const result = streamText({
363
+ model: openrouter.chat('anthropic/claude-3.5-sonnet'),
364
+ messages: convertToModelMessages(messages),
365
+ })
366
+
367
+ return result.toUIMessageStreamResponse()
368
+ })
369
+
370
+ export default app
371
+ ```
372
+
373
+ ---
374
+
375
+ ## 에러 처리
376
+
377
+ ```typescript
378
+ import { Hono } from 'hono'
379
+ import { HTTPException } from 'hono/http-exception'
380
+ import { streamText, convertToModelMessages } from 'ai'
381
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
382
+
383
+ type Bindings = {
384
+ OPENROUTER_API_KEY: string
385
+ }
386
+
387
+ const app = new Hono<{ Bindings: Bindings }>()
388
+
389
+ app.post('/api/chat', async (c) => {
390
+ try {
391
+ const openrouter = createOpenRouter({
392
+ apiKey: c.env.OPENROUTER_API_KEY,
393
+ })
394
+
395
+ const body = await c.req.json()
396
+
397
+ if (!body.messages || !Array.isArray(body.messages)) {
398
+ throw new HTTPException(400, { message: 'Invalid messages format' })
399
+ }
400
+
401
+ const result = streamText({
402
+ model: openrouter.chat(body.model ?? 'anthropic/claude-3.5-sonnet'),
403
+ messages: convertToModelMessages(body.messages),
404
+ })
405
+
406
+ return result.toUIMessageStreamResponse()
407
+ } catch (error) {
408
+ if (error instanceof HTTPException) {
409
+ throw error
410
+ }
411
+
412
+ console.error('OpenRouter Error:', error)
413
+ throw new HTTPException(500, { message: 'AI processing failed' })
414
+ }
415
+ })
416
+
417
+ // 글로벌 에러 핸들러
418
+ app.onError((err, c) => {
419
+ if (err instanceof HTTPException) {
420
+ return c.json({ error: err.message }, err.status)
421
+ }
422
+ return c.json({ error: 'Internal server error' }, 500)
423
+ })
424
+
425
+ export default app
426
+ ```
427
+
428
+ ---
429
+
430
+ ## 비용 관리
431
+
432
+ ### 사용량 추적
433
+
434
+ ```typescript
435
+ app.post('/api/generate', async (c) => {
436
+ const openrouter = createOpenRouter({
437
+ apiKey: c.env.OPENROUTER_API_KEY,
438
+ })
439
+
440
+ const { prompt } = await c.req.json()
441
+
442
+ const result = await generateText({
443
+ model: openrouter.chat('anthropic/claude-3.5-sonnet'),
444
+ prompt,
445
+ })
446
+
447
+ return c.json({
448
+ text: result.text,
449
+ usage: result.usage,
450
+ // { promptTokens: 10, completionTokens: 50, totalTokens: 60 }
451
+ })
452
+ })
453
+ ```
454
+
455
+ ---
456
+
457
+ ## 환경 변수
458
+
459
+ ```bash
460
+ # .env (로컬 개발)
461
+ OPENROUTER_API_KEY=sk-or-v1-...
462
+ ```
463
+
464
+ ```toml
465
+ # wrangler.toml (Cloudflare Workers)
466
+ # API 키는 Cloudflare 대시보드에서 설정:
467
+ # Settings > Variables > Environment Variables
468
+ ```
469
+
470
+ ---
471
+
472
+ ## 리소스
473
+
474
+ - [OpenRouter 공식 문서](https://openrouter.ai/docs)
475
+ - [OpenRouter 대시보드](https://openrouter.ai/dashboard)
476
+ - [API 키 발급](https://openrouter.ai/keys)
477
+ - [모델 목록](https://openrouter.ai/docs#models)
478
+ - [GitHub 저장소](https://github.com/OpenRouterTeam/ai-sdk-provider)
479
+ - [상태 페이지](https://status.openrouter.ai)