@kood/claude-code 0.3.9 → 0.3.11

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.
@@ -1,16 +1,11 @@
1
- # t3-env - Type-Safe Environment Variables
1
+ # t3-env
2
2
 
3
- > Zod-based type-safe environment variable management
3
+ > v1.x | Type-Safe Environment Variables
4
4
 
5
5
  <context>
6
6
 
7
- **Purpose:** Server/client environment variable separation, runtime validation, type safety
8
-
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
7
+ **Purpose:** Zod 기반 타입 안전 환경 변수 관리
8
+ **Features:** Server/Client 분리, 런타임 검증, Transform & Defaults, 프레임워크 무관
14
9
 
15
10
  </context>
16
11
 
@@ -18,12 +13,12 @@
18
13
 
19
14
  <forbidden>
20
15
 
21
- | Category | Forbidden |
16
+ | 분류 | 금지 |
22
17
  |------|------|
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 |
18
+ | **노출** | Server 변수를 클라이언트에 노출 |
19
+ | **접두사** | Client 변수에 `PUBLIC_` 없이 사용 |
20
+ | **직접 접근** | `process.env` 직접 사용 (env 객체 필수) |
21
+ | **타입** | any 타입으로 env 변수 접근 |
27
22
 
28
23
  </forbidden>
29
24
 
@@ -31,18 +26,19 @@
31
26
 
32
27
  <required>
33
28
 
34
- | Category | Required |
29
+ | 분류 | 필수 |
35
30
  |------|------|
36
- | **Install** | `@t3-oss/env-core zod` |
37
- | **Structure** | Create `src/env.ts` file |
38
- | **Prefix** | Client variables: Start with `PUBLIC_` |
31
+ | **설치** | `@t3-oss/env-core zod` |
32
+ | **구조** | `src/env.ts` 파일 생성 |
33
+ | **접두사** | Client 변수: `PUBLIC_` 시작 |
39
34
  | **Import** | `import { env } from '@/env'` |
35
+ | **검증** | Zod 스키마로 서버/클라이언트 변수 검증 |
40
36
 
41
37
  </required>
42
38
 
43
39
  ---
44
40
 
45
- <setup>
41
+ <installation>
46
42
 
47
43
  ## Installation
48
44
 
@@ -50,6 +46,12 @@
50
46
  npm install @t3-oss/env-core zod
51
47
  ```
52
48
 
49
+ </installation>
50
+
51
+ ---
52
+
53
+ <setup>
54
+
53
55
  ## Basic Setup
54
56
 
55
57
  `src/env.ts`:
@@ -59,21 +61,21 @@ import { createEnv } from '@t3-oss/env-core'
59
61
  import { z } from 'zod'
60
62
 
61
63
  export const env = createEnv({
62
- // Server-only variables
64
+ // Server-only variables
63
65
  server: {
64
66
  DATABASE_URL: z.url(),
65
67
  CLERK_SECRET_KEY: z.string().min(1),
66
68
  OPENAI_API_KEY: z.string().min(1),
67
69
  },
68
70
 
69
- // Client-exposed variables (PUBLIC_ prefix required)
71
+ // Client-exposed variables (PUBLIC_ prefix required)
70
72
  clientPrefix: 'PUBLIC_',
71
73
  client: {
72
74
  PUBLIC_API_URL: z.url().default('http://localhost:3000'),
73
75
  PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
74
76
  },
75
77
 
76
- // Runtime environment
78
+ // Runtime environment
77
79
  runtimeEnv: {
78
80
  // Server
79
81
  DATABASE_URL: process.env.DATABASE_URL,
@@ -88,15 +90,23 @@ export const env = createEnv({
88
90
  })
89
91
  ```
90
92
 
93
+ ## Config Options
94
+
95
+ | 옵션 | 타입 | 설명 |
96
+ |------|------|------|
97
+ | `server` | `Record<string, ZodSchema>` | 서버 전용 변수 스키마 |
98
+ | `client` | `Record<string, ZodSchema>` | 클라이언트 공개 변수 스키마 |
99
+ | `clientPrefix` | `string` | 클라이언트 변수 접두사 (기본: `PUBLIC_`) |
100
+ | `runtimeEnv` | `Record<string, any>` | 실제 환경 변수 매핑 |
101
+ | `emptyStringAsUndefined` | `boolean` | 빈 문자열 → undefined 처리 |
102
+
91
103
  </setup>
