@wazo/sdk 0.41.1 → 0.42.0-rc.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/dist/wazo-sdk.js +42 -41913
- package/esm/__tests__/api-client.test.js +15 -5
- package/esm/api/confd.js +2 -0
- package/esm/domain/CallerID.js +24 -0
- package/esm/domain/Features.js +7 -1
- package/esm/index.js +1 -0
- package/esm/service/__tests__/IssueReporter.test.js +5 -1
- package/esm/types/api/confd.d.ts +2 -0
- package/esm/types/api/confd.d.ts.map +1 -1
- package/esm/types/domain/CallerID.d.ts +22 -0
- package/esm/types/domain/CallerID.d.ts.map +1 -0
- package/esm/types/domain/Features.d.ts +2 -0
- package/esm/types/domain/Features.d.ts.map +1 -1
- package/esm/types/index.d.ts +1 -0
- package/esm/types/index.d.ts.map +1 -1
- package/esm/types/service/getApiClient.d.ts.map +1 -1
- package/esm/types/simple/index.d.ts +2 -0
- package/esm/types/simple/index.d.ts.map +1 -1
- package/esm/types/utils/PhoneNumberUtil.d.ts +5 -6
- package/esm/types/utils/PhoneNumberUtil.d.ts.map +1 -1
- package/esm/types/utils/array.d.ts.map +1 -1
- package/esm/utils/PhoneNumberUtil.js +27 -19
- package/esm/utils/__tests__/PhoneNumberUtil.test.js +23 -6
- package/esm/utils/__tests__/api-requester.test.js +19 -15
- package/esm/web-rtc-client.js +1 -1
- package/esm/websocket-client.js +1 -1
- package/lib/__tests__/api-client.test.js +15 -5
- package/lib/api/confd.js +2 -0
- package/lib/checker/Checker.js +2 -2
- package/lib/domain/CallerID.js +27 -0
- package/lib/domain/Features.js +6 -1
- package/lib/domain/Phone/WebRTCPhone.js +12 -12
- package/lib/index.js +4 -2
- package/lib/service/CallApi.js +4 -4
- package/lib/service/__tests__/IssueReporter.test.js +5 -1
- package/lib/simple/Auth.js +5 -5
- package/lib/simple/Phone.js +9 -9
- package/lib/simple/room/Participant.js +2 -2
- package/lib/simple/room/Room.js +8 -8
- package/lib/simple/room/SipRoom.js +2 -2
- package/lib/simple/utils.js +1 -1
- package/lib/types/api/confd.d.ts +2 -0
- package/lib/types/api/confd.d.ts.map +1 -1
- package/lib/types/domain/CallerID.d.ts +22 -0
- package/lib/types/domain/CallerID.d.ts.map +1 -0
- package/lib/types/domain/Features.d.ts +2 -0
- package/lib/types/domain/Features.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/service/getApiClient.d.ts.map +1 -1
- package/lib/types/simple/index.d.ts +2 -0
- package/lib/types/simple/index.d.ts.map +1 -1
- package/lib/types/utils/PhoneNumberUtil.d.ts +5 -6
- package/lib/types/utils/PhoneNumberUtil.d.ts.map +1 -1
- package/lib/types/utils/array.d.ts.map +1 -1
- package/lib/utils/PhoneNumberUtil.js +28 -25
- package/lib/utils/__tests__/PhoneNumberUtil.test.js +22 -5
- package/lib/utils/__tests__/api-requester.test.js +19 -15
- package/lib/utils/api-requester.js +2 -2
- package/lib/web-rtc-client.js +23 -27
- package/lib/websocket-client.js +1 -1
- package/package.json +23 -21
- package/src/__tests__/api-client.test.ts +15 -5
- package/src/api/confd.ts +3 -0
- package/src/domain/CallerID.ts +49 -0
- package/src/domain/Features.ts +9 -1
- package/src/index.ts +1 -0
- package/src/service/__tests__/IssueReporter.test.ts +5 -1
- package/src/utils/PhoneNumberUtil.ts +31 -24
- package/src/utils/__tests__/PhoneNumberUtil.test.ts +31 -6
- package/src/utils/__tests__/api-requester.test.ts +20 -16
- package/src/web-rtc-client.ts +1 -1
- package/src/websocket-client.ts +1 -1
|
@@ -13,7 +13,7 @@ describe('Formatting phone numbers', () => {
|
|
|
13
13
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+33675456545', 'FR')).toBe('06 75 45 65 45');
|
|
14
14
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0675456545', 'FR')).toBe('06 75 45 65 45');
|
|
15
15
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+33675456545', 'US')).toBe('+33 6 75 45 65 45');
|
|
16
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0675456545', 'US')).toBe('+
|
|
16
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0675456545', 'US')).toBe('+33 6 75 45 65 45');
|
|
17
17
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('4188884356', 'US')).toBe('(418) 888-4356');
|
|
18
18
|
});
|
|
19
19
|
it('should format real phone numbers when typing', () => {
|
|
@@ -21,12 +21,12 @@ describe('Formatting phone numbers', () => {
|
|
|
21
21
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('067545', 'FR', true)).toBe('06 75 45');
|
|
22
22
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+3367545', 'US', true)).toBe('+33 6 75 45');
|
|
23
23
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('067545', 'US', true)).toBe('067545');
|
|
24
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('418808', 'US', true)).toBe('418
|
|
24
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('418808', 'US', true)).toBe('(418) 808');
|
|
25
25
|
});
|
|
26
26
|
it('should use the international number if the country number is different from the given country', () => {
|
|
27
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'FR')).toBe('+20
|
|
28
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+14188004554', 'FR')).toBe('+1 418
|
|
29
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'EG')).toBe('
|
|
27
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'FR')).toBe('+20 10 05803648');
|
|
28
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+14188004554', 'FR')).toBe('+1 418 800 4554');
|
|
29
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'EG')).toBe('010 05803648');
|
|
30
30
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0634543450', 'FR')).toBe('06 34 54 34 50');
|
|
31
31
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('4188034302', 'US')).toBe('(418) 803-4302');
|
|
32
32
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('8775863230', 'CA')).toBe('(877) 586-3230');
|
|
@@ -53,3 +53,20 @@ describe('getCallableNumber', () => {
|
|
|
53
53
|
expect((0, PhoneNumberUtil_1.getCallableNumber)('9000')).toBe('9000');
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
|
+
describe('guessParsePhoneNumber', () => {
|
|
57
|
+
it('should guess with default countries', () => {
|
|
58
|
+
const parsedNumber = (0, PhoneNumberUtil_1.guessParsePhoneNumber)('0675456545');
|
|
59
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.country).toBe('FR');
|
|
60
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
it('should guess with specified countries', () => {
|
|
63
|
+
const parsedNumber = (0, PhoneNumberUtil_1.guessParsePhoneNumber)('752097514', undefined, ['JP']);
|
|
64
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.country).toBe('JP');
|
|
65
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('should used use defaultCountry has guesser', () => {
|
|
68
|
+
const parsedNumber = (0, PhoneNumberUtil_1.guessParsePhoneNumber)('752097514', 'JP', []);
|
|
69
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.country).toBe('JP');
|
|
70
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -88,12 +88,14 @@ describe('Retrieving headers', () => {
|
|
|
88
88
|
});
|
|
89
89
|
describe('Calling fetch', () => {
|
|
90
90
|
it('should call fetch without body but query string in get method', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
Object.defineProperty(global, 'fetch', {
|
|
92
|
+
value: jest.fn(() => Promise.resolve({
|
|
93
|
+
json: () => Promise.resolve({}),
|
|
94
|
+
headers: {
|
|
95
|
+
get: () => '',
|
|
96
|
+
},
|
|
97
|
+
})),
|
|
98
|
+
});
|
|
97
99
|
yield new api_requester_1.default({
|
|
98
100
|
server,
|
|
99
101
|
agent: null,
|
|
@@ -113,15 +115,17 @@ describe('Calling fetch', () => {
|
|
|
113
115
|
describe('With a refresh token', () => {
|
|
114
116
|
it('should retry the call with a new token', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
115
117
|
let calls = 0;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
Object.defineProperty(global, 'fetch', {
|
|
119
|
+
value: jest.fn(() => {
|
|
120
|
+
calls++;
|
|
121
|
+
return Promise.resolve({
|
|
122
|
+
headers: {
|
|
123
|
+
get: () => 'application/json',
|
|
124
|
+
},
|
|
125
|
+
status: calls === 1 ? 401 : 200,
|
|
126
|
+
json: () => Promise.resolve({}),
|
|
127
|
+
});
|
|
128
|
+
}),
|
|
125
129
|
});
|
|
126
130
|
const requester = new api_requester_1.default({
|
|
127
131
|
server,
|
|
@@ -73,8 +73,8 @@ class ApiRequester {
|
|
|
73
73
|
enableErrorLogging() {
|
|
74
74
|
this.shouldLogErrors = true;
|
|
75
75
|
}
|
|
76
|
-
call(
|
|
77
|
-
return __awaiter(this,
|
|
76
|
+
call(path_1) {
|
|
77
|
+
return __awaiter(this, arguments, void 0, function* (path, method = 'get', body = null, headers = null, parse = ApiRequester.defaultParser, firstCall = true) {
|
|
78
78
|
const url = this.computeUrl(method, path, body);
|
|
79
79
|
const newHeaders = this.getHeaders(headers);
|
|
80
80
|
let newBody = method === 'get' ? null : body;
|
package/lib/web-rtc-client.js
CHANGED
|
@@ -249,8 +249,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
249
249
|
return this.register();
|
|
250
250
|
}
|
|
251
251
|
onDisconnect(error) {
|
|
252
|
-
var _a;
|
|
253
252
|
return __awaiter(this, void 0, void 0, function* () {
|
|
253
|
+
var _a;
|
|
254
254
|
logger.info('sdk webrtc disconnected', { method: 'delegate.onConnect', clientId: this.clientId, error });
|
|
255
255
|
this.connectionPromise = null;
|
|
256
256
|
// The UA will attempt to reconnect automatically when an error occurred
|
|
@@ -266,9 +266,9 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
266
266
|
}
|
|
267
267
|
});
|
|
268
268
|
}
|
|
269
|
-
register(
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
register() {
|
|
270
|
+
return __awaiter(this, arguments, void 0, function* (tries = 0) {
|
|
271
|
+
var _a;
|
|
272
272
|
const logInfo = {
|
|
273
273
|
clientId: this.clientId,
|
|
274
274
|
userAgent: !!this.userAgent,
|
|
@@ -449,14 +449,10 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
449
449
|
conference,
|
|
450
450
|
options,
|
|
451
451
|
});
|
|
452
|
-
const inviterOptions = {
|
|
453
|
-
sessionDescriptionHandlerOptionsReInvite: {
|
|
452
|
+
const inviterOptions = Object.assign({ sessionDescriptionHandlerOptionsReInvite: {
|
|
454
453
|
conference,
|
|
455
454
|
audioOnly,
|
|
456
|
-
},
|
|
457
|
-
earlyMedia: true,
|
|
458
|
-
options,
|
|
459
|
-
};
|
|
455
|
+
}, earlyMedia: true }, options);
|
|
460
456
|
if (audioOnly) {
|
|
461
457
|
inviterOptions.sessionDescriptionHandlerModifiersReInvite = [modifiers_1.stripVideo];
|
|
462
458
|
}
|
|
@@ -576,8 +572,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
576
572
|
});
|
|
577
573
|
}
|
|
578
574
|
getStats(session) {
|
|
579
|
-
var _a;
|
|
580
575
|
return __awaiter(this, void 0, void 0, function* () {
|
|
576
|
+
var _a;
|
|
581
577
|
const pc = (_a = session.sessionDescriptionHandler) === null || _a === void 0 ? void 0 : _a.peerConnection;
|
|
582
578
|
if (!pc) {
|
|
583
579
|
return null;
|
|
@@ -628,8 +624,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
628
624
|
}
|
|
629
625
|
});
|
|
630
626
|
}
|
|
631
|
-
close(
|
|
632
|
-
return __awaiter(this,
|
|
627
|
+
close() {
|
|
628
|
+
return __awaiter(this, arguments, void 0, function* (force = false) {
|
|
633
629
|
logger.info('sdk webrtc closing client', {
|
|
634
630
|
clientId: this.clientId,
|
|
635
631
|
userAgent: !!this.userAgent,
|
|
@@ -817,8 +813,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
817
813
|
}
|
|
818
814
|
// Returns true if a re-INVITE is required
|
|
819
815
|
upgradeToVideo(session, constraints, isConference) {
|
|
820
|
-
var _a, _b;
|
|
821
816
|
return __awaiter(this, void 0, void 0, function* () {
|
|
817
|
+
var _a, _b;
|
|
822
818
|
const pc = (_a = session.sessionDescriptionHandler) === null || _a === void 0 ? void 0 : _a.peerConnection;
|
|
823
819
|
// Check if a video sender already exists
|
|
824
820
|
let videoSender;
|
|
@@ -875,8 +871,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
875
871
|
localStream.removeTrack(videoTrack);
|
|
876
872
|
});
|
|
877
873
|
}
|
|
878
|
-
getStreamFromConstraints(
|
|
879
|
-
return __awaiter(this,
|
|
874
|
+
getStreamFromConstraints(constraints_1) {
|
|
875
|
+
return __awaiter(this, arguments, void 0, function* (constraints, conference = false) {
|
|
880
876
|
const video = constraints && constraints.video;
|
|
881
877
|
const { constraints: newConstraints, } = this.getMediaConfiguration(video, conference, constraints);
|
|
882
878
|
let newStream = null;
|
|
@@ -2032,9 +2028,9 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
2032
2028
|
_makeURI(target) {
|
|
2033
2029
|
return user_agent_1.UserAgent.makeURI(`sip:${target}@${this.config.host}`);
|
|
2034
2030
|
}
|
|
2035
|
-
_disconnectTransport(
|
|
2036
|
-
|
|
2037
|
-
|
|
2031
|
+
_disconnectTransport() {
|
|
2032
|
+
return __awaiter(this, arguments, void 0, function* (force = false) {
|
|
2033
|
+
var _a;
|
|
2038
2034
|
const transport = (_a = this.userAgent) === null || _a === void 0 ? void 0 : _a.transport;
|
|
2039
2035
|
if (force && transport) {
|
|
2040
2036
|
// Bypass sip.js state machine that prevent to close WS with the state `Connecting`
|
|
@@ -2155,8 +2151,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
2155
2151
|
}
|
|
2156
2152
|
});
|
|
2157
2153
|
}
|
|
2158
|
-
_accept(
|
|
2159
|
-
return __awaiter(this,
|
|
2154
|
+
_accept(session_1) {
|
|
2155
|
+
return __awaiter(this, arguments, void 0, function* (session, options = {}) {
|
|
2160
2156
|
if (session.state === session_state_1.SessionState.Terminated || session.state === session_state_1.SessionState.Terminating) {
|
|
2161
2157
|
const error = 'Trying to accept a terminated sipSession.';
|
|
2162
2158
|
logger.warn(error, { state: session.state, sessionId: session.id });
|
|
@@ -2181,8 +2177,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
2181
2177
|
}
|
|
2182
2178
|
});
|
|
2183
2179
|
}
|
|
2184
|
-
_reject(
|
|
2185
|
-
return __awaiter(this,
|
|
2180
|
+
_reject(session_1) {
|
|
2181
|
+
return __awaiter(this, arguments, void 0, function* (session, options = {}) {
|
|
2186
2182
|
if (session.state !== session_state_1.SessionState.Initial && session.state !== session_state_1.SessionState.Establishing) {
|
|
2187
2183
|
logger.warn('Trying to reject a session in a wrong state', { state: session.state, sessionId: session.id });
|
|
2188
2184
|
return;
|
|
@@ -2200,8 +2196,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
2200
2196
|
}
|
|
2201
2197
|
});
|
|
2202
2198
|
}
|
|
2203
|
-
_cancel(
|
|
2204
|
-
return __awaiter(this,
|
|
2199
|
+
_cancel(session_1) {
|
|
2200
|
+
return __awaiter(this, arguments, void 0, function* (session, options = {}) {
|
|
2205
2201
|
if (session.state !== session_state_1.SessionState.Initial && session.state !== session_state_1.SessionState.Establishing) {
|
|
2206
2202
|
logger.warn('Trying to cancel a session in a wrong state', { state: session.state, sessionId: session.id });
|
|
2207
2203
|
return;
|
|
@@ -2214,8 +2210,8 @@ class WebRTCClient extends Emitter_1.default {
|
|
|
2214
2210
|
}
|
|
2215
2211
|
});
|
|
2216
2212
|
}
|
|
2217
|
-
_bye(
|
|
2218
|
-
return __awaiter(this,
|
|
2213
|
+
_bye(session_1) {
|
|
2214
|
+
return __awaiter(this, arguments, void 0, function* (session, options = {}) {
|
|
2219
2215
|
if (session.state !== session_state_1.SessionState.Established) {
|
|
2220
2216
|
logger.warn('Trying to end a session in a wrong state', { state: session.state, sessionId: session.id });
|
|
2221
2217
|
return null;
|
package/lib/websocket-client.js
CHANGED
|
@@ -220,7 +220,7 @@ class WebSocketClient extends Emitter_1.default {
|
|
|
220
220
|
logger.warn('Trying to close an already closed websocket, bailing.', { url: this._getUrl() });
|
|
221
221
|
return;
|
|
222
222
|
}
|
|
223
|
-
this.socket.close();
|
|
223
|
+
this.socket.close(1000);
|
|
224
224
|
this.initialized = false;
|
|
225
225
|
if (force) {
|
|
226
226
|
this.host = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wazo/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0-rc.0",
|
|
4
4
|
"description": "Wazo's JavaScript Software Development Kit.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -50,27 +50,26 @@
|
|
|
50
50
|
"events": "^3.3.0",
|
|
51
51
|
"fstream": "^1.0.12",
|
|
52
52
|
"getstats": "wazo-platform/getStats#fix_stats_mobile",
|
|
53
|
-
"
|
|
54
|
-
"js-base64": "^3.7.5",
|
|
53
|
+
"js-base64": "^3.7.7",
|
|
55
54
|
"json-to-graphql-query": "^2.2.5",
|
|
56
|
-
"jsrsasign": "^11.
|
|
57
|
-
"
|
|
55
|
+
"jsrsasign": "^11.1.0",
|
|
56
|
+
"libphonenumber-js": "^1.10.60",
|
|
57
|
+
"moment": "^2.30.1",
|
|
58
58
|
"reconnecting-websocket": "^4.4.0",
|
|
59
|
-
"sdp-transform": "^2.14.
|
|
59
|
+
"sdp-transform": "^2.14.2",
|
|
60
60
|
"sip.js": "^0.21.2",
|
|
61
61
|
"webrtc-adapter": "^8.2.3"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@babel/core": "^7.
|
|
65
|
-
"@babel/preset-env": "^7.
|
|
66
|
-
"@babel/preset-typescript": "^7.
|
|
67
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
68
|
-
"@rollup/plugin-json": "^6.
|
|
69
|
-
"@rollup/plugin-node-resolve": "^15.
|
|
70
|
-
"@rollup/plugin-terser": "^0.4.
|
|
71
|
-
"@rollup/plugin-typescript": "^11.1.
|
|
72
|
-
"@types/events": "^3.0.
|
|
73
|
-
"@types/google-libphonenumber": "^7.4.23",
|
|
64
|
+
"@babel/core": "^7.24.4",
|
|
65
|
+
"@babel/preset-env": "^7.24.4",
|
|
66
|
+
"@babel/preset-typescript": "^7.24.1",
|
|
67
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
68
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
69
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
70
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
71
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
72
|
+
"@types/events": "^3.0.3",
|
|
74
73
|
"@types/jest": "^29.5.2",
|
|
75
74
|
"@types/jsrsasign": "^10.5.8",
|
|
76
75
|
"@types/node": "^20.4.0",
|
|
@@ -79,20 +78,23 @@
|
|
|
79
78
|
"@typescript-eslint/parser": "^5.61.0",
|
|
80
79
|
"babel-core": "^7.0.0-bridge.0",
|
|
81
80
|
"babel-eslint": "10.1.0",
|
|
82
|
-
"babel-loader": "^9.1.
|
|
81
|
+
"babel-loader": "^9.1.3",
|
|
83
82
|
"eslint": "^8.44.0",
|
|
84
83
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
85
84
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
|
86
85
|
"eslint-config-prettier": "^8.8.0",
|
|
87
|
-
"eslint-plugin-import": "^2.
|
|
86
|
+
"eslint-plugin-import": "^2.29.1",
|
|
88
87
|
"eslint-plugin-prettier": "^4.2.1",
|
|
89
88
|
"jest": "^29.6.1",
|
|
90
89
|
"jsonlint": "^1.6.3",
|
|
91
90
|
"prettier-eslint-cli": "^7.1.0",
|
|
92
|
-
"rimraf": "^5.0.
|
|
91
|
+
"rimraf": "^5.0.5",
|
|
93
92
|
"rollup": "^3.26.2",
|
|
94
|
-
"ts-jest": "^29.1.
|
|
95
|
-
"typescript": "^5.
|
|
93
|
+
"ts-jest": "^29.1.2",
|
|
94
|
+
"typescript": "^5.4.5"
|
|
95
|
+
},
|
|
96
|
+
"resolutions": {
|
|
97
|
+
"underscore": "1.12.1"
|
|
96
98
|
},
|
|
97
99
|
"engines": {
|
|
98
100
|
"node": ">=18.0.0"
|
|
@@ -87,7 +87,9 @@ client.setToken(token);
|
|
|
87
87
|
describe('With correct API results', () => {
|
|
88
88
|
beforeEach(() => {
|
|
89
89
|
jest.resetModules();
|
|
90
|
-
|
|
90
|
+
Object.defineProperty(global, 'fetch', {
|
|
91
|
+
value: jest.fn(() => Promise.resolve(mockedJson) as any),
|
|
92
|
+
});
|
|
91
93
|
});
|
|
92
94
|
|
|
93
95
|
describe('logIn test', () => {
|
|
@@ -135,7 +137,9 @@ describe('With correct API results', () => {
|
|
|
135
137
|
describe('With unAuthorized API results', () => {
|
|
136
138
|
beforeEach(() => {
|
|
137
139
|
jest.resetModules();
|
|
138
|
-
|
|
140
|
+
Object.defineProperty(global, 'fetch', {
|
|
141
|
+
value: jest.fn(() => Promise.resolve(mockedUnAuthorized) as any),
|
|
142
|
+
});
|
|
139
143
|
});
|
|
140
144
|
|
|
141
145
|
describe('checkLogin test', () => {
|
|
@@ -157,7 +161,9 @@ describe('With unAuthorized API results', () => {
|
|
|
157
161
|
describe('With not found API results', () => {
|
|
158
162
|
beforeEach(() => {
|
|
159
163
|
jest.resetModules();
|
|
160
|
-
|
|
164
|
+
Object.defineProperty(global, 'fetch', {
|
|
165
|
+
value: jest.fn(() => Promise.resolve(mockedNotFound) as any),
|
|
166
|
+
});
|
|
161
167
|
});
|
|
162
168
|
|
|
163
169
|
describe('fetchVoicemail test', () => {
|
|
@@ -192,7 +198,9 @@ describe('With not found API results', () => {
|
|
|
192
198
|
describe('With erroneous text API results', () => {
|
|
193
199
|
beforeEach(() => {
|
|
194
200
|
jest.resetModules();
|
|
195
|
-
|
|
201
|
+
Object.defineProperty(global, 'fetch', {
|
|
202
|
+
value: jest.fn(() => Promise.resolve(mockedTextError) as any),
|
|
203
|
+
});
|
|
196
204
|
});
|
|
197
205
|
|
|
198
206
|
it('throw an exception when the response is >= 500', async () => {
|
|
@@ -217,7 +225,9 @@ describe('With erroneous text API results', () => {
|
|
|
217
225
|
describe('With erroneous json API results', () => {
|
|
218
226
|
beforeEach(() => {
|
|
219
227
|
jest.resetModules();
|
|
220
|
-
|
|
228
|
+
Object.defineProperty(global, 'fetch', {
|
|
229
|
+
value: jest.fn(() => Promise.resolve(mockedJsonError) as any),
|
|
230
|
+
});
|
|
221
231
|
});
|
|
222
232
|
|
|
223
233
|
it('throw an exception when the response is >= 500', async () => {
|
package/src/api/confd.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ApiRequester from '../utils/api-requester';
|
|
2
2
|
import type { UUID, ListConfdUsersResponse, ListApplicationsResponse } from '../domain/types';
|
|
3
3
|
import type { MeetingCreateArguments, MeetingUpdateArguments } from '../domain/Meeting';
|
|
4
|
+
import CallerID from '../domain/CallerID';
|
|
4
5
|
import Profile from '../domain/Profile';
|
|
5
6
|
import SipLine from '../domain/SipLine';
|
|
6
7
|
import ExternalApp from '../domain/ExternalApp';
|
|
@@ -35,6 +36,7 @@ export interface ConfD {
|
|
|
35
36
|
guestGetMeeting: (meetingUuid: string) => Promise<Meeting>;
|
|
36
37
|
guestAuthorizationRequest: (userUuid: string, meetingUuid: string, username: string) => Promise<any>;
|
|
37
38
|
guestAuthorizationCheck: (userUuid: string, meetingUuid: string, authorizationUuid: string) => Promise<any>;
|
|
39
|
+
getOutgoingCallerIDs: (userUuid: string) => Promise<CallerID[]>;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export default ((client: ApiRequester, baseUrl: string): ConfD => ({
|
|
@@ -107,4 +109,5 @@ export default ((client: ApiRequester, baseUrl: string): ConfD => ({
|
|
|
107
109
|
guest_name: username,
|
|
108
110
|
}).then(MeetingAuthorization.parse),
|
|
109
111
|
guestAuthorizationCheck: (userUuid: string, meetingUuid: string, authorizationUuid: string): Promise<any> => client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
|
|
112
|
+
getOutgoingCallerIDs: (userUuid: string): Promise<CallerID[]> => client.get(`${baseUrl}/users/${userUuid}/callerids/outgoing`, null).then(CallerID.parseMany),
|
|
110
113
|
}));
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import newFrom from '../utils/new-from';
|
|
2
|
+
|
|
3
|
+
type Response = {
|
|
4
|
+
number?: string;
|
|
5
|
+
type: 'main' | 'associated' | 'anonymous';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ListResponse = {
|
|
9
|
+
items: Response[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type Arguments = {
|
|
13
|
+
number?: string;
|
|
14
|
+
type: 'main' | 'associated' | 'anonymous';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default class CallerID {
|
|
18
|
+
number?: string;
|
|
19
|
+
|
|
20
|
+
idType: 'main' | 'associated' | 'anonymous';
|
|
21
|
+
|
|
22
|
+
type: string;
|
|
23
|
+
|
|
24
|
+
static parse(plain: Response): CallerID {
|
|
25
|
+
return new CallerID({
|
|
26
|
+
number: plain.number,
|
|
27
|
+
type: plain.type,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static parseMany(plain: ListResponse): CallerID[] {
|
|
32
|
+
return plain.items.map(item => CallerID.parse(item));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static newFrom(profile: CallerID) {
|
|
36
|
+
return newFrom(profile, CallerID);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
constructor({
|
|
40
|
+
type,
|
|
41
|
+
number,
|
|
42
|
+
}: Arguments) {
|
|
43
|
+
this.idType = type;
|
|
44
|
+
this.number = number;
|
|
45
|
+
// Useful to compare instead of instanceof with minified code
|
|
46
|
+
this.type = 'CallerID';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
package/src/domain/Features.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import getApiClient from '../service/getApiClient';
|
|
2
2
|
|
|
3
|
-
export const FEATURES = ['chat', 'video', 'call_recording', 'fax', 'mobile_double_call', 'mobile_gsm', 'meeting'];
|
|
3
|
+
export const FEATURES = ['chat', 'video', 'call_recording', 'fax', 'mobile_double_call', 'mobile_gsm', 'meeting', 'caller_id'];
|
|
4
4
|
export const getScopeName = (featureName: string) => `enterprise.app.${featureName}`;
|
|
5
5
|
const scopesToCheck = FEATURES.map(getScopeName); // Handle available features on the engine.
|
|
6
6
|
|
|
@@ -19,6 +19,8 @@ class Features {
|
|
|
19
19
|
|
|
20
20
|
_hasMeeting: boolean;
|
|
21
21
|
|
|
22
|
+
_hasCallerID: boolean;
|
|
23
|
+
|
|
22
24
|
constructor() {
|
|
23
25
|
this._hasChat = true;
|
|
24
26
|
this._hasVideo = true;
|
|
@@ -27,6 +29,7 @@ class Features {
|
|
|
27
29
|
this._hasMobileDoubleCall = true;
|
|
28
30
|
this._hasMobileGsm = true;
|
|
29
31
|
this._hasMeeting = true;
|
|
32
|
+
this._hasCallerID = false;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
async fetchAccess() {
|
|
@@ -51,6 +54,7 @@ class Features {
|
|
|
51
54
|
this._hasMobileDoubleCall = this._hasFeatures(scopes, 'mobile_double_call');
|
|
52
55
|
this._hasMobileGsm = this._hasFeatures(scopes, 'mobile_gsm');
|
|
53
56
|
this._hasMeeting = this._hasFeatures(scopes, 'meeting');
|
|
57
|
+
this._hasCallerID = this._hasFeatures(scopes, 'caller_id');
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
hasChat() {
|
|
@@ -81,6 +85,10 @@ class Features {
|
|
|
81
85
|
return this._hasMeeting;
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
hasCallerID() {
|
|
89
|
+
return this._hasCallerID;
|
|
90
|
+
}
|
|
91
|
+
|
|
84
92
|
_hasFeatures(scopes: Record<string, any>, featureName: string) {
|
|
85
93
|
const scopeName = getScopeName(featureName);
|
|
86
94
|
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ export { default as Room } from './domain/Room';
|
|
|
24
24
|
export { default as CallSession } from './domain/CallSession';
|
|
25
25
|
export { default as IndirectTransfer } from './domain/IndirectTransfer';
|
|
26
26
|
export { default as SwitchboardCall } from './domain/SwitchboardCall';
|
|
27
|
+
export { default as CallerID } from './domain/CallerID';
|
|
27
28
|
export { default as WebRTCPhone } from './domain/Phone/WebRTCPhone';
|
|
28
29
|
export { default as CTIPhone } from './domain/Phone/CTIPhone';
|
|
29
30
|
export { default as Meeting, MeetingCreateArguments, MeetingUpdateArguments } from './domain/Meeting';
|
|
@@ -24,7 +24,11 @@ describe('IssueReporter', () => {
|
|
|
24
24
|
});
|
|
25
25
|
beforeEach(() => {
|
|
26
26
|
jest.resetAllMocks();
|
|
27
|
-
|
|
27
|
+
Object.defineProperty(global, 'fetch', {
|
|
28
|
+
value: jest.fn(() => ({
|
|
29
|
+
catch: () => {},
|
|
30
|
+
})),
|
|
31
|
+
});
|
|
28
32
|
});
|
|
29
33
|
afterAll(() => {
|
|
30
34
|
console.log = oldLog;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AsYouType, parsePhoneNumber as libParsePhoneNumber, CountryCode } from 'libphonenumber-js';
|
|
2
2
|
|
|
3
|
-
const PhoneNumberUtil = LibPhoneNumber.PhoneNumberUtil.getInstance();
|
|
4
|
-
const {
|
|
5
|
-
PhoneNumberFormat,
|
|
6
|
-
AsYouTypeFormatter,
|
|
7
|
-
} = LibPhoneNumber;
|
|
8
3
|
// eslint-disable-next-line
|
|
9
4
|
const EXTRA_CHAR_REGEXP = /[^+*\d]/g;
|
|
5
|
+
const DEFAULT_GUESSING_COUNTRIES: CountryCode[] = ['US', 'FR', 'GB', 'AU'];
|
|
10
6
|
|
|
11
7
|
const shouldBeFormatted = (number: string | null | undefined) => {
|
|
12
8
|
if (!number || number.length <= 5) {
|
|
@@ -24,7 +20,23 @@ const isSameCountry = (country1: string, country2: string) => {
|
|
|
24
20
|
return country1 === country2;
|
|
25
21
|
};
|
|
26
22
|
|
|
27
|
-
const
|
|
23
|
+
const guessParsePhoneNumber = (number: string, defaultCountry?: CountryCode, guessingCountries: CountryCode[] = DEFAULT_GUESSING_COUNTRIES) => {
|
|
24
|
+
const mergedCountries = [...new Set([defaultCountry, ...guessingCountries])].filter(Boolean) as CountryCode[];
|
|
25
|
+
|
|
26
|
+
let parsedNumber;
|
|
27
|
+
for (let i = 0; i < mergedCountries.length; i++) {
|
|
28
|
+
const country = mergedCountries[i];
|
|
29
|
+
|
|
30
|
+
parsedNumber = libParsePhoneNumber(number, country);
|
|
31
|
+
if (parsedNumber.isValid()) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return parsedNumber;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getDisplayableNumber = (rawNumber: string, country: CountryCode, asYouType = false, guessingCountries: CountryCode[] | undefined = DEFAULT_GUESSING_COUNTRIES): string => {
|
|
28
40
|
if (!rawNumber) {
|
|
29
41
|
return rawNumber;
|
|
30
42
|
}
|
|
@@ -38,18 +50,16 @@ const getDisplayableNumber = (rawNumber: string, country: string, asYouType = fa
|
|
|
38
50
|
let displayValue = '';
|
|
39
51
|
|
|
40
52
|
if (asYouType) {
|
|
41
|
-
|
|
42
|
-
number.split('').forEach(char => {
|
|
43
|
-
displayValue = formatter.inputDigit(char);
|
|
44
|
-
});
|
|
53
|
+
displayValue = new AsYouType(country).input(number);
|
|
45
54
|
} else {
|
|
46
55
|
try {
|
|
47
|
-
const parsedNumber =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const parsedNumber = guessParsePhoneNumber(number, country, guessingCountries);
|
|
57
|
+
if (parsedNumber?.isValid()) {
|
|
58
|
+
displayValue = isSameCountry(String(parsedNumber.country), country) ? parsedNumber.formatNational() : parsedNumber.formatInternational();
|
|
59
|
+
} else {
|
|
60
|
+
displayValue = rawNumber;
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
53
63
|
displayValue = rawNumber;
|
|
54
64
|
}
|
|
55
65
|
}
|
|
@@ -59,16 +69,13 @@ const getDisplayableNumber = (rawNumber: string, country: string, asYouType = fa
|
|
|
59
69
|
|
|
60
70
|
const parsePhoneNumber = (phoneNumber: string): string => phoneNumber.replace(EXTRA_CHAR_REGEXP, '');
|
|
61
71
|
|
|
62
|
-
const getCallableNumber = (number: string, country?:
|
|
72
|
+
const getCallableNumber = (number: string, country?: CountryCode): string => {
|
|
63
73
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return parsePhoneNumber(number);
|
|
74
|
+
const callableNumber = country ? getDisplayableNumber(number, country) : number;
|
|
75
|
+
return parsePhoneNumber(callableNumber);
|
|
69
76
|
} catch (_) {
|
|
70
77
|
return number;
|
|
71
78
|
}
|
|
72
79
|
};
|
|
73
80
|
|
|
74
|
-
export {
|
|
81
|
+
export { parsePhoneNumber, getDisplayableNumber, guessParsePhoneNumber, getCallableNumber, type CountryCode };
|