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.
- package/dist/{index-CjM3evKb.d.cts → index-Cx_Kflfl.d.cts} +1 -0
- package/dist/{index-CjM3evKb.d.ts → index-Cx_Kflfl.d.ts} +1 -0
- package/dist/index.cjs +41 -11
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +39 -9
- package/dist/playwright/index.d.cts +1 -1
- package/dist/playwright/index.d.ts +1 -1
- package/dist/proxy.js +40 -10
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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(
|
|
82
|
+
JSON.stringify(processedSession, null, JSON_INDENT_SPACES)
|
|
53
83
|
);
|
|
54
84
|
console.log(
|
|
55
|
-
`Saved ${
|
|
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 =
|
|
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
|
|
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-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
37
|
-
|
|
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(
|
|
70
|
+
JSON.stringify(processedSession, null, JSON_INDENT_SPACES)
|
|
41
71
|
);
|
|
42
72
|
console.log(
|
|
43
|
-
`Saved ${
|
|
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 =
|
|
81
|
+
const normalizedPath = filenamify2(pathPart, { replacement: "_" });
|
|
52
82
|
const queryHash = generateQueryHash(query);
|
|
53
83
|
const filename = `${req.method}_${normalizedPath}${queryHash}.json`;
|
|
54
|
-
return
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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(
|
|
104
|
+
JSON.stringify(processedSession, null, JSON_INDENT_SPACES)
|
|
75
105
|
);
|
|
76
106
|
console.log(
|
|
77
|
-
`Saved ${
|
|
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 =
|
|
115
|
+
const normalizedPath = filenamify2(pathPart, { replacement: "_" });
|
|
86
116
|
const queryHash = generateQueryHash(query);
|
|
87
117
|
const filename = `${req.method}_${normalizedPath}${queryHash}.json`;
|
|
88
|
-
return
|
|
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.
|
|
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",
|