connectbase-client 5.12.0 → 5.12.2
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/CHANGELOG.md +52 -0
- package/dist/connect-base.umd.js +5 -5
- package/dist/index.d.mts +0 -33
- package/dist/index.d.ts +0 -33
- package/dist/index.js +34 -12
- package/dist/index.mjs +34 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -7154,39 +7154,6 @@ interface ReadReceiptInfo {
|
|
|
7154
7154
|
/** 읽음 확인 핸들러 */
|
|
7155
7155
|
type ReadReceiptHandler = (receipt: ReadReceiptInfo) => void;
|
|
7156
7156
|
|
|
7157
|
-
/**
|
|
7158
|
-
* Realtime API
|
|
7159
|
-
* WebSocket 기반 실시간 통신 API
|
|
7160
|
-
*
|
|
7161
|
-
* @example
|
|
7162
|
-
* ```typescript
|
|
7163
|
-
* // 연결
|
|
7164
|
-
* await client.realtime.connect()
|
|
7165
|
-
*
|
|
7166
|
-
* // 카테고리 구독
|
|
7167
|
-
* const chat = await client.realtime.subscribe('chat-room-1')
|
|
7168
|
-
*
|
|
7169
|
-
* // 메시지 수신
|
|
7170
|
-
* chat.onMessage((msg) => {
|
|
7171
|
-
* console.log('Received:', msg.data)
|
|
7172
|
-
* })
|
|
7173
|
-
*
|
|
7174
|
-
* // 메시지 전송
|
|
7175
|
-
* await chat.send({ text: 'Hello!' })
|
|
7176
|
-
*
|
|
7177
|
-
* // 히스토리 조회 (persist=true인 카테고리만)
|
|
7178
|
-
* if (chat.info.persist) {
|
|
7179
|
-
* const history = await chat.getHistory(50)
|
|
7180
|
-
* console.log('History:', history.messages)
|
|
7181
|
-
* }
|
|
7182
|
-
*
|
|
7183
|
-
* // 구독 해제
|
|
7184
|
-
* await chat.unsubscribe()
|
|
7185
|
-
*
|
|
7186
|
-
* // 연결 해제
|
|
7187
|
-
* client.realtime.disconnect()
|
|
7188
|
-
* ```
|
|
7189
|
-
*/
|
|
7190
7157
|
declare class RealtimeAPI {
|
|
7191
7158
|
private http;
|
|
7192
7159
|
private socketUrl;
|
package/dist/index.d.ts
CHANGED
|
@@ -7154,39 +7154,6 @@ interface ReadReceiptInfo {
|
|
|
7154
7154
|
/** 읽음 확인 핸들러 */
|
|
7155
7155
|
type ReadReceiptHandler = (receipt: ReadReceiptInfo) => void;
|
|
7156
7156
|
|
|
7157
|
-
/**
|
|
7158
|
-
* Realtime API
|
|
7159
|
-
* WebSocket 기반 실시간 통신 API
|
|
7160
|
-
*
|
|
7161
|
-
* @example
|
|
7162
|
-
* ```typescript
|
|
7163
|
-
* // 연결
|
|
7164
|
-
* await client.realtime.connect()
|
|
7165
|
-
*
|
|
7166
|
-
* // 카테고리 구독
|
|
7167
|
-
* const chat = await client.realtime.subscribe('chat-room-1')
|
|
7168
|
-
*
|
|
7169
|
-
* // 메시지 수신
|
|
7170
|
-
* chat.onMessage((msg) => {
|
|
7171
|
-
* console.log('Received:', msg.data)
|
|
7172
|
-
* })
|
|
7173
|
-
*
|
|
7174
|
-
* // 메시지 전송
|
|
7175
|
-
* await chat.send({ text: 'Hello!' })
|
|
7176
|
-
*
|
|
7177
|
-
* // 히스토리 조회 (persist=true인 카테고리만)
|
|
7178
|
-
* if (chat.info.persist) {
|
|
7179
|
-
* const history = await chat.getHistory(50)
|
|
7180
|
-
* console.log('History:', history.messages)
|
|
7181
|
-
* }
|
|
7182
|
-
*
|
|
7183
|
-
* // 구독 해제
|
|
7184
|
-
* await chat.unsubscribe()
|
|
7185
|
-
*
|
|
7186
|
-
* // 연결 해제
|
|
7187
|
-
* client.realtime.disconnect()
|
|
7188
|
-
* ```
|
|
7189
|
-
*/
|
|
7190
7157
|
declare class RealtimeAPI {
|
|
7191
7158
|
private http;
|
|
7192
7159
|
private socketUrl;
|
package/dist/index.js
CHANGED
|
@@ -7209,6 +7209,7 @@ var QueueAPI = class {
|
|
|
7209
7209
|
};
|
|
7210
7210
|
|
|
7211
7211
|
// src/api/realtime.ts
|
|
7212
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7212
7213
|
var RealtimeAPI = class {
|
|
7213
7214
|
constructor(http, socketUrl) {
|
|
7214
7215
|
this.ws = null;
|
|
@@ -7286,6 +7287,11 @@ var RealtimeAPI = class {
|
|
|
7286
7287
|
if (options.userId) {
|
|
7287
7288
|
this.userId = options.userId;
|
|
7288
7289
|
}
|
|
7290
|
+
if (this.userId && !this.options.accessToken && UUID_RE.test(this.userId)) {
|
|
7291
|
+
throw new Error(
|
|
7292
|
+
`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.`
|
|
7293
|
+
);
|
|
7294
|
+
}
|
|
7289
7295
|
this.connectPromise = this.doConnect();
|
|
7290
7296
|
try {
|
|
7291
7297
|
await this.connectPromise;
|
|
@@ -7305,6 +7311,7 @@ var RealtimeAPI = class {
|
|
|
7305
7311
|
* (degraded) AI stream() 이 SSE 로 동작하게 한다. 백그라운드 WS 재연결 머신은 정지한다.
|
|
7306
7312
|
*/
|
|
7307
7313
|
activateSseFallback(cause) {
|
|
7314
|
+
if (this.sseFallbackActive) return;
|
|
7308
7315
|
if (this.ws) {
|
|
7309
7316
|
try {
|
|
7310
7317
|
this.ws.close();
|
|
@@ -7312,14 +7319,20 @@ var RealtimeAPI = class {
|
|
|
7312
7319
|
}
|
|
7313
7320
|
this.ws = null;
|
|
7314
7321
|
}
|
|
7322
|
+
const causeMsg = cause instanceof Error ? cause.message : String(cause);
|
|
7315
7323
|
this.sseFallbackActive = true;
|
|
7316
7324
|
this.activeTransport = "sse";
|
|
7317
7325
|
this.state = "connected";
|
|
7318
7326
|
this.retryCount = 0;
|
|
7319
7327
|
this.log(
|
|
7320
|
-
`WS unavailable (${
|
|
7328
|
+
`WS unavailable (${causeMsg}); using SSE fallback transport for AI streaming`
|
|
7321
7329
|
);
|
|
7322
7330
|
this.notifyStateChange();
|
|
7331
|
+
this.notifyError(
|
|
7332
|
+
new Error(
|
|
7333
|
+
`Realtime WebSocket unavailable, downgraded to SSE fallback transport (cb.realtime.transport === 'sse'). Only realtime.stream() works in this mode \u2014 subscribe/send/setPresence/typing calls will throw. Cause: ${causeMsg}`
|
|
7334
|
+
)
|
|
7335
|
+
);
|
|
7323
7336
|
}
|
|
7324
7337
|
/**
|
|
7325
7338
|
* 연결 해제
|
|
@@ -11658,7 +11671,7 @@ var HttpClient = class {
|
|
|
11658
11671
|
if (this.persistence !== "none") return;
|
|
11659
11672
|
if (!this.config.refreshToken) return;
|
|
11660
11673
|
try {
|
|
11661
|
-
await this.refreshAccessToken();
|
|
11674
|
+
await this.refreshAccessToken({ silent: true });
|
|
11662
11675
|
} catch {
|
|
11663
11676
|
}
|
|
11664
11677
|
}
|
|
@@ -11791,7 +11804,8 @@ var HttpClient = class {
|
|
|
11791
11804
|
getAppId() {
|
|
11792
11805
|
return this.config.appId;
|
|
11793
11806
|
}
|
|
11794
|
-
async refreshAccessToken() {
|
|
11807
|
+
async refreshAccessToken(options) {
|
|
11808
|
+
const silent = options?.silent ?? false;
|
|
11795
11809
|
if (this.isRefreshing) {
|
|
11796
11810
|
return this.refreshPromise;
|
|
11797
11811
|
}
|
|
@@ -11905,27 +11919,35 @@ var HttpClient = class {
|
|
|
11905
11919
|
);
|
|
11906
11920
|
this.refreshLockedUntil = Date.now() + backoffMs;
|
|
11907
11921
|
if (failureKind === "permanent") {
|
|
11908
|
-
|
|
11909
|
-
|
|
11922
|
+
if (!silent) {
|
|
11923
|
+
this.clearTokens();
|
|
11924
|
+
this.config.onTokenExpired?.();
|
|
11925
|
+
}
|
|
11910
11926
|
const error2 = new AuthError(`${baseMsg}. Please login again.`);
|
|
11911
|
-
|
|
11912
|
-
|
|
11927
|
+
if (!silent) {
|
|
11928
|
+
this.emitError(error2);
|
|
11929
|
+
this.config.onAuthError?.(error2);
|
|
11930
|
+
}
|
|
11913
11931
|
throw error2;
|
|
11914
11932
|
}
|
|
11915
11933
|
if (failureKind === "client_bug") {
|
|
11916
11934
|
const error2 = new AuthError(
|
|
11917
11935
|
`${baseMsg}. Client request invalid; tokens preserved.`
|
|
11918
11936
|
);
|
|
11919
|
-
|
|
11920
|
-
|
|
11937
|
+
if (!silent) {
|
|
11938
|
+
this.emitError(error2);
|
|
11939
|
+
this.config.onAuthError?.(error2);
|
|
11940
|
+
}
|
|
11921
11941
|
throw error2;
|
|
11922
11942
|
}
|
|
11923
11943
|
const error = new AuthError(
|
|
11924
11944
|
`${baseMsg}. Transient failure; tokens preserved, will retry after backoff.`
|
|
11925
11945
|
);
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11946
|
+
if (!silent) {
|
|
11947
|
+
this.emitError(error);
|
|
11948
|
+
this.config.onTransientRefreshFailure?.(error);
|
|
11949
|
+
this.config.onAuthError?.(error);
|
|
11950
|
+
}
|
|
11929
11951
|
throw error;
|
|
11930
11952
|
} finally {
|
|
11931
11953
|
cleanup();
|
package/dist/index.mjs
CHANGED
|
@@ -7160,6 +7160,7 @@ var QueueAPI = class {
|
|
|
7160
7160
|
};
|
|
7161
7161
|
|
|
7162
7162
|
// src/api/realtime.ts
|
|
7163
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7163
7164
|
var RealtimeAPI = class {
|
|
7164
7165
|
constructor(http, socketUrl) {
|
|
7165
7166
|
this.ws = null;
|
|
@@ -7237,6 +7238,11 @@ var RealtimeAPI = class {
|
|
|
7237
7238
|
if (options.userId) {
|
|
7238
7239
|
this.userId = options.userId;
|
|
7239
7240
|
}
|
|
7241
|
+
if (this.userId && !this.options.accessToken && UUID_RE.test(this.userId)) {
|
|
7242
|
+
throw new Error(
|
|
7243
|
+
`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.`
|
|
7244
|
+
);
|
|
7245
|
+
}
|
|
7240
7246
|
this.connectPromise = this.doConnect();
|
|
7241
7247
|
try {
|
|
7242
7248
|
await this.connectPromise;
|
|
@@ -7256,6 +7262,7 @@ var RealtimeAPI = class {
|
|
|
7256
7262
|
* (degraded) AI stream() 이 SSE 로 동작하게 한다. 백그라운드 WS 재연결 머신은 정지한다.
|
|
7257
7263
|
*/
|
|
7258
7264
|
activateSseFallback(cause) {
|
|
7265
|
+
if (this.sseFallbackActive) return;
|
|
7259
7266
|
if (this.ws) {
|
|
7260
7267
|
try {
|
|
7261
7268
|
this.ws.close();
|
|
@@ -7263,14 +7270,20 @@ var RealtimeAPI = class {
|
|
|
7263
7270
|
}
|
|
7264
7271
|
this.ws = null;
|
|
7265
7272
|
}
|
|
7273
|
+
const causeMsg = cause instanceof Error ? cause.message : String(cause);
|
|
7266
7274
|
this.sseFallbackActive = true;
|
|
7267
7275
|
this.activeTransport = "sse";
|
|
7268
7276
|
this.state = "connected";
|
|
7269
7277
|
this.retryCount = 0;
|
|
7270
7278
|
this.log(
|
|
7271
|
-
`WS unavailable (${
|
|
7279
|
+
`WS unavailable (${causeMsg}); using SSE fallback transport for AI streaming`
|
|
7272
7280
|
);
|
|
7273
7281
|
this.notifyStateChange();
|
|
7282
|
+
this.notifyError(
|
|
7283
|
+
new Error(
|
|
7284
|
+
`Realtime WebSocket unavailable, downgraded to SSE fallback transport (cb.realtime.transport === 'sse'). Only realtime.stream() works in this mode \u2014 subscribe/send/setPresence/typing calls will throw. Cause: ${causeMsg}`
|
|
7285
|
+
)
|
|
7286
|
+
);
|
|
7274
7287
|
}
|
|
7275
7288
|
/**
|
|
7276
7289
|
* 연결 해제
|
|
@@ -11609,7 +11622,7 @@ var HttpClient = class {
|
|
|
11609
11622
|
if (this.persistence !== "none") return;
|
|
11610
11623
|
if (!this.config.refreshToken) return;
|
|
11611
11624
|
try {
|
|
11612
|
-
await this.refreshAccessToken();
|
|
11625
|
+
await this.refreshAccessToken({ silent: true });
|
|
11613
11626
|
} catch {
|
|
11614
11627
|
}
|
|
11615
11628
|
}
|
|
@@ -11742,7 +11755,8 @@ var HttpClient = class {
|
|
|
11742
11755
|
getAppId() {
|
|
11743
11756
|
return this.config.appId;
|
|
11744
11757
|
}
|
|
11745
|
-
async refreshAccessToken() {
|
|
11758
|
+
async refreshAccessToken(options) {
|
|
11759
|
+
const silent = options?.silent ?? false;
|
|
11746
11760
|
if (this.isRefreshing) {
|
|
11747
11761
|
return this.refreshPromise;
|
|
11748
11762
|
}
|
|
@@ -11856,27 +11870,35 @@ var HttpClient = class {
|
|
|
11856
11870
|
);
|
|
11857
11871
|
this.refreshLockedUntil = Date.now() + backoffMs;
|
|
11858
11872
|
if (failureKind === "permanent") {
|
|
11859
|
-
|
|
11860
|
-
|
|
11873
|
+
if (!silent) {
|
|
11874
|
+
this.clearTokens();
|
|
11875
|
+
this.config.onTokenExpired?.();
|
|
11876
|
+
}
|
|
11861
11877
|
const error2 = new AuthError(`${baseMsg}. Please login again.`);
|
|
11862
|
-
|
|
11863
|
-
|
|
11878
|
+
if (!silent) {
|
|
11879
|
+
this.emitError(error2);
|
|
11880
|
+
this.config.onAuthError?.(error2);
|
|
11881
|
+
}
|
|
11864
11882
|
throw error2;
|
|
11865
11883
|
}
|
|
11866
11884
|
if (failureKind === "client_bug") {
|
|
11867
11885
|
const error2 = new AuthError(
|
|
11868
11886
|
`${baseMsg}. Client request invalid; tokens preserved.`
|
|
11869
11887
|
);
|
|
11870
|
-
|
|
11871
|
-
|
|
11888
|
+
if (!silent) {
|
|
11889
|
+
this.emitError(error2);
|
|
11890
|
+
this.config.onAuthError?.(error2);
|
|
11891
|
+
}
|
|
11872
11892
|
throw error2;
|
|
11873
11893
|
}
|
|
11874
11894
|
const error = new AuthError(
|
|
11875
11895
|
`${baseMsg}. Transient failure; tokens preserved, will retry after backoff.`
|
|
11876
11896
|
);
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11897
|
+
if (!silent) {
|
|
11898
|
+
this.emitError(error);
|
|
11899
|
+
this.config.onTransientRefreshFailure?.(error);
|
|
11900
|
+
this.config.onAuthError?.(error);
|
|
11901
|
+
}
|
|
11880
11902
|
throw error;
|
|
11881
11903
|
} finally {
|
|
11882
11904
|
cleanup();
|