trickle-observe 0.2.97 → 0.2.99

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.
@@ -757,7 +757,10 @@ function transformCjsSource(source, filename, moduleName, env, sourceMap) {
757
757
  }
758
758
  }
759
759
  // Also find variable declarations for tracing
760
- const varTraceEnabled = process.env.TRICKLE_TRACE_VARS !== '0';
760
+ // In production mode, disable variable tracing by default
761
+ const isProduction = process.env.TRICKLE_PRODUCTION === '1' || process.env.TRICKLE_PRODUCTION === 'true';
762
+ const varTraceDefault = isProduction ? '0' : '1';
763
+ const varTraceEnabled = (process.env.TRICKLE_TRACE_VARS || varTraceDefault) !== '0';
761
764
  // For TypeScript files (compiled by ts-node/tsc), type declarations (interfaces, type aliases)
762
765
  // are stripped from the compiled JS, shifting line numbers. The only accurate way to get correct
763
766
  // line numbers is to read the original .ts source file and parse it directly.
@@ -885,7 +888,7 @@ function transformCjsSource(source, filename, moduleName, env, sourceMap) {
885
888
  ` module: ${JSON.stringify(effectiveModuleName)},`,
886
889
  ` trackArgs: true,`,
887
890
  ` trackReturn: true,`,
888
- ` sampleRate: 1,`,
891
+ ` sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),`,
889
892
  ` maxDepth: 3,`,
890
893
  ` environment: ${JSON.stringify(env)},`,
891
894
  ` enabled: true,`,
@@ -1166,6 +1169,24 @@ if (enabled) {
1166
1169
  }
1167
1170
  catch { /* not critical */ }
1168
1171
  }
1172
+ // WebSocket (ws)
1173
+ if (request === 'ws' && !expressPatched.has('ws')) {
1174
+ expressPatched.add('ws');
1175
+ try {
1176
+ const { patchWs } = require(path_1.default.join(__dirname, 'ws-observer.js'));
1177
+ patchWs(exports, debug);
1178
+ }
1179
+ catch { /* not critical */ }
1180
+ }
1181
+ // socket.io-client
1182
+ if (request === 'socket.io-client' && !expressPatched.has('socket.io-client')) {
1183
+ expressPatched.add('socket.io-client');
1184
+ try {
1185
+ const { patchSocketIo } = require(path_1.default.join(__dirname, 'ws-observer.js'));
1186
+ patchSocketIo(exports, debug);
1187
+ }
1188
+ catch { /* not critical */ }
1189
+ }
1169
1190
  // Resolve to absolute path for dedup — do this FIRST since bundlers like
1170
1191
  // tsx/esbuild may use path aliases (e.g., @config/env) that don't start
1171
1192
  // with './' or '/'. We need the resolved path to decide if it's user code.
