@16x/webphone-sdk 4.0.0 → 4.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 +17 -0
- package/README.md +43 -0
- package/dist/{CCBarClient-BFq7695C.cjs → CCBarClient-BJXQRMWp.cjs} +1 -1
- package/dist/{CCBarClient-CAGBUxil.js → CCBarClient-CqNuYXza.js} +1 -1
- package/dist/{Diagnostics-DwF6aDHZ.cjs → Diagnostics-BfBUpek0.cjs} +1 -1
- package/dist/{Diagnostics-Cs02iAlB.js → Diagnostics-Bh2KjW2U.js} +1 -1
- package/dist/diagnostics/index.cjs +1 -1
- package/dist/diagnostics/index.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/index.umd.js +1 -1
- package/dist/legacy/index.cjs +1 -1
- package/dist/legacy/index.d.ts +2 -0
- package/dist/legacy/index.js +288 -3
- package/dist/legacy/legacyAes.d.ts +29 -0
- package/dist/legacy/legacySessionProvider.d.ts +79 -0
- package/dist/types.d.ts +5 -1
- package/dist/version.d.ts +1 -1
- package/package.json +109 -109
package/dist/legacy/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as e } from "../SharedWorkerProtocol-DKVQ5-po.js";
|
|
2
|
-
import { t } from "../CCBarClient-
|
|
2
|
+
import { t } from "../CCBarClient-CqNuYXza.js";
|
|
3
3
|
//#region src/legacy/CCBarSDK.ts
|
|
4
4
|
var n = class extends Error {
|
|
5
5
|
code = "LEGACY_METHOD_DEPRECATED";
|
|
@@ -101,8 +101,293 @@ function i() {
|
|
|
101
101
|
return !1;
|
|
102
102
|
}
|
|
103
103
|
//#endregion
|
|
104
|
+
//#region src/legacy/legacyAes.ts
|
|
105
|
+
var a = "q7X4p6MvK1z8Lb3A", o = "W9e2T4mN0aQ7Ru6C";
|
|
106
|
+
async function s(t, n = {}) {
|
|
107
|
+
let r = String(t ?? "").replace(/\s+/g, "");
|
|
108
|
+
if (!r) throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "解密的密文为空:坐席账号里没有 password/registerPassword" });
|
|
109
|
+
let i = n.subtle ?? globalThis.crypto?.subtle;
|
|
110
|
+
if (i === void 0) throw new e("CONFIG_INVALID", "configuration", !1, { cause: "需要 WebCrypto 才能解 SIP 密码:请在安全上下文(https / localhost)或 Node 18+ 里运行" });
|
|
111
|
+
let s;
|
|
112
|
+
try {
|
|
113
|
+
let e = atob(r);
|
|
114
|
+
s = new Uint8Array(new ArrayBuffer(e.length));
|
|
115
|
+
for (let t = 0; t < e.length; t += 1) s[t] = e.charCodeAt(t);
|
|
116
|
+
} catch {
|
|
117
|
+
throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "密文不是合法的 Base64:确认取的是 password/registerPassword 原值,没有被截断或转义" });
|
|
118
|
+
}
|
|
119
|
+
let l = await i.importKey("raw", c(n.key ?? a), "AES-CBC", !1, ["decrypt"]);
|
|
120
|
+
try {
|
|
121
|
+
let e = await i.decrypt({
|
|
122
|
+
name: "AES-CBC",
|
|
123
|
+
iv: c(n.iv ?? o)
|
|
124
|
+
}, l, s);
|
|
125
|
+
return new TextDecoder("utf-8").decode(e).trim();
|
|
126
|
+
} catch (t) {
|
|
127
|
+
throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: `SIP 密码解密失败(检查 key/iv 与该环境是否一致):${t instanceof Error ? t.message : String(t)}` });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function c(e) {
|
|
131
|
+
let t = new TextEncoder().encode(e), n = new Uint8Array(new ArrayBuffer(t.byteLength));
|
|
132
|
+
return n.set(t), n;
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/legacy/legacySessionProvider.ts
|
|
136
|
+
var l = "/openapi/token/v1", u = "/seat/account/get", d = "/seats/set-status", f = "/api/fs/sip-ws", p = 7443, m = 3478, h = 600, g = 600, _ = 180, v = 60, y = 5e3, b = 2e4, x = [
|
|
137
|
+
"outbound",
|
|
138
|
+
"inbound",
|
|
139
|
+
"mute",
|
|
140
|
+
"dtmf",
|
|
141
|
+
"hold",
|
|
142
|
+
"blind_transfer"
|
|
143
|
+
], S = {
|
|
144
|
+
available: {
|
|
145
|
+
status: "Available",
|
|
146
|
+
reason: "空闲"
|
|
147
|
+
},
|
|
148
|
+
break: {
|
|
149
|
+
status: "On Break",
|
|
150
|
+
reason: "休息"
|
|
151
|
+
},
|
|
152
|
+
offline: {
|
|
153
|
+
status: "Logged Out",
|
|
154
|
+
reason: ""
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
function C(t) {
|
|
158
|
+
let n = w(t.host), r = T(t.pathPrefix ?? l), i = `${n}${r}${E(t.accountPath ?? u)}`, a = `${n}${r}${E(t.statusPath ?? d)}`, o = E(t.sipWsPath ?? f), c = {
|
|
159
|
+
...t.aesKey ? { key: t.aesKey } : {},
|
|
160
|
+
...t.aesIv ? { iv: t.aesIv } : {}
|
|
161
|
+
}, b = Math.max(0, t.refreshBufferSeconds ?? _), C = t.fetchImpl ?? globalThis.fetch, j, M;
|
|
162
|
+
async function N() {
|
|
163
|
+
if (t.getToken !== void 0) return t.getToken();
|
|
164
|
+
if (t.tokenUrl !== void 0) {
|
|
165
|
+
let n = t.tokenMethod ?? "POST", r = {
|
|
166
|
+
method: n,
|
|
167
|
+
headers: {
|
|
168
|
+
Accept: "application/json",
|
|
169
|
+
...t.tokenHeaders ?? {}
|
|
170
|
+
},
|
|
171
|
+
credentials: "include"
|
|
172
|
+
};
|
|
173
|
+
n === "POST" && (r.headers = {
|
|
174
|
+
"Content-Type": "application/json",
|
|
175
|
+
...r.headers
|
|
176
|
+
}, r.body = JSON.stringify(t.tokenBody ?? {}));
|
|
177
|
+
let i = await A(C, t.tokenUrl, r, "取 token"), a = await i.text();
|
|
178
|
+
try {
|
|
179
|
+
return JSON.parse(a);
|
|
180
|
+
} catch {
|
|
181
|
+
throw new e("AUTH_TOKEN_UNAVAILABLE", "auth", !0, {
|
|
182
|
+
status: i.status,
|
|
183
|
+
cause: `取 token 的接口返回了非 JSON 响应(HTTP ${i.status}):${a.trim().slice(0, 120)}`
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
throw new e("CONFIG_INVALID", "configuration", !1, { cause: "createLegacySessionProvider 需要 getToken 或 tokenUrl" });
|
|
188
|
+
}
|
|
189
|
+
async function P() {
|
|
190
|
+
if (j && j.expiresAtMs - Date.now() > y) return j.token;
|
|
191
|
+
let t;
|
|
192
|
+
try {
|
|
193
|
+
t = await N();
|
|
194
|
+
} catch (t) {
|
|
195
|
+
throw t instanceof e ? t : new e("AUTH_TOKEN_UNAVAILABLE", "auth", !0, { cause: t });
|
|
196
|
+
}
|
|
197
|
+
let n = k(t);
|
|
198
|
+
if (!n.token) throw new e("AUTH_TOKEN_UNAVAILABLE", "auth", !0, { cause: "取 token 的返回里没有 token(支持 {token}、{accessToken}、{data:{token}} 或裸字符串)" });
|
|
199
|
+
let r = O(n.expires, 3600);
|
|
200
|
+
return j = {
|
|
201
|
+
token: n.token,
|
|
202
|
+
expiresAtMs: Date.now() + r * 1e3
|
|
203
|
+
}, j.token;
|
|
204
|
+
}
|
|
205
|
+
async function F() {
|
|
206
|
+
let t = await P(), n = await A(C, i, {
|
|
207
|
+
method: "POST",
|
|
208
|
+
headers: {
|
|
209
|
+
Authorization: t,
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
Accept: "application/json"
|
|
212
|
+
},
|
|
213
|
+
body: "{}"
|
|
214
|
+
}, "取坐席账号"), r = await n.text(), a;
|
|
215
|
+
try {
|
|
216
|
+
a = JSON.parse(r);
|
|
217
|
+
} catch {
|
|
218
|
+
throw new e("LEGACY_PLATFORM_UNREACHABLE", "network", !0, {
|
|
219
|
+
status: n.status,
|
|
220
|
+
cause: `${i} 返回了非 JSON 响应(HTTP ${n.status});请确认 host 填的是接口网关(不是文档站)`
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
let o = Number(a.code ?? NaN);
|
|
224
|
+
if (!n.ok || o !== 0) throw new e("LEGACY_PLATFORM_REJECTED", "auth", o === 50, {
|
|
225
|
+
status: n.status,
|
|
226
|
+
serverCode: Number.isFinite(o) ? String(o) : void 0,
|
|
227
|
+
cause: a.message || `取坐席账号失败(HTTP ${n.status})`
|
|
228
|
+
});
|
|
229
|
+
if (!a.data) throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "坐席账号接口没有返回 data" });
|
|
230
|
+
return M = a.data, M;
|
|
231
|
+
}
|
|
232
|
+
let I = (e) => s(e, c);
|
|
233
|
+
function L(r, i) {
|
|
234
|
+
let a = Number(r.wssPort) || p, s = String(r.domain ?? "").trim(), c = String(t.sipWsUrl ?? "").trim(), l;
|
|
235
|
+
if (c) l = new URL(c, n), l.protocol === "http:" && (l.protocol = "ws:"), l.protocol === "https:" && (l.protocol = "wss:");
|
|
236
|
+
else {
|
|
237
|
+
if (!s) throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "坐席账号里没有 domain,无法拼软电话地址;可用 sipWsUrl 显式指定" });
|
|
238
|
+
let t = a === 443 ? "" : `:${a}`;
|
|
239
|
+
l = new URL(`wss://${s}${t}${o}`);
|
|
240
|
+
}
|
|
241
|
+
return (t.attachTokenToWss ?? !0) && i && l.searchParams.set("token", i), l.toString();
|
|
242
|
+
}
|
|
243
|
+
function R(e) {
|
|
244
|
+
let t = (Array.isArray(e.iceServers) ? e.iceServers : []).map((e) => {
|
|
245
|
+
let t = (Array.isArray(e?.urls) ? e.urls : typeof e?.urls == "string" ? [e.urls] : []).map((e) => String(e ?? "").trim()).filter(Boolean);
|
|
246
|
+
if (t.length !== 0) return {
|
|
247
|
+
urls: t,
|
|
248
|
+
...e?.username ? { username: String(e.username) } : {},
|
|
249
|
+
...e?.credential ? { credential: String(e.credential) } : {}
|
|
250
|
+
};
|
|
251
|
+
}).filter((e) => e !== void 0);
|
|
252
|
+
if (t.length > 0) return t;
|
|
253
|
+
let n = String(e.turnIp ?? "").trim();
|
|
254
|
+
return n ? [{ urls: [`stun:${n}:${Number(e.turnPort) || m}`] }] : [];
|
|
255
|
+
}
|
|
256
|
+
async function z() {
|
|
257
|
+
let r = await P(), i = await F(), a = String(i.username ?? i.account ?? "").trim();
|
|
258
|
+
if (!a) throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "坐席账号里没有 username" });
|
|
259
|
+
let o = String(i.registerPassword ?? i.password ?? ""), s = o ? await I(o) : "";
|
|
260
|
+
if (!s) throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "坐席账号里没有 password/registerPassword,或解密后为空" });
|
|
261
|
+
let c = O(i.expiresIn ?? i.expires_in, g), l = Math.max(0, Math.round((j.expiresAtMs - Date.now()) / 1e3)), u = Math.max(v, Math.min(l || c, c) - b), d = String(i.domain ?? "").trim() || D(n), f = L(i, r);
|
|
262
|
+
return {
|
|
263
|
+
sessionId: `legacy-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
264
|
+
expiresAt: Math.floor(Date.now() / 1e3) + u,
|
|
265
|
+
agent: {
|
|
266
|
+
id: a,
|
|
267
|
+
externalUserId: a,
|
|
268
|
+
displayName: a,
|
|
269
|
+
extension: a,
|
|
270
|
+
status: "Available"
|
|
271
|
+
},
|
|
272
|
+
sip: {
|
|
273
|
+
uri: `sip:${a}@${d}`,
|
|
274
|
+
registrar: d,
|
|
275
|
+
registerTicket: s,
|
|
276
|
+
registerExpires: Number(t.registerExpires) > 0 ? Number(t.registerExpires) : h,
|
|
277
|
+
ticketExpiresIn: u
|
|
278
|
+
},
|
|
279
|
+
transport: {
|
|
280
|
+
wssUrl: f,
|
|
281
|
+
ticket: "",
|
|
282
|
+
ticketExpiresIn: u
|
|
283
|
+
},
|
|
284
|
+
iceServers: R(i),
|
|
285
|
+
policy: {
|
|
286
|
+
maxConcurrentCalls: Number(t.maxConcurrentCalls) > 0 ? Number(t.maxConcurrentCalls) : 2,
|
|
287
|
+
incomingEnabled: t.incomingEnabled ?? !0,
|
|
288
|
+
mobileIncomingEnabled: t.mobileIncomingEnabled ?? !0,
|
|
289
|
+
backgroundCallingSupported: !1
|
|
290
|
+
},
|
|
291
|
+
capabilities: [...t.capabilities ?? x]
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
createSession: z,
|
|
296
|
+
refreshSession: z,
|
|
297
|
+
setAgentStatus: async ({ status: t, reason: n }) => {
|
|
298
|
+
let r = M ?? await F(), i = String(r.username ?? r.account ?? "").trim();
|
|
299
|
+
if (!i) throw new e("LEGACY_PLATFORM_REJECTED", "auth", !1, { cause: "坐席账号里没有 username" });
|
|
300
|
+
let o = S[t], s = await P(), c = await A(C, a, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: {
|
|
303
|
+
Authorization: s,
|
|
304
|
+
"Content-Type": "application/json",
|
|
305
|
+
Accept: "application/json"
|
|
306
|
+
},
|
|
307
|
+
body: JSON.stringify({
|
|
308
|
+
extension: i,
|
|
309
|
+
status: o.status,
|
|
310
|
+
reason: n || o.reason
|
|
311
|
+
})
|
|
312
|
+
}, "设置坐席状态"), l = await c.text(), u;
|
|
313
|
+
try {
|
|
314
|
+
u = JSON.parse(l);
|
|
315
|
+
} catch {
|
|
316
|
+
throw new e("LEGACY_PLATFORM_UNREACHABLE", "network", !0, {
|
|
317
|
+
status: c.status,
|
|
318
|
+
cause: `${a} 返回了非 JSON 响应(HTTP ${c.status})`
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
let d = Number(u.code ?? NaN);
|
|
322
|
+
if (!c.ok || d !== 0) throw new e("LEGACY_PLATFORM_REJECTED", "auth", d === 50, {
|
|
323
|
+
status: c.status,
|
|
324
|
+
serverCode: Number.isFinite(d) ? String(d) : void 0,
|
|
325
|
+
cause: u.message || `设置坐席状态失败(HTTP ${c.status})`
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
invalidateToken: () => {
|
|
329
|
+
j = void 0;
|
|
330
|
+
},
|
|
331
|
+
getSeatAccount: async () => M ?? F()
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function w(t) {
|
|
335
|
+
let n = String(t ?? "").trim().replace(/\/+$/, "");
|
|
336
|
+
if (!n) throw new e("CONFIG_INVALID", "configuration", !1, { cause: "createLegacySessionProvider 需要 host" });
|
|
337
|
+
return /^https?:\/\//i.test(n) ? n : `https://${n}`;
|
|
338
|
+
}
|
|
339
|
+
function T(e) {
|
|
340
|
+
let t = String(e ?? "").trim();
|
|
341
|
+
return !t || t === "/" ? "" : `/${t.replace(/^\/+|\/+$/g, "")}`;
|
|
342
|
+
}
|
|
343
|
+
function E(e) {
|
|
344
|
+
let t = String(e ?? "").trim();
|
|
345
|
+
return t.startsWith("/") ? t : `/${t}`;
|
|
346
|
+
}
|
|
347
|
+
function D(e) {
|
|
348
|
+
try {
|
|
349
|
+
return new URL(e).hostname;
|
|
350
|
+
} catch {
|
|
351
|
+
return "";
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function O(e, t) {
|
|
355
|
+
let n = Number(e);
|
|
356
|
+
return !Number.isFinite(n) || n <= 0 ? t : (n > 86400 && (n /= 1e3), Math.min(Math.max(Math.floor(n), v), 86400));
|
|
357
|
+
}
|
|
358
|
+
function k(e) {
|
|
359
|
+
if (typeof e == "string") return { token: e.trim() };
|
|
360
|
+
let t = e ?? {}, n = typeof t.data == "object" && t.data !== null ? t.data : void 0;
|
|
361
|
+
for (let e of [t, n]) {
|
|
362
|
+
if (e === void 0) continue;
|
|
363
|
+
let t = e.token ?? e.accessToken;
|
|
364
|
+
if (typeof t == "string" && t.trim()) {
|
|
365
|
+
let n = Number(e.expires ?? e.expiresIn ?? e.expires_at);
|
|
366
|
+
return {
|
|
367
|
+
token: t.trim(),
|
|
368
|
+
...Number.isFinite(n) && n > 0 ? { expires: n } : {}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return { token: "" };
|
|
373
|
+
}
|
|
374
|
+
async function A(t, n, r, i) {
|
|
375
|
+
let a = new AbortController(), o = setTimeout(() => a.abort(), b);
|
|
376
|
+
try {
|
|
377
|
+
return await t(n, {
|
|
378
|
+
...r,
|
|
379
|
+
signal: a.signal
|
|
380
|
+
});
|
|
381
|
+
} catch (t) {
|
|
382
|
+
let r = a.signal.aborted;
|
|
383
|
+
throw new e(r ? "NETWORK_TIMEOUT" : "LEGACY_PLATFORM_UNREACHABLE", "network", !0, { cause: r ? `${i}超时(${b / 1e3} 秒):POST ${n}` : `${i}失败:无法请求 ${n}(${t instanceof Error ? t.message : String(t)})` });
|
|
384
|
+
} finally {
|
|
385
|
+
clearTimeout(o);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
//#endregion
|
|
104
389
|
//#region src/legacy/index.ts
|
|
105
|
-
var
|
|
390
|
+
var j = "0.1.0";
|
|
106
391
|
typeof window < "u" && (window.CCBarSDK = r);
|
|
107
392
|
//#endregion
|
|
108
|
-
export { r as CCBarSDK, n as DeprecatedError,
|
|
393
|
+
export { r as CCBarSDK, n as DeprecatedError, C as createLegacySessionProvider, s as decryptSipPassword, j as legacyVersion };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 老平台坐席密码的解密:`seat/account/get` 返回的 `password`(或 `registerPassword`)
|
|
3
|
+
* 是 **AES-128-CBC / Pkcs7 的密文,Base64 编码**,需要解密才有明文 SIP 密码。
|
|
4
|
+
*
|
|
5
|
+
* key/iv 各 16 字节,老平台是固定值(旧版 `ccbar.js` 里同样是硬编码),可用 options 覆盖。
|
|
6
|
+
* 在浏览器与 Node 里都能用(走 WebCrypto,无需额外依赖;需要安全上下文或 Node 18+)。
|
|
7
|
+
*/
|
|
8
|
+
export interface DecryptSipPasswordOptions {
|
|
9
|
+
/** AES key(16 字节,UTF-8),默认用老平台内置值 */
|
|
10
|
+
key?: string;
|
|
11
|
+
/** AES iv(16 字节,UTF-8),默认用老平台内置值 */
|
|
12
|
+
iv?: string;
|
|
13
|
+
/** 解密实现所用的 WebCrypto(测试可注入),默认全局 crypto.subtle */
|
|
14
|
+
subtle?: SubtleCrypto;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 解出 SIP 密码明文。
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { decryptSipPassword } from '@16x/webphone-sdk/legacy';
|
|
21
|
+
*
|
|
22
|
+
* const res = await fetch(`${host}/openapi/token/v1/seat/account/get`, { method: 'POST', headers: { Authorization: token }, body: '{}' });
|
|
23
|
+
* const { data } = await res.json();
|
|
24
|
+
* const password = await decryptSipPassword(data.password); // 明文 SIP 密码
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* 失败时抛 `CCBarError`:可读原因在 `error.cause` 上(密文为空 / 不是合法 Base64 / 解密失败)。
|
|
28
|
+
*/
|
|
29
|
+
export declare function decryptSipPassword(cipherText: string, options?: DecryptSipPasswordOptions): Promise<string>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { SessionProvider } from '../core/CCBarClient.js';
|
|
2
|
+
/** 换票结果:`{ token, expires }`、`{ accessToken, expires }`、`{ data: {...} }` 或裸字符串都能接 */
|
|
3
|
+
export type LegacyTokenResult = string | {
|
|
4
|
+
token?: string;
|
|
5
|
+
accessToken?: string;
|
|
6
|
+
expires?: number;
|
|
7
|
+
data?: unknown;
|
|
8
|
+
};
|
|
9
|
+
export interface LegacySeatAccount {
|
|
10
|
+
username?: string;
|
|
11
|
+
account?: string;
|
|
12
|
+
customerPrefix?: string;
|
|
13
|
+
extension?: string;
|
|
14
|
+
password?: string;
|
|
15
|
+
registerPassword?: string;
|
|
16
|
+
expiresIn?: number;
|
|
17
|
+
expires_in?: number;
|
|
18
|
+
domain?: string;
|
|
19
|
+
wsPort?: number;
|
|
20
|
+
wssPort?: number;
|
|
21
|
+
turnIp?: string;
|
|
22
|
+
turnPort?: number;
|
|
23
|
+
iceServers?: Array<{
|
|
24
|
+
urls?: string[] | string;
|
|
25
|
+
username?: string;
|
|
26
|
+
credential?: string;
|
|
27
|
+
}>;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
export interface LegacyPlatformSessionProviderOptions {
|
|
31
|
+
/** 平台网关地址,例如 `https://vxapi.yundianlab.com`(不含路径前缀);必填 */
|
|
32
|
+
host: string;
|
|
33
|
+
/** 取 token 的两种写法二选一:函数(接入方自己调) */
|
|
34
|
+
getToken?: () => LegacyTokenResult | Promise<LegacyTokenResult>;
|
|
35
|
+
/** 取 token 的两种写法二选一:地址(SDK 去 POST 这个地址,通常是接入方自己的接口) */
|
|
36
|
+
tokenUrl?: string;
|
|
37
|
+
/** tokenUrl 的请求方法,默认 POST */
|
|
38
|
+
tokenMethod?: 'GET' | 'POST';
|
|
39
|
+
/** tokenUrl 的请求体(POST 时 JSON 发送),默认 {} */
|
|
40
|
+
tokenBody?: Record<string, unknown>;
|
|
41
|
+
/** tokenUrl 的额外请求头 */
|
|
42
|
+
tokenHeaders?: Record<string, string>;
|
|
43
|
+
/** 路径前缀,默认 `/openapi/token/v1` */
|
|
44
|
+
pathPrefix?: string;
|
|
45
|
+
/** 坐席账号路径(相对 pathPrefix),默认 `/seat/account/get` */
|
|
46
|
+
accountPath?: string;
|
|
47
|
+
/** 坐席状态路径(相对 pathPrefix),默认 `/seats/set-status` */
|
|
48
|
+
statusPath?: string;
|
|
49
|
+
/** 软电话路径,默认 `/api/fs/sip-ws` */
|
|
50
|
+
sipWsPath?: string;
|
|
51
|
+
/** 显式指定 WSS 地址(覆盖按 domain/wssPort 拼装),可以是相对路径 */
|
|
52
|
+
sipWsUrl?: string;
|
|
53
|
+
/** 是否把 token 挂到 WSS 的 `?token=`,默认 true(旧页面那套不挂时可设 false) */
|
|
54
|
+
attachTokenToWss?: boolean;
|
|
55
|
+
/** AES key / iv(16 字节,UTF-8);默认用平台内置值 */
|
|
56
|
+
aesKey?: string;
|
|
57
|
+
aesIv?: string;
|
|
58
|
+
/** REGISTER 有效期(秒),默认 600 */
|
|
59
|
+
registerExpires?: number;
|
|
60
|
+
/** 会话 TTL 的提前换票缓冲(秒),默认 180 */
|
|
61
|
+
refreshBufferSeconds?: number;
|
|
62
|
+
/** 并发上限,默认 2(移动端形态下 SDK 也会压到 1) */
|
|
63
|
+
maxConcurrentCalls?: number;
|
|
64
|
+
/** 是否允许接来电(总闸),默认 true */
|
|
65
|
+
incomingEnabled?: boolean;
|
|
66
|
+
/** 移动端是否允许接来电,默认 true(桌面形态不看这一项) */
|
|
67
|
+
mobileIncomingEnabled?: boolean;
|
|
68
|
+
/** 能力白名单,默认老平台六项 */
|
|
69
|
+
capabilities?: string[];
|
|
70
|
+
/** 请求实现(测试/代理场景可替换),默认全局 fetch */
|
|
71
|
+
fetchImpl?: typeof fetch;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 造一个会话来源:`new CCBarClient({ sessionProvider: createLegacySessionProvider({...}) })`。
|
|
75
|
+
* `refreshSession` 与 `createSession` 等价——整条链路重跑一遍,等价于换一次 SIP 密码。
|
|
76
|
+
*/
|
|
77
|
+
export declare function createLegacySessionProvider(options: LegacyPlatformSessionProviderOptions): SessionProvider & {
|
|
78
|
+
getSeatAccount(): Promise<LegacySeatAccount>;
|
|
79
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -58,7 +58,11 @@ export interface MediaManager {
|
|
|
58
58
|
releaseAll(): Promise<void>;
|
|
59
59
|
}
|
|
60
60
|
export type CCBarErrorCategory = 'auth' | 'configuration' | 'network' | 'registration' | 'media' | 'call' | 'capability' | 'internal';
|
|
61
|
-
export type CCBarErrorCode = 'AUTH_TOKEN_UNAVAILABLE' | 'AUTH_TOKEN_EXPIRED' | 'AUTH_PERMISSION_DENIED' | 'CONFIG_INVALID' | 'CONFIG_ORIGIN_NOT_ALLOWED' | 'NETWORK_OFFLINE' | 'NETWORK_TIMEOUT' | 'SIP_WS_UNAVAILABLE' | 'REGISTRATION_FAILED' | 'REGISTRATION_REJECTED' | 'MEDIA_PERMISSION_DENIED' | 'MEDIA_DEVICE_NOT_FOUND' | 'MEDIA_DEVICE_IN_USE' | 'MEDIA_PLAYBACK_BLOCKED' | 'CALL_INVALID_DESTINATION' | 'CALL_INVALID_USERDATA' | 'CALL_ALREADY_EXISTS' | 'CALL_REJECTED' | 'CALL_BUSY' | 'CALL_NOT_CONNECTED' | 'CALL_OPERATION_NOT_ALLOWED' | 'CAPABILITY_NOT_SUPPORTED' | 'H5_BACKGROUND_NOT_SUPPORTED' | 'SDK_ALREADY_DISPOSED' | 'SDK_INTERNAL_ERROR'
|
|
61
|
+
export type CCBarErrorCode = 'AUTH_TOKEN_UNAVAILABLE' | 'AUTH_TOKEN_EXPIRED' | 'AUTH_PERMISSION_DENIED' | 'CONFIG_INVALID' | 'CONFIG_ORIGIN_NOT_ALLOWED' | 'NETWORK_OFFLINE' | 'NETWORK_TIMEOUT' | 'SIP_WS_UNAVAILABLE' | 'REGISTRATION_FAILED' | 'REGISTRATION_REJECTED' | 'MEDIA_PERMISSION_DENIED' | 'MEDIA_DEVICE_NOT_FOUND' | 'MEDIA_DEVICE_IN_USE' | 'MEDIA_PLAYBACK_BLOCKED' | 'CALL_INVALID_DESTINATION' | 'CALL_INVALID_USERDATA' | 'CALL_ALREADY_EXISTS' | 'CALL_REJECTED' | 'CALL_BUSY' | 'CALL_NOT_CONNECTED' | 'CALL_OPERATION_NOT_ALLOWED' | 'CAPABILITY_NOT_SUPPORTED' | 'H5_BACKGROUND_NOT_SUPPORTED' | 'SDK_ALREADY_DISPOSED' | 'SDK_INTERNAL_ERROR'
|
|
62
|
+
/** 老平台接口(seat/account/get、seats/set-status)不可达:网络失败、超时或返回非 JSON */
|
|
63
|
+
| 'LEGACY_PLATFORM_UNREACHABLE'
|
|
64
|
+
/** 老平台接口返回了业务错误(code != 0)或缺少必需字段;平台的 code 在 error.serverCode 上 */
|
|
65
|
+
| 'LEGACY_PLATFORM_REJECTED';
|
|
62
66
|
export interface ConnectionStateEvent {
|
|
63
67
|
state: 'offline' | 'connecting' | 'connected' | 'reconnecting' | 'failed';
|
|
64
68
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "4.
|
|
1
|
+
export declare const SDK_VERSION = "4.1.0";
|
package/package.json
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@16x/webphone-sdk",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"homepage": "https://www.npmjs.com/package/@16x/webphone-sdk",
|
|
5
|
-
"private": false,
|
|
6
|
-
"license": "UNLICENSED",
|
|
7
|
-
"publishConfig": {
|
|
8
|
-
"access": "public",
|
|
9
|
-
"registry": "https://registry.npmjs.org"
|
|
10
|
-
},
|
|
11
|
-
"type": "module",
|
|
12
|
-
"sideEffects": [
|
|
13
|
-
"./dist/styles.css"
|
|
14
|
-
],
|
|
15
|
-
"files": [
|
|
16
|
-
"dist/index.js",
|
|
17
|
-
"dist/index.cjs",
|
|
18
|
-
"dist/index.umd.js",
|
|
19
|
-
"dist/*.js",
|
|
20
|
-
"dist/*.cjs",
|
|
21
|
-
"dist/index.d.ts",
|
|
22
|
-
"dist/types.d.ts",
|
|
23
|
-
"dist/version.d.ts",
|
|
24
|
-
"dist/errors",
|
|
25
|
-
"dist/events",
|
|
26
|
-
"dist/state",
|
|
27
|
-
"dist/api",
|
|
28
|
-
"dist/core",
|
|
29
|
-
"dist/shared",
|
|
30
|
-
"dist/ui",
|
|
31
|
-
"dist/legacy",
|
|
32
|
-
"dist/diagnostics",
|
|
33
|
-
"dist/shared-worker.js",
|
|
34
|
-
"dist/shared-worker.d.ts",
|
|
35
|
-
"dist/styles.css",
|
|
36
|
-
"README.md",
|
|
37
|
-
"LICENSE",
|
|
38
|
-
"CHANGELOG.md"
|
|
39
|
-
],
|
|
40
|
-
"exports": {
|
|
41
|
-
".": {
|
|
42
|
-
"types": "./dist/index.d.ts",
|
|
43
|
-
"import": "./dist/index.js",
|
|
44
|
-
"require": "./dist/index.cjs"
|
|
45
|
-
},
|
|
46
|
-
"./ui": {
|
|
47
|
-
"types": "./dist/ui/index.d.ts",
|
|
48
|
-
"import": "./dist/ui/index.js",
|
|
49
|
-
"require": "./dist/ui/index.cjs"
|
|
50
|
-
},
|
|
51
|
-
"./legacy": {
|
|
52
|
-
"types": "./dist/legacy/index.d.ts",
|
|
53
|
-
"import": "./dist/legacy/index.js",
|
|
54
|
-
"require": "./dist/legacy/index.cjs"
|
|
55
|
-
},
|
|
56
|
-
"./diagnostics": {
|
|
57
|
-
"types": "./dist/diagnostics/index.d.ts",
|
|
58
|
-
"import": "./dist/diagnostics/index.js",
|
|
59
|
-
"require": "./dist/diagnostics/index.cjs"
|
|
60
|
-
},
|
|
61
|
-
"./shared-worker": {
|
|
62
|
-
"types": "./dist/shared-worker.d.ts",
|
|
63
|
-
"import": "./dist/shared-worker.js"
|
|
64
|
-
},
|
|
65
|
-
"./styles.css": "./dist/styles.css"
|
|
66
|
-
},
|
|
67
|
-
"scripts": {
|
|
68
|
-
"build": "vite build && vite build -c vite.umd.config.ts",
|
|
69
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
70
|
-
"test": "npm run build && npm run docs:build && vitest run",
|
|
71
|
-
"lint": "eslint .",
|
|
72
|
-
"pack:check": "node scripts/check-package.mjs",
|
|
73
|
-
"sbom": "node scripts/generate-sbom.mjs",
|
|
74
|
-
"release:artifacts": "node scripts/generate-release-artifacts.mjs",
|
|
75
|
-
"check:node-next": "npm run build && node scripts/check-node-next-consumer.mjs",
|
|
76
|
-
"verify:bundle": "node scripts/check-bundle-size.mjs",
|
|
77
|
-
"verify:memory": "node scripts/run-memory-soak.mjs",
|
|
78
|
-
"verify:call-soak": "node scripts/run-call-soak.mjs",
|
|
79
|
-
"verify:hour-soak": "node scripts/run-browser-call-soak.mjs",
|
|
80
|
-
"verify:staged": "npm run verify:memory && npm run verify:call-soak",
|
|
81
|
-
"docs:build": "node scripts/build-docs-site.mjs",
|
|
82
|
-
"docs:check": "node scripts/check-docs-site.mjs",
|
|
83
|
-
"docs:test": "npm run docs:build && npx vitest run tests/docs-site/static-site.test.ts tests/docs-site/navigation.test.ts tests/docs-site/check-docs-site.test.ts",
|
|
84
|
-
"docs:release": "npm run customer:packages && npm run docs:build && node scripts/create-integration-package.mjs && npm run docs:build && npm run docs:check",
|
|
85
|
-
"customer:packages": "node scripts/create-customer-packages.mjs",
|
|
86
|
-
"publish:npm": "bash scripts/publish-npm.sh",
|
|
87
|
-
"verify:release": "npm run lint && npm run typecheck && npm test && npm run build && npm run verify:bundle && npm run pack:check && npm run sbom"
|
|
88
|
-
},
|
|
89
|
-
"dependencies": {
|
|
90
|
-
"jssip": "3.10.1"
|
|
91
|
-
},
|
|
92
|
-
"devDependencies": {
|
|
93
|
-
"@eslint/js": "^10.0.1",
|
|
94
|
-
"@types/react": "^19.3.0",
|
|
95
|
-
"@types/react-dom": "^19.3.0",
|
|
96
|
-
"@vitejs/plugin-react": "^6.1.1",
|
|
97
|
-
"@vitejs/plugin-vue": "^6.0.9",
|
|
98
|
-
"eslint": "^10.10.0",
|
|
99
|
-
"happy-dom": "^20.14.5",
|
|
100
|
-
"react": "^19.3.0",
|
|
101
|
-
"react-dom": "^19.3.0",
|
|
102
|
-
"typescript": "^6.0.3",
|
|
103
|
-
"typescript-eslint": "^8.70.0",
|
|
104
|
-
"vite": "^8.3.0",
|
|
105
|
-
"vite-plugin-dts": "^5.1.0",
|
|
106
|
-
"vitest": "^5.0.1",
|
|
107
|
-
"vue": "^3.5.43"
|
|
108
|
-
}
|
|
109
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@16x/webphone-sdk",
|
|
3
|
+
"version": "4.1.0",
|
|
4
|
+
"homepage": "https://www.npmjs.com/package/@16x/webphone-sdk",
|
|
5
|
+
"private": false,
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public",
|
|
9
|
+
"registry": "https://registry.npmjs.org"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": [
|
|
13
|
+
"./dist/styles.css"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/index.js",
|
|
17
|
+
"dist/index.cjs",
|
|
18
|
+
"dist/index.umd.js",
|
|
19
|
+
"dist/*.js",
|
|
20
|
+
"dist/*.cjs",
|
|
21
|
+
"dist/index.d.ts",
|
|
22
|
+
"dist/types.d.ts",
|
|
23
|
+
"dist/version.d.ts",
|
|
24
|
+
"dist/errors",
|
|
25
|
+
"dist/events",
|
|
26
|
+
"dist/state",
|
|
27
|
+
"dist/api",
|
|
28
|
+
"dist/core",
|
|
29
|
+
"dist/shared",
|
|
30
|
+
"dist/ui",
|
|
31
|
+
"dist/legacy",
|
|
32
|
+
"dist/diagnostics",
|
|
33
|
+
"dist/shared-worker.js",
|
|
34
|
+
"dist/shared-worker.d.ts",
|
|
35
|
+
"dist/styles.css",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"CHANGELOG.md"
|
|
39
|
+
],
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"import": "./dist/index.js",
|
|
44
|
+
"require": "./dist/index.cjs"
|
|
45
|
+
},
|
|
46
|
+
"./ui": {
|
|
47
|
+
"types": "./dist/ui/index.d.ts",
|
|
48
|
+
"import": "./dist/ui/index.js",
|
|
49
|
+
"require": "./dist/ui/index.cjs"
|
|
50
|
+
},
|
|
51
|
+
"./legacy": {
|
|
52
|
+
"types": "./dist/legacy/index.d.ts",
|
|
53
|
+
"import": "./dist/legacy/index.js",
|
|
54
|
+
"require": "./dist/legacy/index.cjs"
|
|
55
|
+
},
|
|
56
|
+
"./diagnostics": {
|
|
57
|
+
"types": "./dist/diagnostics/index.d.ts",
|
|
58
|
+
"import": "./dist/diagnostics/index.js",
|
|
59
|
+
"require": "./dist/diagnostics/index.cjs"
|
|
60
|
+
},
|
|
61
|
+
"./shared-worker": {
|
|
62
|
+
"types": "./dist/shared-worker.d.ts",
|
|
63
|
+
"import": "./dist/shared-worker.js"
|
|
64
|
+
},
|
|
65
|
+
"./styles.css": "./dist/styles.css"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "vite build && vite build -c vite.umd.config.ts",
|
|
69
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
70
|
+
"test": "npm run build && npm run docs:build && vitest run",
|
|
71
|
+
"lint": "eslint .",
|
|
72
|
+
"pack:check": "node scripts/check-package.mjs",
|
|
73
|
+
"sbom": "node scripts/generate-sbom.mjs",
|
|
74
|
+
"release:artifacts": "node scripts/generate-release-artifacts.mjs",
|
|
75
|
+
"check:node-next": "npm run build && node scripts/check-node-next-consumer.mjs",
|
|
76
|
+
"verify:bundle": "node scripts/check-bundle-size.mjs",
|
|
77
|
+
"verify:memory": "node scripts/run-memory-soak.mjs",
|
|
78
|
+
"verify:call-soak": "node scripts/run-call-soak.mjs",
|
|
79
|
+
"verify:hour-soak": "node scripts/run-browser-call-soak.mjs",
|
|
80
|
+
"verify:staged": "npm run verify:memory && npm run verify:call-soak",
|
|
81
|
+
"docs:build": "node scripts/build-docs-site.mjs",
|
|
82
|
+
"docs:check": "node scripts/check-docs-site.mjs",
|
|
83
|
+
"docs:test": "npm run docs:build && npx vitest run tests/docs-site/static-site.test.ts tests/docs-site/navigation.test.ts tests/docs-site/check-docs-site.test.ts",
|
|
84
|
+
"docs:release": "npm run customer:packages && npm run docs:build && node scripts/create-integration-package.mjs && npm run docs:build && npm run docs:check",
|
|
85
|
+
"customer:packages": "node scripts/create-customer-packages.mjs",
|
|
86
|
+
"publish:npm": "bash scripts/publish-npm.sh",
|
|
87
|
+
"verify:release": "npm run lint && npm run typecheck && npm test && npm run build && npm run verify:bundle && npm run pack:check && npm run sbom"
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"jssip": "3.10.1"
|
|
91
|
+
},
|
|
92
|
+
"devDependencies": {
|
|
93
|
+
"@eslint/js": "^10.0.1",
|
|
94
|
+
"@types/react": "^19.3.0",
|
|
95
|
+
"@types/react-dom": "^19.3.0",
|
|
96
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
97
|
+
"@vitejs/plugin-vue": "^6.0.9",
|
|
98
|
+
"eslint": "^10.10.0",
|
|
99
|
+
"happy-dom": "^20.14.5",
|
|
100
|
+
"react": "^19.3.0",
|
|
101
|
+
"react-dom": "^19.3.0",
|
|
102
|
+
"typescript": "^6.0.3",
|
|
103
|
+
"typescript-eslint": "^8.70.0",
|
|
104
|
+
"vite": "^8.3.0",
|
|
105
|
+
"vite-plugin-dts": "^5.1.0",
|
|
106
|
+
"vitest": "^5.0.1",
|
|
107
|
+
"vue": "^3.5.43"
|
|
108
|
+
}
|
|
109
|
+
}
|