connectbase-client 6.4.0 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -152,6 +152,64 @@ declare class GameError extends Error {
152
152
  /** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
153
153
  toJSON(): Record<string, unknown>;
154
154
  }
155
+ /**
156
+ * 실시간(WebSocket) 연결 거부 코드. socket-server 가 연결을 받지 않은 이유이고, 대응이 코드마다 다르다.
157
+ *
158
+ * | 코드 | 원인 | 재시도 | 권장 대응 |
159
+ * |------|------|--------|-----------|
160
+ * | `connection_limit_exceeded` | 플랜의 동시접속 한도 도달 | 가능 | 다른 연결이 끊기면 자리가 난다. `details.current`/`details.limit` 확인, 계속되면 플랜 상향 |
161
+ * | `quota_exceeded` | 월간 WebSocket 사용 시간 소진 | 불가 | 플랜 업그레이드 전까지 재시도 무의미 |
162
+ * | `server_at_capacity` | 서버 일시 혼잡 | 가능 | 잠시 후 재시도 |
163
+ * | `auth_unavailable` | 인증 서버 일시 장애 | 가능 | 잠시 후 재시도 |
164
+ * | `unauthorized` | 공개 키/액세스 토큰이 유효하지 않음 | 불가 | 키·토큰 확인 (토큰 만료면 새 토큰으로 `connect()`) |
165
+ * | `forbidden` | 다른 앱의 경로로 접속 | 불가 | 설정 확인 |
166
+ * | `invalid_user_id` | 공개 키 연결에 UUID 형식 `userId` | 불가 | `accessToken` 을 쓰거나 UUID 가 아닌 식별자 사용 |
167
+ * | `internal_error` | 서버 설정 오류 | 가능 | 잠시 후 재시도 |
168
+ */
169
+ type RealtimeConnectionErrorCode = "connection_limit_exceeded" | "quota_exceeded" | "server_at_capacity" | "auth_unavailable" | "unauthorized" | "forbidden" | "invalid_user_id" | "internal_error" | (string & {});
170
+ /**
171
+ * 서버가 이유를 밝히고 실시간 연결을 거부했을 때 `cb.realtime.connect()` 가 던지는 에러.
172
+ *
173
+ * 브라우저의 WebSocket API 는 실패한 핸드셰이크의 HTTP 상태를 읽을 수 없어, 예전에는 동시접속
174
+ * 초과도 인증 실패도 "Connection timeout"/"Failed to connect" 로만 보였고 SDK 는 SSE 폴백으로
175
+ * 넘어가 subscribe/send 가 나중에야 이유 없이 실패했다(platform-issue 01a15d9d). 이제 서버가
176
+ * 연결을 받은 뒤 거부 이유를 보내고 4000+HTTP상태 close 코드(예: 4401, 4402, 4503)로 닫는다.
177
+ *
178
+ * - 거부는 SSE 폴백 대상이 아니다 — 네트워크는 정상이고 서버가 받지 않은 것이다.
179
+ * - 자동 재연결 중에 받은 거부는 `retryable` 이면 백오프로 계속 시도하고, 아니면 재연결을 멈추고
180
+ * `cb.realtime.onError` 로 이 에러를 알린다.
181
+ *
182
+ * ```ts
183
+ * try {
184
+ * await cb.realtime.connect()
185
+ * } catch (e) {
186
+ * if (e instanceof RealtimeConnectionError) {
187
+ * if (e.code === 'connection_limit_exceeded') showFull(e.details?.limit)
188
+ * else if (e.retryable) setTimeout(() => cb.realtime.connect(), 5000)
189
+ * else showConfigError(e.message)
190
+ * }
191
+ * }
192
+ * ```
193
+ */
194
+ declare class RealtimeConnectionError extends Error {
195
+ /** 문서화된 거부 코드. 분기 기준은 항상 이 필드다. */
196
+ code: RealtimeConnectionErrorCode;
197
+ /** WebSocket close 코드 (4000 + 서버의 HTTP 상태). */
198
+ closeCode: number;
199
+ /** 시간차를 두고 다시 연결하면 성공할 수 있는지. */
200
+ retryable: boolean;
201
+ /** 거부 상세 (예: connection_limit_exceeded 의 `current`/`limit`, quota_exceeded 의 `quota`/`unit`). */
202
+ details?: Record<string, unknown>;
203
+ constructor(init: {
204
+ code?: string;
205
+ message?: string;
206
+ closeCode: number;
207
+ retryable?: boolean;
208
+ details?: Record<string, unknown>;
209
+ });
210
+ /** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
211
+ toJSON(): Record<string, unknown>;
212
+ }
155
213
 
156
214
  interface AbortOptions {
157
215
  timeout?: number;
@@ -8099,6 +8157,16 @@ declare class RealtimeAPI {
8099
8157
  get transport(): "ws" | "sse" | null;
8100
8158
  private options;
8101
8159
  private retryCount;
8160
+ /**
8161
+ * 재연결 뒤 복구할 구독 상태. 연결이 끊긴 첫 순간에 떠 두고, 재연결이 성공해 복구한 뒤 비운다.
8162
+ *
8163
+ * 재연결 시도가 실패할 때마다 onclose → handleDisconnect 가 다시 불린다. 예전에는 그때마다 구독 맵을
8164
+ * 새로 떴는데, 첫 끊김에서 이미 비워진 맵이라 빈 스냅샷으로 덮였다 — 첫 재연결 시도가 실패하면
8165
+ * (서버 롤링 재시작 등) 재연결에 성공해도 구독이 하나도 복구되지 않았다.
8166
+ */
8167
+ private pendingRestore;
8168
+ /** 첫 연결 전에 direct 원본 힌트를 한 번 물었는지 (primeDirectRealtime). */
8169
+ private directRealtimePrimed;
8102
8170
  private pendingRequests;
8103
8171
  private subscriptions;
8104
8172
  private streamSessions;
@@ -8383,6 +8451,17 @@ declare class RealtimeAPI {
8383
8451
  * ```
8384
8452
  */
8385
8453
  onReadReceipt(category: string, handler: ReadReceiptHandler): () => void;
8454
+ /**
8455
+ * direct(저지연) 원본을 아직 모르면 첫 연결 전에 한 번 묻는다 — `GET /v1/public/edge-hints`.
8456
+ *
8457
+ * direct 원본은 core-server 응답 헤더(`X-CB-Realtime-Direct-Base`)로만 배운다. realtime 만 쓰는
8458
+ * 페이지는 WS 를 열기 전에 REST 를 부르지 않아 배울 기회가 없었고, 첫 연결이 늘 Cloudflare 를 타
8459
+ * 한국 사용자는 미국(LAX)을 거친 ~270ms 로 붙었다(platform-issue 01a15d9d 의 273ms). 응답 헤더는
8460
+ * HttpClient 가 평소처럼 학습한다. 광고 대상이 아니면(해외, 킬 스위치) 빈 응답이라 원래 소켓
8461
+ * URL 로 간다. 실패하거나 느리면(1.5초) 그냥 넘어간다 — 최적화일 뿐 연결의 전제가 아니다.
8462
+ * 세션당 한 번만 묻는다.
8463
+ */
8464
+ private primeDirectRealtime;
8386
8465
  private doConnect;
8387
8466
  private log;
8388
8467
  /**
@@ -8393,6 +8472,11 @@ declare class RealtimeAPI {
8393
8472
  private logError;
8394
8473
  private handleServerMessage;
8395
8474
  private handleDisconnect;
8475
+ /**
8476
+ * 재연결을 멈추고 앱에 알린다 — 서버가 재시도해도 소용없는 이유(자격증명, 할당량)로 거부했거나
8477
+ * 재시도할 수 있는 거부가 maxRetries 를 다 썼다.
8478
+ */
8479
+ private failRealtime;
8396
8480
  /**
8397
8481
  * 이전 구독 상태를 복구합니다.
8398
8482
  * 재연결 성공 후 호출됩니다.
@@ -11757,4 +11841,4 @@ declare class ConnectBase {
11757
11841
  updateConfig(config: Partial<ConnectBaseConfig>): void;
11758
11842
  }
11759
11843
 
11760
- 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 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 QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, type RealtimeMessage, 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 };
11844
+ 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 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 QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, RealtimeConnectionError, type RealtimeConnectionErrorCode, type RealtimeMessage, 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 };
package/dist/index.d.ts CHANGED
@@ -152,6 +152,64 @@ declare class GameError extends Error {
152
152
  /** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
153
153
  toJSON(): Record<string, unknown>;
154
154
  }
155
+ /**
156
+ * 실시간(WebSocket) 연결 거부 코드. socket-server 가 연결을 받지 않은 이유이고, 대응이 코드마다 다르다.
157
+ *
158
+ * | 코드 | 원인 | 재시도 | 권장 대응 |
159
+ * |------|------|--------|-----------|
160
+ * | `connection_limit_exceeded` | 플랜의 동시접속 한도 도달 | 가능 | 다른 연결이 끊기면 자리가 난다. `details.current`/`details.limit` 확인, 계속되면 플랜 상향 |
161
+ * | `quota_exceeded` | 월간 WebSocket 사용 시간 소진 | 불가 | 플랜 업그레이드 전까지 재시도 무의미 |
162
+ * | `server_at_capacity` | 서버 일시 혼잡 | 가능 | 잠시 후 재시도 |
163
+ * | `auth_unavailable` | 인증 서버 일시 장애 | 가능 | 잠시 후 재시도 |
164
+ * | `unauthorized` | 공개 키/액세스 토큰이 유효하지 않음 | 불가 | 키·토큰 확인 (토큰 만료면 새 토큰으로 `connect()`) |
165
+ * | `forbidden` | 다른 앱의 경로로 접속 | 불가 | 설정 확인 |
166
+ * | `invalid_user_id` | 공개 키 연결에 UUID 형식 `userId` | 불가 | `accessToken` 을 쓰거나 UUID 가 아닌 식별자 사용 |
167
+ * | `internal_error` | 서버 설정 오류 | 가능 | 잠시 후 재시도 |
168
+ */
169
+ type RealtimeConnectionErrorCode = "connection_limit_exceeded" | "quota_exceeded" | "server_at_capacity" | "auth_unavailable" | "unauthorized" | "forbidden" | "invalid_user_id" | "internal_error" | (string & {});
170
+ /**
171
+ * 서버가 이유를 밝히고 실시간 연결을 거부했을 때 `cb.realtime.connect()` 가 던지는 에러.
172
+ *
173
+ * 브라우저의 WebSocket API 는 실패한 핸드셰이크의 HTTP 상태를 읽을 수 없어, 예전에는 동시접속
174
+ * 초과도 인증 실패도 "Connection timeout"/"Failed to connect" 로만 보였고 SDK 는 SSE 폴백으로
175
+ * 넘어가 subscribe/send 가 나중에야 이유 없이 실패했다(platform-issue 01a15d9d). 이제 서버가
176
+ * 연결을 받은 뒤 거부 이유를 보내고 4000+HTTP상태 close 코드(예: 4401, 4402, 4503)로 닫는다.
177
+ *
178
+ * - 거부는 SSE 폴백 대상이 아니다 — 네트워크는 정상이고 서버가 받지 않은 것이다.
179
+ * - 자동 재연결 중에 받은 거부는 `retryable` 이면 백오프로 계속 시도하고, 아니면 재연결을 멈추고
180
+ * `cb.realtime.onError` 로 이 에러를 알린다.
181
+ *
182
+ * ```ts
183
+ * try {
184
+ * await cb.realtime.connect()
185
+ * } catch (e) {
186
+ * if (e instanceof RealtimeConnectionError) {
187
+ * if (e.code === 'connection_limit_exceeded') showFull(e.details?.limit)
188
+ * else if (e.retryable) setTimeout(() => cb.realtime.connect(), 5000)
189
+ * else showConfigError(e.message)
190
+ * }
191
+ * }
192
+ * ```
193
+ */
194
+ declare class RealtimeConnectionError extends Error {
195
+ /** 문서화된 거부 코드. 분기 기준은 항상 이 필드다. */
196
+ code: RealtimeConnectionErrorCode;
197
+ /** WebSocket close 코드 (4000 + 서버의 HTTP 상태). */
198
+ closeCode: number;
199
+ /** 시간차를 두고 다시 연결하면 성공할 수 있는지. */
200
+ retryable: boolean;
201
+ /** 거부 상세 (예: connection_limit_exceeded 의 `current`/`limit`, quota_exceeded 의 `quota`/`unit`). */
202
+ details?: Record<string, unknown>;
203
+ constructor(init: {
204
+ code?: string;
205
+ message?: string;
206
+ closeCode: number;
207
+ retryable?: boolean;
208
+ details?: Record<string, unknown>;
209
+ });
210
+ /** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
211
+ toJSON(): Record<string, unknown>;
212
+ }
155
213
 
156
214
  interface AbortOptions {
157
215
  timeout?: number;
@@ -8099,6 +8157,16 @@ declare class RealtimeAPI {
8099
8157
  get transport(): "ws" | "sse" | null;
8100
8158
  private options;
8101
8159
  private retryCount;
8160
+ /**
8161
+ * 재연결 뒤 복구할 구독 상태. 연결이 끊긴 첫 순간에 떠 두고, 재연결이 성공해 복구한 뒤 비운다.
8162
+ *
8163
+ * 재연결 시도가 실패할 때마다 onclose → handleDisconnect 가 다시 불린다. 예전에는 그때마다 구독 맵을
8164
+ * 새로 떴는데, 첫 끊김에서 이미 비워진 맵이라 빈 스냅샷으로 덮였다 — 첫 재연결 시도가 실패하면
8165
+ * (서버 롤링 재시작 등) 재연결에 성공해도 구독이 하나도 복구되지 않았다.
8166
+ */
8167
+ private pendingRestore;
8168
+ /** 첫 연결 전에 direct 원본 힌트를 한 번 물었는지 (primeDirectRealtime). */
8169
+ private directRealtimePrimed;
8102
8170
  private pendingRequests;
8103
8171
  private subscriptions;
8104
8172
  private streamSessions;
@@ -8383,6 +8451,17 @@ declare class RealtimeAPI {
8383
8451
  * ```
8384
8452
  */
8385
8453
  onReadReceipt(category: string, handler: ReadReceiptHandler): () => void;
8454
+ /**
8455
+ * direct(저지연) 원본을 아직 모르면 첫 연결 전에 한 번 묻는다 — `GET /v1/public/edge-hints`.
8456
+ *
8457
+ * direct 원본은 core-server 응답 헤더(`X-CB-Realtime-Direct-Base`)로만 배운다. realtime 만 쓰는
8458
+ * 페이지는 WS 를 열기 전에 REST 를 부르지 않아 배울 기회가 없었고, 첫 연결이 늘 Cloudflare 를 타
8459
+ * 한국 사용자는 미국(LAX)을 거친 ~270ms 로 붙었다(platform-issue 01a15d9d 의 273ms). 응답 헤더는
8460
+ * HttpClient 가 평소처럼 학습한다. 광고 대상이 아니면(해외, 킬 스위치) 빈 응답이라 원래 소켓
8461
+ * URL 로 간다. 실패하거나 느리면(1.5초) 그냥 넘어간다 — 최적화일 뿐 연결의 전제가 아니다.
8462
+ * 세션당 한 번만 묻는다.
8463
+ */
8464
+ private primeDirectRealtime;
8386
8465
  private doConnect;
8387
8466
  private log;
8388
8467
  /**
@@ -8393,6 +8472,11 @@ declare class RealtimeAPI {
8393
8472
  private logError;
8394
8473
  private handleServerMessage;
8395
8474
  private handleDisconnect;
8475
+ /**
8476
+ * 재연결을 멈추고 앱에 알린다 — 서버가 재시도해도 소용없는 이유(자격증명, 할당량)로 거부했거나
8477
+ * 재시도할 수 있는 거부가 maxRetries 를 다 썼다.
8478
+ */
8479
+ private failRealtime;
8396
8480
  /**
8397
8481
  * 이전 구독 상태를 복구합니다.
8398
8482
  * 재연결 성공 후 호출됩니다.
@@ -11757,4 +11841,4 @@ declare class ConnectBase {
11757
11841
  updateConfig(config: Partial<ConnectBaseConfig>): void;
11758
11842
  }
11759
11843
 
11760
- 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 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 QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, type RealtimeMessage, 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 };
11844
+ 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 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 QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, RealtimeConnectionError, type RealtimeConnectionErrorCode, type RealtimeMessage, 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 };
package/dist/index.js CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  GameRoomTransport: () => GameRoomTransport,
37
37
  NativeAPI: () => NativeAPI,
38
38
  OrganizationsAPI: () => OrganizationsAPI,
39
+ RealtimeConnectionError: () => RealtimeConnectionError,
39
40
  RolesAPI: () => RolesAPI,
40
41
  SessionManager: () => SessionManager,
41
42
  VideoProcessingError: () => VideoProcessingError,
@@ -282,6 +283,30 @@ var GameError = class extends Error {
282
283
  };
283
284
  }
284
285
  };
286
+ var RealtimeConnectionError = class extends Error {
287
+ constructor(init) {
288
+ super(init.message || init.code || "Realtime connection rejected");
289
+ this.name = "RealtimeConnectionError";
290
+ this.code = init.code || "unknown";
291
+ this.closeCode = init.closeCode;
292
+ this.retryable = init.retryable ?? isRetryableRealtimeRejection(this.code);
293
+ this.details = init.details;
294
+ }
295
+ /** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
296
+ toJSON() {
297
+ return {
298
+ name: this.name,
299
+ code: this.code,
300
+ message: this.message,
301
+ closeCode: this.closeCode,
302
+ retryable: this.retryable,
303
+ details: this.details
304
+ };
305
+ }
306
+ };
307
+ function isRetryableRealtimeRejection(code) {
308
+ return code === "connection_limit_exceeded" || code === "server_at_capacity" || code === "auth_unavailable" || code === "internal_error";
309
+ }
285
310
 
286
311
  // src/api/ai.ts
287
312
  function aiErrorToApiError(err) {
@@ -7924,6 +7949,18 @@ var QueueAPI = class {
7924
7949
 
7925
7950
  // src/api/realtime.ts
7926
7951
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7952
+ function toConnectionRejection(msg) {
7953
+ if (msg.event !== "error" || msg.request_id) return null;
7954
+ const data = msg.data;
7955
+ if (!data || typeof data.close_code !== "number") return null;
7956
+ return new RealtimeConnectionError({
7957
+ code: data.code,
7958
+ message: data.message || msg.error,
7959
+ closeCode: data.close_code,
7960
+ retryable: data.retryable,
7961
+ details: data.details
7962
+ });
7963
+ }
7927
7964
  var RealtimeAPI = class {
7928
7965
  constructor(http, socketUrl) {
7929
7966
  this.ws = null;
@@ -7951,6 +7988,16 @@ var RealtimeAPI = class {
7951
7988
  fallback: "sse"
7952
7989
  };
7953
7990
  this.retryCount = 0;
7991
+ /**
7992
+ * 재연결 뒤 복구할 구독 상태. 연결이 끊긴 첫 순간에 떠 두고, 재연결이 성공해 복구한 뒤 비운다.
7993
+ *
7994
+ * 재연결 시도가 실패할 때마다 onclose → handleDisconnect 가 다시 불린다. 예전에는 그때마다 구독 맵을
7995
+ * 새로 떴는데, 첫 끊김에서 이미 비워진 맵이라 빈 스냅샷으로 덮였다 — 첫 재연결 시도가 실패하면
7996
+ * (서버 롤링 재시작 등) 재연결에 성공해도 구독이 하나도 복구되지 않았다.
7997
+ */
7998
+ this.pendingRestore = null;
7999
+ /** 첫 연결 전에 direct 원본 힌트를 한 번 물었는지 (primeDirectRealtime). */
8000
+ this.directRealtimePrimed = false;
7954
8001
  this.pendingRequests = /* @__PURE__ */ new Map();
7955
8002
  this.subscriptions = /* @__PURE__ */ new Map();
7956
8003
  this.streamSessions = /* @__PURE__ */ new Map();
@@ -7994,7 +8041,7 @@ var RealtimeAPI = class {
7994
8041
  if (this.state === "connected") {
7995
8042
  return;
7996
8043
  }
7997
- if (this.state === "connecting" && this.connectPromise) {
8044
+ if (this.connectPromise) {
7998
8045
  return this.connectPromise;
7999
8046
  }
8000
8047
  this.options = { ...this.options, ...options };
@@ -8006,10 +8053,15 @@ var RealtimeAPI = class {
8006
8053
  `Invalid userId: "${this.userId}" looks like a UUID, which is reserved for authenticated members. Pass that member's accessToken (JWT) instead of userId+publicKey, or use a non-UUID identifier for anonymous/guest connections.`
8007
8054
  );
8008
8055
  }
8009
- this.connectPromise = this.doConnect();
8056
+ this.connectPromise = this.primeDirectRealtime().then(
8057
+ () => this.doConnect()
8058
+ );
8010
8059
  try {
8011
8060
  await this.connectPromise;
8012
8061
  } catch (e) {
8062
+ if (e instanceof RealtimeConnectionError) {
8063
+ throw e;
8064
+ }
8013
8065
  const hasAuth = !!(this.options.accessToken || this.http.getPublicKey());
8014
8066
  if (this.options.fallback !== "none" && hasAuth) {
8015
8067
  this.activateSseFallback(e);
@@ -8038,6 +8090,7 @@ var RealtimeAPI = class {
8038
8090
  this.activeTransport = "sse";
8039
8091
  this.state = "connected";
8040
8092
  this.retryCount = 0;
8093
+ this.pendingRestore = null;
8041
8094
  this.log(
8042
8095
  `WS unavailable (${causeMsg}); using SSE fallback transport for AI streaming`
8043
8096
  );
@@ -8094,6 +8147,7 @@ var RealtimeAPI = class {
8094
8147
  this._appId = null;
8095
8148
  this.retryCount = 0;
8096
8149
  this.connectPromise = null;
8150
+ this.pendingRestore = null;
8097
8151
  }
8098
8152
  /**
8099
8153
  * 카테고리 구독
@@ -8876,6 +8930,30 @@ var RealtimeAPI = class {
8876
8930
  };
8877
8931
  }
8878
8932
  // Private methods
8933
+ /**
8934
+ * direct(저지연) 원본을 아직 모르면 첫 연결 전에 한 번 묻는다 — `GET /v1/public/edge-hints`.
8935
+ *
8936
+ * direct 원본은 core-server 응답 헤더(`X-CB-Realtime-Direct-Base`)로만 배운다. realtime 만 쓰는
8937
+ * 페이지는 WS 를 열기 전에 REST 를 부르지 않아 배울 기회가 없었고, 첫 연결이 늘 Cloudflare 를 타
8938
+ * 한국 사용자는 미국(LAX)을 거친 ~270ms 로 붙었다(platform-issue 01a15d9d 의 273ms). 응답 헤더는
8939
+ * HttpClient 가 평소처럼 학습한다. 광고 대상이 아니면(해외, 킬 스위치) 빈 응답이라 원래 소켓
8940
+ * URL 로 간다. 실패하거나 느리면(1.5초) 그냥 넘어간다 — 최적화일 뿐 연결의 전제가 아니다.
8941
+ * 세션당 한 번만 묻는다.
8942
+ */
8943
+ async primeDirectRealtime() {
8944
+ if (this.directRealtimePrimed) return;
8945
+ this.directRealtimePrimed = true;
8946
+ if (this.http.getDirectRealtimeBaseUrl() || !this.http.getPublicKey()) {
8947
+ return;
8948
+ }
8949
+ try {
8950
+ await this.http.get("/v1/public/edge-hints", { timeout: 1500 });
8951
+ } catch (e) {
8952
+ this.log(
8953
+ `edge hint lookup failed, using default socket URL: ${e instanceof Error ? e.message : String(e)}`
8954
+ );
8955
+ }
8956
+ }
8879
8957
  async doConnect() {
8880
8958
  return new Promise((resolve, reject) => {
8881
8959
  this.state = "connecting";
@@ -8904,7 +8982,9 @@ var RealtimeAPI = class {
8904
8982
  if (this.userId) {
8905
8983
  url += `&user_id=${encodeURIComponent(this.userId)}`;
8906
8984
  }
8985
+ url += "&reject_mode=close";
8907
8986
  let settled = false;
8987
+ let rejection = null;
8908
8988
  const timeoutId = setTimeout(() => {
8909
8989
  if (!settled) {
8910
8990
  settled = true;
@@ -8932,6 +9012,11 @@ var RealtimeAPI = class {
8932
9012
  for (const line of messages) {
8933
9013
  try {
8934
9014
  const msg = JSON.parse(line);
9015
+ const rejected = toConnectionRejection(msg);
9016
+ if (rejected && !settled) {
9017
+ rejection = rejected;
9018
+ continue;
9019
+ }
8935
9020
  this.handleServerMessage(msg, () => {
8936
9021
  if (!settled) {
8937
9022
  settled = true;
@@ -8949,6 +9034,30 @@ var RealtimeAPI = class {
8949
9034
  this.log(
8950
9035
  `WebSocket closed: code=${event.code}, reason=${event.reason}`
8951
9036
  );
9037
+ if (event.code >= 4e3 && event.code <= 4999) {
9038
+ const err = rejection ?? new RealtimeConnectionError({
9039
+ code: event.reason || void 0,
9040
+ closeCode: event.code
9041
+ });
9042
+ const wasConnected = this.state === "connected";
9043
+ if (!settled) {
9044
+ settled = true;
9045
+ clearTimeout(timeoutId);
9046
+ }
9047
+ this.ws = null;
9048
+ if (wasConnected) {
9049
+ if (err.retryable) {
9050
+ this.handleDisconnect();
9051
+ } else {
9052
+ this.failRealtime(err);
9053
+ }
9054
+ return;
9055
+ }
9056
+ this.state = "disconnected";
9057
+ this.notifyStateChange();
9058
+ reject(err);
9059
+ return;
9060
+ }
8952
9061
  if (!settled && this.state === "connecting") {
8953
9062
  settled = true;
8954
9063
  clearTimeout(timeoutId);
@@ -9195,20 +9304,23 @@ var RealtimeAPI = class {
9195
9304
  }
9196
9305
  });
9197
9306
  this.streamSessions.clear();
9198
- const previousSubscriptions = /* @__PURE__ */ new Map();
9199
- for (const [category, sub] of this.subscriptions) {
9200
- previousSubscriptions.set(category, [...sub.handlers]);
9307
+ if (!this.pendingRestore) {
9308
+ const subscriptions = /* @__PURE__ */ new Map();
9309
+ for (const [category, sub] of this.subscriptions) {
9310
+ subscriptions.set(category, [...sub.handlers]);
9311
+ }
9312
+ const presence = /* @__PURE__ */ new Map();
9313
+ for (const [userId, handlers] of this.presenceSubscriptions) {
9314
+ presence.set(userId, [...handlers]);
9315
+ }
9316
+ const typing = /* @__PURE__ */ new Map();
9317
+ for (const [roomId, handlers] of this.typingHandlers) {
9318
+ typing.set(roomId, [...handlers]);
9319
+ }
9320
+ this.pendingRestore = { subscriptions, presence, typing };
9201
9321
  }
9202
9322
  this.subscriptions.clear();
9203
- const previousPresenceSubscriptions = /* @__PURE__ */ new Map();
9204
- for (const [userId, handlers] of this.presenceSubscriptions) {
9205
- previousPresenceSubscriptions.set(userId, [...handlers]);
9206
- }
9207
9323
  this.presenceSubscriptions.clear();
9208
- const previousTypingHandlers = /* @__PURE__ */ new Map();
9209
- for (const [roomId, handlers] of this.typingHandlers) {
9210
- previousTypingHandlers.set(roomId, [...handlers]);
9211
- }
9212
9324
  this.typingHandlers.clear();
9213
9325
  if (this.retryCount < this.options.maxRetries) {
9214
9326
  this.state = "reconnecting";
@@ -9220,16 +9332,29 @@ var RealtimeAPI = class {
9220
9332
  );
9221
9333
  setTimeout(async () => {
9222
9334
  if (this.sseFallbackActive) return;
9335
+ if (this.state !== "reconnecting") return;
9223
9336
  try {
9224
9337
  await this.doConnect();
9225
9338
  this.log("Reconnected successfully, restoring subscriptions...");
9226
- await this.restoreSubscriptions(
9227
- previousSubscriptions,
9228
- previousPresenceSubscriptions,
9229
- previousTypingHandlers
9230
- );
9339
+ const snapshot = this.pendingRestore;
9340
+ this.pendingRestore = null;
9341
+ if (snapshot) {
9342
+ await this.restoreSubscriptions(
9343
+ snapshot.subscriptions,
9344
+ snapshot.presence,
9345
+ snapshot.typing
9346
+ );
9347
+ }
9231
9348
  } catch (e) {
9232
9349
  this.logError("Reconnect failed", e);
9350
+ if (e instanceof RealtimeConnectionError) {
9351
+ if (e.retryable && this.retryCount < this.options.maxRetries) {
9352
+ this.handleDisconnect();
9353
+ } else {
9354
+ this.failRealtime(e);
9355
+ }
9356
+ return;
9357
+ }
9233
9358
  if (this.retryCount >= this.options.maxRetries && this.options.fallback !== "none" && !this.sseFallbackActive) {
9234
9359
  this.activateSseFallback(e);
9235
9360
  }
@@ -9247,6 +9372,18 @@ var RealtimeAPI = class {
9247
9372
  }
9248
9373
  }
9249
9374
  }
9375
+ /**
9376
+ * 재연결을 멈추고 앱에 알린다 — 서버가 재시도해도 소용없는 이유(자격증명, 할당량)로 거부했거나
9377
+ * 재시도할 수 있는 거부가 maxRetries 를 다 썼다.
9378
+ */
9379
+ failRealtime(err) {
9380
+ this.pendingRestore = null;
9381
+ this.ws = null;
9382
+ this._connectionId = null;
9383
+ this.state = "disconnected";
9384
+ this.notifyStateChange();
9385
+ this.notifyError(err);
9386
+ }
9250
9387
  /**
9251
9388
  * 이전 구독 상태를 복구합니다.
9252
9389
  * 재연결 성공 후 호출됩니다.
@@ -14224,6 +14361,7 @@ var index_default = ConnectBase;
14224
14361
  GameRoomTransport,
14225
14362
  NativeAPI,
14226
14363
  OrganizationsAPI,
14364
+ RealtimeConnectionError,
14227
14365
  RolesAPI,
14228
14366
  SessionManager,
14229
14367
  VideoProcessingError,