@rscc/common-core 0.3.0 → 0.5.0

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.d.ts CHANGED
@@ -4,12 +4,14 @@
4
4
  * 원천: contracts/common-response.schema.json (수동 동기화)
5
5
  *
6
6
  * - 와이어 키는 `success` (Java 필드명 isSuccess 의 직렬화 결과).
7
- * - `code` 는 문자열 — error-codes.yaml 의 ResultCode 코드 값 중 하나.
7
+ * - `code` 는 문자열 — error-codes.yaml 의 공통 ResultCode 코드 값 또는 서비스 도메인 코드
8
+ * (contracts/error-code-extension.md — 실패 전용, 3자리 숫자 금지). 모르는 코드는 HTTP 상태로
9
+ * 공통 코드를 유도한다 ({@link import("./errorCodes").toCommonResultCode}).
8
10
  * - `data` 는 실패 응답/데이터 없는 성공 응답에서 키 자체가 생략된다(absent, null 아님).
9
11
  */
10
12
  interface CommonResponse<T> {
11
13
  success: boolean;
12
- code: string;
14
+ code: ErrorCodeValue;
13
15
  message: string;
14
16
  data?: T;
15
17
  }
@@ -74,6 +76,121 @@ declare const ResultCode: {
74
76
  };
75
77
  /** ResultCode 코드 값의 유니온 타입 ("200" | "400" | ...). */
76
78
  type ResultCode = (typeof ResultCode)[keyof typeof ResultCode];
79
+ /**
80
+ * 봉투 `code` 의 값 타입 — 공통 {@link ResultCode} 또는 서비스 도메인 코드(임의 문자열).
81
+ *
82
+ * `(string & {})` 트릭으로 `string` 과 상호 대입 가능하면서도 IDE 자동완성에 공통 코드
83
+ * 리터럴("200" | "400" | ...)을 노출한다. 도메인 코드 규칙·폴백은 contracts/error-code-extension.md.
84
+ */
85
+ type ErrorCodeValue = ResultCode | (string & {});
86
+
87
+ /**
88
+ * 에러 코드 확장 — 공통 코드 + 서비스 도메인 코드의 소비자 폴백 헬퍼.
89
+ *
90
+ * 원천: contracts/error-code-extension.md (수동 동기화 — 골든 벡터 EC-01~07·EC-12)
91
+ *
92
+ * 봉투의 `code` 는 공통 코드(error-codes.yaml 의 ResultCode 10종) 또는 서비스가 얹은 도메인 코드
93
+ * (예: `ORDER_OUT_OF_STOCK`)다. 모르는 코드를 받은 소비자는 오류를 내지 말고 **HTTP 상태로 공통
94
+ * 코드를 유도**한다 — 이 폴백 규칙 덕분에 도메인 코드 추가가 기존 소비자에게 non-breaking 이다.
95
+ * 원래의 도메인 코드는 그대로 보존해 도메인별 처리에 쓴다 (`ApiError.code` vs `ApiError.commonCode`).
96
+ *
97
+ * Java `ResultCode.forHttpStatus` / Python `result_code_for_status` 와 같은 규칙.
98
+ */
99
+
100
+ /**
101
+ * 문자열이 공통 카탈로그의 코드(error-codes.yaml 의 ResultCode 10종)인지 판별하는 타입 가드.
102
+ * 도메인 코드·클라이언트 로컬 코드(예: `INVALID_JSON`)는 false.
103
+ */
104
+ declare function isCommonResultCode(code: string): code is ResultCode;
105
+ /**
106
+ * HTTP 상태 → 공통 코드 (contracts/error-code-extension.md §2 폴백 규칙, 골든 벡터 EC-01~07).
107
+ *
108
+ * 1. 상태와 정확히 일치하는 공통 코드가 있으면(SUCCESS `"200"` 제외) 그 코드 — 404 → `"404"`
109
+ * 2. 그 외 4xx → `"400"` — 422·418·413 → `"400"`
110
+ * 3. 그 외 → `"500"` — 502·503 → `"500"` (2xx·3xx·0 등 비정상 입력도 `"500"`)
111
+ */
112
+ declare function resultCodeForStatus(status: number): ResultCode;
113
+ /**
114
+ * 봉투 code + HTTP 상태 → 공통 코드 (골든 벡터 EC-12).
115
+ *
116
+ * 공통 코드면 그대로 통과, 모르는 코드(도메인 코드·클라이언트 로컬 코드)는
117
+ * {@link resultCodeForStatus} 로 HTTP 상태에서 유도한다.
118
+ * 예: HTTP 402 + `PAYMENT_DECLINED` → `"400"`.
119
+ */
120
+ declare function toCommonResultCode(code: string, status: number): ResultCode;
121
+
122
+ /**
123
+ * CSRF double-submit 클라이언트 헬퍼 — contracts/session-auth.md §4·§5 (수동 동기화).
124
+ *
125
+ * 쿠키 운반 인증 모드(`jwt-cookie` / `session`)에서 서버는 CSRF 토큰을 HttpOnly 가 아닌 쿠키
126
+ * (`XSRF-TOKEN`)로 발급하고, 클라이언트는 **비안전 메서드** 요청마다 그 값을 헤더(`X-XSRF-TOKEN`)에
127
+ * 되돌려 보낸다. 서버는 쿠키 값과 헤더 값의 동등성만 확인한다.
128
+ *
129
+ * 부착 규칙 (골든 벡터 XC-01~08):
130
+ * - 비안전 메서드(GET·HEAD·OPTIONS·TRACE 외)일 때만.
131
+ * - CSRF 쿠키가 있고 값이 비어 있지 않을 때만 (없으면 부착 안 함 — 오류 없음).
132
+ * - 요청 URL 이 **같은 출처**(상대 URL 포함)이거나 명시한 `allowedOrigins` 에 속할 때만 —
133
+ * 교차 출처로는 보내지 않는다(토큰 유출 방지).
134
+ * - `document` 가 없는 환경(SSR·Node)에서는 `readCookie` 주입이 없으면 아무것도 붙이지 않는다.
135
+ *
136
+ * SSR 안전: 모듈 로드 시점에 `document`/`location` 에 접근하지 않는다 (호출 시점에만 존재 확인).
137
+ */
138
+ /** CSRF 토큰 쿠키 기본 이름 (contracts/session-auth.md §2.1). */
139
+ declare const DEFAULT_CSRF_COOKIE_NAME = "XSRF-TOKEN";
140
+ /** CSRF 요청 헤더 기본 이름 — Spring `CookieCsrfTokenRepository` 관례 (contracts/session-auth.md §2.1). */
141
+ declare const DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
142
+ /** CSRF 헤더 자동 부착 옵션 (apiClient `csrf` / useSse `csrf`). */
143
+ interface CsrfOptions {
144
+ /** CSRF 토큰 쿠키 이름. 기본 {@link DEFAULT_CSRF_COOKIE_NAME} (`"XSRF-TOKEN"`) — 서버 설정과 일치시킬 것. */
145
+ cookieName?: string;
146
+ /** CSRF 요청 헤더 이름. 기본 {@link DEFAULT_CSRF_HEADER_NAME} (`"X-XSRF-TOKEN"`). */
147
+ headerName?: string;
148
+ /**
149
+ * 같은 출처 외에 헤더를 보내도 되는 **오리진** 목록 (예: `["https://api.example.com"]`) —
150
+ * 같은 사이트 서브도메인 토폴로지(`app.example.com` → `api.example.com`, contracts §8)용.
151
+ * 항목은 `scheme://host[:port]` 로 정규화해 비교한다(경로·끝 슬래시·대소문자·기본 포트 무관).
152
+ * 와일드카드는 지원하지 않는다. 기본: 없음 (같은 출처만).
153
+ */
154
+ allowedOrigins?: readonly string[];
155
+ /**
156
+ * **원시 쿠키 문자열**(`"a=1; XSRF-TOKEN=abc"` 형태) 공급자 — `document.cookie` 대신 쓴다
157
+ * (React Native·테스트 등 `document` 가 없는 환경). null/undefined 반환은 쿠키 없음.
158
+ * 기본: `document` 가 있으면 `document.cookie`, 없으면 쿠키 없음.
159
+ */
160
+ readCookie?: () => string | null | undefined;
161
+ }
162
+ /**
163
+ * 원시 쿠키 문자열에서 `name` 쿠키 값을 읽는다 (contracts/session-auth.md §2.3).
164
+ *
165
+ * - `;` 로 나누고 각 조각의 앞뒤 공백을 제거한 뒤 **첫 `=`** 기준으로 이름·값을 가른다.
166
+ * - 이름은 **대소문자 구분 정확 일치**, 같은 이름이 여럿이면 **첫 값**(XC-08).
167
+ * - 값은 디코딩하지 않는다(`decodeURIComponent` 미적용). 빈 값(`name=`)은 `""` 를 반환한다.
168
+ * - `cookieString` 생략 시 `document` 가 있으면 `document.cookie` 를 쓰고, 없으면(SSR·Node) null.
169
+ * `document.cookie` 접근 자체가 실패하는 환경(샌드박스 iframe 등)도 null.
170
+ *
171
+ * @returns 쿠키 값, 해당 쿠키가 없으면 null.
172
+ */
173
+ declare function readCookie(name: string, cookieString?: string): string | null;
174
+ /**
175
+ * 비안전 메서드 여부 — GET·HEAD·OPTIONS·TRACE 외 전부 true (대소문자 무관).
176
+ * `method` 생략(또는 빈 문자열)은 fetch 기본값 GET 으로 보아 false.
177
+ */
178
+ declare function isUnsafeMethod(method?: string): boolean;
179
+ /**
180
+ * 요청 하나에 붙일 CSRF 헤더를 계산한다 — 붙여야 하면 `[헤더명, 쿠키값]`, 아니면 null.
181
+ *
182
+ * 판정 순서: 비안전 메서드? → CSRF 쿠키 있음(빈 값 제외)? → 같은 출처(상대 URL, 또는 `location` 이
183
+ * 있을 때 그 오리진과 같은 절대 URL) 또는 `allowedOrigins` 소속? → 부착 (골든 벡터 XC-01~05·07·08).
184
+ * 호출자가 이미 같은 헤더를 실었는지(XC-06)는 호출 측(apiClient·useSse)이 확인한다.
185
+ *
186
+ * 오류를 던지지 않는다 — `document`·`readCookie` 가 모두 없으면(SSR) null. URL 을 해석할 수 없으면
187
+ * 교차 출처로 간주해 null (토큰 유출 방지 쪽으로 실패).
188
+ *
189
+ * @param url 요청 URL (상대/절대). 상대 URL 은 같은 출처로 본다.
190
+ * @param method HTTP 메서드. 생략 시 GET.
191
+ * @param options `true` 또는 생략 = 기본값, 객체 = {@link CsrfOptions}.
192
+ */
193
+ declare function csrfHeaderFor(url: string, method: string | undefined, options?: true | CsrfOptions): [name: string, value: string] | null;
77
194
 
