@rscc/common-core
v0.2.0
Published
RSCC 공통 코어 — CommonResponse 타입, apiClient 팩토리(traceId 발신/에코), SSE 프레임 파서, JWT 디코더, 마스킹 유틸. 프레임워크 무관, 런타임 의존성 0.
Maintainers
Readme
@rscc/common-core
RSCC 공통 코어 — CommonResponse 봉투 타입, API 클라이언트 팩토리(traceId 발신/에코), SSE 프레임 파서, JWT 디코더, 시크릿 마스킹 유틸. 프레임워크 무관, 런타임 의존성 0.
설치
npm i @rscc/common-core- Node >= 18 (전역
fetch/Headers/ReadableStream전제) - ESM + CJS 듀얼 빌드, 타입 선언(
.d.ts/.d.cts) 동봉,sideEffects: false
공개 API
| 모듈 | 공개 API | 설명 |
|---|---|---|
| types | CommonResponse<T> · PageResponse<T> · ResultCode | 응답 봉투·페이지네이션(page 0 시작)·결과 코드(값은 문자열) |
| apiClient | createApiClient(config) · ApiError · ApiClient · ApiClientConfig · ApiResult<T> | 봉투 언랩 · 401 콜백 · X-Trace-Id 발신/에코 |
| sse | parseSseFrame · readSseStream · SseFrameEvent · SseSource · SseCallbacks | SSE 프레임 파싱 — 청크/멀티바이트 경계 안전, 모르는 키는 skip |
| jwt | decodeJwtPayload · getTokenExpiry · isTokenExpired | base64url 디코드만 — 서명 미검증, 만료 판단은 fail-closed |
| masking | maskSecret | 앞4+뒤4 노출, 8자 이하 전량 마스킹 (java MaskingUtils 와 동일 규칙) |
사용 예시
createApiClient — CommonResponse 언랩 + traceId
import { createApiClient, ApiError } from "@rscc/common-core";
const api = createApiClient({
baseUrl: "https://api.example.com", // 끝 슬래시 없이
getToken: () => localStorage.getItem("token"), // 선택 — Authorization: Bearer 부착
onUnauthorized: () => { /* 로그아웃/리다이렉트 정책은 소비자가 결정 */ },
});
// 성공 봉투 → data 언랩
const user = await api.request<UserInfo>("/api/v1/users/me");
// 실패 봉투/HTTP 에러 → ApiError { code, message, status, traceId }
try {
await api.request("/api/v1/things/999");
} catch (e) {
if (e instanceof ApiError) console.error(`[${e.traceId}] ${e.code}: ${e.message}`);
}SSE 스트림 소비
import { readSseStream } from "@rscc/common-core";
const res = await fetch(streamUrl, { method: "POST", body, signal });
await readSseStream(res, {
onDelta: (chunk) => { /* 텍스트 증분 */ },
onSources: (sources) => { /* RAG 근거 */ },
onError: (message) => { /* in-band 오류 */ },
onDone: () => { /* data: [DONE] */ },
});알려진 제약
- SSE 파서는 프레임 구분자 LF(
\n\n) 고정 — CRLF 로 정규화하는 프록시 뒤에서는 프레임이 분리되지 않는다. baseUrl은 끝 슬래시 없이 지정할 것 — path 와 단순 연결하며 정규화하지 않는다.requestWithMeta의ApiResult.response는 body 가 이미 소비된 상태 — headers/status 조회용.- 2xx 응답인데 본문이 JSON 이 아니면
data는 조용히 null 이 된다. - JWT 디코더는 서명을 검증하지 않는다 — 표시·만료 판단 전용. 인가 판단은 반드시 서버에서.
문서 / 저장소
- 상세 문서: js/README.md
- 와이어 계약(단일 소스): contracts/
- React 훅: @rscc/common-react
- 저장소: Jeonghyeon-Ryu/r-common · MIT
