@kood/claude-code 0.2.4 → 0.3.0

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 (130) hide show
  1. package/dist/index.js +13 -8
  2. package/package.json +1 -1
  3. package/templates/.claude/agents/code-reviewer.md +371 -19
  4. package/templates/.claude/agents/dependency-manager.md +197 -0
  5. package/templates/.claude/agents/deployment-validator.md +136 -0
  6. package/templates/.claude/agents/git-operator.md +147 -0
  7. package/templates/.claude/agents/implementation-executor.md +202 -0
  8. package/templates/.claude/agents/lint-fixer.md +155 -0
  9. package/templates/.claude/agents/refactor-advisor.md +339 -29
  10. package/templates/.claude/commands/agent-creator.md +355 -0
  11. package/templates/.claude/commands/docs-creator.md +404 -163
  12. package/templates/.claude/commands/docs-refactor.md +400 -113
  13. package/templates/.claude/commands/execute.md +357 -185
  14. package/templates/.claude/commands/git-all.md +16 -70
  15. package/templates/.claude/commands/git-session.md +36 -68
  16. package/templates/.claude/commands/git.md +20 -69
  17. package/templates/.claude/commands/lint-fix.md +164 -107
  18. package/templates/.claude/commands/lint-init.md +142 -168
  19. package/templates/.claude/commands/plan.md +300 -84
  20. package/templates/.claude/commands/prd.md +613 -0
  21. package/templates/.claude/commands/pre-deploy.md +242 -0
  22. package/templates/.claude/commands/subagent-creator.md +118 -0
  23. package/templates/.claude/commands/version-update.md +45 -57
  24. package/templates/hono/CLAUDE.md +99 -54
  25. package/templates/hono/docs/guides/conventions.md +352 -0
  26. package/templates/hono/docs/guides/env-setup.md +347 -0
  27. package/templates/hono/docs/guides/getting-started.md +239 -0
  28. package/templates/hono/docs/library/hono/error-handling.md +20 -29
  29. package/templates/hono/docs/library/hono/index.md +25 -52
  30. package/templates/hono/docs/library/hono/middleware.md +16 -75
  31. package/templates/hono/docs/library/hono/rpc.md +7 -35
  32. package/templates/hono/docs/library/hono/validation.md +25 -45
  33. package/templates/hono/docs/library/t3-env/index.md +374 -0
  34. package/templates/npx/CLAUDE.md +165 -65
  35. package/templates/npx/docs/library/commander/index.md +10 -73
  36. package/templates/npx/docs/library/fs-extra/index.md +21 -113
  37. package/templates/npx/docs/library/prompts/index.md +30 -176
  38. package/templates/npx/docs/references/patterns.md +75 -48
  39. package/templates/tanstack-start/CLAUDE.md +101 -77
  40. package/templates/tanstack-start/docs/architecture.md +427 -0
  41. package/templates/tanstack-start/docs/design.md +558 -0
  42. package/templates/tanstack-start/docs/guides/conventions.md +132 -32
  43. package/templates/tanstack-start/docs/guides/env-setup.md +127 -62
  44. package/templates/tanstack-start/docs/guides/getting-started.md +81 -20
  45. package/templates/tanstack-start/docs/guides/hooks.md +241 -36
  46. package/templates/tanstack-start/docs/guides/routes.md +213 -61
  47. package/templates/tanstack-start/docs/guides/services.md +260 -24
  48. package/templates/tanstack-start/docs/library/better-auth/index.md +469 -16
  49. package/templates/tanstack-start/docs/library/t3-env/index.md +307 -0
  50. package/templates/tanstack-start/docs/library/tanstack-query/index.md +12 -21
  51. package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +22 -35
  52. package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +7 -24
  53. package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +26 -39
  54. package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +23 -26
  55. package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +32 -147
  56. package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +25 -167
  57. package/templates/tanstack-start/docs/library/tanstack-router/index.md +39 -74
  58. package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +46 -116
  59. package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +35 -154
  60. package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +32 -171
  61. package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +7 -15
  62. package/templates/tanstack-start/docs/library/tanstack-start/routing.md +16 -23
  63. package/templates/tanstack-start/docs/library/zod/complex-types.md +12 -31
  64. package/templates/tanstack-start/docs/library/zod/index.md +18 -35
  65. package/templates/tanstack-start/docs/library/zod/transforms.md +11 -25
  66. package/templates/tanstack-start/docs/library/zod/validation.md +12 -34
  67. package/templates/.claude/agents/debug-detective.md +0 -37
  68. package/templates/.claude/agents/test-writer.md +0 -41
  69. package/templates/.claude/commands/feedback.md +0 -199
  70. package/templates/.claude/commands/ts-fix.md +0 -176
  71. package/templates/.claude/skills/command-creator/LICENSE.txt +0 -202
  72. package/templates/.claude/skills/command-creator/SKILL.md +0 -245
  73. package/templates/.claude/skills/command-creator/scripts/init_command.py +0 -244
  74. package/templates/.claude/skills/command-creator/scripts/package_command.py +0 -125
  75. package/templates/.claude/skills/command-creator/scripts/quick_validate.py +0 -143
  76. package/templates/.claude/skills/frontend-design/SKILL.md +0 -310
  77. package/templates/.claude/skills/frontend-design/references/animation-patterns.md +0 -446
  78. package/templates/.claude/skills/frontend-design/references/colors-2026.md +0 -244
  79. package/templates/.claude/skills/frontend-design/references/typography-2026.md +0 -302
  80. package/templates/.claude/skills/gemini-review/SKILL.md +0 -118
  81. package/templates/.claude/skills/gemini-review/references/checklists.md +0 -129
  82. package/templates/.claude/skills/gemini-review/references/prompt-templates.md +0 -274
  83. package/templates/.claude/skills/skill-creator/LICENSE.txt +0 -202
  84. package/templates/.claude/skills/skill-creator/SKILL.md +0 -184
  85. package/templates/.claude/skills/skill-creator/scripts/init_skill.py +0 -303
  86. package/templates/.claude/skills/skill-creator/scripts/package_skill.py +0 -110
  87. package/templates/.claude/skills/skill-creator/scripts/quick_validate.py +0 -65
  88. package/templates/hono/docs/library/ai-sdk/index.md +0 -190
  89. package/templates/hono/docs/library/ai-sdk/openrouter.md +0 -111
  90. package/templates/hono/docs/library/ai-sdk/providers.md +0 -102
  91. package/templates/hono/docs/library/ai-sdk/streaming.md +0 -146
  92. package/templates/hono/docs/library/ai-sdk/structured-output.md +0 -161
  93. package/templates/hono/docs/library/ai-sdk/tools.md +0 -144
  94. package/templates/hono/docs/library/drizzle/cloudflare-d1.md +0 -247
  95. package/templates/hono/docs/library/drizzle/config.md +0 -167
  96. package/templates/hono/docs/library/drizzle/index.md +0 -259
  97. package/templates/hono/docs/library/hono/env-setup.md +0 -169
  98. package/templates/hono/docs/library/pino/index.md +0 -146
  99. package/templates/tanstack-start/docs/architecture/architecture.md +0 -243
  100. package/templates/tanstack-start/docs/deployment/cloudflare.md +0 -132
  101. package/templates/tanstack-start/docs/deployment/index.md +0 -163
  102. package/templates/tanstack-start/docs/deployment/nitro.md +0 -110
  103. package/templates/tanstack-start/docs/deployment/railway.md +0 -147
  104. package/templates/tanstack-start/docs/deployment/vercel.md +0 -135
  105. package/templates/tanstack-start/docs/design/components.md +0 -175
  106. package/templates/tanstack-start/docs/design/index.md +0 -151
  107. package/templates/tanstack-start/docs/design/safe-area.md +0 -118
  108. package/templates/tanstack-start/docs/design/tailwind-setup.md +0 -156
  109. package/templates/tanstack-start/docs/library/ai-sdk/hooks.md +0 -472
  110. package/templates/tanstack-start/docs/library/ai-sdk/index.md +0 -264
  111. package/templates/tanstack-start/docs/library/ai-sdk/openrouter.md +0 -371
  112. package/templates/tanstack-start/docs/library/ai-sdk/providers.md +0 -403
  113. package/templates/tanstack-start/docs/library/ai-sdk/streaming.md +0 -320
  114. package/templates/tanstack-start/docs/library/ai-sdk/structured-output.md +0 -454
  115. package/templates/tanstack-start/docs/library/ai-sdk/tools.md +0 -473
  116. package/templates/tanstack-start/docs/library/better-auth/2fa.md +0 -48
  117. package/templates/tanstack-start/docs/library/better-auth/advanced.md +0 -55
  118. package/templates/tanstack-start/docs/library/better-auth/plugins.md +0 -34
  119. package/templates/tanstack-start/docs/library/better-auth/session.md +0 -47
  120. package/templates/tanstack-start/docs/library/better-auth/setup.md +0 -41
  121. package/templates/tanstack-start/docs/library/drizzle/cloudflare-d1.md +0 -147
  122. package/templates/tanstack-start/docs/library/drizzle/config.md +0 -118
  123. package/templates/tanstack-start/docs/library/drizzle/crud.md +0 -205
  124. package/templates/tanstack-start/docs/library/drizzle/index.md +0 -79
  125. package/templates/tanstack-start/docs/library/drizzle/relations.md +0 -202
  126. package/templates/tanstack-start/docs/library/drizzle/schema.md +0 -154
  127. package/templates/tanstack-start/docs/library/drizzle/setup.md +0 -96
  128. package/templates/tanstack-start/docs/library/drizzle/transactions.md +0 -127
  129. package/templates/tanstack-start/docs/library/pino/index.md +0 -320
  130. /package/templates/hono/docs/{architecture/architecture.md → architecture.md} +0 -0
