react-sip-kit 0.6.2 → 0.7.0-beta

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.
@@ -4,7 +4,8 @@ export declare class SipInitializer {
4
4
  private ua?;
5
5
  private configs;
6
6
  private username;
7
- constructor(configs: SipConfigs);
7
+ private configKey;
8
+ constructor(configs: SipConfigs, key: string);
8
9
  init(): Promise<void>;
9
10
  private detectDevices;
10
11
  private createUserAgent;
package/dist/manager.d.ts CHANGED
@@ -1,35 +1,51 @@
1
+ import { SipConfigs } from './configs/types';
2
+ import { useWatchSessionData } from './hooks';
1
3
  import { LineType, SipUserAgentStatus } from './store/types';
2
4
  import { GetAccountKey, GetMethodsKey, LineLookup, SipManagerConfig } from './types';
3
5
  export declare class SipManager {
6
+ /**
7
+ * Active SIP instances keyed by `configKey`.
8
+ *
9
+ * `configKey` defaults to `config.account.username` if not explicitly provided.
10
+ * Ensures multiple accounts (e.g., same username on different domains) can coexist.
11
+ */
4
12
  private instances;
13
+ /**
14
+ * Hook for reactively watching session data (delegates to Zustand store).
15
+ */
16
+ useWatchSessionData: typeof useWatchSessionData;
17
+ /**
18
+ * Hook for reactively watching added configs and line rendering (delegates to Zustand store).
19
+ *
20
+ * Recommended for rendering `Lines` with unique key(config.key)
21
+ */
22
+ useWatchConfigs: () => SipConfigs[];
5
23
  /**
6
24
  * Update the configuration for an existing SIP instance.
7
- * - Updates both local instance map and global store.
8
- * - Does NOT restart or reconnect automatically.
25
+ *
26
+ * - Replaces stored config in memory and global store.
27
+ * - Does **not** automatically reconnect or restart the UserAgent.
9
28
  *
10
29
  * Use `initilizeMediaStreams` or `reconnect()` if runtime behavior must change.
11
30
  *
12
- * @param username - SIP account username
31
+ * @param configKey - Unique identifier of the SIP instance
13
32
  * @param config - Updated SIP configuration
14
33
  */
15
34
  private updateConfig;
16
35
  /**
17
- * Add a new SIP account, or update an existing one if the config has changed.
36
+ * Add or update a SIP account.
18
37
  *
19
- * - If identical config already exists → ignored.
20
- * - If username exists with a different config re-initializes media streams.
21
- * - Otherwise → creates and initializes a new SIP instance.
38
+ * - If identical config exists → ignored.
39
+ * - If same `configKey` but config changed → updates config + re-initializes media streams.
40
+ * - Otherwise → creates and initializes a new UserAgent instance.
22
41
  *
23
- * @param config - SIP account configuration
42
+ * @param config - SIP account configuration (must contain account info, optional `key`)
24
43
  */
25
44
  add(config: SipManagerConfig): Promise<void>;
26
45
  /**
27
- * Get session methods (dial, answer, hold, etc.) for a live session.
28
- *
29
- * Resolves the session by `username`, `lineKey`, or `remoteNumber`.
46
+ * Get high-level session methods (answer, dial, hold, transfer, etc.).
30
47
  *
31
- * @param key - Identifier for session resolution
32
- * @throws Error if no session could be resolved
48
+ * Resolves the SIP instance by `configKey`, `lineKey`, or `remoteNumber`.
33
49
  */
34
50
  getSessionMethodsBy(key: GetMethodsKey): {
35
51
  receiveSession: (invitation: import("./store/types").SipInvitationType) => void;
@@ -48,22 +64,16 @@ export declare class SipManager {
48
64
  };
49
65
  toggleMuteSession: (lineKey: LineType["lineKey"]) => void;
50
66
  toggleHoldSession: (lineKey: LineType["lineKey"], forcedValue?: boolean) => void;
51
- makeTransferSession: (lineKey: LineType["lineKey"], transferLineKey: LineType["lineKey"]) => void;
52
- cancelTransferSession: (lineKey: LineType["lineKey"], transferLineKey: LineType["lineKey"]) => void;
67
+ makeTransferSession: (lineKey: LineType["lineKey"], transferNumber: LineType["lineKey"]) => void;
68
+ cancelTransferSession: (lineKey: LineType["lineKey"], transferNumber: LineType["lineKey"]) => void;
53
69
  cancelSession: (lineKey: LineType["lineKey"]) => void;
54
70
  teardownSession: typeof import("./methods/session").teardownSession;
55
71
  };
56
72
  /**
57
73
  * Get SIP account state.
58
74
  *
59
- * Resolves the account by `username`, `lineKey`, or `remoteNumber`.
60
- *
61
- * @param key - Identifier for account resolution
62
- * @returns Object containing:
63
- * - `status` → UA status
64
- * - `lines` → all active lines
65
- * - `watch` → reactive watcher hook
66
- * @throws Error if no username could be resolved
75
+ * Resolves account by `configKey`, `lineKey`, or `remoteNumber`.
76
+ * Returns reactive account information and watcher hook.
67
77
  */
68
78
  getAccountBy(key: GetAccountKey): {
69
79
  status: SipUserAgentStatus;
@@ -73,43 +83,21 @@ export declare class SipManager {
73
83
  lines: LineType[];
74
84
  };
75
85
  };
86
+ /** Check if an instance exists for the given configKey. */
87
+ has(configKey: string): boolean;
88
+ /** Force reconnect transport for an existing SIP instance. */
89
+ reconnect(configKey: string): void;
76
90
  /**
77
- * Check if an instance exists for the given username.
78
- */
79
- has(username: string): boolean;
80
- /**
81
- * Reconnect transport for an existing SIP instance.
82
- */
83
- reconnect(username: string): void;
84
- /**
85
- * Stop and remove a SIP instance by username.
86
- * Also removes related data from the global store.
87
- */
88
- stop(username: string): Promise<void>;
89
- /**
90
- * Stop and clear all SIP instances.
91
- * Useful for logout or application shutdown.
91
+ * Stop and remove a SIP instance.
92
+ * Cleans up associated data from the global store.
92
93
  */
94
+ stop(configKey: string): Promise<void>;
95
+ /** Stop and clear all SIP instances (e.g., on logout). */
93
96
  stopAll(): Promise<void>;
94
- /**
95
- * Get a Line by either `lineKey` or `remoteNumber`.
96
- *
97
- * @param key - Lookup key (mutually exclusive)
98
- * @returns Line if found, otherwise null
99
- */
97
+ /** Lookup a line by `lineKey` or `remoteNumber`. */
100
98
  getLineBy(key: LineLookup): LineType | null;
101
- /**
102
- * Get a SIP session by either `lineKey` or `remoteNumber`.
103
- *
104
- * @param key - Lookup key (mutually exclusive)
105
- * @returns SIP session if found, otherwise null
106
- */
99
+ /** Lookup a session by `lineKey` or `remoteNumber`. */
107
100
  getSessionBy(key: LineLookup): import("./store/types").SipInvitationType | import("./store/types").SipInviterType | null;
108
- /**
109
- * Get a username by either `lineKey` or `remoteNumber`.
110
- *
111
- * @param key - Lookup key (mutually exclusive)
112
- * @returns Username if found, otherwise null
113
- */
114
- getUsernameBy(key: LineLookup): string | null;
101
+ /** Resolve the `configKey` for a given `lineKey` or `remoteNumber`. */
102
+ getConfigKeyBy(key: LineLookup): string | null;
115
103
  }
@@ -1,4 +1,4 @@
1
- import { SipAccountConfig } from '../../configs/types';
2
- export declare function register(username: SipAccountConfig['username'], userAgent?: import("../..").SipUserAgent | null): void;
3
- export declare function unregister(username: SipAccountConfig['username'], skipUnsubscribe?: boolean, userAgent?: import("../..").SipUserAgent | null): void;
4
- export declare function refreshRegistration(username: SipAccountConfig['username']): void;
1
+ import { SipConfigs } from '../../configs/types';
2
+ export declare function register(configKey: SipConfigs['key'], userAgent?: import("../..").SipUserAgent | null): void;
3
+ export declare function unregister(configKey: SipConfigs['key'], skipUnsubscribe?: boolean, userAgent?: import("../..").SipUserAgent | null): void;
4
+ export declare function refreshRegistration(configKey: SipConfigs['key']): void;
@@ -1,9 +1,9 @@
1
- import { SipAccountConfig } from '../../configs/types';
1
+ import { SipConfigs } from '../../configs/types';
2
2
  import { LineType, SipInvitationType } from '../../store/types';
3
3
  import { CallType } from '../../types';
4
4
  import { SendMessageSessionEnum, SendMessageSessionValueType } from './types';
5
- export declare const sessionMethods: ({ username }: {
6
- username: SipAccountConfig["username"];
5
+ export declare const sessionMethods: ({ configKey }: {
6
+ configKey: SipConfigs["key"];
7
7
  }) => {
8
8
  receiveSession: (invitation: SipInvitationType) => void;
9
9
  answerAudioSession: (lineKey: LineType["lineKey"]) => void;
@@ -21,8 +21,8 @@ export declare const sessionMethods: ({ username }: {
21
21
  };
22
22
  toggleMuteSession: (lineKey: LineType["lineKey"]) => void;
23
23
  toggleHoldSession: (lineKey: LineType["lineKey"], forcedValue?: boolean) => void;
24
- makeTransferSession: (lineKey: LineType["lineKey"], transferLineKey: LineType["lineKey"]) => void;
25
- cancelTransferSession: (lineKey: LineType["lineKey"], transferLineKey: LineType["lineKey"]) => void;
24
+ makeTransferSession: (lineKey: LineType["lineKey"], transferNumber: LineType["lineKey"]) => void;
25
+ cancelTransferSession: (lineKey: LineType["lineKey"], transferNumber: LineType["lineKey"]) => void;
26
26
  cancelSession: (lineKey: LineType["lineKey"]) => void;
27
27
  teardownSession: typeof teardownSession;
28
28
  };
@@ -1,7 +1,7 @@
1
- import { SipAccountConfig } from '../../../configs/types';
1
+ import { SipConfigs } from '../../../configs/types';
2
2
  import { SPDOptionsType } from '../types';
3
- export declare const spdOptions: ({ username }: {
4
- username: SipAccountConfig["username"];
3
+ export declare const spdOptions: ({ configKey }: {
4
+ configKey: SipConfigs["key"];
5
5
  }) => {
6
6
  answerAudioSpdOptions: ({ option: defaultOption }?: {
7
7
  option?: SPDOptionsType;
@@ -1,4 +1,4 @@
1
- import { SipAccountConfig, SipConfigs } from '../configs/types';
1
+ import { SipConfigs } from '../configs/types';
2
2
  import { SipUserAgent } from '../types';
3
3
  import { SipStoreStateType } from './types';
4
4
  export declare const useSipStore: import("zustand").UseBoundStore<import("zustand").StoreApi<SipStoreStateType>>;
@@ -16,12 +16,12 @@ export declare const getSipStore: () => SipStoreStateType;
16
16
  *
17
17
  * Get sip store userAgent for none functional components
18
18
  */
19
- export declare const getSipStoreUserAgent: (username: SipAccountConfig["username"]) => SipUserAgent | null;
19
+ export declare const getSipStoreUserAgent: (configKey: SipConfigs["key"]) => SipUserAgent | null;
20
20
  /**
21
21
  *
22
22
  * Get sip store configs for none functional components
23
23
  */
24
- export declare const getSipUsernameConfigs: (username: SipAccountConfig["username"]) => SipConfigs | null;
24
+ export declare const getSipUsernameConfigs: (configKey: SipConfigs["key"]) => SipConfigs | null;
25
25
  /**
26
26
  *
27
27
  * Init sip store for none functional components
@@ -3,36 +3,49 @@ import { CallbackFunction, CallType, SipUserAgent } from '../types';
3
3
  import { Invitation, Inviter, Session, SessionDescriptionHandler, SessionDescriptionHandlerOptions } from 'sip.js';
4
4
  import { IncomingInviteRequest } from 'sip.js/lib/core';
5
5
  export interface SipStoreStateType {
6
- configs: Record<SipAccountConfig['username'], SipConfigs> | null;
7
- statuses: Record<SipAccountConfig['username'], SipUserAgentStatus> | null;
8
- userAgents?: Record<SipAccountConfig['username'], SipUserAgent>;
9
- lines: Record<SipAccountConfig['username'], Record<LineType['lineKey'], LineType>>;
10
- usernamesByLineKey: Record<LineType['lineKey'], SipAccountConfig['username']>;
11
- lineKeyByRemoteNumber: Record<SipSessionDataType['remoteNumber'], LineType['lineKey']>;
6
+ configs: Record<SipConfigs['key'], SipConfigs> | null;
7
+ statuses: Record<SipConfigs['key'], SipUserAgentStatus> | null;
8
+ userAgents?: Record<SipConfigs['key'], SipUserAgent>;
9
+ lines: Record<SipConfigs['key'], Record<LineType['lineKey'], LineType>>;
10
+ configKeysByLineKey: Record<LineType['lineKey'], SipConfigs['key']>;
11
+ lineKeyByRemoteNumber_ConfigKey: Record<SipSessionDataType['remoteNumber'], LineType['lineKey']>;
12
12
  devicesInfo: DevicesInfoType;
13
13
  setSipStore: (state: Partial<SipStoreStateType>) => void;
14
- setConfig: (username: SipAccountConfig['username'], userAgent: SipConfigs) => void;
15
- setUserAgent: (username: SipAccountConfig['username'], userAgent: SipUserAgent) => void;
14
+ setConfig: (key: SipConfigs['key'], userAgent: SipConfigs) => void;
15
+ setUserAgent: (key: SipConfigs['key'], userAgent: SipUserAgent) => void;
16
16
  addLine: (line: LineType) => void;
17
17
  updateLine: (line: LineType, callback?: CallbackFunction) => void;
18
18
  removeLine: (lineKey: LineType['lineKey']) => void;
19
- remove: (username: SipAccountConfig['username']) => void;
19
+ remove: (key: SipConfigs['key']) => void;
20
20
  removeAll: () => void;
21
21
  findLineByLineKey: (lineKey: LineType['lineKey']) => LineType | null;
22
22
  getSessionByLineKey: (lineKey: LineType['lineKey']) => LineType['sipSession'] | null;
23
- getUsernameByLineKey: (lineKey: LineType['lineKey']) => SipAccountConfig['username'] | null;
24
- getUsernameByRemoteNumber: (remoteNumber: SipSessionDataType['remoteNumber']) => SipAccountConfig['username'] | null;
25
- getLineKeyByRemoteNumber: (remoteNumber: SipSessionDataType['remoteNumber']) => LineType['lineKey'] | null;
26
- getLineByRemoteNumber: (remoteNumber: SipSessionDataType['remoteNumber']) => LineType | null;
27
- getNewLineKey: () => number;
23
+ getConfigKeyByLineKey: (lineKey: LineType['lineKey']) => SipConfigs['key'] | null;
24
+ getConfigKeyByRemoteNumber_ConfigKey: ({ remoteNumber, configKey, }: {
25
+ remoteNumber: SipSessionDataType['remoteNumber'];
26
+ configKey: SipConfigs['key'];
27
+ }) => SipConfigs['key'] | null;
28
+ getLineKeyByRemoteNumber_ConfigKey: ({ remoteNumber, configKey, }: {
29
+ remoteNumber: SipSessionDataType['remoteNumber'];
30
+ configKey: SipConfigs['key'];
31
+ }) => LineType['lineKey'] | null;
32
+ getLineBy: ({ remoteNumber, configKey, }: {
33
+ remoteNumber: SipSessionDataType['remoteNumber'];
34
+ configKey: SipConfigs['key'];
35
+ }) => LineType | null;
36
+ remoteNumberConfigKeyResolver: ({ remoteNumber, configKey, }: {
37
+ remoteNumber: SipSessionDataType['remoteNumber'];
38
+ configKey: SipConfigs['key'];
39
+ }) => `${typeof remoteNumber}:${typeof configKey}`;
40
+ getNewLineKey: () => LineType['lineKey'];
28
41
  }
29
42
  export interface SipInvitationType extends Omit<Invitation, 'incomingInviteRequest' | 'sessionDescriptionHandler'> {
30
43
  data: Partial<SipSessionDataType>;
31
44
  incomingInviteRequest: IncomingInviteRequest;
32
45
  sessionDescriptionHandler: SipSessionDescriptionHandler;
33
46
  sessionDescriptionHandlerOptionsReInvite: SipSessionDescriptionHandlerOptions;
34
- initiateLocalMediaStreams: (params: InitiateMediaStreamsParams) => void;
35
- initiateRemoteMediaStreams: (params: InitiateMediaStreamsParams) => void;
47
+ initiateLocalMediaStreams: (params?: InitiateMediaStreamsParams) => void;
48
+ initiateRemoteMediaStreams: (params?: InitiateMediaStreamsParams) => void;
36
49
  }
37
50
  export interface InitiateMediaStreamsParams {
38
51
  videoEnabled?: boolean;
@@ -46,17 +59,17 @@ export interface SipInviterType extends Inviter {
46
59
  data: Partial<SipSessionDataType>;
47
60
  sessionDescriptionHandler: SipSessionDescriptionHandler;
48
61
  sessionDescriptionHandlerOptionsReInvite: SipSessionDescriptionHandlerOptions;
49
- initiateLocalMediaStreams: (params: InitiateMediaStreamsParams) => void;
50
- initiateRemoteMediaStreams: (params: InitiateMediaStreamsParams) => void;
62
+ initiateLocalMediaStreams: (params?: InitiateMediaStreamsParams) => void;
63
+ initiateRemoteMediaStreams: (params?: InitiateMediaStreamsParams) => void;
51
64
  }
52
65
  export interface SipSessionDescriptionHandler extends SessionDescriptionHandler {
53
66
  peerConnection: RTCPeerConnection;
54
67
  peerConnectionDelegate: any;
55
68
  }
56
69
  export interface LineType {
57
- lineKey: number;
70
+ lineKey: string;
58
71
  remoteNumber: string;
59
- username: SipAccountConfig['username'];
72
+ configKey: SipConfigs['key'];
60
73
  sipSession: SipInvitationType | SipInviterType | null;
61
74
  localSoundMeter: any;
62
75
  remoteSoundMeter: any;
@@ -65,7 +78,8 @@ export interface SipSessionType extends Session {
65
78
  data: SipSessionDataType;
66
79
  }
67
80
  export interface SipSessionDataType {
68
- lineKey: number;
81
+ configKey: SipConfigs['key'];
82
+ lineKey: LineType['lineKey'];
69
83
  callDirection: 'inbound' | 'outbound';
70
84
  callType: CallType;
71
85
  terminateBy: string;
@@ -107,7 +121,7 @@ export interface SipSessionDataType {
107
121
  }
108
122
  export interface SipSessionTransferType {
109
123
  type: 'Attended' | 'Blind';
110
- to: number;
124
+ to: LineType['remoteNumber'];
111
125
  transferTime: string;
112
126
  disposition: string;
113
127
  dispositionTime: string;
package/dist/types.d.ts CHANGED
@@ -25,6 +25,17 @@ export interface SipUserAgent extends UserAgent {
25
25
  voicemailSub: Subscriber | null;
26
26
  }
27
27
  export type SipManagerConfig = {
28
+ /**
29
+ * Unique identifier for the SIP account instance.
30
+ *
31
+ * - Default: `account.username`
32
+ * - Useful when the same username can exist across multiple domains.
33
+ * - All internal maps and store entries use this key.
34
+ */
35
+ key?: SipConfigs['key'];
36
+ /**
37
+ * Core SIP account information (username, password, domain, etc.)
38
+ */
28
39
  account: SipConfigs['account'];
29
40
  } & {
30
41
  [P in Exclude<keyof SipConfigs, 'account'>]?: Partial<SipConfigs[P]>;
@@ -37,40 +48,48 @@ export interface SipContextTransportType {
37
48
  }
38
49
  export type CallbackFunction<T = any> = (value?: T) => void;
39
50
  export type CallType = 'audio' | 'video' | 'conferenceAudio' | 'conferenceVideo' | 'transferAudio' | 'transferVideo';
51
+ /**
52
+ * Wrapper for a SIP account + its active UserAgent instance.
53
+ */
40
54
  export interface SipManagerInstance {
41
55
  config: SipManagerConfig;
42
56
  instance: SipInitializer;
43
57
  }
58
+ /**
59
+ * Keys that can resolve an account:
60
+ * - `configKey` → explicit instance key
61
+ * - `lineKey` → active line identifier
62
+ */
44
63
  export type GetAccountKey = {
45
- username: string;
64
+ configKey: SipManagerConfig['key'];
46
65
  lineKey?: never;
47
- remoteNumber?: never;
48
66
  } | {
49
67
  lineKey: LineType['lineKey'];
50
- username?: never;
51
- remoteNumber?: never;
52
- } | {
53
- remoteNumber: SipSessionDataType['remoteNumber'];
54
- username?: never;
55
- lineKey?: never;
68
+ configKey?: never;
56
69
  };
70
+ /**
71
+ * Keys that can resolve session control methods:
72
+ * - `configKey` → explicit instance key
73
+ * - `lineKey` → active line identifier
74
+ */
57
75
  export type GetMethodsKey = {
58
- username: string;
76
+ configKey: SipManagerConfig['key'];
59
77
  lineKey?: never;
60
- remoteNumber?: never;
61
78
  } | {
62
79
  lineKey: LineType['lineKey'];
63
- username?: never;
64
- remoteNumber?: never;
65
- } | {
66
- remoteNumber: SipSessionDataType['remoteNumber'];
67
- username?: never;
68
- lineKey?: never;
80
+ configKey?: never;
69
81
  };
82
+ /**
83
+ * Keys for resolving lines/sessions (mutually exclusive).
84
+ * - `configKey` & `remoteNumber` → explicit instance key and peer phone number(aka remoteNumber)
85
+ * - `lineKey` → active line identifier
86
+ */
70
87
  export type LineLookup = {
71
88
  lineKey: LineType['lineKey'];
72
89
  remoteNumber?: never;
90
+ configKey?: never;
73
91
  } | {
92
+ configKey: SipConfigs['key'];
74
93
  remoteNumber: SipSessionDataType['remoteNumber'];
75
94
  lineKey?: never;
76
95
  };
@@ -0,0 +1 @@
1
+ export declare const generateUUID: () => string;
@@ -1,5 +1,5 @@
1
- import { SipAccountConfig } from '../../configs/types';
2
- export declare const getMediaDevices: (username: SipAccountConfig["username"]) => Promise<{
1
+ import { SipConfigs } from '../../configs/types';
2
+ export declare const getMediaDevices: (configKey: SipConfigs["key"]) => Promise<{
3
3
  hasAudioDevice: boolean;
4
4
  audioInputDevices: MediaDeviceInfo[];
5
5
  hasSpeakerDevice: boolean;
@@ -3,3 +3,4 @@ export * from './dayjs';
3
3
  export * from './deepMerge';
4
4
  export * from './utcDateNow';
5
5
  export * from './getMediaDevices';
6
+ export * from './generateUUID';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-sip-kit",
3
3
  "private": false,
4
- "version": "0.6.02",
4
+ "version": "0.7.0-beta",
5
5
  "type": "module",
6
6
  "author": {
7
7
  "name": "Shervin Ghajar",