@@ -1235,7 +1256,7 @@ if (enabled) {
1235
1256
  module: moduleName,
1236
1257
  trackArgs: true,
1237
1258
  trackReturn: true,
1238
- sampleRate: 1,
1259
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1239
1260
  maxDepth: 3,
1240
1261
  environment,
1241
1262
  enabled: true,
@@ -1288,7 +1309,7 @@ if (enabled) {
1288
1309
  module: moduleName,
1289
1310
  trackArgs: true,
1290
1311
  trackReturn: true,
1291
- sampleRate: 1,
1312
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1292
1313
  maxDepth: 3,
1293
1314
  environment,
1294
1315
  enabled: true,
@@ -1341,7 +1362,7 @@ if (enabled) {
1341
1362
  module: moduleName,
1342
1363
  trackArgs: true,
1343
1364
  trackReturn: true,
1344
- sampleRate: 1,
1365
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1345
1366
  maxDepth: 3,
1346
1367
  environment,
1347
1368
  enabled: true,
@@ -1374,7 +1395,7 @@ if (enabled) {
1374
1395
  module: moduleName,
1375
1396
  trackArgs: true,
1376
1397
  trackReturn: true,
1377
- sampleRate: 1,
1398
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1378
1399
  maxDepth: 3,
1379
1400
  environment,
1380
1401
  enabled: true,
@@ -0,0 +1,21 @@
1
+ /**
2
+ * WebSocket observer — patches popular WebSocket libraries to capture
3
+ * message events, connection lifecycle, and timing.
4
+ *
5
+ * Supports:
6
+ * - ws (most popular Node.js WebSocket library)
7
+ * - Native WebSocket (browser/Deno/Bun)
8
+ * - socket.io (real-time framework)
9
+ *
10
+ * Written to .trickle/websocket.jsonl as:
11
+ * { "kind": "ws", "event": "message", "direction": "in",
12
+ * "data": "...", "timestamp": 1710516000, "url": "ws://..." }
13
+ */
14
+ /**
15
+ * Patch ws (node WebSocket library) to capture messages.
16
+ */
17
+ export declare function patchWs(wsModule: any, debug: boolean): void;
18
+ /**
19
+ * Patch socket.io client to capture emit/on events.
20
+ */
21
+ export declare function patchSocketIo(ioModule: any, debug: boolean): void;
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ /**
3
+ * WebSocket observer — patches popular WebSocket libraries to capture
4
+ * message events, connection lifecycle, and timing.
5
+ *
6
+ * Supports:
7
+ * - ws (most popular Node.js WebSocket library)
8
+ * - Native WebSocket (browser/Deno/Bun)
9
+ * - socket.io (real-time framework)
10
+ *
11
+ * Written to .trickle/websocket.jsonl as:
12
+ * { "kind": "ws", "event": "message", "direction": "in",
13
+ * "data": "...", "timestamp": 1710516000, "url": "ws://..." }
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.patchWs = patchWs;
50
+ exports.patchSocketIo = patchSocketIo;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ let wsFile = null;
54
+ const MAX_EVENTS = 200;
55
+ let eventCount = 0;
56
+ const MAX_DATA_LENGTH = 500;
57
+ function getWsFile() {
58
+ if (wsFile)
59
+ return wsFile;
60
+ const dir = process.env.TRICKLE_LOCAL_DIR || path.join(process.cwd(), '.trickle');
61
+ try {
62
+ fs.mkdirSync(dir, { recursive: true });
63
+ }
64
+ catch { }
65
+ wsFile = path.join(dir, 'websocket.jsonl');
66
+ try {
67
+ fs.writeFileSync(wsFile, '');
68
+ }
69
+ catch { }
70
+ ;
71
+ return wsFile;
72
+ }
73
+ function writeWsEvent(event) {
74
+ if (eventCount >= MAX_EVENTS)
75
+ return;
76
+ eventCount++;
77
+ try {
78
+ fs.appendFileSync(getWsFile(), JSON.stringify(event) + '\n');
79
+ }
80
+ catch { }
81
+ }
82
+ function truncateData(data) {
83
+ if (data === undefined || data === null)
84
+ return data;
85
+ if (typeof data === 'string') {
86
+ return data.length > MAX_DATA_LENGTH ? data.substring(0, MAX_DATA_LENGTH) + '...' : data;
87
+ }
88
+ if (Buffer.isBuffer(data)) {
89
+ return `<Buffer(${data.length} bytes)>`;
90
+ }
91
+ if (typeof data === 'object') {
92
+ try {
93
+ const s = JSON.stringify(data);
94
+ return s.length > MAX_DATA_LENGTH ? JSON.parse(s.substring(0, MAX_DATA_LENGTH) + '..."}}') : data;
95
+ }
96
+ catch {
97
+ return String(data).substring(0, MAX_DATA_LENGTH);
98
+ }
99
+ }
100
+ return data;
101
+ }
102
+ /**
103
+ * Patch ws (node WebSocket library) to capture messages.
104
+ */
105
+ function patchWs(wsModule, debug) {
106
+ const WsClass = wsModule.WebSocket || wsModule;
107
+ if (!WsClass?.prototype || WsClass.prototype.__trickle_ws_patched)
108
+ return;
109
+ const origSend = WsClass.prototype.send;
110
+ if (origSend) {
111
+ WsClass.prototype.send = function patchedSend(data, ...args) {
112
+ writeWsEvent({
113
+ kind: 'ws',
114
+ event: 'message',
115
+ direction: 'out',
116
+ url: this.url || this._url,
117
+ data: truncateData(data),
118
+ timestamp: Date.now(),
119
+ });
120
+ return origSend.call(this, data, ...args);
121
+ };
122
+ }
123
+ // Patch 'on' to capture incoming messages
124
+ const origOn = WsClass.prototype.on;
125
+ if (origOn) {
126
+ WsClass.prototype.on = function patchedOn(event, listener, ...args) {
127
+ if (event === 'message') {
128
+ const wrappedListener = (data, ...rest) => {
129
+ writeWsEvent({
130
+ kind: 'ws',
131
+ event: 'message',
132
+ direction: 'in',
133
+ url: this.url || this._url,
134
+ data: truncateData(data),
135
+ timestamp: Date.now(),
136
+ });
137
+ return listener(data, ...rest);
138
+ };
139
+ return origOn.call(this, event, wrappedListener, ...args);
140
+ }
141
+ if (event === 'open') {
142
+ const wrappedListener = (...rest) => {
143
+ writeWsEvent({
144
+ kind: 'ws',
145
+ event: 'connect',
146
+ url: this.url || this._url,
147
+ timestamp: Date.now(),
148
+ });
149
+ return listener(...rest);
150
+ };
151
+ return origOn.call(this, event, wrappedListener, ...args);
152
+ }
153
+ if (event === 'close') {
154
+ const wrappedListener = (code, reason, ...rest) => {
155
+ writeWsEvent({
156
+ kind: 'ws',
157
+ event: 'close',
158
+ url: this.url || this._url,
159
+ data: { code, reason: String(reason || '').substring(0, 100) },
160
+ timestamp: Date.now(),
161
+ });
162
+ return listener(code, reason, ...rest);
163
+ };
164
+ return origOn.call(this, event, wrappedListener, ...args);
165
+ }
166
+ return origOn.call(this, event, listener, ...args);
167
+ };
168
+ }
169
+ WsClass.prototype.__trickle_ws_patched = true;
170
+ if (debug)
171
+ console.log('[trickle/ws] WebSocket tracing enabled');
172
+ }
173
+ /**
174
+ * Patch socket.io client to capture emit/on events.
175
+ */
176
+ function patchSocketIo(ioModule, debug) {
177
+ // socket.io-client: the default export is a function that returns a Socket
178
+ const Socket = ioModule.Socket || (ioModule.io && ioModule.io.Socket);
179
+ if (!Socket?.prototype || Socket.prototype.__trickle_sio_patched)
180
+ return;
181
+ const origEmit = Socket.prototype.emit;
182
+ if (origEmit) {
183
+ Socket.prototype.emit = function patchedEmit(event, ...args) {
184
+ if (event !== 'connect' && event !== 'disconnect' && !event.startsWith('__')) {
185
+ writeWsEvent({
186
+ kind: 'ws',
187
+ event: 'emit',
188
+ direction: 'out',
189
+ channel: event,
190
+ data: truncateData(args[0]),
191
+ timestamp: Date.now(),
192
+ });
193
+ }
194
+ return origEmit.call(this, event, ...args);
195
+ };
196
+ }
197
+ const origOn = Socket.prototype.on;
198
+ if (origOn) {
199
+ Socket.prototype.on = function patchedOn(event, listener, ...rest) {
200
+ if (event !== 'connect' && event !== 'disconnect' && !event.startsWith('__')) {
201
+ const wrappedListener = (...args) => {
202
+ writeWsEvent({
203
+ kind: 'ws',
204
+ event: 'emit',
205
+ direction: 'in',
206
+ channel: event,
207
+ data: truncateData(args[0]),
208
+ timestamp: Date.now(),
209
+ });
210
+ return listener(...args);
211
+ };
212
+ return origOn.call(this, event, wrappedListener, ...rest);
213
+ }
214
+ return origOn.call(this, event, listener, ...rest);
215
+ };
216
+ }
217
+ Socket.prototype.__trickle_sio_patched = true;
218
+ if (debug)
219
+ console.log('[trickle/ws] socket.io tracing enabled');
220
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trickle-observe",
3
- "version": "0.2.97",
3
+ "version": "0.2.99",
4
4
  "description": "Runtime type observability for JavaScript applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -717,7 +717,10 @@ function transformCjsSource(source: string, filename: string, moduleName: string
717
717
  }
718
718
 
719
719
  // Also find variable declarations for tracing
720
- const varTraceEnabled = process.env.TRICKLE_TRACE_VARS !== '0';
720
+ // In production mode, disable variable tracing by default
721
+ const isProduction = process.env.TRICKLE_PRODUCTION === '1' || process.env.TRICKLE_PRODUCTION === 'true';
722
+ const varTraceDefault = isProduction ? '0' : '1';
723
+ const varTraceEnabled = (process.env.TRICKLE_TRACE_VARS || varTraceDefault) !== '0';
721
724
 
722
725
  // For TypeScript files (compiled by ts-node/tsc), type declarations (interfaces, type aliases)
723
726
  // are stripped from the compiled JS, shifting line numbers. The only accurate way to get correct
@@ -851,7 +854,7 @@ function transformCjsSource(source: string, filename: string, moduleName: string
851
854
  ` module: ${JSON.stringify(effectiveModuleName)},`,
852
855
  ` trackArgs: true,`,
853
856
  ` trackReturn: true,`,
854
- ` sampleRate: 1,`,
857
+ ` sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),`,
855
858
  ` maxDepth: 3,`,
856
859
  ` environment: ${JSON.stringify(env)},`,
857
860
  ` enabled: true,`,
@@ -1154,6 +1157,24 @@ if (enabled) {
1154
1157
  } catch { /* not critical */ }
1155
1158
  }
1156
1159
 
1160
+ // WebSocket (ws)
1161
+ if (request === 'ws' && !expressPatched.has('ws')) {
1162
+ expressPatched.add('ws');
1163
+ try {
1164
+ const { patchWs } = require(path.join(__dirname, 'ws-observer.js'));
1165
+ patchWs(exports, debug);
1166
+ } catch { /* not critical */ }
1167
+ }
1168
+
1169
+ // socket.io-client
1170
+ if (request === 'socket.io-client' && !expressPatched.has('socket.io-client')) {
1171
+ expressPatched.add('socket.io-client');
1172
+ try {
1173
+ const { patchSocketIo } = require(path.join(__dirname, 'ws-observer.js'));
1174
+ patchSocketIo(exports, debug);
1175
+ } catch { /* not critical */ }
1176
+ }
1177
+
1157
1178
  // Resolve to absolute path for dedup — do this FIRST since bundlers like
1158
1179
  // tsx/esbuild may use path aliases (e.g., @config/env) that don't start
1159
1180
  // with './' or '/'. We need the resolved path to decide if it's user code.
@@ -1217,7 +1238,7 @@ if (enabled) {
1217
1238
  module: moduleName,
1218
1239
  trackArgs: true,
1219
1240
  trackReturn: true,
1220
- sampleRate: 1,
1241
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1221
1242
  maxDepth: 3,
1222
1243
  environment,
1223
1244
  enabled: true,
@@ -1262,7 +1283,7 @@ if (enabled) {
1262
1283
  module: moduleName,
1263
1284
  trackArgs: true,
1264
1285
  trackReturn: true,
1265
- sampleRate: 1,
1286
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1266
1287
  maxDepth: 3,
1267
1288
  environment,
1268
1289
  enabled: true,
@@ -1304,7 +1325,7 @@ if (enabled) {
1304
1325
  module: moduleName,
1305
1326
  trackArgs: true,
1306
1327
  trackReturn: true,
1307
- sampleRate: 1,
1328
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1308
1329
  maxDepth: 3,
1309
1330
  environment,
1310
1331
  enabled: true,
@@ -1335,7 +1356,7 @@ if (enabled) {
1335
1356
  module: moduleName,
1336
1357
  trackArgs: true,
1337
1358
  trackReturn: true,
1338
- sampleRate: 1,
1359
+ sampleRate: parseFloat(process.env.TRICKLE_SAMPLE_RATE || '1'),
1339
1360
  maxDepth: 3,
1340
1361
  environment,
1341
1362
  enabled: true,
@@ -0,0 +1,190 @@
1
+ /**
2
+ * WebSocket observer — patches popular WebSocket libraries to capture
3
+ * message events, connection lifecycle, and timing.
4
+ *
5
+ * Supports:
6
+ * - ws (most popular Node.js WebSocket library)
7
+ * - Native WebSocket (browser/Deno/Bun)
8
+ * - socket.io (real-time framework)
9
+ *
10
+ * Written to .trickle/websocket.jsonl as:
11
+ * { "kind": "ws", "event": "message", "direction": "in",
12
+ * "data": "...", "timestamp": 1710516000, "url": "ws://..." }
13
+ */
14
+
15
+ import * as fs from 'fs';
16
+ import * as path from 'path';
17
+
18
+ interface WsEvent {
19
+ kind: 'ws';
20
+ event: 'connect' | 'message' | 'close' | 'error' | 'emit';
21
+ direction?: 'in' | 'out';
22
+ url?: string;
23
+ data?: unknown;
24
+ channel?: string;
25
+ timestamp: number;
26
+ }
27
+
28
+ let wsFile: string | null = null;
29
+ const MAX_EVENTS = 200;
30
+ let eventCount = 0;
31
+ const MAX_DATA_LENGTH = 500;
32
+
33
+ function getWsFile(): string {
34
+ if (wsFile) return wsFile;
35
+ const dir = process.env.TRICKLE_LOCAL_DIR || path.join(process.cwd(), '.trickle');
36
+ try { fs.mkdirSync(dir, { recursive: true }); } catch {}
37
+ wsFile = path.join(dir, 'websocket.jsonl');
38
+ try { fs.writeFileSync(wsFile, ''); } catch {};
39
+ return wsFile;
40
+ }
41
+
42
+ function writeWsEvent(event: WsEvent): void {
43
+ if (eventCount >= MAX_EVENTS) return;
44
+ eventCount++;
45
+ try {
46
+ fs.appendFileSync(getWsFile(), JSON.stringify(event) + '\n');
47
+ } catch {}
48
+ }
49
+
50
+ function truncateData(data: unknown): unknown {
51
+ if (data === undefined || data === null) return data;
52
+ if (typeof data === 'string') {
53
+ return data.length > MAX_DATA_LENGTH ? data.substring(0, MAX_DATA_LENGTH) + '...' : data;
54
+ }
55
+ if (Buffer.isBuffer(data)) {
56
+ return `<Buffer(${data.length} bytes)>`;
57
+ }
58
+ if (typeof data === 'object') {
59
+ try {
60
+ const s = JSON.stringify(data);
61
+ return s.length > MAX_DATA_LENGTH ? JSON.parse(s.substring(0, MAX_DATA_LENGTH) + '..."}}') : data;
62
+ } catch {
63
+ return String(data).substring(0, MAX_DATA_LENGTH);
64
+ }
65
+ }
66
+ return data;
67
+ }
68
+
69
+ /**
70
+ * Patch ws (node WebSocket library) to capture messages.
71
+ */
72
+ export function patchWs(wsModule: any, debug: boolean): void {
73
+ const WsClass = wsModule.WebSocket || wsModule;
74
+ if (!WsClass?.prototype || (WsClass.prototype as any).__trickle_ws_patched) return;
75
+
76
+ const origSend = WsClass.prototype.send;
77
+ if (origSend) {
78
+ WsClass.prototype.send = function patchedSend(data: any, ...args: any[]) {
79
+ writeWsEvent({
80
+ kind: 'ws',
81
+ event: 'message',
82
+ direction: 'out',
83
+ url: this.url || this._url,
84
+ data: truncateData(data),
85
+ timestamp: Date.now(),
86
+ });
87
+ return origSend.call(this, data, ...args);
88
+ };
89
+ }
90
+
91
+ // Patch 'on' to capture incoming messages
92
+ const origOn = WsClass.prototype.on;
93
+ if (origOn) {
94
+ WsClass.prototype.on = function patchedOn(event: string, listener: any, ...args: any[]) {
95
+ if (event === 'message') {
96
+ const wrappedListener = (data: any, ...rest: any[]) => {
97
+ writeWsEvent({
98
+ kind: 'ws',
99
+ event: 'message',
100
+ direction: 'in',
101
+ url: this.url || this._url,
102
+ data: truncateData(data),
103
+ timestamp: Date.now(),
104
+ });
105
+ return listener(data, ...rest);
106
+ };
107
+ return origOn.call(this, event, wrappedListener, ...args);
108
+ }
109
+ if (event === 'open') {
110
+ const wrappedListener = (...rest: any[]) => {
111
+ writeWsEvent({
112
+ kind: 'ws',
113
+ event: 'connect',
114
+ url: this.url || this._url,
115
+ timestamp: Date.now(),
116
+ });
117
+ return listener(...rest);
118
+ };
119
+ return origOn.call(this, event, wrappedListener, ...args);
120
+ }
121
+ if (event === 'close') {
122
+ const wrappedListener = (code: number, reason: string, ...rest: any[]) => {
123
+ writeWsEvent({
124
+ kind: 'ws',
125
+ event: 'close',
126
+ url: this.url || this._url,
127
+ data: { code, reason: String(reason || '').substring(0, 100) },
128
+ timestamp: Date.now(),
129
+ });
130
+ return listener(code, reason, ...rest);
131
+ };
132
+ return origOn.call(this, event, wrappedListener, ...args);
133
+ }
134
+ return origOn.call(this, event, listener, ...args);
135
+ };
136
+ }
137
+
138
+ (WsClass.prototype as any).__trickle_ws_patched = true;
139
+ if (debug) console.log('[trickle/ws] WebSocket tracing enabled');
140
+ }
141
+
142
+ /**
143
+ * Patch socket.io client to capture emit/on events.
144
+ */
145
+ export function patchSocketIo(ioModule: any, debug: boolean): void {
146
+ // socket.io-client: the default export is a function that returns a Socket
147
+ const Socket = ioModule.Socket || (ioModule.io && ioModule.io.Socket);
148
+ if (!Socket?.prototype || (Socket.prototype as any).__trickle_sio_patched) return;
149
+
150
+ const origEmit = Socket.prototype.emit;
151
+ if (origEmit) {
152
+ Socket.prototype.emit = function patchedEmit(event: string, ...args: any[]) {
153
+ if (event !== 'connect' && event !== 'disconnect' && !event.startsWith('__')) {
154
+ writeWsEvent({
155
+ kind: 'ws',
156
+ event: 'emit',
157
+ direction: 'out',
158
+ channel: event,
159
+ data: truncateData(args[0]),
160
+ timestamp: Date.now(),
161
+ });
162
+ }
163
+ return origEmit.call(this, event, ...args);
164
+ };
165
+ }
166
+
167
+ const origOn = Socket.prototype.on;
168
+ if (origOn) {
169
+ Socket.prototype.on = function patchedOn(event: string, listener: any, ...rest: any[]) {
170
+ if (event !== 'connect' && event !== 'disconnect' && !event.startsWith('__')) {
171
+ const wrappedListener = (...args: any[]) => {
172
+ writeWsEvent({
173
+ kind: 'ws',
174
+ event: 'emit',
175
+ direction: 'in',
176
+ channel: event,
177
+ data: truncateData(args[0]),
178
+ timestamp: Date.now(),
179
+ });
180
+ return listener(...args);
181
+ };
182
+ return origOn.call(this, event, wrappedListener, ...rest);
183
+ }
184
+ return origOn.call(this, event, listener, ...rest);
185
+ };
186
+ }
187
+
188
+ (Socket.prototype as any).__trickle_sio_patched = true;
189
+ if (debug) console.log('[trickle/ws] socket.io tracing enabled');
190
+ }