@jaredwray/mockhttp 1.8.1 → 1.9.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.
- package/dist/index.d.mts +45 -22
- package/dist/index.mjs +169 -113
- package/package.json +14 -14
package/dist/index.d.mts
CHANGED
|
@@ -1,34 +1,51 @@
|
|
|
1
1
|
import { RateLimitPluginOptions } from "@fastify/rate-limit";
|
|
2
2
|
import { FastifyInstance, FastifyRequest } from "fastify";
|
|
3
3
|
import { Hookified, HookifiedOptions } from "hookified";
|
|
4
|
-
|
|
5
4
|
//#region src/bin-store.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* A request captured by a bin, including method, headers, body and metadata.
|
|
8
7
|
*/
|
|
9
8
|
type CapturedRequest = {
|
|
10
|
-
/** Unique identifier for this captured request */
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
/** Unique identifier for this captured request */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Identifier of the bin that captured this request */
|
|
12
|
+
binId: string;
|
|
13
|
+
/** HTTP method (GET, POST, etc.) */
|
|
14
|
+
method: string;
|
|
15
|
+
/** Request URL path + query, relative to the bin (e.g. "/foo?x=1") */
|
|
16
|
+
url: string;
|
|
17
|
+
/** Sub-path after the bin id ("/" if the request hit the bin root) */
|
|
18
|
+
path: string;
|
|
19
|
+
/** Parsed query string parameters */
|
|
20
|
+
query: Record<string, string | string[]>;
|
|
21
|
+
/** Request headers */
|
|
22
|
+
headers: Record<string, string | string[]>;
|
|
23
|
+
/** Client IP address as reported by Fastify */
|
|
24
|
+
remoteAddress: string;
|
|
25
|
+
/** Content-Type header value, if any */
|
|
26
|
+
contentType?: string;
|
|
27
|
+
/** Original body length in bytes */
|
|
28
|
+
bodySize: number;
|
|
29
|
+
/** Body payload as utf8 text, base64-encoded bytes, or null when empty */
|
|
30
|
+
body: string | null;
|
|
31
|
+
/** Encoding used for the `body` field */
|
|
32
|
+
bodyEncoding: "utf8" | "base64" | "none";
|
|
33
|
+
/** True if the body was longer than the configured `maxBodySize` */
|
|
34
|
+
truncated: boolean;
|
|
35
|
+
/** ISO timestamp of when the request was captured */
|
|
23
36
|
capturedAt: string;
|
|
24
37
|
};
|
|
25
38
|
/**
|
|
26
39
|
* Metadata for a bin (without its captured requests).
|
|
27
40
|
*/
|
|
28
41
|
type Bin = {
|
|
29
|
-
/** Unique short identifier for the bin */
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
/** Unique short identifier for the bin */
|
|
43
|
+
id: string;
|
|
44
|
+
/** ISO timestamp of bin creation */
|
|
45
|
+
createdAt: string;
|
|
46
|
+
/** ISO timestamp at which the bin expires */
|
|
47
|
+
expiresAt: string;
|
|
48
|
+
/** Number of requests currently stored in the bin */
|
|
32
49
|
requestCount: number;
|
|
33
50
|
};
|
|
34
51
|
/**
|
|
@@ -85,11 +102,17 @@ declare class InMemoryBinStore implements BinStore {
|
|
|
85
102
|
* Configuration options for {@link BinManager}.
|
|
86
103
|
*/
|
|
87
104
|
type BinManagerOptions = {
|
|
88
|
-
/** Storage backend. Defaults to a new {@link InMemoryBinStore}. */
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
105
|
+
/** Storage backend. Defaults to a new {@link InMemoryBinStore}. */
|
|
106
|
+
store?: BinStore;
|
|
107
|
+
/** Bin lifetime in milliseconds. Defaults to 24 hours. */
|
|
108
|
+
defaultTtlMs?: number;
|
|
109
|
+
/** Maximum number of requests retained per bin (FIFO). Defaults to 100. */
|
|
110
|
+
maxRequestsPerBin?: number;
|
|
111
|
+
/** Maximum captured body size in bytes. Larger bodies are truncated. Defaults to 1 MiB. */
|
|
112
|
+
maxBodySize?: number;
|
|
113
|
+
/** Length of generated bin and request ids. Defaults to 12. */
|
|
114
|
+
idLength?: number;
|
|
115
|
+
/** Interval between cleanup sweeps in milliseconds. Defaults to 1 minute. */
|
|
93
116
|
cleanupIntervalMs?: number;
|
|
94
117
|
};
|
|
95
118
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -70,9 +70,9 @@ var InMemoryBinStore = class {
|
|
|
70
70
|
};
|
|
71
71
|
//#endregion
|
|
72
72
|
//#region src/bin-manager.ts
|
|
73
|
-
const DEFAULT_TTL_MS =
|
|
73
|
+
const DEFAULT_TTL_MS = 864e5;
|
|
74
74
|
const DEFAULT_MAX_REQUESTS = 100;
|
|
75
|
-
const DEFAULT_MAX_BODY_SIZE =
|
|
75
|
+
const DEFAULT_MAX_BODY_SIZE = 1048576;
|
|
76
76
|
const DEFAULT_ID_LENGTH = 12;
|
|
77
77
|
const DEFAULT_CLEANUP_INTERVAL_MS = 6e4;
|
|
78
78
|
/**
|
|
@@ -228,18 +228,19 @@ function encodeSet(...elements) {
|
|
|
228
228
|
}
|
|
229
229
|
function encodeInteger(value) {
|
|
230
230
|
let buf;
|
|
231
|
-
if (typeof value === "number")
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
231
|
+
if (typeof value === "number") {
|
|
232
|
+
if (value === 0) buf = Buffer.from([0]);
|
|
233
|
+
else {
|
|
234
|
+
const bytes = [];
|
|
235
|
+
let temp = value;
|
|
236
|
+
while (temp > 0) {
|
|
237
|
+
bytes.unshift(temp & 255);
|
|
238
|
+
temp >>= 8;
|
|
239
|
+
}
|
|
240
|
+
if (bytes[0] & 128) bytes.unshift(0);
|
|
241
|
+
buf = Buffer.from(bytes);
|
|
242
|
+
}
|
|
243
|
+
} else if (value.length > 0 && value[0] & 128) buf = Buffer.concat([Buffer.from([0]), value]);
|
|
243
244
|
else buf = value;
|
|
244
245
|
return encodeTlv(2, buf);
|
|
245
246
|
}
|
|
@@ -690,7 +691,7 @@ const bearerAuthRoute = (fastify) => {
|
|
|
690
691
|
//#endregion
|
|
691
692
|
//#region src/routes/auth/digest.ts
|
|
692
693
|
const makeNonce = () => crypto.randomBytes(16).toString("hex");
|
|
693
|
-
const algorithms = new Set([
|
|
694
|
+
const algorithms = /* @__PURE__ */ new Set([
|
|
694
695
|
"MD5",
|
|
695
696
|
"md5",
|
|
696
697
|
"SHA-256",
|
|
@@ -1374,7 +1375,7 @@ function generateSeededBytes$1(n, seed) {
|
|
|
1374
1375
|
for (let i = 0; i < n; i++) bytes[i] = Math.floor(random() * 256);
|
|
1375
1376
|
return bytes;
|
|
1376
1377
|
}
|
|
1377
|
-
const MAX_BYTES$3 =
|
|
1378
|
+
const MAX_BYTES$3 = 102400;
|
|
1378
1379
|
const bytesRoute = (fastify) => {
|
|
1379
1380
|
fastify.get("/bytes/:n", { schema: bytesSchema }, async (request, reply) => {
|
|
1380
1381
|
const n = Number.parseInt(request.params.n, 10);
|
|
@@ -1501,7 +1502,7 @@ const DEFAULT_CODE = 200;
|
|
|
1501
1502
|
const DEFAULT_DELAY = 2;
|
|
1502
1503
|
const MAX_DURATION = 10;
|
|
1503
1504
|
const MAX_DELAY = 10;
|
|
1504
|
-
const MAX_BYTES$2 =
|
|
1505
|
+
const MAX_BYTES$2 = 10485760;
|
|
1505
1506
|
const dripRoute = (fastify) => {
|
|
1506
1507
|
fastify.get("/drip", { schema: dripSchema }, async (request, reply) => {
|
|
1507
1508
|
/* v8 ignore next 2 -- @preserve */
|
|
@@ -1627,7 +1628,7 @@ const rangeSchema = {
|
|
|
1627
1628
|
}
|
|
1628
1629
|
}
|
|
1629
1630
|
};
|
|
1630
|
-
const MAX_BYTES$1 =
|
|
1631
|
+
const MAX_BYTES$1 = 102400;
|
|
1631
1632
|
function sleep(ms) {
|
|
1632
1633
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1633
1634
|
}
|
|
@@ -1808,7 +1809,7 @@ function generateSeededBytes(n, seed) {
|
|
|
1808
1809
|
for (let i = 0; i < n; i++) bytes[i] = Math.floor(random() * 256);
|
|
1809
1810
|
return bytes;
|
|
1810
1811
|
}
|
|
1811
|
-
const MAX_BYTES =
|
|
1812
|
+
const MAX_BYTES = 102400;
|
|
1812
1813
|
const DEFAULT_CHUNK_SIZE = 10240;
|
|
1813
1814
|
const streamBytesRoute = (fastify) => {
|
|
1814
1815
|
fastify.get("/stream-bytes/:n", { schema: streamBytesSchema }, async (request, reply) => {
|
|
@@ -2115,7 +2116,8 @@ const imageRoutes = (fastify) => {
|
|
|
2115
2116
|
contentType = "image/png";
|
|
2116
2117
|
}
|
|
2117
2118
|
try {
|
|
2118
|
-
const
|
|
2119
|
+
const imagePath = join(publicPath, file);
|
|
2120
|
+
const imageBuffer = readFileSync(imagePath);
|
|
2119
2121
|
reply.type(contentType);
|
|
2120
2122
|
return imageBuffer;
|
|
2121
2123
|
} catch (error) {
|
|
@@ -2127,7 +2129,8 @@ const imageRoutes = (fastify) => {
|
|
|
2127
2129
|
});
|
|
2128
2130
|
fastify.get("/image/jpeg", { schema: jpegSchema }, async (_request, reply) => {
|
|
2129
2131
|
try {
|
|
2130
|
-
const
|
|
2132
|
+
const imagePath = join(publicPath, "logo.jpg");
|
|
2133
|
+
const imageBuffer = readFileSync(imagePath);
|
|
2131
2134
|
reply.type("image/jpeg");
|
|
2132
2135
|
return imageBuffer;
|
|
2133
2136
|
} catch (error) {
|
|
@@ -2139,7 +2142,8 @@ const imageRoutes = (fastify) => {
|
|
|
2139
2142
|
});
|
|
2140
2143
|
fastify.get("/image/png", { schema: pngSchema }, async (_request, reply) => {
|
|
2141
2144
|
try {
|
|
2142
|
-
const
|
|
2145
|
+
const imagePath = join(publicPath, "logo.png");
|
|
2146
|
+
const imageBuffer = readFileSync(imagePath);
|
|
2143
2147
|
reply.type("image/png");
|
|
2144
2148
|
return imageBuffer;
|
|
2145
2149
|
} catch (error) {
|
|
@@ -2151,7 +2155,8 @@ const imageRoutes = (fastify) => {
|
|
|
2151
2155
|
});
|
|
2152
2156
|
fastify.get("/image/svg", { schema: svgSchema }, async (_request, reply) => {
|
|
2153
2157
|
try {
|
|
2154
|
-
const
|
|
2158
|
+
const imagePath = join(publicPath, "logo.svg");
|
|
2159
|
+
const imageBuffer = readFileSync(imagePath);
|
|
2155
2160
|
reply.type("image/svg+xml");
|
|
2156
2161
|
return imageBuffer;
|
|
2157
2162
|
} catch (error) {
|
|
@@ -2163,7 +2168,8 @@ const imageRoutes = (fastify) => {
|
|
|
2163
2168
|
});
|
|
2164
2169
|
fastify.get("/image/webp", { schema: webpSchema }, async (_request, reply) => {
|
|
2165
2170
|
try {
|
|
2166
|
-
const
|
|
2171
|
+
const imagePath = join(publicPath, "logo.webp");
|
|
2172
|
+
const imageBuffer = readFileSync(imagePath);
|
|
2167
2173
|
reply.type("image/webp");
|
|
2168
2174
|
return imageBuffer;
|
|
2169
2175
|
} catch (error) {
|
|
@@ -2438,46 +2444,78 @@ const userAgentRoute = (fastify) => {
|
|
|
2438
2444
|
};
|
|
2439
2445
|
//#endregion
|
|
2440
2446
|
//#region src/routes/response-formats/index.ts
|
|
2441
|
-
const
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
response: { 200: {
|
|
2447
|
+
const templateIndexParams = {
|
|
2448
|
+
type: "object",
|
|
2449
|
+
properties: { index: {
|
|
2445
2450
|
type: "string",
|
|
2446
|
-
description: "
|
|
2451
|
+
description: "Optional 1-based template index for stable, repeatable output. Omit for a random template."
|
|
2447
2452
|
} }
|
|
2448
2453
|
};
|
|
2454
|
+
const templateNotFoundResponse = {
|
|
2455
|
+
type: "object",
|
|
2456
|
+
description: "The requested template index does not exist",
|
|
2457
|
+
properties: { error: { type: "string" } }
|
|
2458
|
+
};
|
|
2459
|
+
const plainSchema = {
|
|
2460
|
+
description: "Returns plain text content. A random template is selected unless a 1-based template index is provided (e.g. /plain/1) for stable output.",
|
|
2461
|
+
tags: ["Response Formats"],
|
|
2462
|
+
params: templateIndexParams,
|
|
2463
|
+
response: {
|
|
2464
|
+
200: {
|
|
2465
|
+
type: "string",
|
|
2466
|
+
description: "Plain text content"
|
|
2467
|
+
},
|
|
2468
|
+
404: templateNotFoundResponse
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2449
2471
|
const textSchema = {
|
|
2450
|
-
description: "Returns random text
|
|
2472
|
+
description: "Returns text content. A random template is selected unless a 1-based template index is provided (e.g. /text/1) for stable output.",
|
|
2451
2473
|
tags: ["Response Formats"],
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2474
|
+
params: templateIndexParams,
|
|
2475
|
+
response: {
|
|
2476
|
+
200: {
|
|
2477
|
+
type: "string",
|
|
2478
|
+
description: "Text content"
|
|
2479
|
+
},
|
|
2480
|
+
404: templateNotFoundResponse
|
|
2481
|
+
}
|
|
2456
2482
|
};
|
|
2457
2483
|
const htmlSchema = {
|
|
2458
|
-
description: "Returns random
|
|
2484
|
+
description: "Returns HTML content. A random template is selected unless a 1-based template index is provided (e.g. /html/1) for stable output.",
|
|
2459
2485
|
tags: ["Response Formats"],
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2486
|
+
params: templateIndexParams,
|
|
2487
|
+
response: {
|
|
2488
|
+
200: {
|
|
2489
|
+
type: "string",
|
|
2490
|
+
description: "HTML content"
|
|
2491
|
+
},
|
|
2492
|
+
404: templateNotFoundResponse
|
|
2493
|
+
}
|
|
2464
2494
|
};
|
|
2465
2495
|
const xmlSchema = {
|
|
2466
|
-
description: "Returns random
|
|
2496
|
+
description: "Returns XML content. A random template is selected unless a 1-based template index is provided (e.g. /xml/1) for stable output.",
|
|
2467
2497
|
tags: ["Response Formats"],
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2498
|
+
params: templateIndexParams,
|
|
2499
|
+
response: {
|
|
2500
|
+
200: {
|
|
2501
|
+
type: "string",
|
|
2502
|
+
description: "XML content"
|
|
2503
|
+
},
|
|
2504
|
+
404: templateNotFoundResponse
|
|
2505
|
+
}
|
|
2472
2506
|
};
|
|
2473
2507
|
const jsonSchema = {
|
|
2474
|
-
description: "Returns random
|
|
2508
|
+
description: "Returns JSON content. A random template is selected unless a 1-based template index is provided (e.g. /json/1) for stable output.",
|
|
2475
2509
|
tags: ["Response Formats"],
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2510
|
+
params: templateIndexParams,
|
|
2511
|
+
response: {
|
|
2512
|
+
200: {
|
|
2513
|
+
type: "object",
|
|
2514
|
+
description: "JSON content",
|
|
2515
|
+
additionalProperties: true
|
|
2516
|
+
},
|
|
2517
|
+
404: templateNotFoundResponse
|
|
2518
|
+
}
|
|
2481
2519
|
};
|
|
2482
2520
|
const denySchema = {
|
|
2483
2521
|
description: "Returns page denied by robots.txt rules",
|
|
@@ -2613,7 +2651,7 @@ const randomXmlContent = [
|
|
|
2613
2651
|
`<?xml version="1.0" encoding="UTF-8"?>
|
|
2614
2652
|
<root>
|
|
2615
2653
|
<message>Hello from MockHTTP</message>
|
|
2616
|
-
<timestamp
|
|
2654
|
+
<timestamp>2024-01-15T10:30:00.000Z</timestamp>
|
|
2617
2655
|
<status>success</status>
|
|
2618
2656
|
</root>`,
|
|
2619
2657
|
`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -2656,19 +2694,19 @@ const randomXmlContent = [
|
|
|
2656
2694
|
<title>First Article</title>
|
|
2657
2695
|
<link>http://example.com/article1</link>
|
|
2658
2696
|
<description>This is the first article in our feed</description>
|
|
2659
|
-
<pubDate
|
|
2697
|
+
<pubDate>Mon, 15 Jan 2024 10:30:00 GMT</pubDate>
|
|
2660
2698
|
</item>
|
|
2661
2699
|
</channel>
|
|
2662
2700
|
</rss>`
|
|
2663
2701
|
];
|
|
2664
2702
|
const randomJsonContent = [
|
|
2665
|
-
|
|
2703
|
+
{
|
|
2666
2704
|
message: "Hello from MockHTTP",
|
|
2667
|
-
timestamp:
|
|
2705
|
+
timestamp: "2024-01-15T10:30:00.000Z",
|
|
2668
2706
|
status: "success",
|
|
2669
2707
|
code: 200
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2708
|
+
},
|
|
2709
|
+
{
|
|
2672
2710
|
user: {
|
|
2673
2711
|
id: 1,
|
|
2674
2712
|
name: "John Doe",
|
|
@@ -2681,8 +2719,8 @@ const randomJsonContent = [
|
|
|
2681
2719
|
"write",
|
|
2682
2720
|
"delete"
|
|
2683
2721
|
]
|
|
2684
|
-
}
|
|
2685
|
-
|
|
2722
|
+
},
|
|
2723
|
+
{
|
|
2686
2724
|
products: [{
|
|
2687
2725
|
id: 101,
|
|
2688
2726
|
name: "Laptop",
|
|
@@ -2696,8 +2734,8 @@ const randomJsonContent = [
|
|
|
2696
2734
|
}],
|
|
2697
2735
|
total: 2,
|
|
2698
2736
|
page: 1
|
|
2699
|
-
}
|
|
2700
|
-
|
|
2737
|
+
},
|
|
2738
|
+
{ config: {
|
|
2701
2739
|
theme: "dark",
|
|
2702
2740
|
language: "en",
|
|
2703
2741
|
notifications: {
|
|
@@ -2709,8 +2747,8 @@ const randomJsonContent = [
|
|
|
2709
2747
|
profile: "public",
|
|
2710
2748
|
activity: "friends"
|
|
2711
2749
|
}
|
|
2712
|
-
} }
|
|
2713
|
-
|
|
2750
|
+
} },
|
|
2751
|
+
{ metrics: {
|
|
2714
2752
|
cpu: 45.2,
|
|
2715
2753
|
memory: 78.5,
|
|
2716
2754
|
disk: 62.3,
|
|
@@ -2733,60 +2771,71 @@ const randomJsonContent = [
|
|
|
2733
2771
|
status: "warning"
|
|
2734
2772
|
}
|
|
2735
2773
|
]
|
|
2736
|
-
} }
|
|
2774
|
+
} }
|
|
2737
2775
|
];
|
|
2776
|
+
const resolveTemplateIndex = (index, length) => {
|
|
2777
|
+
if (index === void 0) return Math.floor(Math.random() * length);
|
|
2778
|
+
const value = Number(index);
|
|
2779
|
+
if (!Number.isInteger(value) || value < 1 || value > length) return -1;
|
|
2780
|
+
return value - 1;
|
|
2781
|
+
};
|
|
2782
|
+
const templateNotFound = (reply, length) => reply.code(404).send({ error: `Template index must be between 1 and ${length}` });
|
|
2738
2783
|
const responseFormatRoutes = (fastify) => {
|
|
2739
|
-
const plainHandler = async (
|
|
2740
|
-
const
|
|
2784
|
+
const plainHandler = async (request, reply) => {
|
|
2785
|
+
const index = resolveTemplateIndex(request.params.index, randomTexts.length);
|
|
2786
|
+
if (index === -1) return templateNotFound(reply, randomTexts.length);
|
|
2741
2787
|
reply.type("text/plain");
|
|
2742
|
-
return
|
|
2788
|
+
return randomTexts[index];
|
|
2743
2789
|
};
|
|
2744
|
-
fastify.get("/plain", { schema: plainSchema }, plainHandler);
|
|
2745
|
-
fastify.post("/plain", { schema: plainSchema }, plainHandler);
|
|
2746
|
-
fastify.put("/plain", { schema: plainSchema }, plainHandler);
|
|
2747
|
-
fastify.patch("/plain", { schema: plainSchema }, plainHandler);
|
|
2748
|
-
fastify.delete("/plain", { schema: plainSchema }, plainHandler);
|
|
2749
|
-
const textHandler = async (
|
|
2750
|
-
const
|
|
2790
|
+
fastify.get("/plain/:index?", { schema: plainSchema }, plainHandler);
|
|
2791
|
+
fastify.post("/plain/:index?", { schema: plainSchema }, plainHandler);
|
|
2792
|
+
fastify.put("/plain/:index?", { schema: plainSchema }, plainHandler);
|
|
2793
|
+
fastify.patch("/plain/:index?", { schema: plainSchema }, plainHandler);
|
|
2794
|
+
fastify.delete("/plain/:index?", { schema: plainSchema }, plainHandler);
|
|
2795
|
+
const textHandler = async (request, reply) => {
|
|
2796
|
+
const index = resolveTemplateIndex(request.params.index, randomTexts.length);
|
|
2797
|
+
if (index === -1) return templateNotFound(reply, randomTexts.length);
|
|
2751
2798
|
reply.type("text/plain");
|
|
2752
|
-
return
|
|
2799
|
+
return randomTexts[index];
|
|
2753
2800
|
};
|
|
2754
|
-
fastify.get("/text", { schema: textSchema }, textHandler);
|
|
2755
|
-
fastify.post("/text", { schema: textSchema }, textHandler);
|
|
2756
|
-
fastify.put("/text", { schema: textSchema }, textHandler);
|
|
2757
|
-
fastify.patch("/text", { schema: textSchema }, textHandler);
|
|
2758
|
-
fastify.delete("/text", { schema: textSchema }, textHandler);
|
|
2759
|
-
const htmlHandler = async (
|
|
2760
|
-
const
|
|
2801
|
+
fastify.get("/text/:index?", { schema: textSchema }, textHandler);
|
|
2802
|
+
fastify.post("/text/:index?", { schema: textSchema }, textHandler);
|
|
2803
|
+
fastify.put("/text/:index?", { schema: textSchema }, textHandler);
|
|
2804
|
+
fastify.patch("/text/:index?", { schema: textSchema }, textHandler);
|
|
2805
|
+
fastify.delete("/text/:index?", { schema: textSchema }, textHandler);
|
|
2806
|
+
const htmlHandler = async (request, reply) => {
|
|
2807
|
+
const index = resolveTemplateIndex(request.params.index, randomHtmlContent.length);
|
|
2808
|
+
if (index === -1) return templateNotFound(reply, randomHtmlContent.length);
|
|
2761
2809
|
reply.type("text/html");
|
|
2762
|
-
return
|
|
2810
|
+
return randomHtmlContent[index];
|
|
2763
2811
|
};
|
|
2764
|
-
fastify.get("/html", { schema: htmlSchema }, htmlHandler);
|
|
2765
|
-
fastify.post("/html", { schema: htmlSchema }, htmlHandler);
|
|
2766
|
-
fastify.put("/html", { schema: htmlSchema }, htmlHandler);
|
|
2767
|
-
fastify.patch("/html", { schema: htmlSchema }, htmlHandler);
|
|
2768
|
-
fastify.delete("/html", { schema: htmlSchema }, htmlHandler);
|
|
2769
|
-
const xmlHandler = async (
|
|
2770
|
-
const
|
|
2812
|
+
fastify.get("/html/:index?", { schema: htmlSchema }, htmlHandler);
|
|
2813
|
+
fastify.post("/html/:index?", { schema: htmlSchema }, htmlHandler);
|
|
2814
|
+
fastify.put("/html/:index?", { schema: htmlSchema }, htmlHandler);
|
|
2815
|
+
fastify.patch("/html/:index?", { schema: htmlSchema }, htmlHandler);
|
|
2816
|
+
fastify.delete("/html/:index?", { schema: htmlSchema }, htmlHandler);
|
|
2817
|
+
const xmlHandler = async (request, reply) => {
|
|
2818
|
+
const index = resolveTemplateIndex(request.params.index, randomXmlContent.length);
|
|
2819
|
+
if (index === -1) return templateNotFound(reply, randomXmlContent.length);
|
|
2771
2820
|
reply.type("application/xml");
|
|
2772
|
-
return
|
|
2821
|
+
return randomXmlContent[index];
|
|
2773
2822
|
};
|
|
2774
|
-
fastify.get("/xml", { schema: xmlSchema }, xmlHandler);
|
|
2775
|
-
fastify.post("/xml", { schema: xmlSchema }, xmlHandler);
|
|
2776
|
-
fastify.put("/xml", { schema: xmlSchema }, xmlHandler);
|
|
2777
|
-
fastify.patch("/xml", { schema: xmlSchema }, xmlHandler);
|
|
2778
|
-
fastify.delete("/xml", { schema: xmlSchema }, xmlHandler);
|
|
2779
|
-
const jsonHandler = async (
|
|
2780
|
-
const
|
|
2781
|
-
|
|
2823
|
+
fastify.get("/xml/:index?", { schema: xmlSchema }, xmlHandler);
|
|
2824
|
+
fastify.post("/xml/:index?", { schema: xmlSchema }, xmlHandler);
|
|
2825
|
+
fastify.put("/xml/:index?", { schema: xmlSchema }, xmlHandler);
|
|
2826
|
+
fastify.patch("/xml/:index?", { schema: xmlSchema }, xmlHandler);
|
|
2827
|
+
fastify.delete("/xml/:index?", { schema: xmlSchema }, xmlHandler);
|
|
2828
|
+
const jsonHandler = async (request, reply) => {
|
|
2829
|
+
const index = resolveTemplateIndex(request.params.index, randomJsonContent.length);
|
|
2830
|
+
if (index === -1) return templateNotFound(reply, randomJsonContent.length);
|
|
2782
2831
|
reply.type("application/json");
|
|
2783
|
-
return
|
|
2832
|
+
return structuredClone(randomJsonContent[index]);
|
|
2784
2833
|
};
|
|
2785
|
-
fastify.get("/json", { schema: jsonSchema }, jsonHandler);
|
|
2786
|
-
fastify.post("/json", { schema: jsonSchema }, jsonHandler);
|
|
2787
|
-
fastify.put("/json", { schema: jsonSchema }, jsonHandler);
|
|
2788
|
-
fastify.patch("/json", { schema: jsonSchema }, jsonHandler);
|
|
2789
|
-
fastify.delete("/json", { schema: jsonSchema }, jsonHandler);
|
|
2834
|
+
fastify.get("/json/:index?", { schema: jsonSchema }, jsonHandler);
|
|
2835
|
+
fastify.post("/json/:index?", { schema: jsonSchema }, jsonHandler);
|
|
2836
|
+
fastify.put("/json/:index?", { schema: jsonSchema }, jsonHandler);
|
|
2837
|
+
fastify.patch("/json/:index?", { schema: jsonSchema }, jsonHandler);
|
|
2838
|
+
fastify.delete("/json/:index?", { schema: jsonSchema }, jsonHandler);
|
|
2790
2839
|
const denyHandler = async (_request, reply) => {
|
|
2791
2840
|
const denyMessages = [
|
|
2792
2841
|
`<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
|
@@ -2869,7 +2918,8 @@ const responseFormatRoutes = (fastify) => {
|
|
|
2869
2918
|
...data,
|
|
2870
2919
|
compressedSize: compressed.length
|
|
2871
2920
|
};
|
|
2872
|
-
const
|
|
2921
|
+
const updatedJsonString = JSON.stringify(updatedData);
|
|
2922
|
+
const updatedCompressed = gzipSync(updatedJsonString);
|
|
2873
2923
|
reply.header("Content-Encoding", "gzip");
|
|
2874
2924
|
reply.header("Content-Type", "application/json");
|
|
2875
2925
|
reply.type("application/octet-stream");
|
|
@@ -2925,7 +2975,8 @@ const responseFormatRoutes = (fastify) => {
|
|
|
2925
2975
|
...data,
|
|
2926
2976
|
compressedSize: compressed.length
|
|
2927
2977
|
};
|
|
2928
|
-
const
|
|
2978
|
+
const updatedJsonString = JSON.stringify(updatedData);
|
|
2979
|
+
const updatedCompressed = deflateSync(updatedJsonString);
|
|
2929
2980
|
reply.header("Content-Encoding", "deflate");
|
|
2930
2981
|
reply.header("Content-Type", "application/json");
|
|
2931
2982
|
reply.type("application/octet-stream");
|
|
@@ -2986,7 +3037,8 @@ const responseFormatRoutes = (fastify) => {
|
|
|
2986
3037
|
...data,
|
|
2987
3038
|
compressedSize: compressed.length
|
|
2988
3039
|
};
|
|
2989
|
-
const
|
|
3040
|
+
const updatedJsonString = JSON.stringify(updatedData);
|
|
3041
|
+
const updatedCompressed = brotliCompressSync(updatedJsonString);
|
|
2990
3042
|
reply.header("Content-Encoding", "br");
|
|
2991
3043
|
reply.header("Content-Type", "application/json");
|
|
2992
3044
|
reply.type("application/octet-stream");
|
|
@@ -3449,7 +3501,7 @@ A simple HTTP server that can be used to mock HTTP responses for testing purpose
|
|
|
3449
3501
|
|
|
3450
3502
|
[mockhttp.org](https://mockhttp.org) is a free service that runs this codebase and allows you to use it for testing purposes. It is a simple way to mock HTTP responses for testing purposes. Ran via [Cloudflare](https://cloudflare.com) and [Google Cloud Run](https://cloud.google.com/run/) across 7 regions globally and can do millions of requests per second.
|
|
3451
3503
|
`,
|
|
3452
|
-
version: "1.
|
|
3504
|
+
version: "1.9.0"
|
|
3453
3505
|
},
|
|
3454
3506
|
consumes: ["application/json"],
|
|
3455
3507
|
produces: ["application/json"]
|
|
@@ -3618,14 +3670,18 @@ var MockHttp = class extends Hookified {
|
|
|
3618
3670
|
if (options?.helmet !== void 0) this._helmet = options.helmet;
|
|
3619
3671
|
if (options?.apiDocs !== void 0) this._apiDocs = options.apiDocs;
|
|
3620
3672
|
if (options?.httpBin !== void 0) this._httpBin = options.httpBin;
|
|
3621
|
-
if (options?.rateLimit !== void 0)
|
|
3622
|
-
|
|
3673
|
+
if (options?.rateLimit !== void 0) {
|
|
3674
|
+
if (options.rateLimit === false) this._rateLimit = void 0;
|
|
3675
|
+
else this._rateLimit = options.rateLimit;
|
|
3676
|
+
}
|
|
3623
3677
|
if (options?.logging !== void 0) this._logging = options.logging;
|
|
3624
3678
|
if (options?.http2 !== void 0) this._http2 = options.http2;
|
|
3625
3679
|
if (options?.http1 !== void 0) this._http1 = options.http1;
|
|
3626
|
-
if (options?.https !== void 0)
|
|
3627
|
-
|
|
3628
|
-
|
|
3680
|
+
if (options?.https !== void 0) {
|
|
3681
|
+
if (options.https === true) this._https = { autoGenerate: true };
|
|
3682
|
+
else if (options.https === false) this._https = void 0;
|
|
3683
|
+
else this._https = options.https;
|
|
3684
|
+
}
|
|
3629
3685
|
}
|
|
3630
3686
|
/**
|
|
3631
3687
|
* The port to listen on. If not provided, defaults to 3000 and detects the next available port if in use.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaredwray/mockhttp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Mock Http - Easy way to mock http with httpbin replacement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -39,27 +39,27 @@
|
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://github.com/jaredwray/mockhttp#readme",
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@biomejs/biome": "^2.5.
|
|
43
|
-
"@swc/core": "^1.15.
|
|
42
|
+
"@biomejs/biome": "^2.5.8",
|
|
43
|
+
"@swc/core": "^1.15.47",
|
|
44
44
|
"@types/html-escaper": "^3.0.4",
|
|
45
45
|
"@vitest/coverage-v8": "^4.1.10",
|
|
46
46
|
"rimraf": "^6.1.3",
|
|
47
|
-
"tsdown": "^0.22.
|
|
48
|
-
"tsx": "^4.23.
|
|
49
|
-
"typescript": "
|
|
47
|
+
"tsdown": "^0.22.14",
|
|
48
|
+
"tsx": "^4.23.12",
|
|
49
|
+
"typescript": "7.0.2",
|
|
50
50
|
"vitest": "^4.1.10"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@fastify/cookie": "^11.1.
|
|
53
|
+
"@fastify/cookie": "^11.1.2",
|
|
54
54
|
"@fastify/helmet": "^13.1.0",
|
|
55
|
-
"@fastify/rate-limit": "^11.
|
|
56
|
-
"@fastify/static": "^10.1.
|
|
57
|
-
"@fastify/swagger": "^9.8.
|
|
58
|
-
"@fastify/swagger-ui": "^6.1.
|
|
59
|
-
"@scalar/api-reference": "^1.
|
|
55
|
+
"@fastify/rate-limit": "^11.2.0",
|
|
56
|
+
"@fastify/static": "^10.1.3",
|
|
57
|
+
"@fastify/swagger": "^9.8.1",
|
|
58
|
+
"@fastify/swagger-ui": "^6.1.1",
|
|
59
|
+
"@scalar/api-reference": "^1.64.1",
|
|
60
60
|
"detect-port": "^2.1.0",
|
|
61
|
-
"fastify": "^5.
|
|
62
|
-
"hookified": "^3.0.
|
|
61
|
+
"fastify": "^5.11.3",
|
|
62
|
+
"hookified": "^3.0.2",
|
|
63
63
|
"html-escaper": "^3.0.3",
|
|
64
64
|
"pino": "^10.3.1",
|
|
65
65
|
"pino-pretty": "^13.1.3"
|