92
104
 
93
105
  ---
94
106
 
95
- <patterns>
96
-
97
- ## Common Patterns
107
+ <usage>
98
108
 
99
- ### Server Function
109
+ ## Server Function
100
110
 
101
111
  ```typescript
102
112
  import { createServerFn } from '@tanstack/start'
@@ -104,44 +114,185 @@ import { env } from '@/env'
104
114
 
105
115
  export const getUsers = createServerFn({ method: 'GET' }).handler(async () => {
106
116
  const db = await prisma.$connect(env.DATABASE_URL)
107
- // ^? string (type-safe)
117
+ // ^? string (타입 안전)
108
118
  return db.user.findMany()
109
119
  })
110
120
  ```
111
121
 
112
- ### Client Component
122
+ ## Client Component
113
123
 
114
124
  ```typescript
115
125
  import { env } from '@/env'
116
126
 
117
127
  export const ApiClient = () => {
118
128
  const apiUrl = env.PUBLIC_API_URL
119
- // ^? string (type-safe)
129
+ // ^? string (타입 안전)
120
130
 
121
- // ❌ Error: server variables cannot be accessed in client
131
+ // ❌ Error: server 변수는 클라이언트에서 접근 불가
122
132
  // const dbUrl = env.DATABASE_URL
123
133
  }
124
134
  ```
125
135
 
126
- ### Environment-Specific Defaults
136
+ </usage>
137
+
138
+ ---
139
+
140
+ <validation>
141
+
142
+ ## Validation Patterns
143
+
144
+ ### Email
145
+
146
+ ```typescript
147
+ server: {
148
+ ADMIN_EMAIL: z.email(),
149
+ SUPPORT_EMAIL: z.email().default('support@example.com'),
150
+ }
151
+ ```
152
+
153
+ ### URL
127
154
 
128
155
  ```typescript
129
156
  server: {
130
- NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
131
- LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
157
+ API_URL: z.url(),
158
+ WEBHOOK_URL: z.url().optional(),
159
+ }
160
+ ```
161
+
162
+ ### Enum
163
+
164
+ ```typescript
165
+ server: {
166
+ LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']),
167
+ DATABASE_PROVIDER: z.enum(['postgresql', 'mysql', 'sqlite']),
132
168
  }
133
169
  ```
134
170
 
135
- ### Transform Values
171
+ ### Number
136
172
 
