curltrim 0.1.0

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.
Files changed (47) hide show
  1. package/README.md +96 -0
  2. package/dist/src/assertions.d.ts +6 -0
  3. package/dist/src/assertions.js +176 -0
  4. package/dist/src/assertions.js.map +1 -0
  5. package/dist/src/candidates.d.ts +3 -0
  6. package/dist/src/candidates.js +74 -0
  7. package/dist/src/candidates.js.map +1 -0
  8. package/dist/src/cli.d.ts +4 -0
  9. package/dist/src/cli.js +168 -0
  10. package/dist/src/cli.js.map +1 -0
  11. package/dist/src/config.d.ts +5 -0
  12. package/dist/src/config.js +87 -0
  13. package/dist/src/config.js.map +1 -0
  14. package/dist/src/curl-parser.d.ts +2 -0
  15. package/dist/src/curl-parser.js +110 -0
  16. package/dist/src/curl-parser.js.map +1 -0
  17. package/dist/src/index.d.ts +10 -0
  18. package/dist/src/index.js +11 -0
  19. package/dist/src/index.js.map +1 -0
  20. package/dist/src/inspect.d.ts +2 -0
  21. package/dist/src/inspect.js +29 -0
  22. package/dist/src/inspect.js.map +1 -0
  23. package/dist/src/interactive.d.ts +56 -0
  24. package/dist/src/interactive.js +181 -0
  25. package/dist/src/interactive.js.map +1 -0
  26. package/dist/src/json-output.d.ts +3 -0
  27. package/dist/src/json-output.js +27 -0
  28. package/dist/src/json-output.js.map +1 -0
  29. package/dist/src/minimizer.d.ts +10 -0
  30. package/dist/src/minimizer.js +61 -0
  31. package/dist/src/minimizer.js.map +1 -0
  32. package/dist/src/render-curl.d.ts +2 -0
  33. package/dist/src/render-curl.js +53 -0
  34. package/dist/src/render-curl.js.map +1 -0
  35. package/dist/src/replayer.d.ts +2 -0
  36. package/dist/src/replayer.js +82 -0
  37. package/dist/src/replayer.js.map +1 -0
  38. package/dist/src/request-rendering.d.ts +6 -0
  39. package/dist/src/request-rendering.js +31 -0
  40. package/dist/src/request-rendering.js.map +1 -0
  41. package/dist/src/terminal.d.ts +19 -0
  42. package/dist/src/terminal.js +187 -0
  43. package/dist/src/terminal.js.map +1 -0
  44. package/dist/src/types.d.ts +121 -0
  45. package/dist/src/types.js +2 -0
  46. package/dist/src/types.js.map +1 -0
  47. package/package.json +40 -0
