test-proxy-recorder 0.3.1 → 0.3.2
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 +142 -17
- package/dist/{index-CVuiglPk.d.cts → index-BlBWqSE4.d.cts} +21 -4
- package/dist/{index-CVuiglPk.d.ts → index-BlBWqSE4.d.ts} +21 -4
- package/dist/index.cjs +234 -26
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.mjs +233 -25
- package/dist/playwright/index.cjs +151 -13
- package/dist/playwright/index.d.cts +1 -1
- package/dist/playwright/index.d.ts +1 -1
- package/dist/playwright/index.mjs +147 -14
- package/dist/proxy.js +88 -9
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ var https = require('https');
|
|
|
6
6
|
var httpProxy = require('http-proxy');
|
|
7
7
|
var ws = require('ws');
|
|
8
8
|
var crypto = require('crypto');
|
|
9
|
-
var
|
|
9
|
+
var path2 = require('path');
|
|
10
10
|
var filenamify2 = require('filenamify');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -16,7 +16,7 @@ var http__default = /*#__PURE__*/_interopDefault(http);
|
|
|
16
16
|
var https__default = /*#__PURE__*/_interopDefault(https);
|
|
17
17
|
var httpProxy__default = /*#__PURE__*/_interopDefault(httpProxy);
|
|
18
18
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
19
|
-
var
|
|
19
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
20
20
|
var filenamify2__default = /*#__PURE__*/_interopDefault(filenamify2);
|
|
21
21
|
|
|
22
22
|
// src/constants.ts
|
|
@@ -53,7 +53,7 @@ function getRecordingPath(recordingsDir, id) {
|
|
|
53
53
|
maxLength: 255
|
|
54
54
|
// Set explicit max to prevent filenamify's default truncation
|
|
55
55
|
});
|
|
56
|
-
return
|
|
56
|
+
return path2__default.default.join(recordingsDir, `${sanitizedId}${EXTENSION}`);
|
|
57
57
|
}
|
|
58
58
|
async function loadRecordingSession(filePath) {
|
|
59
59
|
const fileContent = await fs__default.default.readFile(filePath, "utf8");
|
|
@@ -94,16 +94,19 @@ async function saveRecordingSession(recordingsDir, session) {
|
|
|
94
94
|
`Saved ${processedRecordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
|
-
function
|
|
98
|
-
const urlParts = req.url.split("?");
|
|
99
|
-
const pathname = urlParts[0];
|
|
100
|
-
const query = urlParts[1] || "";
|
|
97
|
+
function generateRecordingKey(pathname, query, method) {
|
|
101
98
|
const pathPart = pathname === "/" ? "root" : pathname.slice(1);
|
|
102
99
|
const normalizedPath = filenamify2__default.default(pathPart, { replacement: "_" });
|
|
103
100
|
const queryHash = generateQueryHash(query);
|
|
104
|
-
const filename = `${
|
|
101
|
+
const filename = `${method}_${normalizedPath}${queryHash}.json`;
|
|
105
102
|
return filenamify2__default.default(filename, { replacement: "_" });
|
|
106
103
|
}
|
|
104
|
+
function getReqID(req) {
|
|
105
|
+
const urlParts = req.url.split("?");
|
|
106
|
+
const pathname = urlParts[0];
|
|
107
|
+
const query = urlParts[1] || "";
|
|
108
|
+
return generateRecordingKey(pathname, query, req.method);
|
|
109
|
+
}
|
|
107
110
|
function generateQueryHash(query) {
|
|
108
111
|
if (!query) {
|
|
109
112
|
return "";
|
|
@@ -256,7 +259,15 @@ var ProxyServer = class {
|
|
|
256
259
|
* @returns The recording ID, or null if not found
|
|
257
260
|
*/
|
|
258
261
|
getRecordingIdFromRequest(req) {
|
|
259
|
-
|
|
262
|
+
const fromHeader = this.getRecordingIdFromHeader(req);
|
|
263
|
+
const fromCookie = this.getRecordingIdFromCookie(req);
|
|
264
|
+
if (fromHeader) {
|
|
265
|
+
return fromHeader;
|
|
266
|
+
}
|
|
267
|
+
if (fromCookie) {
|
|
268
|
+
return fromCookie;
|
|
269
|
+
}
|
|
270
|
+
return null;
|
|
260
271
|
}
|
|
261
272
|
/**
|
|
262
273
|
* Get or create a replay session state for a given recording ID
|
|
@@ -281,6 +292,27 @@ var ProxyServer = class {
|
|
|
281
292
|
}
|
|
282
293
|
return session;
|
|
283
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Clean up a session - removes it from memory and resets counters
|
|
297
|
+
* @param sessionId The session ID to clean up
|
|
298
|
+
*/
|
|
299
|
+
async cleanupSession(sessionId) {
|
|
300
|
+
if (this.replaySessions.has(sessionId)) {
|
|
301
|
+
console.log(`[CLEANUP] Removing replay session: ${sessionId}`);
|
|
302
|
+
this.replaySessions.delete(sessionId);
|
|
303
|
+
}
|
|
304
|
+
if (this.recordingId === sessionId) {
|
|
305
|
+
console.log(`[CLEANUP] Saving and clearing active recording session: ${sessionId}`);
|
|
306
|
+
await this.saveCurrentSession();
|
|
307
|
+
this.currentSession = null;
|
|
308
|
+
this.recordingId = null;
|
|
309
|
+
}
|
|
310
|
+
if (this.replayId === sessionId) {
|
|
311
|
+
console.log(`[CLEANUP] Clearing active replay session: ${sessionId}`);
|
|
312
|
+
this.replayId = null;
|
|
313
|
+
}
|
|
314
|
+
console.log(`[CLEANUP] Session ${sessionId} cleaned up successfully`);
|
|
315
|
+
}
|
|
284
316
|
parseGetParams(req) {
|
|
285
317
|
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
286
318
|
const mode = url.searchParams.get("mode");
|
|
@@ -304,9 +336,29 @@ var ProxyServer = class {
|
|
|
304
336
|
throw new Error("Unsupported control method");
|
|
305
337
|
}
|
|
306
338
|
async handleControlRequest(req, res) {
|
|
339
|
+
if (req.method === "GET") {
|
|
340
|
+
sendJsonResponse(res, HTTP_STATUS_OK, {
|
|
341
|
+
recordingsDir: this.recordingsDir,
|
|
342
|
+
mode: this.mode,
|
|
343
|
+
id: this.recordingId || this.replayId
|
|
344
|
+
});
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
307
347
|
try {
|
|
308
348
|
const data = await this.parseControlRequest(req);
|
|
309
|
-
const { mode, id, timeout: requestTimeout } = data;
|
|
349
|
+
const { mode, id, timeout: requestTimeout, cleanup } = data;
|
|
350
|
+
if (cleanup && id) {
|
|
351
|
+
await this.cleanupSession(id);
|
|
352
|
+
sendJsonResponse(res, HTTP_STATUS_OK, {
|
|
353
|
+
success: true,
|
|
354
|
+
message: `Session ${id} cleaned up`,
|
|
355
|
+
mode: this.mode
|
|
356
|
+
});
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (!mode) {
|
|
360
|
+
throw new Error("Mode parameter is required when cleanup is not specified");
|
|
361
|
+
}
|
|
310
362
|
const timeout = requestTimeout ?? DEFAULT_TIMEOUT_MS;
|
|
311
363
|
this.clearModeTimeout();
|
|
312
364
|
await this.switchMode(mode, id);
|
|
@@ -322,7 +374,8 @@ var ProxyServer = class {
|
|
|
322
374
|
success: true,
|
|
323
375
|
mode: this.mode,
|
|
324
376
|
id: this.recordingId || this.replayId,
|
|
325
|
-
timeout
|
|
377
|
+
timeout,
|
|
378
|
+
recordingsDir: this.recordingsDir
|
|
326
379
|
});
|
|
327
380
|
} catch (error) {
|
|
328
381
|
console.error("Control request error:", error);
|
|
@@ -397,6 +450,7 @@ var ProxyServer = class {
|
|
|
397
450
|
console.log(`Switched to replay mode with ID: ${id}`);
|
|
398
451
|
}
|
|
399
452
|
setupModeTimeout(timeout) {
|
|
453
|
+
clearTimeout(this.modeTimeout || 0);
|
|
400
454
|
this.modeTimeout = setTimeout(async () => {
|
|
401
455
|
console.log("Timeout reached, switching back to transparent mode");
|
|
402
456
|
await this.saveCurrentSession();
|
|
@@ -432,7 +486,29 @@ var ProxyServer = class {
|
|
|
432
486
|
await saveRecordingSession(this.recordingsDir, this.currentSession);
|
|
433
487
|
}
|
|
434
488
|
getRecordingIdOrError(req, res) {
|
|
435
|
-
const
|
|
489
|
+
const recordingIdFromRequest = this.getRecordingIdFromRequest(req);
|
|
490
|
+
if (recordingIdFromRequest) {
|
|
491
|
+
return recordingIdFromRequest;
|
|
492
|
+
}
|
|
493
|
+
if (this.replaySessions.size > 1) {
|
|
494
|
+
console.warn(
|
|
495
|
+
`[CONCURRENT REPLAY WARNING] Request to ${req.method} ${req.url} is missing ${RECORDING_ID_HEADER} header/cookie. Active sessions: ${[...this.replaySessions.keys()].join(", ")}. this.replayId fallback would be: ${this.replayId} (NOT USING - could be wrong session)`
|
|
496
|
+
);
|
|
497
|
+
const corsHeaders = this.getCorsHeaders(req);
|
|
498
|
+
res.writeHead(HTTP_STATUS_BAD_REQUEST, {
|
|
499
|
+
"Content-Type": "application/json",
|
|
500
|
+
...corsHeaders
|
|
501
|
+
});
|
|
502
|
+
res.end(
|
|
503
|
+
JSON.stringify({
|
|
504
|
+
error: "Missing recording ID in concurrent replay mode. Ensure x-test-rcrd-id header is set.",
|
|
505
|
+
activeSessions: [...this.replaySessions.keys()],
|
|
506
|
+
hint: "This usually means page.setExtraHTTPHeaders() did not apply to this request type"
|
|
507
|
+
})
|
|
508
|
+
);
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
const recordingId = this.replayId;
|
|
436
512
|
if (!recordingId) {
|
|
437
513
|
const corsHeaders = this.getCorsHeaders(req);
|
|
438
514
|
res.writeHead(HTTP_STATUS_BAD_REQUEST, {
|
|
@@ -442,6 +518,9 @@ var ProxyServer = class {
|
|
|
442
518
|
res.end(JSON.stringify({ error: "No replay session active" }));
|
|
443
519
|
return null;
|
|
444
520
|
}
|
|
521
|
+
console.log(
|
|
522
|
+
`[FALLBACK] Using replayId fallback for ${req.method} ${req.url} -> session: ${recordingId} (single session mode)`
|
|
523
|
+
);
|
|
445
524
|
return recordingId;
|
|
446
525
|
}
|
|
447
526
|
async ensureSessionLoaded(recordingId, filePath) {
|
|
@@ -865,8 +944,6 @@ var ProxyServer = class {
|
|
|
865
944
|
);
|
|
866
945
|
}
|
|
867
946
|
};
|
|
868
|
-
|
|
869
|
-
// src/playwright/index.ts
|
|
870
947
|
function getProxyPort() {
|
|
871
948
|
const envPort = process.env.TEST_PROXY_RECORDER_PORT;
|
|
872
949
|
if (envPort) {
|
|
@@ -902,6 +979,30 @@ async function setProxyMode(mode, sessionId, timeout) {
|
|
|
902
979
|
throw error;
|
|
903
980
|
}
|
|
904
981
|
}
|
|
982
|
+
async function cleanupSession(sessionId) {
|
|
983
|
+
const proxyPort = getProxyPort();
|
|
984
|
+
try {
|
|
985
|
+
const body = {
|
|
986
|
+
cleanup: true,
|
|
987
|
+
id: sessionId
|
|
988
|
+
};
|
|
989
|
+
const response = await fetch(`http://127.0.0.1:${proxyPort}/__control`, {
|
|
990
|
+
method: "POST",
|
|
991
|
+
headers: { "Content-Type": "application/json" },
|
|
992
|
+
body: JSON.stringify(body)
|
|
993
|
+
});
|
|
994
|
+
if (!response.ok) {
|
|
995
|
+
const text = await response.text();
|
|
996
|
+
console.error(`Failed to cleanup session ${sessionId}:`, text);
|
|
997
|
+
throw new Error(`Failed to cleanup session: ${text}`);
|
|
998
|
+
}
|
|
999
|
+
await response.json();
|
|
1000
|
+
console.log(`Session cleaned up: ${sessionId}`);
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
console.error(`Error cleaning up session:`, error);
|
|
1003
|
+
throw error;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
905
1006
|
function parseSpecFilePath(specPath) {
|
|
906
1007
|
const folderMatch = specPath.match(/^(.+?)\/([^/]+)\.(spec|test)\.ts$/);
|
|
907
1008
|
if (folderMatch) {
|
|
@@ -943,6 +1044,53 @@ async function stopProxy(testInfo) {
|
|
|
943
1044
|
const sessionId = generateSessionId(testInfo);
|
|
944
1045
|
await setProxyMode(Modes.transparent, sessionId);
|
|
945
1046
|
}
|
|
1047
|
+
var cachedRecordingsDir = null;
|
|
1048
|
+
async function getRecordingsDir() {
|
|
1049
|
+
if (cachedRecordingsDir) {
|
|
1050
|
+
return cachedRecordingsDir;
|
|
1051
|
+
}
|
|
1052
|
+
const proxyPort = getProxyPort();
|
|
1053
|
+
try {
|
|
1054
|
+
const response = await fetch(`http://127.0.0.1:${proxyPort}/__control`);
|
|
1055
|
+
if (response.ok) {
|
|
1056
|
+
const data = await response.json();
|
|
1057
|
+
if (data.recordingsDir) {
|
|
1058
|
+
cachedRecordingsDir = data.recordingsDir;
|
|
1059
|
+
return cachedRecordingsDir;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
console.warn(
|
|
1064
|
+
"Failed to get recordings directory from proxy, using default:",
|
|
1065
|
+
error
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
cachedRecordingsDir = path2__default.default.join(process.cwd(), "e2e", "recordings");
|
|
1069
|
+
return cachedRecordingsDir;
|
|
1070
|
+
}
|
|
1071
|
+
async function setupClientSideRecording(page, sessionId, mode, url) {
|
|
1072
|
+
const harFileName = sessionId.replaceAll("/", "__");
|
|
1073
|
+
const recordingsDir = await getRecordingsDir();
|
|
1074
|
+
const harPath = path2__default.default.join(recordingsDir, `${harFileName}.har`);
|
|
1075
|
+
console.log(
|
|
1076
|
+
`[Client-Side Recording] Setting up HAR for session: ${sessionId}, mode: ${mode}, path: ${harPath}`
|
|
1077
|
+
);
|
|
1078
|
+
try {
|
|
1079
|
+
await page.routeFromHAR(harPath, {
|
|
1080
|
+
url,
|
|
1081
|
+
update: mode === Modes.record,
|
|
1082
|
+
updateContent: "embed"
|
|
1083
|
+
});
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
if (mode === Modes.replay) {
|
|
1086
|
+
console.error(
|
|
1087
|
+
`[Client-Side Replay] Failed to load HAR file. Run tests in record mode first.`,
|
|
1088
|
+
error
|
|
1089
|
+
);
|
|
1090
|
+
throw error;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
946
1094
|
var playwrightProxy = {
|
|
947
1095
|
/**
|
|
948
1096
|
* Setup before test - sets the proxy mode and configures page with custom header
|
|
@@ -950,24 +1098,84 @@ var playwrightProxy = {
|
|
|
950
1098
|
* @param page - Playwright page object
|
|
951
1099
|
* @param testInfo - Playwright test info object
|
|
952
1100
|
* @param mode - The proxy mode to use for this test
|
|
953
|
-
* @param
|
|
1101
|
+
* @param options - Optional configuration including timeout and client-side recording patterns
|
|
954
1102
|
*/
|
|
955
|
-
async before(page, testInfo, mode,
|
|
1103
|
+
async before(page, testInfo, mode, options) {
|
|
1104
|
+
const timeout = typeof options === "number" ? options : options?.timeout;
|
|
1105
|
+
const clientSideOptions = typeof options === "object" && options !== null ? options : void 0;
|
|
956
1106
|
const sessionId = generateSessionId(testInfo);
|
|
957
1107
|
await page.setExtraHTTPHeaders({
|
|
958
1108
|
[RECORDING_ID_HEADER]: sessionId
|
|
959
1109
|
});
|
|
1110
|
+
console.log(`[Setup] Setting proxy mode: ${mode}, session: ${sessionId}`);
|
|
960
1111
|
await setProxyMode(mode, sessionId, timeout);
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1112
|
+
console.log(`[Setup] Proxy mode set successfully`);
|
|
1113
|
+
if (clientSideOptions?.url) {
|
|
1114
|
+
console.log(`[Setup] Setting up client-side recording with pattern: ${clientSideOptions.url}`);
|
|
1115
|
+
await setupClientSideRecording(
|
|
1116
|
+
page,
|
|
1117
|
+
sessionId,
|
|
1118
|
+
mode,
|
|
1119
|
+
clientSideOptions.url
|
|
1120
|
+
);
|
|
1121
|
+
console.log(`[Setup] Client-side recording setup complete`);
|
|
1122
|
+
}
|
|
1123
|
+
const proxyPort = process.env.TEST_PROXY_RECORDER_PORT || "8100";
|
|
1124
|
+
const proxyUrl = `localhost:${proxyPort}`;
|
|
1125
|
+
console.log(`[Setup] Registering proxy route handler for: ${proxyUrl}`);
|
|
1126
|
+
await page.route(
|
|
1127
|
+
(url) => {
|
|
1128
|
+
const urlStr = url.toString();
|
|
1129
|
+
const matches = urlStr.includes(proxyUrl);
|
|
1130
|
+
if (matches) {
|
|
1131
|
+
console.log(`[Route Matcher] Matched proxy request: ${urlStr}`);
|
|
1132
|
+
}
|
|
1133
|
+
return matches;
|
|
1134
|
+
},
|
|
1135
|
+
async (route) => {
|
|
1136
|
+
try {
|
|
1137
|
+
const url = route.request().url();
|
|
1138
|
+
const method = route.request().method();
|
|
1139
|
+
const headers = route.request().headers();
|
|
1140
|
+
const hadHeader = !!headers[RECORDING_ID_HEADER];
|
|
1141
|
+
headers[RECORDING_ID_HEADER] = sessionId;
|
|
1142
|
+
console.log(
|
|
1143
|
+
`[Route Intercept] ${method} ${url} (had header: ${hadHeader}, adding session: ${sessionId})`
|
|
1144
|
+
);
|
|
1145
|
+
await route.continue({ headers });
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
console.error(
|
|
1148
|
+
`[Route Handler Error] Failed to add ${RECORDING_ID_HEADER} header:`,
|
|
1149
|
+
error
|
|
1150
|
+
);
|
|
1151
|
+
await route.fallback();
|
|
1152
|
+
}
|
|
1153
|
+
},
|
|
1154
|
+
{ times: Infinity }
|
|
1155
|
+
// Ensure the handler applies to all matching requests
|
|
1156
|
+
);
|
|
1157
|
+
console.log(`[Setup] Proxy route handler registered`);
|
|
1158
|
+
const context = page.context();
|
|
1159
|
+
const contextId = context._guid || "default";
|
|
1160
|
+
const handlerKey = `cleanup_${contextId}`;
|
|
1161
|
+
if (!globalThis[handlerKey]) {
|
|
1162
|
+
globalThis[handlerKey] = true;
|
|
1163
|
+
context.on("close", async () => {
|
|
1164
|
+
try {
|
|
1165
|
+
console.log(
|
|
1166
|
+
`[Cleanup] Browser context closed, cleaning up session: ${sessionId}`
|
|
1167
|
+
);
|
|
1168
|
+
await cleanupSession(sessionId);
|
|
1169
|
+
} catch (error) {
|
|
1170
|
+
console.warn(
|
|
1171
|
+
`[Cleanup] Failed to cleanup session ${sessionId}:`,
|
|
1172
|
+
error
|
|
1173
|
+
);
|
|
1174
|
+
} finally {
|
|
1175
|
+
delete globalThis[handlerKey];
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
971
1179
|
},
|
|
972
1180
|
/**
|
|
973
1181
|
* Global teardown - switches proxy to transparent mode
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { RECORDING_ID_HEADER, createHeadersWithRecordingId, getRecordingId, setNextProxyHeaders } from './nextjs/index.cjs';
|
|
2
2
|
import http from 'node:http';
|
|
3
|
-
export { C as ControlRequest, M as Mode, P as PlaywrightTestInfo, R as Recording, a as RecordingSession, W as WebSocketRecording, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from './index-
|
|
3
|
+
export { C as ControlRequest, M as Mode, P as PlaywrightTestInfo, R as Recording, a as RecordingSession, W as WebSocketRecording, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from './index-BlBWqSE4.cjs';
|
|
4
4
|
import '@playwright/test';
|
|
5
5
|
|
|
6
6
|
declare class ProxyServer {
|
|
@@ -56,6 +56,11 @@ declare class ProxyServer {
|
|
|
56
56
|
* @returns The replay session state
|
|
57
57
|
*/
|
|
58
58
|
private getOrCreateReplaySession;
|
|
59
|
+
/**
|
|
60
|
+
* Clean up a session - removes it from memory and resets counters
|
|
61
|
+
* @param sessionId The session ID to clean up
|
|
62
|
+
*/
|
|
63
|
+
private cleanupSession;
|
|
59
64
|
private parseGetParams;
|
|
60
65
|
private parseControlRequest;
|
|
61
66
|
private handleControlRequest;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { RECORDING_ID_HEADER, createHeadersWithRecordingId, getRecordingId, setNextProxyHeaders } from './nextjs/index.js';
|
|
2
2
|
import http from 'node:http';
|
|
3
|
-
export { C as ControlRequest, M as Mode, P as PlaywrightTestInfo, R as Recording, a as RecordingSession, W as WebSocketRecording, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from './index-
|
|
3
|
+
export { C as ControlRequest, M as Mode, P as PlaywrightTestInfo, R as Recording, a as RecordingSession, W as WebSocketRecording, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from './index-BlBWqSE4.js';
|
|
4
4
|
import '@playwright/test';
|
|
5
5
|
|
|
6
6
|
declare class ProxyServer {
|
|
@@ -56,6 +56,11 @@ declare class ProxyServer {
|
|
|
56
56
|
* @returns The replay session state
|
|
57
57
|
*/
|
|
58
58
|
private getOrCreateReplaySession;
|
|
59
|
+
/**
|
|
60
|
+
* Clean up a session - removes it from memory and resets counters
|
|
61
|
+
* @param sessionId The session ID to clean up
|
|
62
|
+
*/
|
|
63
|
+
private cleanupSession;
|
|
59
64
|
private parseGetParams;
|
|
60
65
|
private parseControlRequest;
|
|
61
66
|
private handleControlRequest;
|