@zimic/interceptor 0.16.0-canary.1 → 0.16.0-canary.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +4 -5
  2. package/dist/{chunk-6TSSHQW5.mjs → chunk-NTRC2S4I.mjs} +253 -312
  3. package/dist/chunk-NTRC2S4I.mjs.map +1 -0
  4. package/dist/{chunk-R2ROSKU4.js → chunk-O6ZIPCUJ.js} +254 -313
  5. package/dist/chunk-O6ZIPCUJ.js.map +1 -0
  6. package/dist/cli.js +9 -9
  7. package/dist/cli.js.map +1 -1
  8. package/dist/cli.mjs +5 -5
  9. package/dist/cli.mjs.map +1 -1
  10. package/dist/http.d.ts +156 -176
  11. package/dist/http.js +265 -324
  12. package/dist/http.js.map +1 -1
  13. package/dist/http.mjs +263 -323
  14. package/dist/http.mjs.map +1 -1
  15. package/dist/server.d.ts +20 -46
  16. package/dist/server.js +7 -7
  17. package/dist/server.mjs +1 -1
  18. package/package.json +8 -8
  19. package/src/cli/browser/init.ts +2 -2
  20. package/src/cli/server/start.ts +2 -2
  21. package/src/http/index.ts +6 -13
  22. package/src/http/interceptor/HttpInterceptorClient.ts +30 -15
  23. package/src/http/interceptor/LocalHttpInterceptor.ts +8 -8
  24. package/src/http/interceptor/RemoteHttpInterceptor.ts +8 -8
  25. package/src/http/interceptor/errors/RequestSavingSafeLimitExceededError.ts +22 -0
  26. package/src/http/interceptor/factory.ts +1 -1
  27. package/src/http/interceptor/types/options.ts +4 -11
  28. package/src/http/interceptor/types/public.ts +44 -12
  29. package/src/http/interceptor/types/schema.ts +2 -2
  30. package/src/http/interceptorWorker/HttpInterceptorWorker.ts +6 -31
  31. package/src/http/requestHandler/HttpRequestHandlerClient.ts +15 -5
  32. package/src/http/requestHandler/errors/DisabledRequestSavingError.ts +2 -2
  33. package/src/http/requestHandler/errors/TimesCheckError.ts +15 -14
  34. package/src/http/requestHandler/types/public.ts +16 -8
  35. package/src/server/index.ts +1 -11
  36. package/src/utils/console.ts +2 -2
  37. package/dist/chunk-6TSSHQW5.mjs.map +0 -1
  38. package/dist/chunk-R2ROSKU4.js.map +0 -1
  39. package/src/http/interceptorWorker/HttpInterceptorWorkerStore.ts +0 -34
  40. package/src/http/namespace/HttpInterceptorNamespace.ts +0 -81
  41. package/src/server/namespace/InterceptorServerNamespace.ts +0 -21
package/dist/server.d.ts CHANGED
@@ -1,3 +1,17 @@
1
+ /**
2
+ * An error thrown when the interceptor server is running and some operation requires it to be stopped first.
3
+ *
4
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐server `@zimic/interceptor/server` - API reference}
5
+ */
6
+ declare class RunningInterceptorServerError extends Error {
7
+ constructor(additionalMessage: string);
8
+ }
9
+
10
+ /** An error thrown when the interceptor server is not running. */
11
+ declare class NotRunningInterceptorServerError extends Error {
12
+ constructor();
13
+ }
14
+
1
15
  /**
2
16
  * The options to create an
3
17
  * {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server interceptor server}.
@@ -73,48 +87,6 @@ interface InterceptorServer {
73
87
  stop: () => Promise<void>;
74
88
  }
75
89
 
76
- /**
77
- * Creates an {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server interceptor server}.
78
- *
79
- * @param options The options to create the server.
80
- * @returns The created server.
81
- * @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server-programmatic-usage `zimic-interceptor server` programmatic usage}
82
- * @see {@link https://github.com/zimicjs/zimic/wiki/getting‐started#remote-http-interceptors Remote HTTP Interceptors} .
83
- */
84
- declare function createInterceptorServer(options?: InterceptorServerOptions): InterceptorServer;
85
-
86
- /**
87
- * A namespace of interceptor server resources for handling HTTP requests.
88
- *
89
- * @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server-programmatic-usage `zimic-interceptor server` programmatic usage}
90
- * @see {@link https://github.com/zimicjs/zimic/wiki/getting‐started#remote-http-interceptors Remote HTTP Interceptors} .
91
- */
92
- declare class InterceptorServerNamespace {
93
- /**
94
- * Creates an {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server interceptor server}.
95
- *
96
- * @param options The options to create the server.
97
- * @returns The created server.
98
- * @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server-programmatic-usage `zimic-interceptor server` programmatic usage}
99
- * @see {@link https://github.com/zimicjs/zimic/wiki/getting‐started#remote-http-interceptors Remote HTTP Interceptors} .
100
- */
101
- create: typeof createInterceptorServer;
102
- }
103
-
104
- /**
105
- * An error thrown when the interceptor server is running and some operation requires it to be stopped first.
106
- *
107
- * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐server `@zimic/interceptor/server` - API reference}
108
- */
109
- declare class RunningInterceptorServerError extends Error {
110
- constructor(additionalMessage: string);
111
- }
112
-
113
- /** An error thrown when the interceptor server is not running. */
114
- declare class NotRunningInterceptorServerError extends Error {
115
- constructor();
116
- }
117
-
118
90
  /** The default access control headers for the server. */
