test-proxy-recorder 0.1.10 → 0.1.11

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.
@@ -28,6 +28,7 @@ interface Recording {
28
28
  response?: RecordedResponse;
29
29
  timestamp: string;
30
30
  key: string;
31
+ sequence?: number;
31
32
  recordingId: number;
32
33
  }
33
34
  interface WebSocketMessage {
@@ -28,6 +28,7 @@ interface Recording {
28
28
  response?: RecordedResponse;
29
29
  timestamp: string;
30
30
  key: string;
31
+ sequence?: number;
31
32
  recordingId: number;
32
33
  }
33
34
  interface WebSocketMessage {
package/dist/index.cjs CHANGED
@@ -5,9 +5,9 @@ var http = require('http');
5
5
  var https = require('https');
6
6
  var httpProxy = require('http-proxy');
7
7
  var ws = require('ws');
8
- var path = require('path');
9
8
  var crypto = require('crypto');
10
- var filenamify = require('filenamify');
9
+ var path = require('path');
10
+ var filenamify2 = require('filenamify');
11
11
 
12
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
13
 
@@ -15,9 +15,9 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
15
15
  var http__default = /*#__PURE__*/_interopDefault(http);
16
16
  var https__default = /*#__PURE__*/_interopDefault(https);
17
17
  var httpProxy__default = /*#__PURE__*/_interopDefault(httpProxy);
18
- var path__default = /*#__PURE__*/_interopDefault(path);
19
18
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
20
- var filenamify__default = /*#__PURE__*/_interopDefault(filenamify);
19
+ var path__default = /*#__PURE__*/_interopDefault(path);
20
+ var filenamify2__default = /*#__PURE__*/_interopDefault(filenamify2);
21
21
 
22
22
  // src/ProxyServer.ts
23
23
 
@@ -36,23 +36,53 @@ var Modes = {
36
36
  replay: "replay"
37
37
  };
38
38
  var JSON_INDENT_SPACES = 2;
39
+ var EXTENSION = ".mock.json";
40
+ var MAX_FILENAME_LENGTH = 255 - EXTENSION.length;
41
+ var HASH_LENGTH = 8;
42
+ function generateHash(str) {
43
+ return crypto__default.default.createHash("shake256", { outputLength: HASH_LENGTH / 2 }).update(str).digest("hex");
44
+ }
39
45
  function getRecordingPath(recordingsDir, id) {
40
- return path__default.default.join(recordingsDir, `${id}.mock.json`);
46
+ let processedId = id.replaceAll("/", "__");
47
+ if (processedId.length > MAX_FILENAME_LENGTH) {
48
+ const hash = generateHash(id);
49
+ const maxBaseLength = MAX_FILENAME_LENGTH - HASH_LENGTH - 1;
50
+ processedId = `${processedId.slice(0, maxBaseLength)}_${hash}`;
51
+ }
52
+ const sanitizedId = filenamify2__default.default(processedId, {
53
+ replacement: "_",
54
+ maxLength: 255
55
+ // Set explicit max to prevent filenamify's default truncation
56
+ });
57
+ return path__default.default.join(recordingsDir, `${sanitizedId}${EXTENSION}`);
41
58
  }
42
59
  async function loadRecordingSession(filePath) {
43
60
  const fileContent = await fs__default.default.readFile(filePath, "utf8");
44
61
  return JSON.parse(fileContent);
45
62
  }
63
+ function processRecordings(recordings) {
64
+ const keySequenceMap = /* @__PURE__ */ new Map();
65
+ return recordings.map((recording) => {
66
+ const key = recording.key;
67
+ const currentSeq = keySequenceMap.get(key) || 0;
68
+ keySequenceMap.set(key, currentSeq + 1);
69
+ return { ...recording, sequence: currentSeq };
70
+ });
71
+ }
46
72
  async function saveRecordingSession(recordingsDir, session) {
47
73
  const filePath = getRecordingPath(recordingsDir, session.id);
48
- const dirPath = path__default.default.dirname(filePath);
49
- await fs__default.default.mkdir(dirPath, { recursive: true });
74
+ await fs__default.default.mkdir(recordingsDir, { recursive: true });
75
+ const processedRecordings = processRecordings(session.recordings);
76
+ const processedSession = {
77
+ ...session,
78
+ recordings: processedRecordings
79
+ };
50
80
  await fs__default.default.writeFile(
51
81
  filePath,
52
- JSON.stringify(session, null, JSON_INDENT_SPACES)
82
+ JSON.stringify(processedSession, null, JSON_INDENT_SPACES)
53
83
  );
54
84
  console.log(
55
- `Saved ${session.recordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
85
+ `Saved ${processedRecordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
56
86
  );
57
87
  }
58
88
  function getReqID(req) {
@@ -60,10 +90,10 @@ function getReqID(req) {
60
90
  const pathname = urlParts[0];
61
91
  const query = urlParts[1] || "";
62
92
  const pathPart = pathname === "/" ? "root" : pathname.slice(1);
63
- const normalizedPath = filenamify__default.default(pathPart, { replacement: "_" });
93
+ const normalizedPath = filenamify2__default.default(pathPart, { replacement: "_" });
64
94
  const queryHash = generateQueryHash(query);
65
95
  const filename = `${req.method}_${normalizedPath}${queryHash}.json`;
66
- return filenamify__default.default(filename, { replacement: "_" });
96
+ return filenamify2__default.default(filename, { replacement: "_" });
67
97
  }
68
98
  function generateQueryHash(query) {
69
99
  if (!query) {
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import http from 'node:http';
2
- 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-CjM3evKb.cjs';
2
+ 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-Cx_Kflfl.cjs';
3
3
  import '@playwright/test';
4
4
 
5
5
  declare class ProxyServer {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import http from 'node:http';
2
- 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-CjM3evKb.js';
2
+ 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-Cx_Kflfl.js';
3
3
  import '@playwright/test';
4
4
 
5
5
  declare class ProxyServer {
package/dist/index.mjs CHANGED
@@ -3,9 +3,9 @@ import http from 'http';
3
3
  import https from 'https';
4
4
  import httpProxy from 'http-proxy';
5
5
  import { WebSocket, WebSocketServer } from 'ws';
6
- import path from 'path';
7
6
  import crypto from 'crypto';
8
- import filenamify from 'filenamify';
7
+ import path from 'path';
8
+ import filenamify2 from 'filenamify';
9
9
 
10
10
  // src/ProxyServer.ts
11
11
 
@@ -24,23 +24,53 @@ var Modes = {
24
24
  replay: "replay"
25
25
  };
26
26
  var JSON_INDENT_SPACES = 2;
27
+ var EXTENSION = ".mock.json";
28
+ var MAX_FILENAME_LENGTH = 255 - EXTENSION.length;
29
+ var HASH_LENGTH = 8;
30
+ function generateHash(str) {
31
+ return crypto.createHash("shake256", { outputLength: HASH_LENGTH / 2 }).update(str).digest("hex");
32
+ }
27
33
  function getRecordingPath(recordingsDir, id) {
28
- return path.join(recordingsDir, `${id}.mock.json`);
34
+ let processedId = id.replaceAll("/", "__");
35
+ if (processedId.length > MAX_FILENAME_LENGTH) {
36
+ const hash = generateHash(id);
37
+ const maxBaseLength = MAX_FILENAME_LENGTH - HASH_LENGTH - 1;
38
+ processedId = `${processedId.slice(0, maxBaseLength)}_${hash}`;
39
+ }
40
+ const sanitizedId = filenamify2(processedId, {
41
+ replacement: "_",
42
+ maxLength: 255
43
+ // Set explicit max to prevent filenamify's default truncation
44
+ });
45
+ return path.join(recordingsDir, `${sanitizedId}${EXTENSION}`);
29
46
  }
30
47
  async function loadRecordingSession(filePath) {
31
48
  const fileContent = await fs.readFile(filePath, "utf8");
32
49
  return JSON.parse(fileContent);
33
50
  }
51
+ function processRecordings(recordings) {
52
+ const keySequenceMap = /* @__PURE__ */ new Map();
53
+ return recordings.map((recording) => {
54
+ const key = recording.key;
55
+ const currentSeq = keySequenceMap.get(key) || 0;
56
+ keySequenceMap.set(key, currentSeq + 1);
57
+ return { ...recording, sequence: currentSeq };
58
+ });
59
+ }
34
60
  async function saveRecordingSession(recordingsDir, session) {
35
61
  const filePath = getRecordingPath(recordingsDir, session.id);
36
- const dirPath = path.dirname(filePath);
37
- await fs.mkdir(dirPath, { recursive: true });
62
+ await fs.mkdir(recordingsDir, { recursive: true });
63
+ const processedRecordings = processRecordings(session.recordings);
64
+ const processedSession = {
65
+ ...session,
66
+ recordings: processedRecordings
67
+ };
38
68
  await fs.writeFile(
39
69
  filePath,
40
- JSON.stringify(session, null, JSON_INDENT_SPACES)
70
+ JSON.stringify(processedSession, null, JSON_INDENT_SPACES)
41
71
  );
42
72
  console.log(
43
- `Saved ${session.recordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
73
+ `Saved ${processedRecordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
44
74
  );
45
75
  }
46
76
  function getReqID(req) {
@@ -48,10 +78,10 @@ function getReqID(req) {
48
78
  const pathname = urlParts[0];
49
79
  const query = urlParts[1] || "";
50
80
  const pathPart = pathname === "/" ? "root" : pathname.slice(1);
51
- const normalizedPath = filenamify(pathPart, { replacement: "_" });
81
+ const normalizedPath = filenamify2(pathPart, { replacement: "_" });
52
82
  const queryHash = generateQueryHash(query);
53
83
  const filename = `${req.method}_${normalizedPath}${queryHash}.json`;
54
- return filenamify(filename, { replacement: "_" });
84
+ return filenamify2(filename, { replacement: "_" });
55
85
  }
56
86
  function generateQueryHash(query) {
57
87
  if (!query) {
@@ -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-CjM3evKb.cjs';
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-Cx_Kflfl.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-CjM3evKb.js';
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-Cx_Kflfl.js';
3
3
  import 'node:http';
package/dist/proxy.js CHANGED
@@ -1,4 +1,4 @@
1
- import path2 from 'path';
1
+ import path from 'path';
2
2
  import { Command } from 'commander';
3
3
  import fs from 'fs/promises';
4
4
  import http from 'http';
@@ -6,7 +6,7 @@ import https from 'https';
6
6
  import httpProxy from 'http-proxy';
7
7
  import { WebSocket, WebSocketServer } from 'ws';
8
8
  import crypto from 'crypto';
9
- import filenamify from 'filenamify';
9
+ import filenamify2 from 'filenamify';
10
10
 
11
11
  // src/cli.ts
12
12
  var DEFAULT_PORT = 8e3;
@@ -39,7 +39,7 @@ function parseCliArgs() {
39
39
  if (targets2.length === 0) {
40
40
  program.help();
41
41
  }
42
- const recordingsDir2 = path2.resolve(process.cwd(), options.recordingsDir);
42
+ const recordingsDir2 = path.resolve(process.cwd(), options.recordingsDir);
43
43
  return { targets: targets2, port: port2, recordingsDir: recordingsDir2 };
44
44
  }
45
45
 
@@ -58,23 +58,53 @@ var Modes = {
58
58
  replay: "replay"
59
59
  };
60
60
  var JSON_INDENT_SPACES = 2;
61
+ var EXTENSION = ".mock.json";
62
+ var MAX_FILENAME_LENGTH = 255 - EXTENSION.length;
63
+ var HASH_LENGTH = 8;
64
+ function generateHash(str) {
65
+ return crypto.createHash("shake256", { outputLength: HASH_LENGTH / 2 }).update(str).digest("hex");
66
+ }
61
67
  function getRecordingPath(recordingsDir2, id) {
62
- return path2.join(recordingsDir2, `${id}.mock.json`);
68
+ let processedId = id.replaceAll("/", "__");
69
+ if (processedId.length > MAX_FILENAME_LENGTH) {
70
+ const hash = generateHash(id);
71
+ const maxBaseLength = MAX_FILENAME_LENGTH - HASH_LENGTH - 1;
72
+ processedId = `${processedId.slice(0, maxBaseLength)}_${hash}`;
73
+ }
74
+ const sanitizedId = filenamify2(processedId, {
75
+ replacement: "_",
76
+ maxLength: 255
77
+ // Set explicit max to prevent filenamify's default truncation
78
+ });
79
+ return path.join(recordingsDir2, `${sanitizedId}${EXTENSION}`);
63
80
  }
64
81
  async function loadRecordingSession(filePath) {
65
82
  const fileContent = await fs.readFile(filePath, "utf8");
66
83
  return JSON.parse(fileContent);
67
84
  }
85
+ function processRecordings(recordings) {
86
+ const keySequenceMap = /* @__PURE__ */ new Map();
87
+ return recordings.map((recording) => {
88
+ const key = recording.key;
89
+ const currentSeq = keySequenceMap.get(key) || 0;
90
+ keySequenceMap.set(key, currentSeq + 1);
91
+ return { ...recording, sequence: currentSeq };
92
+ });
93
+ }
68
94
  async function saveRecordingSession(recordingsDir2, session) {
69
95
  const filePath = getRecordingPath(recordingsDir2, session.id);
70
- const dirPath = path2.dirname(filePath);
71
- await fs.mkdir(dirPath, { recursive: true });
96
+ await fs.mkdir(recordingsDir2, { recursive: true });
97
+ const processedRecordings = processRecordings(session.recordings);
98
+ const processedSession = {
99
+ ...session,
100
+ recordings: processedRecordings
101
+ };
72
102
  await fs.writeFile(
73
103
  filePath,
74
- JSON.stringify(session, null, JSON_INDENT_SPACES)
104
+ JSON.stringify(processedSession, null, JSON_INDENT_SPACES)
75
105
  );
76
106
  console.log(
77
- `Saved ${session.recordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
107
+ `Saved ${processedRecordings.length} HTTP recordings and ${session.websocketRecordings?.length || 0} WebSocket recordings to ${filePath}`
78
108
  );
79
109
  }
80
110
  function getReqID(req) {
@@ -82,10 +112,10 @@ function getReqID(req) {
82
112
  const pathname = urlParts[0];
83
113
  const query = urlParts[1] || "";
84
114
  const pathPart = pathname === "/" ? "root" : pathname.slice(1);
85
- const normalizedPath = filenamify(pathPart, { replacement: "_" });
115
+ const normalizedPath = filenamify2(pathPart, { replacement: "_" });
86
116
  const queryHash = generateQueryHash(query);
87
117
  const filename = `${req.method}_${normalizedPath}${queryHash}.json`;
88
- return filenamify(filename, { replacement: "_" });
118
+ return filenamify2(filename, { replacement: "_" });
89
119
  }
90
120
  function generateQueryHash(query) {
91
121
  if (!query) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "test-proxy-recorder",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "HTTP proxy server for recording and replaying network requests in testing. Works seamlessly with Playwright testing framework.",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",