connectbase-client 4.4.1 → 5.1.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/CHANGELOG.md +89 -0
- package/dist/connect-base.umd.js +5 -5
- package/dist/index.d.mts +232 -3
- package/dist/index.d.ts +232 -3
- package/dist/index.js +238 -51
- package/dist/index.mjs +235 -51
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -116,6 +116,123 @@ var AdsAPI = class {
|
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
+
// src/types/error.ts
|
|
120
|
+
var ApiError = class extends Error {
|
|
121
|
+
constructor(statusCode, message, code, details) {
|
|
122
|
+
super(message);
|
|
123
|
+
this.statusCode = statusCode;
|
|
124
|
+
this.name = "ApiError";
|
|
125
|
+
this.code = code;
|
|
126
|
+
this.details = details;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* `JSON.stringify(err)` 가 `{}` 로 찍히지 않게 한다.
|
|
130
|
+
*
|
|
131
|
+
* 표준 `Error` 는 message/stack 이 non-enumerable 이라 JSON 직렬화 시 빈 객체가
|
|
132
|
+
* 된다. 로그를 `JSON.stringify` 로 남기는 소비자에게는 "에러 정보가 아무것도 안
|
|
133
|
+
* 온다"로 보여, 실제로는 있는 정보까지 없는 것으로 오진하게 만든다
|
|
134
|
+
* (platform-issue 019fa21c).
|
|
135
|
+
*/
|
|
136
|
+
toJSON() {
|
|
137
|
+
return {
|
|
138
|
+
name: this.name,
|
|
139
|
+
message: this.message,
|
|
140
|
+
code: this.code,
|
|
141
|
+
statusCode: this.statusCode,
|
|
142
|
+
details: this.details
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var AIError = class extends Error {
|
|
147
|
+
constructor(init) {
|
|
148
|
+
super(init.message || init.code || "AI request failed");
|
|
149
|
+
this.name = "AIError";
|
|
150
|
+
this.code = init.code || "stream_failed";
|
|
151
|
+
this.retryable = init.retryable ?? isRetryableAICode(this.code);
|
|
152
|
+
this.status = init.status;
|
|
153
|
+
this.provider = init.provider;
|
|
154
|
+
this.model = init.model;
|
|
155
|
+
this.retryAfter = init.retryAfter;
|
|
156
|
+
this.detailCode = init.detailCode;
|
|
157
|
+
this.sessionId = init.sessionId;
|
|
158
|
+
}
|
|
159
|
+
/** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
|
|
160
|
+
toJSON() {
|
|
161
|
+
return {
|
|
162
|
+
name: this.name,
|
|
163
|
+
code: this.code,
|
|
164
|
+
message: this.message,
|
|
165
|
+
retryable: this.retryable,
|
|
166
|
+
status: this.status,
|
|
167
|
+
provider: this.provider,
|
|
168
|
+
model: this.model,
|
|
169
|
+
retryAfter: this.retryAfter,
|
|
170
|
+
detailCode: this.detailCode,
|
|
171
|
+
sessionId: this.sessionId
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
function isRetryableAICode(code) {
|
|
176
|
+
return code === "provider_timeout" || code === "service_unavailable" || code === "rate_limit_exceeded" || code === "stream_failed";
|
|
177
|
+
}
|
|
178
|
+
function toAIError(payload, fallback) {
|
|
179
|
+
if (payload instanceof AIError) return payload;
|
|
180
|
+
const p = typeof payload === "object" && payload !== null ? payload : {};
|
|
181
|
+
const str = (v) => typeof v === "string" && v !== "" ? v : void 0;
|
|
182
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
183
|
+
const documented = str(p.error) ?? str(p.code) ?? fallback?.code;
|
|
184
|
+
const sub = str(p.detail_code) ?? str(p.detailCode) ?? str(p.code);
|
|
185
|
+
const code = documented ?? "stream_failed";
|
|
186
|
+
const detailCode = sub && sub !== code ? sub : void 0;
|
|
187
|
+
const message = str(p.message) ?? (payload instanceof Error ? payload.message : void 0) ?? fallback?.message ?? code;
|
|
188
|
+
return new AIError({
|
|
189
|
+
code,
|
|
190
|
+
message,
|
|
191
|
+
retryable: typeof p.retryable === "boolean" ? p.retryable : void 0,
|
|
192
|
+
status: num(p.status) ?? num(p.statusCode) ?? fallback?.status,
|
|
193
|
+
provider: str(p.provider),
|
|
194
|
+
model: str(p.model),
|
|
195
|
+
retryAfter: num(p.retry_after_seconds) ?? num(p.retryAfter),
|
|
196
|
+
detailCode,
|
|
197
|
+
sessionId: str(p.session_id) ?? str(p.sessionId) ?? fallback?.sessionId
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
var AuthError = class extends Error {
|
|
201
|
+
constructor(message) {
|
|
202
|
+
super(message);
|
|
203
|
+
this.name = "AuthError";
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
var GameError = class extends Error {
|
|
207
|
+
constructor(init) {
|
|
208
|
+
super(init.message || init.code || "GameError");
|
|
209
|
+
this.name = "GameError";
|
|
210
|
+
this.code = init.code || "UNKNOWN";
|
|
211
|
+
this.phase = init.phase;
|
|
212
|
+
this.feature = init.feature;
|
|
213
|
+
this.roomId = init.roomId;
|
|
214
|
+
this.scriptId = init.scriptId;
|
|
215
|
+
this.originClientId = init.originClientId;
|
|
216
|
+
this.requested = init.requested;
|
|
217
|
+
this.available = init.available;
|
|
218
|
+
}
|
|
219
|
+
/** `JSON.stringify(err)` 가 `{}` 가 되지 않도록 한다 (ApiError.toJSON 참조). */
|
|
220
|
+
toJSON() {
|
|
221
|
+
return {
|
|
222
|
+
name: this.name,
|
|
223
|
+
code: this.code,
|
|
224
|
+
message: this.message,
|
|
225
|
+
phase: this.phase,
|
|
226
|
+
feature: this.feature,
|
|
227
|
+
roomId: this.roomId,
|
|
228
|
+
scriptId: this.scriptId,
|
|
229
|
+
originClientId: this.originClientId,
|
|
230
|
+
requested: this.requested,
|
|
231
|
+
available: this.available
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
119
236
|
// src/api/ai.ts
|
|
120
237
|
var AIAPI = class {
|
|
121
238
|
constructor(http) {
|
|
@@ -180,13 +297,24 @@ var AIAPI = class {
|
|
|
180
297
|
signal
|
|
181
298
|
});
|
|
182
299
|
if (!response.ok) {
|
|
183
|
-
const errorData = await response.json().catch(() => ({ error: "
|
|
184
|
-
callbacks.onError?.(
|
|
300
|
+
const errorData = await response.json().catch(() => ({ error: "stream_failed" }));
|
|
301
|
+
callbacks.onError?.(
|
|
302
|
+
toAIError(errorData, {
|
|
303
|
+
message: "Stream request failed",
|
|
304
|
+
status: response.status
|
|
305
|
+
})
|
|
306
|
+
);
|
|
185
307
|
return;
|
|
186
308
|
}
|
|
187
309
|
reader = response.body?.getReader();
|
|
188
310
|
if (!reader) {
|
|
189
|
-
callbacks.onError?.(
|
|
311
|
+
callbacks.onError?.(
|
|
312
|
+
new AIError({
|
|
313
|
+
code: "stream_failed",
|
|
314
|
+
message: "ReadableStream not supported",
|
|
315
|
+
retryable: false
|
|
316
|
+
})
|
|
317
|
+
);
|
|
190
318
|
return;
|
|
191
319
|
}
|
|
192
320
|
const decoder = new TextDecoder();
|
|
@@ -207,9 +335,7 @@ var AIAPI = class {
|
|
|
207
335
|
try {
|
|
208
336
|
const event = JSON.parse(data);
|
|
209
337
|
if (event.error) {
|
|
210
|
-
callbacks.onError?.(
|
|
211
|
-
event.message || event.error || "stream error"
|
|
212
|
-
);
|
|
338
|
+
callbacks.onError?.(toAIError(event));
|
|
213
339
|
return;
|
|
214
340
|
}
|
|
215
341
|
if (event.type === "sources" && event.sources) {
|
|
@@ -1194,34 +1320,48 @@ var AnalyticsAPI = class {
|
|
|
1194
1320
|
}
|
|
1195
1321
|
};
|
|
1196
1322
|
|
|
1197
|
-
// src/
|
|
1198
|
-
var
|
|
1199
|
-
constructor(
|
|
1200
|
-
|
|
1201
|
-
this.statusCode = statusCode;
|
|
1202
|
-
this.name = "ApiError";
|
|
1203
|
-
this.code = code;
|
|
1204
|
-
this.details = details;
|
|
1323
|
+
// src/api/app-members.ts
|
|
1324
|
+
var AppMembersAPI = class {
|
|
1325
|
+
constructor(http) {
|
|
1326
|
+
this.http = http;
|
|
1205
1327
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1328
|
+
ensureServerAuth(method) {
|
|
1329
|
+
if (this.http.hasPublicKey() && !this.http.hasJWT()) {
|
|
1330
|
+
throw new Error(
|
|
1331
|
+
`cb.appMembers.${method}() \uB294 \uCF58\uC194 JWT \uB610\uB294 service_role(ctx.cbAdmin, management_scopes: ["app_member:read"]) \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. Public Key(cb_pk_) \uB2E8\uB3C5 SDK \uC778\uC2A4\uD134\uC2A4\uB85C\uB294 \uD638\uCD9C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC790\uAE30 \uC815\uBCF4\uB294 cb.auth.getMe() \uB97C \uC4F0\uC138\uC694.`
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1211
1334
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
this.
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1335
|
+
/**
|
|
1336
|
+
* 앱 멤버 목록을 조회한다 (이메일 포함). (management_scope: `app_member:read`)
|
|
1337
|
+
*
|
|
1338
|
+
* @param appId 앱 ID
|
|
1339
|
+
* @param options 페이지네이션 및 `search`(닉네임·이메일 부분 일치)
|
|
1340
|
+
*/
|
|
1341
|
+
async list(appId, options = {}) {
|
|
1342
|
+
this.ensureServerAuth("list");
|
|
1343
|
+
const query = new URLSearchParams();
|
|
1344
|
+
if (options.page !== void 0) query.set("page", String(options.page));
|
|
1345
|
+
if (options.pageSize !== void 0)
|
|
1346
|
+
query.set("page_size", String(options.pageSize));
|
|
1347
|
+
const search = options.search?.trim();
|
|
1348
|
+
if (search) query.set("search", search);
|
|
1349
|
+
const qs = query.toString();
|
|
1350
|
+
return this.http.get(
|
|
1351
|
+
`/v1/apps/${appId}/app-members${qs ? `?${qs}` : ""}`
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* 앱 멤버 상세를 조회한다 (이메일 + 로그인 수단 포함). (management_scope: `app_member:read`)
|
|
1356
|
+
*
|
|
1357
|
+
* @param appId 앱 ID
|
|
1358
|
+
* @param memberId 멤버 ID
|
|
1359
|
+
*/
|
|
1360
|
+
async get(appId, memberId) {
|
|
1361
|
+
this.ensureServerAuth("get");
|
|
1362
|
+
return this.http.get(
|
|
1363
|
+
`/v1/apps/${appId}/app-members/${memberId}`
|
|
1364
|
+
);
|
|
1225
1365
|
}
|
|
1226
1366
|
};
|
|
1227
1367
|
|
|
@@ -6748,9 +6888,16 @@ var RealtimeAPI = class {
|
|
|
6748
6888
|
});
|
|
6749
6889
|
this.pendingRequests.clear();
|
|
6750
6890
|
this.subscriptions.clear();
|
|
6751
|
-
this.streamSessions.forEach((session) => {
|
|
6891
|
+
this.streamSessions.forEach((session, sessionId) => {
|
|
6752
6892
|
if (session.handlers.onError) {
|
|
6753
|
-
session.handlers.onError(
|
|
6893
|
+
session.handlers.onError(
|
|
6894
|
+
new AIError({
|
|
6895
|
+
code: "service_unavailable",
|
|
6896
|
+
message: "\uC2E4\uC2DC\uAC04 \uC5F0\uACB0\uC774 \uC885\uB8CC\uB418\uC5B4 AI \uC2A4\uD2B8\uB9AC\uBC0D\uC774 \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC7AC\uC5F0\uACB0 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.",
|
|
6897
|
+
retryable: true,
|
|
6898
|
+
sessionId
|
|
6899
|
+
})
|
|
6900
|
+
);
|
|
6754
6901
|
}
|
|
6755
6902
|
});
|
|
6756
6903
|
this.streamSessions.clear();
|
|
@@ -7015,17 +7162,26 @@ var RealtimeAPI = class {
|
|
|
7015
7162
|
signal
|
|
7016
7163
|
});
|
|
7017
7164
|
if (!response.ok) {
|
|
7018
|
-
const errData = await response.json().catch(() => ({ error: "
|
|
7165
|
+
const errData = await response.json().catch(() => ({ error: "stream_failed" }));
|
|
7019
7166
|
handlers.onError?.(
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7167
|
+
toAIError(errData, {
|
|
7168
|
+
message: "Stream request failed",
|
|
7169
|
+
sessionId,
|
|
7170
|
+
status: response.status
|
|
7171
|
+
})
|
|
7023
7172
|
);
|
|
7024
7173
|
return;
|
|
7025
7174
|
}
|
|
7026
7175
|
reader = response.body?.getReader();
|
|
7027
7176
|
if (!reader) {
|
|
7028
|
-
handlers.onError?.(
|
|
7177
|
+
handlers.onError?.(
|
|
7178
|
+
new AIError({
|
|
7179
|
+
code: "stream_failed",
|
|
7180
|
+
message: "ReadableStream not supported",
|
|
7181
|
+
retryable: false,
|
|
7182
|
+
sessionId
|
|
7183
|
+
})
|
|
7184
|
+
);
|
|
7029
7185
|
return;
|
|
7030
7186
|
}
|
|
7031
7187
|
const decoder = new TextDecoder();
|
|
@@ -7052,9 +7208,7 @@ var RealtimeAPI = class {
|
|
|
7052
7208
|
try {
|
|
7053
7209
|
const ev = JSON.parse(data);
|
|
7054
7210
|
if (ev.error) {
|
|
7055
|
-
handlers.onError?.(
|
|
7056
|
-
new Error(ev.message || ev.error || "stream error")
|
|
7057
|
-
);
|
|
7211
|
+
handlers.onError?.(toAIError(ev, { sessionId }));
|
|
7058
7212
|
return;
|
|
7059
7213
|
}
|
|
7060
7214
|
if (ev.type === "tool_start") {
|
|
@@ -7098,7 +7252,14 @@ var RealtimeAPI = class {
|
|
|
7098
7252
|
} catch (err) {
|
|
7099
7253
|
const aborted = signal.aborted || err instanceof DOMException && err.name === "AbortError" || typeof err === "object" && err !== null && err.name === "AbortError";
|
|
7100
7254
|
if (!aborted) {
|
|
7101
|
-
handlers.onError?.(
|
|
7255
|
+
handlers.onError?.(
|
|
7256
|
+
new AIError({
|
|
7257
|
+
code: "service_unavailable",
|
|
7258
|
+
message: err instanceof Error ? err.message : String(err) || "AI \uC2A4\uD2B8\uB9AC\uBC0D \uC694\uCCAD\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
|
|
7259
|
+
retryable: true,
|
|
7260
|
+
sessionId
|
|
7261
|
+
})
|
|
7262
|
+
);
|
|
7102
7263
|
}
|
|
7103
7264
|
} finally {
|
|
7104
7265
|
this.sseSessions.delete(sessionId);
|
|
@@ -7736,12 +7897,11 @@ var RealtimeAPI = class {
|
|
|
7736
7897
|
break;
|
|
7737
7898
|
}
|
|
7738
7899
|
case "stream_error": {
|
|
7739
|
-
const data = msg.data;
|
|
7740
7900
|
if (msg.request_id) {
|
|
7741
7901
|
for (const [sessionId, session] of this.streamSessions) {
|
|
7742
7902
|
if (session.requestId === msg.request_id) {
|
|
7743
7903
|
if (session.handlers.onError) {
|
|
7744
|
-
session.handlers.onError(
|
|
7904
|
+
session.handlers.onError(toAIError(msg.data, { sessionId }));
|
|
7745
7905
|
}
|
|
7746
7906
|
this.streamSessions.delete(sessionId);
|
|
7747
7907
|
break;
|
|
@@ -7814,9 +7974,16 @@ var RealtimeAPI = class {
|
|
|
7814
7974
|
}
|
|
7815
7975
|
this.ws = null;
|
|
7816
7976
|
this._connectionId = null;
|
|
7817
|
-
this.streamSessions.forEach((session) => {
|
|
7977
|
+
this.streamSessions.forEach((session, sessionId) => {
|
|
7818
7978
|
if (session.handlers.onError) {
|
|
7819
|
-
session.handlers.onError(
|
|
7979
|
+
session.handlers.onError(
|
|
7980
|
+
new AIError({
|
|
7981
|
+
code: "service_unavailable",
|
|
7982
|
+
message: "\uC2E4\uC2DC\uAC04 \uC5F0\uACB0\uC774 \uB04A\uACA8 AI \uC2A4\uD2B8\uB9AC\uBC0D\uC774 \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC7AC\uC5F0\uACB0 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.",
|
|
7983
|
+
retryable: true,
|
|
7984
|
+
sessionId
|
|
7985
|
+
})
|
|
7986
|
+
);
|
|
7820
7987
|
}
|
|
7821
7988
|
});
|
|
7822
7989
|
this.streamSessions.clear();
|
|
@@ -11273,13 +11440,26 @@ var HttpClient = class {
|
|
|
11273
11440
|
this.emitError(err2);
|
|
11274
11441
|
throw err2;
|
|
11275
11442
|
}
|
|
11276
|
-
const
|
|
11277
|
-
const
|
|
11443
|
+
const flatMessage = typeof errorData.message === "string" && errorData.message !== "" ? errorData.message : void 0;
|
|
11444
|
+
const explicitCode = typeof errorData.code === "string" && errorData.code !== "" ? errorData.code : void 0;
|
|
11445
|
+
const errorIsCode = typeof rawError === "string" && /^[a-z][a-z0-9_]*$/.test(rawError);
|
|
11446
|
+
const message = flatMessage ?? (typeof rawError === "string" && rawError !== "" ? rawError : "Unknown error");
|
|
11447
|
+
const code = explicitCode ?? (errorIsCode ? rawError : void 0);
|
|
11448
|
+
const legacyDetails = {};
|
|
11449
|
+
if (retryAfterSeconds !== void 0) {
|
|
11450
|
+
legacyDetails.retry_after_seconds = retryAfterSeconds;
|
|
11451
|
+
}
|
|
11452
|
+
if (typeof errorData.provider === "string") {
|
|
11453
|
+
legacyDetails.provider = errorData.provider;
|
|
11454
|
+
}
|
|
11455
|
+
if (typeof errorData.model === "string") {
|
|
11456
|
+
legacyDetails.model = errorData.model;
|
|
11457
|
+
}
|
|
11278
11458
|
const err = new ApiError(
|
|
11279
11459
|
response.status,
|
|
11280
11460
|
message,
|
|
11281
|
-
|
|
11282
|
-
legacyDetails
|
|
11461
|
+
code,
|
|
11462
|
+
Object.keys(legacyDetails).length > 0 ? legacyDetails : void 0
|
|
11283
11463
|
);
|
|
11284
11464
|
this.emitError(err);
|
|
11285
11465
|
throw err;
|
|
@@ -12163,6 +12343,7 @@ var ConnectBase = class {
|
|
|
12163
12343
|
this.subscription = new SubscriptionAPI(this.http);
|
|
12164
12344
|
this.push = new PushAPI(this.http);
|
|
12165
12345
|
this.roles = new RolesAPI(this.http);
|
|
12346
|
+
this.appMembers = new AppMembersAPI(this.http);
|
|
12166
12347
|
this.video = new VideoAPI(
|
|
12167
12348
|
this.http,
|
|
12168
12349
|
config.videoUrl || env("CB_VIDEO_URL") || DEFAULT_VIDEO_URL
|
|
@@ -12257,9 +12438,11 @@ var ConnectBase = class {
|
|
|
12257
12438
|
var index_default = ConnectBase;
|
|
12258
12439
|
export {
|
|
12259
12440
|
AIAPI,
|
|
12441
|
+
AIError,
|
|
12260
12442
|
AUTH_MEMBER_ID_TOKEN,
|
|
12261
12443
|
AdsAPI,
|
|
12262
12444
|
ApiError,
|
|
12445
|
+
AppMembersAPI,
|
|
12263
12446
|
AuthError,
|
|
12264
12447
|
ConnectBase,
|
|
12265
12448
|
EndpointAPI,
|
|
@@ -12276,5 +12459,6 @@ export {
|
|
|
12276
12459
|
detectInAppBrowser,
|
|
12277
12460
|
escapeToExternalBrowser,
|
|
12278
12461
|
isWebTransportSupported,
|
|
12462
|
+
toAIError,
|
|
12279
12463
|
toCreateRoomWire
|
|
12280
12464
|
};
|