@jaredwray/mockhttp 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,7 +60,7 @@ then run `mockhttp` in your code.
60
60
  import { mockhttp } from '@jaredwray/mockhttp';
61
61
  await mockhttp.start(); // start the server
62
62
  const response = await fetch('http://localhost:3000/get');
63
- console.log(reaponse);
63
+ console.log(response);
64
64
  await mockhttp.stop(); // stop the server
65
65
  ```
66
66
 
@@ -247,6 +247,164 @@ const tap = mock.taps.inject(
247
247
  );
248
248
  ```
249
249
 
250
+ # Rate Limiting
251
+
252
+ 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.
253
+
254
+ ## Default Rate Limiting
255
+
256
+ By default, MockHttp applies the following rate limit:
257
+ - **1000 requests per minute** per IP address
258
+ - **Localhost is excluded** - requests from 127.0.0.1 and ::1 bypass rate limiting (ideal for local development and testing)
259
+
260
+ ```javascript
261
+ import { MockHttp } from '@jaredwray/mockhttp';
262
+
263
+ const mock = new MockHttp();
264
+ await mock.start();
265
+ // Rate limiting is active (1000 req/min) except for localhost
266
+ ```
267
+
268
+ ## Customizing Rate Limiting
269
+
270
+ To customize rate limiting, pass a `rateLimit` configuration object when creating your MockHttp instance:
271
+
272
+ ```javascript
273
+ import { MockHttp } from '@jaredwray/mockhttp';
274
+
275
+ const mock = new MockHttp({
276
+ rateLimit: {
277
+ max: 100, // Maximum 100 requests
278
+ timeWindow: '1 minute' // Per 1 minute window
279
+ }
280
+ });
281
+
282
+ await mock.start();
283
+ ```
284
+
285
+ ## Common Configuration Options
286
+
287
+ The `rateLimit` option accepts all [@fastify/rate-limit options](https://github.com/fastify/fastify-rate-limit#options):
288
+
289
+ ### Basic Rate Limiting
290
+
291
+ ```javascript
292
+ // Limit to 50 requests per minute
293
+ const mock = new MockHttp({
294
+ rateLimit: {
295
+ max: 50,
296
+ timeWindow: '1 minute'
297
+ }
298
+ });
299
+ ```
300
+
301
+ ### Stricter Limits with Custom Error Response
302
+
303
+ ```javascript
304
+ const mock = new MockHttp({
305
+ rateLimit: {
306
+ max: 30,
307
+ timeWindow: 60000, // 1 minute in milliseconds
308
+ errorResponseBuilder: (req, context) => ({
309
+ statusCode: 429,
310
+ error: 'Too Many Requests',
311
+ message: `Rate limit exceeded. Try again in ${context.after}`
312
+ })
313
+ }
314
+ });
315
+ ```
316
+
317
+ ### Allow List (Exclude Specific IPs)
318
+
319
+ ```javascript
320
+ const mock = new MockHttp({
321
+ rateLimit: {
322
+ max: 100,
323
+ timeWindow: '1 minute',
324
+ allowList: ['127.0.0.1', '192.168.1.100'] // These IPs bypass rate limiting
325
+ }
326
+ });
327
+ ```
328
+
329
+ ### Custom Key Generator (Rate Limit by Header)
330
+
331
+ ```javascript
332
+ const mock = new MockHttp({
333
+ rateLimit: {
334
+ max: 100,
335
+ timeWindow: '1 minute',
336
+ keyGenerator: (request) => {
337
+ // Rate limit by API key instead of IP
338
+ return request.headers['x-api-key'] || request.ip;
339
+ }
340
+ }
341
+ });
342
+ ```
343
+
344
+ ### Advanced Configuration
345
+
346
+ ```javascript
347
+ const mock = new MockHttp({
348
+ rateLimit: {
349
+ global: true, // Apply to all routes
350
+ max: 100, // Max requests
351
+ timeWindow: '1 minute', // Time window
352
+ cache: 10000, // Cache size for tracking clients
353
+ skipOnError: false, // Don't skip on storage errors
354
+ ban: 10, // Ban after 10 rate limit violations
355
+ continueExceeding: false, // Don't reset window on each request
356
+ enableDraftSpec: true, // Use IETF draft spec headers
357
+ addHeaders: { // Customize rate limit headers
358
+ 'x-ratelimit-limit': true,
359
+ 'x-ratelimit-remaining': true,
360
+ 'x-ratelimit-reset': true
361
+ }
362
+ }
363
+ });
364
+ ```
365
+
366
+ ## Disabling Rate Limiting
367
+
368
+ To disable rate limiting completely, set the `rateLimit` option to `false`:
369
+
370
+ ```javascript
371
+ const mock = new MockHttp({
372
+ rateLimit: false // Completely disable rate limiting
373
+ });
374
+
375
+ await mock.start();
376
+ // No rate limiting is applied to any requests
377
+ ```
378
+
379
+ **Note:** To change rate limiting settings after the server has started, you must restart the server:
380
+
381
+ ```javascript
382
+ const mock = new MockHttp();
383
+ await mock.start(); // Starts with default rate limiting
384
+
385
+ // To change or disable rate limiting:
386
+ await mock.close();
387
+ mock.rateLimit = undefined; // or set new options
388
+ await mock.start(); // Restarts with new settings
389
+ ```
390
+
391
+ ## Available Options
392
+
393
+ | Option | Type | Default | Description |
394
+ |--------|------|---------|-------------|
395
+ | `max` | number \| function | `1000` | Maximum requests per time window |
396
+ | `timeWindow` | number \| string | `60000` | Duration of rate limit window (milliseconds or string like '1 minute') |
397
+ | `cache` | number | `5000` | LRU cache size for tracking clients |
398
+ | `allowList` | array \| function | `[]` | IPs or function to exclude from rate limiting |
399
+ | `keyGenerator` | function | IP-based | Function to generate unique client identifier |
400
+ | `errorResponseBuilder` | function | Default 429 | Custom error response function |
401
+ | `skipOnError` | boolean | `false` | Skip rate limiting if storage errors occur |
402
+ | `ban` | number | `-1` | Ban client after N violations (disabled by default) |
403
+ | `continueExceeding` | boolean | `false` | Renew time window on each request while limited |
404
+ | `enableDraftSpec` | boolean | `false` | Use IETF draft specification headers |
405
+
406
+ For the complete list of options, see the [@fastify/rate-limit documentation](https://github.com/fastify/fastify-rate-limit#options).
407
+
250
408
  # API Reference
251
409
 
252
410
  ## MockHttp Class
@@ -264,7 +422,18 @@ new MockHttp(options?)
264
422
  - `autoDetectPort?`: boolean - Auto-detect next available port if in use (default: true)
265
423
  - `helmet?`: boolean - Use Helmet for security headers (default: true)
266
424
  - `apiDocs?`: boolean - Enable Swagger API documentation (default: true)
425
+ - `rateLimit?`: RateLimitPluginOptions - Configure rate limiting (default: 1000 req/min, localhost excluded)
267
426
  - `httpBin?`: HttpBinOptions - Configure which httpbin routes to enable
427
+ - `httpMethods?`: boolean - Enable HTTP method routes (default: true)
428
+ - `redirects?`: boolean - Enable redirect routes (default: true)
429
+ - `requestInspection?`: boolean - Enable request inspection routes (default: true)
430
+ - `responseInspection?`: boolean - Enable response inspection routes (default: true)
431
+ - `statusCodes?`: boolean - Enable status code routes (default: true)
432
+ - `responseFormats?`: boolean - Enable response format routes (default: true)
433
+ - `cookies?`: boolean - Enable cookie routes (default: true)
434
+ - `anything?`: boolean - Enable anything routes (default: true)
435
+ - `auth?`: boolean - Enable authentication routes (default: true)
436
+ - `images?`: boolean - Enable image routes (default: true)
268
437
  - `hookOptions?`: HookifiedOptions - Hookified options
269
438
 
270
439
  ### Properties
@@ -274,6 +443,7 @@ new MockHttp(options?)
274
443
  - `autoDetectPort`: boolean - Get/set auto-detect port behavior
275
444
  - `helmet`: boolean - Get/set Helmet security headers
276
445
  - `apiDocs`: boolean - Get/set API documentation
446
+ - `rateLimit`: RateLimitPluginOptions | undefined - Get/set rate limiting options
277
447
  - `httpBin`: HttpBinOptions - Get/set httpbin route options
278
448
  - `server`: FastifyInstance - Get/set the Fastify server instance
279
449
  - `taps`: TapManager - Get/set the TapManager instance
@@ -334,6 +504,10 @@ Register "anything" catch-all routes.
334
504
 
335
505
  Register authentication routes (basic, bearer, digest, hidden-basic).
336
506
 
507
+ #### `async registerImageRoutes(fastifyInstance?)`
508
+
509
+ Register image routes (jpeg, png, svg, webp) with content negotiation support.
510
+
337
511
  ## Taps (Response Injection)
338
512
 
339
513
  Access the TapManager via `mockHttp.taps` to inject custom responses.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { RateLimitPluginOptions } from '@fastify/rate-limit';
1
2
  import { FastifyRequest, FastifyInstance } from 'fastify';
2
3
  import { Hookified, HookifiedOptions } from 'hookified';
3
4
 
@@ -130,6 +131,7 @@ type HttpBinOptions = {
130
131
  cookies?: boolean;
131
132
  anything?: boolean;
132
133
  auth?: boolean;
134
+ images?: boolean;
133
135
  };
134
136
  type MockHttpOptions = {
135
137
  /**
@@ -157,6 +159,11 @@ type MockHttpOptions = {
157
159
  * Whether to use Swagger UI. Defaults to true.
158
160
  */
159
161
  httpBin?: HttpBinOptions;
162
+ /**
163
+ * Rate limiting options. Defaults to 1000 requests per minute (localhost excluded).
164
+ * Set to undefined to disable rate limiting, or provide custom options to configure.
165
+ */
166
+ rateLimit?: boolean | RateLimitPluginOptions;
160
167
  /**
161
168
  * Hookified options.
162
169
  */
@@ -169,6 +176,7 @@ declare class MockHttp extends Hookified {
169
176
  private _helmet;
170
177
  private _apiDocs;
171
178
  private _httpBin;
179
+ private _rateLimit?;
172
180
  private _server;
173
181
  private _taps;
174
182
  constructor(options?: MockHttpOptions);
@@ -230,6 +238,20 @@ declare class MockHttp extends Hookified {
230
238
  * HTTP Bin options. Defaults to all enabled.
231
239
  */
232
240
  set httpBin(httpBinary: HttpBinOptions);
241
+ /**
242
+ * Rate limiting options. Defaults to 1000 requests per minute (localhost excluded).
243
+ * Set to undefined to disable rate limiting, or provide custom options to configure.
244
+ * @default { max: 1000, timeWindow: "1 minute", allowList: ["127.0.0.1", "::1"] }
245
+ */
246
+ get rateLimit(): RateLimitPluginOptions | undefined;
247
+ /**
248
+ * Rate limiting options. Defaults to 1000 requests per minute (localhost excluded).
249
+ * Set to undefined to disable rate limiting, or provide custom options to configure.
250
+ *
251
+ * Note: Changing this property requires restarting the server (close() then start()) for changes to take effect.
252
+ * @default { max: 1000, timeWindow: "1 minute", allowList: ["127.0.0.1", "::1"] }
253
+ */
254
+ set rateLimit(rateLimit: RateLimitPluginOptions | undefined);
233
255
  /**
234
256
  * The Fastify server instance.
235
257
  */
@@ -305,6 +327,11 @@ declare class MockHttp extends Hookified {
305
327
  * @param fastifyInstance - the server instance to register the routes on.
306
328
  */
307
329
  registerAuthRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
330
+ /**
331
+ * Register the image routes.
332
+ * @param fastifyInstance - the server instance to register the routes on.
333
+ */
334
+ registerImageRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
308
335
  }
309
336
 
310
337
  declare const start: () => Promise<MockHttp>;