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/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import https from 'https';
4
4
  import httpProxy from 'http-proxy';
5
5
  import { WebSocket, WebSocketServer } from 'ws';
6
6
  import crypto from 'crypto';
7
- import path from 'path';
7
+ import path2 from 'path';
8
8
  import filenamify2 from 'filenamify';
9
9
 
10
10
  // src/constants.ts
@@ -41,7 +41,7 @@ function getRecordingPath(recordingsDir, id) {
41
41
  maxLength: 255
42
42
  // Set explicit max to prevent filenamify's default truncation
43
43
  });
44
- return path.join(recordingsDir, `${sanitizedId}${EXTENSION}`);
44
+ return path2.join(recordingsDir, `${sanitizedId}${EXTENSION}`);
45
45
  }
46
46
  async function loadRecordingSession(filePath) {
47
47
  const fileContent = await fs.readFile(filePath, "utf8");
@@ -82,16 +82,19 @@ async function saveRecordingSession(recordingsDir, session) {
82
82
  `Saved ${processedRecordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
83
83
  );
84
84
  }
85
- function getReqID(req) {
86
- const urlParts = req.url.split("?");
87
- const pathname = urlParts[0];
88
- const query = urlParts[1] || "";
85
+ function generateRecordingKey(pathname, query, method) {
89
86
  const pathPart = pathname === "/" ? "root" : pathname.slice(1);
90
87
  const normalizedPath = filenamify2(pathPart, { replacement: "_" });
91
88
  const queryHash = generateQueryHash(query);
92
- const filename = `${req.method}_${normalizedPath}${queryHash}.json`;
89
+ const filename = `${method}_${normalizedPath}${queryHash}.json`;
93
90
  return filenamify2(filename, { replacement: "_" });
94
91
  }
92
+ function getReqID(req) {
93
+ const urlParts = req.url.split("?");
94
+ const pathname = urlParts[0];
95
+ const query = urlParts[1] || "";
96
+ return generateRecordingKey(pathname, query, req.method);
97
+ }
95
98
  function generateQueryHash(query) {
96
99
  if (!query) {
97
100
  return "";
@@ -244,7 +247,15 @@ var ProxyServer = class {
244
247
  * @returns The recording ID, or null if not found
245
248
  */
246
249
  getRecordingIdFromRequest(req) {
247
- return this.getRecordingIdFromHeader(req) || this.getRecordingIdFromCookie(req);
250
+ const fromHeader = this.getRecordingIdFromHeader(req);
251
+ const fromCookie = this.getRecordingIdFromCookie(req);
252
+ if (fromHeader) {
253
+ return fromHeader;
254
+ }
255
+ if (fromCookie) {
256
+ return fromCookie;
257
+ }
258
+ return null;
248
259
  }
249
260
  /**
250
261
  * Get or create a replay session state for a given recording ID
@@ -269,6 +280,27 @@ var ProxyServer = class {
269
280
  }
270
281
  return session;
271
282
  }
283
+ /**
284
+ * Clean up a session - removes it from memory and resets counters
285
+ * @param sessionId The session ID to clean up
286
+ */
287
+ async cleanupSession(sessionId) {
288
+ if (this.replaySessions.has(sessionId)) {
289
+ console.log(`[CLEANUP] Removing replay session: ${sessionId}`);
290
+ this.replaySessions.delete(sessionId);
291
+ }
292
+ if (this.recordingId === sessionId) {
293
+ console.log(`[CLEANUP] Saving and clearing active recording session: ${sessionId}`);
294
+ await this.saveCurrentSession();
295
+ this.currentSession = null;
296
+ this.recordingId = null;
297
+ }
298
+ if (this.replayId === sessionId) {
299
+ console.log(`[CLEANUP] Clearing active replay session: ${sessionId}`);
300
+ this.replayId = null;
301
+ }
302
+ console.log(`[CLEANUP] Session ${sessionId} cleaned up successfully`);
303
+ }
272
304
  parseGetParams(req) {
273
305
  const url = new URL(req.url || "", `http://${req.headers.host}`);
274
306
  const mode = url.searchParams.get("mode");
@@ -292,9 +324,29 @@ var ProxyServer = class {
292
324
  throw new Error("Unsupported control method");
293
325
  }
294
326
  async handleControlRequest(req, res) {
327
+ if (req.method === "GET") {
328
+ sendJsonResponse(res, HTTP_STATUS_OK, {
329
+ recordingsDir: this.recordingsDir,
330
+ mode: this.mode,
331
+ id: this.recordingId || this.replayId
332
+ });
333
+ return;
334
+ }
295
335
  try {
296
336
  const data = await this.parseControlRequest(req);
297
- const { mode, id, timeout: requestTimeout } = data;
337
+ const { mode, id, timeout: requestTimeout, cleanup } = data;
338
+ if (cleanup && id) {
339
+ await this.cleanupSession(id);
340
+ sendJsonResponse(res, HTTP_STATUS_OK, {
341
+ success: true,
342
+ message: `Session ${id} cleaned up`,
343
+ mode: this.mode
344
+ });
345
+ return;
346
+ }
347
+ if (!mode) {
348
+ throw new Error("Mode parameter is required when cleanup is not specified");
349
+ }
298
350
  const timeout = requestTimeout ?? DEFAULT_TIMEOUT_MS;
299
351
  this.clearModeTimeout();
300
352
  await this.switchMode(mode, id);
@@ -310,7 +362,8 @@ var ProxyServer = class {
310
362
  success: true,
311
363
  mode: this.mode,
312
364
  id: this.recordingId || this.replayId,
313
- timeout
365
+ timeout,
366
+ recordingsDir: this.recordingsDir
314
367
  });
315
368
  } catch (error) {
316
369
  console.error("Control request error:", error);
@@ -385,6 +438,7 @@ var ProxyServer = class {
385
438
  console.log(`Switched to replay mode with ID: ${id}`);
386
439
  }
387
440
  setupModeTimeout(timeout) {
441
+ clearTimeout(this.modeTimeout || 0);
388
442
  this.modeTimeout = setTimeout(async () => {
389
443
  console.log("Timeout reached, switching back to transparent mode");
390
444
  await this.saveCurrentSession();
@@ -420,7 +474,29 @@ var ProxyServer = class {
420
474
  await saveRecordingSession(this.recordingsDir, this.currentSession);
421
475
  }
422
476
  getRecordingIdOrError(req, res) {
423
- const recordingId = this.getRecordingIdFromRequest(req) || this.replayId;
477
+ const recordingIdFromRequest = this.getRecordingIdFromRequest(req);
478
+ if (recordingIdFromRequest) {
479
+ return recordingIdFromRequest;
480
+ }
481
+ if (this.replaySessions.size > 1) {
482
+ console.warn(
483
+ `[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)`
484
+ );
485
+ const corsHeaders = this.getCorsHeaders(req);
486
+ res.writeHead(HTTP_STATUS_BAD_REQUEST, {
487
+ "Content-Type": "application/json",
488
+ ...corsHeaders
489
+ });
490
+ res.end(
491
+ JSON.stringify({
492
+ error: "Missing recording ID in concurrent replay mode. Ensure x-test-rcrd-id header is set.",
493
+ activeSessions: [...this.replaySessions.keys()],
494
+ hint: "This usually means page.setExtraHTTPHeaders() did not apply to this request type"
495
+ })
496
+ );
497
+ return null;
498
+ }
499
+ const recordingId = this.replayId;
424
500
  if (!recordingId) {
425
501
  const corsHeaders = this.getCorsHeaders(req);
426
502
  res.writeHead(HTTP_STATUS_BAD_REQUEST, {
@@ -430,6 +506,9 @@ var ProxyServer = class {
430
506
  res.end(JSON.stringify({ error: "No replay session active" }));
431
507
  return null;
432
508
  }
509
+ console.log(
510
+ `[FALLBACK] Using replayId fallback for ${req.method} ${req.url} -> session: ${recordingId} (single session mode)`
511
+ );
433
512
  return recordingId;
434
513
  }
435
514
  async ensureSessionLoaded(recordingId, filePath) {
@@ -853,8 +932,6 @@ var ProxyServer = class {
853
932
  );
854
933
  }
855
934
  };
856
-
857
- // src/playwright/index.ts
858
935
  function getProxyPort() {
859
936
  const envPort = process.env.TEST_PROXY_RECORDER_PORT;
860
937
  if (envPort) {
@@ -890,6 +967,30 @@ async function setProxyMode(mode, sessionId, timeout) {
890
967
  throw error;
891
968
  }
892
969
  }
970
+ async function cleanupSession(sessionId) {
971
+ const proxyPort = getProxyPort();
972
+ try {
973
+ const body = {
974
+ cleanup: true,
975
+ id: sessionId
976
+ };
977
+ const response = await fetch(`http://127.0.0.1:${proxyPort}/__control`, {
978
+ method: "POST",
979
+ headers: { "Content-Type": "application/json" },
980
+ body: JSON.stringify(body)
981
+ });
982
+ if (!response.ok) {
983
+ const text = await response.text();
984
+ console.error(`Failed to cleanup session ${sessionId}:`, text);
985
+ throw new Error(`Failed to cleanup session: ${text}`);
986
+ }
987
+ await response.json();
988
+ console.log(`Session cleaned up: ${sessionId}`);
989
+ } catch (error) {
990
+ console.error(`Error cleaning up session:`, error);
991
+ throw error;
992
+ }
993
+ }
893
994
  function parseSpecFilePath(specPath) {
894
995
  const folderMatch = specPath.match(/^(.+?)\/([^/]+)\.(spec|test)\.ts$/);
895
996
  if (folderMatch) {
@@ -931,6 +1032,53 @@ async function stopProxy(testInfo) {
931
1032
  const sessionId = generateSessionId(testInfo);
932
1033
  await setProxyMode(Modes.transparent, sessionId);
933
1034
  }
1035
+ var cachedRecordingsDir = null;
1036
+ async function getRecordingsDir() {
1037
+ if (cachedRecordingsDir) {
1038
+ return cachedRecordingsDir;
1039
+ }
1040
+ const proxyPort = getProxyPort();
1041
+ try {
1042
+ const response = await fetch(`http://127.0.0.1:${proxyPort}/__control`);
1043
+ if (response.ok) {
1044
+ const data = await response.json();
1045
+ if (data.recordingsDir) {
1046
+ cachedRecordingsDir = data.recordingsDir;
1047
+ return cachedRecordingsDir;
1048
+ }
1049
+ }
1050
+ } catch (error) {
1051
+ console.warn(
1052
+ "Failed to get recordings directory from proxy, using default:",
1053
+ error
1054
+ );
1055
+ }
1056
+ cachedRecordingsDir = path2.join(process.cwd(), "e2e", "recordings");
1057
+ return cachedRecordingsDir;
1058
+ }
1059
+ async function setupClientSideRecording(page, sessionId, mode, url) {
1060
+ const harFileName = sessionId.replaceAll("/", "__");
1061
+ const recordingsDir = await getRecordingsDir();
1062
+ const harPath = path2.join(recordingsDir, `${harFileName}.har`);
1063
+ console.log(
1064
+ `[Client-Side Recording] Setting up HAR for session: ${sessionId}, mode: ${mode}, path: ${harPath}`
1065
+ );
1066
+ try {
1067
+ await page.routeFromHAR(harPath, {
1068
+ url,
1069
+ update: mode === Modes.record,
1070
+ updateContent: "embed"
1071
+ });
1072
+ } catch (error) {
1073
+ if (mode === Modes.replay) {
1074
+ console.error(
1075
+ `[Client-Side Replay] Failed to load HAR file. Run tests in record mode first.`,
1076
+ error
1077
+ );
1078
+ throw error;
1079
+ }
1080
+ }
1081
+ }
934
1082
  var playwrightProxy = {
935
1083
  /**
936
1084
  * Setup before test - sets the proxy mode and configures page with custom header
@@ -938,24 +1086,84 @@ var playwrightProxy = {
938
1086
  * @param page - Playwright page object
939
1087
  * @param testInfo - Playwright test info object
940
1088
  * @param mode - The proxy mode to use for this test
941
- * @param timeout - Optional timeout in milliseconds
1089
+ * @param options - Optional configuration including timeout and client-side recording patterns
942
1090
  */
943
- async before(page, testInfo, mode, timeout) {
1091
+ async before(page, testInfo, mode, options) {
1092
+ const timeout = typeof options === "number" ? options : options?.timeout;
1093
+ const clientSideOptions = typeof options === "object" && options !== null ? options : void 0;
944
1094
  const sessionId = generateSessionId(testInfo);
945
1095
  await page.setExtraHTTPHeaders({
946
1096
  [RECORDING_ID_HEADER]: sessionId
947
1097
  });
1098
+ console.log(`[Setup] Setting proxy mode: ${mode}, session: ${sessionId}`);
948
1099
  await setProxyMode(mode, sessionId, timeout);
949
- page.on("close", async () => {
950
- try {
951
- await setProxyMode(Modes.replay, sessionId);
952
- console.log(
953
- `[Cleanup] Switched to replay mode for session: ${sessionId}`
954
- );
955
- } catch (error) {
956
- console.error("[Cleanup] Error during page close cleanup:", error);
957
- }
958
- });
1100
+ console.log(`[Setup] Proxy mode set successfully`);
1101
+ if (clientSideOptions?.url) {
1102
+ console.log(`[Setup] Setting up client-side recording with pattern: ${clientSideOptions.url}`);
1103
+ await setupClientSideRecording(
1104
+ page,
1105
+ sessionId,
1106
+ mode,
1107
+ clientSideOptions.url
1108
+ );
1109
+ console.log(`[Setup] Client-side recording setup complete`);
1110
+ }
1111
+ const proxyPort = process.env.TEST_PROXY_RECORDER_PORT || "8100";
1112
+ const proxyUrl = `localhost:${proxyPort}`;
1113
+ console.log(`[Setup] Registering proxy route handler for: ${proxyUrl}`);
1114
+ await page.route(
1115
+ (url) => {
1116
+ const urlStr = url.toString();
1117
+ const matches = urlStr.includes(proxyUrl);
1118
+ if (matches) {
1119
+ console.log(`[Route Matcher] Matched proxy request: ${urlStr}`);
1120
+ }
1121
+ return matches;
1122
+ },
1123
+ async (route) => {
1124
+ try {
1125
+ const url = route.request().url();
1126
+ const method = route.request().method();
1127
+ const headers = route.request().headers();
1128
+ const hadHeader = !!headers[RECORDING_ID_HEADER];
1129
+ headers[RECORDING_ID_HEADER] = sessionId;
1130
+ console.log(
1131
+ `[Route Intercept] ${method} ${url} (had header: ${hadHeader}, adding session: ${sessionId})`
1132
+ );
1133
+ await route.continue({ headers });
1134
+ } catch (error) {
1135
+ console.error(
1136
+ `[Route Handler Error] Failed to add ${RECORDING_ID_HEADER} header:`,
1137
+ error
1138
+ );
1139
+ await route.fallback();
1140
+ }
1141
+ },
1142
+ { times: Infinity }
1143
+ // Ensure the handler applies to all matching requests
1144
+ );
1145
+ console.log(`[Setup] Proxy route handler registered`);
1146
+ const context = page.context();
1147
+ const contextId = context._guid || "default";
1148
+ const handlerKey = `cleanup_${contextId}`;
1149
+ if (!globalThis[handlerKey]) {
1150
+ globalThis[handlerKey] = true;
1151
+ context.on("close", async () => {
1152
+ try {
1153
+ console.log(
1154
+ `[Cleanup] Browser context closed, cleaning up session: ${sessionId}`
1155
+ );
1156
+ await cleanupSession(sessionId);
1157
+ } catch (error) {
1158
+ console.warn(
1159
+ `[Cleanup] Failed to cleanup session ${sessionId}:`,
1160
+ error
1161
+ );
1162
+ } finally {
1163
+ delete globalThis[handlerKey];
1164
+ }
1165
+ });
1166
+ }
959
1167
  },
960
1168
  /**
961
1169
  * Global teardown - switches proxy to transparent mode
@@ -1,6 +1,12 @@
1
1
  'use strict';
2
2
 
3
- // src/constants.ts
3
+ var path = require('path');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var path__default = /*#__PURE__*/_interopDefault(path);
8
+
9
+ // src/playwright/index.ts
4
10
  var RECORDING_ID_HEADER = "x-test-rcrd-id";
5
11
 
6
12
  // src/types.ts
@@ -46,6 +52,30 @@ async function setProxyMode(mode, sessionId, timeout) {
46
52
  throw error;
47
53
  }
48
54
  }
55
+ async function cleanupSession(sessionId) {
56
+ const proxyPort = getProxyPort();
57
+ try {
58
+ const body = {
59
+ cleanup: true,
60
+ id: sessionId
61
+ };
62
+ const response = await fetch(`http://127.0.0.1:${proxyPort}/__control`, {
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify(body)
66
+ });
67
+ if (!response.ok) {
68
+ const text = await response.text();
69
+ console.error(`Failed to cleanup session ${sessionId}:`, text);
70
+ throw new Error(`Failed to cleanup session: ${text}`);
71
+ }
72
+ await response.json();
73
+ console.log(`Session cleaned up: ${sessionId}`);
74
+ } catch (error) {
75
+ console.error(`Error cleaning up session:`, error);
76
+ throw error;
77
+ }
78
+ }
49
79
  function parseSpecFilePath(specPath) {
50
80
  const folderMatch = specPath.match(/^(.+?)\/([^/]+)\.(spec|test)\.ts$/);
51
81
  if (folderMatch) {
@@ -87,6 +117,53 @@ async function stopProxy(testInfo) {
87
117
  const sessionId = generateSessionId(testInfo);
88
118
  await setProxyMode(Modes.transparent, sessionId);
89
119
  }
120
+ var cachedRecordingsDir = null;
121
+ async function getRecordingsDir() {
122
+ if (cachedRecordingsDir) {
123
+ return cachedRecordingsDir;
124
+ }
125
+ const proxyPort = getProxyPort();
126
+ try {
127
+ const response = await fetch(`http://127.0.0.1:${proxyPort}/__control`);
128
+ if (response.ok) {
129
+ const data = await response.json();
130
+ if (data.recordingsDir) {
131
+ cachedRecordingsDir = data.recordingsDir;
132
+ return cachedRecordingsDir;
133
+ }
134
+ }
135
+ } catch (error) {
136
+ console.warn(
137
+ "Failed to get recordings directory from proxy, using default:",
138
+ error
139
+ );
140
+ }
141
+ cachedRecordingsDir = path__default.default.join(process.cwd(), "e2e", "recordings");
142
+ return cachedRecordingsDir;
143
+ }
144
+ async function setupClientSideRecording(page, sessionId, mode, url) {
145
+ const harFileName = sessionId.replaceAll("/", "__");
146
+ const recordingsDir = await getRecordingsDir();
147
+ const harPath = path__default.default.join(recordingsDir, `${harFileName}.har`);
148
+ console.log(
149
+ `[Client-Side Recording] Setting up HAR for session: ${sessionId}, mode: ${mode}, path: ${harPath}`
150
+ );
151
+ try {
152
+ await page.routeFromHAR(harPath, {
153
+ url,
154
+ update: mode === Modes.record,
155
+ updateContent: "embed"
156
+ });
157
+ } catch (error) {
158
+ if (mode === Modes.replay) {
159
+ console.error(
160
+ `[Client-Side Replay] Failed to load HAR file. Run tests in record mode first.`,
161
+ error
162
+ );
163
+ throw error;
164
+ }
165
+ }
166
+ }
90
167
  var playwrightProxy = {
91
168
  /**
92
169
  * Setup before test - sets the proxy mode and configures page with custom header
@@ -94,24 +171,84 @@ var playwrightProxy = {
94
171
  * @param page - Playwright page object
95
172
  * @param testInfo - Playwright test info object
96
173
  * @param mode - The proxy mode to use for this test
97
- * @param timeout - Optional timeout in milliseconds
174
+ * @param options - Optional configuration including timeout and client-side recording patterns
98
175
  */
99
- async before(page, testInfo, mode, timeout) {
176
+ async before(page, testInfo, mode, options) {
177
+ const timeout = typeof options === "number" ? options : options?.timeout;
178
+ const clientSideOptions = typeof options === "object" && options !== null ? options : void 0;
100
179
  const sessionId = generateSessionId(testInfo);
101
180
  await page.setExtraHTTPHeaders({
102
181
  [RECORDING_ID_HEADER]: sessionId
103
182
  });
183
+ console.log(`[Setup] Setting proxy mode: ${mode}, session: ${sessionId}`);
104
184
  await setProxyMode(mode, sessionId, timeout);
105
- page.on("close", async () => {
106
- try {
107
- await setProxyMode(Modes.replay, sessionId);
108
- console.log(
109
- `[Cleanup] Switched to replay mode for session: ${sessionId}`
110
- );
111
- } catch (error) {
112
- console.error("[Cleanup] Error during page close cleanup:", error);
113
- }
114
- });
185
+ console.log(`[Setup] Proxy mode set successfully`);
186
+ if (clientSideOptions?.url) {
187
+ console.log(`[Setup] Setting up client-side recording with pattern: ${clientSideOptions.url}`);
188
+ await setupClientSideRecording(
189
+ page,
190
+ sessionId,
191
+ mode,
192
+ clientSideOptions.url
193
+ );
194
+ console.log(`[Setup] Client-side recording setup complete`);
195
+ }
196
+ const proxyPort = process.env.TEST_PROXY_RECORDER_PORT || "8100";
197
+ const proxyUrl = `localhost:${proxyPort}`;
198
+ console.log(`[Setup] Registering proxy route handler for: ${proxyUrl}`);
199
+ await page.route(
200
+ (url) => {
201
+ const urlStr = url.toString();
202
+ const matches = urlStr.includes(proxyUrl);
203
+ if (matches) {
204
+ console.log(`[Route Matcher] Matched proxy request: ${urlStr}`);
205
+ }
206
+ return matches;
207
+ },
208
+ async (route) => {
209
+ try {
210
+ const url = route.request().url();
211
+ const method = route.request().method();
212
+ const headers = route.request().headers();
213
+ const hadHeader = !!headers[RECORDING_ID_HEADER];
214
+ headers[RECORDING_ID_HEADER] = sessionId;
215
+ console.log(
216
+ `[Route Intercept] ${method} ${url} (had header: ${hadHeader}, adding session: ${sessionId})`
217
+ );
218
+ await route.continue({ headers });
219
+ } catch (error) {
220
+ console.error(
221
+ `[Route Handler Error] Failed to add ${RECORDING_ID_HEADER} header:`,
222
+ error
223
+ );
224
+ await route.fallback();
225
+ }
226
+ },
227
+ { times: Infinity }
228
+ // Ensure the handler applies to all matching requests
229
+ );
230
+ console.log(`[Setup] Proxy route handler registered`);
231
+ const context = page.context();
232
+ const contextId = context._guid || "default";
233
+ const handlerKey = `cleanup_${contextId}`;
234
+ if (!globalThis[handlerKey]) {
235
+ globalThis[handlerKey] = true;
236
+ context.on("close", async () => {
237
+ try {
238
+ console.log(
239
+ `[Cleanup] Browser context closed, cleaning up session: ${sessionId}`
240
+ );
241
+ await cleanupSession(sessionId);
242
+ } catch (error) {
243
+ console.warn(
244
+ `[Cleanup] Failed to cleanup session ${sessionId}:`,
245
+ error
246
+ );
247
+ } finally {
248
+ delete globalThis[handlerKey];
249
+ }
250
+ });
251
+ }
115
252
  },
116
253
  /**
117
254
  * Global teardown - switches proxy to transparent mode
@@ -122,6 +259,7 @@ var playwrightProxy = {
122
259
  }
123
260
  };
124
261
 
262
+ exports.cleanupSession = cleanupSession;
125
263
  exports.generateSessionId = generateSessionId;
126
264
  exports.playwrightProxy = playwrightProxy;
127
265
  exports.setProxyMode = setProxyMode;
@@ -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-CVuiglPk.cjs';
2
+ export { f as ClientSideRecordingOptions, P as PlaywrightTestInfo, e as cleanupSession, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-BlBWqSE4.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-CVuiglPk.js';
2
+ export { f as ClientSideRecordingOptions, P as PlaywrightTestInfo, e as cleanupSession, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-BlBWqSE4.js';
3
3
  import 'node:http';