@zimic/interceptor 0.17.0-canary.2 → 0.17.0-canary.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TYHJPU5G.js → chunk-MXHLBRPB.js} +521 -61
- package/dist/chunk-MXHLBRPB.js.map +1 -0
- package/dist/{chunk-3SKHNQLL.mjs → chunk-OGL76CKO.mjs} +510 -60
- package/dist/chunk-OGL76CKO.mjs.map +1 -0
- package/dist/cli.js +141 -17
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +137 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/http.d.ts +23 -2
- package/dist/http.js +473 -270
- package/dist/http.js.map +1 -1
- package/dist/http.mjs +473 -270
- package/dist/http.mjs.map +1 -1
- package/dist/scripts/postinstall.js +6 -6
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/postinstall.mjs +5 -5
- package/dist/scripts/postinstall.mjs.map +1 -1
- package/dist/server.d.ts +16 -0
- package/dist/server.js +6 -6
- package/dist/server.mjs +1 -1
- package/package.json +12 -11
- package/src/cli/browser/init.ts +5 -6
- package/src/cli/cli.ts +140 -55
- package/src/cli/server/start.ts +22 -7
- package/src/cli/server/token/create.ts +33 -0
- package/src/cli/server/token/list.ts +23 -0
- package/src/cli/server/token/remove.ts +22 -0
- package/src/http/interceptor/HttpInterceptorClient.ts +49 -27
- package/src/http/interceptor/HttpInterceptorStore.ts +25 -9
- package/src/http/interceptor/LocalHttpInterceptor.ts +6 -3
- package/src/http/interceptor/RemoteHttpInterceptor.ts +41 -5
- package/src/http/interceptor/errors/RunningHttpInterceptorError.ts +1 -1
- package/src/http/interceptor/types/options.ts +15 -0
- package/src/http/interceptor/types/public.ts +11 -3
- package/src/http/interceptorWorker/HttpInterceptorWorker.ts +14 -16
- package/src/http/interceptorWorker/RemoteHttpInterceptorWorker.ts +17 -12
- package/src/http/interceptorWorker/types/options.ts +1 -0
- package/src/http/requestHandler/errors/TimesCheckError.ts +1 -1
- package/src/server/InterceptorServer.ts +52 -8
- package/src/server/constants.ts +1 -1
- package/src/server/errors/InvalidInterceptorTokenError.ts +13 -0
- package/src/server/errors/InvalidInterceptorTokenFileError.ts +13 -0
- package/src/server/errors/InvalidInterceptorTokenValueError.ts +13 -0
- package/src/server/types/options.ts +9 -0
- package/src/server/types/public.ts +9 -0
- package/src/server/types/schema.ts +4 -4
- package/src/server/utils/auth.ts +304 -0
- package/src/server/utils/fetch.ts +3 -1
- package/src/utils/data.ts +13 -0
- package/src/utils/files.ts +14 -0
- package/src/utils/{console.ts → logging.ts} +5 -7
- package/src/utils/webSocket.ts +57 -11
- package/src/webSocket/WebSocketClient.ts +11 -5
- package/src/webSocket/WebSocketHandler.ts +72 -51
- package/src/webSocket/WebSocketServer.ts +25 -4
- package/src/webSocket/constants.ts +2 -0
- package/src/webSocket/errors/UnauthorizedWebSocketConnectionError.ts +11 -0
- package/src/webSocket/types.ts +49 -52
- package/dist/chunk-3SKHNQLL.mjs.map +0 -1
- package/dist/chunk-TYHJPU5G.js.map +0 -1
|
@@ -16,7 +16,6 @@ import validateURLProtocol from '@zimic/utils/url/validateURLProtocol';
|
|
|
16
16
|
import { isServerSide } from '@/utils/environment';
|
|
17
17
|
|
|
18
18
|
import HttpInterceptorWorker from '../interceptorWorker/HttpInterceptorWorker';
|
|
19
|
-
import LocalHttpInterceptorWorker from '../interceptorWorker/LocalHttpInterceptorWorker';
|
|
20
19
|
import HttpRequestHandlerClient, { AnyHttpRequestHandlerClient } from '../requestHandler/HttpRequestHandlerClient';
|
|
21
20
|
import LocalHttpRequestHandler from '../requestHandler/LocalHttpRequestHandler';
|
|
22
21
|
import RemoteHttpRequestHandler from '../requestHandler/RemoteHttpRequestHandler';
|
|
@@ -38,11 +37,13 @@ class HttpInterceptorClient<
|
|
|
38
37
|
Schema extends HttpSchema,
|
|
39
38
|
HandlerConstructor extends HttpRequestHandlerConstructor = HttpRequestHandlerConstructor,
|
|
40
39
|
> {
|
|
41
|
-
private worker: HttpInterceptorWorker;
|
|
42
40
|
private store: HttpInterceptorStore;
|
|
43
|
-
|
|
44
41
|
private _baseURL!: URL;
|
|
45
42
|
|
|
43
|
+
private createWorker: () => HttpInterceptorWorker;
|
|
44
|
+
private deleteWorker: () => void;
|
|
45
|
+
private worker?: HttpInterceptorWorker;
|
|
46
|
+
|
|
46
47
|
requestSaving: HttpInterceptorRequestSaving;
|
|
47
48
|
private numberOfSavedRequests = 0;
|
|
48
49
|
|
|
@@ -67,18 +68,20 @@ class HttpInterceptorClient<
|
|
|
67
68
|
};
|
|
68
69
|
|
|
69
70
|
constructor(options: {
|
|
70
|
-
worker: HttpInterceptorWorker;
|
|
71
71
|
store: HttpInterceptorStore;
|
|
72
72
|
baseURL: URL;
|
|
73
|
+
createWorker: () => HttpInterceptorWorker;
|
|
74
|
+
deleteWorker: () => void;
|
|
73
75
|
requestSaving?: Partial<HttpInterceptorRequestSaving>;
|
|
74
76
|
onUnhandledRequest?: UnhandledRequestStrategy;
|
|
75
77
|
Handler: HandlerConstructor;
|
|
76
78
|
}) {
|
|
77
|
-
this.worker = options.worker;
|
|
78
79
|
this.store = options.store;
|
|
79
|
-
|
|
80
80
|
this.baseURL = options.baseURL;
|
|
81
81
|
|
|
82
|
+
this.createWorker = options.createWorker;
|
|
83
|
+
this.deleteWorker = options.deleteWorker;
|
|
84
|
+
|
|
82
85
|
this.requestSaving = {
|
|
83
86
|
enabled: options.requestSaving?.enabled ?? this.getDefaultRequestSavingEnabled(),
|
|
84
87
|
safeLimit: options.requestSaving?.safeLimit ?? DEFAULT_REQUEST_SAVING_SAFE_LIMIT,
|
|
@@ -108,6 +111,7 @@ class HttpInterceptorClient<
|
|
|
108
111
|
|
|
109
112
|
validateURLProtocol(newBaseURL, SUPPORTED_BASE_URL_PROTOCOLS);
|
|
110
113
|
excludeURLParams(newBaseURL);
|
|
114
|
+
|
|
111
115
|
this._baseURL = newBaseURL;
|
|
112
116
|
}
|
|
113
117
|
|
|
@@ -118,29 +122,48 @@ class HttpInterceptorClient<
|
|
|
118
122
|
return this.baseURL.href;
|
|
119
123
|
}
|
|
120
124
|
|
|
125
|
+
private get workerOrThrow() {
|
|
126
|
+
if (!this.worker) {
|
|
127
|
+
throw new NotRunningHttpInterceptorError();
|
|
128
|
+
}
|
|
129
|
+
return this.worker;
|
|
130
|
+
}
|
|
131
|
+
|
|
121
132
|
get platform() {
|
|
122
|
-
return this.worker
|
|
133
|
+
return this.worker?.platform ?? null;
|
|
123
134
|
}
|
|
124
135
|
|
|
125
136
|
async start() {
|
|
126
|
-
|
|
137
|
+
try {
|
|
138
|
+
this.worker = this.createWorker();
|
|
127
139
|
|
|
128
|
-
|
|
129
|
-
|
|
140
|
+
await this.worker.start();
|
|
141
|
+
this.worker.registerRunningInterceptor(this);
|
|
142
|
+
|
|
143
|
+
this.markAsRunning(true);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
await this.stop();
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
130
148
|
}
|
|
131
149
|
|
|
132
150
|
async stop() {
|
|
133
|
-
this.
|
|
134
|
-
this.worker.unregisterRunningInterceptor(this);
|
|
151
|
+
this.worker?.unregisterRunningInterceptor(this);
|
|
135
152
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
153
|
+
// The number of interceptors will be 0 if the first client could not start due to an error.
|
|
154
|
+
const isLastRunningInterceptor = this.numberOfRunningInterceptors === 0 || this.numberOfRunningInterceptors === 1;
|
|
155
|
+
|
|
156
|
+
if (isLastRunningInterceptor) {
|
|
157
|
+
await this.worker?.stop();
|
|
158
|
+
this.deleteWorker();
|
|
139
159
|
}
|
|
160
|
+
|
|
161
|
+
this.markAsRunning(false);
|
|
162
|
+
this.worker = undefined;
|
|
140
163
|
}
|
|
141
164
|
|
|
142
165
|
private markAsRunning(isRunning: boolean) {
|
|
143
|
-
if (this.
|
|
166
|
+
if (this.workerOrThrow.type === 'local') {
|
|
144
167
|
this.store.markLocalInterceptorAsRunning(this, isRunning);
|
|
145
168
|
} else {
|
|
146
169
|
this.store.markRemoteInterceptorAsRunning(this, isRunning, this.baseURL);
|
|
@@ -148,8 +171,12 @@ class HttpInterceptorClient<
|
|
|
148
171
|
this.isRunning = isRunning;
|
|
149
172
|
}
|
|
150
173
|
|
|
151
|
-
|
|
152
|
-
if (this.
|
|
174
|
+
get numberOfRunningInterceptors() {
|
|
175
|
+
if (!this.isRunning) {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (this.workerOrThrow.type === 'local') {
|
|
153
180
|
return this.store.numberOfRunningLocalInterceptors;
|
|
154
181
|
} else {
|
|
155
182
|
return this.store.numberOfRunningRemoteInterceptors(this.baseURL);
|
|
@@ -222,7 +249,7 @@ class HttpInterceptorClient<
|
|
|
222
249
|
const url = joinURL(this.baseURLAsString, handler.path);
|
|
223
250
|
const urlRegex = createRegExpFromURL(url);
|
|
224
251
|
|
|
225
|
-
const registrationResult = this.
|
|
252
|
+
const registrationResult = this.workerOrThrow.use(this, handler.method, url, async (context) => {
|
|
226
253
|
const response = await this.handleInterceptedRequest(
|
|
227
254
|
urlRegex,
|
|
228
255
|
handler.method,
|
|
@@ -316,11 +343,9 @@ class HttpInterceptorClient<
|
|
|
316
343
|
}
|
|
317
344
|
|
|
318
345
|
clear(options: { onCommitSuccess?: () => void; onCommitError?: () => void } = {}) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const clearResults: PossiblePromise<AnyHttpRequestHandlerClient | void>[] = [];
|
|
346
|
+
const clearResults: PossiblePromise<AnyHttpRequestHandlerClient | void>[] = [
|
|
347
|
+
this.workerOrThrow.clearInterceptorHandlers(this),
|
|
348
|
+
];
|
|
324
349
|
|
|
325
350
|
for (const method of HTTP_METHODS) {
|
|
326
351
|
const newClearResults = this.clearMethodHandlers(method);
|
|
@@ -333,9 +358,6 @@ class HttpInterceptorClient<
|
|
|
333
358
|
handlersByPath.clear();
|
|
334
359
|
}
|
|
335
360
|
|
|
336
|
-
const clearResult = this.worker.clearInterceptorHandlers(this);
|
|
337
|
-
clearResults.push(clearResult);
|
|
338
|
-
|
|
339
361
|
if (options.onCommitSuccess) {
|
|
340
362
|
void Promise.all(clearResults).then(options.onCommitSuccess, options.onCommitError);
|
|
341
363
|
}
|
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
} from '../interceptorWorker/types/options';
|
|
8
8
|
import { AnyHttpInterceptorClient } from './HttpInterceptorClient';
|
|
9
9
|
|
|
10
|
+
interface RemoteWorkerKeyOptions {
|
|
11
|
+
auth: RemoteHttpInterceptorWorkerOptions['auth'];
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
class HttpInterceptorStore {
|
|
11
15
|
private static _localWorker?: LocalHttpInterceptorWorker;
|
|
12
16
|
private static runningLocalInterceptors = new Set<AnyHttpInterceptorClient>();
|
|
@@ -20,8 +24,16 @@ class HttpInterceptorStore {
|
|
|
20
24
|
return this.class._localWorker;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
private getRemoteWorkerKey(baseURL: URL, options: RemoteWorkerKeyOptions) {
|
|
28
|
+
if (!options.auth) {
|
|
29
|
+
return baseURL.origin;
|
|
30
|
+
}
|
|
31
|
+
return `${baseURL.origin}:${options.auth.token}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
remoteWorker(baseURL: URL, options: RemoteWorkerKeyOptions) {
|
|
35
|
+
const remoteWorkerKey = this.getRemoteWorkerKey(baseURL, options);
|
|
36
|
+
return this.class.remoteWorkers.get(remoteWorkerKey);
|
|
25
37
|
}
|
|
26
38
|
|
|
27
39
|
get numberOfRunningLocalInterceptors() {
|
|
@@ -70,23 +82,27 @@ class HttpInterceptorStore {
|
|
|
70
82
|
return createdWorker;
|
|
71
83
|
}
|
|
72
84
|
|
|
85
|
+
deleteLocalWorker() {
|
|
86
|
+
this.class._localWorker = undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
73
89
|
getOrCreateRemoteWorker(workerOptions: Omit<RemoteHttpInterceptorWorkerOptions, 'type'>) {
|
|
74
|
-
const
|
|
90
|
+
const remoteWorkerKey = this.getRemoteWorkerKey(workerOptions.serverURL, { auth: workerOptions.auth });
|
|
91
|
+
const existingWorker = this.class.remoteWorkers.get(remoteWorkerKey);
|
|
92
|
+
|
|
75
93
|
if (existingWorker) {
|
|
76
94
|
return existingWorker;
|
|
77
95
|
}
|
|
78
96
|
|
|
79
97
|
const createdWorker = createHttpInterceptorWorker({ ...workerOptions, type: 'remote' });
|
|
80
|
-
this.class.remoteWorkers.set(
|
|
98
|
+
this.class.remoteWorkers.set(remoteWorkerKey, createdWorker);
|
|
81
99
|
|
|
82
100
|
return createdWorker;
|
|
83
101
|
}
|
|
84
102
|
|
|
85
|
-
|
|
86
|
-
this.
|
|
87
|
-
this.class.
|
|
88
|
-
this.class.remoteWorkers.clear();
|
|
89
|
-
this.class.runningRemoteInterceptors.clear();
|
|
103
|
+
deleteRemoteWorker(baseURL: URL, options: RemoteWorkerKeyOptions) {
|
|
104
|
+
const remoteWorkerKey = this.getRemoteWorkerKey(baseURL, options);
|
|
105
|
+
this.class.remoteWorkers.delete(remoteWorkerKey);
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
108
|
|
|
@@ -15,12 +15,15 @@ class LocalHttpInterceptor<Schema extends HttpSchema> implements PublicLocalHttp
|
|
|
15
15
|
constructor(options: LocalHttpInterceptorOptions) {
|
|
16
16
|
const baseURL = new URL(options.baseURL);
|
|
17
17
|
|
|
18
|
-
const worker = this.store.getOrCreateLocalWorker({});
|
|
19
|
-
|
|
20
18
|
this.client = new HttpInterceptorClient<Schema, typeof LocalHttpRequestHandler>({
|
|
21
|
-
worker,
|
|
22
19
|
store: this.store,
|
|
23
20
|
baseURL,
|
|
21
|
+
createWorker: () => {
|
|
22
|
+
return this.store.getOrCreateLocalWorker({});
|
|
23
|
+
},
|
|
24
|
+
deleteWorker: () => {
|
|
25
|
+
this.store.deleteLocalWorker();
|
|
26
|
+
},
|
|
24
27
|
Handler: LocalHttpRequestHandler,
|
|
25
28
|
onUnhandledRequest: options.onUnhandledRequest,
|
|
26
29
|
requestSaving: options.requestSaving,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';
|
|
2
2
|
|
|
3
3
|
import RemoteHttpRequestHandler from '../requestHandler/RemoteHttpRequestHandler';
|
|
4
|
+
import RunningHttpInterceptorError from './errors/RunningHttpInterceptorError';
|
|
4
5
|
import HttpInterceptorClient from './HttpInterceptorClient';
|
|
5
6
|
import HttpInterceptorStore from './HttpInterceptorStore';
|
|
6
7
|
import { AsyncHttpInterceptorMethodHandler } from './types/handlers';
|
|
@@ -9,19 +10,27 @@ import { HttpInterceptorRequestSaving, RemoteHttpInterceptor as PublicRemoteHttp
|
|
|
9
10
|
|
|
10
11
|
class RemoteHttpInterceptor<Schema extends HttpSchema> implements PublicRemoteHttpInterceptor<Schema> {
|
|
11
12
|
private store = new HttpInterceptorStore();
|
|
12
|
-
|
|
13
13
|
client: HttpInterceptorClient<Schema, typeof RemoteHttpRequestHandler>;
|
|
14
14
|
|
|
15
|
+
private _auth?: RemoteHttpInterceptorOptions['auth'];
|
|
16
|
+
|
|
15
17
|
constructor(options: RemoteHttpInterceptorOptions) {
|
|
16
|
-
|
|
18
|
+
this._auth = options.auth;
|
|
17
19
|
|
|
18
|
-
const
|
|
19
|
-
const worker = this.store.getOrCreateRemoteWorker({ serverURL });
|
|
20
|
+
const baseURL = new URL(options.baseURL);
|
|
20
21
|
|
|
21
22
|
this.client = new HttpInterceptorClient<Schema, typeof RemoteHttpRequestHandler>({
|
|
22
|
-
worker,
|
|
23
23
|
store: this.store,
|
|
24
24
|
baseURL,
|
|
25
|
+
createWorker: () => {
|
|
26
|
+
return this.store.getOrCreateRemoteWorker({
|
|
27
|
+
serverURL: new URL(baseURL.origin),
|
|
28
|
+
auth: this._auth,
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
deleteWorker: () => {
|
|
32
|
+
this.store.deleteRemoteWorker(baseURL, { auth: options.auth });
|
|
33
|
+
},
|
|
25
34
|
Handler: RemoteHttpRequestHandler,
|
|
26
35
|
onUnhandledRequest: options.onUnhandledRequest,
|
|
27
36
|
requestSaving: options.requestSaving,
|
|
@@ -48,6 +57,33 @@ class RemoteHttpInterceptor<Schema extends HttpSchema> implements PublicRemoteHt
|
|
|
48
57
|
this.client.requestSaving = requestSaving;
|
|
49
58
|
}
|
|
50
59
|
|
|
60
|
+
get auth() {
|
|
61
|
+
return this._auth;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
set auth(auth: RemoteHttpInterceptorOptions['auth'] | undefined) {
|
|
65
|
+
const cannotChangeAuthWhileRunningMessage =
|
|
66
|
+
'Did you forget to call `await interceptor.stop()` before changing the authentication parameters?';
|
|
67
|
+
|
|
68
|
+
if (this.isRunning) {
|
|
69
|
+
throw new RunningHttpInterceptorError(cannotChangeAuthWhileRunningMessage);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!auth) {
|
|
73
|
+
this._auth = undefined;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this._auth = new Proxy(auth, {
|
|
78
|
+
set: (target, property, value) => {
|
|
79
|
+
if (this.isRunning) {
|
|
80
|
+
throw new RunningHttpInterceptorError(cannotChangeAuthWhileRunningMessage);
|
|
81
|
+
}
|
|
82
|
+
return Reflect.set(target, property, value);
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
51
87
|
get onUnhandledRequest() {
|
|
52
88
|
return this.client.onUnhandledRequest;
|
|
53
89
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
class RunningHttpInterceptorError extends Error {
|
|
9
9
|
constructor(additionalMessage: string) {
|
|
10
|
-
super(`The interceptor is running
|
|
10
|
+
super(`The interceptor is running. ${additionalMessage}`);
|
|
11
11
|
this.name = 'RunningHttpInterceptorError';
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -160,6 +160,21 @@ export interface LocalHttpInterceptorOptions extends SharedHttpInterceptorOption
|
|
|
160
160
|
export interface RemoteHttpInterceptorOptions extends SharedHttpInterceptorOptions {
|
|
161
161
|
type: 'remote';
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Options to authenticate the interceptor when connecting to an interceptor server. This is required if the
|
|
165
|
+
* interceptor server was started with the `--tokens-dir` option.
|
|
166
|
+
*
|
|
167
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐interceptor‐server#authentication Interceptor server authentication}
|
|
168
|
+
*/
|
|
169
|
+
auth?: {
|
|
170
|
+
/**
|
|
171
|
+
* The authentication token to use.
|
|
172
|
+
*
|
|
173
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐interceptor‐server#authentication Interceptor server authentication}
|
|
174
|
+
*/
|
|
175
|
+
token: string;
|
|
176
|
+
};
|
|
177
|
+
|
|
163
178
|
/**
|
|
164
179
|
* The strategy to use for unhandled requests. If a request starts with the base URL of the interceptor, but no
|
|
165
180
|
* matching handler exists, this strategy will be used. If a function is provided, it will be called with the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HttpSchema } from '@zimic/http';
|
|
2
2
|
|
|
3
3
|
import { SyncHttpInterceptorMethodHandler, AsyncHttpInterceptorMethodHandler } from './handlers';
|
|
4
|
-
import { HttpInterceptorPlatform, UnhandledRequestStrategy } from './options';
|
|
4
|
+
import { HttpInterceptorPlatform, RemoteHttpInterceptorOptions, UnhandledRequestStrategy } from './options';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Configures if the intercepted requests are saved and how they are handled.
|
|
@@ -163,7 +163,7 @@ export interface LocalHttpInterceptor<Schema extends HttpSchema> extends HttpInt
|
|
|
163
163
|
*
|
|
164
164
|
* @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#unhandled-requests Unhandled requests}
|
|
165
165
|
*/
|
|
166
|
-
onUnhandledRequest
|
|
166
|
+
onUnhandledRequest?: UnhandledRequestStrategy.Local;
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
169
|
* Creates a GET
|
|
@@ -367,6 +367,14 @@ export interface RemoteHttpInterceptor<Schema extends HttpSchema> extends HttpIn
|
|
|
367
367
|
/** @readonly */
|
|
368
368
|
get type(): 'remote';
|
|
369
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Options to authenticate the interceptor when connecting to an interceptor server. This is required if the
|
|
372
|
+
* interceptor server was started with the `--tokens-dir` option.
|
|
373
|
+
*
|
|
374
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐interceptor‐server#authentication Interceptor server authentication}
|
|
375
|
+
*/
|
|
376
|
+
auth?: RemoteHttpInterceptorOptions['auth'];
|
|
377
|
+
|
|
370
378
|
/**
|
|
371
379
|
* The strategy to use for unhandled requests. If a request starts with the base URL of the interceptor, but no
|
|
372
380
|
* matching handler exists, this strategy will be used. If a function is provided, it will be called with the
|
|
@@ -374,7 +382,7 @@ export interface RemoteHttpInterceptor<Schema extends HttpSchema> extends HttpIn
|
|
|
374
382
|
*
|
|
375
383
|
* @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#unhandled-requests Unhandled requests}
|
|
376
384
|
*/
|
|
377
|
-
onUnhandledRequest
|
|
385
|
+
onUnhandledRequest?: UnhandledRequestStrategy.Remote;
|
|
378
386
|
|
|
379
387
|
/**
|
|
380
388
|
* Creates a GET
|
|
@@ -16,9 +16,9 @@ import { Default, PossiblePromise } from '@zimic/utils/types';
|
|
|
16
16
|
import color from 'picocolors';
|
|
17
17
|
|
|
18
18
|
import { removeArrayElement } from '@/utils/arrays';
|
|
19
|
-
import { formatValueToLog, logWithPrefix } from '@/utils/console';
|
|
20
19
|
import { isClientSide } from '@/utils/environment';
|
|
21
20
|
import { methodCanHaveResponseBody } from '@/utils/http';
|
|
21
|
+
import { formatValueToLog, logger } from '@/utils/logging';
|
|
22
22
|
|
|
23
23
|
import HttpInterceptorClient, { AnyHttpInterceptorClient } from '../interceptor/HttpInterceptorClient';
|
|
24
24
|
import { HttpInterceptorPlatform, HttpInterceptorType, UnhandledRequestStrategy } from '../interceptor/types/options';
|
|
@@ -35,10 +35,11 @@ import {
|
|
|
35
35
|
import { DEFAULT_UNHANDLED_REQUEST_STRATEGY } from './constants';
|
|
36
36
|
import InvalidFormDataError from './errors/InvalidFormDataError';
|
|
37
37
|
import InvalidJSONError from './errors/InvalidJSONError';
|
|
38
|
+
import { HttpInterceptorWorkerType } from './types/options';
|
|
38
39
|
import { HttpResponseFactory } from './types/requests';
|
|
39
40
|
|
|
40
41
|
abstract class HttpInterceptorWorker {
|
|
41
|
-
abstract
|
|
42
|
+
abstract get type(): HttpInterceptorWorkerType;
|
|
42
43
|
|
|
43
44
|
platform: HttpInterceptorPlatform | null = null;
|
|
44
45
|
isRunning = false;
|
|
@@ -474,20 +475,17 @@ abstract class HttpInterceptorWorker {
|
|
|
474
475
|
formatValueToLog(request.body),
|
|
475
476
|
]);
|
|
476
477
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
`${action === 'bypass' ? '
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
'\n\nLearn more: https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#unhandled-requests',
|
|
489
|
-
],
|
|
490
|
-
{ method: action === 'bypass' ? 'warn' : 'error' },
|
|
478
|
+
logger[action === 'bypass' ? 'warn' : 'error'](
|
|
479
|
+
`${action === 'bypass' ? 'Warning:' : 'Error:'} Request was not handled and was ` +
|
|
480
|
+
`${action === 'bypass' ? color.yellow('bypassed') : color.red('rejected')}.\n\n `,
|
|
481
|
+
`${request.method} ${request.url}`,
|
|
482
|
+
'\n Headers:',
|
|
483
|
+
formattedHeaders,
|
|
484
|
+
'\n Search params:',
|
|
485
|
+
formattedSearchParams,
|
|
486
|
+
'\n Body:',
|
|
487
|
+
formattedBody,
|
|
488
|
+
'\n\nLearn more: https://github.com/zimicjs/zimic/wiki/api‐zimic‐interceptor‐http#unhandled-requests',
|
|
491
489
|
);
|
|
492
490
|
}
|
|
493
491
|
}
|
|
@@ -6,7 +6,7 @@ import { HttpHandlerCommit, InterceptorServerWebSocketSchema } from '@/server/ty
|
|
|
6
6
|
import { importCrypto } from '@/utils/crypto';
|
|
7
7
|
import { isClientSide, isServerSide } from '@/utils/environment';
|
|
8
8
|
import { deserializeRequest, serializeResponse } from '@/utils/fetch';
|
|
9
|
-
import {
|
|
9
|
+
import { WebSocketEventMessage } from '@/webSocket/types';
|
|
10
10
|
import WebSocketClient from '@/webSocket/WebSocketClient';
|
|
11
11
|
|
|
12
12
|
import NotRunningHttpInterceptorError from '../interceptor/errors/NotRunningHttpInterceptorError';
|
|
@@ -26,24 +26,26 @@ interface HttpHandler {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
29
|
-
webSocketClient: WebSocketClient<InterceptorServerWebSocketSchema>;
|
|
30
|
-
|
|
31
29
|
private httpHandlers = new Map<HttpHandler['id'], HttpHandler>();
|
|
32
30
|
|
|
31
|
+
webSocketClient: WebSocketClient<InterceptorServerWebSocketSchema>;
|
|
32
|
+
private auth?: RemoteHttpInterceptorWorkerOptions['auth'];
|
|
33
|
+
|
|
33
34
|
constructor(options: RemoteHttpInterceptorWorkerOptions) {
|
|
34
35
|
super();
|
|
35
36
|
|
|
36
|
-
const webSocketServerURL = this.deriveWebSocketServerURL(options.serverURL);
|
|
37
37
|
this.webSocketClient = new WebSocketClient({
|
|
38
|
-
url:
|
|
38
|
+
url: this.getWebSocketServerURL(options.serverURL).toString(),
|
|
39
39
|
});
|
|
40
|
+
|
|
41
|
+
this.auth = options.auth;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
get type() {
|
|
43
45
|
return 'remote' as const;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
private
|
|
48
|
+
private getWebSocketServerURL(serverURL: URL) {
|
|
47
49
|
const webSocketServerURL = new URL(serverURL);
|
|
48
50
|
webSocketServerURL.protocol = serverURL.protocol.replace(/^http(s)?:$/, 'ws$1:');
|
|
49
51
|
return webSocketServerURL;
|
|
@@ -51,7 +53,10 @@ class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
|
51
53
|
|
|
52
54
|
async start() {
|
|
53
55
|
await super.sharedStart(async () => {
|
|
54
|
-
await this.webSocketClient.start(
|
|
56
|
+
await this.webSocketClient.start({
|
|
57
|
+
parameters: this.auth ? { token: this.auth.token } : undefined,
|
|
58
|
+
waitForAuthentication: true,
|
|
59
|
+
});
|
|
55
60
|
|
|
56
61
|
this.webSocketClient.onEvent('interceptors/responses/create', this.createResponse);
|
|
57
62
|
this.webSocketClient.onEvent('interceptors/responses/unhandled', this.handleUnhandledServerRequest);
|
|
@@ -62,7 +67,7 @@ class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
private createResponse = async (
|
|
65
|
-
message:
|
|
70
|
+
message: WebSocketEventMessage<InterceptorServerWebSocketSchema, 'interceptors/responses/create'>,
|
|
66
71
|
) => {
|
|
67
72
|
const { handlerId, request: serializedRequest } = message.data;
|
|
68
73
|
|
|
@@ -87,7 +92,7 @@ class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
|
87
92
|
};
|
|
88
93
|
|
|
89
94
|
private handleUnhandledServerRequest = async (
|
|
90
|
-
message:
|
|
95
|
+
message: WebSocketEventMessage<InterceptorServerWebSocketSchema, 'interceptors/responses/unhandled'>,
|
|
91
96
|
) => {
|
|
92
97
|
const { request: serializedRequest } = message.data;
|
|
93
98
|
const request = deserializeRequest(serializedRequest);
|
|
@@ -156,7 +161,7 @@ class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
|
156
161
|
|
|
157
162
|
this.httpHandlers.set(handler.id, handler);
|
|
158
163
|
|
|
159
|
-
await this.webSocketClient.request('interceptors/workers/
|
|
164
|
+
await this.webSocketClient.request('interceptors/workers/commit', {
|
|
160
165
|
id: handler.id,
|
|
161
166
|
url: handler.url,
|
|
162
167
|
method,
|
|
@@ -171,7 +176,7 @@ class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
|
171
176
|
this.httpHandlers.clear();
|
|
172
177
|
|
|
173
178
|
if (this.webSocketClient.isRunning) {
|
|
174
|
-
await this.webSocketClient.request('interceptors/workers/
|
|
179
|
+
await this.webSocketClient.request('interceptors/workers/reset', undefined);
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
|
|
@@ -193,7 +198,7 @@ class RemoteHttpInterceptorWorker extends HttpInterceptorWorker {
|
|
|
193
198
|
method: handler.method,
|
|
194
199
|
}));
|
|
195
200
|
|
|
196
|
-
await this.webSocketClient.request('interceptors/workers/
|
|
201
|
+
await this.webSocketClient.request('interceptors/workers/reset', groupsToRecommit);
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
|
|
@@ -5,6 +5,7 @@ export interface LocalHttpInterceptorWorkerOptions {
|
|
|
5
5
|
export interface RemoteHttpInterceptorWorkerOptions {
|
|
6
6
|
type: 'remote';
|
|
7
7
|
serverURL: URL;
|
|
8
|
+
auth?: { token: string };
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export type HttpInterceptorWorkerOptions = LocalHttpInterceptorWorkerOptions | RemoteHttpInterceptorWorkerOptions;
|
|
@@ -3,7 +3,7 @@ import { Range } from '@zimic/utils/types';
|
|
|
3
3
|
import color from 'picocolors';
|
|
4
4
|
|
|
5
5
|
import { HttpInterceptorRequestSaving } from '@/http/interceptor/types/public';
|
|
6
|
-
import { stringifyValueToLog } from '@/utils/
|
|
6
|
+
import { stringifyValueToLog } from '@/utils/logging';
|
|
7
7
|
|
|
8
8
|
import { UnmatchedHttpInterceptorRequestGroup } from '../types/restrictions';
|
|
9
9
|
import TimesDeclarationPointer from './TimesDeclarationPointer';
|