@ustriveneo/partner-realtime 1.0.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/README.md +256 -0
- package/dist/calls.d.ts +35 -0
- package/dist/calls.js +92 -0
- package/dist/calls.js.map +1 -0
- package/dist/chat.d.ts +33 -0
- package/dist/chat.js +118 -0
- package/dist/chat.js.map +1 -0
- package/dist/client.d.ts +47 -0
- package/dist/client.js +163 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# @ustriveneo/partner-realtime
|
|
2
|
+
|
|
3
|
+
Client-side realtime SDK for UStrive Partner integrations. Provides real-time chat, video calls, and audio calls between matched mentor-student pairs.
|
|
4
|
+
|
|
5
|
+
This package wraps Stream Chat and Stream Video so partners never need to import or configure Stream SDKs directly.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Web
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @ustriveneo/partner-realtime @ustriveneo/partner-sdk stream-chat @stream-io/video-client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### React Native
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @ustriveneo/partner-realtime @ustriveneo/partner-sdk stream-chat @stream-io/video-react-native-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Note: `@stream-io/video-client` is an optional peer dependency. React Native apps use `@stream-io/video-react-native-sdk` instead (which includes native camera/microphone bindings). See [React Native Usage](#react-native-usage) below.
|
|
22
|
+
|
|
23
|
+
## Quick Start (Web)
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { UStrivePartnerClient } from '@ustriveneo/partner-sdk';
|
|
27
|
+
import { UStriveRealtimeClient } from '@ustriveneo/partner-realtime';
|
|
28
|
+
|
|
29
|
+
// 1. Initialize the server SDK (used for token generation)
|
|
30
|
+
const partnerClient = new UStrivePartnerClient({
|
|
31
|
+
apiKey: 'pk_live_xxx',
|
|
32
|
+
secret: 'sk_live_yyy',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// 2. Create the realtime client for a specific user
|
|
36
|
+
const realtime = new UStriveRealtimeClient({
|
|
37
|
+
partnerClient,
|
|
38
|
+
userId: 'user-id',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 3. Connect (fetches token and auto-creates Stream clients)
|
|
42
|
+
await realtime.connect();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## React Native Usage
|
|
46
|
+
|
|
47
|
+
React Native requires platform-specific Stream SDKs for camera/microphone access. Instead of letting `partner-realtime` auto-create clients, pass your own pre-initialized clients:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { StreamChat } from 'stream-chat';
|
|
51
|
+
import { StreamVideoClient } from '@stream-io/video-react-native-sdk';
|
|
52
|
+
import { UStrivePartnerClient } from '@ustriveneo/partner-sdk';
|
|
53
|
+
import { UStriveRealtimeClient } from '@ustriveneo/partner-realtime';
|
|
54
|
+
|
|
55
|
+
const partnerClient = new UStrivePartnerClient({
|
|
56
|
+
apiKey: 'pk_live_xxx',
|
|
57
|
+
secret: 'sk_live_yyy',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Get a token first to initialize the native clients
|
|
61
|
+
const { token, apiKey } = await partnerClient.messaging.getStreamToken('user-id');
|
|
62
|
+
|
|
63
|
+
// Initialize native-aware clients
|
|
64
|
+
const chatClient = StreamChat.getInstance(apiKey);
|
|
65
|
+
await chatClient.connectUser({ id: 'user-id' }, token);
|
|
66
|
+
|
|
67
|
+
const videoClient = new StreamVideoClient({
|
|
68
|
+
apiKey,
|
|
69
|
+
token,
|
|
70
|
+
user: { id: 'user-id' },
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Pass them to partner-realtime
|
|
74
|
+
const realtime = new UStriveRealtimeClient({
|
|
75
|
+
partnerClient,
|
|
76
|
+
userId: 'user-id',
|
|
77
|
+
chatClient, // Pre-initialized — won't be auto-created
|
|
78
|
+
videoClient, // Pre-initialized — native camera/mic bindings active
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await realtime.connect();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
When injected clients are provided:
|
|
85
|
+
- `connect()` still fetches the API key but skips client creation
|
|
86
|
+
- `disconnect()` cleans up channel watchers and call state but does NOT disconnect injected clients (the host app manages their lifecycle)
|
|
87
|
+
|
|
88
|
+
## Chat
|
|
89
|
+
|
|
90
|
+
Use the `chat` manager to send and receive messages in a match's channel. The `channelId` is the `streamChatId` returned when creating or fetching a match via the Partner SDK.
|
|
91
|
+
|
|
92
|
+
### Open a Channel
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const match = await partnerClient.matches.get('match-id');
|
|
96
|
+
const channel = await realtime.chat.openChat(match.streamChatId);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Send a Message
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
await channel.sendMessage('Hello!');
|
|
103
|
+
|
|
104
|
+
// Or directly via the manager:
|
|
105
|
+
await realtime.chat.sendMessage(match.streamChatId, 'Hello!');
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Get Message History
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const messages = await channel.getMessages({ limit: 50 });
|
|
112
|
+
|
|
113
|
+
// Or directly via the manager:
|
|
114
|
+
const messages = await realtime.chat.getMessages(match.streamChatId, { limit: 50 });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Listen for New Messages
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const unsubscribe = channel.onMessage((msg) => {
|
|
121
|
+
console.log(`${msg.userId}: ${msg.text}`);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Or via the manager:
|
|
125
|
+
const unsubscribe = realtime.chat.onMessage(match.streamChatId, (msg) => {
|
|
126
|
+
console.log(`${msg.userId}: ${msg.text}`);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Clean up when done
|
|
130
|
+
unsubscribe();
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Video & Audio Calls
|
|
134
|
+
|
|
135
|
+
Use the `calls` manager to join and manage calls. Calls use the match ID as the call identifier.
|
|
136
|
+
|
|
137
|
+
Note: `calls` returns `null` if no video client is available (neither injected nor auto-created). Check for availability before using:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
if (realtime.calls) {
|
|
141
|
+
const activeCall = await realtime.calls.joinCall('match-id');
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Join a Call
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const activeCall = await realtime.calls.joinCall('match-id', {
|
|
149
|
+
video: true, // Enable camera (default: true)
|
|
150
|
+
audio: true, // Enable microphone (default: true)
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Control Devices
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
await activeCall.setCamera(false); // Turn off camera (audio-only)
|
|
158
|
+
await activeCall.setMicrophone(false); // Mute
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Listen for Call Events
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const unsubscribe = activeCall.on('call.session_participant_joined', (event) => {
|
|
165
|
+
console.log('Participant joined');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
unsubscribe();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Leave a Call
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
await realtime.calls.leaveCall('match-id');
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Check Active Call
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
const call = realtime.calls?.getActiveCall('match-id');
|
|
181
|
+
if (call) {
|
|
182
|
+
// Currently in a call
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Disconnect
|
|
187
|
+
|
|
188
|
+
Always disconnect when done to clean up resources:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
await realtime.disconnect();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Full Example
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { UStrivePartnerClient } from '@ustriveneo/partner-sdk';
|
|
198
|
+
import { UStriveRealtimeClient } from '@ustriveneo/partner-realtime';
|
|
199
|
+
|
|
200
|
+
async function main() {
|
|
201
|
+
const partnerClient = new UStrivePartnerClient({
|
|
202
|
+
apiKey: process.env.USTRIVE_API_KEY,
|
|
203
|
+
secret: process.env.USTRIVE_SECRET,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Get an active match
|
|
207
|
+
const { matches } = await partnerClient.matches.listByUser('student-id', {
|
|
208
|
+
status: 'ACTIVE',
|
|
209
|
+
});
|
|
210
|
+
const match = matches[0];
|
|
211
|
+
|
|
212
|
+
// Connect realtime for the student
|
|
213
|
+
const realtime = new UStriveRealtimeClient({
|
|
214
|
+
partnerClient,
|
|
215
|
+
userId: 'student-id',
|
|
216
|
+
});
|
|
217
|
+
await realtime.connect();
|
|
218
|
+
|
|
219
|
+
// Open chat and send a message
|
|
220
|
+
const channel = await realtime.chat.openChat(match.streamChatId);
|
|
221
|
+
await channel.sendMessage('Hi! Ready for our session?');
|
|
222
|
+
|
|
223
|
+
// Listen for replies
|
|
224
|
+
channel.onMessage((msg) => {
|
|
225
|
+
console.log(`New message from ${msg.userId}: ${msg.text}`);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Start a video call
|
|
229
|
+
if (realtime.calls) {
|
|
230
|
+
const call = await realtime.calls.joinCall(match.id, { video: true });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Clean up
|
|
234
|
+
await realtime.disconnect();
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Architecture
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
Partner App (Client)
|
|
242
|
+
|
|
|
243
|
+
v
|
|
244
|
+
@ustriveneo/partner-realtime <-- This package (wraps Stream)
|
|
245
|
+
|
|
|
246
|
+
v
|
|
247
|
+
@ustriveneo/partner-sdk <-- Gets Stream tokens via REST
|
|
248
|
+
|
|
|
249
|
+
v
|
|
250
|
+
UStrive Partner API <-- Generates tokens, manages channels
|
|
251
|
+
|
|
|
252
|
+
v
|
|
253
|
+
Stream (Chat + Video) <-- Third-party realtime infrastructure
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Partners interact only with `@ustriveneo/partner-sdk` (server-side) and `@ustriveneo/partner-realtime` (client-side). Stream is fully abstracted.
|
package/dist/calls.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ActiveCall, JoinCallOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps Stream Video call operations.
|
|
4
|
+
*
|
|
5
|
+
* Accepts any video client that implements the Stream Video `call()` interface.
|
|
6
|
+
* This allows the same code to work with:
|
|
7
|
+
* - @stream-io/video-client (web)
|
|
8
|
+
* - @stream-io/video-react-native-sdk (React Native)
|
|
9
|
+
*
|
|
10
|
+
* Both SDKs expose the same Call interface for .getOrCreate(), .join(),
|
|
11
|
+
* .leave(), .camera, .microphone, and .on().
|
|
12
|
+
*/
|
|
13
|
+
export declare class CallManager {
|
|
14
|
+
private videoClient;
|
|
15
|
+
private activeCalls;
|
|
16
|
+
constructor(videoClient: any);
|
|
17
|
+
/**
|
|
18
|
+
* Join (or create) a call for a match.
|
|
19
|
+
* Uses matchId as the call ID, same pattern as the main UStrive app.
|
|
20
|
+
*/
|
|
21
|
+
joinCall(matchId: string, opts?: JoinCallOptions): Promise<ActiveCall>;
|
|
22
|
+
/**
|
|
23
|
+
* Leave an active call.
|
|
24
|
+
*/
|
|
25
|
+
leaveCall(matchId: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Get the active call for a match, or null if not in a call.
|
|
28
|
+
*/
|
|
29
|
+
getActiveCall(matchId: string): ActiveCall | null;
|
|
30
|
+
/**
|
|
31
|
+
* Leave all active calls and clean up resources.
|
|
32
|
+
*/
|
|
33
|
+
cleanup(): Promise<void>;
|
|
34
|
+
private wrapCall;
|
|
35
|
+
}
|
package/dist/calls.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CallManager = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Wraps Stream Video call operations.
|
|
6
|
+
*
|
|
7
|
+
* Accepts any video client that implements the Stream Video `call()` interface.
|
|
8
|
+
* This allows the same code to work with:
|
|
9
|
+
* - @stream-io/video-client (web)
|
|
10
|
+
* - @stream-io/video-react-native-sdk (React Native)
|
|
11
|
+
*
|
|
12
|
+
* Both SDKs expose the same Call interface for .getOrCreate(), .join(),
|
|
13
|
+
* .leave(), .camera, .microphone, and .on().
|
|
14
|
+
*/
|
|
15
|
+
class CallManager {
|
|
16
|
+
constructor(videoClient) {
|
|
17
|
+
this.activeCalls = new Map();
|
|
18
|
+
this.videoClient = videoClient;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Join (or create) a call for a match.
|
|
22
|
+
* Uses matchId as the call ID, same pattern as the main UStrive app.
|
|
23
|
+
*/
|
|
24
|
+
async joinCall(matchId, opts) {
|
|
25
|
+
const call = this.videoClient.call('default', matchId);
|
|
26
|
+
await call.getOrCreate();
|
|
27
|
+
await call.join({ create: false });
|
|
28
|
+
// Apply initial device settings
|
|
29
|
+
if (opts?.video === false) {
|
|
30
|
+
await call.camera.disable();
|
|
31
|
+
}
|
|
32
|
+
if (opts?.audio === false) {
|
|
33
|
+
await call.microphone.disable();
|
|
34
|
+
}
|
|
35
|
+
this.activeCalls.set(matchId, call);
|
|
36
|
+
return this.wrapCall(matchId, call);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Leave an active call.
|
|
40
|
+
*/
|
|
41
|
+
async leaveCall(matchId) {
|
|
42
|
+
const call = this.activeCalls.get(matchId);
|
|
43
|
+
if (call) {
|
|
44
|
+
await call.leave();
|
|
45
|
+
this.activeCalls.delete(matchId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the active call for a match, or null if not in a call.
|
|
50
|
+
*/
|
|
51
|
+
getActiveCall(matchId) {
|
|
52
|
+
const call = this.activeCalls.get(matchId);
|
|
53
|
+
if (!call)
|
|
54
|
+
return null;
|
|
55
|
+
return this.wrapCall(matchId, call);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Leave all active calls and clean up resources.
|
|
59
|
+
*/
|
|
60
|
+
async cleanup() {
|
|
61
|
+
for (const [matchId] of this.activeCalls) {
|
|
62
|
+
await this.leaveCall(matchId).catch(() => { });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
wrapCall(matchId, call) {
|
|
66
|
+
return {
|
|
67
|
+
callId: matchId,
|
|
68
|
+
async setCamera(enabled) {
|
|
69
|
+
if (enabled) {
|
|
70
|
+
await call.camera.enable();
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
await call.camera.disable();
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
async setMicrophone(enabled) {
|
|
77
|
+
if (enabled) {
|
|
78
|
+
await call.microphone.enable();
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
await call.microphone.disable();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
on(event, callback) {
|
|
85
|
+
const unsubscribe = call.on(event, callback);
|
|
86
|
+
return typeof unsubscribe === 'function' ? unsubscribe : () => { };
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.CallManager = CallManager;
|
|
92
|
+
//# sourceMappingURL=calls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calls.js","sourceRoot":"","sources":["../src/calls.ts"],"names":[],"mappings":"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"}
|
package/dist/chat.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { StreamChat } from 'stream-chat';
|
|
2
|
+
import type { ChatMessage, ChatChannel } from './types';
|
|
3
|
+
export declare class ChatManager {
|
|
4
|
+
private chatClient;
|
|
5
|
+
private userId;
|
|
6
|
+
private channels;
|
|
7
|
+
constructor(chatClient: StreamChat, userId: string);
|
|
8
|
+
private getChannel;
|
|
9
|
+
/**
|
|
10
|
+
* Opens a chat channel and starts watching for updates.
|
|
11
|
+
* Use `match.streamChatId` as the channelId.
|
|
12
|
+
*/
|
|
13
|
+
openChat(channelId: string): Promise<ChatChannel>;
|
|
14
|
+
/**
|
|
15
|
+
* Subscribe to new messages on a channel without fully opening it.
|
|
16
|
+
* Returns an unsubscribe function.
|
|
17
|
+
*/
|
|
18
|
+
onMessage(channelId: string, callback: (msg: ChatMessage) => void): () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Send a message to a channel.
|
|
21
|
+
*/
|
|
22
|
+
sendMessage(channelId: string, text: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Get message history for a channel.
|
|
25
|
+
*/
|
|
26
|
+
getMessages(channelId: string, opts?: {
|
|
27
|
+
limit?: number;
|
|
28
|
+
}): Promise<ChatMessage[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Stop watching all channels and clean up resources.
|
|
31
|
+
*/
|
|
32
|
+
cleanup(): Promise<void>;
|
|
33
|
+
}
|
package/dist/chat.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChatManager = void 0;
|
|
4
|
+
function toMessage(msg) {
|
|
5
|
+
return {
|
|
6
|
+
id: msg.id,
|
|
7
|
+
text: msg.text || '',
|
|
8
|
+
userId: msg.user?.id || '',
|
|
9
|
+
attachments: (msg.attachments || []).map((att) => ({
|
|
10
|
+
type: att.type || '',
|
|
11
|
+
url: att.asset_url || att.image_url || att.og_scrape_url || '',
|
|
12
|
+
name: att.title || att.fallback,
|
|
13
|
+
size: att.file_size,
|
|
14
|
+
})),
|
|
15
|
+
createdAt: msg.created_at || new Date().toISOString(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
class ChatManager {
|
|
19
|
+
constructor(chatClient, userId) {
|
|
20
|
+
this.channels = new Map();
|
|
21
|
+
this.chatClient = chatClient;
|
|
22
|
+
this.userId = userId;
|
|
23
|
+
}
|
|
24
|
+
async getChannel(channelId) {
|
|
25
|
+
const existing = this.channels.get(channelId);
|
|
26
|
+
if (existing)
|
|
27
|
+
return existing;
|
|
28
|
+
const channel = this.chatClient.channel('messaging', channelId);
|
|
29
|
+
await channel.watch();
|
|
30
|
+
this.channels.set(channelId, channel);
|
|
31
|
+
return channel;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Opens a chat channel and starts watching for updates.
|
|
35
|
+
* Use `match.streamChatId` as the channelId.
|
|
36
|
+
*/
|
|
37
|
+
async openChat(channelId) {
|
|
38
|
+
const channel = await this.getChannel(channelId);
|
|
39
|
+
const userId = this.userId;
|
|
40
|
+
return {
|
|
41
|
+
id: channelId,
|
|
42
|
+
async sendMessage(text) {
|
|
43
|
+
await channel.sendMessage({ text, user_id: userId });
|
|
44
|
+
},
|
|
45
|
+
async getMessages(opts) {
|
|
46
|
+
const response = await channel.query({
|
|
47
|
+
messages: { limit: opts?.limit || 50 },
|
|
48
|
+
});
|
|
49
|
+
return (response.messages || []).map(toMessage);
|
|
50
|
+
},
|
|
51
|
+
onMessage(callback) {
|
|
52
|
+
const handler = (event) => {
|
|
53
|
+
if (event.message) {
|
|
54
|
+
callback(toMessage(event.message));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
channel.on('message.new', handler);
|
|
58
|
+
return () => channel.off('message.new', handler);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Subscribe to new messages on a channel without fully opening it.
|
|
64
|
+
* Returns an unsubscribe function.
|
|
65
|
+
*/
|
|
66
|
+
onMessage(channelId, callback) {
|
|
67
|
+
let unsubscribe = null;
|
|
68
|
+
let cancelled = false;
|
|
69
|
+
this.getChannel(channelId).then((channel) => {
|
|
70
|
+
if (cancelled)
|
|
71
|
+
return;
|
|
72
|
+
const handler = (event) => {
|
|
73
|
+
if (event.message) {
|
|
74
|
+
callback(toMessage(event.message));
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
channel.on('message.new', handler);
|
|
78
|
+
unsubscribe = () => channel.off('message.new', handler);
|
|
79
|
+
}).catch((err) => {
|
|
80
|
+
if (!cancelled) {
|
|
81
|
+
console.error('Failed to subscribe to channel messages:', err?.message || err);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return () => {
|
|
85
|
+
cancelled = true;
|
|
86
|
+
if (unsubscribe)
|
|
87
|
+
unsubscribe();
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Send a message to a channel.
|
|
92
|
+
*/
|
|
93
|
+
async sendMessage(channelId, text) {
|
|
94
|
+
const channel = await this.getChannel(channelId);
|
|
95
|
+
await channel.sendMessage({ text, user_id: this.userId });
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get message history for a channel.
|
|
99
|
+
*/
|
|
100
|
+
async getMessages(channelId, opts) {
|
|
101
|
+
const channel = await this.getChannel(channelId);
|
|
102
|
+
const response = await channel.query({
|
|
103
|
+
messages: { limit: opts?.limit || 50 },
|
|
104
|
+
});
|
|
105
|
+
return (response.messages || []).map(toMessage);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Stop watching all channels and clean up resources.
|
|
109
|
+
*/
|
|
110
|
+
async cleanup() {
|
|
111
|
+
for (const channel of this.channels.values()) {
|
|
112
|
+
await channel.stopWatching().catch(() => { });
|
|
113
|
+
}
|
|
114
|
+
this.channels.clear();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.ChatManager = ChatManager;
|
|
118
|
+
//# sourceMappingURL=chat.js.map
|
package/dist/chat.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ChatManager } from './chat';
|
|
2
|
+
import { CallManager } from './calls';
|
|
3
|
+
import type { RealtimeClientConfig } from './types';
|
|
4
|
+
export declare class UStriveRealtimeClient {
|
|
5
|
+
private partnerClient;
|
|
6
|
+
private userId;
|
|
7
|
+
private chatClient;
|
|
8
|
+
private videoClient;
|
|
9
|
+
private _chat;
|
|
10
|
+
private _calls;
|
|
11
|
+
private connected;
|
|
12
|
+
/** Whether this instance created the clients (vs. receiving injected ones) */
|
|
13
|
+
private ownsChatClient;
|
|
14
|
+
private ownsVideoClient;
|
|
15
|
+
/** Injected clients from config (used in RN) */
|
|
16
|
+
private injectedChatClient;
|
|
17
|
+
private injectedVideoClient;
|
|
18
|
+
constructor(config: RealtimeClientConfig);
|
|
19
|
+
/**
|
|
20
|
+
* Connect to Stream Chat and Video services.
|
|
21
|
+
*
|
|
22
|
+
* Web: Fetches a token and auto-creates Stream clients.
|
|
23
|
+
* React Native: Uses the pre-initialized clients passed in the constructor.
|
|
24
|
+
* If injected clients are provided, token fetch is still performed for
|
|
25
|
+
* the API key but client creation is skipped.
|
|
26
|
+
*/
|
|
27
|
+
connect(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Disconnect from all Stream services and clean up resources.
|
|
30
|
+
* Only disconnects clients that this instance created (not injected ones).
|
|
31
|
+
*/
|
|
32
|
+
disconnect(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Access chat functionality. Must call connect() first.
|
|
35
|
+
*/
|
|
36
|
+
get chat(): ChatManager;
|
|
37
|
+
/**
|
|
38
|
+
* Access call functionality. Must call connect() first.
|
|
39
|
+
* Returns null if no video client is available (e.g. @stream-io/video-client not installed
|
|
40
|
+
* and no video client was injected).
|
|
41
|
+
*/
|
|
42
|
+
get calls(): CallManager | null;
|
|
43
|
+
/**
|
|
44
|
+
* Whether the client is currently connected.
|
|
45
|
+
*/
|
|
46
|
+
get isConnected(): boolean;
|
|
47
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.UStriveRealtimeClient = void 0;
|
|
37
|
+
const stream_chat_1 = require("stream-chat");
|
|
38
|
+
const chat_1 = require("./chat");
|
|
39
|
+
const calls_1 = require("./calls");
|
|
40
|
+
class UStriveRealtimeClient {
|
|
41
|
+
constructor(config) {
|
|
42
|
+
this.chatClient = null;
|
|
43
|
+
this.videoClient = null;
|
|
44
|
+
this._chat = null;
|
|
45
|
+
this._calls = null;
|
|
46
|
+
this.connected = false;
|
|
47
|
+
/** Whether this instance created the clients (vs. receiving injected ones) */
|
|
48
|
+
this.ownsChatClient = false;
|
|
49
|
+
this.ownsVideoClient = false;
|
|
50
|
+
if (!config.partnerClient)
|
|
51
|
+
throw new Error('partnerClient is required');
|
|
52
|
+
if (!config.userId)
|
|
53
|
+
throw new Error('userId is required');
|
|
54
|
+
this.partnerClient = config.partnerClient;
|
|
55
|
+
this.userId = config.userId;
|
|
56
|
+
this.injectedChatClient = config.chatClient || null;
|
|
57
|
+
this.injectedVideoClient = config.videoClient || null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Connect to Stream Chat and Video services.
|
|
61
|
+
*
|
|
62
|
+
* Web: Fetches a token and auto-creates Stream clients.
|
|
63
|
+
* React Native: Uses the pre-initialized clients passed in the constructor.
|
|
64
|
+
* If injected clients are provided, token fetch is still performed for
|
|
65
|
+
* the API key but client creation is skipped.
|
|
66
|
+
*/
|
|
67
|
+
async connect() {
|
|
68
|
+
if (this.connected)
|
|
69
|
+
return;
|
|
70
|
+
// Get Stream token from Partner API
|
|
71
|
+
const { token, apiKey } = await this.partnerClient.messaging.getStreamToken(this.userId);
|
|
72
|
+
// Chat client setup
|
|
73
|
+
if (this.injectedChatClient) {
|
|
74
|
+
// Use injected client (React Native / bring-your-own)
|
|
75
|
+
this.chatClient = this.injectedChatClient;
|
|
76
|
+
this.ownsChatClient = false;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Auto-create (web convenience)
|
|
80
|
+
this.chatClient = stream_chat_1.StreamChat.getInstance(apiKey);
|
|
81
|
+
await this.chatClient.connectUser({ id: this.userId }, token);
|
|
82
|
+
this.ownsChatClient = true;
|
|
83
|
+
}
|
|
84
|
+
// Video client setup
|
|
85
|
+
if (this.injectedVideoClient) {
|
|
86
|
+
// Use injected client (React Native — must be from @stream-io/video-react-native-sdk)
|
|
87
|
+
this.videoClient = this.injectedVideoClient;
|
|
88
|
+
this.ownsVideoClient = false;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Auto-create (web only — requires @stream-io/video-client peer dep)
|
|
92
|
+
try {
|
|
93
|
+
const { StreamVideoClient } = await Promise.resolve().then(() => __importStar(require('@stream-io/video-client')));
|
|
94
|
+
this.videoClient = new StreamVideoClient({ apiKey, token, user: { id: this.userId } });
|
|
95
|
+
this.ownsVideoClient = true;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// @stream-io/video-client not installed — calls will not be available
|
|
99
|
+
this.videoClient = null;
|
|
100
|
+
this.ownsVideoClient = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this._chat = new chat_1.ChatManager(this.chatClient, this.userId);
|
|
104
|
+
if (this.videoClient) {
|
|
105
|
+
this._calls = new calls_1.CallManager(this.videoClient);
|
|
106
|
+
}
|
|
107
|
+
this.connected = true;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Disconnect from all Stream services and clean up resources.
|
|
111
|
+
* Only disconnects clients that this instance created (not injected ones).
|
|
112
|
+
*/
|
|
113
|
+
async disconnect() {
|
|
114
|
+
if (!this.connected)
|
|
115
|
+
return;
|
|
116
|
+
if (this._chat) {
|
|
117
|
+
await this._chat.cleanup();
|
|
118
|
+
this._chat = null;
|
|
119
|
+
}
|
|
120
|
+
if (this._calls) {
|
|
121
|
+
await this._calls.cleanup();
|
|
122
|
+
this._calls = null;
|
|
123
|
+
}
|
|
124
|
+
// Only disconnect clients we own — injected clients are managed by the host app
|
|
125
|
+
if (this.chatClient && this.ownsChatClient) {
|
|
126
|
+
await this.chatClient.disconnectUser();
|
|
127
|
+
}
|
|
128
|
+
this.chatClient = null;
|
|
129
|
+
if (this.videoClient && this.ownsVideoClient) {
|
|
130
|
+
await this.videoClient.disconnectUser();
|
|
131
|
+
}
|
|
132
|
+
this.videoClient = null;
|
|
133
|
+
this.connected = false;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Access chat functionality. Must call connect() first.
|
|
137
|
+
*/
|
|
138
|
+
get chat() {
|
|
139
|
+
if (!this._chat) {
|
|
140
|
+
throw new Error('Not connected. Call connect() first.');
|
|
141
|
+
}
|
|
142
|
+
return this._chat;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Access call functionality. Must call connect() first.
|
|
146
|
+
* Returns null if no video client is available (e.g. @stream-io/video-client not installed
|
|
147
|
+
* and no video client was injected).
|
|
148
|
+
*/
|
|
149
|
+
get calls() {
|
|
150
|
+
if (!this.connected) {
|
|
151
|
+
throw new Error('Not connected. Call connect() first.');
|
|
152
|
+
}
|
|
153
|
+
return this._calls;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Whether the client is currently connected.
|
|
157
|
+
*/
|
|
158
|
+
get isConnected() {
|
|
159
|
+
return this.connected;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.UStriveRealtimeClient = UStriveRealtimeClient;
|
|
163
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CallManager = exports.ChatManager = exports.UStriveRealtimeClient = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "UStriveRealtimeClient", { enumerable: true, get: function () { return client_1.UStriveRealtimeClient; } });
|
|
6
|
+
var chat_1 = require("./chat");
|
|
7
|
+
Object.defineProperty(exports, "ChatManager", { enumerable: true, get: function () { return chat_1.ChatManager; } });
|
|
8
|
+
var calls_1 = require("./calls");
|
|
9
|
+
Object.defineProperty(exports, "CallManager", { enumerable: true, get: function () { return calls_1.CallManager; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAAiD;AAAxC,+GAAA,qBAAqB,OAAA;AAC9B,+BAAqC;AAA5B,mGAAA,WAAW,OAAA;AACpB,iCAAsC;AAA7B,oGAAA,WAAW,OAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { UStrivePartnerClient } from '@ustriveneo/partner-sdk';
|
|
2
|
+
import type { StreamChat } from 'stream-chat';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for UStriveRealtimeClient.
|
|
5
|
+
*
|
|
6
|
+
* For web apps, `partnerClient` + `userId` is sufficient — Stream clients
|
|
7
|
+
* are auto-created during `connect()`.
|
|
8
|
+
*
|
|
9
|
+
* For React Native apps, pass pre-initialized `chatClient` and `videoClient`
|
|
10
|
+
* because RN requires platform-specific SDKs (e.g. @stream-io/video-react-native-sdk)
|
|
11
|
+
* that register native camera/microphone modules.
|
|
12
|
+
*/
|
|
13
|
+
export interface RealtimeClientConfig {
|
|
14
|
+
partnerClient: UStrivePartnerClient;
|
|
15
|
+
userId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Pre-initialized StreamChat client. Required for React Native.
|
|
18
|
+
* On RN, the host app typically manages the chat client lifecycle.
|
|
19
|
+
* If provided, connect() will skip chat client creation.
|
|
20
|
+
*/
|
|
21
|
+
chatClient?: StreamChat;
|
|
22
|
+
/**
|
|
23
|
+
* Pre-initialized video client. Required for React Native.
|
|
24
|
+
* Pass the StreamVideoClient from @stream-io/video-react-native-sdk
|
|
25
|
+
* (which registers native camera/mic modules).
|
|
26
|
+
* Typed as `any` to avoid forcing a specific video SDK peer dependency —
|
|
27
|
+
* the underlying Call interface is identical across web and RN SDKs.
|
|
28
|
+
*/
|
|
29
|
+
videoClient?: any;
|
|
30
|
+
}
|
|
31
|
+
export interface ChatMessage {
|
|
32
|
+
id: string;
|
|
33
|
+
text: string;
|
|
34
|
+
userId: string;
|
|
35
|
+
attachments: ChatAttachment[];
|
|
36
|
+
createdAt: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ChatAttachment {
|
|
39
|
+
type: string;
|
|
40
|
+
url: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
size?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface ChatChannel {
|
|
45
|
+
id: string;
|
|
46
|
+
sendMessage(text: string): Promise<void>;
|
|
47
|
+
getMessages(opts?: {
|
|
48
|
+
limit?: number;
|
|
49
|
+
}): Promise<ChatMessage[]>;
|
|
50
|
+
onMessage(callback: (msg: ChatMessage) => void): () => void;
|
|
51
|
+
}
|
|
52
|
+
export interface ActiveCall {
|
|
53
|
+
callId: string;
|
|
54
|
+
setCamera(enabled: boolean): Promise<void>;
|
|
55
|
+
setMicrophone(enabled: boolean): Promise<void>;
|
|
56
|
+
on(event: string, callback: (...args: any[]) => void): () => void;
|
|
57
|
+
}
|
|
58
|
+
export interface JoinCallOptions {
|
|
59
|
+
video?: boolean;
|
|
60
|
+
audio?: boolean;
|
|
61
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ustriveneo/partner-realtime",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Client-side realtime SDK for UStrive Partner integrations (chat, video, audio)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"typecheck": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ustrive",
|
|
19
|
+
"partner",
|
|
20
|
+
"realtime",
|
|
21
|
+
"chat",
|
|
22
|
+
"video",
|
|
23
|
+
"stream"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@stream-io/video-client": "^1.0.0",
|
|
28
|
+
"@ustriveneo/partner-sdk": "^1.0.0",
|
|
29
|
+
"stream-chat": "^8.55.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependenciesMeta": {
|
|
32
|
+
"@stream-io/video-client": {
|
|
33
|
+
"optional": true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@stream-io/video-client": "^1.0.0",
|
|
38
|
+
"@ustriveneo/partner-sdk": "workspace:*",
|
|
39
|
+
"stream-chat": "^8.55.0",
|
|
40
|
+
"typescript": "^5.3.0",
|
|
41
|
+
"vitest": "^0.34.6"
|
|
42
|
+
}
|
|
43
|
+
}
|