@koi-design/callkit 2.0.3 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -55,32 +55,44 @@ interface SocketConfig {
55
55
  enabled: boolean;
56
56
  maxAttempts: number;
57
57
  delay: number;
58
- backoffMultiplier: number;
59
58
  pingInterval: number;
60
59
  pingTimeout: number;
61
- maxConnectsPerWindow?: number;
62
- timeWindow?: number;
63
60
  }
64
61
  declare class Socket {
65
62
  private callKit;
66
63
  private ws?;
67
- private socketConfig;
68
64
  lastPingTime: any;
69
- isConnected: boolean;
70
65
  pingTimer?: ReturnType<typeof setInterval>;
71
- satrtConfirm: boolean;
66
+ /**
67
+ * @description reconnect timer
68
+ */
72
69
  private reconnectTimer?;
73
- private isReconnecting;
70
+ /**
71
+ * @description reconnect attempts
72
+ */
74
73
  private reconnectAttempts;
75
- private socketError;
76
- private connectAttemptTimes;
74
+ /**
75
+ * @description connect auth state
76
+ * @default {
77
+ * satrtConfirm: false,
78
+ * isConnected: false,
79
+ * isReconnecting: false,
80
+ * isAuthenticated: false,
81
+ * isError: false
82
+ * }
83
+ */
84
+ private connectAuthState;
85
+ get satrtConfirm(): boolean;
86
+ get isError(): boolean;
77
87
  constructor(callKit: CallKit);
78
88
  init(): void;
89
+ private getSocketConfig;
90
+ private setConnectAuthState;
79
91
  private handleDisconnect;
80
92
  private clearWebSocket;
81
93
  private connect;
82
94
  private onOpen;
83
- private resetReconnectState;
95
+ private resetConnectState;
84
96
  private onClose;
85
97
  private onError;
86
98
  private confirmAck;
@@ -91,7 +103,9 @@ declare class Socket {
91
103
  /**
92
104
  * reset socket connection and all states
93
105
  */
94
- reset(): Promise<void>;
106
+ reset(config?: {
107
+ focus?: boolean;
108
+ }): Promise<void>;
95
109
  private attemptReconnect;
96
110
  }
97
111
 
@@ -504,7 +518,6 @@ declare class CallKit {
504
518
  refer(uri: string, options?: any): Promise<void>;
505
519
  register(): Promise<void>;
506
520
  unregister(): Promise<void>;
507
- stop(): Promise<void>;
508
521
  hangup(): Promise<void>;
509
522
  hold(): void;
510
523
  unhold(): void;
@@ -515,6 +528,13 @@ declare class CallKit {
515
528
  * @param status
516
529
  */
517
530
  setUserStatus(status: number): Promise<void>;
531
+ protected _reset(config?: {
532
+ focus?: boolean;
533
+ }): Promise<void>;
534
+ /**
535
+ * reset callkit
536
+ * @description recover the callkit to the initial state
537
+ */
518
538
  reset(): Promise<void>;
519
539
  on(event: kitEventType, callback: (...args: any[]) => void): void;
520
540
  off(event: kitEventType, callback?: (...args: any[]) => void): void;
@@ -3810,12 +3810,13 @@ var WebCall = (() => {
3810
3810
  // package.json
3811
3811
  var package_default = {
3812
3812
  name: "@koi-design/callkit",
3813
- version: "2.0.3",
3813
+ version: "2.0.5",
3814
3814
  description: "callkit",
3815
3815
  author: "koi",
3816
3816
  license: "ISC",
3817
3817
  scripts: {
3818
3818
  build: "tsup",
3819
+ "build:w": "tsup --watch",
3819
3820
  dev: "vite",
3820
3821
  lint: "eslint -c ../../.eslintrc.js --ext .jsx,.js,.tsx,.ts ./package --fix",
3821
3822
  release: "tsup && node scripts/pkg.js"
@@ -19481,36 +19482,48 @@ var WebCall = (() => {
19481
19482
  var RECONNECT_CONFIG = {
19482
19483
  enabled: true,
19483
19484
  maxAttempts: 3,
19484
- delay: 500,
19485
- backoffMultiplier: 1.5,
19485
+ delay: 1e3,
19486
19486
  pingInterval: 3e4,
19487
- pingTimeout: 5e3,
19488
- maxConnectsPerWindow: 5,
19489
- timeWindow: 6e4
19490
- // 60 seconds
19487
+ pingTimeout: 5e3
19491
19488
  };
19492
19489
  var Socket = class {
19493
19490
  callKit;
19494
19491
  ws;
19495
- socketConfig;
19496
19492
  lastPingTime = void 0;
19497
- isConnected = false;
19498
19493
  pingTimer;
19499
- // Whether received start confirmation
19500
- satrtConfirm = false;
19494
+ /**
19495
+ * @description reconnect timer
19496
+ */
19501
19497
  reconnectTimer;
19502
- isReconnecting = false;
19498
+ /**
19499
+ * @description reconnect attempts
19500
+ */
19503
19501
  reconnectAttempts = 0;
19504
- socketError = false;
19505
- // Track connection attempts for rate limiting
19506
- connectAttemptTimes = [];
19502
+ /**
19503
+ * @description connect auth state
19504
+ * @default {
19505
+ * satrtConfirm: false,
19506
+ * isConnected: false,
19507
+ * isReconnecting: false,
19508
+ * isAuthenticated: false,
19509
+ * isError: false
19510
+ * }
19511
+ */
19512
+ connectAuthState = {
19513
+ satrtConfirm: false,
19514
+ isConnected: false,
19515
+ isReconnecting: false,
19516
+ isAuthenticated: false,
19517
+ isError: false
19518
+ };
19519
+ get satrtConfirm() {
19520
+ return this.connectAuthState.satrtConfirm;
19521
+ }
19522
+ get isError() {
19523
+ return this.connectAuthState.isError;
19524
+ }
19507
19525
  constructor(callKit) {
19508
19526
  this.callKit = callKit;
19509
- const { reconnect } = this.callKit.config.getConfig();
19510
- this.socketConfig = {
19511
- ...RECONNECT_CONFIG,
19512
- ...reconnect
19513
- };
19514
19527
  }
19515
19528
  init() {
19516
19529
  const { socket } = this.callKit.config.getConfig();
@@ -19523,16 +19536,29 @@ var WebCall = (() => {
19523
19536
  });
19524
19537
  this.connect(socket);
19525
19538
  }
19539
+ getSocketConfig() {
19540
+ const { reconnect } = this.callKit.config.getConfig();
19541
+ return {
19542
+ ...RECONNECT_CONFIG,
19543
+ ...reconnect
19544
+ };
19545
+ }
19546
+ setConnectAuthState(key, value) {
19547
+ if (this.connectAuthState[key] === value)
19548
+ return;
19549
+ this.connectAuthState[key] = value;
19550
+ }
19526
19551
  handleDisconnect() {
19527
- this.isConnected = false;
19528
- if (!this.callKit.config.isLogin() || !this.socketConfig.enabled) {
19529
- this.reset();
19552
+ this.setConnectAuthState("isConnected", false);
19553
+ const { enabled } = this.getSocketConfig();
19554
+ if (!this.callKit.config.isLogin() || !enabled) {
19555
+ this.callKit.reset();
19530
19556
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19531
19557
  event: "INCALL_NOT_CONNECTED"
19532
19558
  });
19533
19559
  return;
19534
19560
  }
19535
- if (this.isReconnecting) {
19561
+ if (this.connectAuthState.isReconnecting) {
19536
19562
  return;
19537
19563
  }
19538
19564
  this.attemptReconnect();
@@ -19553,13 +19579,12 @@ var WebCall = (() => {
19553
19579
  });
19554
19580
  }
19555
19581
  this.ws = void 0;
19556
- this.isConnected = false;
19582
+ this.setConnectAuthState("isConnected", false);
19557
19583
  }
19558
19584
  connect(socketUrl) {
19559
19585
  if (this.ws) {
19560
19586
  this.clearWebSocket();
19561
19587
  }
19562
- this.connectAttemptTimes.push(Date.now());
19563
19588
  this.ws = new WebSocket(socketUrl);
19564
19589
  this.ws.onopen = (ev) => this.onOpen(ev);
19565
19590
  this.ws.onclose = (ev) => this.onClose(ev);
@@ -19572,11 +19597,11 @@ var WebCall = (() => {
19572
19597
  type: "INCALL",
19573
19598
  content: { ev }
19574
19599
  });
19575
- this.socketError = false;
19576
- this.isConnected = true;
19600
+ this.setConnectAuthState("isConnected", true);
19577
19601
  this.lastPingTime = Date.now();
19578
19602
  this.checkPing();
19579
- if (this.isReconnecting) {
19603
+ if (this.connectAuthState.isReconnecting) {
19604
+ this.setConnectAuthState("isReconnecting", false);
19580
19605
  this.callKit.logger.info("reconnect success", {
19581
19606
  caller: "Socket.onOpen",
19582
19607
  type: "INCALL",
@@ -19589,10 +19614,15 @@ var WebCall = (() => {
19589
19614
  event: "INCALL_RECONNECT_SUCCESS"
19590
19615
  });
19591
19616
  }
19592
- this.resetReconnectState();
19593
19617
  }
19594
- resetReconnectState() {
19595
- this.isReconnecting = false;
19618
+ resetConnectState() {
19619
+ this.connectAuthState = {
19620
+ satrtConfirm: false,
19621
+ isConnected: false,
19622
+ isReconnecting: false,
19623
+ isAuthenticated: false,
19624
+ isError: false
19625
+ };
19596
19626
  this.reconnectAttempts = 0;
19597
19627
  if (this.reconnectTimer) {
19598
19628
  clearTimeout(this.reconnectTimer);
@@ -19605,13 +19635,9 @@ var WebCall = (() => {
19605
19635
  type: "INCALL",
19606
19636
  content: { ev }
19607
19637
  });
19608
- if (this.socketError) {
19609
- return;
19610
- }
19611
19638
  this.handleDisconnect();
19612
19639
  }
19613
19640
  onError(ev) {
19614
- this.socketError = true;
19615
19641
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19616
19642
  event: "INCALL_CONNECT_ERROR",
19617
19643
  err: ev
@@ -19661,6 +19687,20 @@ var WebCall = (() => {
19661
19687
  this.confirmAck(data);
19662
19688
  if (data.event === SocketReceiveEvent.PONG) {
19663
19689
  this.lastPingTime = Date.now();
19690
+ this.setConnectAuthState("isAuthenticated", true);
19691
+ this.callKit.logger.info("socket onMessage pong Authenticated", {
19692
+ caller: "Socket.onMessage",
19693
+ type: "INCALL",
19694
+ content: {
19695
+ data: content,
19696
+ event: SocketReceiveEvent.PONG,
19697
+ isAuthenticated: true
19698
+ }
19699
+ });
19700
+ this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19701
+ event: "INCALL_AUTHENTICATED",
19702
+ isAuthenticated: true
19703
+ });
19664
19704
  return;
19665
19705
  }
19666
19706
  if (data.event === SocketReceiveEvent.START_CONFIRM) {
@@ -19672,7 +19712,7 @@ var WebCall = (() => {
19672
19712
  event: SocketReceiveEvent.START_CONFIRM
19673
19713
  }
19674
19714
  });
19675
- this.satrtConfirm = true;
19715
+ this.setConnectAuthState("satrtConfirm", true);
19676
19716
  }
19677
19717
  if (data.event === SocketReceiveEvent.CALL_SUCCESS) {
19678
19718
  this.callKit.logger.info("call success", {
@@ -19786,12 +19826,10 @@ var WebCall = (() => {
19786
19826
  event: SocketReceiveEvent.CLOSE
19787
19827
  }
19788
19828
  });
19789
- this.send(SocketSendEvent.END, {
19790
- agentId: userInfo.agentId
19791
- });
19829
+ this.send(SocketSendEvent.END, { agentId: userInfo.agentId });
19792
19830
  }
19793
19831
  if (data.event === SocketReceiveEvent.ERROR) {
19794
- this.socketError = true;
19832
+ this.setConnectAuthState("isError", true);
19795
19833
  this.callKit.reset();
19796
19834
  this.callKit.logger.error(data.msg, {
19797
19835
  caller: `Socket.onMessage:${data.event}`,
@@ -19803,7 +19841,7 @@ var WebCall = (() => {
19803
19841
  });
19804
19842
  }
19805
19843
  if (data.event === SocketReceiveEvent.SESSION_ERROR) {
19806
- this.socketError = true;
19844
+ this.setConnectAuthState("isError", true);
19807
19845
  this.callKit.reset();
19808
19846
  this.callKit.logger.error(data.msg, {
19809
19847
  caller: `Socket.onMessage:${data.event}`,
@@ -19830,7 +19868,7 @@ var WebCall = (() => {
19830
19868
  this.callKit.trigger(KitEvent.SERVER_SOCKET_EVENT, data);
19831
19869
  }
19832
19870
  send(event, message) {
19833
- if (!this.isConnected) {
19871
+ if (!this.connectAuthState.isConnected) {
19834
19872
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19835
19873
  event: "INCALL_NOT_CONNECTED"
19836
19874
  });
@@ -19889,7 +19927,7 @@ var WebCall = (() => {
19889
19927
  }
19890
19928
  }
19891
19929
  ping() {
19892
- if (!this.isConnected)
19930
+ if (!this.connectAuthState.isConnected)
19893
19931
  return;
19894
19932
  this.send(SocketSendEvent.PING);
19895
19933
  this.callKit.logger.info(`socket ping`, {
@@ -19900,12 +19938,12 @@ var WebCall = (() => {
19900
19938
  }
19901
19939
  });
19902
19940
  const now = Date.now();
19903
- const { pingInterval, pingTimeout } = this.socketConfig;
19941
+ const { pingInterval, pingTimeout } = this.getSocketConfig();
19904
19942
  if (now - this.lastPingTime > pingInterval + pingTimeout) {
19905
- if (this.ws && this.isConnected) {
19943
+ if (this.ws && this.connectAuthState.isConnected) {
19906
19944
  this.ws.close(4001, "ping timeout");
19907
19945
  } else {
19908
- this.reset();
19946
+ this.callKit.reset();
19909
19947
  }
19910
19948
  this.callKit.logger.error("socket ping timeout", {
19911
19949
  caller: "Socket.ping",
@@ -19921,23 +19959,29 @@ var WebCall = (() => {
19921
19959
  clearInterval(this.pingTimer);
19922
19960
  }
19923
19961
  this.ping();
19962
+ const { pingInterval } = this.getSocketConfig();
19924
19963
  this.pingTimer = setInterval(() => {
19925
19964
  this.ping();
19926
- }, this.socketConfig.pingInterval);
19965
+ }, pingInterval);
19927
19966
  }
19928
19967
  /**
19929
19968
  * reset socket connection and all states
19930
19969
  */
19931
- async reset() {
19970
+ async reset(config) {
19971
+ const { focus = false } = config || {};
19932
19972
  if (this.pingTimer) {
19933
19973
  clearInterval(this.pingTimer);
19934
19974
  this.pingTimer = void 0;
19935
19975
  }
19936
- this.resetReconnectState();
19976
+ if (focus) {
19977
+ this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19978
+ event: "INCALL_RESET"
19979
+ });
19980
+ this.resetConnectState();
19981
+ this.setConnectAuthState("isConnected", false);
19982
+ }
19937
19983
  this.lastPingTime = void 0;
19938
- this.satrtConfirm = false;
19939
- this.socketError = false;
19940
- this.connectAttemptTimes = [];
19984
+ this.setConnectAuthState("satrtConfirm", false);
19941
19985
  this.clearWebSocket();
19942
19986
  }
19943
19987
  attemptReconnect() {
@@ -19945,34 +19989,12 @@ var WebCall = (() => {
19945
19989
  clearTimeout(this.reconnectTimer);
19946
19990
  this.reconnectTimer = void 0;
19947
19991
  }
19948
- const { maxConnectsPerWindow, timeWindow } = this.socketConfig;
19949
- if (maxConnectsPerWindow && timeWindow) {
19950
- const now = Date.now();
19951
- this.connectAttemptTimes = this.connectAttemptTimes.filter(
19952
- (time) => now - time < timeWindow
19953
- );
19954
- if (this.connectAttemptTimes.length >= maxConnectsPerWindow) {
19955
- this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19956
- event: "INCALL_RECONNECT_ERROR"
19957
- });
19958
- this.callKit.logger.warn("Connection rate limit exceeded", {
19959
- caller: "Socket.attemptReconnect",
19960
- type: "INCALL",
19961
- content: {
19962
- errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
19963
- attempts: this.connectAttemptTimes.length,
19964
- maxConnectsPerWindow,
19965
- timeWindow
19966
- }
19967
- });
19968
- return;
19969
- }
19970
- }
19971
- if (this.reconnectAttempts >= this.socketConfig.maxAttempts) {
19992
+ const { maxAttempts } = this.getSocketConfig();
19993
+ if (this.reconnectAttempts >= maxAttempts) {
19972
19994
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19973
19995
  event: "INCALL_RECONNECT_ERROR"
19974
19996
  });
19975
- this.reset();
19997
+ this.callKit.reset();
19976
19998
  this.callKit.logger.error("Maximum reconnection attempts reached", {
19977
19999
  caller: "Socket.attemptReconnect",
19978
20000
  type: "INCALL",
@@ -19988,17 +20010,17 @@ var WebCall = (() => {
19988
20010
  event: "INCALL_RECONNECT_START"
19989
20011
  });
19990
20012
  }
19991
- this.isReconnecting = true;
20013
+ this.setConnectAuthState("isReconnecting", true);
19992
20014
  this.reconnectAttempts += 1;
19993
- const { delay } = this.socketConfig;
20015
+ const { delay } = this.getSocketConfig();
19994
20016
  this.callKit.logger.info(
19995
- `Preparing reconnection attempt ${this.reconnectAttempts}/${this.socketConfig.maxAttempts}, delay: ${delay}ms`,
20017
+ `Preparing reconnection attempt ${this.reconnectAttempts}/${maxAttempts}, delay: ${delay}ms`,
19996
20018
  {
19997
20019
  caller: "Socket.attemptReconnect",
19998
20020
  type: "INCALL",
19999
20021
  content: {
20000
20022
  reconnectAttempts: this.reconnectAttempts,
20001
- maxAttempts: this.socketConfig.maxAttempts,
20023
+ maxAttempts,
20002
20024
  delay
20003
20025
  }
20004
20026
  }
@@ -20073,6 +20095,13 @@ var WebCall = (() => {
20073
20095
  encryptionPassword
20074
20096
  }
20075
20097
  });
20098
+ if (this.socket.isError) {
20099
+ this.logger.warn("socket is error", {
20100
+ caller: "CallKit.login",
20101
+ content: { username, password, extra, socketError: this.socket.isError }
20102
+ });
20103
+ return;
20104
+ }
20076
20105
  try {
20077
20106
  const user = await this.api.login({
20078
20107
  userName: username,
@@ -20124,7 +20153,7 @@ var WebCall = (() => {
20124
20153
  try {
20125
20154
  await this.api.loginOut({ sessionId });
20126
20155
  } catch (error) {
20127
- this.logger.error(error, {
20156
+ this.logger.warn(error, {
20128
20157
  caller: "CallKit.logout",
20129
20158
  content: {
20130
20159
  errCode: ErrorCode.API_USER_LOGOUT_ERROR
@@ -20200,9 +20229,6 @@ var WebCall = (() => {
20200
20229
  });
20201
20230
  this.connect.unregister();
20202
20231
  }
20203
- async stop() {
20204
- await this.connect.stop();
20205
- }
20206
20232
  async hangup() {
20207
20233
  if (!this.config.check())
20208
20234
  return;
@@ -20285,11 +20311,13 @@ var WebCall = (() => {
20285
20311
  userStatus: status
20286
20312
  });
20287
20313
  }
20288
- async reset() {
20314
+ async _reset(config) {
20315
+ const { focus = false } = config || {};
20289
20316
  this.logger.info("reset", {
20290
20317
  caller: "CallKit.reset",
20291
20318
  content: {
20292
- connectStatus: this.connect.connectStatus
20319
+ connectStatus: this.connect.connectStatus,
20320
+ focus
20293
20321
  }
20294
20322
  });
20295
20323
  if (this.connect.isCalling()) {
@@ -20300,7 +20328,14 @@ var WebCall = (() => {
20300
20328
  await this.logout({ isReset: false });
20301
20329
  }
20302
20330
  await this.config.reset();
20303
- await this.socket.reset();
20331
+ await this.socket.reset({ focus });
20332
+ }
20333
+ /**
20334
+ * reset callkit
20335
+ * @description recover the callkit to the initial state
20336
+ */
20337
+ async reset() {
20338
+ await this._reset({ focus: true });
20304
20339
  }
20305
20340
  on(event, callback) {
20306
20341
  this.listener.push({