@@ -1,473 +0,0 @@
1
- # AI SDK - Tool Calling
2
-
3
- > **상위 문서**: [AI SDK](./index.md)
4
-
5
- ---
6
-
7
- ## 개요
8
-
9
- AI SDK의 도구(Tool)를 사용하면 AI 모델이 외부 함수를 호출할 수 있습니다. 날씨 조회, 데이터베이스 검색, API 호출 등 다양한 작업을 수행할 수 있습니다.
10
-
11
- ---
12
-
13
- ## 기본 도구 정의
14
-
15
- ```typescript
16
- import { generateText, tool } from 'ai'
17
- import { openai } from '@ai-sdk/openai'
18
- import { z } from 'zod'
19
-
20
- const { text, toolCalls, toolResults } = await generateText({
21
- model: openai('gpt-4o'),
22
- prompt: 'What is the weather in Seoul?',
23
- tools: {
24
- getWeather: tool({
25
- description: 'Get the weather for a location',
26
- inputSchema: z.object({
27
- location: z.string().describe('The city name'),
28
- }),
29
- execute: async ({ location }) => {
30
- // 실제 날씨 API 호출
31
- return {
32
- location,
33
- temperature: 22,
34
- condition: 'Sunny',
35
- }
36
- },
37
- }),
38
- },
39
- })
40
- ```
41
-
42
- ---
43
-
44
- ## tool() 함수 구조
45
-
46
- ```typescript
47
- import { tool } from 'ai'
48
- import { z } from 'zod'
49
-
50
- const myTool = tool({
51
- // 도구 설명 (모델이 언제 사용할지 결정하는데 사용)
52
- description: 'Tool description for the AI model',
53
-
54
- // 입력 스키마 (Zod로 정의)
55
- inputSchema: z.object({
56
- param1: z.string().describe('Parameter description'),
57
- param2: z.number().optional(),
58
- }),
59
-
60
- // 실행 함수
61
- execute: async (args, context) => {
62
- // args: 스키마에 맞는 입력 값
63
- // context: { toolCallId, messages } 등 컨텍스트 정보
64
- return { result: 'success' }
65
- },
66
- })
67
- ```
68
-
69
- ---
70
-
71
- ## 여러 도구 정의
72
-
73
- ```typescript
74
- import { generateText, tool } from 'ai'
75
- import { openai } from '@ai-sdk/openai'
76
- import { z } from 'zod'
77
-
78
- const result = await generateText({
79
- model: openai('gpt-4o'),
80
- prompt: 'What is the weather in Seoul and what attractions should I visit?',
81
- tools: {
82
- getWeather: tool({
83
- description: 'Get the weather for a location',
84
- inputSchema: z.object({
85
- location: z.string(),
86
- }),
87
- execute: async ({ location }) => ({
88
- temperature: 22,
89
- condition: 'Sunny',
90
- }),
91
- }),
92
-
93
- getAttractions: tool({
94
- description: 'Get tourist attractions for a city',
95
- inputSchema: z.object({
96
- city: z.string(),
97
- }),
98
- execute: async ({ city }) => ({
99
- attractions: ['Gyeongbokgung Palace', 'N Seoul Tower', 'Bukchon Hanok Village'],
100
- }),
101
- }),
102
- },
103
- })
104
-
105
- console.log(result.text)
106
- console.log(result.toolResults)
107
- ```
108
-
109
- ---
110
-
111
- ## 도구 호출 결과 접근
112
-
113
- ```typescript
114
- const result = await generateText({
115
- model: openai('gpt-4o'),
116
- prompt: 'Get the weather in Tokyo',
117
- tools: { /* ... */ },
118
- })
119
-
120
- // 도구 호출 목록
121
- for (const toolCall of result.toolCalls) {
122
- console.log('Tool:', toolCall.toolName)
123
- console.log('Input:', toolCall.input)
124
- }
125
-
126
- // 도구 실행 결과
127
- for (const toolResult of result.toolResults) {
128
- console.log('Tool:', toolResult.toolName)
129
- console.log('Output:', toolResult.output)
130
- }
131
- ```
132
-
133
- ---
134
-
135
- ## 스트리밍에서 도구 사용
136
-
137
- ```typescript
138
- import { streamText, tool } from 'ai'
139
- import { openai } from '@ai-sdk/openai'
140
- import { z } from 'zod'
141
-
142
- const result = streamText({
143
- model: openai('gpt-4o'),
144
- prompt: 'What is the weather?',
145
- tools: {
146
- getWeather: tool({
147
- description: 'Get weather',
148
- inputSchema: z.object({ location: z.string() }),
149
- execute: async ({ location }) => ({ temp: 22 }),
150
- }),
151
- },
152
- })
153
-
154
- // fullStream으로 도구 이벤트 처리
155
- for await (const event of result.fullStream) {
156
- switch (event.type) {
157
- case 'text-delta':
158
- process.stdout.write(event.textDelta)
159
- break
160
- case 'tool-call':
161
- console.log('Tool called:', event.toolName)
162
- break
163
- case 'tool-result':
164
- console.log('Tool result:', event.output)
165
- break
166
- }
167
- }
168
- ```
169
-
170
- ---
171
-
172
- ## API Route에서 도구 사용
173
-
174
- ```typescript
175
- // app/api/chat/route.ts
176
- import { streamText, tool, convertToModelMessages } from 'ai'
177
- import { openai } from '@ai-sdk/openai'
178
- import { z } from 'zod'
179
-
180
- export async function POST(req: Request) {
181
- const { messages } = await req.json()
182
-
183
- const result = streamText({
184
- model: openai('gpt-4o'),
185
- messages: convertToModelMessages(messages),
186
- tools: {
187
- getWeather: tool({
188
- description: 'Get weather for a location',
189
- inputSchema: z.object({
190
- location: z.string(),
191
- }),
192
- execute: async ({ location }) => {
193
- // 날씨 API 호출
194
- const weather = await fetchWeather(location)
195
- return weather
196
- },
197
- }),
198
- searchDatabase: tool({
199
- description: 'Search the database',
200
- inputSchema: z.object({
201
- query: z.string(),
202
- }),
203
- execute: async ({ query }) => {
204
- // 데이터베이스 검색
205
- const results = await db.search(query)
206
- return results
207
- },
208
- }),
209
- },
210
- })
211
-
212
- return result.toUIMessageStreamResponse()
213
- }
214
- ```
215
-
216
- ---
217
-
218
- ## 도구 컨텍스트 접근
219
-
220
- 도구 실행 시 추가 컨텍스트 정보에 접근할 수 있습니다:
221
-
222
- ```typescript
223
- const result = await generateText({
224
- model: openai('gpt-4o'),
225
- prompt: 'Hello',
226
- tools: {
227
- myTool: tool({
228
- description: 'My tool',
229
- inputSchema: z.object({ input: z.string() }),
230
- execute: async (args, context) => {
231
- // 도구 호출 ID
232
- console.log('Tool call ID:', context.toolCallId)
233
-
234
- // 전체 메시지 히스토리
235
- console.log('Messages:', context.messages)
236
-
237
- return { success: true }
238
- },
239
- }),
240
- },
241
- })
242
- ```
243
-
244
- ---
245
-
246
- ## 다중 단계 실행
247
-
248
- AI가 여러 도구를 순차적으로 호출하도록 허용:
249
-
250
- ```typescript
251
- import { generateText, stepCountIs } from 'ai'
252
-
253
- const result = await generateText({
254
- model: openai('gpt-4o'),
255
- prompt: 'Plan a trip to Seoul',
256
- tools: { /* ... */ },
257
- stopWhen: stepCountIs(5), // 최대 5단계
258
- })
259
-
260
- // 각 단계 정보 접근
261
- for (const step of result.steps) {
262
- console.log('Step:', step.toolCalls)
263
- }
264
-
265
- // 모든 도구 호출 추출
266
- const allToolCalls = result.steps.flatMap(step => step.toolCalls)
267
- ```
268
-
269
- ---
270
-
271
- ## 도구 호출 복구
272
-
273
- 잘못된 도구 호출을 자동으로 복구:
274
-
275
- ```typescript
276
- import { generateText, generateObject, NoSuchToolError, tool } from 'ai'
277
- import { openai } from '@ai-sdk/openai'
278
-
279
- const result = await generateText({
280
- model: openai('gpt-4o'),
281
- prompt: 'Get weather',
282
- tools: { /* ... */ },
283
-
284
- experimental_repairToolCall: async ({ toolCall, tools, inputSchema, error }) => {
285
- // 존재하지 않는 도구면 복구 시도 안함
286
- if (NoSuchToolError.isInstance(error)) {
287
- return null
288
- }
289
-
290
- // 더 강력한 모델로 입력 재생성
291
- const tool = tools[toolCall.toolName as keyof typeof tools]
292
-
293
- const { object: repairedArgs } = await generateObject({
294
- model: openai('gpt-4o'),
295
- schema: tool.inputSchema,
296
- prompt: [
297
- `The tool "${toolCall.toolName}" was called with invalid inputs:`,
298
- JSON.stringify(toolCall.input),
299
- 'Please fix the inputs according to the schema.',
300
- ].join('\n'),
301
- })
302
-
303
- return { ...toolCall, input: JSON.stringify(repairedArgs) }
304
- },
305
- })
306
- ```
307
-
308
- ---
309
-
310
- ## 도구 상태 스트리밍
311
-
312
- 도구 실행 중 상태를 UI로 전송:
313
-
314
- ```typescript
315
- import { streamText, tool, createUIMessageStream, createUIMessageStreamResponse } from 'ai'
316
-
317
- export async function POST(req: Request) {
318
- const { messages } = await req.json()
319
-
320
- const stream = createUIMessageStream({
321
- execute: ({ writer }) => {
322
- const result = streamText({
323
- model: openai('gpt-4o'),
324
- messages,
325
- tools: {
326
- longRunningTask: tool({
327
- description: 'A long running task',
328
- inputSchema: z.object({ input: z.string() }),
329
- execute: async (args, { toolCallId }) => {
330
- // 진행 상태 전송
331
- writer.write({
332
- type: 'data-tool-status',
333
- id: toolCallId,
334
- data: { status: 'started' },
335
- })
336
-
337
- // 작업 수행...
338
- await doSomething()
339
-
340
- writer.write({
341
- type: 'data-tool-status',
342
- id: toolCallId,
343
- data: { status: 'completed' },
344
- })
345
-
346
- return { result: 'done' }
347
- },
348
- }),
349
- },
350
- })
351
-
352
- writer.merge(result.toUIMessageStream())
353
- },
354
- })
355
-
356
- return createUIMessageStreamResponse({ stream })
357
- }
358
- ```
359
-
360
- ---
361
-
362
- ## 타입 안전한 도구
363
-
364
- ```typescript
365
- import { tool, TypedToolCall, TypedToolResult } from 'ai'
366
- import { z } from 'zod'
367
-
368
- const myToolSet = {
369
- greet: tool({
370
- description: 'Greet a user',
371
- inputSchema: z.object({ name: z.string() }),
372
- execute: async ({ name }) => `Hello, ${name}!`,
373
- }),
374
- calculate: tool({
375
- description: 'Calculate',
376
- inputSchema: z.object({
377
- a: z.number(),
378
- b: z.number(),
379
- }),
380
- execute: async ({ a, b }) => a + b,
381
- }),
382
- }
383
-
384
- // 타입 추출
385
- type MyToolCall = TypedToolCall<typeof myToolSet>
386
- type MyToolResult = TypedToolResult<typeof myToolSet>
387
-
388
- // 타입 안전한 함수
389
- async function generate(prompt: string): Promise<{
390
- text: string
391
- toolCalls: MyToolCall[]
392
- toolResults: MyToolResult[]
393
- }> {
394
- return generateText({
395
- model: openai('gpt-4o'),
396
- tools: myToolSet,
397
- prompt,
398
- })
399
- }
400
- ```
401
-
402
- ---
403
-
404
- ## 클라이언트에서 도구 결과 표시
405
-
406
- ```tsx
407
- 'use client'
408
-
409
- import { useChat } from '@ai-sdk/react'
410
-
411
- export default function Chat() {
412
- const { messages } = useChat({ api: '/api/chat' })
413
-
414
- return (
415
- <div>
416
- {messages.map((m) => (
417
- <div key={m.id}>
418
- {/* 텍스트 */}
419
- {m.content && <p>{m.content}</p>}
420
-
421
- {/* 도구 호출 */}
422
- {m.toolInvocations?.map((tool, i) => (
423
- <div key={i} className="tool-invocation">
424
- <h4>Tool: {tool.toolName}</h4>
425
- <pre>Args: {JSON.stringify(tool.args, null, 2)}</pre>
426
-
427
- {tool.state === 'result' && (
428
- <pre>Result: {JSON.stringify(tool.result, null, 2)}</pre>
429
- )}
430
-
431
- {tool.state === 'partial-call' && (
432
- <span>Calling...</span>
433
- )}
434
- </div>
435
- ))}
436
- </div>
437
- ))}
438
- </div>
439
- )
440
- }
441
- ```
442
-
443
- ---
444
-
445
- ## 도구 정의 팁
446
-
447
- 1. **명확한 설명**: 모델이 언제 도구를 사용할지 이해하도록 상세히 작성
448
- 2. **스키마 설명**: 각 파라미터에 `.describe()` 추가
449
- 3. **에러 처리**: execute 함수에서 적절한 에러 처리
450
- 4. **반환값**: 모델이 이해할 수 있는 구조화된 데이터 반환
451
-
452
- ```typescript
453
- const goodTool = tool({
454
- description: `
455
- Search for products in the database.
456
- Use this when the user asks about available products,
457
- product prices, or product availability.
458
- `,
459
- inputSchema: z.object({
460
- query: z.string().describe('Search query for product name or category'),
461
- maxResults: z.number().default(10).describe('Maximum number of results'),
462
- category: z.string().optional().describe('Filter by category'),
463
- }),
464
- execute: async ({ query, maxResults, category }) => {
465
- try {
466
- const results = await db.products.search({ query, maxResults, category })
467
- return { success: true, products: results }
468
- } catch (error) {
469
- return { success: false, error: 'Failed to search products' }
470
- }
471
- },
472
- })
473
- ```
@@ -1,48 +0,0 @@
1
- # Better Auth - 2단계 인증 (2FA)
2
-
3
- ## 서버
4
-
5
- ```typescript
6
- import { twoFactor } from 'better-auth/plugins'
7
-
8
- plugins: [
9
- twoFactor({
10
- issuer: 'My App',
11
- otpOptions: {
12
- async sendOTP({ user, otp }) { await sendEmail({ to: user.email, html: `Code: ${otp}` }) },
13
- period: 300, length: 6,
14
- },
15
- backupCodeLength: 10,
16
- backupCodeCount: 10,
17
- }),
18
- ]
19
- ```
20
-
21
- ## 클라이언트
22
-
23
- ```typescript
24
- import { twoFactorClient } from 'better-auth/client/plugins'
25
- plugins: [twoFactorClient({ twoFactorPage: '/two-factor' })]
26
- ```
27
-
28
- ## 사용법
29
-
30
- ```typescript
31
- // 활성화
32
- const { data } = await authClient.twoFactor.enable({ password })
33
- // data.totpURI, data.backupCodes
34
-
35
- // TOTP 검증
36
- await authClient.twoFactor.verifyTotp({ code: '123456' })
37
-
38
- // OTP 전송 및 검증
39
- await authClient.twoFactor.sendOtp()
40
- await authClient.twoFactor.verifyOtp({ code })
41
-
42
- // 백업 코드
43
- await authClient.twoFactor.useBackupCode({ code: 'ABCD-1234' })
44
- await authClient.twoFactor.regenerateBackupCodes({ password })
45
-
46
- // 비활성화
47
- await authClient.twoFactor.disable({ password })
48
- ```
@@ -1,55 +0,0 @@
1
- # Better Auth - 고급 기능
2
-
3
- ## CAPTCHA
4
-
5
- ```typescript
6
- // 서버
7
- import { captcha } from 'better-auth/plugins'
8
- plugins: [captcha({
9
- provider: 'recaptcha',
10
- siteKey: SITE_KEY, secretKey: SECRET_KEY,
11
- protectEndpoints: ['/sign-up/email', '/sign-in/email'],
12
- })]
13
-
14
- // 클라이언트
15
- import { captchaClient } from 'better-auth/client/plugins'
16
- plugins: [captchaClient({ siteKey: SITE_KEY })]
17
- ```
18
-
19
- ## SSO
20
-
21
- ```typescript
22
- await authClient.signIn.sso({ providerId: 'provider-id', callbackURL: '/dashboard' })
23
- ```
24
-
25
- ## SIWE (Ethereum)
26
-
27
- ```typescript
28
- // 서버
29
- import { siwe } from 'better-auth/plugins'
30
- plugins: [siwe({ domain: 'example.com', uri: 'https://example.com' })]
31
-
32
- // 클라이언트
33
- const { data: nonce } = await authClient.siwe.getNonce()
34
- const message = await authClient.siwe.prepareMessage({ address, nonce: nonce.nonce })
35
- const signature = await signer.signMessage(message)
36
- await authClient.siwe.signIn({ message, signature })
37
- ```
38
-
39
- ## Stateless 모드
40
-
41
- ```typescript
42
- // DB 없이 소셜 로그인만
43
- export const auth = betterAuth({
44
- socialProviders: { google: { clientId, clientSecret } },
45
- })
46
-
47
- // Redis 하이브리드
48
- export const auth = betterAuth({
49
- secondaryStorage: {
50
- get: (key) => redis.get(key),
51
- set: (key, value, ttl) => redis.set(key, value, 'EX', ttl),
52
- delete: (key) => redis.del(key),
53
- },
54
- })
55
- ```
@@ -1,34 +0,0 @@
1
- # Better Auth - 플러그인
2
-
3
- ## Multi-Session
4
-
5
- ```typescript
6
- // 서버
7
- import { multiSession } from 'better-auth/plugins'
8
- plugins: [multiSession({ maximumSessions: 5 })]
9
-
10
- // 클라이언트
11
- import { multiSessionClient } from 'better-auth/client/plugins'
12
- plugins: [multiSessionClient()]
13
-
14
- // 사용
15
- await authClient.multiSession.listSessions()
16
- await authClient.multiSession.revokeSession({ sessionId })
17
- await authClient.multiSession.revokeOtherSessions()
18
- ```
19
-
20
- ## 플러그인 조합
21
-
22
- ```typescript
23
- import { multiSession, customSession, twoFactor, captcha } from 'better-auth/plugins'
24
-
25
- export const auth = betterAuth({
26
- database: prismaAdapter(prisma),
27
- plugins: [
28
- multiSession({ maximumSessions: 5 }),
29
- customSession({ schema: { session: { fields: { ipAddress: { type: 'string' } } } } }),
30
- twoFactor({ issuer: 'My App' }),
31
- captcha({ provider: 'recaptcha', siteKey: SITE_KEY, secretKey: SECRET_KEY }),
32
- ],
33
- })
34
- ```
@@ -1,47 +0,0 @@
1
- # Better Auth - 세션 관리
2
-
3
- ## 설정
4
-
5
- ```typescript
6
- export const auth = betterAuth({
7
- session: {
8
- expiresIn: 604800, // 7일 (초)
9
- updateAge: 86400, // 1일마다 갱신
10
- cookieCache: {
11
- enabled: true,
12
- maxAge: 5 * 60, // 5분
13
- strategy: 'compact', // 'compact' | 'jwt' | 'jwe'
14
- },
15
- },
16
- })
17
- ```
18
-
19
- ## 세션 조회
20
-
21
- ```typescript
22
- // 클라이언트
23
- const session = await authClient.getSession()
24
- const session = await authClient.getSession({ query: { disableCookieCache: true } })
25
-
26
- // 서버
27
- await auth.api.getSession({ headers: req.headers })
28
- ```
29
-
30
- ## Custom Session Plugin
31
-
32
- ```typescript
33
- import { customSession } from 'better-auth/plugins'
34
-
35
- export const auth = betterAuth({
36
- plugins: [
37
- customSession({
38
- schema: {
39
- session: { fields: { ipAddress: { type: 'string' }, metadata: { type: 'json' } } },
40
- },
41
- async onSessionCreate(session, context) {
42
- return { ...session, ipAddress: context.request.headers.get('x-forwarded-for') }
43
- },
44
- }),
45
- ],
46
- })
47
- ```
@@ -1,41 +0,0 @@
1
- # Better Auth - 설치 및 설정
2
-
3
- ## 설치
4
-
5
- ```bash
6
- yarn add better-auth
7
- ```
8
-
9
- ## 서버
10
-
11
- ```typescript
12
- import { betterAuth } from 'better-auth'
13
- import { prismaAdapter } from 'better-auth/adapters/prisma'
14
-
15
- export const auth = betterAuth({
16
- database: prismaAdapter(prisma),
17
- emailAndPassword: { enabled: true },
18
- socialProviders: {
19
- google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET },
20
- github: { clientId: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET },
21
- },
22
- })
23
- ```
24
-
25
- ## 클라이언트
26
-
27
- ```typescript
28
- import { createAuthClient } from 'better-auth/react'
29
- import { twoFactorClient } from 'better-auth/client/plugins'
30
-
31
- export const authClient = createAuthClient({
32
- plugins: [twoFactorClient({ twoFactorPage: '/two-factor' })],
33
- })
34
- ```
35
-
36
- ## TanStack Start 연동
37
-
38
- ```typescript
39
- export const getSession = createServerFn({ method: 'GET' })
40
- .handler(async ({ request }) => auth.api.getSession({ headers: request.headers }))
41
- ```