@gaonjs/cli 0.35.0 → 0.37.1
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/commands/check.js +15 -9
- package/dist/commands/dev.js +10 -1
- package/dist/commands/gen.d.ts +2 -0
- package/dist/commands/gen.js +6 -2
- package/dist/commands/new.d.ts +7 -1
- package/dist/commands/new.js +15 -2
- package/dist/commands/test.d.ts +2 -1
- package/dist/commands/test.js +11 -5
- package/dist/dev.d.ts +13 -1
- package/dist/dev.js +21 -1
- package/dist/doctor/no-import-meta-env.d.ts +5 -0
- package/dist/doctor/no-import-meta-env.js +98 -0
- package/dist/doctor/types.d.ts +1 -1
- package/dist/doctor.d.ts +9 -0
- package/dist/doctor.js +12 -3
- package/dist/env-gen.d.ts +12 -0
- package/dist/env-gen.js +63 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +54 -23
- package/dist/pm.d.ts +13 -0
- package/dist/pm.js +59 -0
- package/dist/templates/index.d.ts +17 -0
- package/dist/templates/index.js +18 -1
- package/dist/templates/index.ts +24 -0
- package/dist/templates/project/.env.example.tpl +6 -0
- package/dist/templates/project/AGENTS.md.tpl +3 -2
- package/dist/templates/project/CLAUDE.md.tpl +1 -1
- package/dist/templates/project/agents/async.md.tpl +36 -3
- package/dist/templates/project/agents/frontend.md.tpl +52 -1
- package/dist/templates/project/agents/i18n.md.tpl +26 -0
- package/dist/templates/project/agents/mail.md.tpl +31 -0
- package/dist/templates/project/agents/realtime.md.tpl +10 -0
- package/dist/templates/project/agents/testing.md.tpl +8 -4
- package/dist/templates/project/agents/web.md.tpl +36 -0
- package/dist/templates/project/package.json.tpl +1 -1
- package/package.json +9 -9
- package/dist/templates/auth/app.ts.tpl +0 -29
- package/dist/templates/auth/server.ts.tpl +0 -14
|
@@ -239,6 +239,35 @@ async create() {
|
|
|
239
239
|
|
|
240
240
|
순수 JSON/API 앱(X-Inertia 아님·세션 없음)은 기존대로 **422 JSON** 을 받는다.
|
|
241
241
|
|
|
242
|
+
#### 검증 사유 로케일화 — 예약 namespace `validation.*` (결정 183)
|
|
243
|
+
|
|
244
|
+
검증 실패의 **필드별 사유**(`form.errors.<필드>` 로 엔드유저에 노출되는 부분)는 요청
|
|
245
|
+
로케일로 번역된다 — `i18n` 이 설정돼 있고 앱이 `locales/<lng>.json` 의 **예약 namespace
|
|
246
|
+
`validation.<code>`** 로 번역을 제공하면. 프레임웍은 **안정적 코드만** 노출하고 번역은
|
|
247
|
+
앱 몫이다(The One Way: 코드는 프레임웍, 문안은 앱). 키가 없으면 내장 fallback(한국어)로
|
|
248
|
+
떨어져 거동이 보존된다. i18n 미설정이면 항상 fallback.
|
|
249
|
+
|
|
250
|
+
| code | 파라미터 | 언제 |
|
|
251
|
+
|---|---|---|
|
|
252
|
+
| `required` | — | 필수 컬럼 누락 |
|
|
253
|
+
| `too_long` | `{ max, len }` | `.max(n)` 초과 |
|
|
254
|
+
| `not_allowed` | `{ value, allowed }` | enum 밖 값 |
|
|
255
|
+
| `not_integer` | `{ value }` | bigint 변환 실패 |
|
|
256
|
+
| `not_boolean` | `{ value }` | boolean 변환 실패 |
|
|
257
|
+
| `not_date` | `{ value }` | 날짜 변환 실패 |
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
// locales/en.json — 앱이 검증 문안을 로케일별로 준다(i18next {{max}} 보간).
|
|
261
|
+
{ "validation": {
|
|
262
|
+
"required": "This field is required.",
|
|
263
|
+
"too_long": "At most {{max}} characters (got {{len}})."
|
|
264
|
+
} }
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
주의: 상단 개발자용 422 `message`(스키마 어느 파일을 고치라는 §7.5.3 **수리 안내**)는
|
|
268
|
+
로케일화하지 않는다 — AI/개발자용 고정 안내다. 로케일화 대상은 **엔드유저에 닿는 필드별
|
|
269
|
+
사유**뿐이다.
|
|
270
|
+
|
|
242
271
|
#### 세션/CSRF 실패·415 도 코어가 Inertia-네이티브로 마감한다 (결정 165)
|
|
243
272
|
|
|
244
273
|
폼 검증(결정 109)과 **대칭**으로, 컨트롤러 액션 밖(디스패처 try-catch 밖)에서 나는
|
|
@@ -423,6 +452,13 @@ const ok = await verifyPassword(plain, user.passwordDigest) // Promise<boolean>
|
|
|
423
452
|
|
|
424
453
|
API 앱(JWT)은 세션 대신 `this.jwt.issue(user)` / `this.jwt.refresh(token)` 를 쓴다.
|
|
425
454
|
|
|
455
|
+
- **API 앱은 프론트엔드가 없다(JSON 전용).** `apps/<app>/app.config.ts`(`auth: { strategy:'jwt', … }`)
|
|
456
|
+
+ `routes.ts` + `controllers/` 만 두면 된다 — `index.html`·`main.ts`·`pages/` 는 만들지 않는다.
|
|
457
|
+
앱 발견은 `routes.ts` 기준이라 `gaon serve` 가 이 앱을 `/<app>` 프리픽스로 정상 마운트하고,
|
|
458
|
+
`gaon build`·`gaon check` 는 프론트 앱(=`index.html` 보유)만 검사하므로 API 앱을 프론트로
|
|
459
|
+
오검사하지 않는다. JWT 앱의 표준 형태다("프론트엔드는 프로젝트당 하나" 규칙은 Vue 앱 한정 ·
|
|
460
|
+
API 앱은 그 규칙 밖).
|
|
461
|
+
|
|
426
462
|
- **`this.auth.user`/`requireAuth()` 사용자 타입은 앱이 증강한다** (결정 58).
|
|
427
463
|
`GaonCurrentUser` 는 빈 인터페이스라 증강 없이는 `user.id` 접근이 타입에러다.
|
|
428
464
|
`gaon g auth` 가 `apps/<app>/auth.ts` 에 심는다:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaonjs/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Gaon CLI
|
|
3
|
+
"version": "0.37.1",
|
|
4
|
+
"description": "Gaon CLI — 스캐폴딩·제너레이터·마이그레이션·dev/serve/work/hub·doctor·check (bin: gaon)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://gaonjs.dev",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
28
28
|
"typescript": "^5.9.0",
|
|
29
29
|
"vite": "^7.0.0",
|
|
30
|
-
"@gaonjs/
|
|
31
|
-
"@gaonjs/
|
|
32
|
-
"@gaonjs/
|
|
33
|
-
"@gaonjs/
|
|
34
|
-
"@gaonjs/
|
|
35
|
-
"@gaonjs/
|
|
36
|
-
"@gaonjs/web": "0.
|
|
30
|
+
"@gaonjs/async": "0.12.0",
|
|
31
|
+
"@gaonjs/config": "0.15.2",
|
|
32
|
+
"@gaonjs/core": "0.2.2",
|
|
33
|
+
"@gaonjs/mail": "0.2.1",
|
|
34
|
+
"@gaonjs/i18n": "0.2.1",
|
|
35
|
+
"@gaonjs/data": "0.16.1",
|
|
36
|
+
"@gaonjs/web": "0.18.1"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node -e \"require('fs').cpSync('src/templates','dist/templates',{recursive:true})\""
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// 웹 앱 팩토리 — gaon g auth 스캐폴드. createWebApp 으로 세션·인증을 배선한다.
|
|
2
|
-
import { createApp, type AppSessionOptions } from 'gaonjs/web'
|
|
3
|
-
import appRoutes from './routes.js'
|
|
4
|
-
import session from './controllers/session.js'
|
|
5
|
-
import registration from './controllers/registration.js'
|
|
6
|
-
import dashboard from './controllers/dashboard.js'
|
|
7
|
-
import { loadUser } from './auth.js'
|
|
8
|
-
|
|
9
|
-
export interface WebAppDeps {
|
|
10
|
-
/** 세션 설정 — { redisUrl, secret } (또는 redis 인스턴스). */
|
|
11
|
-
readonly session: AppSessionOptions
|
|
12
|
-
/** 서명 쿠키/CSRF 용 비밀. */
|
|
13
|
-
readonly cookieSecret?: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function createWebApp(deps: WebAppDeps) {
|
|
17
|
-
return createApp({
|
|
18
|
-
apps: [
|
|
19
|
-
{
|
|
20
|
-
name: '{{APP_NAME}}',
|
|
21
|
-
routes: appRoutes,
|
|
22
|
-
controllers: { session, registration, dashboard },
|
|
23
|
-
session: deps.session,
|
|
24
|
-
auth: { loadUser, loginRedirect: '/session/new' },
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
cookieSecret: deps.cookieSecret,
|
|
28
|
-
})
|
|
29
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// 서버 진입점 — gaon g auth 스캐폴드. `node dist/server.js` 로 실행.
|
|
2
|
-
import { createWebApp } from './apps/{{APP_NAME}}/app.js'
|
|
3
|
-
|
|
4
|
-
const app = await createWebApp({
|
|
5
|
-
session: {
|
|
6
|
-
redisUrl: process.env.REDIS_URL ?? 'redis://127.0.0.1:6379',
|
|
7
|
-
secret: process.env.SESSION_SECRET ?? 'change-me-to-a-32+char-random-secret!!',
|
|
8
|
-
},
|
|
9
|
-
cookieSecret: process.env.COOKIE_SECRET,
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
const port = Number(process.env.PORT ?? 3000)
|
|
13
|
-
await app.listen({ port, host: '0.0.0.0' })
|
|
14
|
-
console.log(`web 앱이 http://localhost:${port} 에서 실행 중입니다.`)
|