137
173
  ```typescript
138
174
  server: {
175
+ PORT: z.coerce.number().positive().default(3000),
176
+ MAX_UPLOAD_SIZE: z.coerce.number().max(10485760), // 10MB
177
+ }
178
+ ```
179
+
180
+ ### Boolean
181
+
182
+ ```typescript
183
+ server: {
184
+ ENABLE_CACHE: z.coerce.boolean().default(true),
185
+ DEBUG_MODE: z.coerce.boolean().default(false),
186
+ }
187
+ ```
188
+
189
+ </validation>
190
+
191
+ ---
192
+
193
+ <examples>
194
+
195
+ ## Database + Auth
196
+
197
+ ```typescript
198
+ // src/env.ts
199
+ export const env = createEnv({
200
+ server: {
201
+ DATABASE_URL: z.url(),
202
+ DIRECT_URL: z.url().optional(), // Prisma connection pooling
203
+ CLERK_SECRET_KEY: z.string().min(1),
204
+ RESEND_API_KEY: z.string().min(1),
205
+ },
206
+ clientPrefix: 'PUBLIC_',
207
+ client: {
208
+ PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
209
+ },
210
+ runtimeEnv: {
211
+ DATABASE_URL: process.env.DATABASE_URL,
212
+ DIRECT_URL: process.env.DIRECT_URL,
213
+ CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
214
+ RESEND_API_KEY: process.env.RESEND_API_KEY,
215
+ PUBLIC_CLERK_PUBLISHABLE_KEY: import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY,
216
+ },
217
+ emptyStringAsUndefined: true,
218
+ })
219
+ ```
220
+
221
+ ## API Integration
222
+
223
+ ```typescript
224
+ // src/env.ts
225
+ export const env = createEnv({
226
+ server: {
227
+ OPENAI_API_KEY: z.string().min(1),
228
+ STRIPE_SECRET_KEY: z.string().min(1),
229
+ STRIPE_WEBHOOK_SECRET: z.string().min(1),
230
+ },
231
+ clientPrefix: 'PUBLIC_',
232
+ client: {
233
+ PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
234
+ PUBLIC_APP_URL: z.url(),
235
+ },
236
+ runtimeEnv: {
237
+ OPENAI_API_KEY: process.env.OPENAI_API_KEY,
238
+ STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
239
+ STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
240
+ PUBLIC_STRIPE_PUBLISHABLE_KEY: import.meta.env.PUBLIC_STRIPE_PUBLISHABLE_KEY,
241
+ PUBLIC_APP_URL: import.meta.env.PUBLIC_APP_URL,
242
+ },
243
+ emptyStringAsUndefined: true,
244
+ })
245
+ ```
246
+
247
+ ## Multi-Environment
248
+
249
+ ```typescript
250
+ // src/env.ts
251
+ export const env = createEnv({
252
+ server: {
253
+ NODE_ENV: z.enum(['development', 'production', 'test']),
254
+ DATABASE_URL: z.url(),
255
+ REDIS_URL: z.url().optional(), // Production only
256
+ },
257
+ clientPrefix: 'PUBLIC_',
258
+ client: {
259
+ PUBLIC_API_URL: z.url(),
260
+ PUBLIC_SENTRY_DSN: z.string().optional(), // Production only
261
+ },
262
+ runtimeEnv: {
263
+ NODE_ENV: process.env.NODE_ENV,
264
+ DATABASE_URL: process.env.DATABASE_URL,
265
+ REDIS_URL: process.env.REDIS_URL,
266
+ PUBLIC_API_URL: import.meta.env.PUBLIC_API_URL,
267
+ PUBLIC_SENTRY_DSN: import.meta.env.PUBLIC_SENTRY_DSN,
268
+ },
269
+ emptyStringAsUndefined: true,
270
+ })
271
+ ```
272
+
273
+ </examples>
274
+
275
+ ---
276
+
277
+ <transforms>
278
+
279
+ ## Transform Values
280
+
281
+ ```typescript
282
+ server: {
283
+ // ✅ String → Number
139
284
  PORT: z.string().transform((val) => parseInt(val, 10)).pipe(z.number().positive()),
285
+
286
+ // ✅ Coerce number
140
287
  MAX_CONNECTIONS: z.coerce.number().default(10),
288
+
289
+ // ✅ Environment-specific defaults
290
+ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
291
+ LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
141
292
  }
142
293
  ```
143
294
 
144
- ### Optional with Fallback
295
+ ## Optional with Fallback
145
296
 
146
297
  ```typescript
147
298
  client: {
@@ -150,19 +301,35 @@ client: {
150
301
  }
151
302
  ```
152
303
 
153
- </patterns>
304
+ </transforms>
154
305
 
155
306
  ---
156
307
 
157
308
  <tips>
158
309
 
159
- ## Tips
160
-
161
- | Situation | Method |
310
+ | 상황 | 방법 |
162
311
  |------|------|
163
312
  | **Vercel** | `process.env.VERCEL_URL` → PUBLIC_APP_URL |
164
- | **Monorepo** | Separate `env.ts` per package |
313
+ | **Monorepo** | 패키지마다 별도 `env.ts` |
165
314
  | **Testing** | `.env.test` + `NODE_ENV=test` |
166
315
  | **CI/CD** | GitHub Secrets → Environment Variables |
316
+ | **빌드 시점** | 빌드 시 모든 env 검증 완료 |
317
+ | **런타임 에러** | 잘못된 env 즉시 에러 발생 (앱 시작 전) |
167
318
 
168
319
  </tips>
320
+
321
+ ---
322
+
323
+ <patterns>
324
+
325
+ ## Do's & Don'ts
326
+
327
+ | ✅ Do | ❌ Don't |
328
+ |-------|----------|
329
+ | `env.DATABASE_URL` 사용 | `process.env.DATABASE_URL` 직접 접근 |
330
+ | `PUBLIC_` 접두사 클라이언트 변수 | 접두사 없이 클라이언트 변수 |
331
+ | Zod 스키마로 타입 정의 | any 타입 사용 |
332
+ | 서버 변수는 서버에서만 | 클라이언트에 서버 변수 노출 |
333
+ | `emptyStringAsUndefined: true` | 빈 문자열 허용 |
334
+
335
+ </patterns>