Skip to content
This repository was archived by the owner on Oct 18, 2024. It is now read-only.

Commit cd4f2be

Browse files
Merge pull request #722 from SuperViz/fix/build-esm-files
feat: add socket client library to SDK
2 parents b19cbb9 + 0ef223a commit cd4f2be

File tree

33 files changed

+785
-72
lines changed

33 files changed

+785
-72
lines changed

__mocks__/io.mock.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { jest } from '@jest/globals';
2-
import { Room } from '@superviz/socket-client';
2+
import { Room } from '../src/lib/socket';
33

44
export const MOCK_IO = {
55
ClientState: {

jest.setup.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ global.DOMPoint = class {
3636
}
3737
};
3838

39-
jest.mock('@superviz/socket-client', () => MOCK_IO);
39+
jest.mock('./src/lib/socket', () => MOCK_IO);

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@
9292
"lodash.isequal": "^4.5.0",
9393
"luxon": "^3.4.4",
9494
"rxjs": "^7.8.1",
95-
"semantic-release-version-file": "^1.0.2"
95+
"semantic-release-version-file": "^1.0.2",
96+
"socket.io-client": "^4.7.5",
97+
"zod": "^3.23.8"
9698
},
9799
"config": {
98100
"commitizen": {

src/components/base/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as Socket from '@superviz/socket-client';
1+
import * as Socket from '../../lib/socket';
22

33
import { ComponentLifeCycleEvent } from '../../common/types/events.types';
44
import { Group } from '../../common/types/participant.types';

src/components/form-elements/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SocketEvent } from '@superviz/socket-client';
1+
import type { SocketEvent } from '../../lib/socket';
22

33
import { Participant } from '../../common/types/participant.types';
44
import { StoreType } from '../../common/types/stores.types';

src/components/form-elements/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SocketEvent } from '@superviz/socket-client';
1+
import { SocketEvent } from '../../lib/socket';
22

33
export type FormElementsProps = {
44
fields?: string[] | string;

src/components/presence-mouse/canvas/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as Socket from '@superviz/socket-client';
1+
import * as Socket from '../../../lib/socket';
22
import { throttle } from 'lodash';
33

44
import { RealtimeEvent } from '../../../common/types/events.types';

src/components/presence-mouse/html/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as Socket from '@superviz/socket-client';
1+
import * as Socket from '../../../lib/socket';
22
import { isEqual } from 'lodash';
33
import { Subscription, fromEvent, throttleTime } from 'rxjs';
44

src/components/realtime/channel.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as Socket from '@superviz/socket-client';
1+
import * as Socket from '../../lib/socket';
22
import throttle from 'lodash/throttle';
33

44
import { ComponentLifeCycleEvent } from '../../common/types/events.types';

src/components/video/index.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { TextEncoder, TextDecoder } from 'util';
22

3-
import { PresenceEvent } from '@superviz/socket-client';
3+
import { PresenceEvent } from '../../lib/socket';
44

55
import { MOCK_CONFIG } from '../../../__mocks__/config.mock';
66
import { EVENT_BUS_MOCK } from '../../../__mocks__/event-bus.mock';

src/components/video/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PresenceEvent, PresenceEvents, Room } from '@superviz/socket-client';
1+
import { PresenceEvent, PresenceEvents, Room } from '../../lib/socket';
22

33
import { ColorsVariables } from '../../common/types/colors.types';
44
import {

src/components/who-is-online/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PresenceEvent, PresenceEvents } from '@superviz/socket-client';
1+
import { PresenceEvent, PresenceEvents } from '../../lib/socket';
22

33
import { RealtimeEvent, WhoIsOnlineEvent } from '../../common/types/events.types';
44
import { Participant, Avatar } from '../../common/types/participant.types';

src/core/launcher/index.test.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { PresenceEvent } from '@superviz/socket-client';
2-
31
import { MOCK_CONFIG } from '../../../__mocks__/config.mock';
42
import { EVENT_BUS_MOCK } from '../../../__mocks__/event-bus.mock';
53
import { MOCK_GROUP, MOCK_LOCAL_PARTICIPANT } from '../../../__mocks__/participants.mock';

src/core/launcher/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as Socket from '@superviz/socket-client';
1+
import * as Socket from '../../lib/socket';
22
import { isEqual } from 'lodash';
33