119
91
  declare const DEFAULT_ACCESS_CONTROL_HEADERS: Readonly<{
120
92
  'access-control-allow-origin': "*";
@@ -127,11 +99,13 @@ declare const DEFAULT_ACCESS_CONTROL_HEADERS: Readonly<{
127
99
  declare const DEFAULT_PREFLIGHT_STATUS_CODE = 204;
128
100
 
129
101
  /**
130
- * A namespace of interceptor server resources for handling HTTP requests.
102
+ * Creates an {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server interceptor server}.
131
103
  *
132
- * @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server `zimic-interceptor server` API reference}
104
+ * @param options The options to create the server.
105
+ * @returns The created server.
106
+ * @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server-programmatic-usage `zimic-interceptor server` programmatic usage}
133
107
  * @see {@link https://github.com/zimicjs/zimic/wiki/getting‐started#remote-http-interceptors Remote HTTP Interceptors} .
134
108
  */
135
- declare const interceptorServer: Readonly<InterceptorServerNamespace>;
109
+ declare function createInterceptorServer(options?: InterceptorServerOptions): InterceptorServer;
136
110
 
137
- export { DEFAULT_ACCESS_CONTROL_HEADERS, DEFAULT_PREFLIGHT_STATUS_CODE, type InterceptorServer, InterceptorServerNamespace, type InterceptorServerOptions, NotRunningInterceptorServerError, RunningInterceptorServerError, interceptorServer };
111
+ export { DEFAULT_ACCESS_CONTROL_HEADERS, DEFAULT_PREFLIGHT_STATUS_CODE, type InterceptorServer, type InterceptorServerOptions, NotRunningInterceptorServerError, RunningInterceptorServerError, createInterceptorServer };
package/dist/server.js CHANGED
@@ -1,29 +1,29 @@
1
1
  'use strict';
2
2
 
3
- var chunkR2ROSKU4_js = require('./chunk-R2ROSKU4.js');
3
+ var chunkO6ZIPCUJ_js = require('./chunk-O6ZIPCUJ.js');
4
4
  require('./chunk-WCQVDF3K.js');
5
5
 
6
6
 
7
7
 
8
8
  Object.defineProperty(exports, "DEFAULT_ACCESS_CONTROL_HEADERS", {
9
9
  enumerable: true,
10
- get: function () { return chunkR2ROSKU4_js.DEFAULT_ACCESS_CONTROL_HEADERS; }
10
+ get: function () { return chunkO6ZIPCUJ_js.DEFAULT_ACCESS_CONTROL_HEADERS; }
11
11
  });
12
12
  Object.defineProperty(exports, "DEFAULT_PREFLIGHT_STATUS_CODE", {
13
13
  enumerable: true,
14
- get: function () { return chunkR2ROSKU4_js.DEFAULT_PREFLIGHT_STATUS_CODE; }
14
+ get: function () { return chunkO6ZIPCUJ_js.DEFAULT_PREFLIGHT_STATUS_CODE; }
15
15
  });
16
16
  Object.defineProperty(exports, "NotRunningInterceptorServerError", {
17
17
  enumerable: true,
18
- get: function () { return chunkR2ROSKU4_js.NotRunningInterceptorServerError_default; }
18
+ get: function () { return chunkO6ZIPCUJ_js.NotRunningInterceptorServerError_default; }
19
19
  });
20
20
  Object.defineProperty(exports, "RunningInterceptorServerError", {
21
21
  enumerable: true,
22
- get: function () { return chunkR2ROSKU4_js.RunningInterceptorServerError_default; }
22
+ get: function () { return chunkO6ZIPCUJ_js.RunningInterceptorServerError_default; }
23
23
  });
24
- Object.defineProperty(exports, "interceptorServer", {
24
+ Object.defineProperty(exports, "createInterceptorServer", {
25
25
  enumerable: true,
26
- get: function () { return chunkR2ROSKU4_js.interceptorServer; }
26
+ get: function () { return chunkO6ZIPCUJ_js.createInterceptorServer; }
27
27
  });
28
28
  //# sourceMappingURL=server.js.map
29
29
  //# sourceMappingURL=server.js.map
package/dist/server.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { DEFAULT_ACCESS_CONTROL_HEADERS, DEFAULT_PREFLIGHT_STATUS_CODE, NotRunningInterceptorServerError_default as NotRunningInterceptorServerError, RunningInterceptorServerError_default as RunningInterceptorServerError, interceptorServer } from './chunk-6TSSHQW5.mjs';
1
+ export { DEFAULT_ACCESS_CONTROL_HEADERS, DEFAULT_PREFLIGHT_STATUS_CODE, NotRunningInterceptorServerError_default as NotRunningInterceptorServerError, RunningInterceptorServerError_default as RunningInterceptorServerError, createInterceptorServer } from './chunk-NTRC2S4I.mjs';
2
2
  import './chunk-CGILA3WO.mjs';
3
3
  //# sourceMappingURL=server.mjs.map
4
4
  //# sourceMappingURL=server.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zimic/interceptor",
3
- "description": "TypeScript-first HTTP intercepting and mocking",
3
+ "description": "Next-gen, TypeScript-first HTTP intercepting and mocking",
4
4
  "keywords": [
5
5
  "zimic",
6
6
  "typescript",
@@ -14,7 +14,7 @@
14
14
  "api",
15
15
  "static"
16
16
  ],
17
- "version": "0.16.0-canary.1",
17
+ "version": "0.16.0-canary.11",
18
18
  "repository": {
19
19
  "type": "git",
20
20
  "url": "https://github.com/zimicjs/zimic.git",
@@ -75,10 +75,10 @@
75
75
  },
76
76
  "dependencies": {
77
77
  "@whatwg-node/server": "0.10.1",
78
- "chalk": "4.1.2",
79
78
  "execa": "9.5.2",
80
79
  "isomorphic-ws": "5.0.0",
81
80
  "msw": "2.7.3",
81
+ "picocolors": "^1.1.1",
82
82
  "ws": "8.18.1",
83
83
  "yargs": "17.7.2"
84
84
  },
@@ -89,21 +89,21 @@
89
89
  "@types/node": "^22.13.10",
90
90
  "@types/ws": "^8.18.0",
91
91
  "@types/yargs": "^17.0.33",
92
- "@vitest/browser": "^3.0.8",
93
- "@vitest/coverage-istanbul": "^3.0.8",
92
+ "@vitest/browser": "^3.0.9",
93
+ "@vitest/coverage-istanbul": "^3.0.9",
94
94
  "dotenv-cli": "^8.0.0",
95
95
  "eslint": "^9.22.0",
96
- "playwright": "^1.51.0",
96
+ "playwright": "^1.51.1",
97
97
  "tsup": "^8.4.0",
98
98
  "typescript": "^5.8.2",
99
- "vitest": "^3.0.8",
99
+ "vitest": "^3.0.9",
100
100
  "@zimic/eslint-config-node": "0.0.0",
101
101
  "@zimic/tsconfig": "0.0.0",
102
102
  "@zimic/lint-staged-config": "0.0.0",
103
103
  "@zimic/utils": "0.0.0"
104
104
  },
105
105
  "peerDependencies": {
106
- "@zimic/http": "^0.1.0 || ^0.1.0-canary.0",
106
+ "@zimic/http": "^0.2.0 || ^0.2.0-canary.0",
107
107
  "typescript": ">=4.8.0"
108
108
  },
109
109
  "peerDependenciesMeta": {
@@ -1,6 +1,6 @@
1
- import chalk from 'chalk';
2
1
  import filesystem from 'fs/promises';
3
2
  import path from 'path';
3
+ import color from 'picocolors';
4
4
 
5
5
  import { logWithPrefix } from '@/utils/console';
6
6
 
@@ -20,7 +20,7 @@ async function initializeBrowserServiceWorker({ publicDirectory }: BrowserServic
20
20
  const destinationPath = path.join(absolutePublicDirectory, SERVICE_WORKER_FILE_NAME);
21
21
  await filesystem.copyFile(MOCK_SERVICE_WORKER_PATH, destinationPath);
22
22
 
23
- logWithPrefix(`Service worker script saved to ${chalk.green(destinationPath)}!`);
23
+ logWithPrefix(`Service worker script saved to ${color.green(destinationPath)}!`);
24
24
  logWithPrefix('You can now use browser interceptors!');
25
25
  }
26
26
 
@@ -1,4 +1,4 @@
1
- import { InterceptorServer, interceptorServer } from '@/server';
1
+ import { InterceptorServer, createInterceptorServer } from '@/server';
2
2
  import { InterceptorServerOptions } from '@/server/types/options';
3
3
  import { logWithPrefix } from '@/utils/console';
4
4
  import {
@@ -26,7 +26,7 @@ async function startInterceptorServer({
26
26
  logUnhandledRequests,
27
27
  onReady,
28
28
  }: InterceptorServerStartOptions) {
29
- const server = interceptorServer.create({
29
+ const server = createInterceptorServer({
30
30
  hostname,
31
31
  port,
32
32
  logUnhandledRequests,
package/src/http/index.ts CHANGED
@@ -1,12 +1,13 @@
1
- import HttpInterceptorNamespace from './namespace/HttpInterceptorNamespace';
2
-
3
- export { default as InvalidJSONError } from './interceptorWorker/errors/InvalidJSONError';
4
- export { default as InvalidFormDataError } from './interceptorWorker/errors/InvalidFormDataError';
5
1
  export { default as RunningHttpInterceptorError } from './interceptor/errors/RunningHttpInterceptorError';
6
2
  export { default as NotRunningHttpInterceptorError } from './interceptor/errors/NotRunningHttpInterceptorError';
7
3
  export { default as UnknownHttpInterceptorPlatformError } from './interceptor/errors/UnknownHttpInterceptorPlatformError';
8
4
  export { default as UnknownHttpInterceptorTypeError } from './interceptor/errors/UnknownHttpInterceptorTypeError';
5
+ export { default as RequestSavingSafeLimitExceededError } from './interceptor/errors/RequestSavingSafeLimitExceededError';
6
+
7
+ export { default as InvalidFormDataError } from './interceptorWorker/errors/InvalidFormDataError';
8
+ export { default as InvalidJSONError } from './interceptorWorker/errors/InvalidJSONError';
9
9
  export { default as UnregisteredBrowserServiceWorkerError } from './interceptorWorker/errors/UnregisteredBrowserServiceWorkerError';
10
+
10
11
  export { default as DisabledRequestSavingError } from './requestHandler/errors/DisabledRequestSavingError';
11
12
  export { default as TimesCheckError } from './requestHandler/errors/TimesCheckError';
12
13
 
@@ -49,12 +50,4 @@ export type { InferHttpInterceptorSchema } from './interceptor/types/schema';
49
50
 
50
51
  export type { LocalHttpInterceptor, RemoteHttpInterceptor, HttpInterceptor } from './interceptor/types/public';
51
52
 
52
- /**
53
- * A namespace of interceptor resources for mocking HTTP requests.
54
- *
55
- * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httpinterceptor `HttpInterceptor` API reference}
56
- */
57
- export const httpInterceptor = Object.freeze(new HttpInterceptorNamespace());
58
-
59
- export type { default as HttpInterceptorNamespace } from './namespace/HttpInterceptorNamespace';
60
- export type { HttpInterceptorNamespaceDefault } from './namespace/HttpInterceptorNamespace';
53
+ export { createHttpInterceptor } from './interceptor/factory';
@@ -23,13 +23,17 @@ import RemoteHttpRequestHandler from '../requestHandler/RemoteHttpRequestHandler
23
23
  import { HttpRequestHandler, InternalHttpRequestHandler } from '../requestHandler/types/public';
24
24
  import { HttpInterceptorRequest } from '../requestHandler/types/requests';
25
25
  import NotRunningHttpInterceptorError from './errors/NotRunningHttpInterceptorError';
26
+ import RequestSavingSafeLimitExceededError from './errors/RequestSavingSafeLimitExceededError';
26
27
  import RunningHttpInterceptorError from './errors/RunningHttpInterceptorError';
27
28
  import HttpInterceptorStore from './HttpInterceptorStore';
28
29
  import { UnhandledRequestStrategy } from './types/options';
30
+ import { HttpInterceptorRequestSaving } from './types/public';
29
31
  import { HttpInterceptorRequestContext } from './types/requests';
30
32
 
31
33
  export const SUPPORTED_BASE_URL_PROTOCOLS = Object.freeze(['http', 'https']);
32
34
 
35
+ export const DEFAULT_REQUEST_SAVING_SAFE_LIMIT = 1000;
36
+
33
37
  class HttpInterceptorClient<
34
38
  Schema extends HttpSchema,
35
39
  HandlerConstructor extends HttpRequestHandlerConstructor = HttpRequestHandlerConstructor,
@@ -38,7 +42,9 @@ class HttpInterceptorClient<
38
42
  private store: HttpInterceptorStore;
39
43
 
40
44
  private _baseURL!: URL;
41
- private _saveRequests?: boolean;
45
+
46
+ requestSaving: HttpInterceptorRequestSaving;
47
+ private numberOfSavedRequests = 0;
42
48
 
43
49
  onUnhandledRequest?: HandlerConstructor extends typeof LocalHttpRequestHandler
44
50
  ? UnhandledRequestStrategy.Local
@@ -64,7 +70,7 @@ class HttpInterceptorClient<
64
70
  worker: HttpInterceptorWorker;
65
71
  store: HttpInterceptorStore;
66
72
  baseURL: URL;
67
- saveRequests?: boolean;
73
+ requestSaving?: Partial<HttpInterceptorRequestSaving>;
68
74
  onUnhandledRequest?: UnhandledRequestStrategy;
69
75
  Handler: HandlerConstructor;
70
76
  }) {
@@ -72,7 +78,12 @@ class HttpInterceptorClient<
72
78
  this.store = options.store;
73
79
 
74
80
  this.baseURL = options.baseURL;
75
- this._saveRequests = options.saveRequests;
81
+
82
+ this.requestSaving = {
83
+ enabled: options.requestSaving?.enabled ?? this.getDefaultRequestSavingEnabled(),
84
+ safeLimit: options.requestSaving?.safeLimit ?? DEFAULT_REQUEST_SAVING_SAFE_LIMIT,
85
+ };
86
+
76
87
  this.onUnhandledRequest = options.onUnhandledRequest satisfies
77
88
  | UnhandledRequestStrategy
78
89
  | undefined as this['onUnhandledRequest'];
@@ -80,6 +91,10 @@ class HttpInterceptorClient<
80
91
  this.Handler = options.Handler;
81
92
  }
82
93
 
94
+ private getDefaultRequestSavingEnabled(): boolean {
95
+ return isServerSide() ? process.env.NODE_ENV === 'test' : false;
96
+ }
97
+
83
98
  get baseURL() {
84
99
  return this._baseURL;
85
100
  }
@@ -103,17 +118,6 @@ class HttpInterceptorClient<
103
118
  return this.baseURL.href;
104
119
  }
105
120
 
106
- get saveRequests() {
107
- if (this._saveRequests === undefined) {
108
- return isServerSide() ? process.env.NODE_ENV === 'test' : false;
109
- }
110
- return this._saveRequests;
111
- }
112
-
113
- set saveRequests(saveRequests: boolean) {
114
- this._saveRequests = saveRequests;
115
- }
116
-
117
121
  get platform() {
118
122
  return this.worker.platform;
119
123
  }
@@ -251,7 +255,7 @@ class HttpInterceptorClient<
251
255
  const responseDeclaration = await matchedHandler.applyResponseDeclaration(parsedRequest);
252
256
  const response = HttpInterceptorWorker.createResponseFromDeclaration(request, responseDeclaration);
253
257
 
254
- if (this.saveRequests) {
258
+ if (this.requestSaving.enabled) {
255
259
  const responseClone = response.clone();
256
260
 
257
261
  const parsedResponse = await HttpInterceptorWorker.parseRawResponse<
@@ -265,6 +269,17 @@ class HttpInterceptorClient<
265
269
  return response;
266
270
  }
267
271
 
272
+ incrementNumberOfSavedRequests(increment: number) {
273
+ this.numberOfSavedRequests = Math.max(this.numberOfSavedRequests + increment, 0);
274
+
275
+ const exceedsSafeLimit = this.numberOfSavedRequests > this.requestSaving.safeLimit;
276
+
277
+ if (increment > 0 && exceedsSafeLimit) {
278
+ const error = new RequestSavingSafeLimitExceededError(this.numberOfSavedRequests, this.requestSaving.safeLimit);
279
+ console.warn(error);
280
+ }
281
+ }
282
+
268
283
  private async findMatchedHandler<
269
284
  Method extends HttpSchemaMethod<Schema>,
270
285
  Path extends HttpSchemaPath<Schema, Method>,
@@ -4,8 +4,8 @@ import LocalHttpRequestHandler from '../requestHandler/LocalHttpRequestHandler';
4
4
  import HttpInterceptorClient from './HttpInterceptorClient';
5
5
  import HttpInterceptorStore from './HttpInterceptorStore';
6
6
  import { SyncHttpInterceptorMethodHandler } from './types/handlers';
7
- import { LocalHttpInterceptorOptions } from './types/options';
8
- import { LocalHttpInterceptor as PublicLocalHttpInterceptor } from './types/public';
7
+ import { LocalHttpInterceptorOptions, UnhandledRequestStrategy } from './types/options';
8
+ import { HttpInterceptorRequestSaving, LocalHttpInterceptor as PublicLocalHttpInterceptor } from './types/public';
9
9
 
10
10
  class LocalHttpInterceptor<Schema extends HttpSchema> implements PublicLocalHttpInterceptor<Schema> {
11
11
  private store = new HttpInterceptorStore();
@@ -23,7 +23,7 @@ class LocalHttpInterceptor<Schema extends HttpSchema> implements PublicLocalHttp
23
23
  baseURL,
24
24
  Handler: LocalHttpRequestHandler,
25
25
  onUnhandledRequest: options.onUnhandledRequest,
26
- saveRequests: options.saveRequests,
26
+ requestSaving: options.requestSaving,
27
27
  });
28
28
  }
29
29
 
@@ -39,19 +39,19 @@ class LocalHttpInterceptor<Schema extends HttpSchema> implements PublicLocalHttp
39
39
  this.client.baseURL = new URL(baseURL);
40
40
  }
41
41
 
42
- get saveRequests() {
43
- return this.client.saveRequests;
42
+ get requestSaving() {
43
+ return this.client.requestSaving;
44
44
  }
45
45
 
46
- set saveRequests(saveRequests: NonNullable<LocalHttpInterceptorOptions['saveRequests']>) {
47
- this.client.saveRequests = saveRequests;
46
+ set requestSaving(requestSaving: HttpInterceptorRequestSaving) {
47
+ this.client.requestSaving = requestSaving;
48
48
  }
49
49
 
50
50
  get onUnhandledRequest() {
51
51
  return this.client.onUnhandledRequest;
52
52
  }
53
53
 
54
- set onUnhandledRequest(onUnhandledRequest: LocalHttpInterceptorOptions['onUnhandledRequest']) {
54
+ set onUnhandledRequest(onUnhandledRequest: UnhandledRequestStrategy.Local | undefined) {
55
55
  this.client.onUnhandledRequest = onUnhandledRequest;
56
56
  }
57
57
 
@@ -4,8 +4,8 @@ import RemoteHttpRequestHandler from '../requestHandler/RemoteHttpRequestHandler
4
4
  import HttpInterceptorClient from './HttpInterceptorClient';
5
5
  import HttpInterceptorStore from './HttpInterceptorStore';
6
6
  import { AsyncHttpInterceptorMethodHandler } from './types/handlers';
7
- import { RemoteHttpInterceptorOptions } from './types/options';
8
- import { RemoteHttpInterceptor as PublicRemoteHttpInterceptor } from './types/public';
7
+ import { RemoteHttpInterceptorOptions, UnhandledRequestStrategy } from './types/options';
8
+ import { HttpInterceptorRequestSaving, RemoteHttpInterceptor as PublicRemoteHttpInterceptor } from './types/public';
9
9
 
10
10
  class RemoteHttpInterceptor<Schema extends HttpSchema> implements PublicRemoteHttpInterceptor<Schema> {
11
11
  private store = new HttpInterceptorStore();
@@ -24,7 +24,7 @@ class RemoteHttpInterceptor<Schema extends HttpSchema> implements PublicRemoteHt
24
24
  baseURL,
25
25
  Handler: RemoteHttpRequestHandler,
26
26
  onUnhandledRequest: options.onUnhandledRequest,
27
- saveRequests: options.saveRequests,
27
+ requestSaving: options.requestSaving,
28
28
  });
29
29
  }
30
30
 
@@ -40,19 +40,19 @@ class RemoteHttpInterceptor<Schema extends HttpSchema> implements PublicRemoteHt
40
40
  this.client.baseURL = new URL(baseURL);
41
41
  }
42
42
 
43
- get saveRequests() {
44
- return this.client.saveRequests;
43
+ get requestSaving() {
44
+ return this.client.requestSaving;
45
45
  }
46
46
 
47
- set saveRequests(saveRequests: NonNullable<RemoteHttpInterceptorOptions['saveRequests']>) {
48
- this.client.saveRequests = saveRequests;
47
+ set requestSaving(requestSaving: HttpInterceptorRequestSaving) {
48
+ this.client.requestSaving = requestSaving;
49
49
  }
50
50
 
51
51
  get onUnhandledRequest() {
52
52
  return this.client.onUnhandledRequest;
53
53
  }
54
54
 
55
- set onUnhandledRequest(onUnhandledRequest: RemoteHttpInterceptorOptions['onUnhandledRequest']) {
55
+ set onUnhandledRequest(onUnhandledRequest: UnhandledRequestStrategy.Remote | undefined) {
56
56
  this.client.onUnhandledRequest = onUnhandledRequest;
57
57
  }
58
58
 
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Error thrown when the safe limit of saved intercepted requests is exceeded.
3
+ *
4
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#saving-requests Saving intercepted requests}
5
+ */
6
+ class RequestSavingSafeLimitExceededError extends TypeError {
7
+ constructor(numberOfSavedRequests: number, safeLimit: number) {
8
+ super(
9
+ `The number of intercepted requests saved in memory (${numberOfSavedRequests}) exceeded the safe limit of ` +
10
+ `${safeLimit}. Did you forget to call \`interceptor.clear()\`?\n\n` +
11
+ 'If you need to save requests, make sure to regularly call `interceptor.clear()`. Alternatively, you can ' +
12
+ 'hide this warning by increasing `requestSaving.safeLimit` in your interceptor. Note that saving too many ' +
13
+ 'requests in memory can lead to performance issues.\n\n' +
14
+ 'If you do not need to save requests, consider setting `requestSaving.enabled: false` in your ' +
15
+ 'interceptor.\n\n' +
16
+ 'Learn more: https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#saving-requests',
17
+ );
18
+ this.name = 'RequestSavingSafeLimitExceededError';
19
+ }
20
+ }
21
+
22
+ export default RequestSavingSafeLimitExceededError;
@@ -24,7 +24,7 @@ function isRemoteHttpInterceptorOptions(options: HttpInterceptorOptions) {
24
24
  * @returns The created HTTP interceptor.
25
25
  * @throws {InvalidURLError} If the base URL is invalid.
26
26
  * @throws {UnsupportedURLProtocolError} If the base URL protocol is not either `http` or `https`.
27
- * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httpinterceptorcreateoptions `httpInterceptor.create(options)` API reference}
27
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#createhttpinterceptoroptions `createHttpInterceptor(options)` API reference}
28
28
  */
29
29
  export function createHttpInterceptor<Schema extends HttpSchema>(
30
30
  options: LocalHttpInterceptorOptions,
@@ -1,5 +1,6 @@
1
1
  import { PossiblePromise } from '@zimic/utils/types';
2
2
 
3
+ import { HttpInterceptorRequestSaving } from './public';
3
4
  import { UnhandledHttpInterceptorRequest } from './requests';
4
5
 
5
6
  /**
@@ -119,20 +120,12 @@ export interface SharedHttpInterceptorOptions {
119
120
  baseURL: string;
120
121
 
121
122
  /**
122
- * Whether {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httprequesthandler request handlers}
123
- * should save their intercepted requests in memory and make them accessible through
124
- * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-handlerrequests `handler.requests`}.
123
+ * Configures if the intercepted requests are saved and how they are handled.
125
124
  *
126
- * **Important**: If `saveRequests` is true, make sure to regularly clear the interceptor to avoid that the requests
127
- * accumulate in memory. A common practice is to call
128
- * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-interceptorclear `interceptor.clear()`}
129
- * after each test.
130
- *
131
- * @default false
132
125
  * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#saving-requests Saving intercepted requests}
133
126
  * @see {@link https://github.com/zimicjs/zimic/wiki/guides‐testing‐interceptor Testing}
134
127
  */
135
- saveRequests?: boolean;
128
+ requestSaving?: Partial<HttpInterceptorRequestSaving>;
136
129
  }
137
130
 
138
131
  /**
@@ -177,6 +170,6 @@ export interface RemoteHttpInterceptorOptions extends SharedHttpInterceptorOptio
177
170
  * The options to create an
178
171
  * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httpinterceptor HTTP interceptor}.
179
172
  *
180
- * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httpinterceptorcreateoptions `httpInterceptor.create(options)` API reference}
173
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#createhttpinterceptoroptions `createHttpInterceptor(options)` API reference}
181
174
  */
182
175
  export type HttpInterceptorOptions = LocalHttpInterceptorOptions | RemoteHttpInterceptorOptions;
@@ -3,6 +3,45 @@ import { HttpSchema } from '@zimic/http';
3
3
  import { SyncHttpInterceptorMethodHandler, AsyncHttpInterceptorMethodHandler } from './handlers';
4
4
  import { HttpInterceptorPlatform, UnhandledRequestStrategy } from './options';
5
5
 
6
+ /**
7
+ * Configures if the intercepted requests are saved and how they are handled.
8
+ *
9
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#saving-requests Saving intercepted requests}
10
+ * @see {@link https://github.com/zimicjs/zimic/wiki/guides‐testing‐interceptor Testing}
11
+ */
12
+ export interface HttpInterceptorRequestSaving {
13
+ /**
14
+ * Whether {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httprequesthandler request handlers}
15
+ * should save their intercepted requests in memory and make them accessible through
16
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-handlerrequests `handler.requests`}.
17
+ *
18
+ * If you are using
19
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-interceptorchecktimes `interceptor.checkTimes()`}
20
+ * or
21
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-handlerchecktimes `handler.checkTimes()`}
22
+ * during tests, consider enabling this option to get more detailed information in `TimesCheckError` errors.
23
+ *
24
+ * **Important**: If `requestSaving.enabled` is `true`, make sure to regularly clear the interceptor to avoid requests
25
+ * accumulating in memory. A common practice is to call
26
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-interceptorclear `interceptor.clear()`}
27
+ * after each test.
28
+ *
29
+ * @default process.env.NODE_ENV === 'test'
30
+ */
31
+ enabled: boolean;
32
+
33
+ /**
34
+ * The safe number of requests to save in memory before logging warnings in the console. If `requestSaving.enabled` is
35
+ * `true` and the interceptor is not regularly cleared with
36
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-interceptorclear `interceptor.clear()`},
37
+ * the requests may accumulate in memory and cause performance issues. This option does not limit the number of
38
+ * requests saved in memory, only when to log warnings.
39
+ *
40
+ * @default 1000
41
+ */
42
+ safeLimit: number;
43
+ }
44
+
6
45
  /**
7
46
  * An interceptor to handle HTTP requests and return mock responses. The methods, paths, status codes, parameters, and
8
47
  * responses are statically-typed based on the provided service schema.
@@ -20,20 +59,12 @@ export interface HttpInterceptor<_Schema extends HttpSchema> {
20
59
  baseURL: string;
21
60
 
22
61
  /**
23
- * Whether {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httprequesthandler request handlers}
24
- * should save their intercepted requests in memory and make them accessible through
25
- * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-handlerrequests `handler.requests`}.
26
- *
27
- * **Important**: If `saveRequests` is true, make sure to regularly clear the interceptor to avoid that the requests
28
- * accumulate in memory. A common practice is to call
29
- * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-interceptorclear `interceptor.clear()`}
30
- * after each test.
62
+ * Configures if the intercepted requests are saved and how they are handled.
31
63
  *
32
- * @default process.env.NODE_ENV === 'test'
33
64
  * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#saving-requests Saving intercepted requests}
34
65
  * @see {@link https://github.com/zimicjs/zimic/wiki/guides‐testing‐interceptor Testing}
35
66
  */
36
- saveRequests: boolean;
67
+ requestSaving: HttpInterceptorRequestSaving;
37
68
 
38
69
  /**
39
70
  * The platform the interceptor is running on.
@@ -86,8 +117,9 @@ export interface HttpInterceptor<_Schema extends HttpSchema> {
86
117
  * of each test.
87
118
  *
88
119
  * When
89
- * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httpinterceptorcreateoptions `saveRequests: true`}
90
- * is enabled in your interceptor, the `TimesCheckError` errors will also list each unmatched request with diff of the
120
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#saving-requests
121
+ * `requestSaving.enabled`} is
122
+ * `true` in your interceptor, the `TimesCheckError` errors will also list each unmatched request with diff of the
91
123
  * expected and received data. This is useful for debugging requests that did not match a handler with
92
124
  * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#http-handlerwithrestriction restrictions}.
93
125
  *
@@ -5,9 +5,9 @@ import { LocalHttpInterceptor, RemoteHttpInterceptor } from './public';
5
5
  * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#httpinterceptor `HttpInterceptor`}.
6
6
  *
7
7
  * @example
8
- * import { httpInterceptor, type InferHttpInterceptorSchema } from '@zimic/http';
8
+ * import { type InferHttpInterceptorSchema } from '@zimic/http';
9
9
  *
10
- * const interceptor = httpInterceptor.create<{
10
+ * const interceptor = createHttpInterceptor<{
11
11
  * '/users': {
12
12
  * GET: {
13
13
  * response: { 200: { body: User[] } };