@jaredwray/mockhttp 0.6.1 → 0.8.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/README.md +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1829 -1209
- package/package.json +77 -82
package/dist/index.js
CHANGED
|
@@ -6,152 +6,13 @@ import process from "process";
|
|
|
6
6
|
|
|
7
7
|
// src/mock-http.ts
|
|
8
8
|
import path from "path";
|
|
9
|
-
import
|
|
9
|
+
import fastifyCookie from "@fastify/cookie";
|
|
10
10
|
import fastifyHelmet from "@fastify/helmet";
|
|
11
|
+
import fastifyStatic from "@fastify/static";
|
|
11
12
|
import { fastifySwagger } from "@fastify/swagger";
|
|
12
|
-
import
|
|
13
|
+
import { detect } from "detect-port";
|
|
13
14
|
import Fastify from "fastify";
|
|
14
15
|
import { Hookified } from "hookified";
|
|
15
|
-
import { detect } from "detect-port";
|
|
16
|
-
|
|
17
|
-
// src/swagger.ts
|
|
18
|
-
import { fastifySwaggerUi } from "@fastify/swagger-ui";
|
|
19
|
-
|
|
20
|
-
// package.json
|
|
21
|
-
var package_default = {
|
|
22
|
-
name: "@jaredwray/mockhttp",
|
|
23
|
-
version: "0.6.1",
|
|
24
|
-
description: "Mock Http - Easy way to mock http with httpbin replacement",
|
|
25
|
-
type: "module",
|
|
26
|
-
main: "dist/index.js",
|
|
27
|
-
directories: {
|
|
28
|
-
test: "test"
|
|
29
|
-
},
|
|
30
|
-
scripts: {
|
|
31
|
-
test: "xo --fix && vitest run --coverage",
|
|
32
|
-
dev: "xo --fix && tsx src/index.ts --watch",
|
|
33
|
-
build: "rimraf ./dist && tsup src/index.ts --format esm --dts --clean",
|
|
34
|
-
"docker:build": "docker build -t jaredwray/mockhttp .",
|
|
35
|
-
"docker:run": "docker run -p 3000:3000 jaredwray/mockhttp",
|
|
36
|
-
"docker:push": "docker push jaredwray/mockhttp",
|
|
37
|
-
"docker:stop": 'docker stop $(docker ps -a -q --filter ancestor=jaredwray/mockhttp --format="{{.ID}}")',
|
|
38
|
-
"docker:readme": "tsx ./scripts/create-docker-readme.ts",
|
|
39
|
-
"docker:compose:up": "docker-compose up -d",
|
|
40
|
-
"docker:compose:down": "docker-compose down",
|
|
41
|
-
prepare: "pnpm run build",
|
|
42
|
-
start: "node dist/index.js"
|
|
43
|
-
},
|
|
44
|
-
repository: {
|
|
45
|
-
type: "git",
|
|
46
|
-
url: "git+https://github.com/jaredwray/mockhttp.git"
|
|
47
|
-
},
|
|
48
|
-
keywords: [
|
|
49
|
-
"mock",
|
|
50
|
-
"http",
|
|
51
|
-
"httpbin",
|
|
52
|
-
"test"
|
|
53
|
-
],
|
|
54
|
-
author: "Jared Wray <me@jaredwray.com>",
|
|
55
|
-
license: "MIT",
|
|
56
|
-
bugs: {
|
|
57
|
-
url: "https://github.com/jaredwray/mockhttp/issues"
|
|
58
|
-
},
|
|
59
|
-
homepage: "https://github.com/jaredwray/mockhttp#readme",
|
|
60
|
-
devDependencies: {
|
|
61
|
-
"@swc/core": "^1.13.0",
|
|
62
|
-
"@types/html-escaper": "^3.0.4",
|
|
63
|
-
"@vitest/coverage-v8": "^3.2.4",
|
|
64
|
-
rimraf: "^6.0.1",
|
|
65
|
-
tsup: "^8.5.0",
|
|
66
|
-
tsx: "^4.20.3",
|
|
67
|
-
typescript: "^5.8.3",
|
|
68
|
-
vitest: "^3.2.4",
|
|
69
|
-
xo: "^1.2.1"
|
|
70
|
-
},
|
|
71
|
-
dependencies: {
|
|
72
|
-
"@fastify/cookie": "^11.0.2",
|
|
73
|
-
"@fastify/helmet": "^13.0.1",
|
|
74
|
-
"@fastify/static": "^8.2.0",
|
|
75
|
-
"@fastify/swagger": "^9.5.1",
|
|
76
|
-
"@fastify/swagger-ui": "^5.2.3",
|
|
77
|
-
"@scalar/api-reference": "^1.32.9",
|
|
78
|
-
"detect-port": "^2.1.0",
|
|
79
|
-
fastify: "^5.4.0",
|
|
80
|
-
hookified: "^1.10.0",
|
|
81
|
-
"html-escaper": "^3.0.3",
|
|
82
|
-
pino: "^9.7.0",
|
|
83
|
-
"pino-pretty": "^13.0.0"
|
|
84
|
-
},
|
|
85
|
-
files: [
|
|
86
|
-
"dist",
|
|
87
|
-
"public",
|
|
88
|
-
"LICENCE"
|
|
89
|
-
],
|
|
90
|
-
pnpm: {
|
|
91
|
-
onlyBuiltDependencies: [
|
|
92
|
-
"@swc/core",
|
|
93
|
-
"esbuild",
|
|
94
|
-
"unrs-resolver",
|
|
95
|
-
"vue-demi"
|
|
96
|
-
]
|
|
97
|
-
},
|
|
98
|
-
xo: {
|
|
99
|
-
rules: {
|
|
100
|
-
"@typescript-eslint/no-unsafe-call": "off",
|
|
101
|
-
"@typescript-eslint/no-unsafe-assignment": "off"
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// src/swagger.ts
|
|
107
|
-
var description = `
|
|
108
|
-
A simple HTTP server that can be used to mock HTTP responses for testing purposes. Inspired by [httpbin](https://httpbin.org/) and built using \`nodejs\` and \`fastify\` with the idea of running it via https://mockhttp.org, via docker \`jaredwray/mockhttp\`, or nodejs \`npm install jaredwray/mockhttp\`.
|
|
109
|
-
|
|
110
|
-
* [GitHub Repository](https://github.com/jaredwray/mockhttp)
|
|
111
|
-
* [Docker Image](https://hub.docker.com/r/jaredwray/mockhttp)
|
|
112
|
-
* [NPM Package](https://www.npmjs.com/package/jaredwray/mockhttp)
|
|
113
|
-
|
|
114
|
-
# About mockhttp.org
|
|
115
|
-
|
|
116
|
-
[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.
|
|
117
|
-
`;
|
|
118
|
-
var fastifySwaggerConfig = {
|
|
119
|
-
openapi: {
|
|
120
|
-
info: {
|
|
121
|
-
title: "Mock HTTP API",
|
|
122
|
-
description,
|
|
123
|
-
version: package_default.version
|
|
124
|
-
},
|
|
125
|
-
consumes: [
|
|
126
|
-
"application/json"
|
|
127
|
-
],
|
|
128
|
-
produces: [
|
|
129
|
-
"application/json"
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
var registerSwaggerUi = /* @__PURE__ */ __name(async (fastify) => {
|
|
134
|
-
await fastify.register(fastifySwaggerUi, {
|
|
135
|
-
routePrefix: "/docs",
|
|
136
|
-
uiConfig: {
|
|
137
|
-
docExpansion: "none",
|
|
138
|
-
deepLinking: false
|
|
139
|
-
},
|
|
140
|
-
uiHooks: {
|
|
141
|
-
/* c8 ignore next 6 */
|
|
142
|
-
onRequest(_request, _reply, next) {
|
|
143
|
-
next();
|
|
144
|
-
},
|
|
145
|
-
preHandler(_request, _reply, next) {
|
|
146
|
-
next();
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
150
|
-
staticCSP: true,
|
|
151
|
-
transformSpecification: /* @__PURE__ */ __name((swaggerObject, _request, _reply) => swaggerObject, "transformSpecification"),
|
|
152
|
-
transformSpecificationClone: true
|
|
153
|
-
});
|
|
154
|
-
}, "registerSwaggerUi");
|
|
155
16
|
|
|
156
17
|
// src/fastify-config.ts
|
|
157
18
|
var fastifyConfig = {
|
|
@@ -168,949 +29,1003 @@ var fastifyConfig = {
|
|
|
168
29
|
}
|
|
169
30
|
};
|
|
170
31
|
|
|
171
|
-
// src/routes/index.ts
|
|
172
|
-
var
|
|
173
|
-
|
|
174
|
-
schema: {
|
|
175
|
-
hide: true
|
|
176
|
-
}
|
|
177
|
-
}, async (_request, reply) => {
|
|
178
|
-
const redocHtml = `
|
|
179
|
-
<!doctype html>
|
|
180
|
-
<html>
|
|
181
|
-
<head>
|
|
182
|
-
<title>{ mockhttp }</title>
|
|
183
|
-
<meta charset="utf-8" />
|
|
184
|
-
<meta
|
|
185
|
-
name="viewport"
|
|
186
|
-
content="width=device-width, initial-scale=1" />
|
|
187
|
-
<style>
|
|
188
|
-
:root {
|
|
189
|
-
--scalar-custom-header-height: 70px;
|
|
190
|
-
}
|
|
191
|
-
.custom-header {
|
|
192
|
-
height: var(--scalar-custom-header-height);
|
|
193
|
-
background-color: var(--scalar-background-1);
|
|
194
|
-
box-shadow: inset 0 -1px 0 var(--scalar-border-color);
|
|
195
|
-
color: var(--scalar-color-1);
|
|
196
|
-
font-size: var(--scalar-font-size-2);
|
|
197
|
-
padding: 0 18px;
|
|
198
|
-
position: sticky;
|
|
199
|
-
justify-content: space-between;
|
|
200
|
-
top: 0;
|
|
201
|
-
z-index: 100;
|
|
202
|
-
}
|
|
203
|
-
.custom-header,
|
|
204
|
-
.custom-header nav {
|
|
205
|
-
display: flex;
|
|
206
|
-
align-items: center;
|
|
207
|
-
gap: 18px;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
.custom-header img {
|
|
211
|
-
height: var(--scalar-custom-header-height);
|
|
212
|
-
object-fit: contain;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.custom-header a:hover {
|
|
216
|
-
color: var(--scalar-color-2);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.github-corner {
|
|
220
|
-
fill: var(--scalar-border-color) !important;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
</style>
|
|
224
|
-
</head>
|
|
225
|
-
<body>
|
|
226
|
-
<header class="custom-header scalar-app">
|
|
227
|
-
<a href="/"><img src="/logo.svg" alt="{ mockhttp }" /></a>
|
|
228
|
-
<a href="https://github.com/jaredwray/mockhttp" class="github-corner" aria-label="View source on GitHub">
|
|
229
|
-
<svg width="70" height="70" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true">
|
|
230
|
-
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
|
231
|
-
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
|
|
232
|
-
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
|
233
|
-
</header>
|
|
234
|
-
|
|
235
|
-
<script
|
|
236
|
-
id="api-reference"
|
|
237
|
-
data-url="/docs/json"></script>
|
|
238
|
-
|
|
239
|
-
<script src="/scalar/browser/standalone.js"></script>
|
|
240
|
-
</body>
|
|
241
|
-
</html>
|
|
242
|
-
`;
|
|
243
|
-
await reply.type("text/html").send(redocHtml);
|
|
244
|
-
});
|
|
245
|
-
}, "indexRoute");
|
|
246
|
-
|
|
247
|
-
// src/routes/sitemap.ts
|
|
248
|
-
var sitemapRoute = /* @__PURE__ */ __name((fastify) => {
|
|
249
|
-
fastify.get("/sitemap.xml", {
|
|
250
|
-
schema: {
|
|
251
|
-
hide: true
|
|
252
|
-
}
|
|
253
|
-
}, async (_request, reply) => {
|
|
254
|
-
try {
|
|
255
|
-
const host = _request.headers.host ?? "mockhttp.org";
|
|
256
|
-
const isSecure = _request.headers["x-forwarded-proto"]?.includes("https");
|
|
257
|
-
const protocol = isSecure ? "https" : "http";
|
|
258
|
-
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
259
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
260
|
-
<url>
|
|
261
|
-
<loc>${protocol}://${host}/</loc>
|
|
262
|
-
<changefreq>monthly</changefreq>
|
|
263
|
-
<priority>1.0</priority>
|
|
264
|
-
</url>
|
|
265
|
-
</urlset>`;
|
|
266
|
-
await reply.type("text/xml").send(xml);
|
|
267
|
-
} catch (error) {
|
|
268
|
-
fastify.log.error(error);
|
|
269
|
-
await reply.status(500).send({
|
|
270
|
-
error: "Internal Server Error"
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
}, "sitemapRoute");
|
|
275
|
-
|
|
276
|
-
// src/routes/http-methods/get.ts
|
|
277
|
-
var getSchema = {
|
|
278
|
-
description: "Returns request information for GET requests",
|
|
32
|
+
// src/routes/anything/index.ts
|
|
33
|
+
var anythingSchema = {
|
|
34
|
+
description: "Will return anything that you send it",
|
|
279
35
|
tags: [
|
|
280
|
-
"
|
|
36
|
+
"Anything"
|
|
281
37
|
],
|
|
282
|
-
querystring: {
|
|
283
|
-
type: "object",
|
|
284
|
-
additionalProperties: true,
|
|
285
|
-
properties: {},
|
|
286
|
-
description: "Query parameters sent in the request"
|
|
287
|
-
},
|
|
288
|
-
headers: {
|
|
289
|
-
type: "object",
|
|
290
|
-
additionalProperties: true,
|
|
291
|
-
properties: {},
|
|
292
|
-
description: "Headers sent in the request"
|
|
293
|
-
},
|
|
294
38
|
response: {
|
|
295
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
296
39
|
200: {
|
|
297
40
|
type: "object",
|
|
298
41
|
properties: {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
additionalProperties: {
|
|
305
|
-
type: "string"
|
|
306
|
-
}
|
|
42
|
+
// Echo back all your params under `args`
|
|
43
|
+
args: {
|
|
44
|
+
type: "object",
|
|
45
|
+
description: "Route parameters",
|
|
46
|
+
additionalProperties: true
|
|
307
47
|
},
|
|
308
|
-
|
|
48
|
+
// Echo back whatever was in the request.body
|
|
49
|
+
data: {
|
|
309
50
|
type: "object",
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
headers: request.headers,
|
|
329
|
-
queryParams: request.query
|
|
330
|
-
}));
|
|
331
|
-
}, "getRoute");
|
|
332
|
-
|
|
333
|
-
// src/routes/http-methods/post.ts
|
|
334
|
-
var postSchema = {
|
|
335
|
-
description: "Handles a POST request and returns request information",
|
|
336
|
-
tags: [
|
|
337
|
-
"HTTP Methods"
|
|
338
|
-
],
|
|
339
|
-
body: {
|
|
340
|
-
type: "object",
|
|
341
|
-
additionalProperties: true,
|
|
342
|
-
description: "The body of the POST request"
|
|
343
|
-
},
|
|
344
|
-
response: {
|
|
345
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
346
|
-
200: {
|
|
347
|
-
type: "object",
|
|
348
|
-
properties: {
|
|
349
|
-
method: {
|
|
350
|
-
type: "string"
|
|
51
|
+
description: "Request body data",
|
|
52
|
+
additionalProperties: true
|
|
53
|
+
},
|
|
54
|
+
// If you’re using fastify-multipart, you’ll get
|
|
55
|
+
// files via request.files(); this just allows
|
|
56
|
+
// you to mirror them back
|
|
57
|
+
files: {
|
|
58
|
+
type: "object",
|
|
59
|
+
description: "Uploaded files",
|
|
60
|
+
additionalProperties: true
|
|
61
|
+
},
|
|
62
|
+
// If you parse application/x-www-form-urlencoded
|
|
63
|
+
// these fields land in request.body too, but you can
|
|
64
|
+
// mirror them separately if you like
|
|
65
|
+
form: {
|
|
66
|
+
type: "object",
|
|
67
|
+
description: "Form data",
|
|
68
|
+
additionalProperties: true
|
|
351
69
|
},
|
|
352
70
|
headers: {
|
|
353
71
|
type: "object",
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
72
|
+
description: "Request headers",
|
|
73
|
+
additionalProperties: true
|
|
357
74
|
},
|
|
358
|
-
|
|
75
|
+
json: {
|
|
359
76
|
type: "object",
|
|
77
|
+
description: "Parsed JSON body",
|
|
360
78
|
additionalProperties: true
|
|
79
|
+
},
|
|
80
|
+
method: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "HTTP method used"
|
|
83
|
+
},
|
|
84
|
+
origin: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description: "Origin of the request"
|
|
87
|
+
},
|
|
88
|
+
url: {
|
|
89
|
+
type: "string",
|
|
90
|
+
description: "Request URL"
|
|
361
91
|
}
|
|
362
92
|
},
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
"headers",
|
|
366
|
-
"body"
|
|
367
|
-
]
|
|
93
|
+
// Don’t allow any other top-level keys in your response
|
|
94
|
+
additionalProperties: false
|
|
368
95
|
}
|
|
369
96
|
}
|
|
370
97
|
};
|
|
371
|
-
var
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
98
|
+
var anythingRoute = /* @__PURE__ */ __name((fastify) => {
|
|
99
|
+
const handler = /* @__PURE__ */ __name(async (request, reply) => {
|
|
100
|
+
const response = {
|
|
101
|
+
args: request.query,
|
|
102
|
+
data: request.body ?? {},
|
|
103
|
+
// biome-ignore lint/suspicious/noExplicitAny: expected
|
|
104
|
+
files: request.raw?.files ?? {},
|
|
105
|
+
form: request.body ?? {},
|
|
106
|
+
headers: request.headers,
|
|
107
|
+
json: request.body ?? {},
|
|
108
|
+
method: request.method,
|
|
109
|
+
origin: request.headers.origin ?? request.headers.host ?? "",
|
|
110
|
+
url: request.url
|
|
111
|
+
};
|
|
112
|
+
await reply.send(response);
|
|
113
|
+
}, "handler");
|
|
114
|
+
const noValidation = {
|
|
115
|
+
schema: anythingSchema,
|
|
116
|
+
// Skip AJV on *this* route
|
|
117
|
+
validatorCompiler: /* @__PURE__ */ __name(() => () => true, "validatorCompiler")
|
|
118
|
+
};
|
|
119
|
+
fastify.get("/anything", noValidation, handler);
|
|
120
|
+
fastify.post("/anything", noValidation, handler);
|
|
121
|
+
fastify.put("/anything", noValidation, handler);
|
|
122
|
+
fastify.patch("/anything", noValidation, handler);
|
|
123
|
+
fastify.delete("/anything", noValidation, handler);
|
|
124
|
+
}, "anythingRoute");
|
|
380
125
|
|
|
381
|
-
// src/routes/
|
|
382
|
-
|
|
383
|
-
|
|
126
|
+
// src/routes/auth/basic.ts
|
|
127
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
128
|
+
import { timingSafeEqual } from "crypto";
|
|
129
|
+
var parseBasic = /* @__PURE__ */ __name((header) => {
|
|
130
|
+
if (!header || typeof header !== "string") {
|
|
131
|
+
return void 0;
|
|
132
|
+
}
|
|
133
|
+
const spaceIndex = header.indexOf(" ");
|
|
134
|
+
if (spaceIndex === -1) {
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
const scheme = header.slice(0, spaceIndex);
|
|
138
|
+
const value = header.slice(spaceIndex + 1);
|
|
139
|
+
if (scheme.toLowerCase() !== "basic" || !value) {
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const decoded = Buffer2.from(value, "base64").toString("utf8");
|
|
144
|
+
const idx = decoded.indexOf(":");
|
|
145
|
+
if (idx === -1) {
|
|
146
|
+
return void 0;
|
|
147
|
+
}
|
|
148
|
+
const username = decoded.slice(0, idx);
|
|
149
|
+
const password = decoded.slice(idx + 1);
|
|
150
|
+
if (username === "") {
|
|
151
|
+
return void 0;
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
username,
|
|
155
|
+
password
|
|
156
|
+
};
|
|
157
|
+
} catch {
|
|
158
|
+
return void 0;
|
|
159
|
+
}
|
|
160
|
+
}, "parseBasic");
|
|
161
|
+
var safeCompare = /* @__PURE__ */ __name((a, b) => {
|
|
162
|
+
if (a.length !== b.length) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
return timingSafeEqual(Buffer2.from(a, "utf8"), Buffer2.from(b, "utf8"));
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}, "safeCompare");
|
|
171
|
+
var basicAuthSchema = {
|
|
172
|
+
description: "HTTP Basic authentication. Succeeds only if the user/pass provided in the path matches the Basic Authorization header.",
|
|
384
173
|
tags: [
|
|
385
|
-
"
|
|
174
|
+
"Auth"
|
|
386
175
|
],
|
|
387
|
-
|
|
176
|
+
params: {
|
|
388
177
|
type: "object",
|
|
389
|
-
|
|
390
|
-
|
|
178
|
+
properties: {
|
|
179
|
+
user: {
|
|
180
|
+
type: "string"
|
|
181
|
+
},
|
|
182
|
+
passwd: {
|
|
183
|
+
type: "string"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
required: [
|
|
187
|
+
"user",
|
|
188
|
+
"passwd"
|
|
189
|
+
]
|
|
391
190
|
},
|
|
392
191
|
response: {
|
|
393
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
394
192
|
200: {
|
|
395
193
|
type: "object",
|
|
396
194
|
properties: {
|
|
397
|
-
|
|
398
|
-
type: "
|
|
399
|
-
},
|
|
400
|
-
headers: {
|
|
401
|
-
type: "object",
|
|
402
|
-
additionalProperties: {
|
|
403
|
-
type: "string"
|
|
404
|
-
}
|
|
195
|
+
authenticated: {
|
|
196
|
+
type: "boolean"
|
|
405
197
|
},
|
|
406
|
-
|
|
407
|
-
type: "
|
|
408
|
-
additionalProperties: true
|
|
198
|
+
user: {
|
|
199
|
+
type: "string"
|
|
409
200
|
}
|
|
410
201
|
},
|
|
411
202
|
required: [
|
|
412
|
-
"
|
|
413
|
-
"
|
|
414
|
-
"body"
|
|
203
|
+
"authenticated",
|
|
204
|
+
"user"
|
|
415
205
|
]
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
};
|
|
419
|
-
var deleteRoute = /* @__PURE__ */ __name((fastify) => {
|
|
420
|
-
fastify.delete("/delete", {
|
|
421
|
-
schema: deleteSchema
|
|
422
|
-
}, async (request) => ({
|
|
423
|
-
method: "DELETE",
|
|
424
|
-
headers: request.headers,
|
|
425
|
-
body: request.body
|
|
426
|
-
}));
|
|
427
|
-
}, "deleteRoute");
|
|
428
|
-
|
|
429
|
-
// src/routes/http-methods/put.ts
|
|
430
|
-
var putSchema = {
|
|
431
|
-
description: "Handles a PUT request and returns request information",
|
|
432
|
-
tags: [
|
|
433
|
-
"HTTP Methods"
|
|
434
|
-
],
|
|
435
|
-
body: {
|
|
436
|
-
type: "object",
|
|
437
|
-
additionalProperties: true,
|
|
438
|
-
description: "The body of the PUT request"
|
|
439
|
-
},
|
|
440
|
-
response: {
|
|
441
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
442
|
-
200: {
|
|
206
|
+
},
|
|
207
|
+
401: {
|
|
443
208
|
type: "object",
|
|
444
209
|
properties: {
|
|
445
|
-
|
|
210
|
+
message: {
|
|
446
211
|
type: "string"
|
|
447
|
-
},
|
|
448
|
-
headers: {
|
|
449
|
-
type: "object",
|
|
450
|
-
additionalProperties: {
|
|
451
|
-
type: "string"
|
|
452
|
-
}
|
|
453
|
-
},
|
|
454
|
-
body: {
|
|
455
|
-
type: "object",
|
|
456
|
-
additionalProperties: true
|
|
457
212
|
}
|
|
458
213
|
},
|
|
459
214
|
required: [
|
|
460
|
-
"
|
|
461
|
-
"headers",
|
|
462
|
-
"body"
|
|
215
|
+
"message"
|
|
463
216
|
]
|
|
464
217
|
}
|
|
465
218
|
}
|
|
466
219
|
};
|
|
467
|
-
var
|
|
468
|
-
fastify.
|
|
469
|
-
schema:
|
|
470
|
-
}, async (request) =>
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
220
|
+
var basicAuthRoute = /* @__PURE__ */ __name((fastify) => {
|
|
221
|
+
fastify.get("/basic-auth/:user/:passwd", {
|
|
222
|
+
schema: basicAuthSchema
|
|
223
|
+
}, async (request, reply) => {
|
|
224
|
+
const { user, passwd } = request.params;
|
|
225
|
+
if (!user || typeof user !== "string" || typeof passwd !== "string") {
|
|
226
|
+
void reply.header("WWW-Authenticate", 'Basic realm="mockhttp"');
|
|
227
|
+
return reply.status(401).send({
|
|
228
|
+
message: "Unauthorized"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
const parsed = parseBasic(request.headers.authorization);
|
|
232
|
+
if (!parsed || !safeCompare(parsed.username, user) || !safeCompare(parsed.password, passwd)) {
|
|
233
|
+
void reply.header("WWW-Authenticate", 'Basic realm="mockhttp"');
|
|
234
|
+
return reply.status(401).send({
|
|
235
|
+
message: "Unauthorized"
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return reply.send({
|
|
239
|
+
authenticated: true,
|
|
240
|
+
user
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}, "basicAuthRoute");
|
|
476
244
|
|
|
477
|
-
// src/routes/
|
|
478
|
-
var
|
|
479
|
-
|
|
245
|
+
// src/routes/auth/bearer.ts
|
|
246
|
+
var parseBearer = /* @__PURE__ */ __name((header) => {
|
|
247
|
+
if (!header) {
|
|
248
|
+
return void 0;
|
|
249
|
+
}
|
|
250
|
+
const [scheme, token] = header.split(" ");
|
|
251
|
+
if (!scheme || scheme.toLowerCase() !== "bearer" || !token) {
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
return token;
|
|
255
|
+
}, "parseBearer");
|
|
256
|
+
var bearerAuthSchema = {
|
|
257
|
+
description: "HTTP Bearer authentication. Succeeds if any Bearer token is present unless ?required=true is provided.",
|
|
480
258
|
tags: [
|
|
481
|
-
"
|
|
259
|
+
"Auth"
|
|
482
260
|
],
|
|
483
|
-
|
|
261
|
+
querystring: {
|
|
484
262
|
type: "object",
|
|
485
|
-
|
|
486
|
-
|
|
263
|
+
properties: {
|
|
264
|
+
required: {
|
|
265
|
+
type: "boolean",
|
|
266
|
+
default: true
|
|
267
|
+
}
|
|
268
|
+
}
|
|
487
269
|
},
|
|
488
270
|
response: {
|
|
489
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
490
271
|
200: {
|
|
491
272
|
type: "object",
|
|
492
273
|
properties: {
|
|
493
|
-
|
|
494
|
-
type: "
|
|
495
|
-
},
|
|
496
|
-
headers: {
|
|
497
|
-
type: "object",
|
|
498
|
-
additionalProperties: {
|
|
499
|
-
type: "string"
|
|
500
|
-
}
|
|
274
|
+
authenticated: {
|
|
275
|
+
type: "boolean"
|
|
501
276
|
},
|
|
502
|
-
|
|
503
|
-
type: "
|
|
504
|
-
additionalProperties: true
|
|
277
|
+
token: {
|
|
278
|
+
type: "string"
|
|
505
279
|
}
|
|
506
280
|
},
|
|
507
281
|
required: [
|
|
508
|
-
"
|
|
509
|
-
"
|
|
510
|
-
|
|
282
|
+
"authenticated",
|
|
283
|
+
"token"
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
401: {
|
|
287
|
+
type: "object",
|
|
288
|
+
properties: {
|
|
289
|
+
message: {
|
|
290
|
+
type: "string"
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
required: [
|
|
294
|
+
"message"
|
|
511
295
|
]
|
|
512
296
|
}
|
|
513
297
|
}
|
|
514
298
|
};
|
|
515
|
-
var
|
|
516
|
-
fastify.
|
|
517
|
-
schema:
|
|
518
|
-
}, async (request) =>
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
299
|
+
var bearerAuthRoute = /* @__PURE__ */ __name((fastify) => {
|
|
300
|
+
fastify.get("/bearer", {
|
|
301
|
+
schema: bearerAuthSchema
|
|
302
|
+
}, async (request, reply) => {
|
|
303
|
+
const token = parseBearer(request.headers.authorization);
|
|
304
|
+
const qs = request.query;
|
|
305
|
+
const required = qs?.required ?? true;
|
|
306
|
+
if (!token && required) {
|
|
307
|
+
void reply.header("WWW-Authenticate", "Bearer");
|
|
308
|
+
return reply.status(401).send({
|
|
309
|
+
message: "Unauthorized"
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
if (!token) {
|
|
313
|
+
return reply.send({
|
|
314
|
+
authenticated: false,
|
|
315
|
+
token: ""
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return reply.send({
|
|
319
|
+
authenticated: true,
|
|
320
|
+
token
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
}, "bearerAuthRoute");
|
|
524
324
|
|
|
525
|
-
// src/routes/
|
|
526
|
-
import
|
|
527
|
-
var
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
{
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
325
|
+
// src/routes/auth/digest.ts
|
|
326
|
+
import crypto from "crypto";
|
|
327
|
+
var makeNonce = /* @__PURE__ */ __name(() => crypto.randomBytes(16).toString("hex"), "makeNonce");
|
|
328
|
+
var algorithms = /* @__PURE__ */ new Set([
|
|
329
|
+
"MD5",
|
|
330
|
+
"md5",
|
|
331
|
+
"SHA-256",
|
|
332
|
+
"sha-256",
|
|
333
|
+
"SHA-512",
|
|
334
|
+
"sha-512"
|
|
335
|
+
]);
|
|
336
|
+
var hashAlg = /* @__PURE__ */ __name((alg) => {
|
|
337
|
+
if (!alg) {
|
|
338
|
+
return "md5";
|
|
339
|
+
}
|
|
340
|
+
const a = alg.toLowerCase();
|
|
341
|
+
if (a === "md5") {
|
|
342
|
+
return "md5";
|
|
343
|
+
}
|
|
344
|
+
if (a === "sha-256") {
|
|
345
|
+
return "sha256";
|
|
346
|
+
}
|
|
347
|
+
if (a === "sha-512") {
|
|
348
|
+
return "sha512";
|
|
349
|
+
}
|
|
350
|
+
return "md5";
|
|
351
|
+
}, "hashAlg");
|
|
352
|
+
var h = /* @__PURE__ */ __name((algo, data) => crypto.createHash(algo).update(data).digest("hex"), "h");
|
|
353
|
+
var parseDigest = /* @__PURE__ */ __name((header) => {
|
|
354
|
+
if (!header) {
|
|
355
|
+
return void 0;
|
|
356
|
+
}
|
|
357
|
+
const spaceIndex = header.indexOf(" ");
|
|
358
|
+
if (spaceIndex === -1) {
|
|
359
|
+
return void 0;
|
|
360
|
+
}
|
|
361
|
+
const scheme = header.slice(0, spaceIndex);
|
|
362
|
+
const rest = header.slice(spaceIndex + 1);
|
|
363
|
+
if (!scheme || scheme.toLowerCase() !== "digest" || !rest) {
|
|
364
|
+
return void 0;
|
|
365
|
+
}
|
|
366
|
+
const out = {};
|
|
367
|
+
const parts = [];
|
|
368
|
+
let current = "";
|
|
369
|
+
let inQuotes = false;
|
|
370
|
+
for (const char of rest) {
|
|
371
|
+
if (char === '"') {
|
|
372
|
+
inQuotes = !inQuotes;
|
|
373
|
+
current += char;
|
|
374
|
+
} else if (char === "," && !inQuotes) {
|
|
375
|
+
if (current.trim()) {
|
|
376
|
+
parts.push(current.trim());
|
|
377
|
+
}
|
|
378
|
+
current = "";
|
|
379
|
+
} else {
|
|
380
|
+
current += char;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (current.trim()) {
|
|
384
|
+
parts.push(current.trim());
|
|
385
|
+
}
|
|
386
|
+
if (parts.length === 0) {
|
|
387
|
+
return out;
|
|
388
|
+
}
|
|
389
|
+
for (const p of parts) {
|
|
390
|
+
const equalIndex = p.indexOf("=");
|
|
391
|
+
if (equalIndex === -1) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const k = p.slice(0, equalIndex).trim();
|
|
395
|
+
const v = p.slice(equalIndex + 1).trim();
|
|
396
|
+
let value = v;
|
|
397
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
398
|
+
value = value.slice(1, -1);
|
|
399
|
+
}
|
|
400
|
+
out[k] = value;
|
|
401
|
+
}
|
|
402
|
+
return out;
|
|
403
|
+
}, "parseDigest");
|
|
404
|
+
var digestAuthSchema = {
|
|
405
|
+
description: "HTTP Digest authentication. Mirrors httpbin behavior for testing clients.",
|
|
406
|
+
tags: [
|
|
407
|
+
"Auth"
|
|
408
|
+
],
|
|
409
|
+
params: {
|
|
410
|
+
type: "object",
|
|
411
|
+
properties: {
|
|
412
|
+
qop: {
|
|
413
|
+
type: "string"
|
|
414
|
+
},
|
|
415
|
+
user: {
|
|
416
|
+
type: "string"
|
|
417
|
+
},
|
|
418
|
+
passwd: {
|
|
419
|
+
type: "string"
|
|
420
|
+
},
|
|
421
|
+
algorithm: {
|
|
422
|
+
type: "string"
|
|
423
|
+
},
|
|
424
|
+
stale_after: {
|
|
425
|
+
type: "string"
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
required: [
|
|
429
|
+
"qop",
|
|
430
|
+
"user",
|
|
431
|
+
"passwd"
|
|
432
|
+
]
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
var digestAuthRoute = /* @__PURE__ */ __name((fastify) => {
|
|
436
|
+
fastify.get("/digest-auth/:qop/:user/:passwd", {
|
|
437
|
+
schema: digestAuthSchema
|
|
438
|
+
}, async (request, reply) => {
|
|
439
|
+
const { user, passwd } = request.params;
|
|
440
|
+
const realm = "mockhttp";
|
|
441
|
+
const nonce = makeNonce();
|
|
442
|
+
const auth = parseDigest(request.headers.authorization);
|
|
443
|
+
if (!auth) {
|
|
444
|
+
void reply.header("WWW-Authenticate", `Digest realm="${realm}", qop="auth,auth-int", nonce="${nonce}", opaque="${makeNonce()}"`);
|
|
445
|
+
return reply.status(401).send({
|
|
446
|
+
message: "Unauthorized"
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
if (auth.username !== user) {
|
|
450
|
+
void reply.header("WWW-Authenticate", `Digest realm="${realm}", qop="auth,auth-int", nonce="${nonce}", opaque="${makeNonce()}"`);
|
|
451
|
+
return reply.status(401).send({
|
|
452
|
+
message: "Unauthorized"
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
const method = "GET";
|
|
456
|
+
const uri = auth.uri ?? request.url.replace(/^https?:\/\/[^/]+/, "");
|
|
457
|
+
const algo = hashAlg(auth.algorithm);
|
|
458
|
+
const ha1 = h(algo, `${user}:${realm}:${passwd}`);
|
|
459
|
+
const ha2 = h(algo, `${method}:${uri}`);
|
|
460
|
+
let expected = "";
|
|
461
|
+
expected = auth.qop ? h(algo, `${ha1}:${auth.nonce}:${auth.nc}:${auth.cnonce}:${auth.qop}:${ha2}`) : h(algo, `${ha1}:${auth.nonce}:${ha2}`);
|
|
462
|
+
if (!auth.response || auth.response !== expected) {
|
|
463
|
+
void reply.header("WWW-Authenticate", `Digest realm="${realm}", qop="auth,auth-int", nonce="${nonce}", opaque="${makeNonce()}"`);
|
|
464
|
+
return reply.status(401).send({
|
|
465
|
+
message: "Unauthorized"
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
return reply.send({
|
|
469
|
+
authenticated: true,
|
|
470
|
+
user
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
fastify.get("/digest-auth/:qop/:user/:passwd/:algorithm", {
|
|
474
|
+
schema: digestAuthSchema
|
|
475
|
+
}, async (request, reply) => {
|
|
476
|
+
const { user, passwd, algorithm } = request.params;
|
|
477
|
+
const realm = "mockhttp";
|
|
478
|
+
const algoHeader = algorithms.has(String(algorithm)) ? String(algorithm) : "MD5";
|
|
479
|
+
const nonce = makeNonce();
|
|
480
|
+
const auth = parseDigest(request.headers.authorization);
|
|
481
|
+
if (!auth) {
|
|
482
|
+
void reply.header("WWW-Authenticate", `Digest realm="${realm}", qop="auth,auth-int", algorithm=${algoHeader}, nonce="${nonce}", opaque="${makeNonce()}"`);
|
|
483
|
+
return reply.status(401).send({
|
|
484
|
+
message: "Unauthorized"
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (auth.username !== user) {
|
|
488
|
+
void reply.header("WWW-Authenticate", `Digest realm="${realm}", qop="auth,auth-int", algorithm=${algoHeader}, nonce="${nonce}", opaque="${makeNonce()}"`);
|
|
489
|
+
return reply.status(401).send({
|
|
490
|
+
message: "Unauthorized"
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
const method = "GET";
|
|
494
|
+
const uri = auth.uri ?? request.url.replace(/^https?:\/\/[^/]+/, "");
|
|
495
|
+
const algo = hashAlg(auth.algorithm ?? algoHeader);
|
|
496
|
+
const ha1 = h(algo, `${user}:${realm}:${passwd}`);
|
|
497
|
+
const ha2 = h(algo, `${method}:${uri}`);
|
|
498
|
+
const expected = auth.qop ? h(algo, `${ha1}:${auth.nonce}:${auth.nc}:${auth.cnonce}:${auth.qop}:${ha2}`) : h(algo, `${ha1}:${auth.nonce}:${ha2}`);
|
|
499
|
+
if (!auth.response || auth.response !== expected) {
|
|
500
|
+
void reply.header("WWW-Authenticate", `Digest realm="${realm}", qop="auth,auth-int", algorithm=${algoHeader}, nonce="${nonce}", opaque="${makeNonce()}"`);
|
|
501
|
+
return reply.status(401).send({
|
|
502
|
+
message: "Unauthorized"
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
return reply.send({
|
|
506
|
+
authenticated: true,
|
|
507
|
+
user
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
}, "digestAuthRoute");
|
|
511
|
+
|
|
512
|
+
// src/routes/auth/hidden-basic.ts
|
|
513
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
514
|
+
var parseBasic2 = /* @__PURE__ */ __name((header) => {
|
|
515
|
+
if (!header) {
|
|
516
|
+
return void 0;
|
|
517
|
+
}
|
|
518
|
+
const [scheme, value] = header.split(" ");
|
|
519
|
+
if (!scheme || scheme.toLowerCase() !== "basic" || !value) {
|
|
520
|
+
return void 0;
|
|
521
|
+
}
|
|
522
|
+
try {
|
|
523
|
+
const decoded = Buffer3.from(value, "base64").toString("utf8");
|
|
524
|
+
const idx = decoded.indexOf(":");
|
|
525
|
+
if (idx === -1) {
|
|
526
|
+
return void 0;
|
|
527
|
+
}
|
|
528
|
+
return {
|
|
529
|
+
username: decoded.slice(0, idx),
|
|
530
|
+
password: decoded.slice(idx + 1)
|
|
531
|
+
};
|
|
532
|
+
} catch {
|
|
533
|
+
return void 0;
|
|
534
|
+
}
|
|
535
|
+
}, "parseBasic");
|
|
536
|
+
var hiddenBasicAuthSchema = {
|
|
537
|
+
description: "HTTP Basic authentication with docs hidden. Mirrors /basic-auth but hides from schema.",
|
|
538
|
+
tags: [
|
|
539
|
+
"Auth"
|
|
540
|
+
],
|
|
541
|
+
hide: true,
|
|
542
|
+
params: {
|
|
543
|
+
type: "object",
|
|
544
|
+
properties: {
|
|
545
|
+
user: {
|
|
546
|
+
type: "string"
|
|
547
|
+
},
|
|
548
|
+
passwd: {
|
|
549
|
+
type: "string"
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
required: [
|
|
553
|
+
"user",
|
|
554
|
+
"passwd"
|
|
555
|
+
]
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
var hiddenBasicAuthRoute = /* @__PURE__ */ __name((fastify) => {
|
|
559
|
+
fastify.get("/hidden-basic-auth/:user/:passwd", {
|
|
560
|
+
schema: hiddenBasicAuthSchema
|
|
561
|
+
}, async (request, reply) => {
|
|
562
|
+
const { user, passwd } = request.params;
|
|
563
|
+
const parsed = parseBasic2(request.headers.authorization);
|
|
564
|
+
if (!parsed || parsed.username !== user || parsed.password !== passwd) {
|
|
565
|
+
void reply.header("WWW-Authenticate", 'Basic realm="mockhttp"');
|
|
566
|
+
return reply.status(401).send({
|
|
567
|
+
message: "Unauthorized"
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
return reply.send({
|
|
571
|
+
authenticated: true,
|
|
572
|
+
user
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
}, "hiddenBasicAuthRoute");
|
|
576
|
+
|
|
577
|
+
// src/routes/cookies/delete.ts
|
|
578
|
+
var cookiesDeleteSchema = {
|
|
579
|
+
description: "Delete a cookie",
|
|
580
|
+
tags: [
|
|
581
|
+
"Cookies"
|
|
582
|
+
],
|
|
583
|
+
querystring: {
|
|
584
|
+
type: "object",
|
|
585
|
+
properties: {
|
|
586
|
+
name: {
|
|
587
|
+
type: "string"
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
required: [
|
|
591
|
+
"name"
|
|
592
|
+
],
|
|
593
|
+
additionalProperties: false
|
|
575
594
|
},
|
|
576
|
-
{
|
|
577
|
-
|
|
578
|
-
|
|
595
|
+
response: {
|
|
596
|
+
204: {
|
|
597
|
+
type: "null"
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
var deleteCookieRoute = /* @__PURE__ */ __name((fastify) => {
|
|
602
|
+
fastify.delete("/cookies", {
|
|
603
|
+
schema: cookiesDeleteSchema
|
|
604
|
+
}, async (request, reply) => {
|
|
605
|
+
const { name } = request.query;
|
|
606
|
+
reply.clearCookie(name, {
|
|
607
|
+
path: "/"
|
|
608
|
+
});
|
|
609
|
+
return reply.status(204).send();
|
|
610
|
+
});
|
|
611
|
+
}, "deleteCookieRoute");
|
|
612
|
+
|
|
613
|
+
// src/routes/cookies/get.ts
|
|
614
|
+
var getCookiesRouteSchema = {
|
|
615
|
+
description: "Return cookies from the request",
|
|
616
|
+
tags: [
|
|
617
|
+
"Cookies"
|
|
618
|
+
],
|
|
619
|
+
response: {
|
|
620
|
+
200: {
|
|
621
|
+
type: "object",
|
|
622
|
+
properties: {
|
|
623
|
+
cookies: {
|
|
624
|
+
type: "object",
|
|
625
|
+
additionalProperties: {
|
|
626
|
+
type: "string"
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
required: [
|
|
631
|
+
"cookies"
|
|
632
|
+
]
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
var getCookiesRoute = /* @__PURE__ */ __name((fastify) => {
|
|
637
|
+
fastify.get("/cookies", {
|
|
638
|
+
schema: getCookiesRouteSchema
|
|
639
|
+
}, async (request, reply) => {
|
|
640
|
+
reply.type("application/json");
|
|
641
|
+
await reply.send({
|
|
642
|
+
cookies: request.cookies
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
}, "getCookiesRoute");
|
|
646
|
+
|
|
647
|
+
// src/routes/cookies/post.ts
|
|
648
|
+
var postCookieRouteSchema = {
|
|
649
|
+
description: "Set a cookie",
|
|
650
|
+
tags: [
|
|
651
|
+
"Cookies"
|
|
652
|
+
],
|
|
653
|
+
body: {
|
|
654
|
+
type: "object",
|
|
655
|
+
properties: {
|
|
656
|
+
name: {
|
|
657
|
+
type: "string"
|
|
658
|
+
},
|
|
659
|
+
value: {
|
|
660
|
+
type: "string"
|
|
661
|
+
},
|
|
662
|
+
expires: {
|
|
663
|
+
type: "string",
|
|
664
|
+
format: "date-time"
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
required: [
|
|
668
|
+
"name",
|
|
669
|
+
"value"
|
|
670
|
+
],
|
|
671
|
+
additionalProperties: false
|
|
579
672
|
},
|
|
580
|
-
{
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
},
|
|
596
|
-
{
|
|
597
|
-
code: 303,
|
|
598
|
-
message: "See Other"
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
code: 304,
|
|
602
|
-
message: "Not Modified"
|
|
603
|
-
},
|
|
604
|
-
{
|
|
605
|
-
code: 305,
|
|
606
|
-
message: "Use Proxy"
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
code: 306,
|
|
610
|
-
message: "Switch Proxy"
|
|
611
|
-
},
|
|
612
|
-
{
|
|
613
|
-
code: 307,
|
|
614
|
-
message: "Temporary Redirect"
|
|
615
|
-
},
|
|
616
|
-
{
|
|
617
|
-
code: 308,
|
|
618
|
-
message: "Permanent Redirect"
|
|
619
|
-
},
|
|
620
|
-
{
|
|
621
|
-
code: 400,
|
|
622
|
-
message: "Bad Request"
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
code: 401,
|
|
626
|
-
message: "Unauthorized"
|
|
627
|
-
},
|
|
628
|
-
{
|
|
629
|
-
code: 402,
|
|
630
|
-
message: "Payment Required"
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
code: 403,
|
|
634
|
-
message: "Forbidden"
|
|
635
|
-
},
|
|
636
|
-
{
|
|
637
|
-
code: 404,
|
|
638
|
-
message: "Not Found"
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
code: 405,
|
|
642
|
-
message: "Method Not Allowed"
|
|
643
|
-
},
|
|
644
|
-
{
|
|
645
|
-
code: 406,
|
|
646
|
-
message: "Not Acceptable"
|
|
647
|
-
},
|
|
648
|
-
{
|
|
649
|
-
code: 407,
|
|
650
|
-
message: "Proxy Authentication Required"
|
|
651
|
-
},
|
|
652
|
-
{
|
|
653
|
-
code: 408,
|
|
654
|
-
message: "Request Timeout"
|
|
655
|
-
},
|
|
656
|
-
{
|
|
657
|
-
code: 409,
|
|
658
|
-
message: "Conflict"
|
|
659
|
-
},
|
|
660
|
-
{
|
|
661
|
-
code: 410,
|
|
662
|
-
message: "Gone"
|
|
663
|
-
},
|
|
664
|
-
{
|
|
665
|
-
code: 411,
|
|
666
|
-
message: "Length Required"
|
|
667
|
-
},
|
|
668
|
-
{
|
|
669
|
-
code: 412,
|
|
670
|
-
message: "Precondition Failed"
|
|
671
|
-
},
|
|
672
|
-
{
|
|
673
|
-
code: 413,
|
|
674
|
-
message: "Payload Too Large"
|
|
675
|
-
},
|
|
676
|
-
{
|
|
677
|
-
code: 414,
|
|
678
|
-
message: "URI Too Long"
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
code: 415,
|
|
682
|
-
message: "Unsupported Media Type"
|
|
683
|
-
},
|
|
684
|
-
{
|
|
685
|
-
code: 416,
|
|
686
|
-
message: "Range Not Satisfiable"
|
|
687
|
-
},
|
|
688
|
-
{
|
|
689
|
-
code: 417,
|
|
690
|
-
message: "Expectation Failed"
|
|
691
|
-
},
|
|
692
|
-
{
|
|
693
|
-
code: 418,
|
|
694
|
-
message: "I'm a teapot"
|
|
695
|
-
},
|
|
696
|
-
{
|
|
697
|
-
code: 421,
|
|
698
|
-
message: "Misdirected Request"
|
|
699
|
-
},
|
|
700
|
-
{
|
|
701
|
-
code: 422,
|
|
702
|
-
message: "Unprocessable Entity"
|
|
703
|
-
},
|
|
704
|
-
{
|
|
705
|
-
code: 423,
|
|
706
|
-
message: "Locked"
|
|
707
|
-
},
|
|
708
|
-
{
|
|
709
|
-
code: 424,
|
|
710
|
-
message: "Failed Dependency"
|
|
711
|
-
},
|
|
712
|
-
{
|
|
713
|
-
code: 425,
|
|
714
|
-
message: "Too Early"
|
|
715
|
-
},
|
|
716
|
-
{
|
|
717
|
-
code: 426,
|
|
718
|
-
message: "Upgrade Required"
|
|
719
|
-
},
|
|
720
|
-
{
|
|
721
|
-
code: 428,
|
|
722
|
-
message: "Precondition Required"
|
|
723
|
-
},
|
|
724
|
-
{
|
|
725
|
-
code: 429,
|
|
726
|
-
message: "Too Many Requests"
|
|
727
|
-
},
|
|
728
|
-
{
|
|
729
|
-
code: 431,
|
|
730
|
-
message: "Request Header Fields Too Large"
|
|
731
|
-
},
|
|
732
|
-
{
|
|
733
|
-
code: 451,
|
|
734
|
-
message: "Unavailable For Legal Reasons"
|
|
735
|
-
},
|
|
736
|
-
{
|
|
737
|
-
code: 500,
|
|
738
|
-
message: "Internal Server Error"
|
|
739
|
-
},
|
|
740
|
-
{
|
|
741
|
-
code: 501,
|
|
742
|
-
message: "Not Implemented"
|
|
743
|
-
},
|
|
744
|
-
{
|
|
745
|
-
code: 502,
|
|
746
|
-
message: "Bad Gateway"
|
|
747
|
-
},
|
|
748
|
-
{
|
|
749
|
-
code: 503,
|
|
750
|
-
message: "Service Unavailable"
|
|
751
|
-
},
|
|
752
|
-
{
|
|
753
|
-
code: 504,
|
|
754
|
-
message: "Gateway Timeout"
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
code: 505,
|
|
758
|
-
message: "HTTP Version Not Supported"
|
|
759
|
-
},
|
|
760
|
-
{
|
|
761
|
-
code: 506,
|
|
762
|
-
message: "Variant Also Negotiates"
|
|
763
|
-
},
|
|
764
|
-
{
|
|
765
|
-
code: 507,
|
|
766
|
-
message: "Insufficient Storage"
|
|
767
|
-
},
|
|
768
|
-
{
|
|
769
|
-
code: 508,
|
|
770
|
-
message: "Loop Detected"
|
|
771
|
-
},
|
|
772
|
-
{
|
|
773
|
-
code: 510,
|
|
774
|
-
message: "Not Extended"
|
|
775
|
-
},
|
|
776
|
-
{
|
|
777
|
-
code: 511,
|
|
778
|
-
message: "Network Authentication Required"
|
|
673
|
+
response: {
|
|
674
|
+
200: {
|
|
675
|
+
type: "object",
|
|
676
|
+
properties: {
|
|
677
|
+
cookies: {
|
|
678
|
+
type: "object",
|
|
679
|
+
additionalProperties: {
|
|
680
|
+
type: "string"
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
required: [
|
|
685
|
+
"cookies"
|
|
686
|
+
]
|
|
687
|
+
}
|
|
779
688
|
}
|
|
780
|
-
|
|
781
|
-
var
|
|
782
|
-
|
|
689
|
+
};
|
|
690
|
+
var postCookieRoute = /* @__PURE__ */ __name((fastify) => {
|
|
691
|
+
fastify.post("/cookies", {
|
|
692
|
+
schema: postCookieRouteSchema
|
|
693
|
+
}, async (request, reply) => {
|
|
694
|
+
const { name, value, expires } = request.body;
|
|
695
|
+
if (expires) {
|
|
696
|
+
const date = new Date(expires);
|
|
697
|
+
reply.setCookie(name, value, {
|
|
698
|
+
path: "/",
|
|
699
|
+
expires: date
|
|
700
|
+
});
|
|
701
|
+
} else {
|
|
702
|
+
reply.setCookie(name, value, {
|
|
703
|
+
path: "/"
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
return reply.status(200).send();
|
|
707
|
+
});
|
|
708
|
+
}, "postCookieRoute");
|
|
709
|
+
|
|
710
|
+
// src/routes/http-methods/delete.ts
|
|
711
|
+
var deleteSchema = {
|
|
712
|
+
description: "Handles a DELETE request and returns request information",
|
|
783
713
|
tags: [
|
|
784
|
-
"
|
|
714
|
+
"HTTP Methods"
|
|
785
715
|
],
|
|
786
|
-
|
|
716
|
+
body: {
|
|
787
717
|
type: "object",
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
type: "string",
|
|
791
|
-
description: "HTTP status code to be returned"
|
|
792
|
-
}
|
|
793
|
-
}
|
|
718
|
+
additionalProperties: true,
|
|
719
|
+
description: "The body of the DELETE request"
|
|
794
720
|
},
|
|
795
721
|
response: {
|
|
796
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
797
722
|
200: {
|
|
798
723
|
type: "object",
|
|
799
724
|
properties: {
|
|
800
|
-
|
|
725
|
+
method: {
|
|
801
726
|
type: "string"
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
727
|
+
},
|
|
728
|
+
headers: {
|
|
729
|
+
type: "object",
|
|
730
|
+
additionalProperties: {
|
|
731
|
+
type: "string"
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
body: {
|
|
735
|
+
type: "object",
|
|
736
|
+
additionalProperties: true
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
required: [
|
|
740
|
+
"method",
|
|
741
|
+
"headers",
|
|
742
|
+
"body"
|
|
743
|
+
]
|
|
812
744
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
schema: statusSchema
|
|
825
|
-
}, handler);
|
|
826
|
-
fastify.patch("/status/:code?", {
|
|
827
|
-
schema: statusSchema
|
|
828
|
-
}, handler);
|
|
829
|
-
fastify.delete("/status/:code?", {
|
|
830
|
-
schema: statusSchema
|
|
831
|
-
}, handler);
|
|
832
|
-
}, "statusCodeRoute");
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
var deleteRoute = /* @__PURE__ */ __name((fastify) => {
|
|
748
|
+
fastify.delete("/delete", {
|
|
749
|
+
schema: deleteSchema
|
|
750
|
+
}, async (request) => ({
|
|
751
|
+
method: "DELETE",
|
|
752
|
+
headers: request.headers,
|
|
753
|
+
body: request.body
|
|
754
|
+
}));
|
|
755
|
+
}, "deleteRoute");
|
|
833
756
|
|
|
834
|
-
// src/routes/
|
|
835
|
-
var
|
|
836
|
-
description: "Returns
|
|
757
|
+
// src/routes/http-methods/get.ts
|
|
758
|
+
var getSchema = {
|
|
759
|
+
description: "Returns request information for GET requests",
|
|
837
760
|
tags: [
|
|
838
|
-
"
|
|
761
|
+
"HTTP Methods"
|
|
839
762
|
],
|
|
763
|
+
querystring: {
|
|
764
|
+
type: "object",
|
|
765
|
+
additionalProperties: true,
|
|
766
|
+
properties: {},
|
|
767
|
+
description: "Query parameters sent in the request"
|
|
768
|
+
},
|
|
769
|
+
headers: {
|
|
770
|
+
type: "object",
|
|
771
|
+
additionalProperties: true,
|
|
772
|
+
properties: {},
|
|
773
|
+
description: "Headers sent in the request"
|
|
774
|
+
},
|
|
840
775
|
response: {
|
|
841
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
842
776
|
200: {
|
|
843
777
|
type: "object",
|
|
844
778
|
properties: {
|
|
845
|
-
|
|
846
|
-
type: "string"
|
|
847
|
-
|
|
779
|
+
method: {
|
|
780
|
+
type: "string"
|
|
781
|
+
},
|
|
782
|
+
headers: {
|
|
783
|
+
type: "object",
|
|
784
|
+
additionalProperties: {
|
|
785
|
+
type: "string"
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
queryParams: {
|
|
789
|
+
type: "object",
|
|
790
|
+
additionalProperties: {
|
|
791
|
+
type: "string"
|
|
792
|
+
}
|
|
848
793
|
}
|
|
849
794
|
},
|
|
850
795
|
required: [
|
|
851
|
-
"
|
|
796
|
+
"method",
|
|
797
|
+
"headers",
|
|
798
|
+
"queryParams"
|
|
852
799
|
]
|
|
853
800
|
}
|
|
854
801
|
}
|
|
855
802
|
};
|
|
856
|
-
var
|
|
857
|
-
fastify.get("/
|
|
858
|
-
schema:
|
|
859
|
-
}, async (request) => {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
ip
|
|
866
|
-
};
|
|
867
|
-
});
|
|
868
|
-
}, "ipRoute");
|
|
803
|
+
var getRoute = /* @__PURE__ */ __name((fastify) => {
|
|
804
|
+
fastify.get("/get", {
|
|
805
|
+
schema: getSchema
|
|
806
|
+
}, async (request, _reply) => ({
|
|
807
|
+
method: "GET",
|
|
808
|
+
headers: request.headers,
|
|
809
|
+
queryParams: request.query
|
|
810
|
+
}));
|
|
811
|
+
}, "getRoute");
|
|
869
812
|
|
|
870
|
-
// src/routes/
|
|
871
|
-
var
|
|
872
|
-
description: "
|
|
813
|
+
// src/routes/http-methods/patch.ts
|
|
814
|
+
var patchSchema = {
|
|
815
|
+
description: "Handles a PATCH request and returns request information",
|
|
873
816
|
tags: [
|
|
874
|
-
"
|
|
817
|
+
"HTTP Methods"
|
|
875
818
|
],
|
|
819
|
+
body: {
|
|
820
|
+
type: "object",
|
|
821
|
+
additionalProperties: true,
|
|
822
|
+
description: "The body of the PATCH request"
|
|
823
|
+
},
|
|
876
824
|
response: {
|
|
877
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
878
825
|
200: {
|
|
879
826
|
type: "object",
|
|
880
827
|
properties: {
|
|
828
|
+
method: {
|
|
829
|
+
type: "string"
|
|
830
|
+
},
|
|
881
831
|
headers: {
|
|
882
832
|
type: "object",
|
|
883
833
|
additionalProperties: {
|
|
884
834
|
type: "string"
|
|
885
|
-
}
|
|
886
|
-
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
body: {
|
|
838
|
+
type: "object",
|
|
839
|
+
additionalProperties: true
|
|
887
840
|
}
|
|
888
841
|
},
|
|
889
842
|
required: [
|
|
890
|
-
"
|
|
843
|
+
"method",
|
|
844
|
+
"headers",
|
|
845
|
+
"body"
|
|
891
846
|
]
|
|
892
847
|
}
|
|
893
848
|
}
|
|
894
849
|
};
|
|
895
|
-
var
|
|
896
|
-
fastify.
|
|
897
|
-
schema:
|
|
898
|
-
}, async (request) => {
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
}, "headersRoute");
|
|
850
|
+
var patchRoute = /* @__PURE__ */ __name((fastify) => {
|
|
851
|
+
fastify.patch("/patch", {
|
|
852
|
+
schema: patchSchema
|
|
853
|
+
}, async (request) => ({
|
|
854
|
+
method: "PATCH",
|
|
855
|
+
headers: request.headers,
|
|
856
|
+
body: request.body
|
|
857
|
+
}));
|
|
858
|
+
}, "patchRoute");
|
|
905
859
|
|
|
906
|
-
// src/routes/
|
|
907
|
-
var
|
|
908
|
-
description: "
|
|
860
|
+
// src/routes/http-methods/post.ts
|
|
861
|
+
var postSchema = {
|
|
862
|
+
description: "Handles a POST request and returns request information",
|
|
909
863
|
tags: [
|
|
910
|
-
"
|
|
864
|
+
"HTTP Methods"
|
|
911
865
|
],
|
|
866
|
+
body: {
|
|
867
|
+
type: "object",
|
|
868
|
+
additionalProperties: true,
|
|
869
|
+
description: "The body of the POST request"
|
|
870
|
+
},
|
|
912
871
|
response: {
|
|
913
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
914
872
|
200: {
|
|
915
873
|
type: "object",
|
|
916
874
|
properties: {
|
|
917
|
-
|
|
918
|
-
type: "string"
|
|
919
|
-
|
|
875
|
+
method: {
|
|
876
|
+
type: "string"
|
|
877
|
+
},
|
|
878
|
+
headers: {
|
|
879
|
+
type: "object",
|
|
880
|
+
additionalProperties: {
|
|
881
|
+
type: "string"
|
|
882
|
+
}
|
|
883
|
+
},
|
|
884
|
+
body: {
|
|
885
|
+
type: "object",
|
|
886
|
+
additionalProperties: true
|
|
920
887
|
}
|
|
921
888
|
},
|
|
922
889
|
required: [
|
|
923
|
-
"
|
|
890
|
+
"method",
|
|
891
|
+
"headers",
|
|
892
|
+
"body"
|
|
924
893
|
]
|
|
925
894
|
}
|
|
926
895
|
}
|
|
927
896
|
};
|
|
928
|
-
var
|
|
929
|
-
fastify.
|
|
930
|
-
schema:
|
|
931
|
-
}, async (request) => {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
}, "userAgentRoute");
|
|
897
|
+
var postRoute = /* @__PURE__ */ __name((fastify) => {
|
|
898
|
+
fastify.post("/post", {
|
|
899
|
+
schema: postSchema
|
|
900
|
+
}, async (request) => ({
|
|
901
|
+
method: "POST",
|
|
902
|
+
headers: request.headers,
|
|
903
|
+
body: request.body
|
|
904
|
+
}));
|
|
905
|
+
}, "postRoute");
|
|
938
906
|
|
|
939
|
-
// src/routes/
|
|
940
|
-
var
|
|
941
|
-
description: "Handles
|
|
907
|
+
// src/routes/http-methods/put.ts
|
|
908
|
+
var putSchema = {
|
|
909
|
+
description: "Handles a PUT request and returns request information",
|
|
942
910
|
tags: [
|
|
943
|
-
"
|
|
911
|
+
"HTTP Methods"
|
|
944
912
|
],
|
|
913
|
+
body: {
|
|
914
|
+
type: "object",
|
|
915
|
+
additionalProperties: true,
|
|
916
|
+
description: "The body of the PUT request"
|
|
917
|
+
},
|
|
945
918
|
response: {
|
|
946
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
947
919
|
200: {
|
|
948
|
-
type: "
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
920
|
+
type: "object",
|
|
921
|
+
properties: {
|
|
922
|
+
method: {
|
|
923
|
+
type: "string"
|
|
924
|
+
},
|
|
925
|
+
headers: {
|
|
926
|
+
type: "object",
|
|
927
|
+
additionalProperties: {
|
|
928
|
+
type: "string"
|
|
929
|
+
}
|
|
930
|
+
},
|
|
931
|
+
body: {
|
|
932
|
+
type: "object",
|
|
933
|
+
additionalProperties: true
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
required: [
|
|
937
|
+
"method",
|
|
938
|
+
"headers",
|
|
939
|
+
"body"
|
|
940
|
+
]
|
|
955
941
|
}
|
|
956
942
|
}
|
|
957
943
|
};
|
|
958
|
-
var
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
type: "integer",
|
|
968
|
-
description: "Number of seconds to cache the resource."
|
|
969
|
-
}
|
|
970
|
-
},
|
|
971
|
-
required: [
|
|
972
|
-
"value"
|
|
973
|
-
]
|
|
974
|
-
},
|
|
975
|
-
response: {
|
|
976
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
977
|
-
200: {
|
|
978
|
-
type: "string",
|
|
979
|
-
description: "Confirmation message for setting cache."
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
};
|
|
983
|
-
var cacheRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
984
|
-
fastify.get("/cache", {
|
|
985
|
-
schema: cacheGetSchema
|
|
986
|
-
}, async (request, reply) => {
|
|
987
|
-
const ifModifiedSince = request.headers["if-modified-since"];
|
|
988
|
-
const ifNoneMatch = request.headers["if-none-match"];
|
|
989
|
-
if (ifModifiedSince ?? ifNoneMatch) {
|
|
990
|
-
await reply.status(304).send();
|
|
991
|
-
return;
|
|
992
|
-
}
|
|
993
|
-
await reply.send("Cache content or resource response here.");
|
|
994
|
-
});
|
|
995
|
-
fastify.get("/cache/:value", {
|
|
996
|
-
schema: cacheSetSchema
|
|
997
|
-
}, async (request, reply) => {
|
|
998
|
-
const { value } = request.params;
|
|
999
|
-
await reply.header("Cache-Control", `max-age=${value}`).send(`Cache-Control set for ${value} seconds.`);
|
|
1000
|
-
});
|
|
1001
|
-
}, "cacheRoutes");
|
|
944
|
+
var putRoute = /* @__PURE__ */ __name((fastify) => {
|
|
945
|
+
fastify.put("/put", {
|
|
946
|
+
schema: putSchema
|
|
947
|
+
}, async (request) => ({
|
|
948
|
+
method: "PUT",
|
|
949
|
+
headers: request.headers,
|
|
950
|
+
body: request.body
|
|
951
|
+
}));
|
|
952
|
+
}, "putRoute");
|
|
1002
953
|
|
|
1003
|
-
// src/routes/
|
|
1004
|
-
var
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
],
|
|
1009
|
-
params: {
|
|
1010
|
-
type: "object",
|
|
1011
|
-
properties: {
|
|
1012
|
-
etag: {
|
|
1013
|
-
type: "string",
|
|
1014
|
-
description: "The ETag value for the resource."
|
|
1015
|
-
}
|
|
1016
|
-
},
|
|
1017
|
-
required: [
|
|
1018
|
-
"etag"
|
|
1019
|
-
]
|
|
1020
|
-
},
|
|
1021
|
-
response: {
|
|
1022
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1023
|
-
200: {
|
|
1024
|
-
type: "string",
|
|
1025
|
-
description: "Resource content for matching ETag."
|
|
1026
|
-
},
|
|
1027
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1028
|
-
304: {
|
|
1029
|
-
type: "null",
|
|
1030
|
-
description: "Indicates the resource has not been modified."
|
|
1031
|
-
},
|
|
1032
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1033
|
-
412: {
|
|
1034
|
-
type: "null",
|
|
1035
|
-
description: "Indicates a precondition failed due to mismatched ETag."
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
};
|
|
1039
|
-
var etagRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1040
|
-
fastify.get("/etag/:etag", {
|
|
1041
|
-
schema: etagSchema
|
|
1042
|
-
}, async (request, reply) => {
|
|
1043
|
-
const { etag } = request.params;
|
|
1044
|
-
const ifNoneMatch = request.headers["if-none-match"];
|
|
1045
|
-
const ifMatch = request.headers["if-match"];
|
|
1046
|
-
if (ifNoneMatch === etag) {
|
|
1047
|
-
await reply.status(304).send();
|
|
1048
|
-
return;
|
|
1049
|
-
}
|
|
1050
|
-
if (ifMatch && ifMatch !== etag) {
|
|
1051
|
-
await reply.status(412).send();
|
|
1052
|
-
return;
|
|
954
|
+
// src/routes/index.ts
|
|
955
|
+
var indexRoute = /* @__PURE__ */ __name((fastify) => {
|
|
956
|
+
fastify.get("/", {
|
|
957
|
+
schema: {
|
|
958
|
+
hide: true
|
|
1053
959
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
960
|
+
}, async (_request, reply) => {
|
|
961
|
+
const redocHtml = `
|
|
962
|
+
<!doctype html>
|
|
963
|
+
<html>
|
|
964
|
+
<head>
|
|
965
|
+
<title>{ mockhttp }</title>
|
|
966
|
+
<meta charset="utf-8" />
|
|
967
|
+
<meta
|
|
968
|
+
name="viewport"
|
|
969
|
+
content="width=device-width, initial-scale=1" />
|
|
970
|
+
<style>
|
|
971
|
+
:root {
|
|
972
|
+
--scalar-custom-header-height: 70px;
|
|
973
|
+
}
|
|
974
|
+
.custom-header {
|
|
975
|
+
height: var(--scalar-custom-header-height);
|
|
976
|
+
background-color: var(--scalar-background-1);
|
|
977
|
+
box-shadow: inset 0 -1px 0 var(--scalar-border-color);
|
|
978
|
+
color: var(--scalar-color-1);
|
|
979
|
+
font-size: var(--scalar-font-size-2);
|
|
980
|
+
padding: 0 18px;
|
|
981
|
+
position: sticky;
|
|
982
|
+
justify-content: space-between;
|
|
983
|
+
top: 0;
|
|
984
|
+
z-index: 100;
|
|
985
|
+
}
|
|
986
|
+
.custom-header,
|
|
987
|
+
.custom-header nav {
|
|
988
|
+
display: flex;
|
|
989
|
+
align-items: center;
|
|
990
|
+
gap: 18px;
|
|
991
|
+
}
|
|
1057
992
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
await reply.send(
|
|
1092
|
-
});
|
|
1093
|
-
fastify.post("/response-headers", {
|
|
1094
|
-
schema: responseHeadersSchema
|
|
1095
|
-
}, async (request, reply) => {
|
|
1096
|
-
const queryParameters = request.query ?? {};
|
|
1097
|
-
const body = request.body ?? {};
|
|
1098
|
-
for (const [key, value] of Object.entries(queryParameters)) {
|
|
1099
|
-
reply.header(key, escape(value));
|
|
1100
|
-
}
|
|
1101
|
-
for (const [key, value] of Object.entries(body)) {
|
|
1102
|
-
reply.header(key, escape(value));
|
|
1103
|
-
}
|
|
1104
|
-
const cleanedResponse = Object.fromEntries(Object.entries({
|
|
1105
|
-
...queryParameters,
|
|
1106
|
-
...body
|
|
1107
|
-
}).map(([key, value]) => [
|
|
1108
|
-
key,
|
|
1109
|
-
escape(value)
|
|
1110
|
-
]));
|
|
1111
|
-
await reply.send(cleanedResponse);
|
|
993
|
+
.custom-header img {
|
|
994
|
+
height: var(--scalar-custom-header-height);
|
|
995
|
+
object-fit: contain;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
.custom-header a:hover {
|
|
999
|
+
color: var(--scalar-color-2);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
.github-corner {
|
|
1003
|
+
fill: var(--scalar-border-color) !important;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
</style>
|
|
1007
|
+
</head>
|
|
1008
|
+
<body>
|
|
1009
|
+
<header class="custom-header scalar-app">
|
|
1010
|
+
<a href="/"><img src="/logo.svg" alt="{ mockhttp }" /></a>
|
|
1011
|
+
<a href="https://github.com/jaredwray/mockhttp" class="github-corner" aria-label="View source on GitHub">
|
|
1012
|
+
<svg width="70" height="70" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true">
|
|
1013
|
+
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
|
1014
|
+
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
|
|
1015
|
+
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
|
1016
|
+
</header>
|
|
1017
|
+
|
|
1018
|
+
<script
|
|
1019
|
+
id="api-reference"
|
|
1020
|
+
data-url="/docs/json"></script>
|
|
1021
|
+
|
|
1022
|
+
<script src="/scalar/browser/standalone.js"></script>
|
|
1023
|
+
</body>
|
|
1024
|
+
</html>
|
|
1025
|
+
`;
|
|
1026
|
+
await reply.type("text/html").send(redocHtml);
|
|
1112
1027
|
});
|
|
1113
|
-
}, "
|
|
1028
|
+
}, "indexRoute");
|
|
1114
1029
|
|
|
1115
1030
|
// src/routes/redirects/absolute-redirect.ts
|
|
1116
1031
|
var absoluteRedirectSchema = {
|
|
@@ -1142,7 +1057,6 @@ var absoluteRedirectSchema = {
|
|
|
1142
1057
|
]
|
|
1143
1058
|
},
|
|
1144
1059
|
response: {
|
|
1145
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1146
1060
|
302: {
|
|
1147
1061
|
type: "string"
|
|
1148
1062
|
}
|
|
@@ -1173,84 +1087,24 @@ var absoluteRedirectRoute = /* @__PURE__ */ __name((fastify) => {
|
|
|
1173
1087
|
});
|
|
1174
1088
|
}, "absoluteRedirectRoute");
|
|
1175
1089
|
|
|
1176
|
-
// src/routes/redirects/
|
|
1177
|
-
var
|
|
1090
|
+
// src/routes/redirects/redirect-to.ts
|
|
1091
|
+
var redirectToSchema = {
|
|
1178
1092
|
tags: [
|
|
1179
1093
|
"Redirects"
|
|
1180
1094
|
],
|
|
1181
|
-
description: "Redirects the request to the target URL
|
|
1182
|
-
|
|
1183
|
-
type: "object",
|
|
1184
|
-
properties: {
|
|
1185
|
-
value: {
|
|
1186
|
-
type: "integer",
|
|
1187
|
-
minimum: 1
|
|
1188
|
-
}
|
|
1189
|
-
},
|
|
1190
|
-
required: [
|
|
1191
|
-
"value"
|
|
1192
|
-
]
|
|
1193
|
-
},
|
|
1194
|
-
headers: {
|
|
1095
|
+
description: "Redirects the request to the target URL",
|
|
1096
|
+
querystring: {
|
|
1195
1097
|
type: "object",
|
|
1196
1098
|
properties: {
|
|
1197
|
-
|
|
1198
|
-
type: "string"
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1207
|
-
302: {
|
|
1208
|
-
type: "string"
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
};
|
|
1212
|
-
var relativeRedirectRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1213
|
-
fastify.get("/relative-redirect/:value", {
|
|
1214
|
-
schema: relativeRedirectSchema
|
|
1215
|
-
}, async (request, reply) => {
|
|
1216
|
-
const { value } = request.params;
|
|
1217
|
-
let url = "/get";
|
|
1218
|
-
let html = `
|
|
1219
|
-
<title>Redirecting...</title>
|
|
1220
|
-
<h1>Redirecting...</h1>
|
|
1221
|
-
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1222
|
-
`;
|
|
1223
|
-
if (value > 1) {
|
|
1224
|
-
url = `/relative-redirect/${value - 1}`;
|
|
1225
|
-
html = `
|
|
1226
|
-
<title>Redirecting...</title>
|
|
1227
|
-
<h1>Redirecting...</h1>
|
|
1228
|
-
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1229
|
-
`;
|
|
1230
|
-
}
|
|
1231
|
-
await reply.header("Location", url).status(302).type("text/html").send(html);
|
|
1232
|
-
});
|
|
1233
|
-
}, "relativeRedirectRoute");
|
|
1234
|
-
|
|
1235
|
-
// src/routes/redirects/redirect-to.ts
|
|
1236
|
-
var redirectToSchema = {
|
|
1237
|
-
tags: [
|
|
1238
|
-
"Redirects"
|
|
1239
|
-
],
|
|
1240
|
-
description: "Redirects the request to the target URL",
|
|
1241
|
-
querystring: {
|
|
1242
|
-
type: "object",
|
|
1243
|
-
properties: {
|
|
1244
|
-
url: {
|
|
1245
|
-
type: "string",
|
|
1246
|
-
format: "uri",
|
|
1247
|
-
description: "The URL to redirect to"
|
|
1248
|
-
},
|
|
1249
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1250
|
-
status_code: {
|
|
1251
|
-
type: "string",
|
|
1252
|
-
pattern: "^[1-5][0-9][0-9]$",
|
|
1253
|
-
description: "The HTTP status code to use for redirection"
|
|
1099
|
+
url: {
|
|
1100
|
+
type: "string",
|
|
1101
|
+
format: "uri",
|
|
1102
|
+
description: "The URL to redirect to"
|
|
1103
|
+
},
|
|
1104
|
+
status_code: {
|
|
1105
|
+
type: "string",
|
|
1106
|
+
pattern: "^[1-5][0-9][0-9]$",
|
|
1107
|
+
description: "The HTTP status code to use for redirection"
|
|
1254
1108
|
}
|
|
1255
1109
|
},
|
|
1256
1110
|
required: [
|
|
@@ -1282,235 +1136,984 @@ var redirectToRoute = /* @__PURE__ */ __name((fastify) => {
|
|
|
1282
1136
|
}, handler);
|
|
1283
1137
|
}, "redirectToRoute");
|
|
1284
1138
|
|
|
1285
|
-
// src/routes/
|
|
1286
|
-
var
|
|
1287
|
-
description: "Return cookies from the request",
|
|
1139
|
+
// src/routes/redirects/relative-redirect.ts
|
|
1140
|
+
var relativeRedirectSchema = {
|
|
1288
1141
|
tags: [
|
|
1289
|
-
"
|
|
1142
|
+
"Redirects"
|
|
1143
|
+
],
|
|
1144
|
+
description: "Redirects the request to the target URL using an relative URL",
|
|
1145
|
+
params: {
|
|
1146
|
+
type: "object",
|
|
1147
|
+
properties: {
|
|
1148
|
+
value: {
|
|
1149
|
+
type: "integer",
|
|
1150
|
+
minimum: 1
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1153
|
+
required: [
|
|
1154
|
+
"value"
|
|
1155
|
+
]
|
|
1156
|
+
},
|
|
1157
|
+
headers: {
|
|
1158
|
+
type: "object",
|
|
1159
|
+
properties: {
|
|
1160
|
+
host: {
|
|
1161
|
+
type: "string"
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
required: [
|
|
1165
|
+
"host"
|
|
1166
|
+
]
|
|
1167
|
+
},
|
|
1168
|
+
response: {
|
|
1169
|
+
302: {
|
|
1170
|
+
type: "string"
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
var relativeRedirectRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1175
|
+
fastify.get("/relative-redirect/:value", {
|
|
1176
|
+
schema: relativeRedirectSchema
|
|
1177
|
+
}, async (request, reply) => {
|
|
1178
|
+
const { value } = request.params;
|
|
1179
|
+
let url = "/get";
|
|
1180
|
+
let html = `
|
|
1181
|
+
<title>Redirecting...</title>
|
|
1182
|
+
<h1>Redirecting...</h1>
|
|
1183
|
+
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1184
|
+
`;
|
|
1185
|
+
if (value > 1) {
|
|
1186
|
+
url = `/relative-redirect/${value - 1}`;
|
|
1187
|
+
html = `
|
|
1188
|
+
<title>Redirecting...</title>
|
|
1189
|
+
<h1>Redirecting...</h1>
|
|
1190
|
+
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1191
|
+
`;
|
|
1192
|
+
}
|
|
1193
|
+
await reply.header("Location", url).status(302).type("text/html").send(html);
|
|
1194
|
+
});
|
|
1195
|
+
}, "relativeRedirectRoute");
|
|
1196
|
+
|
|
1197
|
+
// src/routes/request-inspection/headers.ts
|
|
1198
|
+
var headersSchema = {
|
|
1199
|
+
description: "Returns all headers of the client request",
|
|
1200
|
+
tags: [
|
|
1201
|
+
"Request Inspection"
|
|
1290
1202
|
],
|
|
1291
1203
|
response: {
|
|
1292
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1293
1204
|
200: {
|
|
1294
1205
|
type: "object",
|
|
1295
1206
|
properties: {
|
|
1296
|
-
|
|
1207
|
+
headers: {
|
|
1297
1208
|
type: "object",
|
|
1298
1209
|
additionalProperties: {
|
|
1299
1210
|
type: "string"
|
|
1300
|
-
}
|
|
1211
|
+
},
|
|
1212
|
+
description: "All headers of the client request"
|
|
1301
1213
|
}
|
|
1302
1214
|
},
|
|
1303
1215
|
required: [
|
|
1304
|
-
"
|
|
1216
|
+
"headers"
|
|
1305
1217
|
]
|
|
1306
1218
|
}
|
|
1307
1219
|
}
|
|
1308
1220
|
};
|
|
1309
|
-
var
|
|
1310
|
-
fastify.get("/
|
|
1311
|
-
schema:
|
|
1312
|
-
}, async (request
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
}
|
|
1221
|
+
var headersRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1222
|
+
fastify.get("/headers", {
|
|
1223
|
+
schema: headersSchema
|
|
1224
|
+
}, async (request) => {
|
|
1225
|
+
const { headers } = request;
|
|
1226
|
+
return {
|
|
1227
|
+
headers
|
|
1228
|
+
};
|
|
1317
1229
|
});
|
|
1318
|
-
}, "
|
|
1230
|
+
}, "headersRoute");
|
|
1319
1231
|
|
|
1320
|
-
// src/routes/
|
|
1321
|
-
var
|
|
1322
|
-
description: "
|
|
1232
|
+
// src/routes/request-inspection/ip.ts
|
|
1233
|
+
var ipSchema = {
|
|
1234
|
+
description: "Returns the IP address of the client",
|
|
1323
1235
|
tags: [
|
|
1324
|
-
"
|
|
1236
|
+
"Request Inspection"
|
|
1325
1237
|
],
|
|
1326
|
-
body: {
|
|
1327
|
-
type: "object",
|
|
1328
|
-
properties: {
|
|
1329
|
-
name: {
|
|
1330
|
-
type: "string"
|
|
1331
|
-
},
|
|
1332
|
-
value: {
|
|
1333
|
-
type: "string"
|
|
1334
|
-
},
|
|
1335
|
-
expires: {
|
|
1336
|
-
type: "string",
|
|
1337
|
-
format: "date-time"
|
|
1338
|
-
}
|
|
1339
|
-
},
|
|
1340
|
-
required: [
|
|
1341
|
-
"name",
|
|
1342
|
-
"value"
|
|
1343
|
-
],
|
|
1344
|
-
additionalProperties: false
|
|
1345
|
-
},
|
|
1346
1238
|
response: {
|
|
1347
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1348
1239
|
200: {
|
|
1349
1240
|
type: "object",
|
|
1350
1241
|
properties: {
|
|
1351
|
-
|
|
1352
|
-
type: "
|
|
1353
|
-
|
|
1354
|
-
type: "string"
|
|
1355
|
-
}
|
|
1242
|
+
ip: {
|
|
1243
|
+
type: "string",
|
|
1244
|
+
description: "The IP address of the client"
|
|
1356
1245
|
}
|
|
1357
1246
|
},
|
|
1358
1247
|
required: [
|
|
1359
|
-
"
|
|
1248
|
+
"ip"
|
|
1360
1249
|
]
|
|
1361
1250
|
}
|
|
1362
1251
|
}
|
|
1363
1252
|
};
|
|
1364
|
-
var
|
|
1365
|
-
fastify.
|
|
1366
|
-
schema:
|
|
1367
|
-
}, async (request
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
} else {
|
|
1376
|
-
reply.setCookie(name, value, {
|
|
1377
|
-
path: "/"
|
|
1378
|
-
});
|
|
1379
|
-
}
|
|
1380
|
-
return reply.status(200).send();
|
|
1253
|
+
var ipRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1254
|
+
fastify.get("/ip", {
|
|
1255
|
+
schema: ipSchema
|
|
1256
|
+
}, async (request) => {
|
|
1257
|
+
const cloudflareIp = request.headers["cf-connecting-ip"];
|
|
1258
|
+
const forwardedIp = request.headers["x-forwarded-for"];
|
|
1259
|
+
const remoteIp = request.ip;
|
|
1260
|
+
const ip = cloudflareIp ?? (typeof forwardedIp === "string" ? forwardedIp.split(",")[0].trim() : remoteIp);
|
|
1261
|
+
return {
|
|
1262
|
+
ip
|
|
1263
|
+
};
|
|
1381
1264
|
});
|
|
1382
|
-
}, "
|
|
1265
|
+
}, "ipRoute");
|
|
1383
1266
|
|
|
1384
|
-
// src/routes/
|
|
1385
|
-
var
|
|
1386
|
-
description: "
|
|
1267
|
+
// src/routes/request-inspection/user-agent.ts
|
|
1268
|
+
var userAgentSchema = {
|
|
1269
|
+
description: "Returns the User-Agent header of the client request",
|
|
1387
1270
|
tags: [
|
|
1388
|
-
"
|
|
1271
|
+
"Request Inspection"
|
|
1389
1272
|
],
|
|
1390
|
-
querystring: {
|
|
1391
|
-
type: "object",
|
|
1392
|
-
properties: {
|
|
1393
|
-
name: {
|
|
1394
|
-
type: "string"
|
|
1395
|
-
}
|
|
1396
|
-
},
|
|
1397
|
-
required: [
|
|
1398
|
-
"name"
|
|
1399
|
-
],
|
|
1400
|
-
additionalProperties: false
|
|
1401
|
-
},
|
|
1402
1273
|
response: {
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1274
|
+
200: {
|
|
1275
|
+
type: "object",
|
|
1276
|
+
properties: {
|
|
1277
|
+
userAgent: {
|
|
1278
|
+
type: "string",
|
|
1279
|
+
description: "The User-Agent header of the client request"
|
|
1280
|
+
}
|
|
1281
|
+
},
|
|
1282
|
+
required: [
|
|
1283
|
+
"userAgent"
|
|
1284
|
+
]
|
|
1406
1285
|
}
|
|
1407
1286
|
}
|
|
1408
1287
|
};
|
|
1409
|
-
var
|
|
1410
|
-
fastify.
|
|
1411
|
-
schema:
|
|
1412
|
-
}, async (request
|
|
1413
|
-
const
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1288
|
+
var userAgentRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1289
|
+
fastify.get("/user-agent", {
|
|
1290
|
+
schema: userAgentSchema
|
|
1291
|
+
}, async (request) => {
|
|
1292
|
+
const userAgent = request.headers["user-agent"];
|
|
1293
|
+
return {
|
|
1294
|
+
userAgent
|
|
1295
|
+
};
|
|
1296
|
+
});
|
|
1297
|
+
}, "userAgentRoute");
|
|
1298
|
+
|
|
1299
|
+
// src/routes/response-inspection/cache.ts
|
|
1300
|
+
var cacheGetSchema = {
|
|
1301
|
+
description: "Handles cache validation and retrieval.",
|
|
1302
|
+
tags: [
|
|
1303
|
+
"Response Inspection"
|
|
1304
|
+
],
|
|
1305
|
+
response: {
|
|
1306
|
+
200: {
|
|
1307
|
+
type: "string",
|
|
1308
|
+
description: "The cached content or resource."
|
|
1309
|
+
},
|
|
1310
|
+
304: {
|
|
1311
|
+
type: "null",
|
|
1312
|
+
description: "Indicates the resource has not been modified."
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
var cacheSetSchema = {
|
|
1317
|
+
description: "Sets a Cache-Control header for n seconds.",
|
|
1318
|
+
tags: [
|
|
1319
|
+
"Response Inspection"
|
|
1320
|
+
],
|
|
1321
|
+
params: {
|
|
1322
|
+
type: "object",
|
|
1323
|
+
properties: {
|
|
1324
|
+
value: {
|
|
1325
|
+
type: "integer",
|
|
1326
|
+
description: "Number of seconds to cache the resource."
|
|
1327
|
+
}
|
|
1328
|
+
},
|
|
1329
|
+
required: [
|
|
1330
|
+
"value"
|
|
1331
|
+
]
|
|
1332
|
+
},
|
|
1333
|
+
response: {
|
|
1334
|
+
200: {
|
|
1335
|
+
type: "string",
|
|
1336
|
+
description: "Confirmation message for setting cache."
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
var cacheRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1341
|
+
fastify.get("/cache", {
|
|
1342
|
+
schema: cacheGetSchema
|
|
1343
|
+
}, async (request, reply) => {
|
|
1344
|
+
const ifModifiedSince = request.headers["if-modified-since"];
|
|
1345
|
+
const ifNoneMatch = request.headers["if-none-match"];
|
|
1346
|
+
if (ifModifiedSince ?? ifNoneMatch) {
|
|
1347
|
+
await reply.status(304).send();
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
await reply.send("Cache content or resource response here.");
|
|
1351
|
+
});
|
|
1352
|
+
fastify.get("/cache/:value", {
|
|
1353
|
+
schema: cacheSetSchema
|
|
1354
|
+
}, async (request, reply) => {
|
|
1355
|
+
const { value } = request.params;
|
|
1356
|
+
await reply.header("Cache-Control", `max-age=${value}`).send(`Cache-Control set for ${value} seconds.`);
|
|
1357
|
+
});
|
|
1358
|
+
}, "cacheRoutes");
|
|
1359
|
+
|
|
1360
|
+
// src/routes/response-inspection/etag.ts
|
|
1361
|
+
var etagSchema = {
|
|
1362
|
+
description: "Handles ETag-based conditional requests.",
|
|
1363
|
+
tags: [
|
|
1364
|
+
"Response Inspection"
|
|
1365
|
+
],
|
|
1366
|
+
params: {
|
|
1367
|
+
type: "object",
|
|
1368
|
+
properties: {
|
|
1369
|
+
etag: {
|
|
1370
|
+
type: "string",
|
|
1371
|
+
description: "The ETag value for the resource."
|
|
1372
|
+
}
|
|
1373
|
+
},
|
|
1374
|
+
required: [
|
|
1375
|
+
"etag"
|
|
1376
|
+
]
|
|
1377
|
+
},
|
|
1378
|
+
response: {
|
|
1379
|
+
200: {
|
|
1380
|
+
type: "string",
|
|
1381
|
+
description: "Resource content for matching ETag."
|
|
1382
|
+
},
|
|
1383
|
+
304: {
|
|
1384
|
+
type: "null",
|
|
1385
|
+
description: "Indicates the resource has not been modified."
|
|
1386
|
+
},
|
|
1387
|
+
412: {
|
|
1388
|
+
type: "null",
|
|
1389
|
+
description: "Indicates a precondition failed due to mismatched ETag."
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
var etagRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1394
|
+
fastify.get("/etag/:etag", {
|
|
1395
|
+
schema: etagSchema
|
|
1396
|
+
}, async (request, reply) => {
|
|
1397
|
+
const { etag } = request.params;
|
|
1398
|
+
const ifNoneMatch = request.headers["if-none-match"];
|
|
1399
|
+
const ifMatch = request.headers["if-match"];
|
|
1400
|
+
if (ifNoneMatch === etag) {
|
|
1401
|
+
await reply.status(304).send();
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
if (ifMatch && ifMatch !== etag) {
|
|
1405
|
+
await reply.status(412).send();
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
await reply.header("ETag", etag).send("Resource content for matching ETag.");
|
|
1409
|
+
});
|
|
1410
|
+
}, "etagRoutes");
|
|
1411
|
+
|
|
1412
|
+
// src/routes/response-inspection/plain.ts
|
|
1413
|
+
var plainSchema = {
|
|
1414
|
+
description: "Returns random plain text content",
|
|
1415
|
+
tags: [
|
|
1416
|
+
"Response Inspection"
|
|
1417
|
+
],
|
|
1418
|
+
// @ts-expect-error
|
|
1419
|
+
response: {
|
|
1420
|
+
200: {
|
|
1421
|
+
type: "string",
|
|
1422
|
+
description: "Random plain text content"
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1426
|
+
var textSchema = {
|
|
1427
|
+
description: "Returns random text content",
|
|
1428
|
+
tags: [
|
|
1429
|
+
"Response Inspection"
|
|
1430
|
+
],
|
|
1431
|
+
// @ts-expect-error
|
|
1432
|
+
response: {
|
|
1433
|
+
200: {
|
|
1434
|
+
type: "string",
|
|
1435
|
+
description: "Random text content"
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
var htmlSchema = {
|
|
1440
|
+
description: "Returns random HTML content",
|
|
1441
|
+
tags: [
|
|
1442
|
+
"Response Inspection"
|
|
1443
|
+
],
|
|
1444
|
+
// @ts-expect-error
|
|
1445
|
+
response: {
|
|
1446
|
+
200: {
|
|
1447
|
+
type: "string",
|
|
1448
|
+
description: "Random HTML content"
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
var randomTexts = [
|
|
1453
|
+
"The quick brown fox jumps over the lazy dog.",
|
|
1454
|
+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
|
1455
|
+
"To be or not to be, that is the question.",
|
|
1456
|
+
"All work and no play makes Jack a dull boy.",
|
|
1457
|
+
"The only way to do great work is to love what you do.",
|
|
1458
|
+
"In the beginning was the Word, and the Word was with God.",
|
|
1459
|
+
"Once upon a time in a galaxy far, far away...",
|
|
1460
|
+
"It was the best of times, it was the worst of times.",
|
|
1461
|
+
"The journey of a thousand miles begins with a single step.",
|
|
1462
|
+
"Knowledge is power. France is bacon."
|
|
1463
|
+
];
|
|
1464
|
+
var randomHtmlContent = [
|
|
1465
|
+
`<!DOCTYPE html>
|
|
1466
|
+
<html lang="en">
|
|
1467
|
+
<head>
|
|
1468
|
+
<title>Sample Page</title>
|
|
1469
|
+
</head>
|
|
1470
|
+
<body>
|
|
1471
|
+
<h1>Welcome to MockHTTP</h1>
|
|
1472
|
+
<p>This is a sample HTML page with random content.</p>
|
|
1473
|
+
</body>
|
|
1474
|
+
</html>`,
|
|
1475
|
+
`<!DOCTYPE html>
|
|
1476
|
+
<html>
|
|
1477
|
+
<head>
|
|
1478
|
+
<meta charset="UTF-8">
|
|
1479
|
+
<title>Test Document</title>
|
|
1480
|
+
</head>
|
|
1481
|
+
<body>
|
|
1482
|
+
<header>
|
|
1483
|
+
<h1>Test Page</h1>
|
|
1484
|
+
<nav>
|
|
1485
|
+
<ul>
|
|
1486
|
+
<li><a href="#">Home</a></li>
|
|
1487
|
+
<li><a href="#">About</a></li>
|
|
1488
|
+
<li><a href="#">Contact</a></li>
|
|
1489
|
+
</ul>
|
|
1490
|
+
</nav>
|
|
1491
|
+
</header>
|
|
1492
|
+
<main>
|
|
1493
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
|
1494
|
+
</main>
|
|
1495
|
+
</body>
|
|
1496
|
+
</html>`,
|
|
1497
|
+
`<!DOCTYPE html>
|
|
1498
|
+
<html lang="en">
|
|
1499
|
+
<head>
|
|
1500
|
+
<title>Article Page</title>
|
|
1501
|
+
<style>
|
|
1502
|
+
body { font-family: Arial, sans-serif; }
|
|
1503
|
+
article { max-width: 800px; margin: 0 auto; }
|
|
1504
|
+
</style>
|
|
1505
|
+
</head>
|
|
1506
|
+
<body>
|
|
1507
|
+
<article>
|
|
1508
|
+
<h1>The Journey Begins</h1>
|
|
1509
|
+
<p>Once upon a time in a digital world...</p>
|
|
1510
|
+
<blockquote>
|
|
1511
|
+
"The only way to do great work is to love what you do."
|
|
1512
|
+
</blockquote>
|
|
1513
|
+
</article>
|
|
1514
|
+
</body>
|
|
1515
|
+
</html>`,
|
|
1516
|
+
`<!DOCTYPE html>
|
|
1517
|
+
<html>
|
|
1518
|
+
<head>
|
|
1519
|
+
<title>Form Example</title>
|
|
1520
|
+
</head>
|
|
1521
|
+
<body>
|
|
1522
|
+
<h2>Contact Form</h2>
|
|
1523
|
+
<form action="/submit" method="post">
|
|
1524
|
+
<label for="name">Name:</label>
|
|
1525
|
+
<input type="text" id="name" name="name" required>
|
|
1526
|
+
<br>
|
|
1527
|
+
<label for="email">Email:</label>
|
|
1528
|
+
<input type="email" id="email" name="email" required>
|
|
1529
|
+
<br>
|
|
1530
|
+
<button type="submit">Submit</button>
|
|
1531
|
+
</form>
|
|
1532
|
+
</body>
|
|
1533
|
+
</html>`,
|
|
1534
|
+
`<!DOCTYPE html>
|
|
1535
|
+
<html lang="en">
|
|
1536
|
+
<head>
|
|
1537
|
+
<meta charset="UTF-8">
|
|
1538
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1539
|
+
<title>Responsive Page</title>
|
|
1540
|
+
</head>
|
|
1541
|
+
<body>
|
|
1542
|
+
<div class="container">
|
|
1543
|
+
<h1>Responsive Design</h1>
|
|
1544
|
+
<p>This page adapts to different screen sizes.</p>
|
|
1545
|
+
<img src="placeholder.jpg" alt="Placeholder" style="max-width: 100%; height: auto;">
|
|
1546
|
+
</div>
|
|
1547
|
+
</body>
|
|
1548
|
+
</html>`
|
|
1549
|
+
];
|
|
1550
|
+
var plainRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1551
|
+
fastify.get(
|
|
1552
|
+
"/plain",
|
|
1553
|
+
{
|
|
1554
|
+
schema: plainSchema
|
|
1555
|
+
},
|
|
1556
|
+
// biome-ignore lint/suspicious/noExplicitAny: reply
|
|
1557
|
+
async (_request, reply) => {
|
|
1558
|
+
const randomIndex = Math.floor(Math.random() * randomTexts.length);
|
|
1559
|
+
const text = randomTexts[randomIndex];
|
|
1560
|
+
reply.type("text/plain");
|
|
1561
|
+
return text;
|
|
1562
|
+
}
|
|
1563
|
+
);
|
|
1564
|
+
fastify.get(
|
|
1565
|
+
"/text",
|
|
1566
|
+
{
|
|
1567
|
+
schema: textSchema
|
|
1568
|
+
},
|
|
1569
|
+
// biome-ignore lint/suspicious/noExplicitAny: reply
|
|
1570
|
+
async (_request, reply) => {
|
|
1571
|
+
const randomIndex = Math.floor(Math.random() * randomTexts.length);
|
|
1572
|
+
const text = randomTexts[randomIndex];
|
|
1573
|
+
reply.type("text/plain");
|
|
1574
|
+
return text;
|
|
1575
|
+
}
|
|
1576
|
+
);
|
|
1577
|
+
fastify.get(
|
|
1578
|
+
"/html",
|
|
1579
|
+
{
|
|
1580
|
+
schema: htmlSchema
|
|
1581
|
+
},
|
|
1582
|
+
// biome-ignore lint/suspicious/noExplicitAny: reply
|
|
1583
|
+
async (_request, reply) => {
|
|
1584
|
+
const randomIndex = Math.floor(Math.random() * randomHtmlContent.length);
|
|
1585
|
+
const html = randomHtmlContent[randomIndex];
|
|
1586
|
+
reply.type("text/html");
|
|
1587
|
+
return html;
|
|
1588
|
+
}
|
|
1589
|
+
);
|
|
1590
|
+
}, "plainRoute");
|
|
1591
|
+
|
|
1592
|
+
// src/routes/response-inspection/response-headers.ts
|
|
1593
|
+
import { escape as escapeHtml } from "html-escaper";
|
|
1594
|
+
var responseHeadersSchema = {
|
|
1595
|
+
description: "Returns a set of response headers based on the query string.",
|
|
1596
|
+
tags: [
|
|
1597
|
+
"Response Inspection"
|
|
1598
|
+
],
|
|
1599
|
+
querystring: {
|
|
1600
|
+
type: "object",
|
|
1601
|
+
additionalProperties: true,
|
|
1602
|
+
description: "Freeform query string parameters to be added as response headers."
|
|
1603
|
+
},
|
|
1604
|
+
response: {
|
|
1605
|
+
200: {
|
|
1606
|
+
type: "object",
|
|
1607
|
+
additionalProperties: true,
|
|
1608
|
+
description: "Response headers as per query string parameters."
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
var responseHeadersRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1613
|
+
fastify.get("/response-headers", {
|
|
1614
|
+
schema: responseHeadersSchema
|
|
1615
|
+
}, async (request, reply) => {
|
|
1616
|
+
const queryParameters = request.query;
|
|
1617
|
+
for (const [key, value] of Object.entries(queryParameters)) {
|
|
1618
|
+
reply.header(key, escapeHtml(value));
|
|
1619
|
+
}
|
|
1620
|
+
const cleanedResponse = Object.fromEntries(Object.entries(queryParameters).map(([key, value]) => [
|
|
1621
|
+
key,
|
|
1622
|
+
escapeHtml(value)
|
|
1623
|
+
]));
|
|
1624
|
+
await reply.send(cleanedResponse);
|
|
1625
|
+
});
|
|
1626
|
+
fastify.post("/response-headers", {
|
|
1627
|
+
schema: responseHeadersSchema
|
|
1628
|
+
}, async (request, reply) => {
|
|
1629
|
+
const queryParameters = request.query ?? {};
|
|
1630
|
+
const body = request.body ?? {};
|
|
1631
|
+
for (const [key, value] of Object.entries(queryParameters)) {
|
|
1632
|
+
reply.header(key, escapeHtml(value));
|
|
1633
|
+
}
|
|
1634
|
+
for (const [key, value] of Object.entries(body)) {
|
|
1635
|
+
reply.header(key, escapeHtml(value));
|
|
1636
|
+
}
|
|
1637
|
+
const cleanedResponse = Object.fromEntries(Object.entries({
|
|
1638
|
+
...queryParameters,
|
|
1639
|
+
...body
|
|
1640
|
+
}).map(([key, value]) => [
|
|
1641
|
+
key,
|
|
1642
|
+
escapeHtml(value)
|
|
1643
|
+
]));
|
|
1644
|
+
await reply.send(cleanedResponse);
|
|
1645
|
+
});
|
|
1646
|
+
}, "responseHeadersRoutes");
|
|
1647
|
+
|
|
1648
|
+
// src/routes/sitemap.ts
|
|
1649
|
+
var sitemapRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1650
|
+
fastify.get("/sitemap.xml", {
|
|
1651
|
+
schema: {
|
|
1652
|
+
hide: true
|
|
1653
|
+
}
|
|
1654
|
+
}, async (_request, reply) => {
|
|
1655
|
+
try {
|
|
1656
|
+
const host = _request.headers.host ?? "mockhttp.org";
|
|
1657
|
+
const isSecure = _request.headers["x-forwarded-proto"]?.includes("https");
|
|
1658
|
+
const protocol = isSecure ? "https" : "http";
|
|
1659
|
+
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1660
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
1661
|
+
<url>
|
|
1662
|
+
<loc>${protocol}://${host}/</loc>
|
|
1663
|
+
<changefreq>monthly</changefreq>
|
|
1664
|
+
<priority>1.0</priority>
|
|
1665
|
+
</url>
|
|
1666
|
+
</urlset>`;
|
|
1667
|
+
await reply.type("text/xml").send(xml);
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
fastify.log.error(error);
|
|
1670
|
+
await reply.status(500).send({
|
|
1671
|
+
error: "Internal Server Error"
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
}, "sitemapRoute");
|
|
1676
|
+
|
|
1677
|
+
// src/routes/status-codes/index.ts
|
|
1678
|
+
import { randomInt } from "crypto";
|
|
1679
|
+
var statusCodes = [
|
|
1680
|
+
{
|
|
1681
|
+
code: 100,
|
|
1682
|
+
message: "Continue"
|
|
1683
|
+
},
|
|
1684
|
+
{
|
|
1685
|
+
code: 101,
|
|
1686
|
+
message: "Switching Protocols"
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
code: 102,
|
|
1690
|
+
message: "Processing"
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
code: 103,
|
|
1694
|
+
message: "Early Hints"
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
code: 200,
|
|
1698
|
+
message: "OK"
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
code: 201,
|
|
1702
|
+
message: "Created"
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
code: 202,
|
|
1706
|
+
message: "Accepted"
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
code: 203,
|
|
1710
|
+
message: "Non-Authoritative Information"
|
|
1711
|
+
},
|
|
1712
|
+
{
|
|
1713
|
+
code: 204,
|
|
1714
|
+
message: "No Content"
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
code: 205,
|
|
1718
|
+
message: "Reset Content"
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
code: 206,
|
|
1722
|
+
message: "Partial Content"
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
code: 207,
|
|
1726
|
+
message: "Multi-Status"
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
code: 208,
|
|
1730
|
+
message: "Already Reported"
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
code: 226,
|
|
1734
|
+
message: "IM Used"
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
code: 300,
|
|
1738
|
+
message: "Multiple Choices"
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
code: 301,
|
|
1742
|
+
message: "Moved Permanently"
|
|
1743
|
+
},
|
|
1744
|
+
{
|
|
1745
|
+
code: 302,
|
|
1746
|
+
message: "Found"
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
code: 303,
|
|
1750
|
+
message: "See Other"
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
code: 304,
|
|
1754
|
+
message: "Not Modified"
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
code: 305,
|
|
1758
|
+
message: "Use Proxy"
|
|
1759
|
+
},
|
|
1760
|
+
{
|
|
1761
|
+
code: 306,
|
|
1762
|
+
message: "Switch Proxy"
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
code: 307,
|
|
1766
|
+
message: "Temporary Redirect"
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
code: 308,
|
|
1770
|
+
message: "Permanent Redirect"
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
code: 400,
|
|
1774
|
+
message: "Bad Request"
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
code: 401,
|
|
1778
|
+
message: "Unauthorized"
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
code: 402,
|
|
1782
|
+
message: "Payment Required"
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
code: 403,
|
|
1786
|
+
message: "Forbidden"
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
code: 404,
|
|
1790
|
+
message: "Not Found"
|
|
1791
|
+
},
|
|
1792
|
+
{
|
|
1793
|
+
code: 405,
|
|
1794
|
+
message: "Method Not Allowed"
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
code: 406,
|
|
1798
|
+
message: "Not Acceptable"
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
code: 407,
|
|
1802
|
+
message: "Proxy Authentication Required"
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
code: 408,
|
|
1806
|
+
message: "Request Timeout"
|
|
1807
|
+
},
|
|
1808
|
+
{
|
|
1809
|
+
code: 409,
|
|
1810
|
+
message: "Conflict"
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
code: 410,
|
|
1814
|
+
message: "Gone"
|
|
1815
|
+
},
|
|
1816
|
+
{
|
|
1817
|
+
code: 411,
|
|
1818
|
+
message: "Length Required"
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
code: 412,
|
|
1822
|
+
message: "Precondition Failed"
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
code: 413,
|
|
1826
|
+
message: "Payload Too Large"
|
|
1827
|
+
},
|
|
1828
|
+
{
|
|
1829
|
+
code: 414,
|
|
1830
|
+
message: "URI Too Long"
|
|
1831
|
+
},
|
|
1832
|
+
{
|
|
1833
|
+
code: 415,
|
|
1834
|
+
message: "Unsupported Media Type"
|
|
1835
|
+
},
|
|
1836
|
+
{
|
|
1837
|
+
code: 416,
|
|
1838
|
+
message: "Range Not Satisfiable"
|
|
1839
|
+
},
|
|
1840
|
+
{
|
|
1841
|
+
code: 417,
|
|
1842
|
+
message: "Expectation Failed"
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
code: 418,
|
|
1846
|
+
message: "I'm a teapot"
|
|
1847
|
+
},
|
|
1848
|
+
{
|
|
1849
|
+
code: 421,
|
|
1850
|
+
message: "Misdirected Request"
|
|
1851
|
+
},
|
|
1852
|
+
{
|
|
1853
|
+
code: 422,
|
|
1854
|
+
message: "Unprocessable Entity"
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
code: 423,
|
|
1858
|
+
message: "Locked"
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
code: 424,
|
|
1862
|
+
message: "Failed Dependency"
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
code: 425,
|
|
1866
|
+
message: "Too Early"
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
code: 426,
|
|
1870
|
+
message: "Upgrade Required"
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
code: 428,
|
|
1874
|
+
message: "Precondition Required"
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
code: 429,
|
|
1878
|
+
message: "Too Many Requests"
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
code: 431,
|
|
1882
|
+
message: "Request Header Fields Too Large"
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
code: 451,
|
|
1886
|
+
message: "Unavailable For Legal Reasons"
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
code: 500,
|
|
1890
|
+
message: "Internal Server Error"
|
|
1891
|
+
},
|
|
1892
|
+
{
|
|
1893
|
+
code: 501,
|
|
1894
|
+
message: "Not Implemented"
|
|
1895
|
+
},
|
|
1896
|
+
{
|
|
1897
|
+
code: 502,
|
|
1898
|
+
message: "Bad Gateway"
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
code: 503,
|
|
1902
|
+
message: "Service Unavailable"
|
|
1903
|
+
},
|
|
1904
|
+
{
|
|
1905
|
+
code: 504,
|
|
1906
|
+
message: "Gateway Timeout"
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
code: 505,
|
|
1910
|
+
message: "HTTP Version Not Supported"
|
|
1911
|
+
},
|
|
1912
|
+
{
|
|
1913
|
+
code: 506,
|
|
1914
|
+
message: "Variant Also Negotiates"
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
code: 507,
|
|
1918
|
+
message: "Insufficient Storage"
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
code: 508,
|
|
1922
|
+
message: "Loop Detected"
|
|
1923
|
+
},
|
|
1924
|
+
{
|
|
1925
|
+
code: 510,
|
|
1926
|
+
message: "Not Extended"
|
|
1927
|
+
},
|
|
1928
|
+
{
|
|
1929
|
+
code: 511,
|
|
1930
|
+
message: "Network Authentication Required"
|
|
1931
|
+
}
|
|
1932
|
+
];
|
|
1933
|
+
var statusSchema = {
|
|
1934
|
+
description: "Return status code or random status code if more than one are given ",
|
|
1424
1935
|
tags: [
|
|
1425
|
-
"
|
|
1936
|
+
"Status Codes"
|
|
1426
1937
|
],
|
|
1938
|
+
params: {
|
|
1939
|
+
type: "object",
|
|
1940
|
+
properties: {
|
|
1941
|
+
code: {
|
|
1942
|
+
type: "string",
|
|
1943
|
+
description: "HTTP status code to be returned"
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
},
|
|
1427
1947
|
response: {
|
|
1428
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1429
1948
|
200: {
|
|
1430
1949
|
type: "object",
|
|
1431
1950
|
properties: {
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
type: "object",
|
|
1435
|
-
description: "Route parameters",
|
|
1436
|
-
additionalProperties: true
|
|
1437
|
-
},
|
|
1438
|
-
// Echo back whatever was in the request.body
|
|
1439
|
-
data: {
|
|
1440
|
-
type: "object",
|
|
1441
|
-
description: "Request body data",
|
|
1442
|
-
additionalProperties: true
|
|
1443
|
-
},
|
|
1444
|
-
// If you’re using fastify-multipart, you’ll get
|
|
1445
|
-
// files via request.files(); this just allows
|
|
1446
|
-
// you to mirror them back
|
|
1447
|
-
files: {
|
|
1448
|
-
type: "object",
|
|
1449
|
-
description: "Uploaded files",
|
|
1450
|
-
additionalProperties: true
|
|
1451
|
-
},
|
|
1452
|
-
// If you parse application/x-www-form-urlencoded
|
|
1453
|
-
// these fields land in request.body too, but you can
|
|
1454
|
-
// mirror them separately if you like
|
|
1455
|
-
form: {
|
|
1456
|
-
type: "object",
|
|
1457
|
-
description: "Form data",
|
|
1458
|
-
additionalProperties: true
|
|
1459
|
-
},
|
|
1460
|
-
headers: {
|
|
1461
|
-
type: "object",
|
|
1462
|
-
description: "Request headers",
|
|
1463
|
-
additionalProperties: true
|
|
1464
|
-
},
|
|
1465
|
-
json: {
|
|
1466
|
-
type: "object",
|
|
1467
|
-
description: "Parsed JSON body",
|
|
1468
|
-
additionalProperties: true
|
|
1469
|
-
},
|
|
1470
|
-
method: {
|
|
1471
|
-
type: "string",
|
|
1472
|
-
description: "HTTP method used"
|
|
1473
|
-
},
|
|
1474
|
-
origin: {
|
|
1475
|
-
type: "string",
|
|
1476
|
-
description: "Origin of the request"
|
|
1477
|
-
},
|
|
1478
|
-
url: {
|
|
1479
|
-
type: "string",
|
|
1480
|
-
description: "Request URL"
|
|
1951
|
+
status: {
|
|
1952
|
+
type: "string"
|
|
1481
1953
|
}
|
|
1482
|
-
}
|
|
1483
|
-
// Don’t allow any other top-level keys in your response
|
|
1484
|
-
additionalProperties: false
|
|
1954
|
+
}
|
|
1485
1955
|
}
|
|
1486
1956
|
}
|
|
1487
1957
|
};
|
|
1488
|
-
var
|
|
1958
|
+
var statusCodeRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1489
1959
|
const handler = /* @__PURE__ */ __name(async (request, reply) => {
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
method: request.method,
|
|
1498
|
-
origin: request.headers.origin ?? request.headers.host ?? "",
|
|
1499
|
-
url: request.url
|
|
1500
|
-
};
|
|
1501
|
-
await reply.send(response);
|
|
1960
|
+
let { code } = request.params;
|
|
1961
|
+
if (!code || !statusCodes.map((status) => status.code).includes(Number(code))) {
|
|
1962
|
+
code = statusCodes[randomInt(0, statusCodes.length)].code.toString();
|
|
1963
|
+
}
|
|
1964
|
+
await reply.code(Number(code)).send({
|
|
1965
|
+
status: `Response with status code ${code}`
|
|
1966
|
+
});
|
|
1502
1967
|
}, "handler");
|
|
1503
|
-
|
|
1504
|
-
schema:
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
fastify.
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
fastify.
|
|
1513
|
-
|
|
1968
|
+
fastify.get("/status/:code?", {
|
|
1969
|
+
schema: statusSchema
|
|
1970
|
+
}, handler);
|
|
1971
|
+
fastify.post("/status/:code?", {
|
|
1972
|
+
schema: statusSchema
|
|
1973
|
+
}, handler);
|
|
1974
|
+
fastify.put("/status/:code?", {
|
|
1975
|
+
schema: statusSchema
|
|
1976
|
+
}, handler);
|
|
1977
|
+
fastify.patch("/status/:code?", {
|
|
1978
|
+
schema: statusSchema
|
|
1979
|
+
}, handler);
|
|
1980
|
+
fastify.delete("/status/:code?", {
|
|
1981
|
+
schema: statusSchema
|
|
1982
|
+
}, handler);
|
|
1983
|
+
}, "statusCodeRoute");
|
|
1984
|
+
|
|
1985
|
+
// src/swagger.ts
|
|
1986
|
+
import { fastifySwaggerUi } from "@fastify/swagger-ui";
|
|
1987
|
+
|
|
1988
|
+
// package.json
|
|
1989
|
+
var package_default = {
|
|
1990
|
+
name: "@jaredwray/mockhttp",
|
|
1991
|
+
version: "0.8.0",
|
|
1992
|
+
description: "Mock Http - Easy way to mock http with httpbin replacement",
|
|
1993
|
+
type: "module",
|
|
1994
|
+
main: "dist/index.js",
|
|
1995
|
+
directories: {
|
|
1996
|
+
test: "test"
|
|
1997
|
+
},
|
|
1998
|
+
scripts: {
|
|
1999
|
+
lint: "biome check --write --error-on-warnings",
|
|
2000
|
+
test: "pnpm lint && vitest run --coverage",
|
|
2001
|
+
"test:ci": "biome check --error-on-warnings && vitest run --coverage",
|
|
2002
|
+
dev: "pnpm lint && tsx src/index.ts --watch",
|
|
2003
|
+
build: "rimraf ./dist && tsup src/index.ts --format esm --dts --clean",
|
|
2004
|
+
"docker:build": "docker build -t jaredwray/mockhttp .",
|
|
2005
|
+
"docker:run": "docker run -p 3000:3000 jaredwray/mockhttp",
|
|
2006
|
+
"docker:push": "docker push jaredwray/mockhttp",
|
|
2007
|
+
"docker:stop": 'docker stop $(docker ps -a -q --filter ancestor=jaredwray/mockhttp --format="{{.ID}}")',
|
|
2008
|
+
"docker:readme": "tsx ./scripts/create-docker-readme.ts",
|
|
2009
|
+
"docker:compose:up": "docker-compose up -d",
|
|
2010
|
+
"docker:compose:down": "docker-compose down",
|
|
2011
|
+
prepare: "pnpm run build",
|
|
2012
|
+
start: "node dist/index.js"
|
|
2013
|
+
},
|
|
2014
|
+
repository: {
|
|
2015
|
+
type: "git",
|
|
2016
|
+
url: "git+https://github.com/jaredwray/mockhttp.git"
|
|
2017
|
+
},
|
|
2018
|
+
keywords: [
|
|
2019
|
+
"mock",
|
|
2020
|
+
"http",
|
|
2021
|
+
"httpbin",
|
|
2022
|
+
"test"
|
|
2023
|
+
],
|
|
2024
|
+
author: "Jared Wray <me@jaredwray.com>",
|
|
2025
|
+
license: "MIT",
|
|
2026
|
+
bugs: {
|
|
2027
|
+
url: "https://github.com/jaredwray/mockhttp/issues"
|
|
2028
|
+
},
|
|
2029
|
+
homepage: "https://github.com/jaredwray/mockhttp#readme",
|
|
2030
|
+
devDependencies: {
|
|
2031
|
+
"@biomejs/biome": "^2.2.2",
|
|
2032
|
+
"@swc/core": "^1.13.5",
|
|
2033
|
+
"@types/html-escaper": "^3.0.4",
|
|
2034
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
2035
|
+
rimraf: "^6.0.1",
|
|
2036
|
+
tsup: "^8.5.0",
|
|
2037
|
+
tsx: "^4.20.5",
|
|
2038
|
+
typescript: "^5.9.2",
|
|
2039
|
+
vitest: "^3.2.4"
|
|
2040
|
+
},
|
|
2041
|
+
dependencies: {
|
|
2042
|
+
"@fastify/cookie": "^11.0.2",
|
|
2043
|
+
"@fastify/helmet": "^13.0.1",
|
|
2044
|
+
"@fastify/static": "^8.2.0",
|
|
2045
|
+
"@fastify/swagger": "^9.5.1",
|
|
2046
|
+
"@fastify/swagger-ui": "^5.2.3",
|
|
2047
|
+
"@scalar/api-reference": "^1.34.6",
|
|
2048
|
+
"detect-port": "^2.1.0",
|
|
2049
|
+
fastify: "^5.5.0",
|
|
2050
|
+
hookified: "^1.12.0",
|
|
2051
|
+
"html-escaper": "^3.0.3",
|
|
2052
|
+
pino: "^9.9.0",
|
|
2053
|
+
"pino-pretty": "^13.1.1"
|
|
2054
|
+
},
|
|
2055
|
+
files: [
|
|
2056
|
+
"dist",
|
|
2057
|
+
"public",
|
|
2058
|
+
"LICENCE"
|
|
2059
|
+
],
|
|
2060
|
+
pnpm: {
|
|
2061
|
+
onlyBuiltDependencies: [
|
|
2062
|
+
"@swc/core",
|
|
2063
|
+
"unrs-resolver",
|
|
2064
|
+
"vue-demi"
|
|
2065
|
+
]
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
|
|
2069
|
+
// src/swagger.ts
|
|
2070
|
+
var description = `
|
|
2071
|
+
A simple HTTP server that can be used to mock HTTP responses for testing purposes. Inspired by [httpbin](https://httpbin.org/) and built using \`nodejs\` and \`fastify\` with the idea of running it via https://mockhttp.org, via docker \`jaredwray/mockhttp\`, or nodejs \`npm install jaredwray/mockhttp\`.
|
|
2072
|
+
|
|
2073
|
+
* [GitHub Repository](https://github.com/jaredwray/mockhttp)
|
|
2074
|
+
* [Docker Image](https://hub.docker.com/r/jaredwray/mockhttp)
|
|
2075
|
+
* [NPM Package](https://www.npmjs.com/package/jaredwray/mockhttp)
|
|
2076
|
+
|
|
2077
|
+
# About mockhttp.org
|
|
2078
|
+
|
|
2079
|
+
[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.
|
|
2080
|
+
`;
|
|
2081
|
+
var fastifySwaggerConfig = {
|
|
2082
|
+
openapi: {
|
|
2083
|
+
info: {
|
|
2084
|
+
title: "Mock HTTP API",
|
|
2085
|
+
description,
|
|
2086
|
+
version: package_default.version
|
|
2087
|
+
},
|
|
2088
|
+
consumes: [
|
|
2089
|
+
"application/json"
|
|
2090
|
+
],
|
|
2091
|
+
produces: [
|
|
2092
|
+
"application/json"
|
|
2093
|
+
]
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
var registerSwaggerUi = /* @__PURE__ */ __name(async (fastify) => {
|
|
2097
|
+
await fastify.register(fastifySwaggerUi, {
|
|
2098
|
+
routePrefix: "/docs",
|
|
2099
|
+
uiConfig: {
|
|
2100
|
+
docExpansion: "none",
|
|
2101
|
+
deepLinking: false
|
|
2102
|
+
},
|
|
2103
|
+
uiHooks: {
|
|
2104
|
+
/* c8 ignore next 6 */
|
|
2105
|
+
onRequest(_request, _reply, next) {
|
|
2106
|
+
next();
|
|
2107
|
+
},
|
|
2108
|
+
preHandler(_request, _reply, next) {
|
|
2109
|
+
next();
|
|
2110
|
+
}
|
|
2111
|
+
},
|
|
2112
|
+
staticCSP: true,
|
|
2113
|
+
transformSpecification: /* @__PURE__ */ __name((swaggerObject, _request, _reply) => swaggerObject, "transformSpecification"),
|
|
2114
|
+
transformSpecificationClone: true
|
|
2115
|
+
});
|
|
2116
|
+
}, "registerSwaggerUi");
|
|
1514
2117
|
|
|
1515
2118
|
// src/mock-http.ts
|
|
1516
2119
|
var MockHttp = class extends Hookified {
|
|
@@ -1529,9 +2132,9 @@ var MockHttp = class extends Hookified {
|
|
|
1529
2132
|
responseInspection: true,
|
|
1530
2133
|
statusCodes: true,
|
|
1531
2134
|
cookies: true,
|
|
1532
|
-
anything: true
|
|
2135
|
+
anything: true,
|
|
2136
|
+
auth: true
|
|
1533
2137
|
};
|
|
1534
|
-
// eslint-disable-next-line new-cap
|
|
1535
2138
|
_server = Fastify();
|
|
1536
2139
|
constructor(options) {
|
|
1537
2140
|
super(options?.hookOptions);
|
|
@@ -1669,7 +2272,7 @@ var MockHttp = class extends Hookified {
|
|
|
1669
2272
|
if (this._apiDocs) {
|
|
1670
2273
|
await this.registerApiDocs();
|
|
1671
2274
|
}
|
|
1672
|
-
const { httpMethods, redirects, requestInspection, responseInspection, statusCodes: statusCodes2, cookies, anything } = this._httpBin;
|
|
2275
|
+
const { httpMethods, redirects, requestInspection, responseInspection, statusCodes: statusCodes2, cookies, anything, auth } = this._httpBin;
|
|
1673
2276
|
if (httpMethods) {
|
|
1674
2277
|
await this.registerHttpMethods();
|
|
1675
2278
|
}
|
|
@@ -1691,6 +2294,9 @@ var MockHttp = class extends Hookified {
|
|
|
1691
2294
|
if (anything) {
|
|
1692
2295
|
await this.registerAnythingRoutes();
|
|
1693
2296
|
}
|
|
2297
|
+
if (auth) {
|
|
2298
|
+
await this.registerAuthRoutes();
|
|
2299
|
+
}
|
|
1694
2300
|
if (this._autoDetectPort) {
|
|
1695
2301
|
const originalPort = this._port;
|
|
1696
2302
|
this._port = await this.detectPort();
|
|
@@ -1768,6 +2374,7 @@ var MockHttp = class extends Hookified {
|
|
|
1768
2374
|
const fastify = fastifyInstance ?? this._server;
|
|
1769
2375
|
await fastify.register(cacheRoutes);
|
|
1770
2376
|
await fastify.register(etagRoutes);
|
|
2377
|
+
await fastify.register(plainRoute);
|
|
1771
2378
|
await fastify.register(responseHeadersRoutes);
|
|
1772
2379
|
}
|
|
1773
2380
|
/**
|
|
@@ -1799,6 +2406,17 @@ var MockHttp = class extends Hookified {
|
|
|
1799
2406
|
const fastify = fastifyInstance ?? this._server;
|
|
1800
2407
|
await fastify.register(anythingRoute);
|
|
1801
2408
|
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Register the auth routes.
|
|
2411
|
+
* @param fastifyInstance - the server instance to register the routes on.
|
|
2412
|
+
*/
|
|
2413
|
+
async registerAuthRoutes(fastifyInstance) {
|
|
2414
|
+
const fastify = fastifyInstance ?? this._server;
|
|
2415
|
+
await fastify.register(basicAuthRoute);
|
|
2416
|
+
await fastify.register(hiddenBasicAuthRoute);
|
|
2417
|
+
await fastify.register(bearerAuthRoute);
|
|
2418
|
+
await fastify.register(digestAuthRoute);
|
|
2419
|
+
}
|
|
1802
2420
|
};
|
|
1803
2421
|
|
|
1804
2422
|
// src/index.ts
|
|
@@ -1813,7 +2431,9 @@ var start = /* @__PURE__ */ __name(async () => {
|
|
|
1813
2431
|
await mockHttp.start();
|
|
1814
2432
|
return mockHttp;
|
|
1815
2433
|
}, "start");
|
|
1816
|
-
|
|
2434
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
2435
|
+
await start();
|
|
2436
|
+
}
|
|
1817
2437
|
export {
|
|
1818
2438
|
MockHttp as default,
|
|
1819
2439
|
MockHttp as mockhttp,
|