@simplysm/sd-claude 14.0.75 → 14.0.77
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/claude/output-styles/sd-tone.md +128 -0
- package/claude/references/sd-simplysm14/apis/angular/README.md +28 -89
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +75 -32
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +65 -29
- package/claude/references/sd-simplysm14/apis/angular/crud.md +86 -21
- package/claude/references/sd-simplysm14/apis/angular/forms.md +168 -42
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +200 -49
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +64 -20
- package/claude/references/sd-simplysm14/apis/angular/layout.md +75 -30
- package/claude/references/sd-simplysm14/apis/angular/modal.md +92 -40
- package/claude/references/sd-simplysm14/apis/angular/routing.md +86 -25
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +72 -41
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +113 -21
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +108 -33
- package/claude/references/sd-simplysm14/apis/angular/toast.md +81 -30
- package/claude/references/sd-simplysm14/apis/angular/visual.md +140 -32
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +46 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +59 -48
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +17 -7
- package/claude/references/sd-simplysm14/apis/core-common/README.md +43 -116
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +74 -109
- package/claude/references/sd-simplysm14/apis/core-common/features.md +40 -35
- package/claude/references/sd-simplysm14/apis/core-common/types.md +80 -106
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +142 -111
- package/claude/references/sd-simplysm14/apis/core-node/README.md +7 -16
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +33 -38
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +25 -33
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +27 -38
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +32 -60
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -45
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +35 -81
- package/claude/references/sd-simplysm14/apis/excel/README.md +178 -80
- package/claude/references/sd-simplysm14/apis/lint/README.md +5 -0
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +28 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-client/README.md +57 -50
- package/claude/references/sd-simplysm14/apis/service-server/README.md +8 -15
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +24 -16
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +55 -31
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +28 -44
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +59 -18
- package/claude/references/sd-simplysm14/apis/service-server/server.md +37 -46
- package/claude/references/sd-simplysm14/manuals/client-component.md +3 -1
- package/claude/references/sd-simplysm14/manuals/logging.md +9 -8
- package/claude/rules/sd-base-rules.md +380 -217
- package/claude/settings.json +1 -0
- package/claude/skills/sd-commit/SKILL.md +31 -8
- package/claude/skills/sd-docs/SKILL.md +15 -10
- package/claude/skills/sd-docs/references/subagent-prompt.md +26 -8
- package/claude/skills/sd-impl/SKILL.md +1 -1
- package/claude/skills/sd-skill/references/skill-authoring.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +22 -13
- package/claude/skills/sd-spec/references/spec-authoring.md +1 -1
- package/claude/skills/sd-unpack/SKILL.md +150 -26
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/_common.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/eml_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/pdf_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/_common.py +17 -2
- package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +100 -24
- package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +140 -27
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +698 -107
- package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +34 -26
- package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +130 -8
- package/package.json +1 -1
|
@@ -1,41 +1,82 @@
|
|
|
1
|
-
# @simplysm/service-server —
|
|
1
|
+
# @simplysm/service-server — 내부 전송 계층
|
|
2
2
|
|
|
3
|
-
`ServiceServer.listen()` 이
|
|
3
|
+
`ServiceServer.listen()` 이 자동 결선하므로 일반 사용에선 불필요. 커스텀 Fastify 라우트·테스트·비표준 전송 시 참고.
|
|
4
4
|
|
|
5
|
-
## HTTP
|
|
5
|
+
## HTTP
|
|
6
6
|
|
|
7
7
|
### `handleHttpRequest(req, reply, jwtSecret, runMethod)`
|
|
8
8
|
|
|
9
|
-
`/api/:service/:method` 라우트 핸들러.
|
|
9
|
+
`/api/:service/:method` 라우트 핸들러.
|
|
10
|
+
|
|
11
|
+
- `x-sd-client-name` 헤더 필수(없으면 throw).
|
|
12
|
+
- `Authorization: Bearer <jwt>` 있고 `jwtSecret` 도 있으면 `verifyJwt`. 토큰만 있고 secret 없으면 throw. 검증 실패 시 401 응답.
|
|
13
|
+
- GET: `?json=<JSON encoded array>` → `json.parse`.
|
|
14
|
+
- POST: body 가 배열이어야 함(아니면 400).
|
|
15
|
+
- 그 외 메서드: 405.
|
|
16
|
+
- `runMethod({ serviceName, methodName, params, http: { clientName, authTokenPayload } })` 호출 후 결과를 `reply.send`.
|
|
10
17
|
|
|
11
18
|
### `handleUpload(req, reply, rootPath, jwtSecret)`
|
|
12
19
|
|
|
13
|
-
multipart 업로드. `Authorization` 필수
|
|
20
|
+
multipart 업로드. `Authorization` 헤더 필수(없으면 401, `jwtSecret` 미구성 시 401). 각 파일을 `<rootPath>/www/uploads/<uuid><ext>` 로 저장. 응답 `ServiceUploadResult[] = { path, filename, size }[]` (`path` = `uploads/<saveName>`). 도중 truncated 또는 에러 발생 시 진행 중 + 이미 저장된 모든 파일 삭제 후 500.
|
|
14
21
|
|
|
15
22
|
### `handleStaticFile(req, reply, rootPath, urlPath)`
|
|
16
23
|
|
|
17
|
-
`<rootPath>/www/<urlPath>` 정적 서빙.
|
|
24
|
+
`<rootPath>/www/<urlPath>` 정적 서빙.
|
|
25
|
+
|
|
26
|
+
- 경로 탐색 차단: `pathx.isChildPath(targetFilePath, allowedRootPath)` 가드.
|
|
27
|
+
- 디렉터리 + URL 미 trailing slash → `pathname + "/"` 리다이렉트. trailing slash 있으면 `<dir>/index.html` 사용.
|
|
28
|
+
- 숨김 파일(basename 이 `.` 시작) → 403.
|
|
29
|
+
- ENOENT 404, 기타 500. 에러는 HTML 응답.
|
|
30
|
+
|
|
31
|
+
## WebSocket
|
|
32
|
+
|
|
33
|
+
### `createWebSocketHandler(runMethod, jwtSecret): WebSocketHandler`
|
|
34
|
+
|
|
35
|
+
여러 WS 연결 풀 관리. 처리 메시지:
|
|
36
|
+
|
|
37
|
+
- `<service>.<method>` (body 가 배열) → RPC. `runMethod` 위임.
|
|
38
|
+
- `evt:add { key, name, info }` — 이벤트 리스너 등록.
|
|
39
|
+
- `evt:remove { key }` — 제거.
|
|
40
|
+
- `evt:gets { name }` — 모든 소켓의 해당 이벤트 리스너 정보 조회.
|
|
41
|
+
- `evt:emit { keys, data }` — 매칭 키 가진 소켓에게 `evt:on` 푸시.
|
|
42
|
+
- `auth <token>` — JWT 검증 후 `socket.authTokenPayload` 설정.
|
|
43
|
+
|
|
44
|
+
에러 코드: `BAD_MESSAGE`(알 수 없는 요청), `INTERNAL_ERROR`. `env("DEV")` truthy 시 `stack` 포함.
|
|
45
|
+
|
|
46
|
+
`addSocket(socket, clientId, clientName, connReq)` 동일 clientId 이전 연결 자동 종료 후 교체. `emit(name, infoSelector, data)` 는 `ServiceServer.emitEvent` 의 백엔드.
|
|
47
|
+
|
|
48
|
+
### `createServiceSocket(socket, clientId, clientName, connReq): ServiceSocket`
|
|
49
|
+
|
|
50
|
+
단일 WS 관리.
|
|
51
|
+
|
|
52
|
+
- 5초 ping/pong (`socket.ping()` → 응답 없으면 `terminate()`).
|
|
53
|
+
- 1바이트 `0x01`(ping) 수신 → `0x02`(pong) 송신.
|
|
54
|
+
- 메시지는 `createServerProtocolWrapper()` 통과. 진행률(`type === "progress"`) 디코드 결과는 자동으로 `progress` 메시지 회신.
|
|
18
55
|
|
|
19
|
-
|
|
56
|
+
표면: `connectedAtDateTime: DateTime`, `clientName`, `connReq`, `authTokenPayload`(get/set), `close()`, `send(uuid, msg)`(전송 바이트), `addListener(key, eventName, info)`, `removeListener(key)`, `getEventListeners(eventName)`, `filterEventTargetKeys(targetKeys)`, `on("error"|"close"|"message", handler)`.
|
|
20
57
|
|
|
21
|
-
|
|
58
|
+
## 프로토콜 래퍼
|
|
22
59
|
|
|
23
|
-
|
|
60
|
+
### `createServerProtocolWrapper(): ServerProtocolWrapper`
|
|
24
61
|
|
|
25
|
-
|
|
62
|
+
`@simplysm/service-common` 의 `createServiceProtocol()` 기반. 무거운 케이스만 워커 스레드로 위임:
|
|
26
63
|
|
|
27
|
-
|
|
64
|
+
- encode: body 가 `Uint8Array` 이거나 `Uint8Array` 요소를 하나라도 가진 배열 → 워커.
|
|
65
|
+
- decode: 입력 바이트 > 30KB → 워커.
|
|
28
66
|
|
|
29
|
-
|
|
67
|
+
워커는 모듈 로드 시 1회 생성 lazy singleton(`maxOldGenerationSizeMb: 4096`). 워커 모듈: `workers/service-protocol.worker.ts`.
|
|
30
68
|
|
|
31
|
-
|
|
69
|
+
표면: `encode(uuid, message)`, `decode(bytes)`, `dispose()`(메인 스레드 프로토콜만 정리, 워커는 공유).
|
|
32
70
|
|
|
33
|
-
|
|
71
|
+
## 설정 캐시
|
|
34
72
|
|
|
35
|
-
|
|
73
|
+
### `getConfig<T>(filePath: string): Promise<T | undefined>`
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
JSON 설정 파일 로더.
|
|
38
76
|
|
|
39
|
-
|
|
77
|
+
- `LazyGcMap` 캐시: 만료 1시간, GC 10분 간격. 캐시 히트 시 만료 시간 자동 갱신.
|
|
78
|
+
- 파일 없으면 undefined.
|
|
79
|
+
- `FsWatcher` 로 변경 감시 → 100ms 디바운스 후 리로드. 삭제 감지 시 캐시·워처 정리.
|
|
80
|
+
- 만료 시 워처도 함께 해제.
|
|
40
81
|
|
|
41
|
-
|
|
82
|
+
`ServiceContext.getConfig(section)` 이 root/client `.config.json` 두 경로를 이 함수로 읽어 `obj.merge`. 그 외 경로의 설정 파일을 읽을 때만 직접 호출.
|
|
@@ -1,66 +1,57 @@
|
|
|
1
|
-
# @simplysm/service-server —
|
|
1
|
+
# @simplysm/service-server — 서버
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## `createServiceServer<TAuthInfo>(options): ServiceServer<TAuthInfo>`
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
interface ServiceServerOptions {
|
|
9
|
-
rootPath: string; // 정적/업로드/설정 루트 (www, .config.json 기준)
|
|
10
|
-
port: number;
|
|
11
|
-
ssl?: { pfxBytes: Uint8Array; passphrase: string };
|
|
12
|
-
auth?: { jwtSecret: string } | false; // undefined: auth 미설정(=auth 서비스 등록 시 에러)
|
|
13
|
-
// false: 의도적 비활성화 (검사 스킵)
|
|
14
|
-
services: ServiceDefinition[]; // defineService 결과
|
|
15
|
-
legacyV1Handlers?: V1RequestHandler[]; // V1 클라이언트 fallback
|
|
16
|
-
}
|
|
17
|
-
```
|
|
5
|
+
`new ServiceServer(options)` 단순 팩토리. `TAuthInfo` 는 JWT payload 의 `data` 필드 타입.
|
|
18
6
|
|
|
19
|
-
## `
|
|
7
|
+
## `ServiceServerOptions`
|
|
20
8
|
|
|
21
|
-
`
|
|
9
|
+
- `rootPath: string` — 정적/업로드/설정 루트. 정적은 `<rootPath>/www/`, 업로드 저장은 `<rootPath>/www/uploads/`, 설정은 `<rootPath>/.config.json` 및 `<rootPath>/www/<clientName>/.config.json`.
|
|
10
|
+
- `port: number` — listen 포트. host 는 항상 `0.0.0.0`.
|
|
11
|
+
- `ssl?: { pfxBytes: Uint8Array; passphrase: string }` — 지정 시 HTTPS. 내부에서 `Buffer.from(pfxBytes)` 변환. 미지정 시 helmet 의 `upgrade-insecure-requests` 제거, `hsts`/`crossOriginOpenerPolicy` 비활성.
|
|
12
|
+
- `auth?: { jwtSecret: string } | false`
|
|
13
|
+
- `undefined`(미지정): auth 미구성. 인증 요구 서비스가 하나라도 있으면 `listen()` 시 throw.
|
|
14
|
+
- `false`: 의도적 비활성화. `auth()` 래핑된 서비스/메서드도 인증 스킵.
|
|
15
|
+
- 객체: jwt 시크릿 등록.
|
|
16
|
+
- `services: ServiceDefinition[]` — `defineService()` 결과 배열.
|
|
17
|
+
- `legacyV1Handlers?: V1RequestHandler[]` — ver≠"2" 로 접속한 클라이언트의 커스텀 핸들러. 이 배열도 비고 `AutoUpdate` 서비스도 services 에 없으면 V1 연결을 1008 로 거부.
|
|
22
18
|
|
|
23
19
|
## `ServiceServer<TAuthInfo>`
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
class ServiceServer<TAuthInfo = unknown> extends EventEmitter<{ ready: void; close: void }> {
|
|
27
|
-
readonly fastify: FastifyInstance;
|
|
28
|
-
readonly options: ServiceServerOptions;
|
|
29
|
-
isOpen: boolean;
|
|
21
|
+
`EventEmitter<{ ready: void; close: void }>` 상속.
|
|
30
22
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
- `readonly options: ServiceServerOptions`
|
|
24
|
+
- `readonly fastify: FastifyInstance` — 생성자에서 즉시 생성, 플러그인은 `listen()` 시 등록.
|
|
25
|
+
- `isOpen: boolean`
|
|
26
|
+
- `listen(): Promise<void>` — fastify 플러그인(`@fastify/websocket`, `@fastify/helmet`, `@fastify/multipart`, `@fastify/static`, `@fastify/cors`) 등록, JSON 파서/직렬화기를 `@simplysm/core-common` 의 `json` 으로 교체(Date/BigInt/Uint8Array 보존), 라우트 바인딩, `0.0.0.0:port` listen, SIGINT/SIGTERM 핸들러 등록(10초 후 `process.exit(1)` 강제), `ready` 이벤트 발생.
|
|
27
|
+
- `close(): Promise<void>` — 모든 WebSocket 종료 → `fastify.close()` → `close` 이벤트.
|
|
28
|
+
- `getEvent<TEventDef>(eventName): ServerEventProxy<TEventDef>` — `{ emit(infoSelector, data): Promise<void> }` 핸들 반환.
|
|
29
|
+
- `emitEvent<TEventDef>(eventName, infoSelector, data): Promise<void>` — 클라이언트가 `evt:add` 로 등록한 리스너 중 `infoSelector(info) === true` 인 키에만 푸시.
|
|
30
|
+
- `signAuthToken(payload: AuthTokenPayload<TAuthInfo>): Promise<string>` — HS256, `exp` 12h 고정. `jwtSecret` 미구성 시 throw.
|
|
31
|
+
- `verifyAuthToken(token: string): Promise<AuthTokenPayload<TAuthInfo>>` — 만료/위조 시 throw.
|
|
39
32
|
|
|
40
|
-
`
|
|
33
|
+
`TEventDef` 는 `@simplysm/service-common` 의 `ServiceEventDef`(`{ $info; $data }` 형태). `infoSelector` 는 클라이언트가 listener 등록 시 보낸 `info` 객체를 받아 boolean 반환.
|
|
41
34
|
|
|
42
|
-
|
|
35
|
+
## 자동 등록되는 라우트
|
|
43
36
|
|
|
44
|
-
|
|
37
|
+
- `ALL /api/:service/:method` — RPC. `x-sd-client-name` 헤더 필수, `Authorization: Bearer <jwt>` 옵션. GET 은 `?json=<JSON encoded array>`, POST 는 body 가 params 배열. 그 외 HTTP 메서드 405.
|
|
38
|
+
- `ALL /upload` — multipart 업로드. 인증 헤더 필수. 응답 `ServiceUploadResult[]`.
|
|
39
|
+
- `GET /`, `GET /ws` — WebSocket. 쿼리 `ver=2&clientId=<id>&clientName=<name>` (clientId/clientName 누락 시 1008). ver≠"2" → V1 레거시.
|
|
40
|
+
- `* /*` — 정적 서빙(`/api/...`·`/upload`·`/`·`/ws` 외).
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
server.getEvent<{ $info: { tenantId: string }; $data: { id: string } }>("orderCreated")
|
|
48
|
-
.emit((info) => info.tenantId === "T1", { id: "O-100" });
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## `ServerEventProxy<TEventDef>`
|
|
52
|
-
|
|
53
|
-
`getEvent()` 가 반환하는 핸들. `emit(infoSelector, data)` 만 노출.
|
|
54
|
-
|
|
55
|
-
## 최소 예제
|
|
42
|
+
## 예
|
|
56
43
|
|
|
57
44
|
```ts
|
|
58
|
-
const server = createServiceServer<
|
|
45
|
+
const server = createServiceServer<{ userId: string }>({
|
|
59
46
|
rootPath: process.cwd(),
|
|
60
47
|
port: 50080,
|
|
61
|
-
auth: { jwtSecret: env
|
|
62
|
-
services: [
|
|
48
|
+
auth: { jwtSecret: process.env.JWT_SECRET! },
|
|
49
|
+
services: [UserService, OrmService],
|
|
63
50
|
});
|
|
64
51
|
server.on("ready", () => console.log("up"));
|
|
65
52
|
await server.listen();
|
|
53
|
+
|
|
54
|
+
const token = await server.signAuthToken({ roles: ["admin"], data: { userId: "u1" } });
|
|
55
|
+
await server.getEvent<{ $info: { shopId: number }; $data: { id: number } }>("order-created")
|
|
56
|
+
.emit(info => info.shopId === 1, { id: 99 });
|
|
66
57
|
```
|
|
@@ -528,7 +528,9 @@ async onSubmit(): Promise<void> {
|
|
|
528
528
|
- 단, **숫자 셀은 `tx-right` 기본 적용** (수량·금액·단가·합계 등 숫자값 컬럼).
|
|
529
529
|
- `[cell]="items()"` 는 타입 추론용 더미 — 실제 행 데이터는 `<sd-sheet>` 의 `[items]` 가 들고 있다.
|
|
530
530
|
- 셀 컨텍스트: `let-item="item"` / `let-index="index"` / `let-depth="depth"` / `let-edit="edit"`.
|
|
531
|
-
- 셀 안 div 에 배경색 클래스(`bg-theme-*-lightest` 등)를 토글할 때는 빈 값 자리에 ` 
|
|
531
|
+
- 셀 안 div 에 배경색 클래스(`bg-theme-*-lightest` 등)를 토글할 때는 빈 값 자리에 ` `를 채워 div 가 셀 높이를 유지하게 한다. (table cell 자식 div 가 콘텐츠 없을 때 높이 0 → bg 가 셀에 차지 않음.)
|
|
532
|
+
- 좋은 예: `{{ item.surveyLocationCode ?? " " }}`
|
|
533
|
+
- 나쁜 예: `{{ item.surveyLocationCode }}`, `{{ item.surveyLocationCode ?? " " }}`, `{{ item.surveyLocationCode ?? " " }}`
|
|
532
534
|
|
|
533
535
|
**list 안에서**: `<sd-crud-list>` 의 직속 자식으로 `<sd-sheet-column>` 을 두면 내부 시트로 자동 투영된다.
|
|
534
536
|
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
## 원칙
|
|
6
6
|
|
|
7
|
-
- 모든 로그는 `
|
|
7
|
+
- 모든 로그는 `createLogger(tag)` (`@simplysm/core-common`) 로 생성한 인스턴스로 출력. `console.*` 직접 호출 금지.
|
|
8
8
|
- ESLint `no-console` 규칙은 의도된 게이트 — `eslint-disable`/`eslint-disable-next-line no-console` 우회 금지.
|
|
9
9
|
- 메시지에 `[패키지]` 같은 수동 prefix 금지. tag 가 그 역할.
|
|
10
10
|
|
|
11
11
|
## 권장 패턴
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import
|
|
14
|
+
import { createLogger } from "@simplysm/core-common";
|
|
15
15
|
|
|
16
|
-
const logger =
|
|
16
|
+
const logger = createLogger("capacitor:auto-update");
|
|
17
17
|
|
|
18
18
|
// ...
|
|
19
19
|
logger.info("최신 버전 확인 중");
|
|
@@ -40,19 +40,20 @@ const logger = {
|
|
|
40
40
|
console.error("[X] 실패:", err);
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
→ 모두 `
|
|
43
|
+
→ 모두 `createLogger("x")` 1줄로 대체.
|
|
44
44
|
|
|
45
45
|
## 환경별 셋업
|
|
46
46
|
|
|
47
47
|
- **Node 진입점(서버·CLI)**: 진입점에서 `setupConsola()` 1회. 자세히 [apis/core-node/consola.md](../apis/core-node/consola.md).
|
|
48
48
|
- **Browser·Capacitor 진입점**: `setupConsola` 호출 X (Node 전용). consola 기본 reporter 가 브라우저 콘솔로 출력. tag/level/통일된 호출면 충족.
|
|
49
49
|
|
|
50
|
-
## 모듈-레벨 logger 주의
|
|
50
|
+
## 모듈-레벨 logger 주의
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
모듈 레벨에서 `consola.withTag()` 를 직접 호출하면 호출 시점의 options(level/reporters)가 스냅샷으로 고정되어, 이후 `setupConsola()` 가 reporters 를 갱신해도 child instance 에 반영되지 않는다.
|
|
53
53
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
54
|
+
- **해결**: `createLogger(tag)` 사용 (`@simplysm/core-common`, 내부 구현은 lazy Proxy — 첫 메서드 접근 시점까지 `withTag` 생성을 지연).
|
|
55
|
+
- 모든 환경(Node·브라우저·Capacitor)에서 위치(모듈 레벨·함수 내부·class field)에 관계없이 `createLogger` 로 통일.
|
|
56
|
+
- `consola.withTag()` 직접 호출 금지.
|
|
56
57
|
|
|
57
58
|
## 예외 — `eslint-disable no-console` 가 정당화되는 자리
|
|
58
59
|
|