78
195
  /**
79
196
  * 아웃바운드 회복탄력성 — 지수 백오프 + full jitter 재시도. 런타임 의존성 0(native 만).
@@ -140,10 +257,24 @@ declare function retry<T>(fn: (attempt: number) => Promise<T> | T, options?: Ret
140
257
  * `traceId` 는 장애 문의 시 사용자에게 제시할 수 있는 상관관계 식별자다
141
258
  * (contracts/trace.md). 응답 에코 헤더 값이 우선이며, 에코를 읽을 수 없으면
142
259
  * (예: CORS 에서 Access-Control-Expose-Headers 미설정) 요청에 부착해 보낸 값을 쓴다.
260
+ *
261
+ * 에러 코드 확장 (contracts/error-code-extension.md): `code` 는 서버가 보낸 원 코드(서비스 도메인 코드
262
+ * 포함)를 그대로 보존하고, `commonCode` 는 폴백 규칙으로 정규화한 공통 코드다 — 공통 코드만 아는
263
+ * 분기(`switch (e.commonCode)`)는 도메인 코드가 추가돼도 깨지지 않는다.
143
264
  */
144
265
  declare class ApiError extends Error {
145
- /** 결과 코드 — 봉투의 code, 비봉투 응답이면 HTTP 상태 코드 문자열. */
146
- readonly code: string;
266
+ /**
267
+ * 결과 코드 — 봉투의 code(공통 코드 또는 서비스 도메인 코드, 원문 보존), 비봉투 응답이면
268
+ * HTTP 상태 코드 문자열. strictJson 경로는 클라이언트 로컬 코드 `"INVALID_JSON"`.
269
+ */
270
+ readonly code: ErrorCodeValue;
271
+ /**
272
+ * 공통 코드로 정규화한 결과 코드 (골든 벡터 EC-12) — `code` 가 공통 코드면 그대로, 모르는 코드
273
+ * (도메인 코드·`INVALID_JSON` 등)면 HTTP 상태로 유도한다 (`resultCodeForStatus`: 정확 일치
274
+ * 공통 코드(SUCCESS 제외) → 그 외 4xx `"400"` → 그 외 `"500"`).
275
+ * 예: HTTP 402 + `PAYMENT_DECLINED` → `"400"`.
276
+ */
277
+ readonly commonCode: ResultCode;
147
278
  /** HTTP 상태 코드. */
148
279
  readonly status: number;
149
280
  /** 이 요청의 traceId (에코 헤더 우선, 없으면 발신 값). */
@@ -229,8 +360,34 @@ interface ApiClientConfig {
229
360
  * 상대 baseUrl("/api")도 지원.
230
361
  */
231
362
  baseUrl: string;
232
- /** 토큰 공급자. 지정 시 반환값이 truthy 면 `Authorization: Bearer <token>` 부착. */
363
+ /**
364
+ * 토큰 공급자 (`bearer` 모드). 지정 시 반환값이 truthy 면 `Authorization: Bearer <token>` 부착
365
+ * (호출자가 Authorization 을 이미 실었으면 덮어쓰지 않음). 쿠키 모드(`jwt-cookie`/`session`)의
366
+ * 웹 클라이언트는 쓰지 않는다 — `credentials`·`csrf` 참조.
367
+ */
233
368
  getToken?: () => string | null | undefined;
369
+ /**
370
+ * fetch `credentials` 기본값 — 쿠키 운반 인증 모드(`jwt-cookie`/`session`, contracts/session-auth.md §5)용.
371
+ * 같은 출처 API 는 `"same-origin"`(fetch 기본값과 같음), 서브도메인 등 교차 출처 API 는 `"include"`.
372
+ *
373
+ * - 미지정 = fetch 에 `credentials` 속성 자체를 넘기지 않는다 (현행 동작 — fetch 기본값 `"same-origin"`).
374
+ * - 호출별 `init.credentials` 가 있으면 그 값이 우선한다.
375
+ */
376
+ credentials?: RequestCredentials;
377
+ /**
378
+ * CSRF double-submit 헤더 자동 부착 (contracts/session-auth.md §4·§5, 골든 벡터 XC-01~08).
379
+ * `true` = 기본값(쿠키 `XSRF-TOKEN` → 헤더 `X-XSRF-TOKEN`, 같은 출처만), 객체 = {@link CsrfOptions}
380
+ * (쿠키·헤더 이름, 서브도메인 API 용 `allowedOrigins`, `document` 없는 환경용 `readCookie`).
381
+ * 미지정/false = 부착 안 함 (현행 동작).
382
+ *
383
+ * - **비안전 메서드**(GET·HEAD·OPTIONS·TRACE 외)이고 CSRF 쿠키가 있으며 요청 URL(baseUrl 조인 후)이
384
+ * 같은 출처(상대 URL 포함)이거나 `allowedOrigins` 에 속할 때만 붙인다 — 교차 출처로는 보내지 않는다.
385
+ * - 호출자가 이미 같은 이름의 헤더를 실었으면 덮어쓰지 않는다 (호출자 우선, XC-06).
386
+ * - 쿠키는 **시도마다 다시 읽는다** — 재시도 사이에 서버가 토큰을 회전해도 새 값을 싣는다.
387
+ * - `document` 가 없는 환경(SSR·Node)에서는 `readCookie` 주입이 없으면 아무것도 붙이지 않는다(오류 없음).
388
+ * - `getToken`(bearer)과 독립적으로 동작한다.
389
+ */
390
+ csrf?: boolean | CsrfOptions;
234
391
  /** 401 수신 시 throw 직전에 호출되는 콜백 (로그아웃/리다이렉트 등 소비자 정책 주입). */
235
392
  onUnauthorized?: (error: ApiError) => void;
236
393
  /** fetch 구현체 주입 (테스트용). 기본 globalThis.fetch. */
@@ -285,6 +442,27 @@ interface ApiClientConfig {
285
442
  onResponse?: (info: ApiResponseInfo) => void;
286
443
  /** 관측 훅 — 재시도 포함 최종 실패 확정 시 1회 발화. 예외 정책은 {@link onRequest} 참조. */
287
444
  onError?: (info: ApiErrorInfo) => void;
445
+ /**
446
+ * 클라이언트 로컬 메시지의 로케일 (BCP 47 — `"en"`·`"en-US"` 등, 주 서브태그 사용, contracts/i18n.md).
447
+ * 미지정 = `ko` (현행 문구와 바이트 동일).
448
+ *
449
+ * 적용 대상은 서버가 message 를 주지 않아 **클라이언트가 직접 만드는** ApiError 메시지뿐이다
450
+ * (messages.yaml `scope: client`): 본문 읽기 실패 `rscc.client.unreadableBody`, strictJson 의
451
+ * `rscc.client.invalidJson`, 비봉투 HTTP 에러 `rscc.client.httpError`(`{0}` 상태 코드, `{1}` statusText).
452
+ * 실패 봉투의 message 는 서버 문구를 그대로 쓴다 — 서버 문구의 언어는 서비스가 i18n(기본 로케일 변경 또는
453
+ * Accept-Language 협상)을 켰을 때 서버가 정한다 ({@link sendAcceptLanguage} 참조).
454
+ */
455
+ locale?: string;
456
+ /**
457
+ * true 이고 {@link locale} 이 지정돼 있으면 요청에 `Accept-Language: <locale>` 을 부착한다 (opt-in, 기본 false).
458
+ * 호출자가 이미 `Accept-Language` 를 실었으면 덮어쓰지 않는다 (호출자 우선).
459
+ *
460
+ * 브라우저는 사용자 언어 설정으로 `Accept-Language` 를 **스스로 보낸다** — 이 옵션은 그 헤더가 없는
461
+ * Node·SSR 환경이나, 브라우저 설정과 무관하게 특정 언어를 강제하고 싶을 때 쓴다. 서버가 요청별 협상
462
+ * (i18n.md §3, `Vary: Accept-Language`)을 켠 경우에만 응답 message 언어가 바뀐다. 값은 BCP 47 태그
463
+ * (영숫자·`-`)여야 CORS safelisted 헤더로 인정돼 교차 출처 preflight 를 유발하지 않는다.
464
+ */
465
+ sendAcceptLanguage?: boolean;
288
466
  }
289
467
  /** 성공 결과 + 메타 (traceId 등). requestWithMeta 의 반환형. */
290
468
  interface ApiResult<T> {
@@ -324,10 +502,15 @@ interface ApiClient {
324
502
  * (data 부재 시 undefined). 비봉투 JSON 은 그대로 반환.
325
503
  * - 실패 봉투 / HTTP 에러는 code·message·traceId 를 담은 ApiError 를 throw.
326
504
  * - 401 은 throw 직전에 onUnauthorized 콜백을 호출한다.
505
+ * - 인증 운반 (contracts/session-auth.md): `bearer` = `getToken` 으로 Authorization 헤더,
506
+ * `jwt-cookie`/`session` = `credentials` + `csrf` (쿠키는 브라우저가 싣고 CSRF 헤더만 자동 부착).
327
507
  * - retry 지정 시 요청을 core retry() 로 감싼다 ({@link ApiClientRetryOptions} —
328
508
  * 멱등 메서드 기본, Retry-After 하한, 시도 간 동일 traceId).
509
+ * - 클라이언트가 직접 만드는 ApiError 메시지는 `locale` 로 다국어화된다 (기본 ko, contracts/i18n.md) —
510
+ * `sendAcceptLanguage` 로 서버 협상용 `Accept-Language` 부착도 opt-in 가능.
329
511
  *
330
- * 저장소 접근·경로·이벤트명 하드코딩 없음 — 전부 config 주입.
512
+ * 저장소 접근·경로·이벤트명 하드코딩 없음 — 전부 config 주입 (opt-in `csrf` 의 CSRF 쿠키 읽기만 예외 —
513
+ * 기본 `document.cookie`, `readCookie` 로 교체 가능).
331
514
  */
332
515
  declare function createApiClient(config: ApiClientConfig): ApiClient;
333
516
 
@@ -342,7 +525,8 @@ declare function createApiClient(config: ApiClientConfig): ApiClient;
342
525
  *
343
526
  * 주의: 프레임 구분자는 계약상 LF(`\n\n`) 고정 — CRLF(`\r\n\r\n`) 로 내려오는
344
527
  * 스트림은 지원하지 않는다 (프록시 등이 개행을 CRLF 로 정규화하면 프레임이
345
- * 분리되지 않아 유실됨. 서버 계약이 LF 를 보장할 때만 사용할 것).
528
+ * 분리되지 않아 유실됨. 서버 계약이 LF 를 보장할 때만 사용할 것). CRLF·멀티라인 data 에도
529
+ * 견고해야 하면 표준 파서 위의 {@link readSseChatEvents} 를 쓴다 (contracts/sse-events.md §4).
346
530
  */
347
531
  /** sources 프레임의 요소 (camelCase — sse-frames.md 의 웹/외부 응답 계약). */
348
532
  interface SseSource {
@@ -382,6 +566,16 @@ type SseFrameEvent = {
382
566
  * - 일치 키 없음/JSON 파싱 실패 → 조용히 skip
383
567
  */
384
568
  declare function parseSseFrame(frame: string): SseFrameEvent;
569
+ /**
570
+ * 채팅 프로필 페이로드(`data:` 접두를 벗긴 값) 1개를 판별한다. 순수 함수 —
571
+ * {@link parseSseFrame} 과 {@link readSseChatEvents} 가 공유한다.
572
+ *
573
+ * - 빈 문자열 → skip
574
+ * - 리터럴 `[DONE]` → done (정확 일치 — 공백 제거는 호출 측 책임. readSseChatEvents 는 trim 후 전달)
575
+ * - 키 검사 순서: conversationId(number) → sources(array) → delta(string) → error(string)
576
+ * - 일치 키 없음/JSON 파싱 실패 → 조용히 skip
577
+ */
578
+ declare function parseChatPayload(data: string): SseFrameEvent;
385
579
  interface SseCallbacks {
386
580
  /** 스트림 첫 프레임의 대화 세션 id (search-api 가 prepend). */
387
581
  onConversationId?: (id: number) => void;
@@ -404,6 +598,163 @@ interface SseCallbacks {
404
598
  declare function readSseStream(response: {
405
599
  body: ReadableStream<Uint8Array> | null;
406
600
  }, callbacks: SseCallbacks): Promise<void>;
601
+ /**
602
+ * 채팅 프로필(sse-frames.md)을 **표준 파서**(sse-events.md, {@link readSseEvents}) 위에서 읽는 어댑터.
603
+ * 콜백 시맨틱은 {@link readSseStream} 과 같다 (sse-events.md §4).
604
+ *
605
+ * 레거시 리더 대비 차이 — 상위집합 수용:
606
+ * - 줄 끝 CRLF·CR 도 인정 (프록시가 개행을 CRLF 로 정규화해도 프레임 유실 없음)
607
+ * - 멀티라인 `data:` 는 LF 로 이어 한 페이로드로 해석 (레거시는 첫 `data:` 라인만)
608
+ * - 페이로드 앞뒤 공백을 제거한 뒤 `[DONE]` 을 비교 (`data: [DONE] ` 도 종료)
609
+ * - `event:`/`id:`/`retry:` 필드는 채팅 프로필에서 의미가 없으므로 무시 (이벤트 타입 무관하게 data 처리)
610
+ *
611
+ * 레거시와 같은 점: error 프레임 이후 delta 무시, [DONE] 수신 시 reader cancel 후 즉시 resolve,
612
+ * [DONE] 없이 EOF 면 빈 줄로 끝나지 않은 잔여 프레임까지 처리하고 resolve.
613
+ *
614
+ * @throws body 가 없으면 Error (readSseStream 과 동일).
615
+ */
616
+ declare function readSseChatEvents(response: {
617
+ body: ReadableStream<Uint8Array> | null;
618
+ }, callbacks: SseCallbacks): Promise<void>;
619
+
620
+ /**
621
+ * SSE 범용 계층 — WHATWG 표준 이벤트 스트림 파서·리더·정규 빌더.
622
+ *
623
+ * 원천: contracts/sse-events.md (수동 동기화 — 골든 벡터 SE-01~17, SB-01~09)
624
+ *
625
+ * contracts/sse-frames.md(채팅 전용 프로필 — `parseSseFrame`/`readSseStream`)의 **아래 계층**이다.
626
+ * 채팅 외의 SSE(알림·진행률·로그 등)와 `event`/`id`/`retry` 표준 필드를 쓰는 서버·프록시를 다룬다.
627
+ * 채팅 프레임을 이 계층 위에서 읽으려면 `readSseChatEvents`(sse.ts)를 쓴다.
628
+ *
629
+ * 브라우저·SSR·Node 공용 — `TextDecoder`/`ReadableStream` 외 런타임 의존 없음.
630
+ */
631
+ /** 디스패치된 SSE 이벤트 1개 (WHATWG MessageEvent 의 type·data·lastEventId 대응). */
632
+ interface SseEvent {
633
+ /** 이벤트 타입 — `event:` 필드 값, 없으면 `"message"`. */
634
+ event: string;
635
+ /** 데이터 — `data:` 라인들을 LF 로 이은 값 (끝의 LF 1개 제거). */
636
+ data: string;
637
+ /** 디스패치 시점의 마지막 이벤트 ID (`id:` 필드로 설정, 없으면 `""`). */
638
+ id: string;
639
+ }
640
+ /** {@link createSseEventParser} 옵션. */
641
+ interface SseEventParserOptions {
642
+ /**
643
+ * 시작 시점의 마지막 이벤트 ID (기본 `""`). 재연결한 새 연결의 파서에 직전 연결의 값을 넘기면
644
+ * WHATWG EventSource 처럼 `id:` 없는 이벤트도 그 값을 이어받고, 서버가 새 `id:` 를 보낼 때까지 유지된다.
645
+ */
646
+ lastEventId?: string;
647
+ }
648
+ /** 증분 SSE 파서 — 텍스트 청크를 `feed` 로 밀어 넣으면 완성된 이벤트마다 콜백을 부른다. */
649
+ interface SseEventParser {
650
+ /**
651
+ * 디코드된 텍스트 청크를 공급한다. 청크 경계는 줄·이벤트 중간이어도 안전하다
652
+ * (CR 로 끝난 청크 + LF 로 시작하는 다음 청크 = 줄 끝 1개).
653
+ * `end()` 이후 호출하면 throw 한다.
654
+ */
655
+ feed(text: string): void;
656
+ /**
657
+ * 스트림 종료(EOF). 기본은 빈 줄로 끝나지 않은 **미완성 이벤트를 폐기**한다(표준, SE-14).
658
+ * `dispatchIncomplete: true` 면 잔여 줄을 처리하고 빈 줄이 온 것처럼 디스패치한다
659
+ * (레거시 채팅 리더의 EOF 잔여 처리 호환용). 여러 번 호출해도 안전하다(두 번째부터 no-op).
660
+ */
661
+ end(options?: {
662
+ dispatchIncomplete?: boolean;
663
+ }): void;
664
+ /**
665
+ * 마지막 이벤트 ID — 빈 줄(디스패치 시점)마다 `id:` 버퍼 값으로 확정된다(표준: 데이터 없는
666
+ * `id:` 전용 블록도 확정). 재연결 시 `Last-Event-ID` 헤더 값. 초기값 `""`.
667
+ */
668
+ readonly lastEventId: string;
669
+ /** 서버가 보낸 마지막 유효 `retry:` 값(ms, ASCII 숫자만). 미수신 시 null. */
670
+ readonly retryMs: number | null;
671
+ }
672
+ /**
673
+ * WHATWG 표준 SSE 증분 파서를 만든다 (contracts/sse-events.md §1, 골든 벡터 SE-01~16).
674
+ *
675
+ * - 스트림 첫머리 BOM(U+FEFF) 1개 제거, 줄 끝 CRLF·LF·CR 모두 인정 (청크 경계의 CR+LF 도 1개)
676
+ * - 빈 줄 = 디스패치: 데이터 버퍼 끝 LF 1개 제거, 타입 기본 `"message"`, 데이터 없으면 디스패치 안 함
677
+ * - `:` 시작 줄은 주석, 값 앞 공백은 1개만 제거, `id` 의 NUL 포함 값 무시, `retry` 는 ASCII 숫자만
678
+ * - EOF 의 미완성 이벤트는 기본 폐기 (`end({ dispatchIncomplete: true })` 로 잔여 처리 가능)
679
+ *
680
+ * @param onEvent 이벤트 디스패치마다 동기 호출된다.
681
+ * @param onRetry 유효한 `retry:` 필드를 만날 때마다 호출된다(ms).
682
+ * @param options 초기 마지막 이벤트 ID 등 ({@link SseEventParserOptions}).
683
+ */
684
+ declare function createSseEventParser(onEvent: (event: SseEvent) => void, onRetry?: (ms: number) => void, options?: SseEventParserOptions): SseEventParser;
685
+ /**
686
+ * 완결된 SSE 텍스트 전체를 표준 규칙으로 파싱해 이벤트 목록을 반환한다. 순수 함수.
687
+ * 끝의 미완성 이벤트(빈 줄로 끝나지 않음)는 폐기한다 (SE-14).
688
+ */
689
+ declare function parseSseEvents(text: string): SseEvent[];
690
+ /** {@link readSseEvents} 옵션. */
691
+ interface ReadSseEventsOptions {
692
+ /**
693
+ * 이벤트마다 호출된다. `true` 를 반환하면 **즉시 읽기를 멈추고 reader 를 cancel** 한다
694
+ * (같은 청크의 뒤따르는 이벤트도 전달하지 않음). 그 외 반환값은 계속.
695
+ */
696
+ onEvent: (event: SseEvent) => boolean | void;
697
+ /** 유효한 `retry:` 필드 수신 시 호출 (ms). */
698
+ onRetry?: (ms: number) => void;
699
+ /**
700
+ * EOF 에서 빈 줄로 끝나지 않은 잔여 이벤트를 디스패치할지. 기본 false(표준 — 폐기).
701
+ * 레거시 채팅 리더와 같은 잔여 처리가 필요할 때만 true.
702
+ */
703
+ dispatchIncompleteAtEof?: boolean;
704
+ /**
705
+ * 시작 시점의 마지막 이벤트 ID (기본 `""`) — 재연결 시 직전 연결의 `lastEventId` 를 넘기면
706
+ * EventSource 처럼 연결을 넘어 ID 가 유지된다 ({@link SseEventParserOptions.lastEventId}).
707
+ */
708
+ lastEventId?: string;
709
+ }
710
+ /** {@link readSseEvents} 결과. */
711
+ interface ReadSseEventsResult {
712
+ /** 종료 시점의 마지막 이벤트 ID (재연결 `Last-Event-ID` 값). */
713
+ lastEventId: string;
714
+ /** 서버가 보낸 마지막 유효 `retry:` 값(ms). 미수신 시 null. */
715
+ retryMs: number | null;
716
+ /** onEvent 가 true 를 반환해 중단됐으면 true, EOF 로 끝났으면 false. */
717
+ stopped: boolean;
718
+ }
719
+ /**
720
+ * fetch Response 의 body 스트림을 UTF-8 스트리밍 디코드 → 표준 파서 → onEvent 호출.
721
+ *
722
+ * - 청크 경계가 줄·이벤트·멀티바이트 문자 중간에 걸려도 안전하다.
723
+ * - onEvent 가 true 를 반환하면 reader 를 cancel 하고 `stopped: true` 로 resolve 한다.
724
+ * - EOF 에서 미완성 이벤트는 기본 폐기(`dispatchIncompleteAtEof` 로 변경).
725
+ * - BOM 은 파서가 정확히 1개만 제거한다 (디코더는 `ignoreBOM: true` — 이중 제거 방지).
726
+ * - onEvent/onRetry 가 throw 하면 reader 를 cancel 한 뒤 그 오류로 reject 한다.
727
+ *
728
+ * @throws body 가 없으면 Error (readSseStream 과 동일).
729
+ */
730
+ declare function readSseEvents(response: {
731
+ body: ReadableStream<Uint8Array> | null;
732
+ }, options: ReadSseEventsOptions): Promise<ReadSseEventsResult>;
733
+ /** {@link formatSseEvent} 옵션. */
734
+ interface FormatSseEventOptions {
735
+ /** 이벤트 타입 (`event:`). CR·LF 포함 시 오류. 미지정/빈 문자열이면 생략(수신 측 기본 `"message"`). */
736
+ event?: string;
737
+ /** 이벤트 ID (`id:`). CR·LF·NUL 포함 시 오류. 빈 문자열이면 `id: ` 를 써서 마지막 이벤트 ID 를 초기화. */
738
+ id?: string;
739
+ /** 재연결 대기(ms, `retry:`). 0 이상의 정수 — 음수·비정수는 오류. */
740
+ retry?: number;
741
+ }
742
+ /**
743
+ * SSE 이벤트 1개를 정규 형식으로 직렬화한다 (contracts/sse-events.md §2, 골든 벡터 SB-01~06·SB-08).
744
+ *
745
+ * - 줄 끝 LF, 필드 순서 `id` → `event` → `retry` → `data`, 마지막에 빈 줄
746
+ * - data 는 CR·LF·CRLF 로 나눠 줄마다 `data: <줄>` (빈 데이터는 `data: ` 한 줄)
747
+ *
748
+ * @throws id/event 에 CR·LF, id 에 NUL, retry 가 음수·비정수이면 Error.
749
+ */
750
+ declare function formatSseEvent(data: string, options?: FormatSseEventOptions): string;
751
+ /**
752
+ * SSE 주석(하트비트) 프레임을 만든다 (골든 벡터 SB-07) — `": <text>\n\n"`, 빈 텍스트는 `":\n\n"`.
753
+ * 빈 줄로 끝나므로 프록시 버퍼를 비우되 수신 측에서 이벤트를 만들지 않는다.
754
+ *
755
+ * @throws text 에 CR·LF 가 있으면 Error.
756
+ */
757
+ declare function formatSseComment(text?: string): string;
407
758
 
408
759
  /**
409
760
  * JWT 페이로드 디코더 (contracts/jwt-claims.md).
@@ -847,7 +1198,7 @@ declare function generateIdempotencyKey(): string;
847
1198
  * 시맨틱(입력→판정)은 3언어 동일하며 반환 형태만 다르다."
848
1199
  *
849
1200
  * Node 전용 API(`timingSafeEqual` 등) 미사용 — 브라우저/Node 공용
850
- * (`globalThis.crypto.subtle`, Node 18+ / 모던 브라우저).
1201
+ * (`globalThis.crypto.subtle`, Node 20+ / 모던 브라우저).
851
1202
  */
852
1203
  /** 웹훅 서명 헤더명 기본값 (contracts/webhook-signature.md). */
853
1204
  declare const WEBHOOK_SIGNATURE_HEADER = "X-Rscc-Signature";
@@ -966,6 +1317,7 @@ declare function createBulkResultBuilder(): BulkResultBuilder;
966
1317
  * - 판정은 **컨테이너 수준**: docx/hwpx 는 `zip`, hwp(5.0)/doc 는 `cfbf` 로
967
1318
  * 판정된다 (내부 구조 열람은 비범위).
968
1319
  * - 판정 우선순위는 계약 테이블 위→아래, 첫 일치 kind 반환.
1320
+ * - 메시지는 contracts/messages.yaml 의 `rscc.upload.*` 키 (기본 ko — 현행 문구 그대로, `locale` 로 en 등).
969
1321
  */
970
1322
  /** 매직바이트 판정 결과 kind — 3언어 공유 소문자 문자열 (계약 테이블 고정). */
971
1323
  type FileKind = "png" | "jpeg" | "gif" | "webp" | "pdf" | "zip" | "cfbf" | "hwp3";
@@ -982,6 +1334,8 @@ declare function sniffFile(head: ArrayBuffer | Uint8Array): FileKind | null;
982
1334
  * 대소문자 무시, 선행 `.` 은 허용(제거 후 비교).
983
1335
  */
984
1336
  declare function kindsForExtension(ext: string): ReadonlySet<FileKind>;
1337
+ /** validateUpload 메시지 키 — contracts/messages.yaml `rscc.upload.*` (`messages` 오버라이드 대상). */
1338
+ type UploadMessageKey = "rscc.upload.size" | "rscc.upload.extension" | "rscc.upload.contentMismatch";
985
1339
  /** validateUpload 결과 — ok:false 면 첫 위반 사유·계약 메시지를 담는다. */
986
1340
  type UploadValidationResult = {
987
1341
  ok: true;
@@ -1007,6 +1361,11 @@ type UploadValidationResult = {
1007
1361
  * @param input.allowedExtensions 허용 확장자 allowlist (대소문자 무시).
1008
1362
  * @param input.extraMappings 확장자 → 허용 kind 확장 주입 (선택). 키는 소문자·
1009
1363
  * 선행 `.` 없는 확장자.
1364
+ * @param input.locale 메시지 로케일 (BCP 47 — `"en"`·`"en-US"` 등, 주 서브태그 사용). 미지정 = `ko`
1365
+ * (현행 문구와 바이트 동일). 내장은 ko·en, 그 외 언어는 `messages` 로 템플릿을 주지 않으면 ko 로 폴백.
1366
+ * @param input.messages 메시지 템플릿 오버라이드 (선택) — 키 `rscc.upload.size` / `rscc.upload.extension`
1367
+ * (`{0}` = 확장자) / `rscc.upload.contentMismatch`. 준 키는 로케일과 무관하게 내장 문구보다 우선한다
1368
+ * (빈 문자열·키 자체와 같은 값은 무시 — {@link getMessage} 해석 순서).
1010
1369
  */
1011
1370
  declare function validateUpload(input: {
1012
1371
  fileName: string;
@@ -1015,8 +1374,94 @@ declare function validateUpload(input: {
1015
1374
  maxSizeBytes: number;
1016
1375
  allowedExtensions: readonly string[];
1017
1376
  extraMappings?: Readonly<Record<string, readonly FileKind[]>>;
1377
+ locale?: string;
1378
+ messages?: Partial<Record<UploadMessageKey, string>>;
1018
1379
  }): UploadValidationResult;
1019
1380
 
1381
+ /**
1382
+ * 와이어 메시지 다국어(i18n) — 내장 카탈로그(ko 기본 + en)·자리표시자 치환·해석·Accept-Language 협상.
1383
+ *
1384
+ * 단일 소스는 contracts/messages.yaml (문구) + contracts/i18n.md (규칙) — 수동 동기화, 계약 테스트
1385
+ * (`messages.test.ts`)가 yaml 을 직접 파싱해 25개 키의 ko·en 문구·fixed 여부·자리표시자 수를 대조한다.
1386
+ * Java `com.rscc.common.i18n.WireMessages` / Python `rscc_common.messages` 와 골든 벡터 LN-01~11·MSG-01~10 공유.
1387
+ *
1388
+ * - **기본 로케일은 `ko`** — 아무것도 지정하지 않으면 모든 문구는 이전(현행 한국어)과 바이트 동일.
1389
+ * - 서버 키(`rscc.result.*` 등)도 전부 내장한다 — 클라이언트 화면 표시·업로드 프리검증에 재사용.
1390
+ * - 런타임 의존성 0, `Intl`·DOM 미사용 — 브라우저·SSR·Node 공용.
1391
+ */
1392
+ /** 내장 언어 — 라이브러리가 문구를 직접 보유하는 언어 (그 외 언어는 `overrides` 로 공급). */
1393
+ type BuiltinLanguage = "ko" | "en";
1394
+ /** 메시지 키 — contracts/messages.yaml 의 25개 키 (서버 22 + 클라이언트 3). */
1395
+ type MessageKey = "rscc.result.SUCCESS" | "rscc.result.BAD_REQUEST" | "rscc.result.UNAUTHORIZED" | "rscc.result.FORBIDDEN" | "rscc.result.NOT_FOUND" | "rscc.result.METHOD_NOT_ALLOWED" | "rscc.result.CONFLICT" | "rscc.result.UNSUPPORTED_MEDIA_TYPE" | "rscc.result.TOO_MANY_REQUESTS" | "rscc.result.INTERNAL_SERVER_ERROR" | "rscc.web.missingParameter" | "rscc.web.typeMismatch" | "rscc.web.unreadableBody" | "rscc.idempotency.conflict" | "rscc.idempotency.invalidFormat" | "rscc.idempotency.required" | "rscc.upload.size" | "rscc.upload.extension" | "rscc.upload.contentMismatch" | "rscc.query.sortField" | "rscc.query.sortDirection" | "rscc.security.csrf" | "rscc.client.unreadableBody" | "rscc.client.invalidJson" | "rscc.client.httpError";
1396
+ /**
1397
+ * 내장 메시지 카탈로그 — `MESSAGES[언어][키]` = 템플릿(자리표시자 `{0}`… 미치환 원문). 동결 객체.
1398
+ * 표시용 문자열이 필요하면 {@link getMessage} 를 쓴다 (해석 순서·치환 포함).
1399
+ */
1400
+ declare const MESSAGES: Readonly<Record<BuiltinLanguage, Readonly<Record<MessageKey, string>>>>;
1401
+ /**
1402
+ * 규약 고정 문구 키 집합 (messages.yaml `fixed: true`) — 요청 언어가 `ko`·`en` 이면 내장 문구가
1403
+ * 오버라이드보다 항상 이긴다 (i18n.md §4-1). 그 외 언어는 오버라이드 허용.
1404
+ */
1405
+ declare const FIXED_MESSAGE_KEYS: ReadonlySet<MessageKey>;
1406
+ /**
1407
+ * 메시지 오버라이드 — 키 → 템플릿 표(언어 무관), 또는 `(key, language) => 템플릿` 리졸버.
1408
+ * `language` 는 요청 로케일의 주 서브태그(소문자, 예: `"ja"`). 빈 문자열·`null`·`undefined`·
1409
+ * **키 자체와 같은 결과**는 "미해결"로 보고 다음 단계로 넘어간다 (Spring `use-code-as-default-message` 대응).
1410
+ */
1411
+ type MessageOverrides = Readonly<Record<string, string | undefined>> | ((key: string, language: string) => string | null | undefined);
1412
+ /** {@link getMessage} 옵션. */
1413
+ interface GetMessageOptions {
1414
+ /** 요청 로케일 (BCP 47 태그 — `"en-US"`·`"ko"` 등, 주 서브태그만 사용). 미지정/빈 값 = `defaultLocale`. */
1415
+ locale?: string;
1416
+ /** 자리표시자 인자 — `{0}`, `{1}` … 에 순서대로 치환 ({@link formatMessage}). */
1417
+ args?: readonly unknown[];
1418
+ /** 기본 언어 (BCP 47 태그, 주 서브태그 사용). 기본 `"ko"`. */
1419
+ defaultLocale?: string;
1420
+ /** 오버라이드 표 또는 리졸버 — 내장 외 언어 공급·비고정 문구 교체용. {@link MessageOverrides} 참조. */
1421
+ overrides?: MessageOverrides;
1422
+ }
1423
+ /**
1424
+ * 템플릿의 `{N}` 을 N 번째 인자의 문자열 표현(`String(arg)`)으로 **단일 패스** 치환한다
1425
+ * (i18n.md §2 — MessageFormat 아님). 인자가 없는 `{N}` 은 그대로 두고, 치환된 인자 안의 `{…}` 는
1426
+ * 다시 치환하지 않는다 (MSG-10: `formatMessage("{0}-{1}", "{1}", "x")` → `"{1}-x"`).
1427
+ *
1428
+ * @example formatMessage("File type is not allowed: {0}", "exe") // "File type is not allowed: exe"
1429
+ */
1430
+ declare function formatMessage(template: string, ...args: unknown[]): string;
1431
+ /**
1432
+ * 메시지 키를 로케일별 문구로 해석하고 자리표시자를 치환한다 — 해석 순서는 i18n.md §4 그대로
1433
+ * (키 `K`, 요청 언어 `L` = `locale` 의 주 서브태그, 기본 언어 `D` = `defaultLocale` 의 주 서브태그(기본 `ko`)):
1434
+ *
1435
+ * 1. `K` 가 고정 키({@link FIXED_MESSAGE_KEYS})이고 `L` 이 `ko`·`en` → 내장[`L`][`K`] (오버라이드 불가)
1436
+ * 2. 오버라이드 결과가 비어 있지 않고 `K` 와 다르면 → 그 결과
1437
+ * 3. 내장[`L`][`K`] → 4. 내장[`D`][`K`] → 5. 내장[`ko`][`K`] → 6. 키 문자열 `K`
1438
+ *
1439
+ * 모르는 키도 예외 없이 키 문자열을 돌려준다 (MSG-04). `key` 는 `string` 이라 서비스 고유 키
1440
+ * (오버라이드로만 공급)도 조회할 수 있다.
1441
+ *
1442
+ * @example
1443
+ * getMessage("rscc.result.NOT_FOUND"); // "리소스를 찾을 수 없습니다." (기본 ko)
1444
+ * getMessage("rscc.upload.extension", { locale: "en-US", args: ["exe"] }); // "File type is not allowed: exe"
1445
+ */
1446
+ declare function getMessage(key: string, options?: GetMessageOptions): string;
1447
+ /**
1448
+ * `Accept-Language` 헤더로 응답 언어를 고른다 — i18n.md §3 그대로 (골든 벡터 LN-01~11):
1449
+ *
1450
+ * 1. `,` 로 나눈 각 항목을 `언어태그[;q=값]` 로 해석 — 형식 오류 항목·`q` 가 0~1 의 유효 숫자가 아닌 항목은 버림
1451
+ * 2. `q=0` 항목은 제외 (명시적 거부), `q` 생략은 1
1452
+ * 3. `q` 내림차순 **안정 정렬** (같은 `q` 는 헤더 순서 유지)
1453
+ * 4. 순서대로 각 태그의 주 서브태그(대소문자 무시)가 `supported` 에 있으면 그 언어, `*` 면 `fallback`
1454
+ * 5. 못 고르면(헤더 없음·전부 미지원·형식 오류) `fallback`
1455
+ *
1456
+ * 반환값은 소문자 주 서브태그(예: `"en"`) 또는 `fallback`. 브라우저에서는 `navigator.languages`
1457
+ * 대신 서버와 같은 규칙으로 판정하고 싶을 때(SSR 요청 헤더 등) 쓴다.
1458
+ *
1459
+ * @param acceptLanguage 헤더 값 (없으면 null/undefined).
1460
+ * @param supported 지원 언어(주 서브태그, 대소문자 무시). 기본 `["ko", "en"]` — 추가 언어는 오버라이드로 공급하는 언어.
1461
+ * @param fallback 기본 언어. 기본 `"ko"`.
1462
+ */
1463
+ declare function negotiateLanguage(acceptLanguage: string | null | undefined, supported?: readonly string[], fallback?: string): string;
1464
+
1020
1465
  /**
1021
1466
  * 목록 조회 쿼리 빌더 — page/size/sort. contracts/query-params.md (수동 동기화).
1022
1467
  *
@@ -1347,4 +1792,4 @@ declare function composeHangul(s: string): string;
1347
1792
  */
1348
1793
  declare function matchesHangul(query: string, target: string): boolean;
1349
1794
 
1350
- export { type ApiClient, type ApiClientConfig, type ApiClientRetryOptions, ApiError, type ApiErrorInfo, type ApiRequestInfo, type ApiResponseInfo, type ApiResult, type BulkResult, type BulkResultBuilder, type BulkResultItem, type Bulkhead, BulkheadFullError, type BulkheadOptions, type BusinessDays, type BusinessDaysOptions, type CircuitBreaker, type CircuitBreakerOptions, CircuitOpenError, type CircuitState, type CommonResponse, type FeatureFlagReader, type FieldErrorDetail, type FileKind, type JosaPair, type ListQueryOptions, type PageResponse, type PhoneType, ResultCode, type RetryOptions, type SortParam, type SseCallbacks, type SseFrameEvent, type SseSource, type TokenBucket, type TokenBucketOptions, type TtlCache, type TtlCacheOptions, type UploadValidationResult, type ValidationErrorData, WEBHOOK_SIGNATURE_HEADER, abbreviateAmount, ageByYear, ageInsurance, ageMan, attachJosa, buildListQuery, bulkFailures, classifyPhoneNumber, composeHangul, createApiClient, createBulkResultBuilder, createBulkhead, createBusinessDays, createCircuitBreaker, createFeatureFlags, createTokenBucket, createTtlCache, decodeJwtPayload, decomposeHangul, formatPhoneNumber, generateIdempotencyKey, getTokenExpiry, isBulkResult, isChosungQuery, isForeignerRrn, isRetryableStatus, isTokenExpired, isValidBusinessNumber, isValidCorporateNumber, isValidRrn, isValidationErrorData, kindsForExtension, maskCardNumber, maskEmail, maskName, maskPhone, maskSecret, matchesHangul, normalizeBusinessNumber, normalizePhoneNumber, normalizeRrn, parseFlag, parseRetryAfterMs, parseSseFrame, parseWireDateTime, pickJosa, readSseStream, retry, rrnBirthDate, rrnChecksumOkLegacy, sanitizeLogValue, signWebhook, sniffFile, stripZone, toChosung, toE164, toFormalNotation, toKoreanWords, toWireDate, toWireDateTime, validateUpload, verifyWebhook };
1795
+ export { type ApiClient, type ApiClientConfig, type ApiClientRetryOptions, ApiError, type ApiErrorInfo, type ApiRequestInfo, type ApiResponseInfo, type ApiResult, type BuiltinLanguage, type BulkResult, type BulkResultBuilder, type BulkResultItem, type Bulkhead, BulkheadFullError, type BulkheadOptions, type BusinessDays, type BusinessDaysOptions, type CircuitBreaker, type CircuitBreakerOptions, CircuitOpenError, type CircuitState, type CommonResponse, type CsrfOptions, DEFAULT_CSRF_COOKIE_NAME, DEFAULT_CSRF_HEADER_NAME, type ErrorCodeValue, FIXED_MESSAGE_KEYS, type FeatureFlagReader, type FieldErrorDetail, type FileKind, type FormatSseEventOptions, type GetMessageOptions, type JosaPair, type ListQueryOptions, MESSAGES, type MessageKey, type MessageOverrides, type PageResponse, type PhoneType, type ReadSseEventsOptions, type ReadSseEventsResult, ResultCode, type RetryOptions, type SortParam, type SseCallbacks, type SseEvent, type SseEventParser, type SseEventParserOptions, type SseFrameEvent, type SseSource, type TokenBucket, type TokenBucketOptions, type TtlCache, type TtlCacheOptions, type UploadMessageKey, type UploadValidationResult, type ValidationErrorData, WEBHOOK_SIGNATURE_HEADER, abbreviateAmount, ageByYear, ageInsurance, ageMan, attachJosa, buildListQuery, bulkFailures, classifyPhoneNumber, composeHangul, createApiClient, createBulkResultBuilder, createBulkhead, createBusinessDays, createCircuitBreaker, createFeatureFlags, createSseEventParser, createTokenBucket, createTtlCache, csrfHeaderFor, decodeJwtPayload, decomposeHangul, formatMessage, formatPhoneNumber, formatSseComment, formatSseEvent, generateIdempotencyKey, getMessage, getTokenExpiry, isBulkResult, isChosungQuery, isCommonResultCode, isForeignerRrn, isRetryableStatus, isTokenExpired, isUnsafeMethod, isValidBusinessNumber, isValidCorporateNumber, isValidRrn, isValidationErrorData, kindsForExtension, maskCardNumber, maskEmail, maskName, maskPhone, maskSecret, matchesHangul, negotiateLanguage, normalizeBusinessNumber, normalizePhoneNumber, normalizeRrn, parseChatPayload, parseFlag, parseRetryAfterMs, parseSseEvents, parseSseFrame, parseWireDateTime, pickJosa, readCookie, readSseChatEvents, readSseEvents, readSseStream, resultCodeForStatus, retry, rrnBirthDate, rrnChecksumOkLegacy, sanitizeLogValue, signWebhook, sniffFile, stripZone, toChosung, toCommonResultCode, toE164, toFormalNotation, toKoreanWords, toWireDate, toWireDateTime, validateUpload, verifyWebhook };