@@ -0,0 +1,2 @@
1
+ import type { RequestModel } from "./types.js";
2
+ export declare function parseCurlCommand(curlCommand: string): RequestModel;
@@ -0,0 +1,110 @@
1
+ import { toJsonObject } from "curlconverter";
2
+ export function parseCurlCommand(curlCommand) {
3
+ const parsed = toJsonObject(curlCommand);
4
+ const headers = normalizeHeaders(parsed.headers ?? {});
5
+ const cookies = normalizeCookies(parsed.cookies ?? {}, headers);
6
+ const url = new URL(parsed.raw_url);
7
+ const query = normalizeQuery(url.searchParams);
8
+ url.search = "";
9
+ const requestBody = normalizeBody(parsed.data, headers);
10
+ return {
11
+ method: (parsed.method || inferMethod(requestBody.bodyType)).toUpperCase(),
12
+ url: normalizeUrl(url),
13
+ followRedirects: parsed.follow_redirects === true,
14
+ headers,
15
+ cookies,
16
+ query,
17
+ ...requestBody
18
+ };
19
+ }
20
+ function normalizeHeaders(headers) {
21
+ return Object.fromEntries(Object.entries(headers)
22
+ .filter((entry) => entry[1] !== null)
23
+ .map(([key, value]) => [key.toLowerCase(), value]));
24
+ }
25
+ function normalizeCookies(parsedCookies, headers) {
26
+ const headerCookies = parseCookieHeader(headers.cookie);
27
+ delete headers.cookie;
28
+ return {
29
+ ...headerCookies,
30
+ ...parsedCookies
31
+ };
32
+ }
33
+ function parseCookieHeader(cookieHeader) {
34
+ if (!cookieHeader) {
35
+ return {};
36
+ }
37
+ return Object.fromEntries(cookieHeader
38
+ .split(";")
39
+ .map((part) => part.trim())
40
+ .filter(Boolean)
41
+ .map((part) => {
42
+ const separatorIndex = part.indexOf("=");
43
+ if (separatorIndex === -1) {
44
+ return [part, ""];
45
+ }
46
+ return [part.slice(0, separatorIndex), part.slice(separatorIndex + 1)];
47
+ }));
48
+ }
49
+ function normalizeQuery(searchParams) {
50
+ const query = {};
51
+ for (const [key, value] of searchParams) {
52
+ const existingValue = query[key];
53
+ if (existingValue === undefined) {
54
+ query[key] = value;
55
+ }
56
+ else if (Array.isArray(existingValue)) {
57
+ existingValue.push(value);
58
+ }
59
+ else {
60
+ query[key] = [existingValue, value];
61
+ }
62
+ }
63
+ return query;
64
+ }
65
+ function normalizeUrl(url) {
66
+ const serializedUrl = url.toString();
67
+ return url.pathname === "/" ? serializedUrl.replace(/\/$/, "") : serializedUrl;
68
+ }
69
+ function normalizeBody(data, headers) {
70
+ if (data === undefined) {
71
+ return { body: undefined, bodyType: "none" };
72
+ }
73
+ const contentType = headers["content-type"]?.toLowerCase() ?? "";
74
+ if (typeof data === "string") {
75
+ if (contentType.includes("application/x-www-form-urlencoded")) {
76
+ const urlencodedBody = parseUrlEncodedBody(data);
77
+ if (urlencodedBody !== undefined) {
78
+ return { body: urlencodedBody, bodyType: "urlencoded" };
79
+ }
80
+ return { body: data, bodyType: "raw" };
81
+ }
82
+ if (contentType.includes("application/json")) {
83
+ try {
84
+ return { body: JSON.parse(data), bodyType: "json" };
85
+ }
86
+ catch {
87
+ return { body: data, bodyType: "raw" };
88
+ }
89
+ }
90
+ return { body: data, bodyType: "raw" };
91
+ }
92
+ if (contentType.includes("application/json")) {
93
+ return { body: data, bodyType: "json" };
94
+ }
95
+ if (contentType.includes("application/x-www-form-urlencoded")) {
96
+ return { body: data, bodyType: "urlencoded" };
97
+ }
98
+ return { body: data, bodyType: "form" };
99
+ }
100
+ function parseUrlEncodedBody(data) {
101
+ const parts = data.split("&");
102
+ if (!parts.every((part) => part.indexOf("=") > 0)) {
103
+ return undefined;
104
+ }
105
+ return Object.fromEntries(new URLSearchParams(data));
106
+ }
107
+ function inferMethod(bodyType) {
108
+ return bodyType === "none" ? "GET" : "POST";
109
+ }
110
+ //# sourceMappingURL=curl-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curl-parser.js","sourceRoot":"","sources":["../../src/curl-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export * from "./types.js";
2
+ export * from "./config.js";
3
+ export * from "./assertions.js";
4
+ export * from "./curl-parser.js";
5
+ export * from "./candidates.js";
6
+ export * from "./render-curl.js";
7
+ export * from "./replayer.js";
8
+ export * from "./minimizer.js";
9
+ export * from "./inspect.js";
10
+ export * from "./json-output.js";
@@ -0,0 +1,11 @@
1
+ export * from "./types.js";
2
+ export * from "./config.js";
3
+ export * from "./assertions.js";
4
+ export * from "./curl-parser.js";
5
+ export * from "./candidates.js";
6
+ export * from "./render-curl.js";
7
+ export * from "./replayer.js";
8
+ export * from "./minimizer.js";
9
+ export * from "./inspect.js";
10
+ export * from "./json-output.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AssertionConfig, InspectSummary, RequestModel, Target } from "./types.js";
2
+ export declare function buildInspectSummary(request: RequestModel, targets: Target[], assertions: AssertionConfig): InspectSummary;
@@ -0,0 +1,29 @@
1
+ import { createCandidates } from "./candidates.js";
2
+ export function buildInspectSummary(request, targets, assertions) {
3
+ const candidates = createCandidates(request, targets);
4
+ return {
5
+ method: request.method,
6
+ url: request.url,
7
+ followRedirects: request.followRedirects,
8
+ headers: summarizeRecord(request.headers),
9
+ cookies: summarizeRecord(request.cookies),
10
+ query: summarizeRecord(request.query),
11
+ body: summarizeBody(request),
12
+ targets,
13
+ assertions,
14
+ candidateCount: candidates.length,
15
+ estimatedReplayCount: candidates.length + 1
16
+ };
17
+ }
18
+ function summarizeRecord(record) {
19
+ const keys = Object.keys(record);
20
+ return { count: keys.length, keys };
21
+ }
22
+ function summarizeBody(request) {
23
+ if (request.body !== null && typeof request.body === "object" && !Array.isArray(request.body)) {
24
+ const keys = Object.keys(request.body);
25
+ return { type: request.bodyType, candidateCount: keys.length, keys };
26
+ }
27
+ return { type: request.bodyType, candidateCount: 0, keys: [] };
28
+ }
29
+ //# sourceMappingURL=inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/inspect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAUnD,MAAM,UAAU,mBAAmB,CACjC,OAAqB,EACrB,OAAiB,EACjB,UAA2B;IAE3B,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAEtD,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;QACzC,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;QACzC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC;QACrC,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC;QAC5B,OAAO;QACP,UAAU;QACV,cAAc,EAAE,UAAU,CAAC,MAAM;QACjC,oBAAoB,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAA+B;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,aAAa,CAAC,OAAqB;IAC1C,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9F,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IACvE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACjE,CAAC"}
@@ -0,0 +1,56 @@
1
+ import type { CliConfig, Target } from "./types.js";
2
+ type InputMode = "paste" | "file";
3
+ type RunMode = "trim" | "inspect";
4
+ type OutputFormat = "terminal" | "json";
5
+ type SelectValue = InputMode | RunMode | OutputFormat;
6
+ type SelectChoice<T extends string> = T | {
7
+ name: string;
8
+ value: T;
9
+ };
10
+ type CheckboxChoice<T extends string> = T | {
11
+ name: string;
12
+ value: T;
13
+ checked?: boolean;
14
+ };
15
+ interface SelectPromptConfig<T extends string = SelectValue> {
16
+ message: string;
17
+ choices: readonly SelectChoice<T>[];
18
+ default?: T;
19
+ }
20
+ interface InputPromptConfig {
21
+ message: string;
22
+ default?: string;
23
+ required?: boolean;
24
+ }
25
+ interface EditorPromptConfig {
26
+ message: string;
27
+ default?: string;
28
+ required?: boolean;
29
+ }
30
+ interface CheckboxPromptConfig<T extends string> {
31
+ message: string;
32
+ choices: readonly CheckboxChoice<T>[];
33
+ }
34
+ interface ConfirmPromptConfig {
35
+ message: string;
36
+ default?: boolean;
37
+ }
38
+ interface ErrorPromptConfig {
39
+ message: string;
40
+ }
41
+ export interface PromptApi {
42
+ select<T extends SelectValue>(config: SelectPromptConfig<T>): Promise<T>;
43
+ input(config: InputPromptConfig): Promise<string>;
44
+ editor(config: EditorPromptConfig): Promise<string>;
45
+ checkbox(config: CheckboxPromptConfig<Target>): Promise<Target[]>;
46
+ confirm(config: ConfirmPromptConfig): Promise<boolean>;
47
+ error(config: ErrorPromptConfig): void;
48
+ }
49
+ export interface InteractiveOptions {
50
+ plain?: boolean;
51
+ inspect?: boolean;
52
+ json?: boolean;
53
+ }
54
+ export declare function runInteractive(options?: InteractiveOptions): Promise<CliConfig>;
55
+ export declare function collectInteractiveConfig(prompts: PromptApi, options?: InteractiveOptions): Promise<CliConfig>;
56
+ export {};
@@ -0,0 +1,181 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { checkbox, confirm, editor, input, select } from "@inquirer/prompts";
3
+ import { DEFAULT_TARGETS, parseTargets } from "./config.js";
4
+ import { parseCurlCommand } from "./curl-parser.js";
5
+ const defaultPrompts = {
6
+ select: (config) => select(config),
7
+ input: (config) => input(config),
8
+ editor: (config) => editor(config),
9
+ checkbox: (config) => checkbox(config),
10
+ confirm: (config) => confirm(config),
11
+ error: (config) => console.error(config.message)
12
+ };
13
+ export async function runInteractive(options = { plain: false }) {
14
+ if (!process.stdin.isTTY) {
15
+ throw new Error("No curl input provided. Pass a curl command, use --file, or run curltrim in an interactive TTY.");
16
+ }
17
+ return collectInteractiveConfig(defaultPrompts, options);
18
+ }
19
+ export async function collectInteractiveConfig(prompts, options = {}) {
20
+ const curlCommand = await readValidatedCurlCommand(prompts);
21
+ const output = await collectOutputOptions(prompts, options);
22
+ if (output.inspect) {
23
+ return {
24
+ curlCommand: curlCommand.trim(),
25
+ targets: [...DEFAULT_TARGETS],
26
+ assertions: {
27
+ text: [],
28
+ regex: [],
29
+ json: []
30
+ },
31
+ delayMs: 0,
32
+ plain: Boolean(options.plain),
33
+ inspect: true,
34
+ json: output.json
35
+ };
36
+ }
37
+ const selectedTargets = await prompts.checkbox({
38
+ message: "Targets to trim",
39
+ choices: [
40
+ { name: "cookies", value: "cookies", checked: true },
41
+ { name: "headers", value: "headers", checked: true },
42
+ { name: "query", value: "query" },
43
+ { name: "body", value: "body" }
44
+ ]
45
+ });
46
+ const status = await prompts.input({
47
+ message: "Expected HTTP status",
48
+ default: "200-299"
49
+ });
50
+ const text = splitPromptList(await prompts.input({ message: "Expected text contains, one per line or empty" }));
51
+ const regex = splitPromptList(await prompts.input({ message: "Expected regex, one per line or empty" }));
52
+ const json = splitPromptList(await prompts.input({
53
+ message: "Expected JSONPath assertions, one per line or empty"
54
+ }));
55
+ const delay = await prompts.input({
56
+ message: "Request delay in milliseconds",
57
+ default: "0"
58
+ });
59
+ const delayMs = parseDelay(delay);
60
+ const accepted = await prompts.confirm({
61
+ message: "Start replay and trimming now?",
62
+ default: true
63
+ });
64
+ if (!accepted) {
65
+ throw new Error("Interactive configuration cancelled");
66
+ }
67
+ return {
68
+ curlCommand: curlCommand.trim(),
69
+ targets: parseTargets(selectedTargets.length > 0 ? selectedTargets.join(",") : undefined),
70
+ assertions: {
71
+ status: status.trim() || "200-299",
72
+ text,
73
+ regex,
74
+ json
75
+ },
76
+ delayMs,
77
+ plain: Boolean(options.plain),
78
+ inspect: false,
79
+ json: output.json
80
+ };
81
+ }
82
+ async function collectOutputOptions(prompts, options) {
83
+ if (options.inspect !== undefined || options.json !== undefined) {
84
+ return {
85
+ inspect: Boolean(options.inspect),
86
+ json: Boolean(options.json)
87
+ };
88
+ }
89
+ const runMode = await prompts.select({
90
+ message: "Run mode",
91
+ choices: [
92
+ { name: "Trim request", value: "trim" },
93
+ { name: "Inspect only", value: "inspect" }
94
+ ],
95
+ default: "trim"
96
+ });
97
+ const outputFormat = await prompts.select({
98
+ message: "Output format",
99
+ choices: [
100
+ { name: "Terminal", value: "terminal" },
101
+ { name: "JSON", value: "json" }
102
+ ],
103
+ default: "terminal"
104
+ });
105
+ return {
106
+ inspect: runMode === "inspect",
107
+ json: outputFormat === "json"
108
+ };
109
+ }
110
+ async function readValidatedCurlCommand(prompts) {
111
+ while (true) {
112
+ const inputMode = await prompts.select({
113
+ message: "How do you want to provide the curl request?",
114
+ choices: [
115
+ { name: "Paste curl text", value: "paste" },
116
+ { name: "Read from file", value: "file" }
117
+ ],
118
+ default: "paste"
119
+ });
120
+ const result = inputMode === "file" ? await readCurlFile(prompts) : await readCurlText(prompts);
121
+ if (!result.ok) {
122
+ switch (result.kind) {
123
+ case "read":
124
+ prompts.error({ message: `Unable to read curl file: ${result.error}` });
125
+ continue;
126
+ }
127
+ }
128
+ const error = validateCurlCommand(result.value);
129
+ if (error === undefined) {
130
+ return result.value.trim();
131
+ }
132
+ prompts.error({ message: `Invalid curl command: ${error}` });
133
+ }
134
+ }
135
+ async function readCurlFile(prompts) {
136
+ const filePath = (await prompts.input({ message: "curl file path", required: true })).trim();
137
+ try {
138
+ return { ok: true, value: await readFile(filePath, "utf8") };
139
+ }
140
+ catch (error) {
141
+ return { ok: false, kind: "read", error: formatError(error) };
142
+ }
143
+ }
144
+ async function readCurlText(prompts) {
145
+ return {
146
+ ok: true,
147
+ value: await prompts.editor({
148
+ message: "curl command, paste text then save and exit",
149
+ required: true
150
+ })
151
+ };
152
+ }
153
+ function validateCurlCommand(curlCommand) {
154
+ if (!curlCommand.trim()) {
155
+ return "curl command is empty";
156
+ }
157
+ try {
158
+ parseCurlCommand(curlCommand);
159
+ return undefined;
160
+ }
161
+ catch (error) {
162
+ return formatError(error);
163
+ }
164
+ }
165
+ function splitPromptList(value) {
166
+ return value
167
+ .split(/\r?\n/)
168
+ .map((item) => item.trim())
169
+ .filter(Boolean);
170
+ }
171
+ function parseDelay(value) {
172
+ const delayMs = Number(value.trim() || "0");
173
+ if (!Number.isInteger(delayMs) || delayMs < 0) {
174
+ throw new Error("Delay must be a non-negative integer");
175
+ }
176
+ return delayMs;
177
+ }
178
+ function formatError(error) {
179
+ return error instanceof Error ? error.message : String(error);
180
+ }
181
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { InspectSummary, TrimResult } from "./types.js";
2
+ export declare function renderInspectJson(summary: InspectSummary): string;
3
+ export declare function renderTrimJson(result: TrimResult): string;
@@ -0,0 +1,27 @@
1
+ export function renderInspectJson(summary) {
2
+ return renderJson({
3
+ mode: "inspect",
4
+ requestSummary: summary,
5
+ targets: summary.targets,
6
+ assertions: summary.assertions,
7
+ candidateCount: summary.candidateCount,
8
+ estimatedReplayCount: summary.estimatedReplayCount
9
+ });
10
+ }
11
+ export function renderTrimJson(result) {
12
+ return renderJson({
13
+ mode: "trim",
14
+ originalOk: result.originalOk,
15
+ removed: result.removed,
16
+ kept: result.kept,
17
+ finalCurl: result.finalCurl,
18
+ finalRequest: {
19
+ ...result.finalRequest,
20
+ body: result.finalRequest.body === undefined ? null : result.finalRequest.body
21
+ }
22
+ });
23
+ }
24
+ function renderJson(value) {
25
+ return `${JSON.stringify(value, null, 2)}\n`;
26
+ }
27
+ //# sourceMappingURL=json-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-output.js","sourceRoot":"","sources":["../../src/json-output.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,OAAuB;IACvD,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,SAAS;QACf,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;KACnD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE;YACZ,GAAG,MAAM,CAAC,YAAY;YACtB,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI;SAC/E;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AssertionConfig, MinimizeProgressEvent, ReplayResponse, RequestModel, Target, TrimResult } from "./types.js";
2
+ export interface MinimizeOptions {
3
+ request: RequestModel;
4
+ targets: Target[];
5
+ assertions: AssertionConfig;
6
+ delayMs: number;
7
+ replay(request: RequestModel, delayMs: number): Promise<ReplayResponse>;
8
+ onProgress?(event: MinimizeProgressEvent): void;
9
+ }
10
+ export declare function minimizeRequest(options: MinimizeOptions): Promise<TrimResult>;
@@ -0,0 +1,61 @@
1
+ import { assertReplaySuccess } from "./assertions.js";
2
+ import { createCandidates, removeCandidate } from "./candidates.js";
3
+ import { renderCurl } from "./render-curl.js";
4
+ export async function minimizeRequest(options) {
5
+ options.onProgress?.({ type: "original:start", label: "original request" });
6
+ const original = await replaySafely(options, options.request);
7
+ if (!original.ok) {
8
+ options.onProgress?.({
9
+ type: "original:failure",
10
+ label: "original request",
11
+ error: formatFailure(original.error)
12
+ });
13
+ throw new Error(`Original request did not satisfy success assertions: ${formatFailure(original.error)}`);
14
+ }
15
+ options.onProgress?.({ type: "original:success", label: "original request" });
16
+ let current = options.request;
17
+ const removed = [];
18
+ const kept = [];
19
+ const candidates = createCandidates(current, options.targets);
20
+ for (const [offset, candidate] of candidates.entries()) {
21
+ const index = offset + 1;
22
+ const total = candidates.length;
23
+ options.onProgress?.({ type: "candidate:start", index, total, label: candidate.label });
24
+ const next = removeCandidate(current, candidate);
25
+ const result = await replaySafely(options, next);
26
+ if (result.ok) {
27
+ current = next;
28
+ removed.push({ ...candidate, ok: true });
29
+ options.onProgress?.({ type: "candidate:removed", index, total, label: candidate.label });
30
+ }
31
+ else {
32
+ const error = formatFailure(result.error);
33
+ kept.push({ ...candidate, ok: false, error });
34
+ options.onProgress?.({ type: "candidate:kept", index, total, label: candidate.label, error });
35
+ }
36
+ }
37
+ return {
38
+ originalOk: true,
39
+ removed,
40
+ kept,
41
+ finalRequest: current,
42
+ finalCurl: renderCurl(current)
43
+ };
44
+ }
45
+ async function replaySafely(options, request) {
46
+ try {
47
+ const response = await options.replay(request, options.delayMs);
48
+ const result = assertReplaySuccess(response, options.assertions);
49
+ return result.ok ? { ok: true } : { ok: false, error: result.reasons.join("; ") };
50
+ }
51
+ catch (error) {
52
+ return { ok: false, error: formatError(error) };
53
+ }
54
+ }
55
+ function formatFailure(reason) {
56
+ return reason || "success assertions failed";
57
+ }
58
+ function formatError(error) {
59
+ return error instanceof Error ? error.message : String(error);
60
+ }
61
+ //# sourceMappingURL=minimizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minimizer.js","sourceRoot":"","sources":["../../src/minimizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { RequestModel } from "./types.js";
2
+ export declare function renderCurl(request: RequestModel): string;
@@ -0,0 +1,53 @@
1
+ import { renderCookieHeader, renderRequestUrl, renderUrlEncodedBody } from "./request-rendering.js";
2
+ export function renderCurl(request) {
3
+ const parts = ["curl"];
4
+ const method = request.method.toUpperCase();
5
+ if (request.followRedirects) {
6
+ parts.push("-L");
7
+ }
8
+ parts.push(shellQuote(renderRequestUrl(request)));
9
+ if (method !== "GET") {
10
+ parts.push("-X", method);
11
+ }
12
+ for (const [key, value] of Object.entries(request.headers)) {
13
+ if (key.toLowerCase() !== "cookie") {
14
+ parts.push("-H", shellQuote(`${key}: ${value}`));
15
+ }
16
+ }
17
+ const cookieHeader = renderCookieHeader(request.cookies);
18
+ if (cookieHeader) {
19
+ parts.push("-H", shellQuote(`Cookie: ${cookieHeader}`));
20
+ }
21
+ parts.push(...renderBodyParts(request));
22
+ return parts.join(" ");
23
+ }
24
+ function renderBodyParts(request) {
25
+ if (request.bodyType === "none") {
26
+ return [];
27
+ }
28
+ if (request.bodyType === "form") {
29
+ return renderFormFields(request.body).flatMap((field) => ["-F", shellQuote(field)]);
30
+ }
31
+ if (request.bodyType === "json") {
32
+ return ["--data", shellQuote(JSON.stringify(request.body) ?? String(request.body))];
33
+ }
34
+ if (request.bodyType === "urlencoded") {
35
+ return ["--data", shellQuote(renderUrlEncodedBody(request.body))];
36
+ }
37
+ return ["--data", shellQuote(String(request.body))];
38
+ }
39
+ function renderFormFields(body) {
40
+ if (body !== null && typeof body === "object" && !Array.isArray(body)) {
41
+ return Object.entries(body).flatMap(([key, value]) => {
42
+ if (Array.isArray(value)) {
43
+ return value.map((item) => `${key}=${String(item)}`);
44
+ }
45
+ return `${key}=${String(value)}`;
46
+ });
47
+ }
48
+ return [String(body)];
49
+ }
50
+ function shellQuote(value) {
51
+ return `'${value.replaceAll("'", "'\\''")}'`;
52
+ }
53
+ //# sourceMappingURL=render-curl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-curl.js","sourceRoot":"","sources":["../../src/render-curl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ReplayResponse, RequestModel } from "./types.js";
2
+ export declare function replayRequest(request: RequestModel, delayMs: number): Promise<ReplayResponse>;