@principal-ai/control-tower-core 0.2.2 → 0.3.1
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/adapters/websocket/WebSocketTransportAdapter.d.ts +60 -0
- package/dist/adapters/websocket/WebSocketTransportAdapter.d.ts.map +1 -0
- package/dist/adapters/websocket/WebSocketTransportAdapter.js +386 -0
- package/dist/client/BaseClient.d.ts +23 -0
- package/dist/client/BaseClient.d.ts.map +1 -1
- package/dist/client/BaseClient.js +60 -0
- package/dist/client/PresenceClient.d.ts +43 -8
- package/dist/client/PresenceClient.d.ts.map +1 -1
- package/dist/client/PresenceClient.js +72 -18
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +6 -6
- package/dist/index.mjs +94 -7
- package/dist/index.mjs.map +6 -6
- package/dist/server/BaseServer.d.ts +18 -1
- package/dist/server/BaseServer.d.ts.map +1 -1
- package/dist/server/BaseServer.js +15 -1
- package/dist/server/ServerBuilder.d.ts +22 -1
- package/dist/server/ServerBuilder.d.ts.map +1 -1
- package/dist/server/ServerBuilder.js +24 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/presence.d.ts +69 -0
- package/dist/types/presence.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ITransportAdapter } from '../../abstractions/TransportAdapter.js';
|
|
2
|
+
import type { IAuthAdapter } from '../../abstractions/AuthAdapter.js';
|
|
3
|
+
import type { ConnectionState, ConnectionOptions, Message, MessageHandler, ErrorHandler, CloseHandler } from '../../types/index.js';
|
|
4
|
+
import type { Server as HttpServer } from 'http';
|
|
5
|
+
import type { Server as HttpsServer } from 'https';
|
|
6
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
7
|
+
interface ClientConnection {
|
|
8
|
+
id: string;
|
|
9
|
+
ws: WebSocket;
|
|
10
|
+
userId?: string;
|
|
11
|
+
authenticated: boolean;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
authTimeout?: NodeJS.Timeout;
|
|
14
|
+
connectedAt: number;
|
|
15
|
+
}
|
|
16
|
+
export interface WebSocketTransportConfig {
|
|
17
|
+
authTimeout?: number;
|
|
18
|
+
closeOnAuthFailure?: boolean;
|
|
19
|
+
requireAuth?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare class WebSocketTransportAdapter implements ITransportAdapter {
|
|
22
|
+
private state;
|
|
23
|
+
private messageHandlers;
|
|
24
|
+
private errorHandlers;
|
|
25
|
+
private closeHandlers;
|
|
26
|
+
private wss?;
|
|
27
|
+
private serverUrl?;
|
|
28
|
+
private attachedServer?;
|
|
29
|
+
private attachedWss?;
|
|
30
|
+
private webSocketPath?;
|
|
31
|
+
private clients;
|
|
32
|
+
private mode;
|
|
33
|
+
private authAdapter?;
|
|
34
|
+
private config;
|
|
35
|
+
constructor(config?: WebSocketTransportConfig);
|
|
36
|
+
setAuthAdapter(auth: IAuthAdapter): void;
|
|
37
|
+
connect(url: string, _options?: ConnectionOptions): Promise<void>;
|
|
38
|
+
attach(server: HttpServer | HttpsServer, path?: string): Promise<void>;
|
|
39
|
+
attachToWebSocketServer(wss: WebSocketServer): Promise<void>;
|
|
40
|
+
private handleConnection;
|
|
41
|
+
private handleClientMessage;
|
|
42
|
+
private handleAuthMessage;
|
|
43
|
+
private extractBearerToken;
|
|
44
|
+
private sendToClient;
|
|
45
|
+
disconnect(): Promise<void>;
|
|
46
|
+
send(message: Message): Promise<void>;
|
|
47
|
+
onMessage(handler: MessageHandler): void;
|
|
48
|
+
onError(handler: ErrorHandler): void;
|
|
49
|
+
onClose(handler: CloseHandler): void;
|
|
50
|
+
getState(): ConnectionState;
|
|
51
|
+
isConnected(): boolean;
|
|
52
|
+
getConnectedClients(): ClientConnection[];
|
|
53
|
+
getAuthenticatedClients(): ClientConnection[];
|
|
54
|
+
getClientCount(): number;
|
|
55
|
+
getMode(): 'standalone' | 'integration';
|
|
56
|
+
isAuthRequired(): boolean;
|
|
57
|
+
private generateId;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=WebSocketTransportAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSocketTransportAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/websocket/WebSocketTransportAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,YAAY,EACZ,YAAY,EAGb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAEhD,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,yBAA0B,YAAW,iBAAiB;IACjE,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,aAAa,CAAgC;IAGrD,OAAO,CAAC,GAAG,CAAC,CAAkB;IAC9B,OAAO,CAAC,SAAS,CAAC,CAAS;IAG3B,OAAO,CAAC,cAAc,CAAC,CAA2B;IAClD,OAAO,CAAC,WAAW,CAAC,CAAkB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAS;IAG/B,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,IAAI,CAA8C;IAG1D,OAAO,CAAC,WAAW,CAAC,CAAe;IACnC,OAAO,CAAC,MAAM,CAA2B;gBAE7B,MAAM,CAAC,EAAE,wBAAwB;IAU7C,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAclC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCjE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,EAAE,IAAI,GAAE,MAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC7E,uBAAuB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YA2BpD,gBAAgB;YA6EhB,mBAAmB;YAuCnB,iBAAiB;IA4E/B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,YAAY;IAMd,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B3C,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAIpC,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAIpC,QAAQ,IAAI,eAAe;IAI3B,WAAW,IAAI,OAAO;IAKtB,mBAAmB,IAAI,gBAAgB,EAAE;IAIzC,uBAAuB,IAAI,gBAAgB,EAAE;IAI7C,cAAc,IAAI,MAAM;IAIxB,OAAO,IAAI,YAAY,GAAG,aAAa;IAIvC,cAAc,IAAI,OAAO;IAIzB,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebSocketTransportAdapter = void 0;
|
|
4
|
+
const ws_1 = require("ws");
|
|
5
|
+
class WebSocketTransportAdapter {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.state = 'disconnected';
|
|
8
|
+
this.messageHandlers = new Set();
|
|
9
|
+
this.errorHandlers = new Set();
|
|
10
|
+
this.closeHandlers = new Set();
|
|
11
|
+
// Client management
|
|
12
|
+
this.clients = new Map();
|
|
13
|
+
this.mode = 'standalone';
|
|
14
|
+
this.config = {
|
|
15
|
+
authTimeout: config?.authTimeout ?? 5000,
|
|
16
|
+
closeOnAuthFailure: config?.closeOnAuthFailure ?? false,
|
|
17
|
+
requireAuth: config?.requireAuth ?? false,
|
|
18
|
+
...config
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Set the auth adapter
|
|
22
|
+
setAuthAdapter(auth) {
|
|
23
|
+
this.authAdapter = auth;
|
|
24
|
+
// Use auth adapter's preference only if requireAuth is not already true
|
|
25
|
+
// This allows explicit requireAuth: true in config to take precedence
|
|
26
|
+
if (auth.isAuthRequired && !this.config.requireAuth) {
|
|
27
|
+
this.config.requireAuth = auth.isAuthRequired();
|
|
28
|
+
}
|
|
29
|
+
// For authTimeout, use adapter's value if not explicitly set (not matching default)
|
|
30
|
+
if (auth.getAuthTimeout && this.config.authTimeout === 5000) {
|
|
31
|
+
this.config.authTimeout = auth.getAuthTimeout();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Standalone mode implementation
|
|
35
|
+
async connect(url, _options) {
|
|
36
|
+
if (this.state === 'connected' || this.state === 'connecting') {
|
|
37
|
+
throw new Error('Already connected or connecting');
|
|
38
|
+
}
|
|
39
|
+
this.state = 'connecting';
|
|
40
|
+
this.serverUrl = url;
|
|
41
|
+
this.mode = 'standalone';
|
|
42
|
+
try {
|
|
43
|
+
// Extract port from URL
|
|
44
|
+
const urlObj = new URL(url);
|
|
45
|
+
const port = parseInt(urlObj.port) || (urlObj.protocol === 'wss:' ? 443 : 80);
|
|
46
|
+
// Create WebSocket server
|
|
47
|
+
this.wss = new ws_1.WebSocketServer({ port });
|
|
48
|
+
this.wss.on('connection', (ws, req) => {
|
|
49
|
+
this.handleConnection(ws, req);
|
|
50
|
+
});
|
|
51
|
+
this.wss.on('error', (error) => {
|
|
52
|
+
this.errorHandlers.forEach(handler => handler(error));
|
|
53
|
+
});
|
|
54
|
+
this.wss.on('close', () => {
|
|
55
|
+
this.state = 'disconnected';
|
|
56
|
+
this.closeHandlers.forEach(handler => handler(1000, 'Server closed'));
|
|
57
|
+
});
|
|
58
|
+
this.state = 'connected';
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
this.state = 'disconnected';
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Integration mode implementation
|
|
66
|
+
async attach(server, path = '/ws') {
|
|
67
|
+
if (this.state === 'connected' || this.state === 'connecting') {
|
|
68
|
+
throw new Error('Already connected or connecting');
|
|
69
|
+
}
|
|
70
|
+
this.state = 'connecting';
|
|
71
|
+
this.attachedServer = server;
|
|
72
|
+
this.webSocketPath = path;
|
|
73
|
+
this.mode = 'integration';
|
|
74
|
+
try {
|
|
75
|
+
// Create WebSocket server attached to the existing HTTP server
|
|
76
|
+
this.wss = new ws_1.WebSocketServer({
|
|
77
|
+
server,
|
|
78
|
+
path,
|
|
79
|
+
perMessageDeflate: false
|
|
80
|
+
});
|
|
81
|
+
this.wss.on('connection', (ws, req) => {
|
|
82
|
+
this.handleConnection(ws, req);
|
|
83
|
+
});
|
|
84
|
+
this.wss.on('error', (error) => {
|
|
85
|
+
this.errorHandlers.forEach(handler => handler(error));
|
|
86
|
+
});
|
|
87
|
+
this.state = 'connected';
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.state = 'disconnected';
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async attachToWebSocketServer(wss) {
|
|
95
|
+
if (this.state === 'connected' || this.state === 'connecting') {
|
|
96
|
+
throw new Error('Already connected or connecting');
|
|
97
|
+
}
|
|
98
|
+
this.state = 'connecting';
|
|
99
|
+
this.attachedWss = wss;
|
|
100
|
+
this.mode = 'integration';
|
|
101
|
+
try {
|
|
102
|
+
this.wss = wss;
|
|
103
|
+
this.wss.on('connection', (ws, req) => {
|
|
104
|
+
this.handleConnection(ws, req);
|
|
105
|
+
});
|
|
106
|
+
this.wss.on('error', (error) => {
|
|
107
|
+
this.errorHandlers.forEach(handler => handler(error));
|
|
108
|
+
});
|
|
109
|
+
this.state = 'connected';
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
this.state = 'disconnected';
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async handleConnection(ws, req) {
|
|
117
|
+
const clientId = this.generateId();
|
|
118
|
+
// Step 1: Try header authentication if auth adapter is available
|
|
119
|
+
let authenticated = false;
|
|
120
|
+
let authResult = null;
|
|
121
|
+
if (this.authAdapter && req.headers.authorization) {
|
|
122
|
+
const token = this.extractBearerToken(req.headers.authorization);
|
|
123
|
+
if (token) {
|
|
124
|
+
try {
|
|
125
|
+
authResult = await this.authAdapter.authenticate({
|
|
126
|
+
type: 'bearer',
|
|
127
|
+
token: token
|
|
128
|
+
});
|
|
129
|
+
authenticated = authResult.success;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Header auth failed but don't reject connection
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Step 2: Create client with auth state
|
|
137
|
+
const client = {
|
|
138
|
+
id: clientId,
|
|
139
|
+
ws,
|
|
140
|
+
authenticated,
|
|
141
|
+
userId: authResult?.userId || (authResult?.user?.userId),
|
|
142
|
+
metadata: authResult?.metadata || authResult?.user?.metadata,
|
|
143
|
+
connectedAt: Date.now()
|
|
144
|
+
};
|
|
145
|
+
this.clients.set(clientId, client);
|
|
146
|
+
// Step 3: Set up message handling
|
|
147
|
+
ws.on('message', (data) => {
|
|
148
|
+
this.handleClientMessage(clientId, data);
|
|
149
|
+
});
|
|
150
|
+
ws.on('error', (error) => {
|
|
151
|
+
this.errorHandlers.forEach(handler => handler(error));
|
|
152
|
+
});
|
|
153
|
+
ws.on('close', (_code, _reason) => {
|
|
154
|
+
// Clear auth timeout if exists
|
|
155
|
+
if (client.authTimeout) {
|
|
156
|
+
clearTimeout(client.authTimeout);
|
|
157
|
+
}
|
|
158
|
+
this.clients.delete(clientId);
|
|
159
|
+
});
|
|
160
|
+
// Step 4: Set auth timeout if not authenticated and auth is required
|
|
161
|
+
if (!authenticated && this.config.requireAuth && this.authAdapter) {
|
|
162
|
+
client.authTimeout = setTimeout(() => {
|
|
163
|
+
if (!client.authenticated) {
|
|
164
|
+
ws.close(1008, 'Authentication timeout');
|
|
165
|
+
this.clients.delete(clientId);
|
|
166
|
+
}
|
|
167
|
+
}, this.config.authTimeout);
|
|
168
|
+
}
|
|
169
|
+
// Step 5: Notify about connection (with auth status)
|
|
170
|
+
const connectionMessage = {
|
|
171
|
+
id: this.generateId(),
|
|
172
|
+
type: 'connection',
|
|
173
|
+
payload: {
|
|
174
|
+
clientId,
|
|
175
|
+
authenticated,
|
|
176
|
+
userId: client.userId,
|
|
177
|
+
metadata: client.metadata
|
|
178
|
+
},
|
|
179
|
+
timestamp: Date.now()
|
|
180
|
+
};
|
|
181
|
+
this.messageHandlers.forEach(handler => handler(connectionMessage));
|
|
182
|
+
}
|
|
183
|
+
async handleClientMessage(clientId, data) {
|
|
184
|
+
const client = this.clients.get(clientId);
|
|
185
|
+
if (!client)
|
|
186
|
+
return;
|
|
187
|
+
try {
|
|
188
|
+
const message = JSON.parse(data.toString());
|
|
189
|
+
// Special handling for authentication messages
|
|
190
|
+
if (message.type === 'authenticate' && !client.authenticated && this.authAdapter) {
|
|
191
|
+
await this.handleAuthMessage(client, message);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// Reject messages from unauthenticated clients if auth is required
|
|
195
|
+
if (this.config.requireAuth && !client.authenticated) {
|
|
196
|
+
this.sendToClient(client, {
|
|
197
|
+
id: this.generateId(),
|
|
198
|
+
type: 'error',
|
|
199
|
+
payload: { error: 'Authentication required' },
|
|
200
|
+
timestamp: Date.now()
|
|
201
|
+
});
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Add clientId to message payload for routing
|
|
205
|
+
const enrichedMessage = {
|
|
206
|
+
...message,
|
|
207
|
+
payload: {
|
|
208
|
+
...message.payload,
|
|
209
|
+
clientId
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
this.messageHandlers.forEach(handler => handler(enrichedMessage));
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
this.errorHandlers.forEach(handler => handler(error));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async handleAuthMessage(client, message) {
|
|
219
|
+
if (!this.authAdapter) {
|
|
220
|
+
this.sendToClient(client, {
|
|
221
|
+
id: this.generateId(),
|
|
222
|
+
type: 'auth_error',
|
|
223
|
+
payload: { error: 'No auth adapter configured' },
|
|
224
|
+
timestamp: Date.now()
|
|
225
|
+
});
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const credentials = message.payload;
|
|
230
|
+
const result = await this.authAdapter.authenticate(credentials);
|
|
231
|
+
if (result.success) {
|
|
232
|
+
// Clear auth timeout
|
|
233
|
+
if (client.authTimeout) {
|
|
234
|
+
clearTimeout(client.authTimeout);
|
|
235
|
+
client.authTimeout = undefined;
|
|
236
|
+
}
|
|
237
|
+
// Update client state
|
|
238
|
+
client.authenticated = true;
|
|
239
|
+
client.userId = result.userId || result.user?.userId;
|
|
240
|
+
client.metadata = result.metadata || result.user?.metadata;
|
|
241
|
+
// Send success response
|
|
242
|
+
this.sendToClient(client, {
|
|
243
|
+
id: this.generateId(),
|
|
244
|
+
type: 'auth_success',
|
|
245
|
+
payload: {
|
|
246
|
+
userId: client.userId,
|
|
247
|
+
metadata: client.metadata
|
|
248
|
+
},
|
|
249
|
+
timestamp: Date.now()
|
|
250
|
+
});
|
|
251
|
+
// Notify handlers about authentication
|
|
252
|
+
const authMessage = {
|
|
253
|
+
id: this.generateId(),
|
|
254
|
+
type: 'client_authenticated',
|
|
255
|
+
payload: {
|
|
256
|
+
clientId: client.id,
|
|
257
|
+
userId: client.userId,
|
|
258
|
+
metadata: client.metadata
|
|
259
|
+
},
|
|
260
|
+
timestamp: Date.now()
|
|
261
|
+
};
|
|
262
|
+
this.messageHandlers.forEach(handler => handler(authMessage));
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
// Send error response
|
|
266
|
+
this.sendToClient(client, {
|
|
267
|
+
id: this.generateId(),
|
|
268
|
+
type: 'auth_error',
|
|
269
|
+
payload: { error: result.error || 'Authentication failed' },
|
|
270
|
+
timestamp: Date.now()
|
|
271
|
+
});
|
|
272
|
+
// Optionally close connection
|
|
273
|
+
if (this.config.closeOnAuthFailure) {
|
|
274
|
+
client.ws.close(1008, 'Authentication failed');
|
|
275
|
+
this.clients.delete(client.id);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
this.sendToClient(client, {
|
|
281
|
+
id: this.generateId(),
|
|
282
|
+
type: 'auth_error',
|
|
283
|
+
payload: { error: error.message },
|
|
284
|
+
timestamp: Date.now()
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
extractBearerToken(authHeader) {
|
|
289
|
+
if (authHeader.startsWith('Bearer ')) {
|
|
290
|
+
return authHeader.substring(7);
|
|
291
|
+
}
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
sendToClient(client, message) {
|
|
295
|
+
if (client.ws.readyState === ws_1.WebSocket.OPEN) {
|
|
296
|
+
client.ws.send(JSON.stringify(message));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async disconnect() {
|
|
300
|
+
if (this.state === 'disconnected') {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.state = 'disconnecting';
|
|
304
|
+
// Close all client connections
|
|
305
|
+
for (const [_clientId, client] of this.clients) {
|
|
306
|
+
try {
|
|
307
|
+
if (client.authTimeout) {
|
|
308
|
+
clearTimeout(client.authTimeout);
|
|
309
|
+
}
|
|
310
|
+
client.ws.close(1000, 'Server shutting down');
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// Ignore errors when closing individual connections
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
this.clients.clear();
|
|
317
|
+
// Close the WebSocket server (only if we created it)
|
|
318
|
+
if (this.wss && this.mode === 'standalone') {
|
|
319
|
+
await new Promise((resolve) => {
|
|
320
|
+
this.wss.close(() => resolve());
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
this.state = 'disconnected';
|
|
324
|
+
this.wss = undefined;
|
|
325
|
+
this.attachedServer = undefined;
|
|
326
|
+
this.attachedWss = undefined;
|
|
327
|
+
}
|
|
328
|
+
async send(message) {
|
|
329
|
+
if (this.state !== 'connected') {
|
|
330
|
+
throw new Error('Not connected');
|
|
331
|
+
}
|
|
332
|
+
// Extract clientId from message payload for routing
|
|
333
|
+
const payload = message.payload;
|
|
334
|
+
const { clientId, ...clientMessage } = payload;
|
|
335
|
+
if (!clientId) {
|
|
336
|
+
throw new Error('Message must contain clientId in payload for routing');
|
|
337
|
+
}
|
|
338
|
+
const client = this.clients.get(clientId);
|
|
339
|
+
if (!client) {
|
|
340
|
+
throw new Error(`Client ${clientId} not found`);
|
|
341
|
+
}
|
|
342
|
+
if (client.ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
343
|
+
throw new Error(`Client ${clientId} connection is not open`);
|
|
344
|
+
}
|
|
345
|
+
const messageToSend = {
|
|
346
|
+
...message,
|
|
347
|
+
payload: clientMessage
|
|
348
|
+
};
|
|
349
|
+
client.ws.send(JSON.stringify(messageToSend));
|
|
350
|
+
}
|
|
351
|
+
onMessage(handler) {
|
|
352
|
+
this.messageHandlers.add(handler);
|
|
353
|
+
}
|
|
354
|
+
onError(handler) {
|
|
355
|
+
this.errorHandlers.add(handler);
|
|
356
|
+
}
|
|
357
|
+
onClose(handler) {
|
|
358
|
+
this.closeHandlers.add(handler);
|
|
359
|
+
}
|
|
360
|
+
getState() {
|
|
361
|
+
return this.state;
|
|
362
|
+
}
|
|
363
|
+
isConnected() {
|
|
364
|
+
return this.state === 'connected';
|
|
365
|
+
}
|
|
366
|
+
// Utility methods
|
|
367
|
+
getConnectedClients() {
|
|
368
|
+
return Array.from(this.clients.values());
|
|
369
|
+
}
|
|
370
|
+
getAuthenticatedClients() {
|
|
371
|
+
return Array.from(this.clients.values()).filter(c => c.authenticated);
|
|
372
|
+
}
|
|
373
|
+
getClientCount() {
|
|
374
|
+
return this.clients.size;
|
|
375
|
+
}
|
|
376
|
+
getMode() {
|
|
377
|
+
return this.mode;
|
|
378
|
+
}
|
|
379
|
+
isAuthRequired() {
|
|
380
|
+
return this.config.requireAuth ?? false;
|
|
381
|
+
}
|
|
382
|
+
generateId() {
|
|
383
|
+
return Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
exports.WebSocketTransportAdapter = WebSocketTransportAdapter;
|
|
@@ -78,6 +78,7 @@ export declare class BaseClient extends TypedEventEmitter<ClientEvents> {
|
|
|
78
78
|
private reconnectTimer;
|
|
79
79
|
private lastConnectionUrl;
|
|
80
80
|
private lastToken;
|
|
81
|
+
private pendingRequests;
|
|
81
82
|
constructor(config: ClientConfig);
|
|
82
83
|
/**
|
|
83
84
|
* Connect to the server with an optional authentication token.
|
|
@@ -105,6 +106,28 @@ export declare class BaseClient extends TypedEventEmitter<ClientEvents> {
|
|
|
105
106
|
broadcast(event: Event): Promise<void>;
|
|
106
107
|
requestLock(request: LockRequest): Promise<void>;
|
|
107
108
|
releaseLock(lockId: string): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* Send a request message and wait for a response.
|
|
111
|
+
*
|
|
112
|
+
* This enables request/response patterns over WebSocket by correlating
|
|
113
|
+
* the response message with the request via the message ID.
|
|
114
|
+
*
|
|
115
|
+
* @param type The message type to send
|
|
116
|
+
* @param payload The message payload
|
|
117
|
+
* @param timeoutMs Timeout in milliseconds (default: 5000)
|
|
118
|
+
* @returns Promise that resolves with the response payload
|
|
119
|
+
* @throws Error if the request times out or the client is not connected
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const response = await client.request<PresenceGetUsersResponse>(
|
|
124
|
+
* 'presence:get_users',
|
|
125
|
+
* {}
|
|
126
|
+
* );
|
|
127
|
+
* console.log(response.users);
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
request<T>(type: string, payload: unknown, timeoutMs?: number): Promise<T>;
|
|
108
131
|
getConnectionState(): ConnectionState;
|
|
109
132
|
getRoomState(): RoomState | null;
|
|
110
133
|
getPresence(): RoomUser[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseClient.d.ts","sourceRoot":"","sources":["../../src/client/BaseClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EACX,mBAAmB,EAGnB,eAAe,EACf,KAAK,EACL,IAAI,EACJ,WAAW,EAEX,SAAS,EACT,QAAQ,EACR,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;KACtB,CAAC;CACF;AAED,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,qBAAqB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,YAAY,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IACxB,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;IAClD,SAAS,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,cAAc,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IACjC,aAAa,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IAC9B,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,WAAW,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,gBAAgB,EAAE;QAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,qBAAa,UAAW,SAAQ,iBAAiB,CAAC,YAAY,CAAC;IAC9D,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,IAAI,CAAC,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAC,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAe;IAE7B,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,MAAM,CAAuB;IAGrC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,SAAS,CAAuB;
|
|
1
|
+
{"version":3,"file":"BaseClient.d.ts","sourceRoot":"","sources":["../../src/client/BaseClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EACX,mBAAmB,EAGnB,eAAe,EACf,KAAK,EACL,IAAI,EACJ,WAAW,EAEX,SAAS,EACT,QAAQ,EACR,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;KACtB,CAAC;CACF;AAED,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,qBAAqB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,YAAY,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IACxB,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;IAClD,SAAS,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,cAAc,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IACjC,aAAa,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IAC9B,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,WAAW,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,gBAAgB,EAAE;QAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,qBAAa,UAAW,SAAQ,iBAAiB,CAAC,YAAY,CAAC;IAC9D,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,IAAI,CAAC,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAC,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAe;IAE7B,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,MAAM,CAAuB;IAGrC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,SAAS,CAAuB;IAGxC,OAAO,CAAC,eAAe,CAOnB;gBAEQ,MAAM,EAAE,YAAY;IAchC;;;;;OAKG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyDnD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC3B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAahC;;;;;;OAMG;IACG,YAAY,CACjB,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAC1C,OAAO,CAAC,IAAI,CAAC;IA2BhB;;OAEG;IACH,YAAY,IAAI,OAAO;IAKjB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB1B,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBtC,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBhD;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,OAAO,CAAC,CAAC,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,SAAS,SAAO,GACd,OAAO,CAAC,CAAC,CAAC;IAkCb,kBAAkB,IAAI,eAAe;IAIrC,YAAY,IAAI,SAAS,GAAG,IAAI;IAIhC,WAAW,IAAI,QAAQ,EAAE;IAMzB,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,SAAS,IAAI,MAAM,GAAG,IAAI;YAKZ,aAAa;YAoDb,WAAW;YAIX,WAAW;YAcX,gBAAgB;YAahB,gBAAgB;YAgBhB,cAAc;YAQd,oBAAoB;YAIpB,kBAAkB;YAIlB,kBAAkB;YAIlB,gBAAgB;YAOhB,qBAAqB;YAYrB,iBAAiB;YAKjB,iBAAiB;IAiC/B,OAAO,CAAC,UAAU;CAGlB"}
|
|
@@ -16,6 +16,8 @@ class BaseClient extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
16
16
|
this.reconnectTimer = null;
|
|
17
17
|
this.lastConnectionUrl = null;
|
|
18
18
|
this.lastToken = null;
|
|
19
|
+
// Request/response tracking for request() method
|
|
20
|
+
this.pendingRequests = new Map();
|
|
19
21
|
this.config = config;
|
|
20
22
|
this.transport = config.transport;
|
|
21
23
|
this.auth = config.auth;
|
|
@@ -222,6 +224,56 @@ class BaseClient extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
222
224
|
};
|
|
223
225
|
await this.transport.send(message);
|
|
224
226
|
}
|
|
227
|
+
// Request/Response Pattern
|
|
228
|
+
/**
|
|
229
|
+
* Send a request message and wait for a response.
|
|
230
|
+
*
|
|
231
|
+
* This enables request/response patterns over WebSocket by correlating
|
|
232
|
+
* the response message with the request via the message ID.
|
|
233
|
+
*
|
|
234
|
+
* @param type The message type to send
|
|
235
|
+
* @param payload The message payload
|
|
236
|
+
* @param timeoutMs Timeout in milliseconds (default: 5000)
|
|
237
|
+
* @returns Promise that resolves with the response payload
|
|
238
|
+
* @throws Error if the request times out or the client is not connected
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const response = await client.request<PresenceGetUsersResponse>(
|
|
243
|
+
* 'presence:get_users',
|
|
244
|
+
* {}
|
|
245
|
+
* );
|
|
246
|
+
* console.log(response.users);
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
async request(type, payload, timeoutMs = 5000) {
|
|
250
|
+
if (this.connectionState !== "connected") {
|
|
251
|
+
throw new Error("Client must be connected to send requests");
|
|
252
|
+
}
|
|
253
|
+
const id = this.generateId();
|
|
254
|
+
const message = {
|
|
255
|
+
id,
|
|
256
|
+
type,
|
|
257
|
+
payload,
|
|
258
|
+
timestamp: Date.now(),
|
|
259
|
+
};
|
|
260
|
+
return new Promise((resolve, reject) => {
|
|
261
|
+
const timeout = setTimeout(() => {
|
|
262
|
+
this.pendingRequests.delete(id);
|
|
263
|
+
reject(new Error(`Request '${type}' timed out after ${timeoutMs}ms`));
|
|
264
|
+
}, timeoutMs);
|
|
265
|
+
this.pendingRequests.set(id, {
|
|
266
|
+
resolve: resolve,
|
|
267
|
+
reject,
|
|
268
|
+
timeout,
|
|
269
|
+
});
|
|
270
|
+
this.transport.send(message).catch((error) => {
|
|
271
|
+
this.pendingRequests.delete(id);
|
|
272
|
+
clearTimeout(timeout);
|
|
273
|
+
reject(error);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
225
277
|
// State Getters
|
|
226
278
|
getConnectionState() {
|
|
227
279
|
return this.connectionState;
|
|
@@ -242,6 +294,14 @@ class BaseClient extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
242
294
|
}
|
|
243
295
|
// Private Methods
|
|
244
296
|
async handleMessage(message) {
|
|
297
|
+
// Check for pending request response (matched by message id)
|
|
298
|
+
if (message.id && this.pendingRequests.has(message.id)) {
|
|
299
|
+
const pending = this.pendingRequests.get(message.id);
|
|
300
|
+
clearTimeout(pending.timeout);
|
|
301
|
+
this.pendingRequests.delete(message.id);
|
|
302
|
+
pending.resolve(message.payload);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
245
305
|
try {
|
|
246
306
|
switch (message.type) {
|
|
247
307
|
case "auth_result":
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Automatically handles connection, authentication, and presence event forwarding.
|
|
6
6
|
*/
|
|
7
7
|
import { TypedEventEmitter } from "../abstractions/EventEmitter.js";
|
|
8
|
-
import type {
|
|
8
|
+
import type { SerializableUserPresence } from "../types/presence.js";
|
|
9
9
|
import { BaseClient, type ClientConfig } from "./BaseClient.js";
|
|
10
10
|
export interface PresenceClientConfig {
|
|
11
11
|
/**
|
|
@@ -118,23 +118,58 @@ export declare class PresenceClient extends TypedEventEmitter<PresenceClientEven
|
|
|
118
118
|
*/
|
|
119
119
|
disconnect(): Promise<void>;
|
|
120
120
|
/**
|
|
121
|
-
* Get all online users
|
|
121
|
+
* Get all online users with their presence data
|
|
122
122
|
*
|
|
123
|
-
*
|
|
123
|
+
* @returns Array of user presence objects
|
|
124
124
|
*/
|
|
125
|
-
getOnlineUsers(): Promise<
|
|
125
|
+
getOnlineUsers(): Promise<SerializableUserPresence[]>;
|
|
126
|
+
/**
|
|
127
|
+
* Get presence information for a specific user
|
|
128
|
+
*
|
|
129
|
+
* @param userId The user ID to look up
|
|
130
|
+
* @returns User presence or null if not found
|
|
131
|
+
*/
|
|
132
|
+
getUserPresence(userId: string): Promise<SerializableUserPresence | null>;
|
|
133
|
+
/**
|
|
134
|
+
* Get all users in a specific repository
|
|
135
|
+
*
|
|
136
|
+
* @param owner Repository owner
|
|
137
|
+
* @param repo Repository name
|
|
138
|
+
* @returns Array of user presence objects
|
|
139
|
+
*/
|
|
140
|
+
getRepoUsers(owner: string, repo: string): Promise<SerializableUserPresence[]>;
|
|
126
141
|
/**
|
|
127
142
|
* Set user status
|
|
128
143
|
*
|
|
129
|
-
*
|
|
144
|
+
* @param status The status to set ('online' or 'away')
|
|
145
|
+
* @param statusMessage Optional status message
|
|
130
146
|
*/
|
|
131
|
-
setStatus(status: "online" | "away",
|
|
147
|
+
setStatus(status: "online" | "away", statusMessage?: string): Promise<void>;
|
|
132
148
|
/**
|
|
133
|
-
* Set visibility
|
|
149
|
+
* Set visibility (invisible/lurker mode)
|
|
134
150
|
*
|
|
135
|
-
*
|
|
151
|
+
* @param visible Whether the user should be visible to others
|
|
136
152
|
*/
|
|
137
153
|
setVisibility(visible: boolean): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Report that a repository was opened
|
|
156
|
+
*
|
|
157
|
+
* @param repoId Repository ID (format: "owner/repo")
|
|
158
|
+
* @param branch Branch name
|
|
159
|
+
*/
|
|
160
|
+
reportRepoOpened(repoId: string, branch: string): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Report that a repository was closed
|
|
163
|
+
*
|
|
164
|
+
* @param repoId Repository ID (format: "owner/repo")
|
|
165
|
+
*/
|
|
166
|
+
reportRepoClosed(repoId: string): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Report that a repository is now focused/active
|
|
169
|
+
*
|
|
170
|
+
* @param repoId Repository ID (format: "owner/repo")
|
|
171
|
+
*/
|
|
172
|
+
reportRepoFocused(repoId: string): Promise<void>;
|
|
138
173
|
/**
|
|
139
174
|
* Get the underlying BaseClient
|
|
140
175
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresenceClient.d.ts","sourceRoot":"","sources":["../../src/client/PresenceClient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"PresenceClient.d.ts","sourceRoot":"","sources":["../../src/client/PresenceClient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAKX,wBAAwB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,YAAY,EAAE,YAAY,CAAC;IAE3B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAEnD;;OAEG;IACH,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAEhC;;OAEG;IACH,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1E;;OAEG;IACH,SAAS,EAAE,EAAE,CAAC;IAEd;;OAEG;IACH,YAAY,EAAE,EAAE,CAAC;IAEjB;;OAEG;IACH,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IAExB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,cAAe,SAAQ,iBAAiB,CAAC,oBAAoB,CAAC;IAC1E,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,oBAAoB,CAAU;IACtC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAC,CAAiB;gBAE9B,MAAM,EAAE,oBAAoB;IAiBxC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBjC;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAQ3D;;;;;OAKG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAQ/E;;;;;;OAMG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAQpF;;;;;OAKG;IACG,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjF;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAUpD;;;;;OAKG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrE;;;;OAIG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrD;;;;OAIG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtD;;OAEG;IACH,SAAS,IAAI,UAAU;IAIvB;;OAEG;IACH,WAAW,IAAI,OAAO;IAMtB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CAwD5B"}
|