connectbase-client 6.11.0 → 6.13.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
@@ -456,6 +456,17 @@ declare class HttpClient {
456
456
  private markNoCookieSession;
457
457
  private clearNoCookieSessionMark;
458
458
  /** 쿠키 전용 refresh 를 지금 건너뛰어야 하는지 (최근에 401/403 을 받았는지). */
459
+ /**
460
+ * 이 브라우저에 세션이 없다는 것을 이미 아는가. 메모리에 access/refresh token 이 없고, 60초 안의 쿠키 복구가
461
+ * "세션 없음"(401 또는 quiet 204)으로 끝났으면 true 다. 회원 전용 API 는 물어도 401 뿐이라, 부르는 쪽이 요청을
462
+ * 건너뛰고 {@link rejectNoSession} 으로 같은 오류를 던질 때 쓴다.
463
+ */
464
+ knowsNoSession(): boolean;
465
+ /**
466
+ * 세션이 없을 때 서버가 돌려주는 것과 같은 401 ApiError 를 요청 없이 만든다. 서버 경로와 같은 변환(buildApiError)과
467
+ * 오류 알림(emitError)을 거치므로 앱이 받는 오류는 그대로이고, 브라우저 콘솔에 실패한 요청만 남지 않는다.
468
+ */
469
+ rejectNoSession(): Promise<ApiError>;
459
470
  private isNoCookieSessionMarkFresh;
460
471
  /**
461
472
  * OAuth redirect callback 직후 호출되어 HttpOnly cookie 를 부트스트랩한다.
@@ -558,6 +569,23 @@ declare class HttpClient {
558
569
  tryRestoreSessionFromCookie(): Promise<boolean>;
559
570
  private emitError;
560
571
  private isTokenExpired;
572
+ /**
573
+ * 실시간 연결(`cb.realtime`, `cb.database` 실시간)이 연결 위에서 token 을 갱신할 수 있는지 — token 이 이 클라이언트가 들고
574
+ * 있는 멤버 세션(같은 앱, 같은 멤버)의 것이고, 세션을 refresh 할 수단(메모리의 refresh token, 또는 브라우저의 HttpOnly
575
+ * 쿠키)이 있을 때만이다. 앱이 다른 곳에서 받은 토큰(다른 멤버, 함수의 위임 토큰, OAuth 토큰)이면 false.
576
+ */
577
+ canRefreshMemberToken(token: string | undefined): boolean;
578
+ /**
579
+ * token 과 같은 멤버 세션의 access token 을 minValiditySec 초 이상 남은 것으로 돌려준다. 지금 세션 토큰이 그만큼 남았으면
580
+ * 그대로, 아니면 HTTP 요청과 같은 refresh(같은 single-flight, 같은 실패 처리 — 세션이 끝났으면 onTokenExpired)를 한다.
581
+ * 세션이 다르거나 갱신에 실패하면 undefined.
582
+ *
583
+ * `replace` 는 token 이 곧 만료된다고 서버가 알렸을 때 쓴다 — 세션 토큰이 token 과 같으면 이쪽 시계로는 아직 남았어도
584
+ * 갱신한다(기기 시계가 늦으면 서버 기준 만료를 놓친다).
585
+ */
586
+ freshTokenForMember(token: string, minValiditySec: number, options?: {
587
+ replace?: boolean;
588
+ }): Promise<string | undefined>;
561
589
  private prepareHeaders;
562
590
  /**
563
591
  * 실패 응답(`!response.ok`)을 ApiError 로 변환한다. 던지지도, emitError 하지도 않는다.
@@ -1639,6 +1667,33 @@ interface AppMemberDetail {
1639
1667
  suspended_until?: string;
1640
1668
  suspend_reason?: string;
1641
1669
  }
1670
+ /** `cb.appMembers.suspend` 옵션. */
1671
+ interface SuspendAppMemberOptions {
1672
+ /**
1673
+ * 정지 사유(1~500자). 정지된 회원이 로그인하거나 실시간에 다시 붙으려 할 때 이 문구가 그대로 보인다 — 회원에게
1674
+ * 보여 줄 문장으로 쓴다.
1675
+ */
1676
+ reason: string;
1677
+ /**
1678
+ * 정지가 풀리는 시각. 생략하면 `unsuspend` 할 때까지 **영구** 정지다. 지금 이후, 2038-01-19T03:14:07Z 이전이어야
1679
+ * 한다(그보다 길게 막으려면 생략한다). `Date` 또는 ISO 8601 문자열.
1680
+ */
1681
+ until?: Date | string;
1682
+ }
1683
+ /** `cb.appMembers.suspend` 반환값. 백엔드 `SuspendMemberResponse` 매핑. */
1684
+ interface SuspendAppMemberResult {
1685
+ member_id: string;
1686
+ is_suspended: boolean;
1687
+ suspended_at: string;
1688
+ /** 없으면 영구 정지. */
1689
+ suspended_until?: string;
1690
+ suspend_reason: string;
1691
+ }
1692
+ /** `cb.appMembers.unsuspend` 반환값. 백엔드 `UnsuspendMemberResponse` 매핑. */
1693
+ interface UnsuspendAppMemberResult {
1694
+ member_id: string;
1695
+ is_suspended: boolean;
1696
+ }
1642
1697
  /**
1643
1698
  * 앱 멤버 **관리자 조회** API — 서버사이드 전용.
1644
1699
  *
@@ -1649,7 +1704,8 @@ interface AppMemberDetail {
1649
1704
  * service_role 함수에서 쓰려면 함수 `management_scopes` 에 `app_member:read` 를 opt-in 해야
1650
1705
  * 한다. 이 스코프는 **이메일(개인정보)** 을 함께 열어주므로 어드민/CS 흐름에만 부여할 것.
1651
1706
  *
1652
- * 쓰기(생성·삭제·정지·수정)와 활동 로그 조회는 콘솔 전용이다 — service_role 에 열려 있지 않다.
1707
+ * 쓰기 중 삭제(`remove`, `app_member:write`)와 정지(`suspend`/`unsuspend`, `app_member:suspend`)만 service_role 에
1708
+ * 열려 있다. 생성, 수정과 활동 로그 조회는 콘솔 전용이다.
1653
1709
  *
1654
1710
  * @example
1655
1711
  * ```typescript
@@ -1712,6 +1768,46 @@ declare class AppMembersAPI {
1712
1768
  remove(appId: string, memberId: string): Promise<{
1713
1769
  message: string;
1714
1770
  }>;
1771
+ /**
1772
+ * 앱 멤버를 정지한다. 되돌릴 수 있다(`unsuspend`). (management_scope: `app_member:suspend`)
1773
+ *
1774
+ * 콘솔의 정지와 같은 일을 한다.
1775
+ * - 정지 기간 동안 로그인(비밀번호, 소셜), 토큰 재발급, 실시간 접속이 거부된다. 거부 사유로 `reason` 이 보인다.
1776
+ * - 그 회원의 세션(refresh token)을 모두 끊고, 지금 붙어 있는 실시간 연결(`cb.realtime`, DB 실시간, 게임, WebRTC
1777
+ * 시그널링)을 닫는다(close 4403 `member_revoked`).
1778
+ * - 이미 발급된 access token 은 HTTP 요청에는 만료(최대 1시간)까지 유효하다. 데이터 접근을 즉시 막아야 하면 RLS 규칙에
1779
+ * 정지 여부를 반영한다.
1780
+ * - 활동 로그(invoked_by `service_role`)와 IAM 감사(`app_member.suspend`)에 남는다.
1781
+ *
1782
+ * 이미 정지된 회원이면 400 이다(기간을 바꾸려면 `unsuspend` 후 다시 정지한다). 기간이 지난 정지는 정지로 보지 않는다.
1783
+ *
1784
+ * @param appId 앱 ID (함수 안에서는 `ctx.appId`)
1785
+ * @param memberId 정지할 멤버 ID
1786
+ * @param options `reason`(필수), `until`(생략하면 영구)
1787
+ *
1788
+ * @example
1789
+ * ```typescript
1790
+ * // 함수(service_role, management_scopes: ["app_member:suspend"]) 안에서 — 신고 누적 7일 정지
1791
+ * await ctx.cbAdmin.appMembers.suspend(ctx.appId, memberId, {
1792
+ * reason: '신고가 누적되어 7일간 이용이 제한됩니다',
1793
+ * until: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
1794
+ * })
1795
+ *
1796
+ * // 결제 사기 — 영구 정지(until 생략)
1797
+ * await ctx.cbAdmin.appMembers.suspend(ctx.appId, memberId, { reason: '결제 이상으로 계정이 정지되었습니다' })
1798
+ * ```
1799
+ */
1800
+ suspend(appId: string, memberId: string, options: SuspendAppMemberOptions): Promise<SuspendAppMemberResult>;
1801
+ /**
1802
+ * 앱 멤버의 정지를 푼다. (management_scope: `app_member:suspend`)
1803
+ *
1804
+ * 정지로 끊긴 세션은 되살아나지 않는다 — 회원은 다시 로그인해야 한다(정지 전에 발급된 토큰으로는 실시간에 다시 붙을
1805
+ * 수 없다). 정지되지 않은 회원이면 400 이다.
1806
+ *
1807
+ * @param appId 앱 ID
1808
+ * @param memberId 정지를 풀 멤버 ID
1809
+ */
1810
+ unsuspend(appId: string, memberId: string): Promise<UnsuspendAppMemberResult>;
1715
1811
  }
1716
1812
 
1717
1813
  /**
@@ -3219,6 +3315,15 @@ declare class DatabaseAPI {
3219
3315
  private pingInterval;
3220
3316
  private realtimeOnStateChange;
3221
3317
  private realtimeOnError;
3318
+ /**
3319
+ * 이 연결이 `token_refresh=1` 로 협상했는지 — 연결 토큰이 SDK 세션의 멤버 토큰이라 연결 위에서 갱신할 수 있을 때만.
3320
+ * 협상하지 않은 연결(다른 곳에서 받은 토큰, cross-app OAuth 토큰)은 예전처럼 동작한다(서버가 만료 뒤 24시간에 닫는다).
3321
+ */
3322
+ private realtimeTokenRefresh;
3323
+ private realtimeAuthRefreshInFlight;
3324
+ private realtimeAuthRetryTimer;
3325
+ /** 서버가 닫기 직전에 보낸 안내(TOKEN_EXPIRED, MEMBER_REVOKED) — 이어지는 close 오류의 메시지가 된다. */
3326
+ private realtimeCloseNotice;
3222
3327
  private activeSubscriptions;
3223
3328
  constructor(http: HttpClient);
3224
3329
  /**
@@ -3600,6 +3705,11 @@ declare class DatabaseAPI {
3600
3705
  */
3601
3706
  onRealtimeError(handler: (error: Error) => void): () => void;
3602
3707
  private setRealtimeState;
3708
+ /**
3709
+ * 연결(재연결)을 연다 — 먼저 토큰을 준비한다. SDK 세션의 멤버 토큰인데 곧(1분 안) 만료되면 새로 받는다. 끊긴 사이 만료된
3710
+ * 토큰으로 붙으면 서버가 거부해 재연결이 멈춘다. 앱이 다른 곳에서 받은 토큰은 건드리지 않는다.
3711
+ */
3712
+ private connectRealtimeSocket;
3603
3713
  private doRealtimeConnect;
