@dora-cell/sdk 1.0.0 → 1.0.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/README.md +18 -14
- package/dist/index.d.mts +26 -5
- package/dist/index.d.ts +26 -5
- package/dist/index.js +217 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +217 -84
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,10 @@ VoIP calling SDK for Dora Cell - Make calls from any JavaScript application with
|
|
|
8
8
|
✅ **TypeScript support** - Full type definitions included
|
|
9
9
|
✅ **WebRTC-based** - High-quality voice calls using JsSIP
|
|
10
10
|
✅ **Event-driven API** - Listen to call state changes
|
|
11
|
-
✅ **
|
|
12
|
-
✅ **
|
|
13
|
-
✅ **
|
|
11
|
+
✅ **API Token Auth** - Securely authenticate with Public & Secret keys
|
|
12
|
+
✅ **Dynamic Extensions** - Fetch and switch between DID numbers
|
|
13
|
+
✅ **Wallet Integration** - Check credit balance directly from the SDK
|
|
14
|
+
✅ **React bindings** - Premium UI components and hooks included
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -48,14 +49,14 @@ const sdk = new DoraCell({
|
|
|
48
49
|
|
|
49
50
|
#### Option B: API Token Authentication (Production)
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
Best for production apps. The SDK will verify keys and fetch SIP credentials automatically.
|
|
52
53
|
|
|
53
54
|
```javascript
|
|
54
55
|
const sdk = new DoraCell({
|
|
55
56
|
auth: {
|
|
56
57
|
type: "api-token",
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
publicKey: "pk_live_...",
|
|
59
|
+
secretKey: "sk_live_...",
|
|
59
60
|
},
|
|
60
61
|
});
|
|
61
62
|
```
|
|
@@ -112,17 +113,20 @@ try {
|
|
|
112
113
|
#### `new DoraCell(config)`
|
|
113
114
|
|
|
114
115
|
- `config.auth` (Required)
|
|
115
|
-
- `type: 'extension' | '
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
116
|
+
- `type: 'api-token' | 'extension' | 'direct'`
|
|
117
|
+
- `publicKey/secretKey` (for api-token)
|
|
118
|
+
- `extension` (for extension type)
|
|
119
|
+
- `config.environment?: 'dev' | 'staging' | 'production'` - Shortcut for API URLs (default: 'production')
|
|
120
|
+
- `config.autoSelectExtension?: boolean` - Register first available DID (default: true)
|
|
118
121
|
- `config.debug?: boolean` - Enable JsSIP debug logs (default: false)
|
|
119
122
|
|
|
120
123
|
#### Methods
|
|
121
124
|
|
|
122
|
-
- `initialize(): Promise<void>` -
|
|
123
|
-
- `call(number,
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
- `initialize(): Promise<void>` - Authenticate and register with the SIP server.
|
|
126
|
+
- `call(number, extension?): Promise<Call>` - Initiate an outbound call.
|
|
127
|
+
- `getWallet(): Promise<{ balance: number, currency: string }>` - Get current credit balance.
|
|
128
|
+
- `fetchExtensions(): Promise<Extension[]>` - Fetch available DID numbers/extensions.
|
|
129
|
+
- `setExtension(ext): Promise<void>` - Switch active extension and re-register SIP.
|
|
126
130
|
- `answerCall(): void` - Answer a pending incoming call.
|
|
127
131
|
- `hangup(): void` - End the current active call.
|
|
128
132
|
- `on(event, handler): void` - Listen for events (see below).
|
|
@@ -145,7 +149,7 @@ Returned by `call()` and emitted in events.
|
|
|
145
149
|
|
|
146
150
|
| Event | Description | Data |
|
|
147
151
|
| ------------------- | ------------------------------ | ---------------------------------- |
|
|
148
|
-
| `connection:status` | SIP registration status change | `{ status: string, error?: string }` |
|
|
152
|
+
| `connection:status` | SIP registration status change | `{ status: string, extension?: string, error?: string }` |
|
|
149
153
|
| `call:incoming` | New incoming call detected | `Call` object |
|
|
150
154
|
| `call:outgoing` | New outbound call started | `Call` object |
|
|
151
155
|
| `call:ringing` | Remote party is ringing | `Call` object |
|
package/dist/index.d.mts
CHANGED
|
@@ -5,8 +5,8 @@ import EventEmitter from 'eventemitter3';
|
|
|
5
5
|
*/
|
|
6
6
|
interface ApiTokenAuth {
|
|
7
7
|
type: 'api-token';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
publicKey: string;
|
|
9
|
+
secretKey: string;
|
|
10
10
|
}
|
|
11
11
|
interface DirectCredentialsAuth {
|
|
12
12
|
type: 'direct';
|
|
@@ -21,8 +21,11 @@ interface ExtensionAuth {
|
|
|
21
21
|
sipDomain?: string;
|
|
22
22
|
}
|
|
23
23
|
type AuthConfig = ApiTokenAuth | DirectCredentialsAuth | ExtensionAuth;
|
|
24
|
+
type DoraCellEnv = 'dev' | 'staging' | 'production' | 'local';
|
|
24
25
|
interface DoraCellConfig {
|
|
25
26
|
auth: AuthConfig;
|
|
27
|
+
apiBaseUrl?: string;
|
|
28
|
+
environment?: DoraCellEnv;
|
|
26
29
|
sipServer?: string;
|
|
27
30
|
turnServers?: RTCIceServer[];
|
|
28
31
|
debug?: boolean;
|
|
@@ -106,6 +109,8 @@ declare class DoraCell {
|
|
|
106
109
|
private credentials;
|
|
107
110
|
private ua;
|
|
108
111
|
private callManager;
|
|
112
|
+
private apiClient;
|
|
113
|
+
private apiBaseUrl;
|
|
109
114
|
private connectionStatus;
|
|
110
115
|
private retryCount;
|
|
111
116
|
private maxRetries;
|
|
@@ -134,14 +139,29 @@ declare class DoraCell {
|
|
|
134
139
|
* Get current call
|
|
135
140
|
*/
|
|
136
141
|
getCurrentCall(): Call | null;
|
|
142
|
+
/**
|
|
143
|
+
* Get user's wallet/credit balance
|
|
144
|
+
*/
|
|
145
|
+
getWallet(): Promise<{
|
|
146
|
+
balance: number;
|
|
147
|
+
currency: string;
|
|
148
|
+
}>;
|
|
137
149
|
/**
|
|
138
150
|
* Get connection status
|
|
139
151
|
*/
|
|
140
152
|
getStatus(): ConnectionStatus;
|
|
141
153
|
/**
|
|
142
|
-
*
|
|
154
|
+
* Fetch available extensions (DID numbers) from the API
|
|
155
|
+
*/
|
|
156
|
+
fetchExtensions(): Promise<any[]>;
|
|
157
|
+
/**
|
|
158
|
+
* Get available extensions (DID numbers)
|
|
159
|
+
*/
|
|
160
|
+
getExtensions(): any[];
|
|
161
|
+
/**
|
|
162
|
+
* Update active extension and re-initialize SIP connection
|
|
143
163
|
*/
|
|
144
|
-
|
|
164
|
+
setExtension(extension: string): Promise<void>;
|
|
145
165
|
/**
|
|
146
166
|
* Event listener management
|
|
147
167
|
*/
|
|
@@ -157,6 +177,7 @@ declare class DoraCell {
|
|
|
157
177
|
private getDefaultTurnServers;
|
|
158
178
|
private getDisplayName;
|
|
159
179
|
private generateInstanceId;
|
|
180
|
+
private resolveApiBaseUrl;
|
|
160
181
|
}
|
|
161
182
|
|
|
162
183
|
/**
|
|
@@ -215,4 +236,4 @@ declare function extractNumberFromSipUri(sipUri: string): string;
|
|
|
215
236
|
*/
|
|
216
237
|
declare function isValidPhoneNumber(phone: string, minLength?: number): boolean;
|
|
217
238
|
|
|
218
|
-
export { type ApiTokenAuth, type AuthConfig, AuthenticationError, type Call, type CallDirection, CallError, type CallOptions, CallSession, type CallStatus, ConnectionError, type ConnectionState, type ConnectionStatus, type DirectCredentialsAuth, DoraCell, type DoraCellConfig, DoraCellError, type DoraCellEvent, type DoraCellEventMap, type Extension, type SipCredentials, DoraCell as default, extractNumberFromSipUri, formatPhoneToSIP, isValidPhoneNumber, normalizePhoneNumber };
|
|
239
|
+
export { type ApiTokenAuth, type AuthConfig, AuthenticationError, type Call, type CallDirection, CallError, type CallOptions, CallSession, type CallStatus, ConnectionError, type ConnectionState, type ConnectionStatus, type DirectCredentialsAuth, DoraCell, type DoraCellConfig, DoraCellError, type DoraCellEvent, type DoraCellEventMap, type Extension, type ExtensionAuth, type SipCredentials, DoraCell as default, extractNumberFromSipUri, formatPhoneToSIP, isValidPhoneNumber, normalizePhoneNumber };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ import EventEmitter from 'eventemitter3';
|
|
|
5
5
|
*/
|
|
6
6
|
interface ApiTokenAuth {
|
|
7
7
|
type: 'api-token';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
publicKey: string;
|
|
9
|
+
secretKey: string;
|
|
10
10
|
}
|
|
11
11
|
interface DirectCredentialsAuth {
|
|
12
12
|
type: 'direct';
|
|
@@ -21,8 +21,11 @@ interface ExtensionAuth {
|
|
|
21
21
|
sipDomain?: string;
|
|
22
22
|
}
|
|
23
23
|
type AuthConfig = ApiTokenAuth | DirectCredentialsAuth | ExtensionAuth;
|
|
24
|
+
type DoraCellEnv = 'dev' | 'staging' | 'production' | 'local';
|
|
24
25
|
interface DoraCellConfig {
|
|
25
26
|
auth: AuthConfig;
|
|
27
|
+
apiBaseUrl?: string;
|
|
28
|
+
environment?: DoraCellEnv;
|
|
26
29
|
sipServer?: string;
|
|
27
30
|
turnServers?: RTCIceServer[];
|
|
28
31
|
debug?: boolean;
|
|
@@ -106,6 +109,8 @@ declare class DoraCell {
|
|
|
106
109
|
private credentials;
|
|
107
110
|
private ua;
|
|
108
111
|
private callManager;
|
|
112
|
+
private apiClient;
|
|
113
|
+
private apiBaseUrl;
|
|
109
114
|
private connectionStatus;
|
|
110
115
|
private retryCount;
|
|
111
116
|
private maxRetries;
|
|
@@ -134,14 +139,29 @@ declare class DoraCell {
|
|
|
134
139
|
* Get current call
|
|
135
140
|
*/
|
|
136
141
|
getCurrentCall(): Call | null;
|
|
142
|
+
/**
|
|
143
|
+
* Get user's wallet/credit balance
|
|
144
|
+
*/
|
|
145
|
+
getWallet(): Promise<{
|
|
146
|
+
balance: number;
|
|
147
|
+
currency: string;
|
|
148
|
+
}>;
|
|
137
149
|
/**
|
|
138
150
|
* Get connection status
|
|
139
151
|
*/
|
|
140
152
|
getStatus(): ConnectionStatus;
|
|
141
153
|
/**
|
|
142
|
-
*
|
|
154
|
+
* Fetch available extensions (DID numbers) from the API
|
|
155
|
+
*/
|
|
156
|
+
fetchExtensions(): Promise<any[]>;
|
|
157
|
+
/**
|
|
158
|
+
* Get available extensions (DID numbers)
|
|
159
|
+
*/
|
|
160
|
+
getExtensions(): any[];
|
|
161
|
+
/**
|
|
162
|
+
* Update active extension and re-initialize SIP connection
|
|
143
163
|
*/
|
|
144
|
-
|
|
164
|
+
setExtension(extension: string): Promise<void>;
|
|
145
165
|
/**
|
|
146
166
|
* Event listener management
|
|
147
167
|
*/
|
|
@@ -157,6 +177,7 @@ declare class DoraCell {
|
|
|
157
177
|
private getDefaultTurnServers;
|
|
158
178
|
private getDisplayName;
|
|
159
179
|
private generateInstanceId;
|
|
180
|
+
private resolveApiBaseUrl;
|
|
160
181
|
}
|
|
161
182
|
|
|
162
183
|
/**
|
|
@@ -215,4 +236,4 @@ declare function extractNumberFromSipUri(sipUri: string): string;
|
|
|
215
236
|
*/
|
|
216
237
|
declare function isValidPhoneNumber(phone: string, minLength?: number): boolean;
|
|
217
238
|
|
|
218
|
-
export { type ApiTokenAuth, type AuthConfig, AuthenticationError, type Call, type CallDirection, CallError, type CallOptions, CallSession, type CallStatus, ConnectionError, type ConnectionState, type ConnectionStatus, type DirectCredentialsAuth, DoraCell, type DoraCellConfig, DoraCellError, type DoraCellEvent, type DoraCellEventMap, type Extension, type SipCredentials, DoraCell as default, extractNumberFromSipUri, formatPhoneToSIP, isValidPhoneNumber, normalizePhoneNumber };
|
|
239
|
+
export { type ApiTokenAuth, type AuthConfig, AuthenticationError, type Call, type CallDirection, CallError, type CallOptions, CallSession, type CallStatus, ConnectionError, type ConnectionState, type ConnectionStatus, type DirectCredentialsAuth, DoraCell, type DoraCellConfig, DoraCellError, type DoraCellEvent, type DoraCellEventMap, type Extension, type ExtensionAuth, type SipCredentials, DoraCell as default, extractNumberFromSipUri, formatPhoneToSIP, isValidPhoneNumber, normalizePhoneNumber };
|
package/dist/index.js
CHANGED
|
@@ -23003,43 +23003,41 @@ var ConnectionError = class extends DoraCellError {
|
|
|
23003
23003
|
|
|
23004
23004
|
// src/core/AuthProvider.ts
|
|
23005
23005
|
var ApiTokenAuthProvider = class {
|
|
23006
|
-
constructor(
|
|
23006
|
+
constructor(publicKey, secretKey) {
|
|
23007
23007
|
this.credentials = null;
|
|
23008
|
-
this.
|
|
23009
|
-
|
|
23010
|
-
|
|
23011
|
-
defaultBaseUrl = process.env.NEXT_PUBLIC_BASE_API_URL || "";
|
|
23012
|
-
}
|
|
23013
|
-
this.apiBaseUrl = apiBaseUrl || defaultBaseUrl;
|
|
23008
|
+
this.sessionToken = null;
|
|
23009
|
+
this.publicKey = publicKey;
|
|
23010
|
+
this.secretKey = secretKey;
|
|
23014
23011
|
}
|
|
23015
|
-
async authenticate(config) {
|
|
23012
|
+
async authenticate(config, apiBaseUrl) {
|
|
23016
23013
|
if (config.type !== "api-token") {
|
|
23017
23014
|
throw new AuthenticationError("Invalid auth config type for ApiTokenAuthProvider");
|
|
23018
23015
|
}
|
|
23016
|
+
const baseUrl = apiBaseUrl?.replace(/\/$/, "") || "https://api.cell.usedora.com/api";
|
|
23019
23017
|
try {
|
|
23020
|
-
|
|
23021
|
-
|
|
23018
|
+
console.log("SDK: Verifying keys at:", `${baseUrl}/sdk/v1/auth/session`);
|
|
23019
|
+
const authResponse = await fetch(`${baseUrl}/sdk/v1/auth/session`, {
|
|
23020
|
+
method: "POST",
|
|
23022
23021
|
headers: {
|
|
23023
|
-
"Authorization": `Bearer ${this.apiToken}`,
|
|
23024
23022
|
"Content-Type": "application/json",
|
|
23025
23023
|
"Accept": "application/json"
|
|
23026
23024
|
},
|
|
23027
|
-
|
|
23025
|
+
body: JSON.stringify({
|
|
23026
|
+
secret_key: this.secretKey
|
|
23027
|
+
})
|
|
23028
23028
|
});
|
|
23029
|
-
if (!
|
|
23030
|
-
if (response.status === 401 || response.status === 403) {
|
|
23031
|
-
throw new AuthenticationError(
|
|
23032
|
-
"Invalid API token or insufficient permissions",
|
|
23033
|
-
{ status: response.status }
|
|
23034
|
-
);
|
|
23035
|
-
}
|
|
23029
|
+
if (!authResponse.ok) {
|
|
23036
23030
|
throw new AuthenticationError(
|
|
23037
|
-
`
|
|
23038
|
-
{ status:
|
|
23031
|
+
`Key verification failed: ${authResponse.status}`,
|
|
23032
|
+
{ status: authResponse.status }
|
|
23039
23033
|
);
|
|
23040
23034
|
}
|
|
23041
|
-
const
|
|
23042
|
-
this.
|
|
23035
|
+
const authData = await authResponse.json();
|
|
23036
|
+
this.sessionToken = authData.session_token || authData.token || authData.data?.session_token;
|
|
23037
|
+
if (!this.sessionToken) {
|
|
23038
|
+
throw new AuthenticationError("No session token returned after key verification");
|
|
23039
|
+
}
|
|
23040
|
+
this.credentials = this.parseCredentials(authData);
|
|
23043
23041
|
return this.credentials;
|
|
23044
23042
|
} catch (error) {
|
|
23045
23043
|
if (error instanceof AuthenticationError) {
|
|
@@ -23051,28 +23049,38 @@ var ApiTokenAuthProvider = class {
|
|
|
23051
23049
|
);
|
|
23052
23050
|
}
|
|
23053
23051
|
}
|
|
23054
|
-
async refreshCredentials() {
|
|
23055
|
-
return this.authenticate({
|
|
23052
|
+
async refreshCredentials(apiBaseUrl) {
|
|
23053
|
+
return this.authenticate({
|
|
23054
|
+
type: "api-token",
|
|
23055
|
+
publicKey: this.publicKey,
|
|
23056
|
+
secretKey: this.secretKey
|
|
23057
|
+
}, apiBaseUrl);
|
|
23056
23058
|
}
|
|
23057
23059
|
isAuthenticated() {
|
|
23058
|
-
return this.credentials !== null;
|
|
23060
|
+
return this.credentials !== null && this.sessionToken !== null;
|
|
23061
|
+
}
|
|
23062
|
+
getSessionToken() {
|
|
23063
|
+
return this.sessionToken;
|
|
23059
23064
|
}
|
|
23060
23065
|
parseCredentials(data) {
|
|
23061
|
-
const
|
|
23062
|
-
const
|
|
23063
|
-
const
|
|
23064
|
-
const
|
|
23065
|
-
const
|
|
23066
|
+
const DEFAULT_WSS_URL = "wss://cell.usedora.com:8089/ws";
|
|
23067
|
+
const DEFAULT_SIP_IP = "64.227.10.164";
|
|
23068
|
+
const DEFAULT_PASSWORD = "1234";
|
|
23069
|
+
const wsUrl = data.ws_url || data.wsUrl || DEFAULT_WSS_URL;
|
|
23070
|
+
const sipDomain = data.sip_domain || data.sipDomain || DEFAULT_SIP_IP;
|
|
23071
|
+
const password = data.password || DEFAULT_PASSWORD;
|
|
23072
|
+
const extensions = data.extensions || [];
|
|
23066
23073
|
const expiresIn = data.expires_in || data.expiresIn;
|
|
23067
|
-
|
|
23068
|
-
|
|
23069
|
-
|
|
23070
|
-
|
|
23074
|
+
let sipUri = data.sip_uri || data.sipUri;
|
|
23075
|
+
if (!sipUri && extensions.length > 0) {
|
|
23076
|
+
const ext = extensions[0].extension;
|
|
23077
|
+
sipUri = `sip:${ext}@${sipDomain}`;
|
|
23078
|
+
console.log(`SDK: Constructed SIP URI from extension: ${sipUri}`);
|
|
23071
23079
|
}
|
|
23072
23080
|
return {
|
|
23073
23081
|
wsUrl,
|
|
23074
|
-
sipUri,
|
|
23075
|
-
password
|
|
23082
|
+
sipUri: sipUri || "",
|
|
23083
|
+
password,
|
|
23076
23084
|
sipDomain,
|
|
23077
23085
|
extensions,
|
|
23078
23086
|
expiresIn
|
|
@@ -23080,64 +23088,42 @@ var ApiTokenAuthProvider = class {
|
|
|
23080
23088
|
}
|
|
23081
23089
|
};
|
|
23082
23090
|
var DirectCredentialsAuthProvider = class {
|
|
23083
|
-
constructor() {
|
|
23084
|
-
this.credentials =
|
|
23091
|
+
constructor(sipUri, password, wsUrl) {
|
|
23092
|
+
this.credentials = { sipUri, password, wsUrl, extensions: [] };
|
|
23085
23093
|
}
|
|
23086
|
-
async authenticate(
|
|
23087
|
-
if (config.type !== "direct") {
|
|
23088
|
-
throw new AuthenticationError("Invalid auth config type for DirectCredentialsAuthProvider");
|
|
23089
|
-
}
|
|
23090
|
-
this.credentials = {
|
|
23091
|
-
wsUrl: config.wsUrl,
|
|
23092
|
-
sipUri: config.sipUri,
|
|
23093
|
-
password: config.password
|
|
23094
|
-
};
|
|
23094
|
+
async authenticate() {
|
|
23095
23095
|
return this.credentials;
|
|
23096
23096
|
}
|
|
23097
23097
|
isAuthenticated() {
|
|
23098
|
-
return
|
|
23098
|
+
return true;
|
|
23099
23099
|
}
|
|
23100
23100
|
};
|
|
23101
|
-
var DEFAULT_WSS_URL = "wss://cell.usedora.com:8089/ws";
|
|
23102
|
-
var DEFAULT_SIP_IP = "64.227.10.164";
|
|
23103
|
-
var DEFAULT_PASSWORD = "1234";
|
|
23104
23101
|
var ExtensionAuthProvider = class {
|
|
23105
|
-
constructor() {
|
|
23106
|
-
this.credentials = null;
|
|
23107
|
-
}
|
|
23108
|
-
async authenticate(config) {
|
|
23109
|
-
if (config.type !== "extension") {
|
|
23110
|
-
throw new AuthenticationError("Invalid auth config type for ExtensionAuthProvider");
|
|
23111
|
-
}
|
|
23112
|
-
const extension = config.extension;
|
|
23113
|
-
const password = config.password || DEFAULT_PASSWORD;
|
|
23114
|
-
const wsUrl = DEFAULT_WSS_URL;
|
|
23115
|
-
const sipDomain = config.sipDomain || DEFAULT_SIP_IP;
|
|
23116
|
-
const sipUri = `sip:${extension}@${sipDomain}`;
|
|
23102
|
+
constructor(extension, password = "1234", sipDomain = "64.227.10.164") {
|
|
23117
23103
|
this.credentials = {
|
|
23118
|
-
|
|
23119
|
-
sipUri,
|
|
23104
|
+
sipUri: `sip:${extension}@${sipDomain}`,
|
|
23120
23105
|
password,
|
|
23121
|
-
|
|
23122
|
-
extensions: [{ extension,
|
|
23106
|
+
wsUrl: "wss://cell.usedora.com:8089/ws",
|
|
23107
|
+
extensions: [{ extension, isPrimary: true }],
|
|
23108
|
+
sipDomain
|
|
23123
23109
|
};
|
|
23110
|
+
}
|
|
23111
|
+
async authenticate() {
|
|
23124
23112
|
return this.credentials;
|
|
23125
23113
|
}
|
|
23126
23114
|
isAuthenticated() {
|
|
23127
|
-
return
|
|
23115
|
+
return true;
|
|
23128
23116
|
}
|
|
23129
23117
|
};
|
|
23130
23118
|
function createAuthProvider(config) {
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23134
|
-
|
|
23135
|
-
|
|
23136
|
-
|
|
23137
|
-
return new ExtensionAuthProvider();
|
|
23138
|
-
default:
|
|
23139
|
-
throw new AuthenticationError("Unknown authentication type");
|
|
23119
|
+
if (config.type === "api-token") {
|
|
23120
|
+
return new ApiTokenAuthProvider(config.publicKey, config.secretKey);
|
|
23121
|
+
} else if (config.type === "direct") {
|
|
23122
|
+
return new DirectCredentialsAuthProvider(config.sipUri, config.password, config.wsUrl);
|
|
23123
|
+
} else if (config.type === "extension") {
|
|
23124
|
+
return new ExtensionAuthProvider(config.extension, config.password, config.sipDomain);
|
|
23140
23125
|
}
|
|
23126
|
+
throw new AuthenticationError("Unknown authentication type");
|
|
23141
23127
|
}
|
|
23142
23128
|
|
|
23143
23129
|
// src/utils/phoneFormatter.ts
|
|
@@ -23411,6 +23397,64 @@ var CallManager = class {
|
|
|
23411
23397
|
}
|
|
23412
23398
|
};
|
|
23413
23399
|
|
|
23400
|
+
// src/core/ApiClient.ts
|
|
23401
|
+
var ApiClient = class {
|
|
23402
|
+
constructor(baseUrl) {
|
|
23403
|
+
this.sessionToken = null;
|
|
23404
|
+
this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
23405
|
+
}
|
|
23406
|
+
setSessionToken(token) {
|
|
23407
|
+
this.sessionToken = token;
|
|
23408
|
+
}
|
|
23409
|
+
getSessionToken() {
|
|
23410
|
+
return this.sessionToken;
|
|
23411
|
+
}
|
|
23412
|
+
async post(path, data, headers = {}) {
|
|
23413
|
+
return this.request(path, {
|
|
23414
|
+
method: "POST",
|
|
23415
|
+
headers: {
|
|
23416
|
+
"Content-Type": "application/json",
|
|
23417
|
+
...headers
|
|
23418
|
+
},
|
|
23419
|
+
body: JSON.stringify(data)
|
|
23420
|
+
});
|
|
23421
|
+
}
|
|
23422
|
+
async get(path, headers = {}) {
|
|
23423
|
+
return this.request(path, {
|
|
23424
|
+
method: "GET",
|
|
23425
|
+
headers: {
|
|
23426
|
+
...headers
|
|
23427
|
+
}
|
|
23428
|
+
});
|
|
23429
|
+
}
|
|
23430
|
+
async request(path, options) {
|
|
23431
|
+
const url = path.startsWith("http") ? path : `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
23432
|
+
const headers = {
|
|
23433
|
+
...options.headers
|
|
23434
|
+
};
|
|
23435
|
+
if (this.sessionToken && !headers["Authorization"]) {
|
|
23436
|
+
headers["Authorization"] = `Bearer ${this.sessionToken}`;
|
|
23437
|
+
}
|
|
23438
|
+
const response = await fetch(url, {
|
|
23439
|
+
...options,
|
|
23440
|
+
headers
|
|
23441
|
+
});
|
|
23442
|
+
if (!response.ok) {
|
|
23443
|
+
let errorData;
|
|
23444
|
+
try {
|
|
23445
|
+
errorData = await response.json();
|
|
23446
|
+
} catch (e) {
|
|
23447
|
+
errorData = { message: response.statusText };
|
|
23448
|
+
}
|
|
23449
|
+
const error = new Error(errorData.message || `API Request failed: ${response.status}`);
|
|
23450
|
+
error.status = response.status;
|
|
23451
|
+
error.data = errorData;
|
|
23452
|
+
throw error;
|
|
23453
|
+
}
|
|
23454
|
+
return response.json();
|
|
23455
|
+
}
|
|
23456
|
+
};
|
|
23457
|
+
|
|
23414
23458
|
// src/core/DoraCell.ts
|
|
23415
23459
|
var DoraCell = class {
|
|
23416
23460
|
constructor(config) {
|
|
@@ -23428,6 +23472,8 @@ var DoraCell = class {
|
|
|
23428
23472
|
};
|
|
23429
23473
|
this.events = new eventemitter3_default();
|
|
23430
23474
|
this.authProvider = createAuthProvider(config.auth);
|
|
23475
|
+
this.apiBaseUrl = this.resolveApiBaseUrl(config);
|
|
23476
|
+
this.apiClient = new ApiClient(this.apiBaseUrl);
|
|
23431
23477
|
if (this.config.debug) {
|
|
23432
23478
|
import_jssip.default.debug.enable("JsSIP:*");
|
|
23433
23479
|
}
|
|
@@ -23437,7 +23483,20 @@ var DoraCell = class {
|
|
|
23437
23483
|
*/
|
|
23438
23484
|
async initialize() {
|
|
23439
23485
|
try {
|
|
23440
|
-
this.credentials = await this.authProvider.authenticate(
|
|
23486
|
+
this.credentials = await this.authProvider.authenticate(
|
|
23487
|
+
this.config.auth,
|
|
23488
|
+
this.apiBaseUrl
|
|
23489
|
+
);
|
|
23490
|
+
if (this.authProvider instanceof ApiTokenAuthProvider) {
|
|
23491
|
+
const token = this.authProvider.getSessionToken();
|
|
23492
|
+
if (token) this.apiClient.setSessionToken(token);
|
|
23493
|
+
}
|
|
23494
|
+
if (this.config.autoSelectExtension && this.credentials?.extensions && this.credentials.extensions.length > 0) {
|
|
23495
|
+
const primary = this.credentials.extensions.find((e) => e.isPrimary) || this.credentials.extensions[0];
|
|
23496
|
+
const domain = this.credentials.sipDomain || "cell.usedora.com";
|
|
23497
|
+
this.credentials.sipUri = `sip:${primary.extension}@${domain}`;
|
|
23498
|
+
console.log(`SDK: Auto-selected extension ${primary.extension}`);
|
|
23499
|
+
}
|
|
23441
23500
|
await this.initializeUserAgent();
|
|
23442
23501
|
this.initializeCallManager();
|
|
23443
23502
|
await this.waitForRegistration();
|
|
@@ -23590,6 +23649,35 @@ var DoraCell = class {
|
|
|
23590
23649
|
getCurrentCall() {
|
|
23591
23650
|
return this.callManager?.getCurrentCall() || null;
|
|
23592
23651
|
}
|
|
23652
|
+
/**
|
|
23653
|
+
* Get user's wallet/credit balance
|
|
23654
|
+
*/
|
|
23655
|
+
async getWallet() {
|
|
23656
|
+
const token = this.apiClient.getSessionToken();
|
|
23657
|
+
if (!token) {
|
|
23658
|
+
console.warn("SDK: Cannot fetch wallet, no session token available.");
|
|
23659
|
+
return { balance: 0, currency: "NGN" };
|
|
23660
|
+
}
|
|
23661
|
+
try {
|
|
23662
|
+
console.log("SDK: Fetching wallet balance...");
|
|
23663
|
+
const response = await this.apiClient.get("/wallets");
|
|
23664
|
+
const wallets = Array.isArray(response) ? response : response.data || [];
|
|
23665
|
+
if (wallets.length === 0) {
|
|
23666
|
+
console.log("SDK: No wallets found for user.");
|
|
23667
|
+
return { balance: 0, currency: "NGN" };
|
|
23668
|
+
}
|
|
23669
|
+
const primary = wallets[0];
|
|
23670
|
+
const result = {
|
|
23671
|
+
balance: parseFloat(primary.balance || "0"),
|
|
23672
|
+
currency: primary.currency || "NGN"
|
|
23673
|
+
};
|
|
23674
|
+
console.log("SDK: Wallet balance fetched:", result);
|
|
23675
|
+
return result;
|
|
23676
|
+
} catch (error) {
|
|
23677
|
+
console.error("SDK: Failed to fetch wallet:", error);
|
|
23678
|
+
throw error;
|
|
23679
|
+
}
|
|
23680
|
+
}
|
|
23593
23681
|
/**
|
|
23594
23682
|
* Get connection status
|
|
23595
23683
|
*/
|
|
@@ -23597,13 +23685,41 @@ var DoraCell = class {
|
|
|
23597
23685
|
return this.connectionStatus;
|
|
23598
23686
|
}
|
|
23599
23687
|
/**
|
|
23600
|
-
*
|
|
23688
|
+
* Fetch available extensions (DID numbers) from the API
|
|
23689
|
+
*/
|
|
23690
|
+
async fetchExtensions() {
|
|
23691
|
+
if (!this.authProvider.isAuthenticated()) {
|
|
23692
|
+
throw new Error("SDK not authenticated. Call initialize() first.");
|
|
23693
|
+
}
|
|
23694
|
+
try {
|
|
23695
|
+
const response = await this.apiClient.get("/extensions");
|
|
23696
|
+
const extensions = response.data || response.extensions || response;
|
|
23697
|
+
if (this.credentials && Array.isArray(extensions)) {
|
|
23698
|
+
this.credentials.extensions = extensions;
|
|
23699
|
+
}
|
|
23700
|
+
return Array.isArray(extensions) ? extensions : [];
|
|
23701
|
+
} catch (error) {
|
|
23702
|
+
console.error("SDK: Failed to fetch extensions:", error);
|
|
23703
|
+
return this.credentials?.extensions || [];
|
|
23704
|
+
}
|
|
23705
|
+
}
|
|
23706
|
+
/**
|
|
23707
|
+
* Get available extensions (DID numbers)
|
|
23601
23708
|
*/
|
|
23602
23709
|
getExtensions() {
|
|
23603
|
-
|
|
23604
|
-
|
|
23710
|
+
return this.credentials?.extensions || [];
|
|
23711
|
+
}
|
|
23712
|
+
/**
|
|
23713
|
+
* Update active extension and re-initialize SIP connection
|
|
23714
|
+
*/
|
|
23715
|
+
async setExtension(extension) {
|
|
23716
|
+
console.log(`SDK: Switching to extension ${extension}...`);
|
|
23717
|
+
if (this.credentials) {
|
|
23718
|
+
const domain = this.credentials.sipDomain || "cell.usedora.com";
|
|
23719
|
+
this.credentials.sipUri = `sip:${extension}@${domain}`;
|
|
23720
|
+
await this.initializeUserAgent();
|
|
23721
|
+
this.emitConnectionStatus(this.connectionStatus);
|
|
23605
23722
|
}
|
|
23606
|
-
return this.credentials.extensions.map((ext) => ext.extension);
|
|
23607
23723
|
}
|
|
23608
23724
|
/**
|
|
23609
23725
|
* Event listener management
|
|
@@ -23635,9 +23751,10 @@ var DoraCell = class {
|
|
|
23635
23751
|
}
|
|
23636
23752
|
// Helper methods
|
|
23637
23753
|
emitConnectionStatus(error) {
|
|
23754
|
+
const extension = this.credentials?.extensions?.[0]?.extension || (this.credentials?.sipUri ? extractNumberFromSipUri(this.credentials.sipUri) : void 0);
|
|
23638
23755
|
const state = {
|
|
23639
23756
|
status: this.connectionStatus,
|
|
23640
|
-
extension
|
|
23757
|
+
extension,
|
|
23641
23758
|
error
|
|
23642
23759
|
};
|
|
23643
23760
|
this.events.emit("connection:status", state);
|
|
@@ -23678,6 +23795,22 @@ var DoraCell = class {
|
|
|
23678
23795
|
return v.toString(16);
|
|
23679
23796
|
});
|
|
23680
23797
|
}
|
|
23798
|
+
resolveApiBaseUrl(config) {
|
|
23799
|
+
if (config.apiBaseUrl) return config.apiBaseUrl;
|
|
23800
|
+
if (config.environment) {
|
|
23801
|
+
switch (config.environment) {
|
|
23802
|
+
case "staging":
|
|
23803
|
+
case "dev":
|
|
23804
|
+
return "https://dev.api.cell.usedora.com/api";
|
|
23805
|
+
case "production":
|
|
23806
|
+
return "https://api.cell.usedora.com/api";
|
|
23807
|
+
}
|
|
23808
|
+
}
|
|
23809
|
+
if (typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BASE_API_URL) {
|
|
23810
|
+
return process.env.NEXT_PUBLIC_BASE_API_URL;
|
|
23811
|
+
}
|
|
23812
|
+
return "https://api.cell.usedora.com/api";
|
|
23813
|
+
}
|
|
23681
23814
|
};
|
|
23682
23815
|
|
|
23683
23816
|
exports.AuthenticationError = AuthenticationError;
|