@rscc/common-core 0.4.0 → 0.6.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.cts 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,48 @@ 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;
77
121
 
78
122
  /**
79
123
  * CSRF double-submit 클라이언트 헬퍼 — contracts/session-auth.md §4·§5 (수동 동기화).
@@ -213,10 +257,24 @@ declare function retry<T>(fn: (attempt: number) => Promise<T> | T, options?: Ret
213
257
  * `traceId` 는 장애 문의 시 사용자에게 제시할 수 있는 상관관계 식별자다
214
258
  * (contracts/trace.md). 응답 에코 헤더 값이 우선이며, 에코를 읽을 수 없으면
215
259
  * (예: CORS 에서 Access-Control-Expose-Headers 미설정) 요청에 부착해 보낸 값을 쓴다.
260
+ *
261
+ * 에러 코드 확장 (contracts/error-code-extension.md): `code` 는 서버가 보낸 원 코드(서비스 도메인 코드
262
+ * 포함)를 그대로 보존하고, `commonCode` 는 폴백 규칙으로 정규화한 공통 코드다 — 공통 코드만 아는
263
+ * 분기(`switch (e.commonCode)`)는 도메인 코드가 추가돼도 깨지지 않는다.
216
264
  */
217
265
  declare class ApiError extends Error {
218
- /** 결과 코드 — 봉투의 code, 비봉투 응답이면 HTTP 상태 코드 문자열. */
219
- 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;
220
278
  /** HTTP 상태 코드. */
221
279
  readonly status: number;
222
280
  /** 이 요청의 traceId (에코 헤더 우선, 없으면 발신 값). */
@@ -384,6 +442,27 @@ interface ApiClientConfig {
384
442
  onResponse?: (info: ApiResponseInfo) => void;
385
443
  /** 관측 훅 — 재시도 포함 최종 실패 확정 시 1회 발화. 예외 정책은 {@link onRequest} 참조. */
386
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;
387
466
  }
388
467
  /** 성공 결과 + 메타 (traceId 등). requestWithMeta 의 반환형. */
389
468
  interface ApiResult<T> {
@@ -427,6 +506,8 @@ interface ApiClient {
427
506
  * `jwt-cookie`/`session` = `credentials` + `csrf` (쿠키는 브라우저가 싣고 CSRF 헤더만 자동 부착).
428
507
  * - retry 지정 시 요청을 core retry() 로 감싼다 ({@link ApiClientRetryOptions} —
429
508
  * 멱등 메서드 기본, Retry-After 하한, 시도 간 동일 traceId).
509
+ * - 클라이언트가 직접 만드는 ApiError 메시지는 `locale` 로 다국어화된다 (기본 ko, contracts/i18n.md) —
510
+ * `sendAcceptLanguage` 로 서버 협상용 `Accept-Language` 부착도 opt-in 가능.
430
511
  *
431
512
  * 저장소 접근·경로·이벤트명 하드코딩 없음 — 전부 config 주입 (opt-in `csrf` 의 CSRF 쿠키 읽기만 예외 —
432
513
  * 기본 `document.cookie`, `readCookie` 로 교체 가능).
@@ -444,7 +525,8 @@ declare function createApiClient(config: ApiClientConfig): ApiClient;
444
525
  *
445
526
  * 주의: 프레임 구분자는 계약상 LF(`\n\n`) 고정 — CRLF(`\r\n\r\n`) 로 내려오는
446
527
  * 스트림은 지원하지 않는다 (프록시 등이 개행을 CRLF 로 정규화하면 프레임이
447
- * 분리되지 않아 유실됨. 서버 계약이 LF 를 보장할 때만 사용할 것).
528
+ * 분리되지 않아 유실됨. 서버 계약이 LF 를 보장할 때만 사용할 것). CRLF·멀티라인 data 에도
529
+ * 견고해야 하면 표준 파서 위의 {@link readSseChatEvents} 를 쓴다 (contracts/sse-events.md §4).
448
530
  */
449
531
  /** sources 프레임의 요소 (camelCase — sse-frames.md 의 웹/외부 응답 계약). */
450
532
  interface SseSource {
@@ -484,6 +566,16 @@ type SseFrameEvent = {
484
566
  * - 일치 키 없음/JSON 파싱 실패 → 조용히 skip
485
567
  */
486
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;
487
579
  interface SseCallbacks {
488
580
  /** 스트림 첫 프레임의 대화 세션 id (search-api 가 prepend). */
489
581
  onConversationId?: (id: number) => void;
@@ -506,6 +598,163 @@ interface SseCallbacks {
506
598
  declare function readSseStream(response: {
507
599
  body: ReadableStream<Uint8Array> | null;
508
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;
509
758
 
510
759
  /**
511
760
  * JWT 페이로드 디코더 (contracts/jwt-claims.md).
@@ -574,30 +823,93 @@ declare function maskEmail(email: string): string;
574
823
  declare function maskCardNumber(cardNumber: string): string;
575
824
 
576
825
  /**
577
- * 오프셋 없는 LocalDateTime 와이어 직렬화 헬퍼 — contracts/datetime.md.
826
+ * LocalDateTime 와이어 직렬화 헬퍼 — contracts/datetime.md.
578
827
  *
579
- * 핵심 규약: **와이어에는 시간대/오프셋을 절대 싣지 않는다.** 값은 서버 기준
580
- * (운영 전제: KST) 벽시계 시각으로 해석된다.
828
+ * 두 프로필:
829
+ * - **local 프로필(기본·현행)** — 와이어에 시간대/오프셋을 싣지 않는다(`yyyy-MM-ddTHH:mm:ss`).
830
+ * 값은 서버 기준(운영 전제: KST) 벽시계 시각으로 해석된다. 옵션을 주지 않으면 항상 이 동작이다.
831
+ * - **offset 프로필(opt-in)** — `yyyy-MM-ddTHH:mm:ss(Z|±HH:MM)`. 오프셋은 그 순간의 기준 시간대
832
+ * 오프셋이며 0 오프셋은 `Z`. `toWireDateTime(date, { offset: true })` 로 켠다.
833
+ *
834
+ * 기준 시간대(wire zone)는 기본이 **실행 환경의 로컬 시간대**(브라우저/Node 로컬 게터 — 현행)이고,
835
+ * `timeZone`(IANA 이름: `Asia/Seoul`, `UTC`, `America/New_York`)으로 고정할 수 있다. 시간대 계산은
836
+ * `Intl.DateTimeFormat(...).formatToParts` 만 쓴다(런타임 의존성 0 — Node full-ICU / 모던 브라우저 전제).
837
+ * 잘못된 `timeZone` 은 `Intl.DateTimeFormat` 이 던지는 `RangeError` 를 그대로 전파한다.
581
838
  *
582
839
  * ⚠️ Z 스큐 경고(datetime.md): `new Date(x).toISOString()` 은 UTC 로 변환해 끝에
583
840
  * `Z` 를 붙인다. 서버(`LocalDateTime`)는 그 `Z` 를 조용히 버리고 나머지를 KST 벽시계로
584
- * 재해석해 **9시간 스큐**를 만든다. 이 모듈의 직렬화 함수는 오프셋을 절대 만들지 않아
841
+ * 재해석해 **9시간 스큐**를 만든다. 이 모듈의 직렬화 함수는 기본적으로 오프셋을 만들지 않아
585
842
  * 그 경로를 원천 차단한다. `<input type="datetime-local">` 값은 이미 오프셋 없는
586
843
  * 형식이므로 그대로 보내면 되고, Date 객체를 보내야 할 땐 {@link toWireDateTime} 을 쓴다.
844
+ * offset 프로필(`offset: true`)은 **서버가 offset 프로필로 전환한 서비스에서만** 쓸 것.
587
845
  */
846
+ /** {@link toWireDateTime} 옵션 — 모두 opt-in, 생략 시 현행(로컬 게터·오프셋 없음). */
847
+ interface WireDateTimeFormatOptions {
848
+ /**
849
+ * 기준 시간대(IANA 이름, 예: `"Asia/Seoul"`, `"UTC"`). 지정하면 그 순간을 이 시간대의 벽시계로 직렬화한다.
850
+ * 생략 시 실행 환경의 로컬 시간대(현행). 잘못된 이름은 `RangeError`.
851
+ */
852
+ timeZone?: string;
853
+ /**
854
+ * `true` 면 offset 프로필 — 그 순간의 기준 시간대 오프셋을 붙인다(0 은 `Z`, 그 외 `±HH:MM`).
855
+ * `timeZone` 없이 켜면 호스트 오프셋(`-date.getTimezoneOffset()`)을 쓴다. 기본 `false`(현행).
856
+ */
857
+ offset?: boolean;
858
+ }
859
+ /** {@link toWireDate} 옵션 — 생략 시 현행(로컬 날짜). */
860
+ interface WireDateFormatOptions {
861
+ /** 기준 시간대(IANA 이름). 지정하면 그 순간의 이 시간대 날짜를 직렬화한다. 잘못된 이름은 `RangeError`. */
862
+ timeZone?: string;
863
+ }
588
864
  /**
589
- * Date 의 **로컬** 필드를 `yyyy-MM-ddTHH:mm:ss`(오프셋 없음)로 직렬화한다.
590
- * `toISOString()`(UTC/Z) 대신 이 함수를 쓸 것 — 그래야 스큐가 생기지 않는다.
865
+ * 수신 오프셋 정책 — 오프셋이 붙은 문자열을 받았을 때의 동작(contracts/datetime.md §수신 오프셋 정책).
866
+ * - `"drop"`(기본·현행): 오프셋(`Z`·`±HH:MM`·`±HHMM`)을 버리고 나머지를 벽시계로 해석 — Z 스큐 그대로.
867
+ * - `"convert"`: 오프셋으로 정확한 순간을 계산(`timeZone` 무관). RFC 3339 오프셋(`Z`·`±HH:MM`)만 인식.
868
+ * - `"reject"`: RFC 3339 오프셋이 붙어 있으면 `RangeError`.
591
869
  */
592
- declare function toWireDateTime(date: Date): string;
593
- /** Date 의 로컬 날짜를 `yyyy-MM-dd` 로 직렬화한다. */
594
- declare function toWireDate(date: Date): string;
870
+ type InboundOffsetPolicy = "drop" | "convert" | "reject";
871
+ /** {@link parseWireDateTime} 옵션 — 모두 opt-in, 생략 시 현행(로컬 해석·오프셋 drop). */
872
+ interface WireDateTimeParseOptions {
873
+ /**
874
+ * 기준 시간대(IANA 이름). 오프셋 없는 벽시계를 이 시간대 기준으로 해석한다(DST 갭은 갭 길이만큼 뒤로,
875
+ * 겹침은 이른 오프셋). 생략 시 실행 환경의 로컬 시간대(현행). 잘못된 이름은 `RangeError`.
876
+ */
877
+ timeZone?: string;
878
+ /** 수신 오프셋 정책. 기본 `"drop"`(현행). */
879
+ inboundOffset?: InboundOffsetPolicy;
880
+ }
595
881
  /**
596
- * 와이어 datetime 문자열(`yyyy-MM-ddTHH:mm[:ss[.fff]]`)을 **로컬 시간대**로 해석한
597
- * Date 로 파싱한다(사용자·서버가 모두 KST 라는 전제). 끝의 `Z`/오프셋은 무시하고
598
- * 벽시계 숫자만 취한다(Java Jackson lenient 파리티). 형식 불일치 시 throw.
882
+ * Date 를 와이어 datetime(초 단위)으로 직렬화한다. `toISOString()`(UTC/Z) 대신 이 함수를 쓸 것.
883
+ *
884
+ * - 옵션 없음(기본·현행): **로컬** 필드를 `yyyy-MM-ddTHH:mm:ss`(오프셋 없음)로 — 스큐가 생기지 않는다.
885
+ * - `timeZone`: 그 순간을 해당 IANA 시간대의 벽시계로 직렬화.
886
+ * - `offset: true`: offset 프로필 — 그 순간의 기준 시간대 오프셋을 붙인다(`Z` / `±HH:MM`).
887
+ * `timeZone` 이 없으면 호스트 오프셋(`-date.getTimezoneOffset()`).
888
+ *
889
+ * @throws RangeError 잘못된 `timeZone`, 또는 시간대/오프셋 옵션과 함께 준 잘못된 Date(Invalid Date)
599
890
  */
600
- declare function parseWireDateTime(value: string): Date;
891
+ declare function toWireDateTime(date: Date, options?: WireDateTimeFormatOptions): string;
892
+ /**
893
+ * Date 의 날짜를 `yyyy-MM-dd` 로 직렬화한다. 기본은 로컬 날짜(현행), `timeZone` 을 주면 그 순간의
894
+ * 해당 시간대 날짜.
895
+ *
896
+ * @throws RangeError 잘못된 `timeZone`, 또는 `timeZone` 과 함께 준 잘못된 Date
897
+ */
898
+ declare function toWireDate(date: Date, options?: WireDateFormatOptions): string;
899
+ /**
900
+ * 와이어 datetime 문자열(`yyyy-MM-ddTHH:mm[:ss[.fff…]]`, 소수부는 밀리초까지 보존)을 Date 로 파싱한다.
901
+ *
902
+ * - 옵션 없음(기본·현행): **로컬 시간대**로 해석(사용자·서버가 모두 KST 라는 전제). 끝의 `Z`/오프셋은
903
+ * 무시하고 벽시계 숫자만 취한다(Java Jackson lenient 파리티). 로컬 DST 갭 시각은 throw(현행).
904
+ * - `timeZone`: 오프셋 없는 벽시계를 그 IANA 시간대로 해석한다 — DST 갭은 갭 길이만큼 뒤로, 겹침은 이른 오프셋.
905
+ * - `inboundOffset`: 오프셋이 붙은 입력의 정책 — `"drop"`(기본·현행) / `"convert"`(오프셋으로 정확한 순간,
906
+ * `timeZone` 무관) / `"reject"`(`RangeError`). `convert`·`reject` 는 RFC 3339 오프셋(`Z`·`±HH:MM`)만
907
+ * 인식하므로 `+0900` 같은 다른 표기는 형식 오류가 된다. 오프셋 없는 입력은 모든 정책에서 벽시계 그대로.
908
+ *
909
+ * @throws Error 형식 불일치·범위를 벗어난 값(25시·2월 30일 등)·잘못된 오프셋
910
+ * @throws RangeError 잘못된 `timeZone`·알 수 없는 `inboundOffset`, `"reject"` 정책에서 오프셋이 붙은 입력
911
+ */
912
+ declare function parseWireDateTime(value: string, options?: WireDateTimeParseOptions): Date;
601
913
  /**
602
914
  * 문자열 끝의 `Z` 또는 `±HH:MM`/`±HHMM` 오프셋을 제거한다(발신 전 sanitize).
603
915
  * 시각 자체는 변환하지 않고 벽시계 부분만 남긴다. 오프셋이 없으면 원본을 그대로 반환.
@@ -1068,6 +1380,7 @@ declare function createBulkResultBuilder(): BulkResultBuilder;
1068
1380
  * - 판정은 **컨테이너 수준**: docx/hwpx 는 `zip`, hwp(5.0)/doc 는 `cfbf` 로
1069
1381
  * 판정된다 (내부 구조 열람은 비범위).
1070
1382
  * - 판정 우선순위는 계약 테이블 위→아래, 첫 일치 kind 반환.
1383
+ * - 메시지는 contracts/messages.yaml 의 `rscc.upload.*` 키 (기본 ko — 현행 문구 그대로, `locale` 로 en 등).
1071
1384
  */
1072
1385
  /** 매직바이트 판정 결과 kind — 3언어 공유 소문자 문자열 (계약 테이블 고정). */
1073
1386
  type FileKind = "png" | "jpeg" | "gif" | "webp" | "pdf" | "zip" | "cfbf" | "hwp3";
@@ -1084,6 +1397,8 @@ declare function sniffFile(head: ArrayBuffer | Uint8Array): FileKind | null;
1084
1397
  * 대소문자 무시, 선행 `.` 은 허용(제거 후 비교).
1085
1398
  */
1086
1399
  declare function kindsForExtension(ext: string): ReadonlySet<FileKind>;
1400
+ /** validateUpload 메시지 키 — contracts/messages.yaml `rscc.upload.*` (`messages` 오버라이드 대상). */
1401
+ type UploadMessageKey = "rscc.upload.size" | "rscc.upload.extension" | "rscc.upload.contentMismatch";
1087
1402
  /** validateUpload 결과 — ok:false 면 첫 위반 사유·계약 메시지를 담는다. */
1088
1403
  type UploadValidationResult = {
1089
1404
  ok: true;
@@ -1109,6 +1424,11 @@ type UploadValidationResult = {
1109
1424
  * @param input.allowedExtensions 허용 확장자 allowlist (대소문자 무시).
1110
1425
  * @param input.extraMappings 확장자 → 허용 kind 확장 주입 (선택). 키는 소문자·
1111
1426
  * 선행 `.` 없는 확장자.
1427
+ * @param input.locale 메시지 로케일 (BCP 47 — `"en"`·`"en-US"` 등, 주 서브태그 사용). 미지정 = `ko`
1428
+ * (현행 문구와 바이트 동일). 내장은 ko·en, 그 외 언어는 `messages` 로 템플릿을 주지 않으면 ko 로 폴백.
1429
+ * @param input.messages 메시지 템플릿 오버라이드 (선택) — 키 `rscc.upload.size` / `rscc.upload.extension`
1430
+ * (`{0}` = 확장자) / `rscc.upload.contentMismatch`. 준 키는 로케일과 무관하게 내장 문구보다 우선한다
1431
+ * (빈 문자열·키 자체와 같은 값은 무시 — {@link getMessage} 해석 순서).
1112
1432
  */
1113
1433
  declare function validateUpload(input: {
1114
1434
  fileName: string;
@@ -1117,8 +1437,94 @@ declare function validateUpload(input: {
1117
1437
  maxSizeBytes: number;
1118
1438
  allowedExtensions: readonly string[];
1119
1439
  extraMappings?: Readonly<Record<string, readonly FileKind[]>>;
1440
+ locale?: string;
1441
+ messages?: Partial<Record<UploadMessageKey, string>>;
1120
1442
  }): UploadValidationResult;
1121
1443
 
1444
+ /**
1445
+ * 와이어 메시지 다국어(i18n) — 내장 카탈로그(ko 기본 + en)·자리표시자 치환·해석·Accept-Language 협상.
1446
+ *
1447
+ * 단일 소스는 contracts/messages.yaml (문구) + contracts/i18n.md (규칙) — 수동 동기화, 계약 테스트
1448
+ * (`messages.test.ts`)가 yaml 을 직접 파싱해 25개 키의 ko·en 문구·fixed 여부·자리표시자 수를 대조한다.
1449
+ * Java `com.rscc.common.i18n.WireMessages` / Python `rscc_common.messages` 와 골든 벡터 LN-01~11·MSG-01~10 공유.
1450
+ *
1451
+ * - **기본 로케일은 `ko`** — 아무것도 지정하지 않으면 모든 문구는 이전(현행 한국어)과 바이트 동일.
1452
+ * - 서버 키(`rscc.result.*` 등)도 전부 내장한다 — 클라이언트 화면 표시·업로드 프리검증에 재사용.
1453
+ * - 런타임 의존성 0, `Intl`·DOM 미사용 — 브라우저·SSR·Node 공용.
1454
+ */
1455
+ /** 내장 언어 — 라이브러리가 문구를 직접 보유하는 언어 (그 외 언어는 `overrides` 로 공급). */
1456
+ type BuiltinLanguage = "ko" | "en";
1457
+ /** 메시지 키 — contracts/messages.yaml 의 25개 키 (서버 22 + 클라이언트 3). */
1458
+ 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";
1459
+ /**
1460
+ * 내장 메시지 카탈로그 — `MESSAGES[언어][키]` = 템플릿(자리표시자 `{0}`… 미치환 원문). 동결 객체.
1461
+ * 표시용 문자열이 필요하면 {@link getMessage} 를 쓴다 (해석 순서·치환 포함).
1462
+ */
1463
+ declare const MESSAGES: Readonly<Record<BuiltinLanguage, Readonly<Record<MessageKey, string>>>>;
1464
+ /**
1465
+ * 규약 고정 문구 키 집합 (messages.yaml `fixed: true`) — 요청 언어가 `ko`·`en` 이면 내장 문구가
1466
+ * 오버라이드보다 항상 이긴다 (i18n.md §4-1). 그 외 언어는 오버라이드 허용.
1467
+ */
1468
+ declare const FIXED_MESSAGE_KEYS: ReadonlySet<MessageKey>;
1469
+ /**
1470
+ * 메시지 오버라이드 — 키 → 템플릿 표(언어 무관), 또는 `(key, language) => 템플릿` 리졸버.
1471
+ * `language` 는 요청 로케일의 주 서브태그(소문자, 예: `"ja"`). 빈 문자열·`null`·`undefined`·
1472
+ * **키 자체와 같은 결과**는 "미해결"로 보고 다음 단계로 넘어간다 (Spring `use-code-as-default-message` 대응).
1473
+ */
1474
+ type MessageOverrides = Readonly<Record<string, string | undefined>> | ((key: string, language: string) => string | null | undefined);
1475
+ /** {@link getMessage} 옵션. */
1476
+ interface GetMessageOptions {
1477
+ /** 요청 로케일 (BCP 47 태그 — `"en-US"`·`"ko"` 등, 주 서브태그만 사용). 미지정/빈 값 = `defaultLocale`. */
1478
+ locale?: string;
1479
+ /** 자리표시자 인자 — `{0}`, `{1}` … 에 순서대로 치환 ({@link formatMessage}). */
1480
+ args?: readonly unknown[];
1481
+ /** 기본 언어 (BCP 47 태그, 주 서브태그 사용). 기본 `"ko"`. */
1482
+ defaultLocale?: string;
1483
+ /** 오버라이드 표 또는 리졸버 — 내장 외 언어 공급·비고정 문구 교체용. {@link MessageOverrides} 참조. */
1484
+ overrides?: MessageOverrides;
1485
+ }
1486
+ /**
1487
+ * 템플릿의 `{N}` 을 N 번째 인자의 문자열 표현(`String(arg)`)으로 **단일 패스** 치환한다
1488
+ * (i18n.md §2 — MessageFormat 아님). 인자가 없는 `{N}` 은 그대로 두고, 치환된 인자 안의 `{…}` 는
1489
+ * 다시 치환하지 않는다 (MSG-10: `formatMessage("{0}-{1}", "{1}", "x")` → `"{1}-x"`).
1490
+ *
1491
+ * @example formatMessage("File type is not allowed: {0}", "exe") // "File type is not allowed: exe"
1492
+ */
1493
+ declare function formatMessage(template: string, ...args: unknown[]): string;
1494
+ /**
1495
+ * 메시지 키를 로케일별 문구로 해석하고 자리표시자를 치환한다 — 해석 순서는 i18n.md §4 그대로
1496
+ * (키 `K`, 요청 언어 `L` = `locale` 의 주 서브태그, 기본 언어 `D` = `defaultLocale` 의 주 서브태그(기본 `ko`)):
1497
+ *
1498
+ * 1. `K` 가 고정 키({@link FIXED_MESSAGE_KEYS})이고 `L` 이 `ko`·`en` → 내장[`L`][`K`] (오버라이드 불가)
1499
+ * 2. 오버라이드 결과가 비어 있지 않고 `K` 와 다르면 → 그 결과
1500
+ * 3. 내장[`L`][`K`] → 4. 내장[`D`][`K`] → 5. 내장[`ko`][`K`] → 6. 키 문자열 `K`
1501
+ *
1502
+ * 모르는 키도 예외 없이 키 문자열을 돌려준다 (MSG-04). `key` 는 `string` 이라 서비스 고유 키
1503
+ * (오버라이드로만 공급)도 조회할 수 있다.
1504
+ *
1505
+ * @example
1506
+ * getMessage("rscc.result.NOT_FOUND"); // "리소스를 찾을 수 없습니다." (기본 ko)
1507
+ * getMessage("rscc.upload.extension", { locale: "en-US", args: ["exe"] }); // "File type is not allowed: exe"
1508
+ */
1509
+ declare function getMessage(key: string, options?: GetMessageOptions): string;
1510
+ /**
1511
+ * `Accept-Language` 헤더로 응답 언어를 고른다 — i18n.md §3 그대로 (골든 벡터 LN-01~11):
1512
+ *
1513
+ * 1. `,` 로 나눈 각 항목을 `언어태그[;q=값]` 로 해석 — 형식 오류 항목·`q` 가 0~1 의 유효 숫자가 아닌 항목은 버림
1514
+ * 2. `q=0` 항목은 제외 (명시적 거부), `q` 생략은 1
1515
+ * 3. `q` 내림차순 **안정 정렬** (같은 `q` 는 헤더 순서 유지)
1516
+ * 4. 순서대로 각 태그의 주 서브태그(대소문자 무시)가 `supported` 에 있으면 그 언어, `*` 면 `fallback`
1517
+ * 5. 못 고르면(헤더 없음·전부 미지원·형식 오류) `fallback`
1518
+ *
1519
+ * 반환값은 소문자 주 서브태그(예: `"en"`) 또는 `fallback`. 브라우저에서는 `navigator.languages`
1520
+ * 대신 서버와 같은 규칙으로 판정하고 싶을 때(SSR 요청 헤더 등) 쓴다.
1521
+ *
1522
+ * @param acceptLanguage 헤더 값 (없으면 null/undefined).
1523
+ * @param supported 지원 언어(주 서브태그, 대소문자 무시). 기본 `["ko", "en"]` — 추가 언어는 오버라이드로 공급하는 언어.
1524
+ * @param fallback 기본 언어. 기본 `"ko"`.
1525
+ */
1526
+ declare function negotiateLanguage(acceptLanguage: string | null | undefined, supported?: readonly string[], fallback?: string): string;
1527
+
1122
1528
  /**
1123
1529
  * 목록 조회 쿼리 빌더 — page/size/sort. contracts/query-params.md (수동 동기화).
1124
1530
  *
@@ -1449,4 +1855,4 @@ declare function composeHangul(s: string): string;
1449
1855
  */
1450
1856
  declare function matchesHangul(query: string, target: string): boolean;
1451
1857
 
1452
- 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 CsrfOptions, DEFAULT_CSRF_COOKIE_NAME, DEFAULT_CSRF_HEADER_NAME, 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, csrfHeaderFor, decodeJwtPayload, decomposeHangul, formatPhoneNumber, generateIdempotencyKey, getTokenExpiry, isBulkResult, isChosungQuery, isForeignerRrn, isRetryableStatus, isTokenExpired, isUnsafeMethod, isValidBusinessNumber, isValidCorporateNumber, isValidRrn, isValidationErrorData, kindsForExtension, maskCardNumber, maskEmail, maskName, maskPhone, maskSecret, matchesHangul, normalizeBusinessNumber, normalizePhoneNumber, normalizeRrn, parseFlag, parseRetryAfterMs, parseSseFrame, parseWireDateTime, pickJosa, readCookie, readSseStream, retry, rrnBirthDate, rrnChecksumOkLegacy, sanitizeLogValue, signWebhook, sniffFile, stripZone, toChosung, toE164, toFormalNotation, toKoreanWords, toWireDate, toWireDateTime, validateUpload, verifyWebhook };
1858
+ 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 InboundOffsetPolicy, 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, type WireDateFormatOptions, type WireDateTimeFormatOptions, type WireDateTimeParseOptions, 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 };