3604
3714
  /**
3605
3715
  * 서버에 subscribe 메시지를 보내고 서버 subscription_id를 반환하는 Promise
@@ -3615,6 +3725,16 @@ declare class DatabaseAPI {
3615
3725
  private stopRealtimePing;
3616
3726
  private sendRealtimeMessage;
3617
3727
  private generateRequestId;
3728
+ /**
3729
+ * 연결을 끊지 않고 멤버 토큰을 바꾼다(`auth_refresh`). 새 토큰은 HTTP 요청과 같은 refresh 로 받는다
3730
+ * (`HttpClient.freshTokenForMember`). 한 번에 하나만 보내고, 성공하면 재연결도 새 토큰을 쓴다. 실패하면 30초 뒤 다시 해
3731
+ * 본다(서버는 만료 뒤 유예가 지나야 닫는다). SDK 세션 자체가 끝났으면 더 시도하지 않는다.
3732
+ */
3733
+ private refreshRealtimeAuth;
3734
+ /** 요청 하나를 보내고 같은 request_id 의 응답(또는 error)을 기다린다. */
3735
+ private sendRealtimeRequest;
3736
+ private scheduleRealtimeAuthRetry;
3737
+ private clearRealtimeAuthRetry;
3618
3738
  private debugLog;
3619
3739
  }
3620
3740
 
@@ -6333,8 +6453,8 @@ declare class OAuthAPI {
6333
6453
  private bootConsumePromise;
6334
6454
  /** 이 인스턴스가 `getCallbackResult()` 로 이미 적재한 콜백. 다시 불려도 토큰을 되돌리지 않는다. */
6335
6455
  private loadedCallback;
6336
- /** 진행 중이거나 끝난 code 교환. 주소에서 code 를 지운 뒤의 재호출이 같은 결과를 받게 한다. */
6337
- private codeExchange;
6456
+ /** 이 인스턴스가 이미 적재한 code 콜백. 다시 불려도 토큰을 되돌리지 않는다. */
6457
+ private loadedCodeCallback;
6338
6458
  constructor(http: HttpClient);
6339
6459
  /**
6340
6460
  * 활성화된 OAuth 프로바이더 목록 조회
@@ -6444,6 +6564,11 @@ declare class OAuthAPI {
6444
6564
  signInWithPopup(provider: OAuthProvider, callbackUrl?: string, options?: {
6445
6565
  intent?: "signin" | "signup";
6446
6566
  }): Promise<OAuthCallbackResponse>;
6567
+ /**
6568
+ * 네이티브 브릿지가 돌려준 주소에서 로그인 결과를 만든다. code 면 교환하고, 토큰이면(response_type 을 모르는 옛 서버)
6569
+ * 그대로 쓴다.
6570
+ */
6571
+ private readBridgeResult;
6447
6572
  /**
6448
6573
  * 팝업 메시지를 보낼 수 있는 출처: 서버 제공 콜백 페이지(API 서버)와 앱이 지정한 콜백 페이지.
6449
6574
  *
@@ -6475,6 +6600,10 @@ declare class OAuthAPI {
6475
6600
  * 않으면(남이 보낸 링크 등) 토큰을 적재하지 않고 `{ error: 'oauth_state_mismatch' }` 를 돌려줍니다.
6476
6601
  * 토큰은 SDK 가 생성될 때 주소에서 지우므로 `location.search` 로 직접 읽을 수 없습니다.
6477
6602
  *
6603
+ * `signIn()` 은 서버에 1회용 `code` 만 달라고 요청하므로(`response_type=code`) 콜백 주소에는 보통 `?code=&state=` 가 옵니다.
6604
+ * 이 메서드가 state 를 확인한 뒤 `POST /v1/auth/oauth/exchange` 로 교환하고 토큰을 저장합니다(결과 모양은 같다).
6605
+ * state 가 맞지 않는 code 는 교환하지 않고 `{ error: 'oauth_state_mismatch' }` 를 돌려줍니다.
6606
+ *
6478
6607
  * @returns OAuth 결과 (토큰, member_id 등) 또는 null
6479
6608
  *
6480
6609
  * @example
@@ -6505,41 +6634,42 @@ declare class OAuthAPI {
6505
6634
  */
6506
6635
  private loadCallbackOnce;
6507
6636
  /**
6508
- * (SDK 내부용 — `ConnectBase` 생성자가 호출) 주소의 토큰 콜백을 회수해 지우고 그 종류를 알린다.
6637
+ * (SDK 내부용 — `ConnectBase` 생성자가 호출) 주소의 콜백을 회수해 지우고 그 종류를 알린다.
6638
+ *
6639
+ * 토큰 콜백은 state 와 opener 로 가른다. code 콜백은 이 브라우저에서 시작한 로그인(state 일치)일 때만 여기서
6640
+ * 회수한다 — 앱이 지정한 팝업 콜백 페이지의 code 와 앱 자체 OAuth 의 code 는 앱의 명시 호출에 맡긴다.
6509
6641
  *
6510
- * @returns `redirect` 면 부팅 안전망 대상, `popup` 이면 팝업 콜백, `none` 이면 토큰 콜백이 아니거나 거부됨.
6642
+ * @returns `redirect` 면 부팅 안전망 대상, `popup` 이면 팝업 콜백, `none` 이면 콜백이 아니거나 거부됨.
6511
6643
  */
6512
6644
  captureCallbackOnBoot(): "redirect" | "popup" | "none";
6513
6645
  /**
6514
6646
  * (SDK 내부용 — `ConnectBase` 생성자가 호출) 부팅 안전망.
6515
6647
  *
6516
6648
  * OAuth 리다이렉트 콜백 페이지에서 앱이 `getCallbackResult()` 를 호출하지 않아도,
6517
- * `new ConnectBase()` 만으로 URL 의 토큰(`?access_token=&refresh_token=&member_id=`)을
6518
- * 적재해 세션을 확립한다.
6649
+ * `new ConnectBase()` 만으로 이 브라우저에서 시작한 로그인의 결과(URL 의 토큰, 또는 state 가 맞는 1회용
6650
+ * `code` 의 교환 결과)를 적재해 세션을 확립한다.
6519
6651
  *
6520
6652
  * **왜 필요한가:** 정적 호스팅(웹 스토리지)은 SPA fallback 으로 `/auth/callback` 같은 콜백
6521
6653
  * 경로에 홈 `index.html` 을 서빙한다. 그 페이지가 콜백을 처리하지 않으면 URL 토큰이 영영
6522
6654
  * 소비되지 않아 "로그인 → 다시 로그인 페이지" 무한 루프가 발생한다 (여러 사용자 동시 보고).
6523
- * 이 안전망은 콜백 처리 코드를 빠뜨린 앱도 동작하게 한다.
6655
+ * 이 안전망은 콜백 처리 코드를 빠뜨린 앱도 동작하게 한다. `signIn()` 이 code 를 받으므로(`response_type=code`) code 도
6656
+ * 같은 이유로 여기서 교환한다.
6524
6657
  *
6525
6658
  * **token rotation race(2026-05-16) 가 없는 이유:** 사전 `re-issue`(cookie 복구) 없이 URL
6526
6659
  * 토큰을 *직접* 소비한다 — `getCallbackResult()` 의 리다이렉트 경로와 동일한 동작이다. 팝업 콜백과
6527
- * 거부된 콜백(`captureCallbackOnBoot()` 참고)은 생성자에서 제외되어 호출되지 않는다. code-only(`?code=`),
6528
- * 에러(`?error=`) 콜백도 생성자에서 제외된다 (네트워크 교환/에러 분기는 앱이 명시 호출).
6660
+ * 거부된 콜백(`captureCallbackOnBoot()` 참고)은 생성자에서 제외되어 호출되지 않는다. 에러(`?error=`) 콜백과
6661
+ * state 가 맞지 않는 code 도 생성자에서 제외된다 (에러 분기, 앱 자체 OAuth 는 앱이 명시 호출).
6529
6662
  *
6530
6663
  * @returns 토큰 적재 성공 시 true, no-op(토큰 없음 등)이면 false.
6531
6664
  */
6532
6665
  consumeRedirectCallbackOnBoot(): Promise<boolean>;
6533
6666
  private doConsumeRedirectOnBoot;
6534
6667
  /**
6535
- * 콜백 URL 에서 1회용 `code` 를 토큰으로 교환합니다 (`OAUTH_CODE_ONLY` 서버 모드용).
6536
- *
6537
- * 서버가 `OAUTH_CODE_ONLY=true` 모드면 리다이렉트 URL 에 토큰 대신 `code` 만 포함됩니다.
6538
- * 이 메서드는 code 를 `POST /v1/auth/oauth/exchange` 로 교환하고 토큰을 자동 저장합니다.
6668
+ * 콜백 URL 의 1회용 `code` 를 토큰으로 교환합니다.
6539
6669
  *
6540
- * 권장 호출 순서:
6541
- * 1) `cb.oauth.exchangeCodeFromCallback()` 먼저 — code-only 모드면 성공
6542
- * 2) null 반환 시 `cb.oauth.getCallbackResult()` 폴백 (legacy 토큰-in-URL 모드)
6670
+ * 이제 `getCallbackResult()` 와 부팅 안전망이 code 도 처리하므로 따로 부를 필요가 없습니다. 이미 이
6671
+ * 메서드를 부르는 앱(`exchangeCodeFromCallback() ?? getCallbackResult()`)은 그대로 동작하고, 같은 code 를 두 번
6672
+ * 교환하지 않습니다.
6543
6673
  *
6544
6674
  * `getCallbackResult()` 와 같은 이유로, 이 브라우저에서 시작한 로그인의 `code` 만 교환합니다. 확인되지
6545
6675
  * 않으면 `oauth_state_mismatch` 오류를 던지고 교환하지 않습니다.
@@ -6551,7 +6681,11 @@ declare class OAuthAPI {
6551
6681
  * ```
6552
6682
  */
6553
6683
  exchangeCodeFromCallback(): Promise<ExchangedCallbackResult | null>;
6554
- private exchangeCode;
6684
+ /**
6685
+ * 회수한 code 콜백을 마무리한다. code 는 한 번만 교환하고(한 페이지의 인스턴스가 여럿이어도), 리다이렉트면 이
6686
+ * 인스턴스에 토큰을 한 번만 적재하고 쿠키를 부트스트랩한다. 팝업이면 같은 출처 opener 에게 넘기고 창을 닫는다.
6687
+ */
6688
+ private completeCodeCallback;
6555
6689
  }
6556
6690
 
6557
6691
  /**
@@ -6854,7 +6988,17 @@ type PaymentProvider = "toss" | "stripe" | "payapp" | "paypal" | "paddle" | "dod
6854
6988
  */
6855
6989
  type PaymentMode = "test" | "live";
6856
6990
  type PaymentStatus = "pending" | "ready" | "in_progress" | "done" | "canceled" | "partial_canceled" | "aborted" | "expired" | "failed";
