claude-telegram-mirror 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.
Files changed (99) hide show
  1. package/README.md +331 -0
  2. package/dist/bot/commands.d.ts +41 -0
  3. package/dist/bot/commands.d.ts.map +1 -0
  4. package/dist/bot/commands.js +231 -0
  5. package/dist/bot/commands.js.map +1 -0
  6. package/dist/bot/formatting.d.ts +62 -0
  7. package/dist/bot/formatting.d.ts.map +1 -0
  8. package/dist/bot/formatting.js +295 -0
  9. package/dist/bot/formatting.js.map +1 -0
  10. package/dist/bot/telegram.d.ts +93 -0
  11. package/dist/bot/telegram.d.ts.map +1 -0
  12. package/dist/bot/telegram.js +378 -0
  13. package/dist/bot/telegram.js.map +1 -0
  14. package/dist/bot/types.d.ts +28 -0
  15. package/dist/bot/types.d.ts.map +1 -0
  16. package/dist/bot/types.js +5 -0
  17. package/dist/bot/types.js.map +1 -0
  18. package/dist/bridge/daemon.d.ts +93 -0
  19. package/dist/bridge/daemon.d.ts.map +1 -0
  20. package/dist/bridge/daemon.js +626 -0
  21. package/dist/bridge/daemon.js.map +1 -0
  22. package/dist/bridge/index.d.ts +10 -0
  23. package/dist/bridge/index.d.ts.map +1 -0
  24. package/dist/bridge/index.js +9 -0
  25. package/dist/bridge/index.js.map +1 -0
  26. package/dist/bridge/injector.d.ts +97 -0
  27. package/dist/bridge/injector.d.ts.map +1 -0
  28. package/dist/bridge/injector.js +289 -0
  29. package/dist/bridge/injector.js.map +1 -0
  30. package/dist/bridge/session.d.ts +108 -0
  31. package/dist/bridge/session.d.ts.map +1 -0
  32. package/dist/bridge/session.js +381 -0
  33. package/dist/bridge/session.js.map +1 -0
  34. package/dist/bridge/socket.d.ts +97 -0
  35. package/dist/bridge/socket.d.ts.map +1 -0
  36. package/dist/bridge/socket.js +436 -0
  37. package/dist/bridge/socket.js.map +1 -0
  38. package/dist/bridge/types.d.ts +38 -0
  39. package/dist/bridge/types.d.ts.map +1 -0
  40. package/dist/bridge/types.js +5 -0
  41. package/dist/bridge/types.js.map +1 -0
  42. package/dist/cli.d.ts +7 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +332 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/hooks/handler.d.ts +94 -0
  47. package/dist/hooks/handler.d.ts.map +1 -0
  48. package/dist/hooks/handler.js +431 -0
  49. package/dist/hooks/handler.js.map +1 -0
  50. package/dist/hooks/index.d.ts +8 -0
  51. package/dist/hooks/index.d.ts.map +1 -0
  52. package/dist/hooks/index.js +7 -0
  53. package/dist/hooks/index.js.map +1 -0
  54. package/dist/hooks/installer.d.ts +46 -0
  55. package/dist/hooks/installer.d.ts.map +1 -0
  56. package/dist/hooks/installer.js +317 -0
  57. package/dist/hooks/installer.js.map +1 -0
  58. package/dist/hooks/types.d.ts +88 -0
  59. package/dist/hooks/types.d.ts.map +1 -0
  60. package/dist/hooks/types.js +6 -0
  61. package/dist/hooks/types.js.map +1 -0
  62. package/dist/index.d.ts +19 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +20 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/service/doctor.d.ts +10 -0
  67. package/dist/service/doctor.d.ts.map +1 -0
  68. package/dist/service/doctor.js +424 -0
  69. package/dist/service/doctor.js.map +1 -0
  70. package/dist/service/manager.d.ts +48 -0
  71. package/dist/service/manager.d.ts.map +1 -0
  72. package/dist/service/manager.js +584 -0
  73. package/dist/service/manager.js.map +1 -0
  74. package/dist/service/setup.d.ts +10 -0
  75. package/dist/service/setup.d.ts.map +1 -0
  76. package/dist/service/setup.js +266 -0
  77. package/dist/service/setup.js.map +1 -0
  78. package/dist/utils/chunker.d.ts +24 -0
  79. package/dist/utils/chunker.d.ts.map +1 -0
  80. package/dist/utils/chunker.js +123 -0
  81. package/dist/utils/chunker.js.map +1 -0
  82. package/dist/utils/config.d.ts +48 -0
  83. package/dist/utils/config.d.ts.map +1 -0
  84. package/dist/utils/config.js +154 -0
  85. package/dist/utils/config.js.map +1 -0
  86. package/dist/utils/logger.d.ts +7 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +28 -0
  89. package/dist/utils/logger.js.map +1 -0
  90. package/package.json +88 -0
  91. package/postinstall.cjs +76 -0
  92. package/scripts/claude-wrapper.sh +122 -0
  93. package/scripts/doctor.sh +433 -0
  94. package/scripts/get-chat-id.sh +64 -0
  95. package/scripts/global-hooks.sh +39 -0
  96. package/scripts/install.sh +831 -0
  97. package/scripts/start-daemon.sh +49 -0
  98. package/scripts/telegram-hook.sh +449 -0
  99. package/scripts/uninstall.sh +261 -0
