vg-x07df 0.1.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/.azure-pipelines/publish-public.yml +37 -0
- package/.azure-pipelines/publish.yml +39 -0
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/AUTO_JOIN_GUIDE.md +411 -0
- package/README.md +215 -0
- package/Screenshot 2025-09-24 at 14.34.48.png +0 -0
- package/Screenshot 2025-10-04 at 12.58.54.png +0 -0
- package/biome.json +48 -0
- package/examples/demo/.env.example +19 -0
- package/examples/demo/CHANGELOG.md +22 -0
- package/examples/demo/README.md +72 -0
- package/examples/demo/eslint.config.js +23 -0
- package/examples/demo/index.html +13 -0
- package/examples/demo/package.json +34 -0
- package/examples/demo/pnpm-lock.yaml +2098 -0
- package/examples/demo/pnpm-workspace.yaml +1 -0
- package/examples/demo/public/vite.svg +1 -0
- package/examples/demo/src/App.css +52 -0
- package/examples/demo/src/App.tsx +176 -0
- package/examples/demo/src/assets/react.svg +1 -0
- package/examples/demo/src/components/auth/LoginForm.css +144 -0
- package/examples/demo/src/components/auth/LoginForm.tsx +80 -0
- package/examples/demo/src/components/calling/AutoJoinSettings.tsx +213 -0
- package/examples/demo/src/components/calling/AutoJoinStatus.tsx +72 -0
- package/examples/demo/src/components/calling/CallInitiator.css +258 -0
- package/examples/demo/src/components/calling/CallInitiator.tsx +142 -0
- package/examples/demo/src/components/calling/CallNotifications.css +119 -0
- package/examples/demo/src/components/calling/CallNotifications.tsx +108 -0
- package/examples/demo/src/components/calling/IncomingCallModal.css +192 -0
- package/examples/demo/src/components/calling/IncomingCallModal.tsx +78 -0
- package/examples/demo/src/components/calling/MinimizedCall.css +156 -0
- package/examples/demo/src/components/calling/MinimizedCall.tsx +78 -0
- package/examples/demo/src/components/conference/ConferenceHeader.css +265 -0
- package/examples/demo/src/components/conference/ConferenceHeader.tsx +78 -0
- package/examples/demo/src/components/conference/EnhancedControlBar.css +356 -0
- package/examples/demo/src/components/conference/EnhancedControlBar.tsx +262 -0
- package/examples/demo/src/components/conference/PaginationControls.css +67 -0
- package/examples/demo/src/components/conference/PaginationControls.tsx +64 -0
- package/examples/demo/src/components/conference/ParticipantGrid.css +153 -0
- package/examples/demo/src/components/conference/ParticipantGrid.tsx +87 -0
- package/examples/demo/src/components/conference/ParticipantTile.css +210 -0
- package/examples/demo/src/components/conference/ParticipantTile.tsx +114 -0
- package/examples/demo/src/components/conference/VideoConference.css +214 -0
- package/examples/demo/src/components/conference/VideoConference.tsx +93 -0
- package/examples/demo/src/contexts/AuthContext.tsx +105 -0
- package/examples/demo/src/hooks/useAuth.ts +5 -0
- package/examples/demo/src/hooks/useCallTimer.ts +42 -0
- package/examples/demo/src/index.css +68 -0
- package/examples/demo/src/main.tsx +10 -0
- package/examples/demo/src/services/auth.service.ts +153 -0
- package/examples/demo/src/types/auth.types.ts +31 -0
- package/examples/demo/tsconfig.app.json +28 -0
- package/examples/demo/tsconfig.json +7 -0
- package/examples/demo/tsconfig.node.json +26 -0
- package/examples/demo/vite.config.ts +15 -0
- package/images/callpad-without-ai.png +0 -0
- package/package.json +28 -0
- package/packages/sdk/CHANGELOG.md +33 -0
- package/packages/sdk/LICENSE +21 -0
- package/packages/sdk/README.md +97 -0
- package/packages/sdk/documentation.md +1132 -0
- package/packages/sdk/openapi-ts.config.ts +7 -0
- package/packages/sdk/package.json +88 -0
- package/packages/sdk/src/core/auth.manager.ts +52 -0
- package/packages/sdk/src/core/events/event-bus.ts +301 -0
- package/packages/sdk/src/core/events/index.ts +8 -0
- package/packages/sdk/src/core/events/types.ts +165 -0
- package/packages/sdk/src/core/index.ts +3 -0
- package/packages/sdk/src/core/signal/api.config.ts +49 -0
- package/packages/sdk/src/core/signal/index.ts +16 -0
- package/packages/sdk/src/core/signal/signal.client.ts +101 -0
- package/packages/sdk/src/core/signal/types.ts +110 -0
- package/packages/sdk/src/core/socketio/handlers/base.handler.ts +212 -0
- package/packages/sdk/src/core/socketio/handlers/call-accepted.handler.ts +34 -0
- package/packages/sdk/src/core/socketio/handlers/call-canceled.handler.ts +34 -0
- package/packages/sdk/src/core/socketio/handlers/call-declined.handler.ts +29 -0
- package/packages/sdk/src/core/socketio/handlers/call-ended.handler.ts +40 -0
- package/packages/sdk/src/core/socketio/handlers/call-incoming.handler.ts +72 -0
- package/packages/sdk/src/core/socketio/handlers/call-join-info.handler.ts +181 -0
- package/packages/sdk/src/core/socketio/handlers/call-participant-joined.handler.ts +42 -0
- package/packages/sdk/src/core/socketio/handlers/call-participant-joining.handler.ts +42 -0
- package/packages/sdk/src/core/socketio/handlers/call-timeout.handler.ts +31 -0
- package/packages/sdk/src/core/socketio/handlers/handler.registry.ts +62 -0
- package/packages/sdk/src/core/socketio/handlers/index.ts +21 -0
- package/packages/sdk/src/core/socketio/handlers/participant-left.handler.ts +37 -0
- package/packages/sdk/src/core/socketio/handlers/schema.ts +130 -0
- package/packages/sdk/src/core/socketio/index.ts +5 -0
- package/packages/sdk/src/core/socketio/socket.manager.ts +187 -0
- package/packages/sdk/src/core/socketio/types.ts +14 -0
- package/packages/sdk/src/core/types.ts +23 -0
- package/packages/sdk/src/generated/api/core/ApiError.ts +21 -0
- package/packages/sdk/src/generated/api/core/ApiRequestOptions.ts +13 -0
- package/packages/sdk/src/generated/api/core/ApiResult.ts +7 -0
- package/packages/sdk/src/generated/api/core/CancelablePromise.ts +126 -0
- package/packages/sdk/src/generated/api/core/OpenAPI.ts +55 -0
- package/packages/sdk/src/generated/api/core/request.ts +339 -0
- package/packages/sdk/src/generated/api/index.ts +5 -0
- package/packages/sdk/src/generated/api/models.ts +219 -0
- package/packages/sdk/src/generated/api/services.ts +225 -0
- package/packages/sdk/src/hooks/index.ts +21 -0
- package/packages/sdk/src/hooks/useAutoJoin.ts +66 -0
- package/packages/sdk/src/hooks/useCallActions.ts +28 -0
- package/packages/sdk/src/hooks/useCallQuality.ts +416 -0
- package/packages/sdk/src/hooks/useCallState.ts +23 -0
- package/packages/sdk/src/hooks/useConnection.ts +15 -0
- package/packages/sdk/src/hooks/useDevices.ts +296 -0
- package/packages/sdk/src/hooks/useErrorRecovery.ts +299 -0
- package/packages/sdk/src/hooks/useErrors.ts +84 -0
- package/packages/sdk/src/hooks/useEvent.ts +188 -0
- package/packages/sdk/src/hooks/useMediaControls.ts +215 -0
- package/packages/sdk/src/hooks/useParticipantStatus.ts +318 -0
- package/packages/sdk/src/hooks/useParticipants.ts +111 -0
- package/packages/sdk/src/index.ts +66 -0
- package/packages/sdk/src/livekit/constants.ts +76 -0
- package/packages/sdk/src/livekit/device.manager.ts +172 -0
- package/packages/sdk/src/livekit/error-classifier.ts +155 -0
- package/packages/sdk/src/livekit/events/eventBridge.ts +371 -0
- package/packages/sdk/src/livekit/events/trackRegistry.ts +114 -0
- package/packages/sdk/src/livekit/index.ts +49 -0
- package/packages/sdk/src/livekit/livekit.service.ts +110 -0
- package/packages/sdk/src/livekit/media.controls.ts +315 -0
- package/packages/sdk/src/livekit/room.manager.ts +79 -0
- package/packages/sdk/src/livekit/track.utils.ts +230 -0
- package/packages/sdk/src/livekit/types.ts +135 -0
- package/packages/sdk/src/provider/RtcProvider.tsx +78 -0
- package/packages/sdk/src/services/call-actions.ts +260 -0
- package/packages/sdk/src/services/error-recovery.ts +461 -0
- package/packages/sdk/src/services/index.ts +2 -0
- package/packages/sdk/src/services/sdk-builder.ts +104 -0
- package/packages/sdk/src/state/errors.ts +163 -0
- package/packages/sdk/src/state/selectors.ts +28 -0
- package/packages/sdk/src/state/store.ts +36 -0
- package/packages/sdk/src/state/types.ts +151 -0
- package/packages/sdk/src/utils/logger.ts +183 -0
- package/packages/sdk/tsconfig.json +49 -0
- package/packages/sdk/tsup.config.ts +51 -0
- package/pnpm-workspace.yaml +4 -0
- package/tsconfig.base.json +19 -0
- package/turbo.json +34 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vg-x07df",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Headless SDK for dubadav audio/video",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./livekit": {
|
|
16
|
+
"types": "./dist/livekit/index.d.ts",
|
|
17
|
+
"import": "./dist/livekit/index.mjs",
|
|
18
|
+
"require": "./dist/livekit/index.cjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/**/*",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"CHANGELOG.md"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"generate:api": "openapi-ts",
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"dev": "tsup --watch",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"lint": "echo \"Lint not configured - add ESLint setup\"",
|
|
37
|
+
"clean": "rimraf dist",
|
|
38
|
+
"prepublishOnly": "npm run clean && npm run build && npm run typecheck"
|
|
39
|
+
},
|
|
40
|
+
"author": "Voyatek Group",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/VoyatekGroup/go-callpad.git",
|
|
44
|
+
"directory": "web-sdk/packages/sdk"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"react": ">=18",
|
|
48
|
+
"react-dom": ">=18",
|
|
49
|
+
"livekit-client": "^2.8.0",
|
|
50
|
+
"socket.io-client": "^4.7.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependenciesMeta": {
|
|
53
|
+
"react": {
|
|
54
|
+
"optional": false
|
|
55
|
+
},
|
|
56
|
+
"react-dom": {
|
|
57
|
+
"optional": false
|
|
58
|
+
},
|
|
59
|
+
"livekit-client": {
|
|
60
|
+
"optional": false
|
|
61
|
+
},
|
|
62
|
+
"socket.io-client": {
|
|
63
|
+
"optional": false
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"axios": "^1.6.0",
|
|
68
|
+
"jwt-decode": "^4.0.0",
|
|
69
|
+
"zustand": "^4.5.0",
|
|
70
|
+
"immer": "^10.0.0",
|
|
71
|
+
"zod": "^3.22.0"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@hey-api/openapi-ts": "^0.37.0",
|
|
75
|
+
"tsup": "^8.0.0",
|
|
76
|
+
"typescript": "^5.2.0",
|
|
77
|
+
"@types/react": "^18.2.0",
|
|
78
|
+
"@types/react-dom": "^18.2.0",
|
|
79
|
+
"react": "^18.3.1",
|
|
80
|
+
"react-dom": "^18.3.1",
|
|
81
|
+
"livekit-client": "^2.8.0",
|
|
82
|
+
"socket.io-client": "^4.7.0",
|
|
83
|
+
"rimraf": "^6.0.0"
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=18"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { AuthProvider, Nullable, JWTPayload } from "./types";
|
|
2
|
+
|
|
3
|
+
export class AuthManager {
|
|
4
|
+
private readonly authProvider: AuthProvider;
|
|
5
|
+
private lastToken: Nullable<string> = null;
|
|
6
|
+
|
|
7
|
+
constructor(authProvider: AuthProvider) {
|
|
8
|
+
this.authProvider = authProvider;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getCurrentToken(): string | null {
|
|
12
|
+
const token = this.authProvider();
|
|
13
|
+
if (token !== this.lastToken) {
|
|
14
|
+
this.lastToken = token;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return token;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Extract user ID from JWT token
|
|
22
|
+
*/
|
|
23
|
+
getCurrentUserId(): string | null {
|
|
24
|
+
const token = this.getCurrentToken();
|
|
25
|
+
if (!token) return null;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const payload = this.decodeJWT(token);
|
|
29
|
+
return payload?.sub || payload?.userId || payload?.id || null;
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Decode JWT token without verification
|
|
37
|
+
*/
|
|
38
|
+
private decodeJWT(token: string): JWTPayload | null {
|
|
39
|
+
const parts = token.split('.');
|
|
40
|
+
if (parts.length !== 3) return null;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const payload = parts[1]?.replace(/-/g, '+').replace(/_/g, '/');
|
|
44
|
+
if (!payload) return null;
|
|
45
|
+
|
|
46
|
+
const decodedPayload = JSON.parse(atob(payload));
|
|
47
|
+
return decodedPayload as JWTPayload;
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK Event Bus Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides a centralized event system for internal SDK communication.
|
|
5
|
+
* Supports type-safe event subscription, filtering, and debugging.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createLogger } from "../../utils/logger";
|
|
9
|
+
import type {
|
|
10
|
+
EventFilter,
|
|
11
|
+
EventHandler,
|
|
12
|
+
EventSubscription,
|
|
13
|
+
SdkEvent,
|
|
14
|
+
SdkEventType,
|
|
15
|
+
} from "./types";
|
|
16
|
+
|
|
17
|
+
const logger = createLogger("core:event-bus");
|
|
18
|
+
|
|
19
|
+
export class EventBus {
|
|
20
|
+
private listeners = new Map<string, Set<EventHandler>>();
|
|
21
|
+
private isDebugMode = false;
|
|
22
|
+
private eventHistory: SdkEvent[] = [];
|
|
23
|
+
private maxHistorySize = 100;
|
|
24
|
+
|
|
25
|
+
constructor(debugMode = false) {
|
|
26
|
+
this.isDebugMode = debugMode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Subscribe to events of a specific type
|
|
31
|
+
*/
|
|
32
|
+
on<T = any>(
|
|
33
|
+
eventType: string | SdkEventType,
|
|
34
|
+
handler: EventHandler<T>,
|
|
35
|
+
filter?: EventFilter<T>
|
|
36
|
+
): EventSubscription {
|
|
37
|
+
const actualHandler = filter
|
|
38
|
+
? (event: SdkEvent<T>) => {
|
|
39
|
+
if (filter(event)) {
|
|
40
|
+
handler(event);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
: handler;
|
|
44
|
+
|
|
45
|
+
if (!this.listeners.has(eventType)) {
|
|
46
|
+
this.listeners.set(eventType, new Set());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.listeners.get(eventType)?.add(actualHandler);
|
|
50
|
+
|
|
51
|
+
if (this.isDebugMode) {
|
|
52
|
+
logger.debug(`Event listener added for: ${eventType}`, {
|
|
53
|
+
eventType,
|
|
54
|
+
totalListeners: this.listeners.get(eventType)?.size,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
unsubscribe: () => {
|
|
60
|
+
const handlers = this.listeners.get(eventType);
|
|
61
|
+
if (handlers) {
|
|
62
|
+
handlers.delete(actualHandler);
|
|
63
|
+
if (handlers.size === 0) {
|
|
64
|
+
this.listeners.delete(eventType);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this.isDebugMode) {
|
|
69
|
+
logger.debug(`Event listener removed for: ${eventType}`, {
|
|
70
|
+
eventType,
|
|
71
|
+
remainingListeners: handlers?.size || 0,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Subscribe to events matching a pattern (e.g., "call:*")
|
|
80
|
+
*/
|
|
81
|
+
onPattern<T = any>(
|
|
82
|
+
pattern: string,
|
|
83
|
+
handler: EventHandler<T>,
|
|
84
|
+
filter?: EventFilter<T>
|
|
85
|
+
): EventSubscription {
|
|
86
|
+
const regex = new RegExp(pattern.replace(/\*/g, ".*"));
|
|
87
|
+
const patternHandler: EventHandler<T> = (event: SdkEvent<T>) => {
|
|
88
|
+
if (regex.test(event.type)) {
|
|
89
|
+
if (filter && !filter(event)) return;
|
|
90
|
+
handler(event);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Store pattern handlers separately to avoid conflicts
|
|
95
|
+
const patternKey = `__pattern__${pattern}`;
|
|
96
|
+
if (!this.listeners.has(patternKey)) {
|
|
97
|
+
this.listeners.set(patternKey, new Set());
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this.listeners.get(patternKey)?.add(patternHandler);
|
|
101
|
+
|
|
102
|
+
if (this.isDebugMode) {
|
|
103
|
+
logger.debug(`Pattern listener added: ${pattern}`, { pattern });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
unsubscribe: () => {
|
|
108
|
+
const handlers = this.listeners.get(patternKey);
|
|
109
|
+
if (handlers) {
|
|
110
|
+
handlers.delete(patternHandler);
|
|
111
|
+
if (handlers.size === 0) {
|
|
112
|
+
this.listeners.delete(patternKey);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (this.isDebugMode) {
|
|
117
|
+
logger.debug(`Pattern listener removed: ${pattern}`, { pattern });
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Subscribe to a single event occurrence
|
|
125
|
+
*/
|
|
126
|
+
once<T = any>(
|
|
127
|
+
eventType: string | SdkEventType,
|
|
128
|
+
handler: EventHandler<T>,
|
|
129
|
+
filter?: EventFilter<T>
|
|
130
|
+
): EventSubscription {
|
|
131
|
+
const subscription = this.on(
|
|
132
|
+
eventType,
|
|
133
|
+
(event: SdkEvent<T>) => {
|
|
134
|
+
handler(event);
|
|
135
|
+
subscription.unsubscribe();
|
|
136
|
+
},
|
|
137
|
+
filter
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return subscription;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Emit an event
|
|
145
|
+
*/
|
|
146
|
+
emit<T = any>(
|
|
147
|
+
eventType: string | SdkEventType,
|
|
148
|
+
payload: T,
|
|
149
|
+
source: "socket" | "livekit" | "user" = "user"
|
|
150
|
+
): void {
|
|
151
|
+
const event: SdkEvent<T> = {
|
|
152
|
+
type: eventType.toString(),
|
|
153
|
+
payload,
|
|
154
|
+
timestamp: Date.now(),
|
|
155
|
+
source,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Add to history for debugging
|
|
159
|
+
this.addToHistory(event);
|
|
160
|
+
|
|
161
|
+
if (this.isDebugMode) {
|
|
162
|
+
logger.debug(`Event emitted: ${eventType}`, {
|
|
163
|
+
eventType,
|
|
164
|
+
payload,
|
|
165
|
+
source,
|
|
166
|
+
timestamp: event.timestamp,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Emit to exact type listeners
|
|
171
|
+
const exactListeners = this.listeners.get(eventType.toString());
|
|
172
|
+
if (exactListeners) {
|
|
173
|
+
for (const handler of exactListeners) {
|
|
174
|
+
try {
|
|
175
|
+
handler(event);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
logger.error(`Error in event handler for ${eventType}`, {
|
|
178
|
+
error,
|
|
179
|
+
eventType,
|
|
180
|
+
payload,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Emit to pattern listeners
|
|
187
|
+
this.listeners.forEach((handlers, key) => {
|
|
188
|
+
if (key.startsWith("__pattern__")) {
|
|
189
|
+
for (const handler of handlers) {
|
|
190
|
+
try {
|
|
191
|
+
handler(event);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
logger.error(`Error in pattern handler for ${eventType}`, {
|
|
194
|
+
error,
|
|
195
|
+
eventType,
|
|
196
|
+
pattern: key,
|
|
197
|
+
payload,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Remove all listeners for a specific event type
|
|
207
|
+
*/
|
|
208
|
+
off(eventType: string | SdkEventType): void {
|
|
209
|
+
this.listeners.delete(eventType.toString());
|
|
210
|
+
|
|
211
|
+
if (this.isDebugMode) {
|
|
212
|
+
logger.debug(`All listeners removed for: ${eventType}`, { eventType });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Remove all listeners
|
|
218
|
+
*/
|
|
219
|
+
removeAllListeners(): void {
|
|
220
|
+
const totalListeners = Array.from(this.listeners.values()).reduce(
|
|
221
|
+
(sum, handlers) => sum + handlers.size,
|
|
222
|
+
0
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
this.listeners.clear();
|
|
226
|
+
|
|
227
|
+
if (this.isDebugMode) {
|
|
228
|
+
logger.debug("All listeners removed", { removedCount: totalListeners });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get the count of listeners for an event type
|
|
234
|
+
*/
|
|
235
|
+
listenerCount(eventType: string | SdkEventType): number {
|
|
236
|
+
return this.listeners.get(eventType.toString())?.size || 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get all event types that have listeners
|
|
241
|
+
*/
|
|
242
|
+
getEventTypes(): string[] {
|
|
243
|
+
return Array.from(this.listeners.keys());
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Enable or disable debug mode
|
|
248
|
+
*/
|
|
249
|
+
setDebugMode(enabled: boolean): void {
|
|
250
|
+
this.isDebugMode = enabled;
|
|
251
|
+
logger.debug(`Debug mode ${enabled ? "enabled" : "disabled"}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get event history for debugging
|
|
256
|
+
*/
|
|
257
|
+
getEventHistory(): SdkEvent[] {
|
|
258
|
+
return [...this.eventHistory];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Clear event history
|
|
263
|
+
*/
|
|
264
|
+
clearHistory(): void {
|
|
265
|
+
this.eventHistory = [];
|
|
266
|
+
if (this.isDebugMode) {
|
|
267
|
+
logger.debug("Event history cleared");
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get events matching a filter
|
|
273
|
+
*/
|
|
274
|
+
getEventsWhere(filter: EventFilter): SdkEvent[] {
|
|
275
|
+
return this.eventHistory.filter(filter);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private addToHistory(event: SdkEvent): void {
|
|
279
|
+
this.eventHistory.push(event);
|
|
280
|
+
|
|
281
|
+
// Keep history size manageable
|
|
282
|
+
if (this.eventHistory.length > this.maxHistorySize) {
|
|
283
|
+
this.eventHistory.shift();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Set maximum history size
|
|
289
|
+
*/
|
|
290
|
+
setMaxHistorySize(size: number): void {
|
|
291
|
+
this.maxHistorySize = size;
|
|
292
|
+
|
|
293
|
+
// Trim existing history if needed
|
|
294
|
+
if (this.eventHistory.length > size) {
|
|
295
|
+
this.eventHistory = this.eventHistory.slice(-size);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Global event bus instance
|
|
301
|
+
export const eventBus = new EventBus(false);
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK Event System Types
|
|
3
|
+
*
|
|
4
|
+
* This file defines the event types and interfaces for the internal SDK event system.
|
|
5
|
+
* The event system provides extensibility and allows components to communicate
|
|
6
|
+
* through a unified, type-safe event bus.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface SdkEvent<T = any> {
|
|
10
|
+
type: string;
|
|
11
|
+
payload: T;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
source: "socket" | "livekit" | "user";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* SDK Event Types
|
|
18
|
+
* Following the pattern from other WebRTC SDKs like LiveKit
|
|
19
|
+
*/
|
|
20
|
+
export enum SdkEventType {
|
|
21
|
+
// Call lifecycle events
|
|
22
|
+
CALL_INITIATED = "call:initiated",
|
|
23
|
+
CALL_INCOMING = "call:incoming",
|
|
24
|
+
CALL_ACCEPTED = "call:accepted",
|
|
25
|
+
CALL_DECLINED = "call:declined",
|
|
26
|
+
CALL_ENDED = "call:ended",
|
|
27
|
+
CALL_CANCELED = "call:canceled",
|
|
28
|
+
CALL_TIMEOUT = "call:timeout",
|
|
29
|
+
JOIN_INFO_RECEIVED = "join-info:received",
|
|
30
|
+
|
|
31
|
+
// Participant events
|
|
32
|
+
PARTICIPANT_JOINING = "participant:joining",
|
|
33
|
+
PARTICIPANT_JOINED = "participant:joined",
|
|
34
|
+
PARTICIPANT_LEFT = "participant:left",
|
|
35
|
+
PARTICIPANT_UPDATED = "participant:updated",
|
|
36
|
+
|
|
37
|
+
// Media events
|
|
38
|
+
MEDIA_ENABLED = "media:enabled",
|
|
39
|
+
MEDIA_DISABLED = "media:disabled",
|
|
40
|
+
MEDIA_DEVICE_CHANGED = "media:device-changed",
|
|
41
|
+
MEDIA_PERMISSION_GRANTED = "media:permission-granted",
|
|
42
|
+
MEDIA_PERMISSION_DENIED = "media:permission-denied",
|
|
43
|
+
|
|
44
|
+
// Connection events
|
|
45
|
+
CONNECTION_ESTABLISHED = "connection:established",
|
|
46
|
+
CONNECTION_LOST = "connection:lost",
|
|
47
|
+
CONNECTION_RECONNECTING = "connection:reconnecting",
|
|
48
|
+
CONNECTION_QUALITY_CHANGED = "connection:quality-changed",
|
|
49
|
+
|
|
50
|
+
// Error events
|
|
51
|
+
ERROR_OCCURRED = "error:occurred",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Specific event payload types
|
|
56
|
+
*/
|
|
57
|
+
export interface CallInitiatedEvent {
|
|
58
|
+
callId: string;
|
|
59
|
+
participants: string[];
|
|
60
|
+
type: "AUDIO" | "VIDEO";
|
|
61
|
+
timestamp: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface CallIncomingEvent {
|
|
65
|
+
callId: string;
|
|
66
|
+
caller: {
|
|
67
|
+
id: string;
|
|
68
|
+
firstName?: string;
|
|
69
|
+
lastName?: string;
|
|
70
|
+
avatarUrl?: string;
|
|
71
|
+
};
|
|
72
|
+
type: "AUDIO" | "VIDEO";
|
|
73
|
+
timestamp: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface CallAcceptedEvent {
|
|
77
|
+
callId: string;
|
|
78
|
+
participantId: string;
|
|
79
|
+
timestamp: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface CallDeclinedEvent {
|
|
83
|
+
callId: string;
|
|
84
|
+
participantId: string;
|
|
85
|
+
reason?: string;
|
|
86
|
+
timestamp: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface CallEndedEvent {
|
|
90
|
+
callId: string;
|
|
91
|
+
endedBy?: string;
|
|
92
|
+
reason?: "user" | "timeout" | "error";
|
|
93
|
+
timestamp: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface JoinInfoReceivedEvent {
|
|
97
|
+
callId: string;
|
|
98
|
+
participantId: string;
|
|
99
|
+
timestamp: number;
|
|
100
|
+
hasUrl: boolean;
|
|
101
|
+
hasToken: boolean;
|
|
102
|
+
autoJoined?: boolean;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ParticipantJoinedEvent {
|
|
106
|
+
callId: string;
|
|
107
|
+
participant: {
|
|
108
|
+
id: string;
|
|
109
|
+
firstName?: string;
|
|
110
|
+
lastName?: string;
|
|
111
|
+
avatarUrl?: string;
|
|
112
|
+
role: "CALLER" | "CALLEE" | "HOST" | "MEMBER";
|
|
113
|
+
};
|
|
114
|
+
timestamp: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ParticipantLeftEvent {
|
|
118
|
+
callId: string;
|
|
119
|
+
participantId: string;
|
|
120
|
+
reason?: "user" | "timeout" | "error";
|
|
121
|
+
timestamp: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface MediaEnabledEvent {
|
|
125
|
+
participantId: string;
|
|
126
|
+
mediaType: "audio" | "video" | "screen";
|
|
127
|
+
timestamp: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface MediaDisabledEvent {
|
|
131
|
+
participantId: string;
|
|
132
|
+
mediaType: "audio" | "video" | "screen";
|
|
133
|
+
timestamp: number;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface ConnectionQualityChangedEvent {
|
|
137
|
+
participantId: string;
|
|
138
|
+
quality: "excellent" | "good" | "poor" | "lost";
|
|
139
|
+
timestamp: number;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface ErrorOccurredEvent {
|
|
143
|
+
code: string;
|
|
144
|
+
message: string;
|
|
145
|
+
details?: any;
|
|
146
|
+
source: "socket" | "livekit" | "user";
|
|
147
|
+
timestamp: number;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Event handler type
|
|
152
|
+
*/
|
|
153
|
+
export type EventHandler<T = any> = (event: SdkEvent<T>) => void;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Event subscription interface
|
|
157
|
+
*/
|
|
158
|
+
export interface EventSubscription {
|
|
159
|
+
unsubscribe: () => void;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Event filter function type
|
|
164
|
+
*/
|
|
165
|
+
export type EventFilter<T = any> = (event: SdkEvent<T>) => boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { OpenAPI } from "../../generated/api";
|
|
2
|
+
import type { ApiConfig } from "./types";
|
|
3
|
+
|
|
4
|
+
export class OpenApiConfigService {
|
|
5
|
+
private static instance: OpenApiConfigService;
|
|
6
|
+
|
|
7
|
+
private constructor() {}
|
|
8
|
+
|
|
9
|
+
static getInstance(): OpenApiConfigService {
|
|
10
|
+
if (!OpenApiConfigService.instance) {
|
|
11
|
+
OpenApiConfigService.instance = new OpenApiConfigService();
|
|
12
|
+
}
|
|
13
|
+
return OpenApiConfigService.instance;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
configure(config: ApiConfig): void {
|
|
17
|
+
OpenAPI.BASE = config.baseUrl;
|
|
18
|
+
|
|
19
|
+
// Handle token - OpenAPI expects string | Resolver<string>
|
|
20
|
+
// Resolver<string> = (options: ApiRequestOptions) => Promise<string>
|
|
21
|
+
if (typeof config.token === "function") {
|
|
22
|
+
const tokenFn = config.token; // Capture the function reference
|
|
23
|
+
OpenAPI.TOKEN = async (_options) => {
|
|
24
|
+
const result = tokenFn();
|
|
25
|
+
return typeof result === "string" ? result : await result;
|
|
26
|
+
};
|
|
27
|
+
} else {
|
|
28
|
+
OpenAPI.TOKEN = config.token;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
OpenAPI.CREDENTIALS = config.credentials ?? "include";
|
|
32
|
+
OpenAPI.WITH_CREDENTIALS = config.withCredentials ?? false;
|
|
33
|
+
|
|
34
|
+
if (config.headers) {
|
|
35
|
+
OpenAPI.HEADERS = config.headers;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setToken(token: string): void {
|
|
40
|
+
OpenAPI.TOKEN = token;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const apiConfig = OpenApiConfigService.getInstance();
|
|
45
|
+
|
|
46
|
+
export { OpenAPI };
|
|
47
|
+
|
|
48
|
+
// Re-export ApiConfig type
|
|
49
|
+
export type { ApiConfig } from "./types";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { SignalClient } from "./signal.client";
|
|
2
|
+
export { apiConfig } from "./api.config";
|
|
3
|
+
export type {
|
|
4
|
+
SignalClientConfig,
|
|
5
|
+
CallInfo,
|
|
6
|
+
CallParticipant,
|
|
7
|
+
LiveKitJoinInfo,
|
|
8
|
+
IncomingCallEvent,
|
|
9
|
+
CallState,
|
|
10
|
+
CallMode,
|
|
11
|
+
EndReason,
|
|
12
|
+
ApiConfig,
|
|
13
|
+
} from "./types";
|
|
14
|
+
export * from "./types";
|
|
15
|
+
// Re-export the generated API response type for convenience
|
|
16
|
+
export type { CallsData } from "../../generated/api/models";
|