@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
|
@@ -15,7 +15,7 @@ npm install better-auth
|
|
|
15
15
|
## Minimal Setup
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
// src/lib/auth.ts -
|
|
18
|
+
// src/lib/auth.ts - Server
|
|
19
19
|
import { betterAuth } from 'better-auth'
|
|
20
20
|
import { prismaAdapter } from 'better-auth/adapters/prisma'
|
|
21
21
|
import { prisma } from '@/database/prisma'
|
|
@@ -25,7 +25,7 @@ export const auth = betterAuth({
|
|
|
25
25
|
emailAndPassword: { enabled: true },
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
-
// src/lib/auth-client.ts -
|
|
28
|
+
// src/lib/auth-client.ts - Client
|
|
29
29
|
import { createAuthClient } from 'better-auth/react'
|
|
30
30
|
|
|
31
31
|
export const authClient = createAuthClient({
|
|
@@ -55,17 +55,17 @@ export const POST = async ({ request }: { request: Request }) => auth.handler(re
|
|
|
55
55
|
|---------|--------|----------|
|
|
56
56
|
| Prisma | `better-auth/adapters/prisma` | `postgresql`, `mysql`, `sqlite` |
|
|
57
57
|
| Drizzle | `better-auth/adapters/drizzle` | `pg`, `mysql2`, `better-sqlite3` |
|
|
58
|
-
| Kysely | `better-auth/adapters/kysely` | dialect
|
|
58
|
+
| Kysely | `better-auth/adapters/kysely` | dialect-based |
|
|
59
59
|
|
|
60
60
|
## Auth Config
|
|
61
61
|
|
|
62
|
-
|
|
|
63
|
-
|
|
64
|
-
| `database` | `Adapter` |
|
|
65
|
-
| `baseURL` | `string` | `http://localhost:3000` |
|
|
66
|
-
| `basePath` | `string` | `/api/auth` | Auth
|
|
67
|
-
| `secret` | `string` |
|
|
68
|
-
| `trustedOrigins` | `string[]` | `[]` | CORS
|
|
62
|
+
| Option | Type | Default | Description |
|
|
63
|
+
|--------|------|---------|-------------|
|
|
64
|
+
| `database` | `Adapter` | Required | DB adapter |
|
|
65
|
+
| `baseURL` | `string` | `http://localhost:3000` | App URL |
|
|
66
|
+
| `basePath` | `string` | `/api/auth` | Auth path |
|
|
67
|
+
| `secret` | `string` | Environment variable | JWT secret |
|
|
68
|
+
| `trustedOrigins` | `string[]` | `[]` | CORS allowed origins |
|
|
69
69
|
|
|
70
70
|
## Social Providers
|
|
71
71
|
|
|
@@ -107,22 +107,22 @@ export const auth = betterAuth({
|
|
|
107
107
|
|
|
108
108
|
## Session Config
|
|
109
109
|
|
|
110
|
-
|
|
|
111
|
-
|
|
112
|
-
| `expiresIn` | `number` | `604800` (7
|
|
113
|
-
| `updateAge` | `number` | `86400` (1
|
|
114
|
-
| `cookieCache.enabled` | `boolean` | `true` |
|
|
115
|
-
| `cookieCache.maxAge` | `number` | `300` (5
|
|
116
|
-
| `cookieCache.strategy` | `'compact' \| 'jwt' \| 'jwe'` | `'compact'` |
|
|
110
|
+
| Option | Type | Default | Description |
|
|
111
|
+
|--------|------|---------|-------------|
|
|
112
|
+
| `expiresIn` | `number` | `604800` (7 days) | Session expiration time (seconds) |
|
|
113
|
+
| `updateAge` | `number` | `86400` (1 day) | Session renewal period (seconds) |
|
|
114
|
+
| `cookieCache.enabled` | `boolean` | `true` | Enable cookie cache |
|
|
115
|
+
| `cookieCache.maxAge` | `number` | `300` (5 min) | Cache validity time (seconds) |
|
|
116
|
+
| `cookieCache.strategy` | `'compact' \| 'jwt' \| 'jwe'` | `'compact'` | Cache strategy |
|
|
117
117
|
|
|
118
118
|
```typescript
|
|
119
119
|
export const auth = betterAuth({
|
|
120
120
|
session: {
|
|
121
|
-
expiresIn: 604800, // 7
|
|
122
|
-
updateAge: 86400, //
|
|
121
|
+
expiresIn: 604800, // 7 days
|
|
122
|
+
updateAge: 86400, // Renew every day
|
|
123
123
|
cookieCache: {
|
|
124
124
|
enabled: true,
|
|
125
|
-
maxAge: 300, // 5
|
|
125
|
+
maxAge: 300, // 5 minutes
|
|
126
126
|
strategy: 'compact',
|
|
127
127
|
},
|
|
128
128
|
},
|
|
@@ -132,21 +132,21 @@ export const auth = betterAuth({
|
|
|
132
132
|
## Session Methods
|
|
133
133
|
|
|
134
134
|
```typescript
|
|
135
|
-
// ✅
|
|
135
|
+
// ✅ Client
|
|
136
136
|
const session = await authClient.getSession()
|
|
137
137
|
const session = await authClient.getSession({ query: { disableCookieCache: true } })
|
|
138
138
|
|
|
139
|
-
// ✅
|
|
139
|
+
// ✅ Server (TanStack Start)
|
|
140
140
|
export const getSession = createServerFn({ method: 'GET' })
|
|
141
141
|
.handler(async ({ request }) => {
|
|
142
142
|
const session = await auth.api.getSession({ headers: request.headers })
|
|
143
143
|
return session
|
|
144
144
|
})
|
|
145
145
|
|
|
146
|
-
// ✅
|
|
146
|
+
// ✅ Update session
|
|
147
147
|
await authClient.updateUser({ name: 'New Name' })
|
|
148
148
|
|
|
149
|
-
// ✅
|
|
149
|
+
// ✅ Sign out
|
|
150
150
|
await authClient.signOut()
|
|
151
151
|
```
|
|
152
152
|
|
|
@@ -188,30 +188,30 @@ export const auth = betterAuth({
|
|
|
188
188
|
## Email/Password
|
|
189
189
|
|
|
190
190
|
```typescript
|
|
191
|
-
// ✅
|
|
191
|
+
// ✅ Sign up
|
|
192
192
|
await authClient.signUp.email({
|
|
193
193
|
email: 'user@example.com',
|
|
194
194
|
password: 'password123',
|
|
195
195
|
name: 'User Name',
|
|
196
196
|
})
|
|
197
197
|
|
|
198
|
-
// ✅
|
|
198
|
+
// ✅ Sign in
|
|
199
199
|
await authClient.signIn.email({
|
|
200
200
|
email: 'user@example.com',
|
|
201
201
|
password: 'password123',
|
|
202
202
|
})
|
|
203
203
|
|
|
204
|
-
// ✅
|
|
204
|
+
// ✅ Request password reset
|
|
205
205
|
await authClient.forgetPassword({ email: 'user@example.com' })
|
|
206
206
|
|
|
207
|
-
// ✅
|
|
207
|
+
// ✅ Reset password
|
|
208
208
|
await authClient.resetPassword({ token, password: 'newpassword' })
|
|
209
209
|
```
|
|
210
210
|
|
|
211
211
|
## Social Login
|
|
212
212
|
|
|
213
213
|
```typescript
|
|
214
|
-
// ✅
|
|
214
|
+
// ✅ Social sign in
|
|
215
215
|
await authClient.signIn.social({ provider: 'google', callbackURL: '/dashboard' })
|
|
216
216
|
await authClient.signIn.social({ provider: 'github', callbackURL: '/dashboard' })
|
|
217
217
|
|
|
@@ -265,26 +265,26 @@ export const authClient = createAuthClient({
|
|
|
265
265
|
### 2FA Usage
|
|
266
266
|
|
|
267
267
|
```typescript
|
|
268
|
-
// ✅ TOTP
|
|
268
|
+
// ✅ Enable TOTP
|
|
269
269
|
const { data } = await authClient.twoFactor.enable({ password: 'current-password' })
|
|
270
270
|
// data: { totpURI: 'otpauth://...', backupCodes: ['ABCD-1234', ...] }
|
|
271
271
|
|
|
272
|
-
// ✅ TOTP
|
|
272
|
+
// ✅ Verify TOTP
|
|
273
273
|
await authClient.twoFactor.verifyTotp({ code: '123456' })
|
|
274
274
|
|
|
275
|
-
// ✅ OTP
|
|
275
|
+
// ✅ Send OTP
|
|
276
276
|
await authClient.twoFactor.sendOtp()
|
|
277
277
|
|
|
278
|
-
// ✅ OTP
|
|
278
|
+
// ✅ Verify OTP
|
|
279
279
|
await authClient.twoFactor.verifyOtp({ code: '123456' })
|
|
280
280
|
|
|
281
|
-
// ✅
|
|
281
|
+
// ✅ Use backup code
|
|
282
282
|
await authClient.twoFactor.useBackupCode({ code: 'ABCD-1234' })
|
|
283
283
|
|
|
284
|
-
// ✅
|
|
284
|
+
// ✅ Regenerate backup codes
|
|
285
285
|
const { data } = await authClient.twoFactor.regenerateBackupCodes({ password: 'current-password' })
|
|
286
286
|
|
|
287
|
-
// ✅ 2FA
|
|
287
|
+
// ✅ Disable 2FA
|
|
288
288
|
await authClient.twoFactor.disable({ password: 'current-password' })
|
|
289
289
|
```
|
|
290
290
|
|
|
@@ -296,35 +296,35 @@ await authClient.twoFactor.disable({ password: 'current-password' })
|
|
|
296
296
|
|
|
297
297
|
## Plugin System
|
|
298
298
|
|
|
299
|
-
| Plugin | Import |
|
|
300
|
-
|
|
301
|
-
| `multiSession` | `better-auth/plugins` |
|
|
302
|
-
| `customSession` | `better-auth/plugins` |
|
|
303
|
-
| `twoFactor` | `better-auth/plugins` |
|
|
304
|
-
| `captcha` | `better-auth/plugins` | CAPTCHA
|
|
299
|
+
| Plugin | Import | Features |
|
|
300
|
+
|--------|--------|----------|
|
|
301
|
+
| `multiSession` | `better-auth/plugins` | Multi-session management |
|
|
302
|
+
| `customSession` | `better-auth/plugins` | Session field extension |
|
|
303
|
+
| `twoFactor` | `better-auth/plugins` | Two-factor authentication |
|
|
304
|
+
| `captcha` | `better-auth/plugins` | CAPTCHA verification |
|
|
305
305
|
|
|
306
306
|
## Multi-Session
|
|
307
307
|
|
|
308
308
|
```typescript
|
|
309
|
-
// ✅
|
|
309
|
+
// ✅ Server
|
|
310
310
|
import { multiSession } from 'better-auth/plugins'
|
|
311
311
|
|
|
312
312
|
export const auth = betterAuth({
|
|
313
313
|
plugins: [
|
|
314
314
|
multiSession({
|
|
315
|
-
maximumSessions: 5, //
|
|
315
|
+
maximumSessions: 5, // Maximum number of sessions
|
|
316
316
|
}),
|
|
317
317
|
],
|
|
318
318
|
})
|
|
319
319
|
|
|
320
|
-
// ✅
|
|
320
|
+
// ✅ Client
|
|
321
321
|
import { multiSessionClient } from 'better-auth/client/plugins'
|
|
322
322
|
|
|
323
323
|
export const authClient = createAuthClient({
|
|
324
324
|
plugins: [multiSessionClient()],
|
|
325
325
|
})
|
|
326
326
|
|
|
327
|
-
//
|
|
327
|
+
// Usage
|
|
328
328
|
const sessions = await authClient.multiSession.listSessions()
|
|
329
329
|
await authClient.multiSession.revokeSession({ sessionId: 'session-id' })
|
|
330
330
|
await authClient.multiSession.revokeOtherSessions()
|
|
@@ -333,7 +333,7 @@ await authClient.multiSession.revokeOtherSessions()
|
|
|
333
333
|
## CAPTCHA
|
|
334
334
|
|
|
335
335
|
```typescript
|
|
336
|
-
// ✅
|
|
336
|
+
// ✅ Server
|
|
337
337
|
import { captcha } from 'better-auth/plugins'
|
|
338
338
|
|
|
339
339
|
export const auth = betterAuth({
|
|
@@ -347,7 +347,7 @@ export const auth = betterAuth({
|
|
|
347
347
|
],
|
|
348
348
|
})
|
|
349
349
|
|
|
350
|
-
// ✅
|
|
350
|
+
// ✅ Client
|
|
351
351
|
import { captchaClient } from 'better-auth/client/plugins'
|
|
352
352
|
|
|
353
353
|
export const authClient = createAuthClient({
|
|
@@ -368,8 +368,8 @@ export const authClient = createAuthClient({
|
|
|
368
368
|
## SIWE (Ethereum)
|
|
369
369
|
|
|
370
370
|
```typescript
|
|
371
|
-
//
|
|
372
|
-
//
|
|
371
|
+
// Server: siwe({ domain, uri })
|
|
372
|
+
// Client:
|
|
373
373
|
const { data } = await authClient.siwe.getNonce()
|
|
374
374
|
const message = await authClient.siwe.prepareMessage({ address: '0x...', nonce: data.nonce })
|
|
375
375
|
const signature = await signer.signMessage(message)
|
|
@@ -379,7 +379,7 @@ await authClient.siwe.signIn({ message, signature })
|
|
|
379
379
|
## Stateless Mode
|
|
380
380
|
|
|
381
381
|
```typescript
|
|
382
|
-
// ✅
|
|
382
|
+
// ✅ Social login without DB
|
|
383
383
|
export const auth = betterAuth({
|
|
384
384
|
socialProviders: {
|
|
385
385
|
google: {
|
|
@@ -422,8 +422,8 @@ export const auth = betterAuth({
|
|
|
422
422
|
|
|
423
423
|
## TanStack Start Integration
|
|
424
424
|
|
|
425
|
-
|
|
|
426
|
-
|
|
425
|
+
| Pattern | Purpose |
|
|
426
|
+
|---------|---------|
|
|
427
427
|
| API Handler | `src/routes/api/auth/$.ts` |
|
|
428
428
|
| Server Function | `createServerFn` + `auth.api.getSession` |
|
|
429
429
|
| Middleware | `auth.api.getSession` + redirect |
|
|
@@ -431,7 +431,7 @@ export const auth = betterAuth({
|
|
|
431
431
|
### Server Function Pattern
|
|
432
432
|
|
|
433
433
|
```typescript
|
|
434
|
-
// ✅
|
|
434
|
+
// ✅ Auth check Server Function
|
|
435
435
|
export const requireAuth = createServerFn({ method: 'GET' })
|
|
436
436
|
.handler(async ({ request }) => {
|
|
437
437
|
const session = await auth.api.getSession({ headers: request.headers })
|
|
@@ -441,7 +441,7 @@ export const requireAuth = createServerFn({ method: 'GET' })
|
|
|
441
441
|
return session.user
|
|
442
442
|
})
|
|
443
443
|
|
|
444
|
-
// ✅
|
|
444
|
+
// ✅ Fetch protected data
|
|
445
445
|
export const getProtectedData = createServerFn({ method: 'GET' })
|
|
446
446
|
.handler(async ({ request }) => {
|
|
447
447
|
const user = await requireAuth()
|
|
@@ -465,23 +465,23 @@ export const Route = createFileRoute('/dashboard')({
|
|
|
465
465
|
|
|
466
466
|
## Common Patterns
|
|
467
467
|
|
|
468
|
-
|
|
|
469
|
-
|
|
470
|
-
|
|
|
471
|
-
|
|
|
472
|
-
|
|
|
473
|
-
|
|
|
474
|
-
|
|
|
475
|
-
|
|
|
468
|
+
| Action | Pattern |
|
|
469
|
+
|--------|---------|
|
|
470
|
+
| Sign in | `authClient.signIn.email({ email, password })` |
|
|
471
|
+
| Sign up | `authClient.signUp.email({ email, password, name })` |
|
|
472
|
+
| Sign out | `authClient.signOut()` |
|
|
473
|
+
| Get session | `authClient.getSession()` |
|
|
474
|
+
| Update user | `authClient.updateUser({ name })` |
|
|
475
|
+
| Reset password | `authClient.forgetPassword({ email })` → `authClient.resetPassword({ token, password })` |
|
|
476
476
|
|
|
477
477
|
## Do's & Don'ts
|
|
478
478
|
|
|
479
479
|
| ✅ Do | ❌ Don't |
|
|
480
480
|
|-------|----------|
|
|
481
|
-
| `auth.api.getSession()`
|
|
482
|
-
| `authClient`
|
|
483
|
-
|
|
|
484
|
-
| HTTPS
|
|
485
|
-
| `baseURL`
|
|
481
|
+
| Use `auth.api.getSession()` on server | Directly manipulate sessions on client |
|
|
482
|
+
| Use `authClient` on client | Hardcode secrets |
|
|
483
|
+
| Manage secrets via environment variables | Store session tokens in localStorage |
|
|
484
|
+
| HTTPS required in production | Deploy production with HTTP |
|
|
485
|
+
| Configure `baseURL` per environment | Hardcode absolute paths |
|
|
486
486
|
|
|
487
487
|
</patterns>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Prisma - Cloudflare D1
|
|
2
2
|
|
|
3
|
-
SQLite
|
|
3
|
+
SQLite-based serverless database. Different workflow from regular Prisma migrations.
|
|
4
4
|
|
|
5
|
-
⚠️
|
|
5
|
+
⚠️ No transaction support | Can't use prisma migrate - use wrangler | Preview status
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Configuration
|
|
8
8
|
|
|
9
9
|
```prisma
|
|
10
10
|
// schema.prisma
|
|
11
11
|
generator client {
|
|
12
12
|
provider = "prisma-client"
|
|
13
13
|
output = "../src/generated/prisma"
|
|
14
|
-
runtime = "cloudflare" //
|
|
14
|
+
runtime = "cloudflare" // Required
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
datasource db {
|
|
@@ -26,7 +26,7 @@ datasource db {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Usage
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
32
|
import { PrismaClient } from './generated/prisma'
|
|
@@ -44,33 +44,33 @@ export default {
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## Migration Workflow
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
# 1. D1
|
|
50
|
+
# 1. Create D1
|
|
51
51
|
npx wrangler d1 create my-database
|
|
52
52
|
|
|
53
|
-
# 2.
|
|
53
|
+
# 2. Create migration
|
|
54
54
|
npx wrangler d1 migrations create my-database init
|
|
55
55
|
|
|
56
|
-
# 3. SQL
|
|
56
|
+
# 3. Generate SQL (initial)
|
|
57
57
|
npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script --output prisma/migrations/0001.sql
|
|
58
58
|
|
|
59
|
-
# 4. SQL
|
|
59
|
+
# 4. Generate SQL (subsequent)
|
|
60
60
|
npx prisma migrate diff --from-local-d1 --to-schema-datamodel prisma/schema.prisma --script
|
|
61
61
|
|
|
62
|
-
# 5.
|
|
63
|
-
npx wrangler d1 migrations apply my-database --local #
|
|
64
|
-
npx wrangler d1 migrations apply my-database --remote #
|
|
62
|
+
# 5. Apply
|
|
63
|
+
npx wrangler d1 migrations apply my-database --local # Local
|
|
64
|
+
npx wrangler d1 migrations apply my-database --remote # Production
|
|
65
65
|
|
|
66
|
-
# 6. Client
|
|
66
|
+
# 6. Generate Client
|
|
67
67
|
npx prisma generate
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
##
|
|
70
|
+
## Limitations
|
|
71
71
|
|
|
72
|
-
|
|
|
72
|
+
| Feature | Regular SQLite | D1 |
|
|
73
73
|
|------|-------------|-----|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
74
|
+
| Migration | prisma migrate | wrangler d1 |
|
|
75
|
+
| Transactions | ✅ | ❌ |
|
|
76
|
+
| Connection | Direct | HTTP adapter |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Prisma - Config
|
|
1
|
+
# Prisma - Config File
|
|
2
2
|
|
|
3
|
-
Prisma v7 `prisma.config.ts`
|
|
3
|
+
Prisma v7 `prisma.config.ts` configuration.
|
|
4
4
|
|
|
5
|
-
## Multi-File
|
|
5
|
+
## Multi-File Schema (Required)
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
// prisma.config.ts
|
|
@@ -11,7 +11,7 @@ import path from 'node:path'
|
|
|
11
11
|
import { defineConfig, env } from 'prisma/config'
|
|
12
12
|
|
|
13
13
|
export default defineConfig({
|
|
14
|
-
schema: path.join('prisma', 'schema'), //
|
|
14
|
+
schema: path.join('prisma', 'schema'), // folder path!
|
|
15
15
|
migrations: {
|
|
16
16
|
path: 'prisma/migrations',
|
|
17
17
|
seed: 'tsx prisma/seed.ts',
|
|
@@ -22,16 +22,16 @@ export default defineConfig({
|
|
|
22
22
|
})
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Folder Structure
|
|
26
26
|
|
|
27
27
|
```
|
|
28
|
-
|
|
28
|
+
project/
|
|
29
29
|
├── prisma.config.ts
|
|
30
30
|
├── prisma/
|
|
31
31
|
│ ├── schema/
|
|
32
32
|
│ │ ├── +base.prisma # datasource, generator
|
|
33
|
-
│ │ ├── +enum.prisma # enum
|
|
34
|
-
│ │ └── user.prisma #
|
|
33
|
+
│ │ ├── +enum.prisma # enum definitions
|
|
34
|
+
│ │ └── user.prisma # models
|
|
35
35
|
│ └── migrations/
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -49,17 +49,17 @@ generator client {
|
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
##
|
|
52
|
+
## Configuration Options
|
|
53
53
|
|
|
54
|
-
|
|
|
54
|
+
| Option | Description |
|
|
55
55
|
|------|------|
|
|
56
|
-
| `schema` |
|
|
57
|
-
| `datasource.url` | DB URL (
|
|
56
|
+
| `schema` | Schema folder path |
|
|
57
|
+
| `datasource.url` | DB URL (required) |
|
|
58
58
|
| `datasource.shadowDatabaseUrl` | Shadow DB URL |
|
|
59
|
-
| `migrations.path` |
|
|
60
|
-
| `migrations.seed` |
|
|
59
|
+
| `migrations.path` | Migrations folder |
|
|
60
|
+
| `migrations.seed` | Seed command |
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## Seed File
|
|
63
63
|
|
|
64
64
|
```typescript
|
|
65
65
|
// prisma/seed.ts
|
|
@@ -69,7 +69,7 @@ const prisma = new PrismaClient()
|
|
|
69
69
|
|
|
70
70
|
async function main() {
|
|
71
71
|
await prisma.user.create({
|
|
72
|
-
data: { email: 'admin@example.com', name: '
|
|
72
|
+
data: { email: 'admin@example.com', name: 'Admin', role: 'ADMIN' },
|
|
73
73
|
})
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# Prisma - CRUD
|
|
1
|
+
# Prisma - CRUD Operations
|
|
2
2
|
|
|
3
3
|
## Create
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
//
|
|
6
|
+
// Single
|
|
7
7
|
const user = await prisma.user.create({
|
|
8
8
|
data: { email: 'alice@prisma.io', name: 'Alice' },
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// With relations
|
|
12
12
|
const user = await prisma.user.create({
|
|
13
13
|
data: {
|
|
14
14
|
email: 'bob@prisma.io',
|
|
@@ -27,22 +27,22 @@ posts: { create: [{
|
|
|
27
27
|
## Read
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
|
-
//
|
|
30
|
+
// Single
|
|
31
31
|
const user = await prisma.user.findUnique({ where: { email } })
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// Multiple
|
|
34
34
|
const users = await prisma.user.findMany({ where: { name: 'Alice' } })
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// With relations
|
|
37
37
|
const users = await prisma.user.findMany({ where: { role: 'ADMIN' }, include: { posts: true } })
|
|
38
38
|
|
|
39
|
-
//
|
|
39
|
+
// Field selection
|
|
40
40
|
const user = await prisma.user.findUnique({
|
|
41
41
|
where: { email },
|
|
42
42
|
select: { email: true, posts: { select: { title: true } } },
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
//
|
|
45
|
+
// Filter by relations
|
|
46
46
|
const users = await prisma.user.findMany({
|
|
47
47
|
where: { posts: { some: { published: false } } },
|
|
48
48
|
})
|
|
@@ -51,10 +51,10 @@ const users = await prisma.user.findMany({
|
|
|
51
51
|
## Update
|
|
52
52
|
|
|
53
53
|
```typescript
|
|
54
|
-
//
|
|
54
|
+
// Single
|
|
55
55
|
const user = await prisma.user.update({ where: { id }, data: { name: 'Updated' } })
|
|
56
56
|
|
|
57
|
-
//
|
|
57
|
+
// Multiple
|
|
58
58
|
await prisma.user.updateMany({ where: { role: 'USER' }, data: { role: 'ADMIN' } })
|
|
59
59
|
|
|
60
60
|
// Upsert
|
|
@@ -69,22 +69,22 @@ const user = await prisma.user.upsert({
|
|
|
69
69
|
|
|
70
70
|
```typescript
|
|
71
71
|
await prisma.user.delete({ where: { id } })
|
|
72
|
-
await prisma.user.deleteMany({}) //
|
|
73
|
-
await prisma.post.deleteMany({ where: { published: false } }) //
|
|
72
|
+
await prisma.user.deleteMany({}) // All
|
|
73
|
+
await prisma.post.deleteMany({ where: { published: false } }) // Conditional
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
##
|
|
76
|
+
## Filter Operators
|
|
77
77
|
|
|
78
78
|
```typescript
|
|
79
|
-
//
|
|
79
|
+
// String
|
|
80
80
|
{ contains: 'prisma', startsWith: 'A', endsWith: 'io' }
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// Number
|
|
83
83
|
{ gt: 18, gte: 18, lt: 65, lte: 65 }
|
|
84
84
|
|
|
85
|
-
//
|
|
85
|
+
// Array
|
|
86
86
|
{ in: [1, 2, 3], notIn: [4, 5] }
|
|
87
87
|
|
|
88
|
-
//
|
|
88
|
+
// Logical
|
|
89
89
|
{ OR: [...], AND: [...], NOT: {...} }
|
|
90
90
|
```
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
## Quick Reference
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
import { PrismaClient } from './generated/prisma' // v7
|
|
18
|
+
import { PrismaClient } from './generated/prisma' // v7 path!
|
|
19
19
|
export const prisma = new PrismaClient()
|
|
20
20
|
|
|
21
21
|
// CRUD
|
|
@@ -24,34 +24,34 @@ const user = await prisma.user.create({ data: { email, name } })
|
|
|
24
24
|
const updated = await prisma.user.update({ where: { id }, data: { name } })
|
|
25
25
|
const deleted = await prisma.user.delete({ where: { id } })
|
|
26
26
|
|
|
27
|
-
//
|
|
27
|
+
// Include relations
|
|
28
28
|
const userWithPosts = await prisma.user.findUnique({
|
|
29
29
|
where: { id },
|
|
30
30
|
include: { posts: true },
|
|
31
31
|
})
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
### v7 schema.prisma (⚠️
|
|
34
|
+
### v7 schema.prisma (⚠️ Important)
|
|
35
35
|
|
|
36
36
|
```prisma
|
|
37
37
|
generator client {
|
|
38
|
-
provider = "prisma-client" // v7! (prisma-client-js
|
|
39
|
-
output = "../generated/prisma" // output
|
|
38
|
+
provider = "prisma-client" // v7! (not prisma-client-js)
|
|
39
|
+
output = "../generated/prisma" // output is required!
|
|
40
40
|
}
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
### ⛔ Claude Code
|
|
43
|
+
### ⛔ Claude Code Forbidden
|
|
44
44
|
|
|
45
|
-
|
|
|
45
|
+
| Forbidden Actions |
|
|
46
46
|
|----------|
|
|
47
|
-
| prisma db push
|
|
48
|
-
| prisma migrate
|
|
49
|
-
| prisma generate
|
|
50
|
-
| schema.prisma
|
|
47
|
+
| Auto-run prisma db push |
|
|
48
|
+
| Auto-run prisma migrate |
|
|
49
|
+
| Auto-run prisma generate |
|
|
50
|
+
| Unauthorized schema.prisma modifications |
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
54
|
-
## Prisma Client
|
|
54
|
+
## Prisma Client Setup
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
57
|
// lib/prisma.ts
|
|
@@ -62,12 +62,12 @@ export const prisma = globalForPrisma.prisma ?? new PrismaClient({ log: ['query'
|
|
|
62
62
|
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## Migration Commands
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
npx prisma migrate dev --name init #
|
|
69
|
-
npx prisma migrate deploy #
|
|
70
|
-
npx prisma db push #
|
|
71
|
-
npx prisma generate # Client
|
|
68
|
+
npx prisma migrate dev --name init # Development migration
|
|
69
|
+
npx prisma migrate deploy # Production migration
|
|
70
|
+
npx prisma db push # Schema sync (dev only)
|
|
71
|
+
npx prisma generate # Generate Client
|
|
72
72
|
npx prisma studio # GUI
|
|
73
73
|
```
|