@jaredwray/mockhttp 2.1.0 → 3.0.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 +57 -67
- package/dist/index.d.mts +130 -159
- package/dist/index.mjs +199 -231
- package/package.json +21 -18
- package/site/dist/api/index.html +5 -5
- package/site/dist/api/swagger.json +10 -10
- package/site/dist/changelog/index.html +16 -17
- package/site/dist/changelog/page/2/index.html +17 -15
- package/site/dist/changelog/{v0-2-0 → v3-0-0}/index.html +73 -8
- package/site/dist/changelog-latest.json +13 -13
- package/site/dist/changelog.json +13 -13
- package/site/dist/docs/bins/index.html +38 -51
- package/site/dist/docs/configuration/index.html +2 -2
- package/site/dist/docs/hosted/index.html +3 -3
- package/site/dist/docs/how-to-deploy/cloudflare/index.html +2 -7
- package/site/dist/docs/how-to-deploy/docker/index.html +2 -2
- package/site/dist/docs/how-to-deploy/wasmer/index.html +4 -4
- package/site/dist/docs/https/index.html +2 -2
- package/site/dist/docs/index.html +2 -2
- package/site/dist/docs/library/index.html +18 -22
- package/site/dist/docs/taps/index.html +2 -2
- package/site/dist/feed.xml +1 -1
- package/site/dist/index.html +2 -2
- package/site/dist/llms-full.txt +141 -91
- package/site/dist/llms.txt +1 -1
- package/site/dist/search-index.json +1 -1
- package/site/dist/sitemap.xml +1 -1
package/README.md
CHANGED
|
@@ -618,13 +618,13 @@ curl -s "http://localhost:3000/bins/$ID/requests" \
|
|
|
618
618
|
|
|
619
619
|
### Truncation
|
|
620
620
|
|
|
621
|
-
Bodies larger than `maxBodySize` (
|
|
621
|
+
Bodies larger than `maxBodySize` (128 KiB by default) are cut off and flagged:
|
|
622
622
|
|
|
623
623
|
```javascript
|
|
624
624
|
// In test setup
|
|
625
|
-
import { MockHttp,
|
|
625
|
+
import { MockHttp, MockHttpBins } from '@jaredwray/mockhttp';
|
|
626
626
|
const mock = new MockHttp();
|
|
627
|
-
mock.bins = new
|
|
627
|
+
mock.bins = new MockHttpBins({ maxBodySize: 1024 }); // 1 KiB cap
|
|
628
628
|
await mock.start();
|
|
629
629
|
```
|
|
630
630
|
|
|
@@ -664,8 +664,7 @@ curl -s "http://localhost:3000/bins/$ID/requests" | jq '.requests[0].path'
|
|
|
664
664
|
|
|
665
665
|
## Programmatic Access
|
|
666
666
|
|
|
667
|
-
|
|
668
|
-
makes it easy to drive bins from a test suite without going through HTTP:
|
|
667
|
+
Use `mock.bins` to control request bins from a test. You do not need an HTTP call:
|
|
669
668
|
|
|
670
669
|
```javascript
|
|
671
670
|
import { MockHttp } from '@jaredwray/mockhttp';
|
|
@@ -674,13 +673,13 @@ const mock = new MockHttp({ logging: false });
|
|
|
674
673
|
await mock.start();
|
|
675
674
|
|
|
676
675
|
// Create a bin
|
|
677
|
-
const bin = mock.bins.createBin();
|
|
676
|
+
const bin = await mock.bins.createBin();
|
|
678
677
|
console.log(`Webhook target: http://localhost:${mock.port}/b/${bin.id}`);
|
|
679
678
|
|
|
680
679
|
// ... point your code-under-test at that URL ...
|
|
681
680
|
|
|
682
681
|
// Read captured requests (newest first)
|
|
683
|
-
const requests = mock.bins.getRequests(bin.id);
|
|
682
|
+
const requests = await mock.bins.getRequests(bin.id);
|
|
684
683
|
console.log(`Captured ${requests.length} requests`);
|
|
685
684
|
|
|
686
685
|
for (const req of requests) {
|
|
@@ -688,8 +687,8 @@ for (const req of requests) {
|
|
|
688
687
|
}
|
|
689
688
|
|
|
690
689
|
// Clean up
|
|
691
|
-
mock.bins.deleteBin(bin.id);
|
|
692
|
-
await mock.close();
|
|
690
|
+
await mock.bins.deleteBin(bin.id);
|
|
691
|
+
await mock.close();
|
|
693
692
|
```
|
|
694
693
|
|
|
695
694
|
### Using Bins in a Vitest Test
|
|
@@ -710,14 +709,14 @@ afterAll(async () => {
|
|
|
710
709
|
});
|
|
711
710
|
|
|
712
711
|
test('my SDK sends the right webhook payload', async () => {
|
|
713
|
-
const bin = mock.bins.createBin();
|
|
712
|
+
const bin = await mock.bins.createBin();
|
|
714
713
|
const webhookUrl = `http://localhost:${mock.port}/b/${bin.id}`;
|
|
715
714
|
|
|
716
715
|
// Drive your SDK at the bin
|
|
717
716
|
await mySdk.notify(webhookUrl, { event: 'user.created', id: 42 });
|
|
718
717
|
|
|
719
718
|
// Assert on what actually arrived
|
|
720
|
-
const [captured] = mock.bins.getRequests(bin.id);
|
|
719
|
+
const [captured] = await mock.bins.getRequests(bin.id);
|
|
721
720
|
expect(captured.method).toBe('POST');
|
|
722
721
|
expect(captured.contentType).toBe('application/json');
|
|
723
722
|
expect(JSON.parse(captured.body!)).toEqual({
|
|
@@ -738,18 +737,17 @@ const mock = new MockHttp({
|
|
|
738
737
|
});
|
|
739
738
|
```
|
|
740
739
|
|
|
741
|
-
To
|
|
740
|
+
To change the limits, replace the default `MockHttpBins` before you start the server:
|
|
742
741
|
|
|
743
742
|
```javascript
|
|
744
|
-
import { MockHttp,
|
|
743
|
+
import { MockHttp, MockHttpBins } from '@jaredwray/mockhttp';
|
|
745
744
|
|
|
746
745
|
const mock = new MockHttp();
|
|
747
|
-
mock.bins = new
|
|
746
|
+
mock.bins = new MockHttpBins({
|
|
748
747
|
defaultTtlMs: 60 * 60 * 1000, // 1 hour (default: 24h)
|
|
749
748
|
maxRequestsPerBin: 500, // (default: 100)
|
|
750
|
-
maxBodySize:
|
|
749
|
+
maxBodySize: 512 * 1024, // 512 KiB (default: 128 KiB)
|
|
751
750
|
idLength: 16, // (default: 12)
|
|
752
|
-
cleanupIntervalMs: 30 * 1000, // sweep every 30s (default: 60s)
|
|
753
751
|
});
|
|
754
752
|
|
|
755
753
|
await mock.start();
|
|
@@ -759,44 +757,40 @@ await mock.start();
|
|
|
759
757
|
|
|
760
758
|
| Option | Default | Description |
|
|
761
759
|
|--------|---------|-------------|
|
|
762
|
-
| `defaultTtlMs` | `86400000` (24h) | Bin lifetime
|
|
760
|
+
| `defaultTtlMs` | `86400000` (24h) | Bin lifetime, set as the Keyv TTL. An expired bin returns 404. |
|
|
763
761
|
| `maxRequestsPerBin` | `100` | When exceeded, oldest captures are dropped (FIFO). |
|
|
764
|
-
| `maxBodySize` | `
|
|
762
|
+
| `maxBodySize` | `131072` (128 KiB) | Larger bodies are truncated; `truncated: true` is set on the capture. |
|
|
765
763
|
| `idLength` | `12` | Length of generated bin and request ids. |
|
|
766
|
-
| `
|
|
764
|
+
| `keyv` | `new Keyv()` | Keyv store for bins. The default keeps bins in memory. |
|
|
765
|
+
|
|
766
|
+
### Storage
|
|
767
767
|
|
|
768
|
-
|
|
768
|
+
`MockHttpBins` stores each bin in [Keyv](https://github.com/jaredwray/keyv) 6. The default is `new Keyv()`. That store keeps the data in memory for this process.
|
|
769
769
|
|
|
770
|
-
|
|
771
|
-
backends (Redis, SQLite, etc.) without changing the rest of the codebase. The
|
|
772
|
-
default `InMemoryBinStore` keeps state in process memory.
|
|
770
|
+
Pass a Keyv 6 instance when you want a different adapter. Install the adapter in your project. This package does not include an adapter. `@keyv/redis` 6 matches this Keyv version.
|
|
773
771
|
|
|
774
772
|
```typescript
|
|
775
|
-
import
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
type Bin,
|
|
779
|
-
type BinStore,
|
|
780
|
-
type CapturedRequest,
|
|
781
|
-
} from '@jaredwray/mockhttp';
|
|
782
|
-
|
|
783
|
-
class RedisBinStore implements BinStore {
|
|
784
|
-
createBin(bin: Bin): void { /* SET bin:${bin.id} ... */ }
|
|
785
|
-
getBin(id: string): Bin | undefined { /* GET ... */ }
|
|
786
|
-
listBins(): Bin[] { /* SCAN ... */ }
|
|
787
|
-
deleteBin(id: string): boolean { /* DEL ... */ }
|
|
788
|
-
addRequest(binId: string, req: CapturedRequest, max: number): void {
|
|
789
|
-
/* LPUSH bin:${binId}:requests + LTRIM to max */
|
|
790
|
-
}
|
|
791
|
-
getRequests(binId: string): CapturedRequest[] { /* LRANGE ... */ }
|
|
792
|
-
getRequest(binId: string, reqId: string): CapturedRequest | undefined { /* ... */ }
|
|
793
|
-
clearRequests(binId: string): void { /* DEL bin:${binId}:requests */ }
|
|
794
|
-
cleanupExpired(now: number): string[] { /* scan + delete */ return []; }
|
|
795
|
-
}
|
|
773
|
+
import Keyv from 'keyv';
|
|
774
|
+
import KeyvRedis from '@keyv/redis'; // pnpm add @keyv/redis
|
|
775
|
+
import { MockHttpBins } from '@jaredwray/mockhttp';
|
|
796
776
|
|
|
797
|
-
mock.bins = new
|
|
777
|
+
mock.bins = new MockHttpBins({
|
|
778
|
+
keyv: new Keyv({ store: new KeyvRedis('redis://localhost:6379') }),
|
|
779
|
+
});
|
|
798
780
|
```
|
|
799
781
|
|
|
782
|
+
Each capture writes the full bin again. A large body or a high request limit makes that write large. Set `maxBodySize` and `maxRequestsPerBin` to limit the size. With the defaults, a full bin of binary bodies is about 17 MB.
|
|
783
|
+
|
|
784
|
+
Two processes that share one Keyv can lose a capture. This occurs when both processes write the same bin at the same time.
|
|
785
|
+
|
|
786
|
+
If Keyv does not store a write, the bin route returns `500` with the standard Fastify error body: `statusCode`, `error`, and `message`.
|
|
787
|
+
|
|
788
|
+
A failed read depends on the Keyv `error` listener. Without a listener, Keyv throws the store error and the route returns `500`. With a listener, Keyv does not throw. A failed read then looks like a missing bin, and the route returns `404`. `listBins()` returns only the bins that it read before the error.
|
|
789
|
+
|
|
790
|
+
`listBins()` throws an error when the adapter has no iterator.
|
|
791
|
+
|
|
792
|
+
An expired bin returns 404. The in-memory Keyv store deletes an expired bin only when a read or `listBins()` reaches it. Until then, the bin stays in memory.
|
|
793
|
+
|
|
800
794
|
# Rate Limiting
|
|
801
795
|
|
|
802
796
|
MockHttp supports rate limiting using [@fastify/rate-limit](https://github.com/fastify/fastify-rate-limit). Rate limiting is **enabled by default** at **1000 requests per minute** with **localhost (127.0.0.1 and ::1) excluded** from rate limiting.
|
|
@@ -1012,7 +1006,6 @@ new MockHttp(options?)
|
|
|
1012
1006
|
- `logging?`: boolean - Enable logging (default: true)
|
|
1013
1007
|
- `staticFiles?`: boolean - Serve files from the package `public/` directory (default: true)
|
|
1014
1008
|
- `pluginTimeout?`: number - Fastify plugin boot timeout in milliseconds; `0` disables it (default: Fastify's timeout)
|
|
1015
|
-
- `startBins?`: boolean - Start the request-bin cleanup timer during `initialize()` (default: true)
|
|
1016
1009
|
- `httpBin?`: HttpBinOptions - Configure which httpbin routes to enable
|
|
1017
1010
|
- `httpMethods?`: boolean - Enable HTTP method routes (default: true)
|
|
1018
1011
|
- `redirects?`: boolean - Enable redirect routes (default: true)
|
|
@@ -1041,7 +1034,6 @@ new MockHttp(options?)
|
|
|
1041
1034
|
- `logging`: boolean - Get/set logging enabled state
|
|
1042
1035
|
- `staticFiles`: boolean - Get/set whether files from `public/` are served
|
|
1043
1036
|
- `pluginTimeout`: number | undefined - Get/set Fastify plugin boot timeout
|
|
1044
|
-
- `startBins`: boolean - Get/set whether bin cleanup starts during `initialize()`
|
|
1045
1037
|
- `rateLimit`: RateLimitPluginOptions | undefined - Get/set rate limiting options
|
|
1046
1038
|
- `httpBin`: HttpBinOptions - Get/set httpbin route options
|
|
1047
1039
|
- `https`: HttpsOptions | undefined - Get/set HTTPS configuration
|
|
@@ -1050,7 +1042,7 @@ new MockHttp(options?)
|
|
|
1050
1042
|
- `http1`: boolean - Get/set HTTP/1.1 fallback for HTTP/2 with HTTPS
|
|
1051
1043
|
- `server`: FastifyInstance - Get/set the Fastify server instance
|
|
1052
1044
|
- `taps`: TapManager - Get/set the TapManager instance
|
|
1053
|
-
- `bins`:
|
|
1045
|
+
- `bins`: MockHttpBins - Get or set the request bins
|
|
1054
1046
|
|
|
1055
1047
|
### Methods
|
|
1056
1048
|
|
|
@@ -1130,57 +1122,55 @@ Register the request bin routes — management at `/bins` and capture at `/b/:id
|
|
|
1130
1122
|
|
|
1131
1123
|
## Bins (Request Capture)
|
|
1132
1124
|
|
|
1133
|
-
|
|
1125
|
+
Use `mockHttp.bins` to control request bins. See [Request Bins](#request-bins) for usage examples.
|
|
1134
1126
|
|
|
1135
1127
|
### `bins.createBin()`
|
|
1136
1128
|
|
|
1137
|
-
Create a new bin with the configured TTL.
|
|
1129
|
+
Create a new bin with the configured TTL. Throws when Keyv does not store the bin.
|
|
1138
1130
|
|
|
1139
|
-
**Returns:** `Bin
|
|
1131
|
+
**Returns:** `Promise<Bin>` — `{ id, createdAt, expiresAt, requestCount }`
|
|
1140
1132
|
|
|
1141
1133
|
### `bins.getBin(id)`
|
|
1142
1134
|
|
|
1143
|
-
Look up a bin by id. Returns `undefined` if the bin does not exist or has expired
|
|
1135
|
+
Look up a bin by id. Returns `undefined` if the bin does not exist or Keyv has expired it. When the Keyv instance has an `error` listener, a failed read also returns `undefined`.
|
|
1144
1136
|
|
|
1145
|
-
**Returns:** `Bin | undefined
|
|
1137
|
+
**Returns:** `Promise<Bin | undefined>`
|
|
1146
1138
|
|
|
1147
1139
|
### `bins.listBins()`
|
|
1148
1140
|
|
|
1149
|
-
List
|
|
1141
|
+
List the bins that Keyv still holds.
|
|
1150
1142
|
|
|
1151
|
-
**Returns:** `Bin[]
|
|
1143
|
+
**Returns:** `Promise<Bin[]>`
|
|
1152
1144
|
|
|
1153
1145
|
### `bins.deleteBin(id)`
|
|
1154
1146
|
|
|
1155
|
-
Delete a bin and all its captured requests.
|
|
1147
|
+
Delete a bin and all its captured requests. The delete waits for captures already queued for that bin.
|
|
1156
1148
|
|
|
1157
|
-
**Returns:** `boolean
|
|
1149
|
+
**Returns:** `Promise<boolean>` — `true` when the bin existed
|
|
1158
1150
|
|
|
1159
1151
|
### `bins.getRequests(binId)`
|
|
1160
1152
|
|
|
1161
1153
|
List captured requests for a bin, newest first.
|
|
1162
1154
|
|
|
1163
|
-
**Returns:** `CapturedRequest[]
|
|
1155
|
+
**Returns:** `Promise<CapturedRequest[]>`
|
|
1164
1156
|
|
|
1165
1157
|
### `bins.getRequest(binId, reqId)`
|
|
1166
1158
|
|
|
1167
1159
|
Look up a single captured request.
|
|
1168
1160
|
|
|
1169
|
-
**Returns:** `CapturedRequest | undefined
|
|
1161
|
+
**Returns:** `Promise<CapturedRequest | undefined>`
|
|
1170
1162
|
|
|
1171
1163
|
### `bins.clearRequests(binId)`
|
|
1172
1164
|
|
|
1173
|
-
Clear all captured requests in a bin
|
|
1165
|
+
Clear all captured requests in a bin. The bin stays. Throws when Keyv does not store the change.
|
|
1174
1166
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
Manually record a captured request. Returns `undefined` if the bin does not exist or is expired. Normally invoked by the capture route, but available for programmatic use.
|
|
1167
|
+
**Returns:** `Promise<boolean>` — `false` when the bin does not exist
|
|
1178
1168
|
|
|
1179
|
-
|
|
1169
|
+
### `bins.recordRequest(binId, raw)`
|
|
1180
1170
|
|
|
1181
|
-
|
|
1171
|
+
Manually record a captured request. Returns `undefined` if the bin does not exist. Throws when Keyv does not store the capture. Normally invoked by the capture route, but available for programmatic use.
|
|
1182
1172
|
|
|
1183
|
-
|
|
1173
|
+
**Returns:** `Promise<CapturedRequest | undefined>`
|
|
1184
1174
|
|
|
1185
1175
|
### `bins.maxBodySize` / `bins.maxRequestsPerBin` / `bins.defaultTtlMs`
|
|
1186
1176
|
|
|
@@ -1240,7 +1230,7 @@ A getter that returns whether there are any active injections.
|
|
|
1240
1230
|
|
|
1241
1231
|
# About mockhttp.org
|
|
1242
1232
|
|
|
1243
|
-
[mockhttp.org](https://mockhttp.org) is a free hosted instance of this codebase for testing. It runs on a [Cloudflare Worker](https://developers.cloudflare.com/workers/) (no containers): documentation is served from Workers Assets, and mock APIs such as `/get` and `/post` run in the Worker. The service is globally available and rate-limited (1000 requests per minute per IP) to prevent abuse.
|
|
1233
|
+
[mockhttp.org](https://mockhttp.org) is a free hosted instance of this codebase for testing. It runs on a [Cloudflare Worker](https://developers.cloudflare.com/workers/) (no containers): documentation is served from Workers Assets, and mock APIs such as `/get` and `/post` run in the Worker. The service is globally available and rate-limited (1000 requests per minute per IP) to prevent abuse. Request bins on this service are stored in MongoDB Atlas, in the `bins` collection, so they are shared across isolates.
|
|
1244
1234
|
|
|
1245
1235
|
All [mockhttp.org](https://mockhttp.org) traffic stays on Cloudflare. A separate test app runs the Node server on Wasmer Edge at [mockhttp.wasmer.app](https://mockhttp.wasmer.app).
|
|
1246
1236
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
1
|
import { RateLimitPluginOptions } from "@fastify/rate-limit";
|
|
2
2
|
import { FastifyInstance, FastifyRequest } from "fastify";
|
|
3
3
|
import { Hookified, HookifiedOptions } from "hookified";
|
|
4
|
+
import Keyv from "keyv";
|
|
5
|
+
//#region src/certificate.d.ts
|
|
6
|
+
type CertificateOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Common Name for the certificate subject. Defaults to 'localhost'.
|
|
9
|
+
*/
|
|
10
|
+
commonName?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Subject Alternative Names. Defaults to [dns:localhost, ip:127.0.0.1, ip:::1].
|
|
13
|
+
*/
|
|
14
|
+
altNames?: Array<{
|
|
15
|
+
type: "dns";
|
|
16
|
+
value: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: "ip";
|
|
19
|
+
value: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Number of days the certificate is valid. Defaults to 365.
|
|
23
|
+
*/
|
|
24
|
+
validityDays?: number;
|
|
25
|
+
/**
|
|
26
|
+
* RSA key size in bits. Defaults to 2048.
|
|
27
|
+
*/
|
|
28
|
+
keySize?: number;
|
|
29
|
+
};
|
|
30
|
+
type CertificateResult = {
|
|
31
|
+
/**
|
|
32
|
+
* PEM-encoded X.509 certificate.
|
|
33
|
+
*/
|
|
34
|
+
cert: string;
|
|
35
|
+
/**
|
|
36
|
+
* PEM-encoded PKCS#8 private key.
|
|
37
|
+
*/
|
|
38
|
+
key: string;
|
|
39
|
+
};
|
|
40
|
+
type CertificateFileOptions = CertificateOptions & {
|
|
41
|
+
/**
|
|
42
|
+
* File path to write the certificate PEM.
|
|
43
|
+
*/
|
|
44
|
+
certPath: string;
|
|
45
|
+
/**
|
|
46
|
+
* File path to write the private key PEM.
|
|
47
|
+
*/
|
|
48
|
+
keyPath: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Generate a self-signed certificate using only Node.js built-in crypto.
|
|
52
|
+
* Returns PEM-encoded certificate and private key strings.
|
|
53
|
+
*/
|
|
54
|
+
export declare function generateCertificate(options?: CertificateOptions): CertificateResult;
|
|
55
|
+
/**
|
|
56
|
+
* Generate a self-signed certificate and write PEM files to disk.
|
|
57
|
+
* Returns the same CertificateResult as generateCertificate().
|
|
58
|
+
*/
|
|
59
|
+
export declare function generateCertificateFiles(options: CertificateFileOptions): Promise<CertificateResult>;
|
|
60
|
+
//#endregion
|
|
4
61
|
//#region src/bin-store.d.ts
|
|
5
62
|
/**
|
|
6
63
|
* A request captured by a bin, including method, headers, body and metadata.
|
|
@@ -48,179 +105,110 @@ type Bin = {
|
|
|
48
105
|
/** Number of requests currently stored in the bin */
|
|
49
106
|
requestCount: number;
|
|
50
107
|
};
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/mock-http-bins.d.ts
|
|
51
110
|
/**
|
|
52
|
-
*
|
|
53
|
-
* implementation is in-memory; alternative backends (Redis, SQLite, etc.) can
|
|
54
|
-
* implement this interface without changes to the rest of the codebase.
|
|
55
|
-
*/
|
|
56
|
-
interface BinStore {
|
|
57
|
-
/** Create a new bin record. */
|
|
58
|
-
createBin(bin: Bin): void;
|
|
59
|
-
/** Look up a bin by id. */
|
|
60
|
-
getBin(id: string): Bin | undefined;
|
|
61
|
-
/** Return all bins. */
|
|
62
|
-
listBins(): Bin[];
|
|
63
|
-
/** Remove a bin and all its captured requests. Returns true if removed. */
|
|
64
|
-
deleteBin(id: string): boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Append a captured request to a bin, dropping the oldest if the bin has
|
|
67
|
-
* already reached `max` requests (FIFO).
|
|
68
|
-
*/
|
|
69
|
-
addRequest(binId: string, req: CapturedRequest, max: number): void;
|
|
70
|
-
/** List captured requests for a bin (newest first). */
|
|
71
|
-
getRequests(binId: string): CapturedRequest[];
|
|
72
|
-
/** Look up a single captured request by id. */
|
|
73
|
-
getRequest(binId: string, reqId: string): CapturedRequest | undefined;
|
|
74
|
-
/** Clear all captured requests in a bin (the bin itself is preserved). */
|
|
75
|
-
clearRequests(binId: string): void;
|
|
76
|
-
/**
|
|
77
|
-
* Remove bins whose `expiresAt` is in the past relative to `now`.
|
|
78
|
-
* Returns the ids of bins that were removed.
|
|
79
|
-
*/
|
|
80
|
-
cleanupExpired(now: number): string[];
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* In-memory implementation of {@link BinStore} backed by two Maps. State is
|
|
84
|
-
* lost when the process exits.
|
|
111
|
+
* One bin and its captured requests, stored as a single Keyv value.
|
|
85
112
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
getBin(id: string): Bin | undefined;
|
|
91
|
-
listBins(): Bin[];
|
|
92
|
-
deleteBin(id: string): boolean;
|
|
93
|
-
addRequest(binId: string, req: CapturedRequest, max: number): void;
|
|
94
|
-
getRequests(binId: string): CapturedRequest[];
|
|
95
|
-
getRequest(binId: string, reqId: string): CapturedRequest | undefined;
|
|
96
|
-
clearRequests(binId: string): void;
|
|
97
|
-
cleanupExpired(now: number): string[];
|
|
98
|
-
}
|
|
99
|
-
//#endregion
|
|
100
|
-
//#region src/bin-manager.d.ts
|
|
113
|
+
type BinDocument = {
|
|
114
|
+
bin: Bin;
|
|
115
|
+
requests: CapturedRequest[];
|
|
116
|
+
};
|
|
101
117
|
/**
|
|
102
|
-
*
|
|
118
|
+
* Options for a {@link MockHttpBins} instance.
|
|
103
119
|
*/
|
|
104
|
-
type
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
type MockHttpBinsOptions = {
|
|
121
|
+
/**
|
|
122
|
+
* Keyv store for bins. The default is `new Keyv()`, which keeps data in memory.
|
|
123
|
+
* Pass an instance when you want a different Keyv adapter.
|
|
124
|
+
*/
|
|
125
|
+
keyv?: Keyv<BinDocument>;
|
|
126
|
+
/** Bin lifetime in milliseconds. The default is 24 hours. */
|
|
108
127
|
defaultTtlMs?: number;
|
|
109
|
-
/** Maximum number of requests
|
|
128
|
+
/** Maximum number of requests in one bin. The default is 100. */
|
|
110
129
|
maxRequestsPerBin?: number;
|
|
111
|
-
/** Maximum captured body size in bytes.
|
|
130
|
+
/** Maximum captured body size in bytes. The default is 128 KiB. */
|
|
112
131
|
maxBodySize?: number;
|
|
113
|
-
/** Length of generated bin
|
|
132
|
+
/** Length of a generated bin id or request id. The default is 12. */
|
|
114
133
|
idLength?: number;
|
|
115
|
-
/** Interval between cleanup sweeps in milliseconds. Defaults to 1 minute. */
|
|
116
|
-
cleanupIntervalMs?: number;
|
|
117
134
|
};
|
|
118
135
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
136
|
+
* Stores request bins in Keyv.
|
|
137
|
+
* The default store is `new Keyv()`, which keeps data in memory.
|
|
121
138
|
*/
|
|
122
|
-
export declare class
|
|
123
|
-
private readonly
|
|
139
|
+
export declare class MockHttpBins {
|
|
140
|
+
private readonly _keyv;
|
|
124
141
|
private readonly _defaultTtlMs;
|
|
125
142
|
private readonly _maxRequestsPerBin;
|
|
126
143
|
private readonly _maxBodySize;
|
|
127
144
|
private readonly _idLength;
|
|
128
|
-
private readonly
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
get store(): BinStore;
|
|
145
|
+
private readonly _locks;
|
|
146
|
+
constructor(options?: MockHttpBinsOptions);
|
|
147
|
+
/** Keyv instance that stores the bins. */
|
|
148
|
+
get keyv(): Keyv<BinDocument>;
|
|
133
149
|
/** Maximum captured body size in bytes. */
|
|
134
150
|
get maxBodySize(): number;
|
|
135
|
-
/** Maximum number of requests
|
|
151
|
+
/** Maximum number of requests in one bin. */
|
|
136
152
|
get maxRequestsPerBin(): number;
|
|
137
153
|
/** Default bin lifetime in milliseconds. */
|
|
138
154
|
get defaultTtlMs(): number;
|
|
139
|
-
/** Create a new bin with the configured TTL. */
|
|
140
|
-
createBin(): Bin;
|
|
141
|
-
/**
|
|
142
|
-
* Look up a bin by id. Returns `undefined` if the bin does not exist or
|
|
143
|
-
* has expired (in which case it is also lazily removed).
|
|
144
|
-
*/
|
|
145
|
-
getBin(id: string): Bin | undefined;
|
|
146
|
-
/** List all non-expired bins. */
|
|
147
|
-
listBins(): Bin[];
|
|
148
|
-
/** Delete a bin. Returns true if the bin existed. */
|
|
149
|
-
deleteBin(id: string): boolean;
|
|
150
|
-
/**
|
|
151
|
-
* Record an incoming request against a bin. Returns the stored
|
|
152
|
-
* {@link CapturedRequest}, or `undefined` if the bin does not exist or is
|
|
153
|
-
* expired.
|
|
154
|
-
*/
|
|
155
|
-
recordRequest(binId: string, raw: Omit<CapturedRequest, "id" | "binId" | "capturedAt">): CapturedRequest | undefined;
|
|
156
|
-
/** List captured requests for a bin (newest first). */
|
|
157
|
-
getRequests(binId: string): CapturedRequest[];
|
|
158
|
-
/** Look up a single captured request. */
|
|
159
|
-
getRequest(binId: string, reqId: string): CapturedRequest | undefined;
|
|
160
|
-
/** Clear all captured requests in a bin. */
|
|
161
|
-
clearRequests(binId: string): void;
|
|
162
|
-
/** Start the periodic cleanup of expired bins. */
|
|
163
|
-
start(): void;
|
|
164
|
-
/** Stop the periodic cleanup. Idempotent. */
|
|
165
|
-
stop(): void;
|
|
166
|
-
private generateId;
|
|
167
|
-
}
|
|
168
|
-
//#endregion
|
|
169
|
-
//#region src/certificate.d.ts
|
|
170
|
-
type CertificateOptions = {
|
|
171
155
|
/**
|
|
172
|
-
*
|
|
156
|
+
* Create a new bin with the configured lifetime.
|
|
157
|
+
* Throws when Keyv does not store the bin.
|
|
173
158
|
*/
|
|
174
|
-
|
|
159
|
+
createBin(): Promise<Bin>;
|
|
175
160
|
/**
|
|
176
|
-
*
|
|
161
|
+
* Look up a bin by id.
|
|
162
|
+
* Returns `undefined` when the bin does not exist or Keyv has expired it.
|
|
163
|
+
* A failed read also returns `undefined` when the Keyv instance has an `error` listener.
|
|
177
164
|
*/
|
|
178
|
-
|
|
179
|
-
type: "dns";
|
|
180
|
-
value: string;
|
|
181
|
-
} | {
|
|
182
|
-
type: "ip";
|
|
183
|
-
value: string;
|
|
184
|
-
}>;
|
|
165
|
+
getBin(id: string): Promise<Bin | undefined>;
|
|
185
166
|
/**
|
|
186
|
-
*
|
|
167
|
+
* List the bins that Keyv still holds.
|
|
168
|
+
* Throws when the Keyv store has no iterator.
|
|
169
|
+
* When the Keyv instance has an `error` listener, a failed walk returns the bins read before the error.
|
|
187
170
|
*/
|
|
188
|
-
|
|
171
|
+
listBins(): Promise<Bin[]>;
|
|
189
172
|
/**
|
|
190
|
-
*
|
|
173
|
+
* Delete a bin. Returns true when the bin existed.
|
|
174
|
+
* The delete waits for captures already queued for that bin, so a capture cannot write the bin back.
|
|
191
175
|
*/
|
|
192
|
-
|
|
193
|
-
};
|
|
194
|
-
type CertificateResult = {
|
|
176
|
+
deleteBin(id: string): Promise<boolean>;
|
|
195
177
|
/**
|
|
196
|
-
*
|
|
178
|
+
* Record a request for a bin.
|
|
179
|
+
* Returns `undefined` when the bin does not exist.
|
|
180
|
+
* Throws when Keyv does not store the capture.
|
|
197
181
|
*/
|
|
198
|
-
|
|
182
|
+
recordRequest(binId: string, raw: Omit<CapturedRequest, "id" | "binId" | "capturedAt">): Promise<CapturedRequest | undefined>;
|
|
183
|
+
/** List captured requests for a bin, newest first. */
|
|
184
|
+
getRequests(binId: string): Promise<CapturedRequest[]>;
|
|
185
|
+
/** Look up one captured request. */
|
|
186
|
+
getRequest(binId: string, reqId: string): Promise<CapturedRequest | undefined>;
|
|
199
187
|
/**
|
|
200
|
-
*
|
|
188
|
+
* Remove captured requests and keep the bin.
|
|
189
|
+
* Returns false when the bin does not exist.
|
|
190
|
+
* Throws when Keyv does not store the change.
|
|
201
191
|
*/
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
192
|
+
clearRequests(binId: string): Promise<boolean>;
|
|
193
|
+
/** Keyv 6 yields nothing when the store has no iterator. Listing must fail instead. */
|
|
194
|
+
private canIterate;
|
|
195
|
+
/** Returns false when the bin does not exist. */
|
|
196
|
+
private appendRequest;
|
|
205
197
|
/**
|
|
206
|
-
*
|
|
198
|
+
* Write a bin document with a TTL from its lifetime.
|
|
199
|
+
* Keyv returns false or throws when the write fails. Both cases throw here.
|
|
207
200
|
*/
|
|
208
|
-
|
|
201
|
+
private save;
|
|
209
202
|
/**
|
|
210
|
-
*
|
|
203
|
+
* Run writes for one bin in order.
|
|
204
|
+
* A failed write does not block the next write for that bin.
|
|
211
205
|
*/
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
export declare function generateCertificate(options?: CertificateOptions): CertificateResult;
|
|
219
|
-
/**
|
|
220
|
-
* Generate a self-signed certificate and write PEM files to disk.
|
|
221
|
-
* Returns the same CertificateResult as generateCertificate().
|
|
222
|
-
*/
|
|
223
|
-
export declare function generateCertificateFiles(options: CertificateFileOptions): Promise<CertificateResult>;
|
|
206
|
+
private enqueue;
|
|
207
|
+
/** Keyv keeps a key without a TTL forever, so the TTL never drops below 1 ms. */
|
|
208
|
+
private ttlFor;
|
|
209
|
+
private binKey;
|
|
210
|
+
private generateId;
|
|
211
|
+
}
|
|
224
212
|
//#endregion
|
|
225
213
|
//#region src/tap-manager.d.ts
|
|
226
214
|
/**
|
|
@@ -430,12 +418,6 @@ type MockHttpOptions = {
|
|
|
430
418
|
* timeout (needed on Cloudflare Workers, where avvio timers are unreliable).
|
|
431
419
|
*/
|
|
432
420
|
pluginTimeout?: number;
|
|
433
|
-
/**
|
|
434
|
-
* Whether to start the request-bin cleanup timer during `initialize()`.
|
|
435
|
-
* Defaults to true. Disable this on Cloudflare Workers, where `setInterval`
|
|
436
|
-
* during startup can hang the isolate.
|
|
437
|
-
*/
|
|
438
|
-
startBins?: boolean;
|
|
439
421
|
/**
|
|
440
422
|
* HTTPS configuration. Set to true to auto-generate a self-signed certificate,
|
|
441
423
|
* or provide an object with cert/key strings/paths or auto-generation options.
|
|
@@ -464,7 +446,6 @@ declare class MockHttp extends Hookified {
|
|
|
464
446
|
private _siteDistPath;
|
|
465
447
|
private _logging;
|
|
466
448
|
private _pluginTimeout?;
|
|
467
|
-
private _startBins;
|
|
468
449
|
private _httpBin;
|
|
469
450
|
private _rateLimit?;
|
|
470
451
|
private _http2;
|
|
@@ -563,16 +544,6 @@ declare class MockHttp extends Hookified {
|
|
|
563
544
|
* Fastify plugin boot timeout in milliseconds. `undefined` uses Fastify's default.
|
|
564
545
|
*/
|
|
565
546
|
set pluginTimeout(pluginTimeout: number | undefined);
|
|
566
|
-
/**
|
|
567
|
-
* Whether to start the request-bin cleanup timer during `initialize()`.
|
|
568
|
-
* @default true
|
|
569
|
-
*/
|
|
570
|
-
get startBins(): boolean;
|
|
571
|
-
/**
|
|
572
|
-
* Whether to start the request-bin cleanup timer during `initialize()`.
|
|
573
|
-
* @default true
|
|
574
|
-
*/
|
|
575
|
-
set startBins(startBins: boolean);
|
|
576
547
|
/**
|
|
577
548
|
* HTTPS configuration. Set to true to auto-generate a self-signed certificate,
|
|
578
549
|
* or provide an HttpsOptions object with cert/key or auto-generation options.
|
|
@@ -646,13 +617,13 @@ declare class MockHttp extends Hookified {
|
|
|
646
617
|
*/
|
|
647
618
|
set taps(taps: TapManager);
|
|
648
619
|
/**
|
|
649
|
-
* The
|
|
620
|
+
* The MockHttpBins instance for request bins.
|
|
650
621
|
*/
|
|
651
|
-
get bins():
|
|
622
|
+
get bins(): MockHttpBins;
|
|
652
623
|
/**
|
|
653
|
-
* The
|
|
624
|
+
* The MockHttpBins instance for request bins.
|
|
654
625
|
*/
|
|
655
|
-
set bins(bins:
|
|
626
|
+
set bins(bins: MockHttpBins);
|
|
656
627
|
/**
|
|
657
628
|
* Register plugins and routes without listening. Use `inject()` against
|
|
658
629
|
* `server`, or call `start()` to bind a port.
|
|
@@ -749,4 +720,4 @@ declare class MockHttp extends Hookified {
|
|
|
749
720
|
//#region src/index.d.ts
|
|
750
721
|
export declare const start: () => Promise<MockHttp>;
|
|
751
722
|
//#endregion
|
|
752
|
-
export { type Bin, type
|
|
723
|
+
export { type Bin, type CapturedRequest, type CertificateFileOptions, type CertificateOptions, type CertificateResult, type HttpsOptions, type InjectionMatcher, type InjectionResponse, type InjectionTap, type MockHttpBinsOptions, MockHttp as default, MockHttp as mockhttp };
|