@@ -0,0 +1,381 @@
1
+ /**
2
+ * Session Management with SQLite
3
+ * Tracks CLI sessions and pending approvals
4
+ */
5
+ import Database from 'better-sqlite3';
6
+ import { join } from 'path';
7
+ import { mkdirSync, existsSync } from 'fs';
8
+ import { homedir } from 'os';
9
+ import { randomBytes } from 'crypto';
10
+ import logger from '../utils/logger.js';
11
+ const CONFIG_DIR = join(homedir(), '.config', 'claude-telegram-mirror');
12
+ const DB_PATH = join(CONFIG_DIR, 'sessions.db');
13
+ /**
14
+ * Generate a unique ID
15
+ */
16
+ function generateId(prefix = '') {
17
+ const timestamp = Date.now().toString(36);
18
+ const random = randomBytes(4).toString('hex');
19
+ return prefix ? `${prefix}-${timestamp}-${random}` : `${timestamp}-${random}`;
20
+ }
21
+ /**
22
+ * Session Manager
23
+ * Handles session and approval lifecycle
24
+ */
25
+ export class SessionManager {
26
+ db;
27
+ approvalTimeout;
28
+ constructor(dbPath = DB_PATH, approvalTimeoutMinutes = 5) {
29
+ // Ensure config directory exists
30
+ if (!existsSync(CONFIG_DIR)) {
31
+ mkdirSync(CONFIG_DIR, { recursive: true });
32
+ }
33
+ this.db = new Database(dbPath);
34
+ this.approvalTimeout = approvalTimeoutMinutes * 60 * 1000;
35
+ this.initSchema();
36
+ logger.info('Session manager initialized', { dbPath });
37
+ }
38
+ /**
39
+ * Initialize database schema
40
+ */
41
+ initSchema() {
42
+ this.db.exec(`
43
+ CREATE TABLE IF NOT EXISTS sessions (
44
+ id TEXT PRIMARY KEY,
45
+ chat_id INTEGER NOT NULL,
46
+ thread_id INTEGER,
47
+ hostname TEXT,
48
+ tmux_target TEXT,
49
+ tmux_socket TEXT,
50
+ started_at TEXT NOT NULL,
51
+ last_activity TEXT NOT NULL,
52
+ status TEXT DEFAULT 'active',
53
+ project_dir TEXT,
54
+ metadata TEXT
55
+ );
56
+
57
+ -- Migration: Add tmux columns if they don't exist (for existing DBs)
58
+ -- SQLite doesn't support IF NOT EXISTS for ALTER TABLE, so we use a pragma check
59
+
60
+ CREATE TABLE IF NOT EXISTS pending_approvals (
61
+ id TEXT PRIMARY KEY,
62
+ session_id TEXT NOT NULL,
63
+ prompt TEXT NOT NULL,
64
+ created_at TEXT NOT NULL,
65
+ expires_at TEXT NOT NULL,
66
+ status TEXT DEFAULT 'pending',
67
+ message_id INTEGER,
68
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
69
+ );
70
+
71
+ CREATE INDEX IF NOT EXISTS idx_sessions_chat ON sessions(chat_id);
72
+ CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status);
73
+ CREATE INDEX IF NOT EXISTS idx_approvals_session ON pending_approvals(session_id);
74
+ CREATE INDEX IF NOT EXISTS idx_approvals_status ON pending_approvals(status);
75
+ `);
76
+ // Migration: Add tmux_target column to existing databases
77
+ this.migrateAddTmuxTarget();
78
+ }
79
+ /**
80
+ * Migration: Add tmux columns to existing databases
81
+ */
82
+ migrateAddTmuxTarget() {
83
+ try {
84
+ const tableInfo = this.db.prepare(`PRAGMA table_info(sessions)`).all();
85
+ const columns = new Set(tableInfo.map(col => col.name));
86
+ if (!columns.has('tmux_target')) {
87
+ this.db.exec(`ALTER TABLE sessions ADD COLUMN tmux_target TEXT`);
88
+ logger.info('Migration: Added tmux_target column to sessions table');
89
+ }
90
+ if (!columns.has('tmux_socket')) {
91
+ this.db.exec(`ALTER TABLE sessions ADD COLUMN tmux_socket TEXT`);
92
+ logger.info('Migration: Added tmux_socket column to sessions table');
93
+ }
94
+ }
95
+ catch (error) {
96
+ logger.debug('Migration check for tmux columns', { error });
97
+ }
98
+ }
99
+ // ============ Session Methods ============
100
+ /**
101
+ * Create a new session with optional specific ID (for using Claude's native session_id)
102
+ */
103
+ createSession(chatId, projectDir, threadId, hostname, sessionId, tmuxTarget, tmuxSocket) {
104
+ // Use provided sessionId (from Claude) or generate one
105
+ const id = sessionId || generateId('session');
106
+ const now = new Date().toISOString();
107
+ // Check if session already exists
108
+ const existing = this.getSession(id);
109
+ if (existing) {
110
+ logger.info('Session already exists, updating activity', { sessionId: id });
111
+ this.updateActivity(id);
112
+ // Update tmux info if provided and session exists
113
+ if (tmuxTarget || tmuxSocket) {
114
+ this.setTmuxInfo(id, tmuxTarget, tmuxSocket);
115
+ }
116
+ return id;
117
+ }
118
+ this.db.prepare(`
119
+ INSERT INTO sessions (id, chat_id, thread_id, hostname, tmux_target, tmux_socket, started_at, last_activity, status, project_dir)
120
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'active', ?)
121
+ `).run(id, chatId, threadId || null, hostname || null, tmuxTarget || null, tmuxSocket || null, now, now, projectDir || null);
122
+ logger.info('Session created', { sessionId: id, chatId, threadId, hostname, tmuxTarget, tmuxSocket });
123
+ return id;
124
+ }
125
+ /**
126
+ * Update session thread ID
127
+ */
128
+ setSessionThread(sessionId, threadId) {
129
+ this.db.prepare(`
130
+ UPDATE sessions SET thread_id = ? WHERE id = ?
131
+ `).run(threadId, sessionId);
132
+ logger.info('Session thread set', { sessionId, threadId });
133
+ }
134
+ /**
135
+ * Get session thread ID
136
+ */
137
+ getSessionThread(sessionId) {
138
+ const row = this.db.prepare(`
139
+ SELECT thread_id FROM sessions WHERE id = ?
140
+ `).get(sessionId);
141
+ return row?.thread_id || null;
142
+ }
143
+ /**
144
+ * Set session tmux info (target and socket for input injection)
145
+ */
146
+ setTmuxInfo(sessionId, tmuxTarget, tmuxSocket) {
147
+ if (tmuxTarget && tmuxSocket) {
148
+ this.db.prepare(`
149
+ UPDATE sessions SET tmux_target = ?, tmux_socket = ? WHERE id = ?
150
+ `).run(tmuxTarget, tmuxSocket, sessionId);
151
+ }
152
+ else if (tmuxTarget) {
153
+ this.db.prepare(`
154
+ UPDATE sessions SET tmux_target = ? WHERE id = ?
155
+ `).run(tmuxTarget, sessionId);
156
+ }
157
+ else if (tmuxSocket) {
158
+ this.db.prepare(`
159
+ UPDATE sessions SET tmux_socket = ? WHERE id = ?
160
+ `).run(tmuxSocket, sessionId);
161
+ }
162
+ logger.info('Session tmux info set', { sessionId, tmuxTarget, tmuxSocket });
163
+ }
164
+ /**
165
+ * Get session tmux info (target and socket)
166
+ */
167
+ getTmuxInfo(sessionId) {
168
+ const row = this.db.prepare(`
169
+ SELECT tmux_target, tmux_socket FROM sessions WHERE id = ?
170
+ `).get(sessionId);
171
+ return {
172
+ target: row?.tmux_target || null,
173
+ socket: row?.tmux_socket || null
174
+ };
175
+ }
176
+ /**
177
+ * Get session by ID
178
+ */
179
+ getSession(sessionId) {
180
+ const row = this.db.prepare(`
181
+ SELECT * FROM sessions WHERE id = ?
182
+ `).get(sessionId);
183
+ return row ? this.rowToSession(row) : null;
184
+ }
185
+ /**
186
+ * Get session by chat ID (most recent active)
187
+ */
188
+ getSessionByChatId(chatId) {
189
+ const row = this.db.prepare(`
190
+ SELECT * FROM sessions
191
+ WHERE chat_id = ? AND status = 'active'
192
+ ORDER BY last_activity DESC
193
+ LIMIT 1
194
+ `).get(chatId);
195
+ return row ? this.rowToSession(row) : null;
196
+ }
197
+ /**
198
+ * Get session by thread ID (for routing Telegram replies)
199
+ */
200
+ getSessionByThreadId(threadId) {
201
+ const row = this.db.prepare(`
202
+ SELECT * FROM sessions
203
+ WHERE thread_id = ? AND status = 'active'
204
+ LIMIT 1
205
+ `).get(threadId);
206
+ return row ? this.rowToSession(row) : null;
207
+ }
208
+ /**
209
+ * Get all active sessions
210
+ */
211
+ getActiveSessions() {
212
+ const rows = this.db.prepare(`
213
+ SELECT * FROM sessions WHERE status = 'active'
214
+ ORDER BY last_activity DESC
215
+ `).all();
216
+ return rows.map(row => this.rowToSession(row));
217
+ }
218
+ /**
219
+ * Update session activity
220
+ */
221
+ updateActivity(sessionId) {
222
+ this.db.prepare(`
223
+ UPDATE sessions SET last_activity = ? WHERE id = ?
224
+ `).run(new Date().toISOString(), sessionId);
225
+ }
226
+ /**
227
+ * End a session
228
+ */
229
+ endSession(sessionId, status = 'ended') {
230
+ this.db.prepare(`
231
+ UPDATE sessions SET status = ?, last_activity = ? WHERE id = ?
232
+ `).run(status, new Date().toISOString(), sessionId);
233
+ // Expire any pending approvals
234
+ this.db.prepare(`
235
+ UPDATE pending_approvals
236
+ SET status = 'expired'
237
+ WHERE session_id = ? AND status = 'pending'
238
+ `).run(sessionId);
239
+ logger.info('Session ended', { sessionId, status });
240
+ }
241
+ // ============ Approval Methods ============
242
+ /**
243
+ * Create a pending approval
244
+ */
245
+ createApproval(sessionId, prompt, messageId) {
246
+ const id = generateId('approval');
247
+ const now = new Date();
248
+ const expiresAt = new Date(now.getTime() + this.approvalTimeout);
249
+ this.db.prepare(`
250
+ INSERT INTO pending_approvals
251
+ (id, session_id, prompt, created_at, expires_at, status, message_id)
252
+ VALUES (?, ?, ?, ?, ?, 'pending', ?)
253
+ `).run(id, sessionId, prompt, now.toISOString(), expiresAt.toISOString(), messageId || null);
254
+ logger.info('Approval created', { approvalId: id, sessionId });
255
+ return id;
256
+ }
257
+ /**
258
+ * Get approval by ID
259
+ */
260
+ getApproval(approvalId) {
261
+ const row = this.db.prepare(`
262
+ SELECT * FROM pending_approvals WHERE id = ?
263
+ `).get(approvalId);
264
+ return row ? this.rowToApproval(row) : null;
265
+ }
266
+ /**
267
+ * Get pending approvals for a session
268
+ */
269
+ getPendingApprovals(sessionId) {
270
+ const rows = this.db.prepare(`
271
+ SELECT * FROM pending_approvals
272
+ WHERE session_id = ? AND status = 'pending'
273
+ ORDER BY created_at DESC
274
+ `).all(sessionId);
275
+ return rows.map(row => this.rowToApproval(row));
276
+ }
277
+ /**
278
+ * Resolve an approval
279
+ */
280
+ resolveApproval(approvalId, status) {
281
+ const result = this.db.prepare(`
282
+ UPDATE pending_approvals
283
+ SET status = ?
284
+ WHERE id = ? AND status = 'pending'
285
+ `).run(status, approvalId);
286
+ if (result.changes > 0) {
287
+ logger.info('Approval resolved', { approvalId, status });
288
+ return true;
289
+ }
290
+ logger.warn('Approval not found or already resolved', { approvalId });
291
+ return false;
292
+ }
293
+ /**
294
+ * Expire old approvals
295
+ */
296
+ expireOldApprovals() {
297
+ const now = new Date().toISOString();
298
+ const result = this.db.prepare(`
299
+ UPDATE pending_approvals
300
+ SET status = 'expired'
301
+ WHERE status = 'pending' AND expires_at < ?
302
+ `).run(now);
303
+ if (result.changes > 0) {
304
+ logger.info('Expired old approvals', { count: result.changes });
305
+ }
306
+ return result.changes;
307
+ }
308
+ // ============ Cleanup Methods ============
309
+ /**
310
+ * Clean up old sessions
311
+ */
312
+ cleanupOldSessions(maxAgeDays = 7) {
313
+ const cutoff = new Date();
314
+ cutoff.setDate(cutoff.getDate() - maxAgeDays);
315
+ // Delete old approvals first (foreign key)
316
+ this.db.prepare(`
317
+ DELETE FROM pending_approvals
318
+ WHERE session_id IN (
319
+ SELECT id FROM sessions WHERE last_activity < ?
320
+ )
321
+ `).run(cutoff.toISOString());
322
+ // Delete old sessions
323
+ const result = this.db.prepare(`
324
+ DELETE FROM sessions WHERE last_activity < ?
325
+ `).run(cutoff.toISOString());
326
+ if (result.changes > 0) {
327
+ logger.info('Cleaned up old sessions', { count: result.changes });
328
+ }
329
+ return result.changes;
330
+ }
331
+ /**
332
+ * Get database stats
333
+ */
334
+ getStats() {
335
+ const sessions = this.db.prepare(`
336
+ SELECT COUNT(*) as count FROM sessions WHERE status = 'active'
337
+ `).get();
338
+ const approvals = this.db.prepare(`
339
+ SELECT COUNT(*) as count FROM pending_approvals WHERE status = 'pending'
340
+ `).get();
341
+ return {
342
+ activeSessions: sessions.count,
343
+ pendingApprovals: approvals.count
344
+ };
345
+ }
346
+ /**
347
+ * Close database connection
348
+ */
349
+ close() {
350
+ this.db.close();
351
+ logger.info('Session manager closed');
352
+ }
353
+ // ============ Private Helpers ============
354
+ rowToSession(row) {
355
+ return {
356
+ id: row.id,
357
+ chatId: row.chat_id,
358
+ threadId: row.thread_id || undefined,
359
+ hostname: row.hostname || undefined,
360
+ projectDir: row.project_dir || undefined,
361
+ tmuxTarget: row.tmux_target || undefined,
362
+ tmuxSocket: row.tmux_socket || undefined,
363
+ startedAt: new Date(row.started_at),
364
+ lastActivity: new Date(row.last_activity),
365
+ status: row.status,
366
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
367
+ };
368
+ }
369
+ rowToApproval(row) {
370
+ return {
371
+ id: row.id,
372
+ sessionId: row.session_id,
373
+ prompt: row.prompt,
374
+ createdAt: new Date(row.created_at),
375
+ expiresAt: new Date(row.expires_at),
376
+ status: row.status
377
+ };
378
+ }
379
+ }
380
+ export default SessionManager;
381
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/bridge/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Unix Domain Socket Server/Client
3
+ * IPC layer for Claude Code ↔ Telegram bridge
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ import type { BridgeMessage } from './types.js';
7
+ declare const SOCKET_DIR: string;
8
+ declare const DEFAULT_SOCKET_PATH: string;
9
+ declare const DEFAULT_PID_PATH: string;
10
+ /**
11
+ * Check if a socket is stale (file exists but no daemon listening)
12
+ * Returns: 'stale' | 'active' | 'none'
13
+ */
14
+ declare function checkSocketStatus(socketPath: string): Promise<'stale' | 'active' | 'none'>;
15
+ /**
16
+ * Check if a PID is still running
17
+ */
18
+ declare function isPidRunning(pid: number): boolean;
19
+ /**
20
+ * Unix Socket Server
21
+ * Accepts connections from hook scripts and routes messages
22
+ */
23
+ export declare class SocketServer extends EventEmitter {
24
+ private server;
25
+ private clients;
26
+ private socketPath;
27
+ private pidPath;
28
+ private buffer;
29
+ constructor(socketPath?: string, pidPath?: string);
30
+ /**
31
+ * Start listening for connections
32
+ * Includes stale socket detection and PID file locking
33
+ */
34
+ listen(): Promise<void>;
35
+ /**
36
+ * Handle new client connection
37
+ */
38
+ private handleConnection;
39
+ /**
40
+ * Handle incoming data (NDJSON protocol)
41
+ */
42
+ private handleData;
43
+ /**
44
+ * Send message to specific client
45
+ */
46
+ send(clientId: string, message: BridgeMessage): boolean;
47
+ /**
48
+ * Broadcast message to all clients
49
+ */
50
+ broadcast(message: BridgeMessage): void;
51
+ /**
52
+ * Get connected client count
53
+ */
54
+ getClientCount(): number;
55
+ /**
56
+ * Close the server and release all locks
57
+ */
58
+ close(): Promise<void>;
59
+ }
60
+ /**
61
+ * Unix Socket Client
62
+ * Used by hook scripts to send messages to bridge
63
+ */
64
+ export declare class SocketClient extends EventEmitter {
65
+ private socket;
66
+ private socketPath;
67
+ private buffer;
68
+ private reconnectTimer;
69
+ private connected;
70
+ constructor(socketPath?: string);
71
+ /**
72
+ * Connect to the server
73
+ */
74
+ connect(): Promise<void>;
75
+ /**
76
+ * Handle incoming data
77
+ */
78
+ private handleData;
79
+ /**
80
+ * Send message to server
81
+ */
82
+ send(message: BridgeMessage): boolean;
83
+ /**
84
+ * Send message and wait for response
85
+ */
86
+ sendAndWait(message: BridgeMessage, timeout?: number): Promise<BridgeMessage>;
87
+ /**
88
+ * Check if connected
89
+ */
90
+ isConnected(): boolean;
91
+ /**
92
+ * Disconnect from server
93
+ */
94
+ disconnect(): void;
95
+ }
96
+ export { SOCKET_DIR, DEFAULT_SOCKET_PATH, DEFAULT_PID_PATH, checkSocketStatus, isPidRunning };
97
+ //# sourceMappingURL=socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/bridge/socket.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,QAAA,MAAM,UAAU,QAAuD,CAAC;AACxE,QAAA,MAAM,mBAAmB,QAAkC,CAAC;AAC5D,QAAA,MAAM,gBAAgB,QAAiC,CAAC;AAExD;;;GAGG;AACH,iBAAe,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC,CA4BzF;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO1C;AA2CD;;;GAGG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAkC;gBAEpC,UAAU,GAAE,MAA4B,EAAE,OAAO,GAAE,MAAyB;IAMxF;;;OAGG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAwE7B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAoBlB;;OAEG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO;IAgBvD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAavC;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAiCvB;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,SAAS,CAAS;gBAEd,UAAU,GAAE,MAA4B;IAKpD;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAsCxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAkBlB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO;IAerC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,MAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAwBpF;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,UAAU,IAAI,IAAI;CAanB;AAED,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAC"}