6857
- interface PreparePaymentRequest {
6991
+ /**
6992
+ * `prepare()` 의 두 형태에 공통인 옵션.
6993
+ *
6994
+ * 금액을 정하는 방법은 둘 중 하나다:
6995
+ * - {@link PreparePaymentWithProduct} — 가격표의 `product_id`(와 `quantity`)만 보낸다. 금액, 통화, 상품명은
6996
+ * **서버가 콘솔 가격표에서 정한다.** 브라우저에서 부르는 결제는 이 형태를 쓴다.
6997
+ * - {@link PreparePaymentWithAmount} — `amount` 와 `order_name` 을 직접 보낸다(레거시, KRW). 결제 설정의 금액
6998
+ * 출처가 `client` 인 앱이거나, 서버에서 시크릿 키(`cb_sk_`)나 service_role 함수로 부를 때만 받는다. 가격표
6999
+ * 전용 앱(`catalog`, 새 앱의 기본값)에서 브라우저가 금액을 보내면 403 `client_amount_not_allowed` 다.
7000
+ */
7001
+ interface PreparePaymentOptions {
6858
7002
  payment_provider?: PaymentProvider;
6859
7003
  /**
6860
7004
  * 사용할 자격증명 모드 오버라이드(선택).
@@ -6919,19 +7063,51 @@ interface PreparePaymentRequest {
6919
7063
  * (미지정 시 결제 설정의 fail_url).
6920
7064
  */
6921
7065
  fail_url?: string;
6922
- amount: number;
6923
- order_name: string;
6924
7066
  order_id?: string;
6925
7067
  customer_email?: string;
6926
7068
  customer_name?: string;
6927
7069
  customer_phone?: string;
7070
+ /**
7071
+ * 앱이 정하는 부가 데이터. **클라이언트가 보낸 값이라 권한 지급의 근거로 쓰지 않는다** — 무엇을 샀는지는 결제
7072
+ * 기록의 `product_id`/`quantity` 를 본다.
7073
+ */
6928
7074
  metadata?: Record<string, unknown>;
6929
7075
  }
7076
+ /** 가격표 결제 — 서버가 `단가 x 수량` 과 통화를 정한다. */
7077
+ interface PreparePaymentWithProduct extends PreparePaymentOptions {
7078
+ /** 콘솔 가격표의 상품 ID (예: `gem_100`). 없거나 판매를 멈춘 상품이면 404 / 409. */
7079
+ product_id: string;
7080
+ /** 수량 (1~1000, 기본 1). 결제 금액 = 단가 x 수량. */
7081
+ quantity?: number;
7082
+ /** 가격표 결제에는 보낼 수 없다(400 `product_with_amount_fields`). */
7083
+ amount?: never;
7084
+ /** 가격표 결제의 상품명은 가격표에서 정한다(400 `product_with_amount_fields`). */
7085
+ order_name?: never;
7086
+ }
7087
+ /**
7088
+ * 금액 직접 지정(레거시) — 금액은 KRW 원 단위, 최소 100.
7089
+ *
7090
+ * 브라우저 사용자가 금액을 고칠 수 있으므로, 금액 출처가 `client` 인 앱이거나 서버 호출(시크릿 키, service_role
7091
+ * 함수)에서만 쓴다.
7092
+ */
7093
+ interface PreparePaymentWithAmount extends PreparePaymentOptions {
7094
+ amount: number;
7095
+ order_name: string;
7096
+ product_id?: never;
7097
+ quantity?: never;
7098
+ }
7099
+ type PreparePaymentRequest = PreparePaymentWithProduct | PreparePaymentWithAmount;
6930
7100
  interface PreparePaymentResponse {
6931
7101
  payment_id: string;
6932
7102
  order_id: string;
7103
+ /** 서버가 정한 결제 금액(`currency` 의 최소 단위). 결제창에는 이 값을 그대로 넘긴다. */
6933
7104
  amount: number;
7105
+ /** `amount` 의 통화 (ISO 4217). 가격표 상품이면 상품의 통화다. */
7106
+ currency: string;
6934
7107
  order_name: string;
7108
+ /** 가격표 결제면 상품 ID 와 수량. */
7109
+ product_id?: string;
7110
+ quantity?: number;
6935
7111
  payment_provider: PaymentProvider;
6936
7112
  /** 이 결제가 사용한 자격증명 모드. */
6937
7113
  payment_mode: PaymentMode;
@@ -6951,15 +7127,12 @@ interface PreparePaymentResponse {
6951
7127
  checkout_url?: string;
6952
7128
  launch_mode?: "overlay" | "redirect";
6953
7129
  }
6954
- interface CreateCheckoutSessionRequest {
7130
+ interface CreateCheckoutSessionOptions {
6955
7131
  /**
6956
7132
  * 사용할 자격증명 모드 오버라이드(선택). `prepare()` 의 `payment_mode` 와 적용 조건이 같다 —
6957
7133
  * 서버 시크릿 키(`cb_sk_*`) 호출에서만 적용되고, 브라우저 공개 키 호출에서는 무시된다.
6958
7134
  */
6959
7135
  payment_mode?: PaymentMode;
6960
- amount: number;
6961
- currency: string;
6962
- product_name: string;
6963
7136
  success_url: string;
6964
7137
  cancel_url: string;
6965
7138
  order_id?: string;
@@ -6967,11 +7140,31 @@ interface CreateCheckoutSessionRequest {
6967
7140
  customer_name?: string;
6968
7141
  metadata?: Record<string, unknown>;
6969
7142
  }
7143
+ /** 가격표 결제 — 금액, 통화, 상품명은 서버가 가격표에서 정한다. */
7144
+ interface CreateCheckoutSessionWithProduct extends CreateCheckoutSessionOptions {
7145
+ product_id: string;
7146
+ /** 수량 (1~1000, 기본 1) */
7147
+ quantity?: number;
7148
+ amount?: never;
7149
+ currency?: never;
7150
+ product_name?: never;
7151
+ }
7152
+ /** 금액 직접 지정(레거시). 받는 조건은 `prepare()` 의 금액 형태와 같다. */
7153
+ interface CreateCheckoutSessionWithAmount extends CreateCheckoutSessionOptions {
7154
+ amount: number;
7155
+ currency: string;
7156
+ product_name: string;
7157
+ product_id?: never;
7158
+ quantity?: never;
7159
+ }
7160
+ type CreateCheckoutSessionRequest = CreateCheckoutSessionWithProduct | CreateCheckoutSessionWithAmount;
6970
7161
  interface CreateCheckoutSessionResponse {
6971
7162
  payment_id: string;
6972
7163
  order_id: string;
6973
7164
  amount: number;
6974
7165
  currency: string;
7166
+ product_id?: string;
7167
+ quantity?: number;
6975
7168
  session_id: string;
6976
7169
  session_url: string;
6977
7170
  }
@@ -6988,6 +7181,8 @@ interface ConfirmPaymentResponse {
6988
7181
  order_id: string;
6989
7182
  /** **실제 청구된** 금액. 할인이 적용되면 준비 금액보다 작다. */
6990
7183
  amount: number;
7184
+ /** `amount` 의 통화 (ISO 4217). 가격표 상품은 KRW 가 아닐 수 있다. */
7185
+ currency?: string;
6991
7186
  /** 할인으로 차감된 금액(준비 금액 − 실제 청구액). 할인이 없으면 생략된다. */
6992
7187
  discount_amount?: number;
6993
7188
  status: PaymentStatus;
@@ -7015,6 +7210,12 @@ interface PaymentDetail {
7015
7210
  amount: number;
7016
7211
  /** `amount` 의 통화 (ISO 4217) */
7017
7212
  currency: string;
7213
+ /**
7214
+ * 가격표로 준비한 결제의 상품 ID 와 수량. 서버가 정한 값이라 **권한 지급의 근거로 쓴다**
7215
+ * (`metadata` 는 클라이언트가 보낸 값이다). 금액을 직접 지정한 결제는 비어 있다.
7216
+ */
7217
+ product_id?: string;
7218
+ quantity?: number;
7018
7219
  /**
7019
7220
  * 정산통화 환산액 (MoR 프로바이더가 제공할 때만).
7020
7221
  *
@@ -7075,6 +7276,9 @@ interface PaymentListItem {
7075
7276
  amount: number;
7076
7277
  /** `amount` 의 통화 (ISO 4217). 다통화 결제에서 앱 기본 통화를 가정하면 거짓 금액이 된다 */
7077
7278
  currency: string;
7279
+ /** 가격표 결제의 상품 ID 와 수량 (금액을 직접 지정한 결제는 비어 있다). */
7280
+ product_id?: string;
7281
+ quantity?: number;
7078
7282
  status: PaymentStatus;
7079
7283
  method?: string;
7080
7284
  /** toss | stripe 등 */
@@ -7101,19 +7305,26 @@ declare class PaymentAPI {
7101
7305
  private getPublicPrefix;
7102
7306
  /**
7103
7307
  * 결제 준비
7104
- * 토스 결제 위젯에 필요한 정보를 반환합니다.
7308
+ * 결제창(토스 위젯, Stripe Elements, 호스티드 결제 페이지)에 필요한 정보를 반환합니다.
7309
+ *
7310
+ * **금액은 서버가 정합니다.** 브라우저에서는 콘솔 가격표의 `product_id`(와 `quantity`)만 보내고, 서버가
7311
+ * `단가 x 수량` 과 통화를 계산합니다. 사용자가 개발자 도구로 요청을 고쳐도 가격을 바꿀 수 없습니다.
7312
+ * `amount` 를 직접 보내는 형태(레거시)는 결제 설정의 금액 출처가 `client` 인 앱이거나, 서버에서
7313
+ * 시크릿 키(`cb_sk_`)나 service_role 함수로 부를 때만 받습니다.
7105
7314
  *
7106
- * @param data - 결제 준비 정보 (금액, 상품명, 고객 정보 등)
7107
- * @returns 토스 클라이언트 키, 고객 키, 성공/실패 URL 등
7315
+ * @param data - 가격표 상품(`product_id`, `quantity`) 또는 금액(`amount`, `order_name`), 고객 정보 등
7316
+ * @returns 서버가 정한 금액과 통화, 토스 클라이언트 키, 고객 키, 성공/실패 URL 등
7108
7317
  *
7109
7318
  * @example
7110
7319
  * ```typescript
7320
+ * // 가격표 결제 (권장) — 무엇을 몇 개 살지만 보낸다.
7111
7321
  * const result = await cb.payment.prepare({
7112
- * amount: 10000,
7113
- * order_name: '프리미엄 1개월',
7322
+ * product_id: 'gem_100',
7323
+ * quantity: 2,
7114
7324
  * customer_email: 'test@example.com',
7115
7325
  * customer_name: '홍길동'
7116
7326
  * })
7327
+ * // result.amount, result.currency 는 서버가 가격표로 계산한 값이다(단가 x 수량).
7117
7328
  *
7118
7329
  * // Toss V2 결제 플로우
7119
7330
  * if (result.payment_provider === 'toss') {
@@ -7121,7 +7332,7 @@ declare class PaymentAPI {
7121
7332
  * const payment = tossPayments.payment({ customerKey: result.customer_key })
7122
7333
  * await payment.requestPayment({
7123
7334
  * method: 'CARD',
7124
- * amount: { currency: 'KRW', value: result.amount },
7335
+ * amount: { currency: result.currency, value: result.amount },
7125
7336
  * orderId: result.order_id,
7126
7337
  * orderName: result.order_name,
7127
7338
  * successUrl: result.success_url,
@@ -7145,8 +7356,7 @@ declare class PaymentAPI {
7145
7356
  *
7146
7357
  * // 할인 코드 (MoR: dodo/paddle) — PG 대시보드에서 발행한 코드를 그대로 넘긴다.
7147
7358
  * const discounted = await cb.payment.prepare({
7148
- * amount: 10000,
7149
- * order_name: '프리미엄 1개월',
7359
+ * product_id: 'premium_month',
7150
7360
  * discount_code: 'LAUNCH50', // 미리 적용
7151
7361
  * allow_discount_code: true, // 결제창에서 고객이 직접 입력하는 것도 허용 (Dodo)
7152
7362
  * })
@@ -7155,14 +7365,26 @@ declare class PaymentAPI {
7155
7365
  *
7156
7366
  * // 복귀 주소 — 배포마다 자기 호스트로 돌아오게 한다 (QA 가 라이브로 튕기지 않도록)
7157
7367
  * const withReturn = await cb.payment.prepare({
7158
- * amount: 14900,
7159
- * order_name: '프리미엄 1개월',
7368
+ * product_id: 'premium_month',
7160
7369
  * return_url: `${window.location.origin}/app/premium?paid=1`,
7161
7370
  * fail_url: `${window.location.origin}/app/premium?failed=1`,
7162
7371
  * })
7372
+ *
7373
+ * // 금액 직접 지정 (레거시) — 금액 출처가 client 인 앱, 또는 서버(시크릿 키, service_role 함수) 호출에서만 받는다.
7374
+ * // 가격표 전용 앱에서 브라우저가 보내면 403 client_amount_not_allowed.
7375
+ * const legacy = await cb.payment.prepare({
7376
+ * amount: 10000,
7377
+ * order_name: '프리미엄 1개월',
7378
+ * })
7163
7379
  * ```
7164
7380
  *
7165
7381
  * @remarks
7382
+ * 권한(아이템, 기간권)은 결제가 끝난 뒤 결제 기록의 `product_id`/`quantity` 로 지급합니다. `metadata` 는
7383
+ * 클라이언트가 보낸 값이라 근거로 쓰지 않습니다. 가격표 오류는 사유별 코드로 옵니다: 없는 상품 404
7384
+ * `payment_product_not_found`, 판매 중지 409 `payment_product_inactive`, `product_id` 와 `amount`/`order_name`
7385
+ * 을 섞음 400 `product_with_amount_fields`, 프로바이더가 받지 못하는 통화 400 `currency_not_supported`
7386
+ * (toss, payapp 은 KRW 상품만).
7387
+ *
7166
7388
  * PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
7167
7389
  *
7168
7390
  * 할인 코드는 MoR 프로바이더(dodo/paddle)에서만 지원됩니다. 그 외 프로바이더에 넘기면
@@ -7181,15 +7403,16 @@ declare class PaymentAPI {
7181
7403
  * 응답에 `session_url` 이 포함되며, 브라우저를 해당 URL 로 이동시키면 Stripe 가 카드 입력·결제를 처리한 뒤
7182
7404
  * `success_url` / `cancel_url` 로 복귀한다. `client_secret` 은 서버·클라이언트 어디에도 노출되지 않는다.
7183
7405
  *
7184
- * @param data - 결제 세션 정보 (금액, 통화, 상품명, success/cancel URL 등)
7406
+ * 금액을 정하는 규칙은 `prepare()` 와 같다 — 브라우저에서는 가격표의 `product_id` 를 보내고, 금액, 통화,
7407
+ * 상품명을 직접 보내는 형태는 금액 출처가 `client` 인 앱이나 서버 호출에서만 받는다.
7408
+ *
7409
+ * @param data - 가격표 상품(`product_id`, `quantity`) 또는 금액(`amount`, `currency`, `product_name`), success/cancel URL 등
7185
7410
  * @returns session_id, session_url (redirect 대상)
7186
7411
  *
7187
7412
  * @example
7188
7413
  * ```typescript
7189
7414
  * const sess = await client.payment.createCheckoutSession({
7190
- * amount: 1000,
7191
- * currency: 'USD',
7192
- * product_name: 'Premium Subscription',
7415
+ * product_id: 'premium_month',
7193
7416
  * success_url: 'https://app.example.com/success?session_id={CHECKOUT_SESSION_ID}',
7194
7417
  * cancel_url: 'https://app.example.com/cancel',
7195
7418
  * customer_email: 'user@example.com',
@@ -8181,7 +8404,13 @@ interface RealtimeConnectOptions {
8181
8404
  retryInterval?: number;
8182
8405
  /** 사용자 ID (인증된 사용자) */
8183
8406
  userId?: string;
8184
- /** JWT 액세스 토큰 (앱 멤버 인증용, API Key보다 우선) */
8407
+ /**
8408
+ * JWT 액세스 토큰 (앱 멤버 인증용, API Key보다 우선).
8409
+ *
8410
+ * 이 토큰이 SDK 가 로그인으로 들고 있는 멤버 세션(같은 앱, 같은 멤버)의 것이면, 연결은 만료 전에 SDK 세션으로 새 토큰을
8411
+ * 받아 연결 위에서 바꾼다(`auth_refresh`) — 한 시간마다 끊기지 않는다. 재연결도 새 토큰을 쓴다. 다른 곳에서 받은 토큰이면
8412
+ * 갱신하지 않고 예전처럼 동작한다(서버가 만료 뒤 24시간에 닫는다).
8413
+ */
8185
8414
  accessToken?: string;
8186
8415
  /** 연결 타임아웃 (밀리초, 기본: 30000) */
8187
8416
  timeout?: number;
@@ -8245,14 +8474,14 @@ interface Subscription {
8245
8474
  /** 클라이언트 -> 서버 메시지 */
8246
8475
  interface ClientMessage {
8247
8476
  category: string;
8248
- action: "subscribe" | "unsubscribe" | "send" | "invoke" | "ping" | "history" | "stream" | "stream_stop" | "mark_read" | "presence_set" | "presence_on_disconnect" | "presence_get" | "presence_get_many" | "presence_subscribe" | "presence_unsubscribe" | "typing_start" | "typing_stop" | "typing_subscribe" | "typing_unsubscribe";
8477
+ action: "subscribe" | "unsubscribe" | "send" | "invoke" | "ping" | "history" | "stream" | "stream_stop" | "mark_read" | "presence_set" | "presence_on_disconnect" | "presence_get" | "presence_get_many" | "presence_subscribe" | "presence_unsubscribe" | "typing_start" | "typing_stop" | "typing_subscribe" | "typing_unsubscribe" | "auth_refresh";
8249
8478
  data?: unknown;
8250
8479
  request_id: string;
8251
8480
  }
8252
8481
  /** 서버 -> 클라이언트 메시지 */
8253
8482
  interface ServerMessage<T = unknown> {
8254
8483
  category?: string;
8255
- event: "connected" | "subscribed" | "unsubscribed" | "message" | "sent" | "result" | "error" | "pong" | "history" | "stream_token" | "stream_done" | "stream_error" | "stream_tool_call" | "stream_tool_result" | "read_receipt" | "presence" | "presence_status" | "typing";
8484
+ event: "connected" | "subscribed" | "unsubscribed" | "message" | "sent" | "result" | "error" | "pong" | "history" | "stream_token" | "stream_done" | "stream_error" | "stream_tool_call" | "stream_tool_result" | "read_receipt" | "presence" | "presence_status" | "typing" | "token_expiring" | "token_expired" | "token_refreshed";
8256
8485
  data?: T;
8257
8486
  request_id?: string;
8258
8487
  error?: string;
@@ -8354,6 +8583,8 @@ interface ConnectedData {
8354
8583
  app_id: string;
8355
8584
  client_id: string;
8356
8585
  user_id?: string;
8586
+ /** 멤버 토큰의 만료 시각(Unix 초). accessToken 연결에만 있다. */
8587
+ token_expires_at?: number;
8357
8588
  }
8358
8589
  /** 구독 성공 데이터 */
8359
8590
  interface SubscribedData {
@@ -8469,6 +8700,17 @@ declare class RealtimeAPI {
8469
8700
  private readReceiptHandlers;
8470
8701
  constructor(http: HttpClient, socketUrl: string);
8471
8702
  private connectPromise;
8703
+ /**
8704
+ * 이 연결이 `token_refresh=1` 로 협상했는지 — 연결 토큰이 SDK 세션(HttpClient)의 멤버 토큰이라 연결 위에서 갱신할 수
8705
+ * 있을 때만 협상한다. 협상한 연결에만 서버가 만료 안내를 보내고, 협상하지 않은 연결은 예전처럼 만료 뒤 24시간에 닫힌다.
8706
+ */
8707
+ private tokenRefreshNegotiated;
8708
+ /** 진행 중인 auth_refresh — 같은 순간에 두 번 보내지 않는다. */
8709
+ private authRefreshInFlight;
8710
+ /** 갱신이 실패했을 때 다시 해 보는 타이머. */
8711
+ private authRefreshRetryTimer;
8712
+ /** 서버가 닫기 직전에 보낸 안내(TOKEN_EXPIRED, MEMBER_REVOKED) 문구 — 이어지는 4401/4403 close 오류의 메시지가 된다. */
8713
+ private closeNotice;
8472
8714
  /**
8473
8715
  * WebSocket 연결
8474
8716
  * @param options 연결 옵션
@@ -8786,6 +9028,20 @@ declare class RealtimeAPI {
8786
9028
  */
8787
9029
  private connectWithRetry;
8788
9030
  private doConnect;
9031
+ /**
9032
+ * 연결(재연결)에 쓸 토큰을 준비한다 — SDK 세션의 멤버 토큰인데 곧(1분 안) 만료되면 붙기 전에 새로 받는다. 만료된 토큰으로
9033
+ * 붙으면 서버가 거부해 재연결이 멈춘다. 앱이 다른 곳에서 받은 토큰은 건드리지 않는다(예전과 같다).
9034
+ */
9035
+ private prepareConnectToken;
9036
+ /**
9037
+ * 연결을 끊지 않고 멤버 토큰을 바꾼다(`auth_refresh`). 새 토큰은 HTTP 요청과 같은 refresh 로 받는다
9038
+ * (`HttpClient.freshTokenForMember` — 같은 single-flight, 같은 실패 처리). 한 번에 하나만 보내고, 성공하면 재연결도 새
9039
+ * 토큰을 쓴다. 실패하면(세션 일시 장애) 30초 뒤 다시 해 본다 — 서버는 만료 뒤 유예(기본 5분)가 지나야 4401 로 닫는다.
9040
+ * SDK 세션 자체가 끝났으면(로그아웃, refresh 거부) 더 시도하지 않는다.
9041
+ */
9042
+ private refreshConnectionAuth;
9043
+ private scheduleAuthRefreshRetry;
9044
+ private clearAuthRefreshRetry;
8789
9045
  private log;
8790
9046
  /**
8791
9047
  * 에러 로그. `options.debug` 가 true 일 때만 console 에 출력.
@@ -9526,7 +9782,17 @@ interface DeleteBillingKeyResponse {
9526
9782
  }
9527
9783
  type BillingCycle = "daily" | "weekly" | "monthly" | "yearly";
9528
9784
  type SubscriptionStatus = "active" | "paused" | "canceled" | "past_due" | "expired" | "trial";
9529
- interface CreateSubscriptionRequest {
9785
+ /**
9786
+ * `create()` 의 두 형태에 공통인 옵션.
9787
+ *
9788
+ * 무엇을 얼마에 청구할지는 둘 중 하나로 정한다:
9789
+ * - {@link CreateSubscriptionWithProduct} — 콘솔 가격표의 정기 상품 `product_id` 만 보낸다. 금액, 통화, 주기,
9790
+ * 플랜명, 무료 체험, MoR PG 가격 ref 는 **서버가 상품에서 정한다.** 브라우저에서 부르는 구독은 이 형태를 쓴다.
9791
+ * - {@link CreateSubscriptionWithAmount} — 금액과 요금제를 직접 보낸다(레거시). 결제 설정의 금액 출처가 `client`
9792
+ * 인 앱이거나 서버(시크릿 키, service_role 함수)에서 부를 때만 받는다. 가격표 전용 앱(`catalog`, 새 앱의 기본값)에서
9793
+ * 브라우저가 보내면 403 `client_amount_not_allowed` 다.
9794
+ */
9795
+ interface CreateSubscriptionOptions {
9530
9796
  /** 빌링키 ID (toss/stripe 필수, payapp 미사용 — payurl 모델) */
9531
9797
  billing_key_id?: string;
9532
9798
  /**
@@ -9537,34 +9803,19 @@ interface CreateSubscriptionRequest {
9537
9803
  */
9538
9804
  subscription_id?: string;
9539
9805
  /**
9540
- * true 면 구독 생성 즉시 1회차를 청구한다(빌링키 모델). false(기본)면 다음 결제일부터 청구.
9541
- * `trial_days` 가 있으면 즉시 청구하지 않는다(체험 종료 후 첫 청구).
9806
+ * true 면 구독 생성 즉시 1회차를 청구한다(빌링키 모델). 생략하면 가격표 구독은 즉시, 금액 직접 지정은 다음
9807
+ * 결제일부터 청구한다. 체험 기간이 있으면 즉시 청구하지 않는다(체험 종료 후 첫 청구).
9808
+ *
9809
+ * 가격표 전용 앱의 브라우저 호출은 `false` 를 보낼 수 없다(403 `client_schedule_not_allowed`) — 한 주기를 내지 않고
9810
+ * 쓰게 된다. 무료 체험은 가격표 상품의 `trial_days` 로 정한다.
9542
9811
  *
9543
9812
  * MoR(paddle/dodo)은 결제창에서 1회차를 받으므로 이 값을 쓰지 않는다.
9544
9813
  */
9545
9814
  start_now?: boolean;
9546
- /** 플랜 이름 */
9547
- plan_name: string;
9548
- /** 플랜 설명 */
9549
- plan_description?: string;
9550
- /** 결제 금액 */
9551
- amount: number;
9552
- /** 통화 (기본: KRW) */
9553
- currency?: string;
9554
- /** 결제 주기 */
9555
- billing_cycle: BillingCycle;
9556
- /** 결제일 (monthly: 1-28일, weekly: 0-6 요일) */
9557
- billing_day?: number;
9558
9815
  /**
9559
- * 트라이얼(무료 체험) 기간 (일).
9560
- *
9561
- * 빌링키 모델(toss/stripe)에서는 ConnectBase 스케줄러가 체험 종료일에 첫 청구를 건다.
9562
- * MoR 은 PG 가 정기청구를 소유하므로 결제창 생성 시 체험 일수를 함께 보낸다:
9563
- * - **Dodo**: 구독마다 지정 가능(0~10000일)
9564
- * - **Paddle**: 트라이얼이 요금제(price)에 붙는 속성이라 구독마다 지정할 수 없다 →
9565
- * 400 `trial_days_unsupported`. 체험이 설정된 price 를 Paddle 대시보드에서 따로 만들어 쓴다.
9816
+ * 결제일 (monthly: 1-28일, weekly: 0-6 요일). 가격표 전용 앱의 브라우저 호출은 지정할 수 없다(첫 주기가 길어진다).
9566
9817
  */
9567
- trial_days?: number;
9818
+ billing_day?: number;
9568
9819
  /**
9569
9820
  * 첫 결제에 적용할 할인/쿠폰 코드(MoR 전용, 선택).
9570
9821
  *
@@ -9596,8 +9847,6 @@ interface CreateSubscriptionRequest {
9596
9847
  customer_phone?: string;
9597
9848
  /** payapp 정기결제 만료일 yyyy-mm-dd (미입력시 +10년) */
9598
9849
  expire_date?: string;
9599
- /** MoR 필수: PG 카탈로그의 recurring price/product ref (Paddle `pri_*` / Dodo `pdt_*`) */
9600
- provider_price_ref?: string;
9601
9850
  /**
9602
9851
  * 사용할 자격증명 모드 오버라이드 (test|live). 단건결제 `prepare()` 의 `payment_mode` 와
9603
9852
  * 적용 조건이 **완전히 동일**하다 — 서버 시크릿 키(`cb_sk_*`)로 승격된 호출에서만 적용되고,
@@ -9609,9 +9858,48 @@ interface CreateSubscriptionRequest {
9609
9858
  * 구독은 생성 시점 모드가 고정되므로 이후 갱신 청구·해지도 같은 키로 처리된다.
9610
9859
  */
9611
9860
  payment_mode?: "test" | "live";
9612
- /** 메타데이터 */
9861
+ /** 메타데이터 (클라이언트 값이라 권한 지급의 근거로 쓰지 않는다 — 구독의 `product_id` 를 본다) */
9613
9862
  metadata?: Record<string, unknown>;
9614
9863
  }
9864
+ /** 가격표 정기 상품으로 구독한다 — 금액, 통화, 주기, 플랜명, 체험 기간, PG 가격 ref 를 서버가 정한다. */
9865
+ interface CreateSubscriptionWithProduct extends CreateSubscriptionOptions {
9866
+ /** 콘솔 가격표의 정기 상품 ID (예: `premium_month`). 단건 상품이면 400 `product_not_recurring`. */
9867
+ product_id: string;
9868
+ plan_name?: never;
9869
+ plan_description?: never;
9870
+ amount?: never;
9871
+ currency?: never;
9872
+ billing_cycle?: never;
9873
+ trial_days?: never;
9874
+ provider_price_ref?: never;
9875
+ }
9876
+ /** 금액과 요금제를 직접 정한다(레거시 앱, 서버 호출). */
9877
+ interface CreateSubscriptionWithAmount extends CreateSubscriptionOptions {
9878
+ /** 플랜 이름 */
9879
+ plan_name: string;
9880
+ /** 플랜 설명 */
9881
+ plan_description?: string;
9882
+ /** 결제 금액 */
9883
+ amount: number;
9884
+ /** 통화 (기본: KRW) */
9885
+ currency?: string;
9886
+ /** 결제 주기 */
9887
+ billing_cycle: BillingCycle;
9888
+ /**
9889
+ * 트라이얼(무료 체험) 기간 (일).
9890
+ *
9891
+ * 빌링키 모델(toss/stripe)에서는 ConnectBase 스케줄러가 체험 종료일에 첫 청구를 건다.
9892
+ * MoR 은 PG 가 정기청구를 소유하므로 결제창 생성 시 체험 일수를 함께 보낸다:
9893
+ * - **Dodo**: 구독마다 지정 가능(0~10000일)
9894
+ * - **Paddle**: 트라이얼이 요금제(price)에 붙는 속성이라 구독마다 지정할 수 없다 →
9895
+ * 400 `trial_days_unsupported`. 체험이 설정된 price 를 Paddle 대시보드에서 따로 만들어 쓴다.
9896
+ */
9897
+ trial_days?: number;
9898
+ /** MoR 필수: PG 카탈로그의 recurring price/product ref (Paddle `pri_*` / Dodo `pdt_*`) */
9899
+ provider_price_ref?: string;
9900
+ product_id?: never;
9901
+ }
9902
+ type CreateSubscriptionRequest = CreateSubscriptionWithProduct | CreateSubscriptionWithAmount;
9615
9903
  interface SubscriptionResponse {
9616
9904
  /** 구독 ID (UUID) */
9617
9905
  id: string;
@@ -9634,6 +9922,11 @@ interface SubscriptionResponse {
9634
9922
  launch_mode?: "overlay" | "redirect";
9635
9923
  /** paddle: 현재 구독이 물린 recurring price ID (pri_*) */
9636
9924
  provider_price_ref?: string;
9925
+ /**
9926
+ * 가격표 정기 상품으로 만든 구독이면 그 상품 ID. 서버가 정한 값이라 **권한 지급의 근거로 쓴다**. 금액을 직접
9927
+ * 바꾸거나 PG 가 가격표에 없는 가격으로 바꾸면 비워진다.
9928
+ */
9929
+ product_id?: string;
9637
9930
  /** 플랜 이름 */
9638
9931
  plan_name: string;
9639
9932
  /** 플랜 설명 */
@@ -9701,11 +9994,20 @@ interface SubscriptionResponse {
9701
9994
  interface UpdateSubscriptionRequest {
9702
9995
  /** 새 빌링키 ID */
9703
9996
  billing_key_id?: string;
9704
- /** 플랜 이름 */
9997
+ /**
9998
+ * 다른 가격표 정기 상품으로 바꾼다(빌링키 구독만, 다음 청구부터 새 금액). 금액, 통화, 주기, 플랜명을 상품에서 정한다.
9999
+ * 정산이 없어 가격표 전용 앱에서는 서버 호출만 쓸 수 있다(브라우저는 403 `client_plan_change_not_allowed`).
10000
+ * MoR 구독은 {@link SubscriptionAPI.changePlan} 을 쓴다. 빈 문자열이면 가격표 연결만 끊는다.
10001
+ */
10002
+ product_id?: string;
10003
+ /** 플랜 이름 (가격표 전용 앱에서는 서버 호출만) */
9705
10004
  plan_name?: string;
9706
10005
  /** 플랜 설명 */
9707
10006
  plan_description?: string;
9708
- /** 결제 금액 */
10007
+ /**
10008
+ * 결제 금액 (빌링키 구독만, 가격표 전용 앱에서는 서버 호출만). 바꾸면 `product_id` 가 비워진다.
10009
+ * PG 가 청구 금액을 정하는 구독(payapp, paypal, MoR)은 400 `subscription_amount_update_unsupported`.
10010
+ */
9709
10011
  amount?: number;
9710
10012
  /** 메타데이터 */
9711
10013
  metadata?: Record<string, unknown>;
@@ -9790,8 +10092,30 @@ type OnPaymentFailure = "prevent_change" | "apply_change";
9790
10092
  * toss/stripe/payapp/paypal 구독은 PG 네이티브 proration 이 없어 400
9791
10093
  * `plan_change_unsupported` 다.
9792
10094
  */
9793
- interface ChangePlanRequest {
9794
- /** 새 recurring price/product ref (Paddle `pri_*` / Dodo `pdt_*`) — 필수 */
10095
+ interface ChangePlanOptions {
10096
+ /**
10097
+ * 정산 방식 (기본: prorated_immediately). 가격표 전용 앱의 브라우저 호출은 지금 정산하는 모드
10098
+ * (`prorated_immediately`, `full_immediately`, `difference_immediately`)만 쓸 수 있다
10099
+ * (403 `proration_mode_not_allowed`) — 다음 주기로 미루면 돈을 내기 전에 비싼 요금제를 쓴다.
10100
+ */
10101
+ proration_mode?: ProrationMode;
10102
+ /** 즉시청구 실패 시 처리 (기본: prevent_change). 가격표 전용 앱의 브라우저 호출은 `prevent_change` 만. */
10103
+ on_payment_failure?: OnPaymentFailure;
10104
+ /** 메타데이터 병합 (선택) */
10105
+ metadata?: Record<string, unknown>;
10106
+ }
10107
+ /** 가격표 정기 상품으로 바꾼다 — 새 PG 가격 ref 와 플랜명을 서버가 상품에서 정한다. */
10108
+ interface ChangePlanWithProduct extends ChangePlanOptions {
10109
+ /** 콘솔 가격표의 정기 상품 ID. 상품에 이 구독의 프로바이더와 모드용 PG 가격 ref 가 있어야 한다. */
10110
+ product_id: string;
10111
+ provider_price_ref?: never;
10112
+ plan_name?: never;
10113
+ plan_description?: never;
10114
+ amount?: never;
10115
+ }
10116
+ /** PG 가격 ref 를 직접 지정한다(레거시 앱, 서버 호출). */
10117
+ interface ChangePlanWithPriceRef extends ChangePlanOptions {
10118
+ /** 새 recurring price/product ref (Paddle `pri_*` / Dodo `pdt_*`) */
9795
10119
  provider_price_ref: string;
9796
10120
  /** 우리 표시용 플랜명 (선택) */
9797
10121
  plan_name?: string;
@@ -9799,13 +10123,9 @@ interface ChangePlanRequest {
9799
10123
  plan_description?: string;
9800
10124
  /** 우리 기록용 정기 금액 (선택 — 미지정 시 PG 값으로 자동 수렴) */
9801
10125
  amount?: number;
9802
- /** 정산 방식 (기본: prorated_immediately) */
9803
- proration_mode?: ProrationMode;
9804
- /** 즉시청구 실패 시 처리 (기본: prevent_change) */
9805
- on_payment_failure?: OnPaymentFailure;
9806
- /** 메타데이터 병합 (선택) */
9807
- metadata?: Record<string, unknown>;
10126
+ product_id?: never;
9808
10127
  }
10128
+ type ChangePlanRequest = ChangePlanWithProduct | ChangePlanWithPriceRef;
9809
10129
  /**
9810
10130
  * 요금제 스왑 미리보기 응답 — 실제 적용 없이 정산 결과만 계산.
9811
10131
  *
@@ -9911,14 +10231,12 @@ interface ListSubscriptionPaymentsResponse {
9911
10231
  limit: number;
9912
10232
  offset: number;
9913
10233
  }
9914
- interface ChargeWithBillingKeyRequest {
10234
+ interface ChargeWithBillingKeyOptions {
9915
10235
  /** 빌링키 ID */
9916
10236
  billing_key_id: string;
9917
- /** 결제 금액 */
9918
- amount: number;
9919
- /** 상품명 */
9920
- order_name: string;
9921
- /** 주문 ID (선택) */
10237
+ /**
10238
+ * 주문 ID (선택). 재시도는 같은 내용이어야 한다 — 같은 주문 ID 로 다른 금액이나 상품을 보내면 409 `order_id_conflict`.
10239
+ */
9922
10240
  order_id?: string;
9923
10241
  /** 고객 이메일 */
9924
10242
  customer_email?: string;
@@ -9927,6 +10245,24 @@ interface ChargeWithBillingKeyRequest {
9927
10245
  /** 메타데이터 */
9928
10246
  metadata?: Record<string, unknown>;
9929
10247
  }
10248
+ /** 가격표 단건 상품으로 청구한다 — 금액과 상품명을 서버가 정한다. */
10249
+ interface ChargeWithBillingKeyProduct extends ChargeWithBillingKeyOptions {
10250
+ product_id: string;
10251
+ /** 수량 (1~1000, 기본 1) */
10252
+ quantity?: number;
10253
+ amount?: never;
10254
+ order_name?: never;
10255
+ }
10256
+ /** 금액을 직접 정한다(레거시 앱, 서버 호출). KRW. */
10257
+ interface ChargeWithBillingKeyAmount extends ChargeWithBillingKeyOptions {
10258
+ /** 결제 금액 */
10259
+ amount: number;
10260
+ /** 상품명 */
10261
+ order_name: string;
10262
+ product_id?: never;
10263
+ quantity?: never;
10264
+ }
10265
+ type ChargeWithBillingKeyRequest = ChargeWithBillingKeyProduct | ChargeWithBillingKeyAmount;
9930
10266
  interface ChargeWithBillingKeyResponse {
9931
10267
  /** 토스 결제 키 */
9932
10268
  payment_key: string;
@@ -9934,6 +10270,11 @@ interface ChargeWithBillingKeyResponse {
9934
10270
  order_id: string;
9935
10271
  /** 결제 금액 */
9936
10272
  amount: number;
10273
+ /** `amount` 의 통화 (ISO 4217) */
10274
+ currency?: string;
10275
+ /** 가격표 결제면 상품 ID 와 수량 */
10276
+ product_id?: string;
10277
+ quantity?: number;
9937
10278
  /** 결제 상태 */
9938
10279
  status: string;
9939
10280
  /** 영수증 URL */
@@ -10060,32 +10401,41 @@ declare class SubscriptionAPI {
10060
10401
  * 구독 생성
10061
10402
  * 정기결제 구독을 생성합니다.
10062
10403
  *
10063
- * @param data - 구독 정보
10064
- * @returns 생성된 구독 정보
10404
+ * **금액과 요금제는 서버가 정합니다.** 브라우저에서는 콘솔 가격표의 정기 상품 `product_id` 만 보내고, 서버가
10405
+ * 금액, 통화, 주기, 플랜명, 무료 체험, MoR PG 가격 ref 를 상품에서 정합니다. 금액을 직접 보내는 형태(레거시)는
10406
+ * 결제 설정의 금액 출처가 `client` 인 앱이거나 서버(시크릿 키, service_role 함수)에서 부를 때만 받습니다.
10407
+ *
10408
+ * @param data - 가격표 정기 상품(`product_id`) 또는 금액과 요금제, 빌링키, 고객 정보 등
10409
+ * @returns 생성된 구독 정보 (`product_id` 포함)
10065
10410
  *
10066
10411
  * @example
10067
10412
  * ```typescript
10413
+ * // 가격표 구독 (권장) — 금액, 주기, 체험 기간은 콘솔 가격표의 premium_month 가 정한다
10068
10414
  * const subscription = await client.subscription.create({
10069
10415
  * billing_key_id: 'bk_xxxxx',
10070
- * plan_name: '프리미엄 플랜',
10071
- * amount: 9900,
10072
- * billing_cycle: 'monthly',
10073
- * billing_day: 15, // 매월 15일 결제
10074
- * trial_days: 7 // 7일 무료 체험
10416
+ * product_id: 'premium_month',
10075
10417
  * })
10076
10418
  *
10077
- * // MoR(dodo/paddle) 구독 + 할인 코드
10419
+ * // MoR(dodo/paddle) 구독 + 할인 코드 — PG 가격 ref 도 상품의 provider_price_refs 에서 서버가 고른다
10078
10420
  * const promo = await client.subscription.create({
10421
+ * product_id: 'premium_month',
10422
+ * discount_code: 'LAUNCH50', // 첫 결제에 적용 (몇 주기까지인지는 PG 쿠폰 설정이 결정)
10423
+ * })
10424
+ *
10425
+ * // 금액 직접 지정 (레거시 앱, 서버 호출) — 가격표 전용 앱에서 브라우저가 보내면 403 client_amount_not_allowed
10426
+ * const legacy = await client.subscription.create({
10427
+ * billing_key_id: 'bk_xxxxx',
10079
10428
  * plan_name: '프리미엄 플랜',
10080
10429
  * amount: 9900,
10081
10430
  * billing_cycle: 'monthly',
10082
- * provider_price_ref: 'pdt_xxxxx', // PG 카탈로그의 recurring 상품
10083
- * discount_code: 'LAUNCH50', // 첫 결제에 적용 (몇 주기까지인지는 PG 쿠폰 설정이 결정)
10084
- * trial_days: 14, // Dodo 만 지원 — Paddle 은 400 trial_days_unsupported
10085
10431
  * })
10086
10432
  * ```
10087
10433
  *
10088
10434
  * @remarks
10435
+ * 권한은 구독의 `product_id` 로 지급합니다(`metadata` 는 클라이언트 값). 가격표 전용 앱의 브라우저 호출은
10436
+ * `start_now: false` 와 `billing_day` 를 쓸 수 없습니다(403 `client_schedule_not_allowed`) — 둘 다 한 번 낸 돈으로 쓰는
10437
+ * 기간을 늘립니다. 무료 체험은 상품의 `trial_days` 가 정합니다.
10438
+ *
10089
10439
  * 할인 코드(`discount_code`)와 `trial_days` 의 프로바이더 지원 범위가 다릅니다:
10090
10440
  * - **Dodo**: 할인 코드 O, 결제창 쿠폰 입력 토글 O, 구독별 체험 일수 O
10091
10441
  * - **Paddle**: 할인 코드 O(코드→내부 ID 자동 해소), 쿠폰 입력칸은 항상 노출(숨김 불가),
@@ -10127,9 +10477,9 @@ declare class SubscriptionAPI {
10127
10477
  *
10128
10478
  * @example
10129
10479
  * ```typescript
10480
+ * // 서버(시크릿 키, service_role 함수)에서 다른 가격표 상품으로 바꾸기 — 다음 청구부터 새 금액
10130
10481
  * await client.subscription.update(subscriptionId, {
10131
- * plan_name: '엔터프라이즈 플랜',
10132
- * amount: 29900
10482
+ * product_id: 'enterprise_month',
10133
10483
  * })
10134
10484
  *
10135
10485
  * // 다음 결제일을 특정 날짜로 옮기기 (기간권·보상)
@@ -10281,11 +10631,10 @@ declare class SubscriptionAPI {
10281
10631
  *
10282
10632
  * @example
10283
10633
  * ```typescript
10634
+ * // 가격표 정기 상품으로 바꾼다 — 새 PG 가격 ref 와 플랜명은 서버가 상품에서 정한다
10284
10635
  * await client.subscription.changePlan(subscriptionId, {
10285
- * provider_price_ref: 'pri_family_monthly', // Dodo 는 'pdt_*'
10286
- * plan_name: '가족 플랜',
10287
- * amount: 24900,
10288
- * proration_mode: 'prorated_immediately',
10636
+ * product_id: 'family_month',
10637
+ * proration_mode: 'prorated_immediately', // 브라우저는 지금 정산하는 모드만
10289
10638
  * })
10290
10639
  * ```
10291
10640
  */
@@ -10312,7 +10661,7 @@ declare class SubscriptionAPI {
10312
10661
  * @example
10313
10662
  * ```typescript
10314
10663
  * const preview = await client.subscription.previewChangePlan(subscriptionId, {
10315
- * provider_price_ref: 'pri_family_monthly',
10664
+ * product_id: 'family_month',
10316
10665
  * })
10317
10666
  * // 통화를 함께 포맷한다 — 금액만 쓰면 다통화에서 거짓 금액이 된다
10318
10667
  * format(preview.immediate_charge_amount, preview.currency)
@@ -10344,10 +10693,11 @@ declare class SubscriptionAPI {
10344
10693
  *
10345
10694
  * @example
10346
10695
  * ```typescript
10696
+ * // 가격표 단건 상품으로 청구 — 금액과 상품명은 서버가 정한다
10347
10697
  * const result = await client.subscription.chargeWithBillingKey({
10348
10698
  * billing_key_id: 'bk_xxxxx',
10349
- * amount: 15000,
10350
- * order_name: '추가 결제'
10699
+ * product_id: 'gem_100',
10700
+ * quantity: 2,
10351
10701
  * })
10352
10702
  *
10353
10703
  * if (result.status === 'done') {
@@ -11375,6 +11725,19 @@ interface WebRTCConnectOptions {
11375
11725
  isBroadcaster?: boolean;
11376
11726
  /** 로컬 미디어 스트림 */
11377
11727
  localStream?: MediaStream;
11728
+ /**
11729
+ * 비공개 룸으로 열 때 함께 들어올 회원 ID 목록 (최대 50개, 로그인 회원 연결만).
11730
+ *
11731
+ * 이 연결이 룸을 새로 열면 목록의 회원과 자신만 들어오는 비공개 룸이 된다. 이미 열린 룸이면 그 룸이
11732
+ * 비공개이고 내가 목록에 있어야 들어간다(공개 룸이면 `이미 공개 룸으로 열려 있습니다` 오류).
11733
+ * 참가자 모두가 같은 목록을 보내면 누가 먼저 오든 비공개로 열린다. 룸 ID 는 추측할 수 없는 값을 쓴다.
11734
+ */
11735
+ allowedMemberIds?: string[];
11736
+ }
11737
+ /** 서버가 join 요청을 바꿨을 때의 알림 (예: `broadcaster_requires_auth`, `broadcaster_role_required`) */
11738
+ interface WebRTCWarning {
11739
+ code: string;
11740
+ message: string;
11378
11741
  }
11379
11742
  /** 피어 정보 */
11380
11743
  interface PeerInfo {
@@ -11384,8 +11747,6 @@ interface PeerInfo {
11384
11747
  user_id?: string;
11385
11748
  /** 방송자 여부 */
11386
11749
  is_broadcaster?: boolean;
11387
- /** 참가 시간 */
11388
- joined_at?: string;
11389
11750
  }
11390
11751
  /** 룸 정보 */
11391
11752
  interface RoomInfo {
@@ -11448,6 +11809,8 @@ interface RoomSummary {
11448
11809
  peer_count: number;
11449
11810
  broadcaster_count: number;
11450
11811
  viewer_count: number;
11812
+ /** 회원 허용 목록이 있는 비공개 룸이면 true (목록의 회원에게만 보인다) */
11813
+ private?: boolean;
11451
11814
  }
11452
11815
  /**
11453
11816
  * 앱 통계 응답 — server `GetStats` (`GET /v1/apps/:appID/stats`) 의 와이어 형태.
@@ -11474,6 +11837,8 @@ interface JoinRoomRequest {
11474
11837
  room_id: string;
11475
11838
  /** 방송자 요청. 서버가 정한다(`JoinRoomResponse.is_broadcaster`). */
11476
11839
  is_broadcaster?: boolean;
11840
+ /** 비공개 룸 회원 허용 목록 (`WebRTCConnectOptions.allowedMemberIds` 와 같은 규칙) */
11841
+ allowed_member_ids?: string[];
11477
11842
  }
11478
11843
  /** 참가 응답 (`POST /rooms/join`) */
11479
11844
  interface JoinRoomResponse {
@@ -11483,6 +11848,8 @@ interface JoinRoomResponse {
11483
11848
  peers: PeerInfo[];
11484
11849
  /** 서버가 정한 역할 */
11485
11850
  is_broadcaster: boolean;
11851
+ /** 들어간 룸이 비공개 룸이면 true */
11852
+ private?: boolean;
11486
11853
  /** 참가는 됐지만 요청대로 되지 않은 사항 (예: `broadcaster_requires_auth`) */
11487
11854
  warning?: {
11488
11855
  code: string;
@@ -11521,7 +11888,14 @@ declare class WebRTCAPI {
11521
11888
  private currentRoomId;
11522
11889
  private currentPeerId;
11523
11890
  private currentUserId;
11524
- private isBroadcaster;
11891
+ /** connect 가 요청한 방송자 역할 (switchRoom 이 이어받는다) */
11892
+ private broadcasterRequested;
11893
+ /** 서버가 정한 방송자 역할 (`joined` 의 is_broadcaster) */
11894
+ private broadcasterGranted;
11895
+ /** 비공개 룸 허용 목록 요청 (이 연결에서만 쓴다) */
11896
+ private allowedMemberIds;
11897
+ private privateRoom;
11898
+ private warningListeners;
11525
11899
  private localStream;
11526
11900
  private channelType;
11527
11901
  private peerConnections;
@@ -11569,6 +11943,11 @@ declare class WebRTCAPI {
11569
11943
  private handleAnswer;
11570
11944
  private handleICECandidate;
11571
11945
  private closePeerConnection;
11946
+ /**
11947
+ * 서버 error 메시지의 data 에서 안내 문구를 꺼낸다. 대부분은 문자열이지만 할당량, 동시접속 초과는
11948
+ * `{ error, message, ... }` 객체로 온다.
11949
+ */
11950
+ private static signalingErrorMessage;
11572
11951
  private sendSignaling;
11573
11952
  private handleDisconnect;
11574
11953
  private attemptReconnect;
@@ -11630,6 +12009,15 @@ declare class WebRTCAPI {
11630
12009
  * 현재 채널 타입 조회
11631
12010
  */
11632
12011
  getChannelType(): WebRTCMode;
12012
+ /**
12013
+ * 서버가 정한 방송자 역할인지 조회한다. 요청(`isBroadcaster: true`)과 다를 수 있다 — 익명 연결이나
12014
+ * 채널의 방송자 역할이 없는 회원은 시청자로 참가한다(`onWarning` 으로 이유가 온다).
12015
+ */
12016
+ isBroadcaster(): boolean;
12017
+ /**
12018
+ * 지금 룸이 회원 허용 목록이 있는 비공개 룸인지 조회한다.
12019
+ */
12020
+ isPrivateRoom(): boolean;
11633
12021
  /**
11634
12022
  * 원격 스트림 조회
11635
12023
  */
@@ -11658,6 +12046,17 @@ declare class WebRTCAPI {
11658
12046
  * 에러 이벤트
11659
12047
  */
11660
12048
  onError(callback: (error: Error) => void): () => void;
12049
+ /**
12050
+ * 서버가 join 요청을 바꿨다는 알림 이벤트 (예: 방송자 요청을 시청자로 낮춤)
12051
+ *
12052
+ * @example
12053
+ * ```typescript
12054
+ * cb.webrtc.onWarning(({ code, message }) => {
12055
+ * if (code === 'broadcaster_role_required') showToast(message)
12056
+ * })
12057
+ * ```
12058
+ */
12059
+ onWarning(callback: (warning: WebRTCWarning) => void): () => void;
11661
12060
  /**
11662
12061
  * 피어 참가 이벤트
11663
12062
  */
@@ -11672,6 +12071,7 @@ declare class WebRTCAPI {
11672
12071
  onRemoteStream(callback: (peerId: string, stream: MediaStream) => void): () => void;
11673
12072
  private setState;
11674
12073
  private emitError;
12074
+ private emitWarning;
11675
12075
  private emitPeerJoined;
11676
12076
  private emitPeerLeft;
11677
12077
  private emitRemoteStream;
@@ -12139,9 +12539,10 @@ declare class ConnectBase {
12139
12539
  /**
12140
12540
  * 현재 페이지가 앱이 직접 처리할 OAuth 콜백 페이지인지 판별.
12141
12541
  *
12142
- * `?code=...` (OAUTH_CODE_ONLY 흐름) 또는 OAuth 에러 응답 (`?error=...&state=...`) 패턴이면 true.
12143
- * 콜백 페이지에서 일반 `autoRestoreSession` 을 건너뛰어 rotation race 를 피한다. 토큰 콜백은
12144
- * 이미 주소에서 회수됐으므로 여기서 보지 않는다(`oauth.captureCallbackOnBoot`).
12542
+ * `?code=...&state=...` 또는 OAuth 에러 응답 (`?error=...&state=...`) 패턴이면 true.
12543
+ * 콜백 페이지에서 일반 `autoRestoreSession` 을 건너뛰어 rotation race 를 피한다. 토큰 콜백과 이
12544
+ * 브라우저의 state 가 돌아온 code 콜백은 이미 주소에서 회수됐으므로 여기 오지 않는다
12545
+ * (`oauth.captureCallbackOnBoot`).
12145
12546
  */
12146
12547
  private isOAuthCallbackUrl;
12147
12548
  /**
@@ -12167,4 +12568,4 @@ declare class ConnectBase {
12167
12568
  updateConfig(config: Partial<ConnectBaseConfig>): void;
12168
12569
  }
12169
12570
 
12170
- export { AIAPI, type AIChatOptions, type AIChatRequest, type AIChatResponse, type AIChatStreamCallbacks, type AIChatStreamOptions, AIError, type AIErrorCode, type AIMessage, type AISource, type AIStreamChunk, type AITool, type AIToolCall, type AIToolEvent, AUTH_MEMBER_ID_TOKEN, type AcceptInvitationResponse, type AckMessagesRequest, type AdMobDailyReport, type AdMobReportResponse, type AdMobReportSummary, type AdReportResponse, type AdReportSummary, type AdmobConnectionInfo, AdsAPI, type AdsenseConnectionInfo, type AgenticSearchProgress, type AggregateResult, type AggregateStage, type AnalyticsConfig, type AnalyticsEvent, ApiError, type ApiErrorDetail, type AppMemberDetail, type AppMemberIdentityDetail, type AppMemberIdentitySummary, type AppMemberList, type AppMemberListItem, type AppMemberProviderType, AppMembersAPI, type AppStatsResponse, type ArchivePolicy, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BackupInfo, type BatchOperation, type BatchOperationResult, type BatchSetPageMetaRequest, type BatchWriteResult, type BillingCycle, type BillingKeyResponse, type BiometricInfo, type BiometricResult, type BulkCreateResponse, type BulkError, type CPUInfo, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type ChangePlanPreview, type ChangePlanRequest, type Channel, type ChannelMembership, type ChannelStats, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ClientMessage, type ColumnSchema, type CommentListResponse, type CompleteUploadRequest, type CompleteUploadResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type ConsentOptions, type ConsumeMessagesResponse, type ConsumeOptions, type CopyTableRequest, type CopyTableResponse, type CreateBackupRequest, type CreateChannelRequest, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreateColumnRequest, type CreateDataRequest, type CreateDocumentRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateGeoIndexRequest, type CreateIndexRequest, type CreateInvitationRequest, type CreateInvitationResponse, type CreateLobbyRequest, type CreateOrganizationRequest, type CreatePlaylistRequest, type CreatePublicKeyRequest, type CreatePublicKeyResponse, type CreateRelationRequest, type CreateRolePayload, type CreateRoleResult, type CreateRoomResult, type CreateSearchIndexRequest, type CreateSecurityRuleRequest, type CreateSubscriptionRequest, type CreateTableRequest, type CreateTopicOptions, type CreateTriggerRequest, type CreateVideoStorageRequest, type DailyReport, type DataItem, type DataType, type DatabaseChange, type DatabaseChangeMessage, type DatabaseChangeType, type DatabaseRealtimeConnectOptions, type DatabaseRealtimeFilter, type DatabaseRealtimeHandlers, type DatabaseRealtimeSubscription, type DatabaseSnapshot, type DatabaseSnapshotMessage, type DatabaseSubscribeOptions, type DeleteBillingKeyResponse, type DeleteWhereResponse, type DeviceInfo, type DocumentResponse, type EnabledProviderInfo, type EnabledProvidersResponse, EndpointAPI, type EndpointCallInit, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type ExportDataRequest, type ExportDataResponse, type FetchDataResponse, type FetchFilesResponse, type FetchPublicKeysResponse, type FileItem, type FileStats, GameAPI, type GameAction, type GameClientConfig, type GameConfig, GameConfigAPI, type GameConfigPatch, type GameConnectionState, type GameConnectionStatus, type GameDelta, GameError, type GameErrorCode, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GenerateUploadURLByPathRequest, type GenerateUploadURLRequest, type GenerateUploadURLResponse, type GeoBoundingBox, type GeoIndex, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type HistoryResponse, type ICEServer, type ICEServersResponse, type ImageResult, type ImportDataRequest, type ImportDataResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinQueueRequest, type JoinRoomRequest, type JoinRoomResponse, type KnowledgeSearchRequest, type KnowledgeSearchResponse, type KnowledgeSearchResult, type LeaderboardEntry, type LeaderboardListResponse, type LeaderboardScoreEntry, type LifecyclePolicy, type ListAppMembersOptions, type ListBillingKeysResponse, type ListDocumentsResponse, type ListPageMetasOptions, type ListPageMetasResponse, type ListPaymentsOptions, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type LobbyInfo, type LobbyInvite, type LobbyMember, type LobbyVisibility, type MatchResult, type MatchmakingTicket, type MatchqueueListResponse, type MatchqueueTicket, type MemberChangePasswordRequest, type MemberCredentialMessageResponse, type MemberEmailVerificationConfirmRequest, type MemberEmailVerificationConfirmResponse, type MemberEmailVerificationRequest, type MemberInfoResponse, type MemberPasswordResetConfirmRequest, type MemberPasswordResetRequest, type MemberRedirectOption, type MemberSession, type MemberSessionList, type MemberSessionRevokeResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MemoryInfo, type MessageHandler, type MigrateDataRequest, type MigrateDataResponse, type MoveFileRequest, type NackMessageRequest, NativeAPI, type OAuthCallbackResponse, type OAuthProvider, type OnPaymentFailure, type OpenDialogOptions, type OpenDialogResult, type Organization, type OrganizationContext, type OrganizationInvitation, type OrganizationMember, type OrganizationMemberList, type OrganizationRole, OrganizationsAPI, type PageMetaResponse, type PartyInfo, type PartyInvite, type PartyMember, type PauseSubscriptionRequest, type PaymentDetail, type PaymentListItem, type PaymentListResult, type PaymentMode, type PaymentProvider, type PaymentStatus, type PeerInfo, type Platform, type PlayerEvent, type PlayerStats, type Playlist, type PlaylistItem, type PollUntilOptions, type PongMessage, type PopulateOption, type Position, type PostponeBillingRequest, type PreparePaymentRequest, type PreparePaymentResponse, type PresenceChangeHandler, type PresenceInfo, type PresenceSetOptions, type PresenceStatus, type PresenceStatusResult, type ProrationMode, type PublicKeyItem, type PublicKeyPaymentMode, type PublishBatchRequest, type PublishBatchResponse, type PublishMessageRequest, type PublishMessageResponse, type PushPlatform, type PushStatsResult, type PushTopicInfo, type QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, RealtimeConnectionError, type RealtimeConnectionErrorCode, type RealtimeMessage, RealtimeRequestError, type RealtimeSendPolicy, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type ReplayHighlight, type ReplayInfo, type ReplayPlayerInfo, type RestoreBackupRequest, type RestoreBackupResponse, type RetentionPolicy, type RoleDetail, type RoleList, type RoleListItem, type RolePermissionItem, type RoleUserItem, RolesAPI, type RoomInfo, type RoomStaleMessage, type RoomSummary, type RoomsResponse, type RotatePublicKeyRequest, type RotatePublicKeyResponse, type SaveDialogOptions, type SaveDialogResult, type ScriptDetailResponse, type ScriptListResponse, type ScriptLogEntry, type ScriptLogsResponse, type ScriptMeta, type ScriptMetricsResponse, type ScriptVersion, type ScriptVersionListResponse, type SearchIndex, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type SendSuperChatOptions, type SendSuperChatResponse, type ServerMessage, SessionManager, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type SpectatorInfo, type SpectatorPlayerState, type SpectatorState, type SpeechRecognizeOptions, type SpeechResult, type StateChange, type StateChangeHandler, type StorageUploadOptions, type StorageUploadProgress, type StreamContentPart, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamImageURLPart, type StreamMessage, type StreamOptions, type StreamSession, type StreamTextPart, type StreamTokenCallback, type StreamToolCallCallback, type StreamToolResultCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type SuperChatType, type SyncLostMessage, type SystemInfo, type TTLConfig, type TableAccessLevel, type TableColumnDef, type TableIndex, type TableRelation, type TableSchema, type TableSchemaDefinition, type TokenPersistence, type TransactionRead, type TransactionResult, type TransactionWrite, type TransactionWriteResult, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type TypingChangeHandler, type TypingInfo, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateCustomDataRequest, type UpdateCustomDataResponse, type UpdateDataRequest, type UpdateDocumentRequest, type UpdateLobbyRequest, type UpdateOrganizationRequest, type UpdatePublicKeyRequest, type UpdatePublicKeyResponse, type UpdateRolePayload, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UpdateVideoStorageRequest, type UploadByPathOptions, type UploadFileOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type ValidationSchema, type ValidationSchemaField, type ValidationStateTransitions, type Video, type VideoComment, type VideoCompleteUploadResponse, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoStorage, type VideoStorageAccessLevel, type VideoStorageListResponse, type VideoVisibility, type VoiceChannel, type VoiceMember, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WhereCondition, type WhereOperator, ConnectBase as default, detectInAppBrowser, escapeToExternalBrowser, isWebTransportSupported, toAIError, toCreateRoomWire };
12571
+ export { AIAPI, type AIChatOptions, type AIChatRequest, type AIChatResponse, type AIChatStreamCallbacks, type AIChatStreamOptions, AIError, type AIErrorCode, type AIMessage, type AISource, type AIStreamChunk, type AITool, type AIToolCall, type AIToolEvent, AUTH_MEMBER_ID_TOKEN, type AcceptInvitationResponse, type AckMessagesRequest, type AdMobDailyReport, type AdMobReportResponse, type AdMobReportSummary, type AdReportResponse, type AdReportSummary, type AdmobConnectionInfo, AdsAPI, type AdsenseConnectionInfo, type AgenticSearchProgress, type AggregateResult, type AggregateStage, type AnalyticsConfig, type AnalyticsEvent, ApiError, type ApiErrorDetail, type AppMemberDetail, type AppMemberIdentityDetail, type AppMemberIdentitySummary, type AppMemberList, type AppMemberListItem, type AppMemberProviderType, AppMembersAPI, type AppStatsResponse, type ArchivePolicy, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BackupInfo, type BatchOperation, type BatchOperationResult, type BatchSetPageMetaRequest, type BatchWriteResult, type BillingCycle, type BillingKeyResponse, type BiometricInfo, type BiometricResult, type BulkCreateResponse, type BulkError, type CPUInfo, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type ChangePlanOptions, type ChangePlanPreview, type ChangePlanRequest, type ChangePlanWithPriceRef, type ChangePlanWithProduct, type Channel, type ChannelMembership, type ChannelStats, type ChargeWithBillingKeyAmount, type ChargeWithBillingKeyOptions, type ChargeWithBillingKeyProduct, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ClientMessage, type ColumnSchema, type CommentListResponse, type CompleteUploadRequest, type CompleteUploadResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type ConsentOptions, type ConsumeMessagesResponse, type ConsumeOptions, type CopyTableRequest, type CopyTableResponse, type CreateBackupRequest, type CreateChannelRequest, type CreateCheckoutSessionOptions, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreateCheckoutSessionWithAmount, type CreateCheckoutSessionWithProduct, type CreateColumnRequest, type CreateDataRequest, type CreateDocumentRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateGeoIndexRequest, type CreateIndexRequest, type CreateInvitationRequest, type CreateInvitationResponse, type CreateLobbyRequest, type CreateOrganizationRequest, type CreatePlaylistRequest, type CreatePublicKeyRequest, type CreatePublicKeyResponse, type CreateRelationRequest, type CreateRolePayload, type CreateRoleResult, type CreateRoomResult, type CreateSearchIndexRequest, type CreateSecurityRuleRequest, type CreateSubscriptionOptions, type CreateSubscriptionRequest, type CreateSubscriptionWithAmount, type CreateSubscriptionWithProduct, type CreateTableRequest, type CreateTopicOptions, type CreateTriggerRequest, type CreateVideoStorageRequest, type DailyReport, type DataItem, type DataType, type DatabaseChange, type DatabaseChangeMessage, type DatabaseChangeType, type DatabaseRealtimeConnectOptions, type DatabaseRealtimeFilter, type DatabaseRealtimeHandlers, type DatabaseRealtimeSubscription, type DatabaseSnapshot, type DatabaseSnapshotMessage, type DatabaseSubscribeOptions, type DeleteBillingKeyResponse, type DeleteWhereResponse, type DeviceInfo, type DocumentResponse, type EnabledProviderInfo, type EnabledProvidersResponse, EndpointAPI, type EndpointCallInit, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type ExportDataRequest, type ExportDataResponse, type FetchDataResponse, type FetchFilesResponse, type FetchPublicKeysResponse, type FileItem, type FileStats, GameAPI, type GameAction, type GameClientConfig, type GameConfig, GameConfigAPI, type GameConfigPatch, type GameConnectionState, type GameConnectionStatus, type GameDelta, GameError, type GameErrorCode, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GenerateUploadURLByPathRequest, type GenerateUploadURLRequest, type GenerateUploadURLResponse, type GeoBoundingBox, type GeoIndex, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type HistoryResponse, type ICEServer, type ICEServersResponse, type ImageResult, type ImportDataRequest, type ImportDataResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinQueueRequest, type JoinRoomRequest, type JoinRoomResponse, type KnowledgeSearchRequest, type KnowledgeSearchResponse, type KnowledgeSearchResult, type LeaderboardEntry, type LeaderboardListResponse, type LeaderboardScoreEntry, type LifecyclePolicy, type ListAppMembersOptions, type ListBillingKeysResponse, type ListDocumentsResponse, type ListPageMetasOptions, type ListPageMetasResponse, type ListPaymentsOptions, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type LobbyInfo, type LobbyInvite, type LobbyMember, type LobbyVisibility, type MatchResult, type MatchmakingTicket, type MatchqueueListResponse, type MatchqueueTicket, type MemberChangePasswordRequest, type MemberCredentialMessageResponse, type MemberEmailVerificationConfirmRequest, type MemberEmailVerificationConfirmResponse, type MemberEmailVerificationRequest, type MemberInfoResponse, type MemberPasswordResetConfirmRequest, type MemberPasswordResetRequest, type MemberRedirectOption, type MemberSession, type MemberSessionList, type MemberSessionRevokeResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MemoryInfo, type MessageHandler, type MigrateDataRequest, type MigrateDataResponse, type MoveFileRequest, type NackMessageRequest, NativeAPI, type OAuthCallbackResponse, type OAuthProvider, type OnPaymentFailure, type OpenDialogOptions, type OpenDialogResult, type Organization, type OrganizationContext, type OrganizationInvitation, type OrganizationMember, type OrganizationMemberList, type OrganizationRole, OrganizationsAPI, type PageMetaResponse, type PartyInfo, type PartyInvite, type PartyMember, type PauseSubscriptionRequest, type PaymentDetail, type PaymentListItem, type PaymentListResult, type PaymentMode, type PaymentProvider, type PaymentStatus, type PeerInfo, type Platform, type PlayerEvent, type PlayerStats, type Playlist, type PlaylistItem, type PollUntilOptions, type PongMessage, type PopulateOption, type Position, type PostponeBillingRequest, type PreparePaymentOptions, type PreparePaymentRequest, type PreparePaymentResponse, type PreparePaymentWithAmount, type PreparePaymentWithProduct, type PresenceChangeHandler, type PresenceInfo, type PresenceSetOptions, type PresenceStatus, type PresenceStatusResult, type ProrationMode, type PublicKeyItem, type PublicKeyPaymentMode, type PublishBatchRequest, type PublishBatchResponse, type PublishMessageRequest, type PublishMessageResponse, type PushPlatform, type PushStatsResult, type PushTopicInfo, type QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, RealtimeConnectionError, type RealtimeConnectionErrorCode, type RealtimeMessage, RealtimeRequestError, type RealtimeSendPolicy, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type ReplayHighlight, type ReplayInfo, type ReplayPlayerInfo, type RestoreBackupRequest, type RestoreBackupResponse, type RetentionPolicy, type RoleDetail, type RoleList, type RoleListItem, type RolePermissionItem, type RoleUserItem, RolesAPI, type RoomInfo, type RoomStaleMessage, type RoomSummary, type RoomsResponse, type RotatePublicKeyRequest, type RotatePublicKeyResponse, type SaveDialogOptions, type SaveDialogResult, type ScriptDetailResponse, type ScriptListResponse, type ScriptLogEntry, type ScriptLogsResponse, type ScriptMeta, type ScriptMetricsResponse, type ScriptVersion, type ScriptVersionListResponse, type SearchIndex, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type SendSuperChatOptions, type SendSuperChatResponse, type ServerMessage, SessionManager, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type SpectatorInfo, type SpectatorPlayerState, type SpectatorState, type SpeechRecognizeOptions, type SpeechResult, type StateChange, type StateChangeHandler, type StorageUploadOptions, type StorageUploadProgress, type StreamContentPart, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamImageURLPart, type StreamMessage, type StreamOptions, type StreamSession, type StreamTextPart, type StreamTokenCallback, type StreamToolCallCallback, type StreamToolResultCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type SuperChatType, type SuspendAppMemberOptions, type SuspendAppMemberResult, type SyncLostMessage, type SystemInfo, type TTLConfig, type TableAccessLevel, type TableColumnDef, type TableIndex, type TableRelation, type TableSchema, type TableSchemaDefinition, type TokenPersistence, type TransactionRead, type TransactionResult, type TransactionWrite, type TransactionWriteResult, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type TypingChangeHandler, type TypingInfo, type UnsuspendAppMemberResult, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateCustomDataRequest, type UpdateCustomDataResponse, type UpdateDataRequest, type UpdateDocumentRequest, type UpdateLobbyRequest, type UpdateOrganizationRequest, type UpdatePublicKeyRequest, type UpdatePublicKeyResponse, type UpdateRolePayload, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UpdateVideoStorageRequest, type UploadByPathOptions, type UploadFileOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type ValidationSchema, type ValidationSchemaField, type ValidationStateTransitions, type Video, type VideoComment, type VideoCompleteUploadResponse, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoStorage, type VideoStorageAccessLevel, type VideoStorageListResponse, type VideoVisibility, type VoiceChannel, type VoiceMember, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WebRTCWarning, type WhereCondition, type WhereOperator, ConnectBase as default, detectInAppBrowser, escapeToExternalBrowser, isWebTransportSupported, toAIError, toCreateRoomWire };