44
import { ParticipantEvent } from '../../common/types/events.types';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type ErrorCallback = (error: Error) => void;
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* @enum RoomEvents
3+
* @description events that the server listens to in the room module
4+
* @property JOIN_ROOM - event to join a room
5+
* @property LEAVE_ROOM - event to leave a room
6+
* @property UPDATE - event to update a room
7+
* @property JOINED_ROOM - event to indicate a user has joined a room
8+
* @property ERROR - event to indicate an error in the room module
9+
*/
10+
export enum RoomEvents {
11+
JOIN_ROOM = 'room.join',
12+
JOINED_ROOM = 'room.joined',
13+
LEAVE_ROOM = 'room.leave',
14+
UPDATE = 'room.update',
15+
ERROR = 'room.error',
16+
}
17+
18+
export enum InternalRoomEvents {
19+
GET = 'room.get',
20+
}
21+
22+
/**
23+
* @enum PresenceEvents
24+
* @description events that the server listens to in the presence module
25+
* @property JOINED_ROOM - event to indicate a user has joined a room
26+
* @property LEAVE - event to indicate a user has left a room
27+
* @property UPDATE - event to indicate a user has updated their presence
28+
* @property ERROR - event to indicate an error in the presence module
29+
*/
30+
export enum PresenceEvents {
31+
JOINED_ROOM = 'presence.joined-room',
32+
LEAVE = 'presence.leave',
33+
ERROR = 'presence.error',
34+
UPDATE = 'presence.update',
35+
}
36+
37+
/**
38+
* @enum InternalPresenceEvents
39+
* @description events that the server listens to in the presence module
40+
* @property GET - event to get the presence list
41+
*/
42+
export enum InternalPresenceEvents {
43+
GET = 'presence.get',
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { z } from 'zod';
2+
3+
export const PresenceSchema = z.object({
4+
id: z.string(),
5+
name: z.string(),
6+
});
7+
8+
export type Presence = z.infer<typeof PresenceSchema>;

src/lib/socket/connection/index.ts

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { Subject } from 'rxjs';
2+
import type { Socket } from 'socket.io-client';
3+
4+
import { ErrorCallback } from '../common/types/callbacks.types';
5+
6+
import { ClientState, ConnectionState, SocketErrorEvent, SocketEvent } from './types';
7+
import { Logger } from '../../../common/utils';
8+
9+
export class ClientConnection {
10+
private logger: Logger;
11+
private stateObserver: Subject<ConnectionState>;
12+
13+
public state: ClientState;
14+
15+
constructor(private socket: Socket) {
16+
this.logger = new Logger('@superviz/socket-client/connection');
17+
this.subscribeToManagerEvents();
18+
this.stateObserver = new Subject();
19+
}
20+
21+
public on(next: (state: ConnectionState) => void, error?: ErrorCallback) {
22+
if (this.stateObserver.closed) {
23+
this.stateObserver = new Subject();
24+
}
25+
26+
this.stateObserver.subscribe({
27+
next,
28+
error,
29+
});
30+
}
31+
32+
public off() {
33+
if (this.stateObserver.closed) return;
34+
35+
this.stateObserver.unsubscribe();
36+
}
37+
38+
/**
39+
* @function subscribeToManagerEvents
40+
* @description Subscribe to the manager events
41+
* @returns {void}
42+
*/
43+
private subscribeToManagerEvents(): void {
44+
this.socket.on('connect', this.onConnect);
45+
this.socket.on('disconnect', this.onDisconnect);
46+
this.socket.on('connect_error', this.onConnectError);
47+
this.socket.io.on('error', this.onConnectionError);
48+
this.socket.io.on('reconnect', this.onReconnect);
49+
this.socket.io.on('reconnect_attempt', this.onReconnecAttempt);
50+
this.socket.io.on('reconnect_error', this.onReconnectError);
51+
this.socket.io.on('reconnect_failed', this.onReconnectFailed);
52+
53+
// custom validations listener
54+
this.socket.on(SocketEvent.ERROR, this.onCustomError);
55+
}
56+
57+
/**
58+
* @function changeState
59+
* @description Change the state of the connection
60+
* @returns {void}
61+
*/
62+
private changeState(state: ClientState, reason?: string): void {
63+
this.state = state;
64+
65+
if (this.stateObserver.closed) return;
66+
67+
this.stateObserver.next({
68+
state,
69+
reason,
70+
});
71+
}
72+
73+
/** Manager events handlers */
74+
75+
private onConnect = () => {
76+
this.logger.log('connection @ on connect', 'Connected to the socket');
77+
this.changeState(ClientState.CONNECTED);
78+
};
79+
80+
private onDisconnect = (reason: Socket.DisconnectReason) => {
81+
this.logger.log('connection @ on disconnect', 'Disconnected from the socket');
82+
this.changeState(ClientState.DISCONNECTED, reason);
83+
};
84+
85+
private onConnectError = (error: Error) => {
86+
this.logger.log('connection @ on connect error', 'Connection error', error);
87+
this.changeState(ClientState.CONNECTION_ERROR, error.message);
88+
};
89+
90+
private onConnectionError = (error: Error) => {
91+
this.logger.log('connection @ on connection error', 'Connection error', error);
92+
this.changeState(ClientState.CONNECTION_ERROR, error.message);
93+
};
94+
95+
private onReconnect = () => {
96+
this.logger.log('connection @ on reconnect', 'Reconnected to the socket');
97+
this.changeState(ClientState.CONNECTED);
98+
};
99+
100+
private onReconnectError = (error: Error) => {
101+
this.logger.log('connection @ on reconnect error', 'Reconnect error', error);
102+
this.changeState(ClientState.RECONNECT_ERROR, error.message);
103+
};
104+
105+
private onReconnectFailed = () => {
106+
this.logger.log('connection @ on reconnect failed', 'Failed to reconnect to the socket');
107+
this.changeState(ClientState.RECONNECT_ERROR);
108+
};
109+
110+
private onReconnecAttempt = (attempt: number) => {
111+
this.logger.log('connection @ on reconnect attempt', `Reconnect attempt #${attempt}`);
112+
this.changeState(ClientState.RECONNECTING, `Reconnect attempt #${attempt}`);
113+
};
114+
115+
private onCustomError = (error: SocketErrorEvent) => {
116+
if (error.needsToDisconnect) {
117+
this.socket.disconnect();
118+
}
119+
120+
if (error.level === 'error') {
121+
console.error('[SuperViz - Error]', 'Type: ', error.errorType, 'Message :', error.message);
122+
return;
123+
}
124+
125+
console.warn('[SuperViz - Warning]', 'Type: ', error.errorType, 'Message :', error.message);
126+
};
127+
}

src/lib/socket/connection/types.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @enum ClientState
3+
* @description the state of the client
4+
* @property CONNECTED - the client is connected
5+
* @property CONNECTING - the client is connecting
6+
* @property DISCONNECTED - the client is disconnected
7+
* @property CONNECTION_ERROR - the client has a connection error
8+
* @property RECONNECTING - the client is reconnecting
9+
* @property RECONNECT_ERROR - the client has a reconnect error
10+
*/
11+
export enum ClientState {
12+
CONNECTED = 'CONNECTED',
13+
CONNECTING = 'CONNECTING',
14+
DISCONNECTED = 'DISCONNECTED',
15+
CONNECTION_ERROR = 'CONNECTION_ERROR',
16+
RECONNECTING = 'RECONNECTING',
17+
RECONNECT_ERROR = 'RECONNECT_ERROR',
18+
}
19+
20+
/**
21+
* @interface ConnectionState
22+
* @description the state of the connection
23+
* @property state - the state of the connection
24+
* @property reason - the reason for the state change
25+
*/
26+
export interface ConnectionState {
27+
state: ClientState;
28+
reason?: string;
29+
}
30+
31+
export type SocketErrorEvent = {
32+
errorType: 'message-size-limit' | 'rate-limit' | 'room-connections-limit';
33+
message: string;
34+
connectionId: string;
35+
needsToDisconnect: boolean;
36+
level: 'error' | 'warn';
37+
};
38+
39+
export enum SocketEvent {
40+
ERROR = 'socket-event.error',
41+
}

src/lib/socket/index.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { PresenceEvents, RoomEvents } from './common/types/event.types';
2+
import { ClientState, ConnectionState } from './connection/types';
3+
import { PresenceRoom } from './presence';
4+
import { PresenceCallback, PresenceEvent } from './presence/types';
5+
import { Realtime } from './realtime';
6+
import { Room } from './room';
7+
import { Callback, SocketEvent, JoinRoomPayload, RoomHistory } from './room/types';
8+
9+
export {
10+
Realtime,
11+
PresenceEvents,
12+
RoomEvents,
13+
ClientState,
14+
ConnectionState,
15+
Callback,
16+
SocketEvent,
17+
JoinRoomPayload,
18+
RoomHistory,
19+
PresenceCallback,
20+
PresenceEvent,
21+
Room,
22+
PresenceRoom,
23+
};

0 commit comments

Comments
 (0)