test-proxy-recorder 0.1.8 → 0.1.10
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 +2 -2
- package/dist/{index-CBjvm5rb.d.cts → index-CjM3evKb.d.cts} +1 -1
- package/dist/{index-CBjvm5rb.d.ts → index-CjM3evKb.d.ts} +1 -1
- package/dist/index.cjs +184 -81
- package/dist/index.d.cts +16 -3
- package/dist/index.d.ts +16 -3
- package/dist/index.mjs +183 -81
- package/dist/playwright/index.d.cts +1 -1
- package/dist/playwright/index.d.ts +1 -1
- package/dist/proxy.js +183 -81
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import https from 'https';
|
|
|
4
4
|
import httpProxy from 'http-proxy';
|
|
5
5
|
import { WebSocket, WebSocketServer } from 'ws';
|
|
6
6
|
import path from 'path';
|
|
7
|
+
import crypto from 'crypto';
|
|
7
8
|
import filenamify from 'filenamify';
|
|
8
9
|
|
|
9
10
|
// src/ProxyServer.ts
|
|
@@ -42,7 +43,6 @@ async function saveRecordingSession(recordingsDir, session) {
|
|
|
42
43
|
`Saved ${session.recordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
|
-
var QUERY_HASH_LENGTH = 8;
|
|
46
46
|
function getReqID(req) {
|
|
47
47
|
const urlParts = req.url.split("?");
|
|
48
48
|
const pathname = urlParts[0];
|
|
@@ -57,7 +57,7 @@ function generateQueryHash(query) {
|
|
|
57
57
|
if (!query) {
|
|
58
58
|
return "";
|
|
59
59
|
}
|
|
60
|
-
const hash =
|
|
60
|
+
const hash = crypto.createHash("md5").update(query).digest("hex").slice(0, 16);
|
|
61
61
|
return `_${hash}`;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -86,24 +86,25 @@ var ProxyServer = class {
|
|
|
86
86
|
proxy;
|
|
87
87
|
currentSession;
|
|
88
88
|
recordingsDir;
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
// Track replay
|
|
89
|
+
recordingIdCounter;
|
|
90
|
+
// Unique ID for each recording entry
|
|
91
|
+
replaySessions;
|
|
92
|
+
// Track multiple concurrent replay sessions by recording ID
|
|
93
93
|
constructor(targets, recordingsDir) {
|
|
94
94
|
this.targets = targets;
|
|
95
95
|
this.currentTargetIndex = 0;
|
|
96
96
|
this.mode = Modes.transparent;
|
|
97
97
|
this.recordingId = null;
|
|
98
|
+
this.recordingIdCounter = 0;
|
|
98
99
|
this.replayId = null;
|
|
99
100
|
this.modeTimeout = null;
|
|
100
101
|
this.currentSession = null;
|
|
101
102
|
this.recordingsDir = recordingsDir;
|
|
102
|
-
this.
|
|
103
|
-
this.replaySequenceMap = /* @__PURE__ */ new Map();
|
|
103
|
+
this.replaySessions = /* @__PURE__ */ new Map();
|
|
104
104
|
this.proxy = httpProxy.createProxyServer({
|
|
105
105
|
secure: false,
|
|
106
|
-
changeOrigin: true
|
|
106
|
+
changeOrigin: true,
|
|
107
|
+
ws: true
|
|
107
108
|
});
|
|
108
109
|
this.setupProxyEventHandlers();
|
|
109
110
|
}
|
|
@@ -171,6 +172,43 @@ var ProxyServer = class {
|
|
|
171
172
|
this.currentTargetIndex = (this.currentTargetIndex + 1) % this.targets.length;
|
|
172
173
|
return target;
|
|
173
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Extract recording ID from request cookie
|
|
177
|
+
* Used for concurrent replay session routing
|
|
178
|
+
* @param req The incoming HTTP request
|
|
179
|
+
* @returns The recording ID from cookie, or null if not found
|
|
180
|
+
*/
|
|
181
|
+
getRecordingIdFromCookie(req) {
|
|
182
|
+
const cookies = req.headers.cookie;
|
|
183
|
+
if (!cookies) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const match = cookies.match(/proxy-recording-id=([^;]+)/);
|
|
187
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get or create a replay session state for a given recording ID
|
|
191
|
+
* @param recordingId The recording ID to get/create session for
|
|
192
|
+
* @returns The replay session state
|
|
193
|
+
*/
|
|
194
|
+
getOrCreateReplaySession(recordingId) {
|
|
195
|
+
let session = this.replaySessions.get(recordingId);
|
|
196
|
+
if (session) {
|
|
197
|
+
session.lastAccessTime = Date.now();
|
|
198
|
+
} else {
|
|
199
|
+
session = {
|
|
200
|
+
recordingId,
|
|
201
|
+
servedRecordingIdsByKey: /* @__PURE__ */ new Map(),
|
|
202
|
+
loadedSession: null,
|
|
203
|
+
lastAccessTime: Date.now()
|
|
204
|
+
};
|
|
205
|
+
this.replaySessions.set(recordingId, session);
|
|
206
|
+
console.log(
|
|
207
|
+
`[CONCURRENT REPLAY] Created new session for recording: ${recordingId}`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
return session;
|
|
211
|
+
}
|
|
174
212
|
parseGetParams(req) {
|
|
175
213
|
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
176
214
|
const mode = url.searchParams.get("mode");
|
|
@@ -187,16 +225,25 @@ var ProxyServer = class {
|
|
|
187
225
|
let data;
|
|
188
226
|
if (req.method === "GET") {
|
|
189
227
|
data = this.parseGetParams(req);
|
|
190
|
-
} else {
|
|
228
|
+
} else if (req.method === "POST") {
|
|
191
229
|
const body = await readRequestBody(req);
|
|
192
|
-
console.log(
|
|
230
|
+
console.log(`MODE CHANGE (${req.method})`, body);
|
|
193
231
|
data = JSON.parse(body);
|
|
232
|
+
} else {
|
|
233
|
+
return;
|
|
194
234
|
}
|
|
195
235
|
const { mode, id, timeout: requestTimeout } = data;
|
|
196
236
|
const timeout = requestTimeout ?? DEFAULT_TIMEOUT_MS;
|
|
197
237
|
this.clearModeTimeout();
|
|
198
238
|
await this.switchMode(mode, id);
|
|
199
239
|
this.setupModeTimeout(timeout);
|
|
240
|
+
if (mode === Modes.replay && id) {
|
|
241
|
+
res.setHeader(
|
|
242
|
+
"Set-Cookie",
|
|
243
|
+
`proxy-recording-id=${encodeURIComponent(id)}; HttpOnly; Path=/; SameSite=Lax`
|
|
244
|
+
);
|
|
245
|
+
console.log(`[CONCURRENT REPLAY] Set cookie for recording: ${id}`);
|
|
246
|
+
}
|
|
200
247
|
sendJsonResponse(res, HTTP_STATUS_OK, {
|
|
201
248
|
success: true,
|
|
202
249
|
mode: this.mode,
|
|
@@ -211,14 +258,12 @@ var ProxyServer = class {
|
|
|
211
258
|
}
|
|
212
259
|
}
|
|
213
260
|
clearModeTimeout() {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.modeTimeout = null;
|
|
217
|
-
}
|
|
261
|
+
clearTimeout(this.modeTimeout || 0);
|
|
262
|
+
this.modeTimeout = null;
|
|
218
263
|
}
|
|
219
264
|
async switchMode(mode, id) {
|
|
220
|
-
|
|
221
|
-
|
|
265
|
+
console.log(`Switching to ${mode.toUpperCase()} mode`);
|
|
266
|
+
if (this.currentSession && this.mode === Modes.record) {
|
|
222
267
|
await this.saveCurrentSession(true);
|
|
223
268
|
console.log("Session saved, continuing with mode switch");
|
|
224
269
|
}
|
|
@@ -228,11 +273,17 @@ var ProxyServer = class {
|
|
|
228
273
|
break;
|
|
229
274
|
}
|
|
230
275
|
case Modes.record: {
|
|
276
|
+
if (!id) {
|
|
277
|
+
throw new Error("Record ID is required");
|
|
278
|
+
}
|
|
231
279
|
this.switchToRecordMode(id);
|
|
232
280
|
break;
|
|
233
281
|
}
|
|
234
282
|
case Modes.replay: {
|
|
235
|
-
|
|
283
|
+
if (!id) {
|
|
284
|
+
throw new Error("Replay ID is required");
|
|
285
|
+
}
|
|
286
|
+
await this.switchToReplayMode(id);
|
|
236
287
|
break;
|
|
237
288
|
}
|
|
238
289
|
default: {
|
|
@@ -249,36 +300,33 @@ var ProxyServer = class {
|
|
|
249
300
|
console.log("Switched to transparent mode");
|
|
250
301
|
}
|
|
251
302
|
switchToRecordMode(id) {
|
|
252
|
-
if (!id) {
|
|
253
|
-
throw new Error("Record ID is required");
|
|
254
|
-
}
|
|
255
303
|
this.mode = Modes.record;
|
|
256
304
|
this.recordingId = id;
|
|
257
305
|
this.replayId = null;
|
|
258
306
|
this.currentSession = { id, recordings: [], websocketRecordings: [] };
|
|
259
|
-
this.requestSequenceMap.clear();
|
|
260
307
|
console.log(`Switched to record mode with ID: ${id}`);
|
|
261
308
|
}
|
|
262
|
-
switchToReplayMode(id) {
|
|
263
|
-
if (!id) {
|
|
264
|
-
throw new Error("Replay ID is required");
|
|
265
|
-
}
|
|
309
|
+
async switchToReplayMode(id) {
|
|
266
310
|
this.mode = Modes.replay;
|
|
267
311
|
this.replayId = id;
|
|
268
312
|
this.recordingId = null;
|
|
269
313
|
this.currentSession = null;
|
|
270
|
-
this.
|
|
314
|
+
const session = this.replaySessions.get(id);
|
|
315
|
+
if (session) {
|
|
316
|
+
session.servedRecordingIdsByKey.clear();
|
|
317
|
+
console.log(`Reset served recordings tracker for session: ${id}`);
|
|
318
|
+
} else {
|
|
319
|
+
this.getOrCreateReplaySession(id);
|
|
320
|
+
}
|
|
271
321
|
console.log(`Switched to replay mode with ID: ${id}`);
|
|
272
322
|
}
|
|
273
323
|
setupModeTimeout(timeout) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}, timeout);
|
|
281
|
-
}
|
|
324
|
+
this.modeTimeout = setTimeout(async () => {
|
|
325
|
+
console.log("Timeout reached, switching back to transparent mode");
|
|
326
|
+
await this.saveCurrentSession(true);
|
|
327
|
+
this.switchToTransparentMode();
|
|
328
|
+
this.modeTimeout = null;
|
|
329
|
+
}, timeout);
|
|
282
330
|
}
|
|
283
331
|
async saveCurrentSession(filterIncomplete = false) {
|
|
284
332
|
if (!this.currentSession) {
|
|
@@ -304,6 +352,8 @@ var ProxyServer = class {
|
|
|
304
352
|
return;
|
|
305
353
|
}
|
|
306
354
|
const key = getReqID(req);
|
|
355
|
+
const recordingId = this.recordingIdCounter++;
|
|
356
|
+
req.__recordingId = recordingId;
|
|
307
357
|
const record = {
|
|
308
358
|
request: {
|
|
309
359
|
method: req.method,
|
|
@@ -313,44 +363,57 @@ var ProxyServer = class {
|
|
|
313
363
|
},
|
|
314
364
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
315
365
|
key,
|
|
316
|
-
|
|
317
|
-
// Temporary, will be set when response arrives
|
|
366
|
+
recordingId
|
|
318
367
|
};
|
|
319
368
|
this.currentSession.recordings.push(record);
|
|
320
369
|
console.log(
|
|
321
370
|
// eslint-disable-next-line sonarjs/no-nested-template-literals
|
|
322
|
-
`saveRequestRecordSync: Saved ${req.method} ${req.url} (key: ${key}, body: ${body ? `${body.length} chars` : "null"}, total: ${this.currentSession.recordings.length}, sessionId: ${this.currentSession.id})`
|
|
371
|
+
`saveRequestRecordSync: Saved ${req.method} ${req.url} (key: ${key}, recordingId: ${recordingId}, body: ${body ? `${body.length} chars` : "null"}, total: ${this.currentSession.recordings.length}, sessionId: ${this.currentSession.id})`
|
|
323
372
|
);
|
|
324
373
|
}
|
|
325
374
|
updateRequestBodySync(req, body) {
|
|
326
375
|
if (!this.currentSession) {
|
|
327
376
|
return;
|
|
328
377
|
}
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
(
|
|
378
|
+
const recordingId = req.__recordingId;
|
|
379
|
+
if (recordingId === void 0) {
|
|
380
|
+
console.error(
|
|
381
|
+
`updateRequestBodySync: No recording ID found on request ${req.method} ${req.url}`
|
|
382
|
+
);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const record = this.currentSession.recordings.find(
|
|
386
|
+
(r) => r.recordingId === recordingId
|
|
332
387
|
);
|
|
333
388
|
if (!record) {
|
|
334
389
|
console.error(
|
|
335
|
-
`updateRequestBodySync: Could not find
|
|
390
|
+
`updateRequestBodySync: Could not find recording with ID ${recordingId} for ${req.method} ${req.url}`
|
|
336
391
|
);
|
|
337
392
|
return;
|
|
338
393
|
}
|
|
339
394
|
record.request.body = body || null;
|
|
340
395
|
console.log(
|
|
341
|
-
`updateRequestBodySync: Updated body for ${req.method} ${req.url} (${body.length} chars)`
|
|
396
|
+
`updateRequestBodySync: Updated body for ${req.method} ${req.url} (${body.length} chars, recordingId: ${recordingId})`
|
|
342
397
|
);
|
|
343
398
|
}
|
|
344
399
|
async recordResponse(req, proxyRes) {
|
|
345
400
|
if (!this.currentSession) {
|
|
346
401
|
return;
|
|
347
402
|
}
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
(
|
|
403
|
+
const recordingId = req.__recordingId;
|
|
404
|
+
if (recordingId === void 0) {
|
|
405
|
+
console.error(
|
|
406
|
+
`recordResponse: No recording ID found on request ${req.method} ${req.url}`
|
|
407
|
+
);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const record = this.currentSession.recordings.find(
|
|
411
|
+
(r) => r.recordingId === recordingId
|
|
351
412
|
);
|
|
352
413
|
if (!record) {
|
|
353
|
-
console.error(
|
|
414
|
+
console.error(
|
|
415
|
+
`recordResponse: Could not find recording with ID ${recordingId} for ${req.method} ${req.url}`
|
|
416
|
+
);
|
|
354
417
|
return;
|
|
355
418
|
}
|
|
356
419
|
const chunks = [];
|
|
@@ -364,34 +427,28 @@ var ProxyServer = class {
|
|
|
364
427
|
headers: proxyRes.headers,
|
|
365
428
|
body: body || null
|
|
366
429
|
};
|
|
367
|
-
console.log(
|
|
430
|
+
console.log(
|
|
431
|
+
`Recorded: ${req.method} ${req.url} (recordingId: ${recordingId})`
|
|
432
|
+
);
|
|
368
433
|
});
|
|
369
434
|
}
|
|
370
435
|
async recordResponseData(req, proxyRes, body) {
|
|
371
436
|
if (!this.currentSession) {
|
|
372
437
|
return false;
|
|
373
438
|
}
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
(r) => r.key === key && !r.response
|
|
377
|
-
);
|
|
378
|
-
if (!record) {
|
|
379
|
-
const host = req.headers.host || "unknown";
|
|
380
|
-
const recordsWithKey = this.currentSession.recordings.filter(
|
|
381
|
-
(r) => r.key === key
|
|
382
|
-
);
|
|
439
|
+
const recordingId = req.__recordingId;
|
|
440
|
+
if (recordingId === void 0) {
|
|
383
441
|
console.error(
|
|
384
|
-
`
|
|
385
|
-
);
|
|
386
|
-
console.error(
|
|
387
|
-
` Total recordings: ${this.currentSession.recordings.length}, with this key: ${recordsWithKey.length}`
|
|
442
|
+
`recordResponseData: No recording ID found on request ${req.method} ${req.url}`
|
|
388
443
|
);
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
const record = this.currentSession.recordings.find(
|
|
447
|
+
(r) => r.recordingId === recordingId
|
|
448
|
+
);
|
|
449
|
+
if (!record) {
|
|
389
450
|
console.error(
|
|
390
|
-
`
|
|
391
|
-
recordsWithKey.map((r) => ({
|
|
392
|
-
seq: r.sequence,
|
|
393
|
-
hasResponse: !!r.response
|
|
394
|
-
}))
|
|
451
|
+
`recordResponseData: Could not find recording with ID ${recordingId} for ${req.method} ${req.url}`
|
|
395
452
|
);
|
|
396
453
|
return false;
|
|
397
454
|
}
|
|
@@ -400,34 +457,78 @@ var ProxyServer = class {
|
|
|
400
457
|
headers: proxyRes.headers,
|
|
401
458
|
body: body || null
|
|
402
459
|
};
|
|
403
|
-
record.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
404
|
-
const currentSequence = this.requestSequenceMap.get(key) || 0;
|
|
405
|
-
record.sequence = currentSequence;
|
|
406
|
-
this.requestSequenceMap.set(key, currentSequence + 1);
|
|
407
460
|
console.log(
|
|
408
|
-
`recordResponseData: Recorded response for ${req.method} ${req.url} (
|
|
461
|
+
`recordResponseData: Recorded response for ${req.method} ${req.url} (recordingId: ${recordingId})`
|
|
409
462
|
);
|
|
410
463
|
return true;
|
|
411
464
|
}
|
|
412
465
|
async handleReplayRequest(req, res) {
|
|
466
|
+
const recordingId = this.getRecordingIdFromCookie(req) || this.replayId;
|
|
467
|
+
if (!recordingId) {
|
|
468
|
+
const corsHeaders = this.getCorsHeaders(req);
|
|
469
|
+
res.writeHead(HTTP_STATUS_BAD_REQUEST, {
|
|
470
|
+
"Content-Type": "application/json",
|
|
471
|
+
...corsHeaders
|
|
472
|
+
});
|
|
473
|
+
res.end(JSON.stringify({ error: "No replay session active" }));
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
413
476
|
const key = getReqID(req);
|
|
414
|
-
const filePath = getRecordingPath(this.recordingsDir,
|
|
477
|
+
const filePath = getRecordingPath(this.recordingsDir, recordingId);
|
|
415
478
|
try {
|
|
416
|
-
const
|
|
479
|
+
const sessionState = this.getOrCreateReplaySession(recordingId);
|
|
480
|
+
if (!sessionState.loadedSession) {
|
|
481
|
+
sessionState.loadedSession = await loadRecordingSession(filePath);
|
|
482
|
+
console.log(`[REPLAY] Loaded recording session: ${recordingId}`);
|
|
483
|
+
}
|
|
484
|
+
const session = sessionState.loadedSession;
|
|
485
|
+
if (!sessionState.servedRecordingIdsByKey.has(key)) {
|
|
486
|
+
sessionState.servedRecordingIdsByKey.set(key, /* @__PURE__ */ new Set());
|
|
487
|
+
}
|
|
488
|
+
const servedForThisKey = sessionState.servedRecordingIdsByKey.get(key);
|
|
417
489
|
const host = req.headers.host || "unknown";
|
|
418
|
-
const recordsWithKey = session.recordings.filter((r) => r.key === key && r.response).toSorted((a, b) => a.
|
|
490
|
+
const recordsWithKey = session.recordings.filter((r) => r.key === key && r.response).toSorted((a, b) => a.recordingId - b.recordingId);
|
|
419
491
|
if (recordsWithKey.length === 0) {
|
|
420
|
-
|
|
421
|
-
|
|
492
|
+
const errorMsg = `No recording found for ${key} at ${req.method} ${host}${req.url}`;
|
|
493
|
+
console.error(`[REPLAY ERROR] ${errorMsg} (session: ${recordingId})`);
|
|
494
|
+
console.error(
|
|
495
|
+
`[REPLAY ERROR] This request was not made during recording - possible test non-determinism`
|
|
496
|
+
);
|
|
497
|
+
const errorResponse = {
|
|
498
|
+
error: "No recording found",
|
|
499
|
+
message: errorMsg,
|
|
500
|
+
key,
|
|
501
|
+
sessionId: recordingId
|
|
502
|
+
};
|
|
503
|
+
const corsHeaders = this.getCorsHeaders(req);
|
|
504
|
+
res.writeHead(HTTP_STATUS_NOT_FOUND, {
|
|
505
|
+
"Content-Type": "application/json",
|
|
506
|
+
...corsHeaders
|
|
507
|
+
});
|
|
508
|
+
res.end(JSON.stringify(errorResponse));
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const requestCount = servedForThisKey.size + 1;
|
|
512
|
+
console.log(
|
|
513
|
+
`[REPLAY REQUEST #${requestCount}] ${req.method} ${req.url} (session: ${recordingId}, total: ${recordsWithKey.length}, served: ${servedForThisKey.size})`
|
|
514
|
+
);
|
|
515
|
+
let record;
|
|
516
|
+
for (const rec of recordsWithKey) {
|
|
517
|
+
if (!servedForThisKey.has(rec.recordingId)) {
|
|
518
|
+
record = rec;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (!record) {
|
|
523
|
+
console.log(
|
|
524
|
+
`[REPLAY WARNING] All ${recordsWithKey.length} recordings already served for ${key} (session: ${recordingId}), reusing last one`
|
|
422
525
|
);
|
|
526
|
+
record = recordsWithKey[recordsWithKey.length - 1];
|
|
423
527
|
}
|
|
424
|
-
|
|
425
|
-
const recordIndex = usageCount % recordsWithKey.length;
|
|
426
|
-
const record = recordsWithKey[recordIndex];
|
|
528
|
+
servedForThisKey.add(record.recordingId);
|
|
427
529
|
console.log(
|
|
428
|
-
`
|
|
530
|
+
`[REPLAY SERVING] recordingId: ${record.recordingId}, session: ${recordingId}, body_len: ${record.response?.body?.length || 0}`
|
|
429
531
|
);
|
|
430
|
-
this.replaySequenceMap.set(key, usageCount + 1);
|
|
431
532
|
if (!record.response) {
|
|
432
533
|
throw new Error(
|
|
433
534
|
`No response recorded for this request: ${req.method} ${host}${req.url}`
|
|
@@ -493,6 +594,7 @@ var ProxyServer = class {
|
|
|
493
594
|
this.proxy.web(req, res, { target });
|
|
494
595
|
}
|
|
495
596
|
}
|
|
597
|
+
// TODO: check if can handle streaming requests
|
|
496
598
|
async bufferAndProxyRequest(req, res, target) {
|
|
497
599
|
const chunks = [];
|
|
498
600
|
req.on("data", (chunk) => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import '@playwright/test';
|
|
2
|
-
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-
|
|
2
|
+
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-CjM3evKb.cjs';
|
|
3
3
|
import 'node:http';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import '@playwright/test';
|
|
2
|
-
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-
|
|
2
|
+
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-CjM3evKb.js';
|
|
3
3
|
import 'node:http';
|