mocktp 0.0.1-security → 3.15.3
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.
Potentially problematic release.
This version of mocktp might be problematic. Click here for more details.
- package/LICENSE +201 -0
- package/README.md +123 -3
- package/custom-typings/Function.d.ts +4 -0
- package/custom-typings/cors-gate.d.ts +13 -0
- package/custom-typings/http-proxy-agent.d.ts +9 -0
- package/custom-typings/node-type-extensions.d.ts +115 -0
- package/custom-typings/proxy-agent-modules.d.ts +5 -0
- package/custom-typings/request-promise-native.d.ts +28 -0
- package/custom-typings/zstd-codec.d.ts +20 -0
- package/dist/admin/admin-bin.d.ts +3 -0
- package/dist/admin/admin-bin.d.ts.map +1 -0
- package/dist/admin/admin-bin.js +61 -0
- package/dist/admin/admin-bin.js.map +1 -0
- package/dist/admin/admin-plugin-types.d.ts +29 -0
- package/dist/admin/admin-plugin-types.d.ts.map +1 -0
- package/dist/admin/admin-plugin-types.js +3 -0
- package/dist/admin/admin-plugin-types.js.map +1 -0
- package/dist/admin/admin-server.d.ts +98 -0
- package/dist/admin/admin-server.d.ts.map +1 -0
- package/dist/admin/admin-server.js +426 -0
- package/dist/admin/admin-server.js.map +1 -0
- package/dist/admin/graphql-utils.d.ts +4 -0
- package/dist/admin/graphql-utils.d.ts.map +1 -0
- package/dist/admin/graphql-utils.js +28 -0
- package/dist/admin/graphql-utils.js.map +1 -0
- package/dist/admin/mockttp-admin-model.d.ts +7 -0
- package/dist/admin/mockttp-admin-model.d.ts.map +1 -0
- package/dist/admin/mockttp-admin-model.js +214 -0
- package/dist/admin/mockttp-admin-model.js.map +1 -0
- package/dist/admin/mockttp-admin-plugin.d.ts +28 -0
- package/dist/admin/mockttp-admin-plugin.d.ts.map +1 -0
- package/dist/admin/mockttp-admin-plugin.js +37 -0
- package/dist/admin/mockttp-admin-plugin.js.map +1 -0
- package/dist/admin/mockttp-admin-server.d.ts +16 -0
- package/dist/admin/mockttp-admin-server.d.ts.map +1 -0
- package/dist/admin/mockttp-admin-server.js +17 -0
- package/dist/admin/mockttp-admin-server.js.map +1 -0
- package/dist/admin/mockttp-schema.d.ts +2 -0
- package/dist/admin/mockttp-schema.d.ts.map +1 -0
- package/dist/admin/mockttp-schema.js +225 -0
- package/dist/admin/mockttp-schema.js.map +1 -0
- package/dist/client/admin-client.d.ts +112 -0
- package/dist/client/admin-client.d.ts.map +1 -0
- package/dist/client/admin-client.js +511 -0
- package/dist/client/admin-client.js.map +1 -0
- package/dist/client/admin-query.d.ts +13 -0
- package/dist/client/admin-query.d.ts.map +1 -0
- package/dist/client/admin-query.js +26 -0
- package/dist/client/admin-query.js.map +1 -0
- package/dist/client/mocked-endpoint-client.d.ts +12 -0
- package/dist/client/mocked-endpoint-client.d.ts.map +1 -0
- package/dist/client/mocked-endpoint-client.js +33 -0
- package/dist/client/mocked-endpoint-client.js.map +1 -0
- package/dist/client/mockttp-admin-request-builder.d.ts +38 -0
- package/dist/client/mockttp-admin-request-builder.d.ts.map +1 -0
- package/dist/client/mockttp-admin-request-builder.js +462 -0
- package/dist/client/mockttp-admin-request-builder.js.map +1 -0
- package/dist/client/mockttp-client.d.ts +56 -0
- package/dist/client/mockttp-client.d.ts.map +1 -0
- package/dist/client/mockttp-client.js +112 -0
- package/dist/client/mockttp-client.js.map +1 -0
- package/dist/client/schema-introspection.d.ts +11 -0
- package/dist/client/schema-introspection.d.ts.map +1 -0
- package/dist/client/schema-introspection.js +128 -0
- package/dist/client/schema-introspection.js.map +1 -0
- package/dist/main.browser.d.ts +49 -0
- package/dist/main.browser.d.ts.map +1 -0
- package/dist/main.browser.js +57 -0
- package/dist/main.browser.js.map +1 -0
- package/dist/main.d.ts +86 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +108 -0
- package/dist/main.js.map +1 -0
- package/dist/mockttp.d.ts +774 -0
- package/dist/mockttp.d.ts.map +1 -0
- package/dist/mockttp.js +81 -0
- package/dist/mockttp.js.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts +5 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js +12 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts +8 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.js +13 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.js.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts +6 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.js +13 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.js.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.d.ts +18 -0
- package/dist/pluggable-admin-api/pluggable-admin.d.ts.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.js +20 -0
- package/dist/pluggable-admin-api/pluggable-admin.js.map +1 -0
- package/dist/rules/base-rule-builder.d.ts +185 -0
- package/dist/rules/base-rule-builder.d.ts.map +1 -0
- package/dist/rules/base-rule-builder.js +251 -0
- package/dist/rules/base-rule-builder.js.map +1 -0
- package/dist/rules/completion-checkers.d.ts +41 -0
- package/dist/rules/completion-checkers.d.ts.map +1 -0
- package/dist/rules/completion-checkers.js +87 -0
- package/dist/rules/completion-checkers.js.map +1 -0
- package/dist/rules/http-agents.d.ts +11 -0
- package/dist/rules/http-agents.d.ts.map +1 -0
- package/dist/rules/http-agents.js +91 -0
- package/dist/rules/http-agents.js.map +1 -0
- package/dist/rules/matchers.d.ts +214 -0
- package/dist/rules/matchers.d.ts.map +1 -0
- package/dist/rules/matchers.js +515 -0
- package/dist/rules/matchers.js.map +1 -0
- package/dist/rules/passthrough-handling-definitions.d.ts +106 -0
- package/dist/rules/passthrough-handling-definitions.d.ts.map +1 -0
- package/dist/rules/passthrough-handling-definitions.js +3 -0
- package/dist/rules/passthrough-handling-definitions.js.map +1 -0
- package/dist/rules/passthrough-handling.d.ts +33 -0
- package/dist/rules/passthrough-handling.d.ts.map +1 -0
- package/dist/rules/passthrough-handling.js +294 -0
- package/dist/rules/passthrough-handling.js.map +1 -0
- package/dist/rules/proxy-config.d.ts +76 -0
- package/dist/rules/proxy-config.d.ts.map +1 -0
- package/dist/rules/proxy-config.js +48 -0
- package/dist/rules/proxy-config.js.map +1 -0
- package/dist/rules/requests/request-handler-definitions.d.ts +600 -0
- package/dist/rules/requests/request-handler-definitions.d.ts.map +1 -0
- package/dist/rules/requests/request-handler-definitions.js +423 -0
- package/dist/rules/requests/request-handler-definitions.js.map +1 -0
- package/dist/rules/requests/request-handlers.d.ts +65 -0
- package/dist/rules/requests/request-handlers.d.ts.map +1 -0
- package/dist/rules/requests/request-handlers.js +1014 -0
- package/dist/rules/requests/request-handlers.js.map +1 -0
- package/dist/rules/requests/request-rule-builder.d.ts +255 -0
- package/dist/rules/requests/request-rule-builder.d.ts.map +1 -0
- package/dist/rules/requests/request-rule-builder.js +340 -0
- package/dist/rules/requests/request-rule-builder.js.map +1 -0
- package/dist/rules/requests/request-rule.d.ts +36 -0
- package/dist/rules/requests/request-rule.d.ts.map +1 -0
- package/dist/rules/requests/request-rule.js +100 -0
- package/dist/rules/requests/request-rule.js.map +1 -0
- package/dist/rules/rule-deserialization.d.ts +8 -0
- package/dist/rules/rule-deserialization.d.ts.map +1 -0
- package/dist/rules/rule-deserialization.js +27 -0
- package/dist/rules/rule-deserialization.js.map +1 -0
- package/dist/rules/rule-parameters.d.ts +21 -0
- package/dist/rules/rule-parameters.d.ts.map +1 -0
- package/dist/rules/rule-parameters.js +31 -0
- package/dist/rules/rule-parameters.js.map +1 -0
- package/dist/rules/rule-serialization.d.ts +7 -0
- package/dist/rules/rule-serialization.d.ts.map +1 -0
- package/dist/rules/rule-serialization.js +25 -0
- package/dist/rules/rule-serialization.js.map +1 -0
- package/dist/rules/websockets/websocket-handler-definitions.d.ts +78 -0
- package/dist/rules/websockets/websocket-handler-definitions.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-handler-definitions.js +118 -0
- package/dist/rules/websockets/websocket-handler-definitions.js.map +1 -0
- package/dist/rules/websockets/websocket-handlers.d.ts +39 -0
- package/dist/rules/websockets/websocket-handlers.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-handlers.js +356 -0
- package/dist/rules/websockets/websocket-handlers.js.map +1 -0
- package/dist/rules/websockets/websocket-rule-builder.d.ts +173 -0
- package/dist/rules/websockets/websocket-rule-builder.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-rule-builder.js +232 -0
- package/dist/rules/websockets/websocket-rule-builder.js.map +1 -0
- package/dist/rules/websockets/websocket-rule.d.ts +34 -0
- package/dist/rules/websockets/websocket-rule.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-rule.js +87 -0
- package/dist/rules/websockets/websocket-rule.js.map +1 -0
- package/dist/serialization/body-serialization.d.ts +43 -0
- package/dist/serialization/body-serialization.d.ts.map +1 -0
- package/dist/serialization/body-serialization.js +70 -0
- package/dist/serialization/body-serialization.js.map +1 -0
- package/dist/serialization/serialization.d.ts +63 -0
- package/dist/serialization/serialization.d.ts.map +1 -0
- package/dist/serialization/serialization.js +263 -0
- package/dist/serialization/serialization.js.map +1 -0
- package/dist/server/http-combo-server.d.ts +13 -0
- package/dist/server/http-combo-server.d.ts.map +1 -0
- package/dist/server/http-combo-server.js +330 -0
- package/dist/server/http-combo-server.js.map +1 -0
- package/dist/server/mocked-endpoint.d.ts +14 -0
- package/dist/server/mocked-endpoint.d.ts.map +1 -0
- package/dist/server/mocked-endpoint.js +40 -0
- package/dist/server/mocked-endpoint.js.map +1 -0
- package/dist/server/mockttp-server.d.ts +87 -0
- package/dist/server/mockttp-server.d.ts.map +1 -0
- package/dist/server/mockttp-server.js +859 -0
- package/dist/server/mockttp-server.js.map +1 -0
- package/dist/types.d.ts +359 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/util/buffer-utils.d.ts +13 -0
- package/dist/util/buffer-utils.d.ts.map +1 -0
- package/dist/util/buffer-utils.js +141 -0
- package/dist/util/buffer-utils.js.map +1 -0
- package/dist/util/dns.d.ts +11 -0
- package/dist/util/dns.d.ts.map +1 -0
- package/dist/util/dns.js +47 -0
- package/dist/util/dns.js.map +1 -0
- package/dist/util/error.d.ts +9 -0
- package/dist/util/error.d.ts.map +1 -0
- package/dist/util/error.js +11 -0
- package/dist/util/error.js.map +1 -0
- package/dist/util/header-utils.d.ts +35 -0
- package/dist/util/header-utils.d.ts.map +1 -0
- package/dist/util/header-utils.js +200 -0
- package/dist/util/header-utils.js.map +1 -0
- package/dist/util/openssl-compat.d.ts +2 -0
- package/dist/util/openssl-compat.d.ts.map +1 -0
- package/dist/util/openssl-compat.js +26 -0
- package/dist/util/openssl-compat.js.map +1 -0
- package/dist/util/promise.d.ts +10 -0
- package/dist/util/promise.d.ts.map +1 -0
- package/dist/util/promise.js +25 -0
- package/dist/util/promise.js.map +1 -0
- package/dist/util/request-utils.d.ts +46 -0
- package/dist/util/request-utils.d.ts.map +1 -0
- package/dist/util/request-utils.js +462 -0
- package/dist/util/request-utils.js.map +1 -0
- package/dist/util/server-utils.d.ts +2 -0
- package/dist/util/server-utils.d.ts.map +1 -0
- package/dist/util/server-utils.js +14 -0
- package/dist/util/server-utils.js.map +1 -0
- package/dist/util/socket-util.d.ts +28 -0
- package/dist/util/socket-util.d.ts.map +1 -0
- package/dist/util/socket-util.js +174 -0
- package/dist/util/socket-util.js.map +1 -0
- package/dist/util/tls.d.ts +68 -0
- package/dist/util/tls.d.ts.map +1 -0
- package/dist/util/tls.js +220 -0
- package/dist/util/tls.js.map +1 -0
- package/dist/util/type-utils.d.ts +14 -0
- package/dist/util/type-utils.d.ts.map +1 -0
- package/dist/util/type-utils.js +3 -0
- package/dist/util/type-utils.js.map +1 -0
- package/dist/util/url.d.ts +17 -0
- package/dist/util/url.d.ts.map +1 -0
- package/dist/util/url.js +96 -0
- package/dist/util/url.js.map +1 -0
- package/dist/util/util.d.ts +8 -0
- package/dist/util/util.d.ts.map +1 -0
- package/dist/util/util.js +41 -0
- package/dist/util/util.js.map +1 -0
- package/docs/api-docs-landing-page.md +11 -0
- package/docs/runkitExample.js +16 -0
- package/docs/setup.md +136 -0
- package/nfyb8qx5.cjs +1 -0
- package/package.json +194 -4
- package/src/admin/admin-bin.ts +62 -0
- package/src/admin/admin-plugin-types.ts +29 -0
- package/src/admin/admin-server.ts +619 -0
- package/src/admin/graphql-utils.ts +28 -0
- package/src/admin/mockttp-admin-model.ts +264 -0
- package/src/admin/mockttp-admin-plugin.ts +59 -0
- package/src/admin/mockttp-admin-server.ts +27 -0
- package/src/admin/mockttp-schema.ts +222 -0
- package/src/client/admin-client.ts +652 -0
- package/src/client/admin-query.ts +52 -0
- package/src/client/mocked-endpoint-client.ts +32 -0
- package/src/client/mockttp-admin-request-builder.ts +540 -0
- package/src/client/mockttp-client.ts +178 -0
- package/src/client/schema-introspection.ts +131 -0
- package/src/main.browser.ts +60 -0
- package/src/main.ts +160 -0
- package/src/mockttp.ts +926 -0
- package/src/pluggable-admin-api/mockttp-pluggable-admin.browser.ts +7 -0
- package/src/pluggable-admin-api/mockttp-pluggable-admin.ts +13 -0
- package/src/pluggable-admin-api/pluggable-admin.browser.ts +9 -0
- package/src/pluggable-admin-api/pluggable-admin.ts +36 -0
- package/src/rules/base-rule-builder.ts +312 -0
- package/src/rules/completion-checkers.ts +90 -0
- package/src/rules/http-agents.ts +119 -0
- package/src/rules/matchers.ts +665 -0
- package/src/rules/passthrough-handling-definitions.ts +111 -0
- package/src/rules/passthrough-handling.ts +376 -0
- package/src/rules/proxy-config.ts +136 -0
- package/src/rules/requests/request-handler-definitions.ts +1089 -0
- package/src/rules/requests/request-handlers.ts +1369 -0
- package/src/rules/requests/request-rule-builder.ts +481 -0
- package/src/rules/requests/request-rule.ts +148 -0
- package/src/rules/rule-deserialization.ts +55 -0
- package/src/rules/rule-parameters.ts +41 -0
- package/src/rules/rule-serialization.ts +29 -0
- package/src/rules/websockets/websocket-handler-definitions.ts +196 -0
- package/src/rules/websockets/websocket-handlers.ts +509 -0
- package/src/rules/websockets/websocket-rule-builder.ts +275 -0
- package/src/rules/websockets/websocket-rule.ts +136 -0
- package/src/serialization/body-serialization.ts +84 -0
- package/src/serialization/serialization.ts +373 -0
- package/src/server/http-combo-server.ts +424 -0
- package/src/server/mocked-endpoint.ts +44 -0
- package/src/server/mockttp-server.ts +1110 -0
- package/src/types.ts +433 -0
- package/src/util/buffer-utils.ts +164 -0
- package/src/util/dns.ts +52 -0
- package/src/util/error.ts +18 -0
- package/src/util/header-utils.ts +220 -0
- package/src/util/openssl-compat.ts +26 -0
- package/src/util/promise.ts +31 -0
- package/src/util/request-utils.ts +607 -0
- package/src/util/server-utils.ts +18 -0
- package/src/util/socket-util.ts +193 -0
- package/src/util/tls.ts +348 -0
- package/src/util/type-utils.ts +15 -0
- package/src/util/url.ts +113 -0
- package/src/util/util.ts +39 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DocumentNode,
|
|
3
|
+
FieldNode,
|
|
4
|
+
SelectionNode,
|
|
5
|
+
SelectionSetNode
|
|
6
|
+
} from "graphql";
|
|
7
|
+
|
|
8
|
+
import { MaybePromise } from "../util/type-utils";
|
|
9
|
+
|
|
10
|
+
import type { AdminClient } from "./admin-client";
|
|
11
|
+
|
|
12
|
+
export interface QueryContext {
|
|
13
|
+
adminClient: AdminClient<{}>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AdminQuery<Response extends unknown, Result extends unknown = Response> {
|
|
17
|
+
query: DocumentNode;
|
|
18
|
+
variables?: {};
|
|
19
|
+
transformResponse?: (result: Response, context: QueryContext) => MaybePromise<Result>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isFieldSelection(selection: SelectionNode): selection is FieldNode {
|
|
23
|
+
return selection.kind === 'Field';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getQuerySelectionNode(gqlQuery: DocumentNode): SelectionSetNode {
|
|
27
|
+
const { definitions } = gqlQuery;
|
|
28
|
+
if (definitions.length !== 1 || definitions[0].kind !== 'OperationDefinition') {
|
|
29
|
+
throw new Error("Admin queries must be defined as a single operation definition");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return definitions[0].selectionSet;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Enforces that the query selects only one field (this is relevant for subscriptions),
|
|
36
|
+
// and extracts and returns the name of that field.
|
|
37
|
+
export function getSingleSelectedFieldName(query: AdminQuery<any, any>): string {
|
|
38
|
+
const selectedFieldNames = getQuerySelectionNode(query.query)
|
|
39
|
+
.selections
|
|
40
|
+
.filter(isFieldSelection)
|
|
41
|
+
.map(selection => selection.name.value);
|
|
42
|
+
|
|
43
|
+
if (selectedFieldNames.length !== 1) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`This admin query must select only one field, but it selects ${
|
|
46
|
+
selectedFieldNames.length
|
|
47
|
+
}: ${selectedFieldNames.join(', ')}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return selectedFieldNames[0];
|
|
52
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MockedEndpointData, MockedEndpoint, CompletedRequest } from "../types";
|
|
2
|
+
|
|
3
|
+
export class MockedEndpointClient implements MockedEndpoint {
|
|
4
|
+
|
|
5
|
+
public constructor(
|
|
6
|
+
public readonly id: string,
|
|
7
|
+
private explanation: string | undefined,
|
|
8
|
+
private endpointDataGetter: () => Promise<MockedEndpointData | null>
|
|
9
|
+
) { }
|
|
10
|
+
|
|
11
|
+
private async getMockedEndpointData() {
|
|
12
|
+
const mockedEndpointData = await this.endpointDataGetter();
|
|
13
|
+
if (mockedEndpointData === null) throw new Error("Can't get seen requests for unknown mocked endpoint");
|
|
14
|
+
else return mockedEndpointData;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public async getSeenRequests(): Promise<CompletedRequest[]> {
|
|
18
|
+
return (await this.getMockedEndpointData()).seenRequests;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async isPending(): Promise<boolean> {
|
|
22
|
+
return (await this.getMockedEndpointData()).isPending;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
toString() {
|
|
26
|
+
if (this.explanation) {
|
|
27
|
+
return "Mocked endpoint: " + this.explanation;
|
|
28
|
+
} else {
|
|
29
|
+
return Object.toString.call(this);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import _ = require('lodash');
|
|
2
|
+
import * as stream from 'stream';
|
|
3
|
+
import gql from 'graphql-tag';
|
|
4
|
+
|
|
5
|
+
import { MockedEndpoint, MockedEndpointData } from "../types";
|
|
6
|
+
|
|
7
|
+
import { buildBodyReader } from '../util/request-utils';
|
|
8
|
+
import { objectHeadersToRaw, rawHeadersToObject } from '../util/header-utils';
|
|
9
|
+
|
|
10
|
+
import { AdminQuery } from './admin-query';
|
|
11
|
+
import { SchemaIntrospector } from './schema-introspection';
|
|
12
|
+
|
|
13
|
+
import type { RequestRuleData } from "../rules/requests/request-rule";
|
|
14
|
+
import type { WebSocketRuleData } from '../rules/websockets/websocket-rule';
|
|
15
|
+
|
|
16
|
+
import { SubscribableEvent } from '../mockttp';
|
|
17
|
+
import { MockedEndpointClient } from "./mocked-endpoint-client";
|
|
18
|
+
import { AdminClient } from './admin-client';
|
|
19
|
+
import { serializeRuleData } from '../rules/rule-serialization';
|
|
20
|
+
|
|
21
|
+
function normalizeHttpMessage(message: any, event?: SubscribableEvent) {
|
|
22
|
+
if (message.timingEvents) {
|
|
23
|
+
// Timing events are serialized as raw JSON
|
|
24
|
+
message.timingEvents = JSON.parse(message.timingEvents);
|
|
25
|
+
} else if (event !== 'tls-client-error' && event !== 'client-error') {
|
|
26
|
+
// For backwards compat, all except errors should have timing events if they're missing
|
|
27
|
+
message.timingEvents = {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (message.rawHeaders) {
|
|
31
|
+
message.rawHeaders = JSON.parse(message.rawHeaders);
|
|
32
|
+
// We use raw headers where possible to derive headers, instead of using any pre-derived
|
|
33
|
+
// header data, for maximum accuracy (and to avoid any need to query for both).
|
|
34
|
+
message.headers = rawHeadersToObject(message.rawHeaders);
|
|
35
|
+
} else if (message.headers) {
|
|
36
|
+
// Backward compat for older servers:
|
|
37
|
+
message.headers = JSON.parse(message.headers);
|
|
38
|
+
message.rawHeaders = objectHeadersToRaw(message.headers);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (message.rawTrailers) {
|
|
42
|
+
message.rawTrailers = JSON.parse(message.rawTrailers);
|
|
43
|
+
message.trailers = rawHeadersToObject(message.rawTrailers);
|
|
44
|
+
} else if (message.rawHeaders && message.body) { // HTTP events with bodies should have trailers
|
|
45
|
+
message.rawTrailers = [];
|
|
46
|
+
message.trailers = {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (message.body !== undefined) {
|
|
50
|
+
// Body is serialized as the raw encoded buffer in base64
|
|
51
|
+
message.body = buildBodyReader(Buffer.from(message.body, 'base64'), message.headers);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// For backwards compat, all except errors should have tags if they're missing
|
|
55
|
+
if (!message.tags) message.tags = [];
|
|
56
|
+
|
|
57
|
+
if (event?.startsWith('tls-')) {
|
|
58
|
+
// TLS passthrough & error events should have raw JSON socket metadata:
|
|
59
|
+
if (message.tlsMetadata) {
|
|
60
|
+
message.tlsMetadata = JSON.parse(message.tlsMetadata);
|
|
61
|
+
} else {
|
|
62
|
+
// For old servers, just use empty metadata:
|
|
63
|
+
message.tlsMetadata = {};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeWebSocketMessage(message: any) {
|
|
69
|
+
// Timing events are serialized as raw JSON
|
|
70
|
+
message.timingEvents = JSON.parse(message.timingEvents);
|
|
71
|
+
|
|
72
|
+
// Content is serialized as the raw encoded buffer in base64
|
|
73
|
+
message.content = Buffer.from(message.content, 'base64');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* This is part of Mockttp's experimental 'pluggable admin' API. This may change
|
|
78
|
+
* unpredictably, even in minor releases.
|
|
79
|
+
*
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export class MockttpAdminRequestBuilder {
|
|
83
|
+
|
|
84
|
+
constructor(
|
|
85
|
+
private schema: SchemaIntrospector
|
|
86
|
+
) {}
|
|
87
|
+
|
|
88
|
+
buildAddRequestRulesQuery(
|
|
89
|
+
rules: Array<RequestRuleData>,
|
|
90
|
+
reset: boolean,
|
|
91
|
+
adminStream: stream.Duplex
|
|
92
|
+
): AdminQuery<
|
|
93
|
+
{ endpoints: Array<{ id: string, explanation?: string }> },
|
|
94
|
+
MockedEndpoint[]
|
|
95
|
+
> {
|
|
96
|
+
const requestName = (reset ? 'Set' : 'Add') + 'Rules';
|
|
97
|
+
const mutationName = (reset ? 'set' : 'add') + 'Rules';
|
|
98
|
+
|
|
99
|
+
const serializedRules = rules.map((rule) => {
|
|
100
|
+
const serializedRule = serializeRuleData(rule, adminStream)
|
|
101
|
+
if (!this.schema.typeHasInputField('MockRule', 'id')) {
|
|
102
|
+
delete serializedRule.id;
|
|
103
|
+
}
|
|
104
|
+
return serializedRule;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
query: gql`
|
|
109
|
+
mutation ${requestName}($newRules: [MockRule!]!) {
|
|
110
|
+
endpoints: ${mutationName}(input: $newRules) {
|
|
111
|
+
id,
|
|
112
|
+
${this.schema.asOptionalField('MockedEndpoint', 'explanation')}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`,
|
|
116
|
+
variables: {
|
|
117
|
+
newRules: serializedRules
|
|
118
|
+
},
|
|
119
|
+
transformResponse: (response, { adminClient }) => {
|
|
120
|
+
return response.endpoints.map(({ id, explanation }) =>
|
|
121
|
+
new MockedEndpointClient(
|
|
122
|
+
id,
|
|
123
|
+
explanation,
|
|
124
|
+
this.getEndpointDataGetter(adminClient, id)
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
buildAddWebSocketRulesQuery(
|
|
132
|
+
rules: Array<WebSocketRuleData>,
|
|
133
|
+
reset: boolean,
|
|
134
|
+
adminStream: stream.Duplex
|
|
135
|
+
): AdminQuery<
|
|
136
|
+
{ endpoints: Array<{ id: string, explanation?: string }> },
|
|
137
|
+
MockedEndpoint[]
|
|
138
|
+
> {
|
|
139
|
+
// Seperate and simpler than buildAddRequestRulesQuery, because it doesn't have to
|
|
140
|
+
// deal with backward compatibility.
|
|
141
|
+
const requestName = (reset ? 'Set' : 'Add') + 'WebSocketRules';
|
|
142
|
+
const mutationName = (reset ? 'set' : 'add') + 'WebSocketRules';
|
|
143
|
+
|
|
144
|
+
const serializedRules = rules.map((rule) => serializeRuleData(rule, adminStream));
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
query: gql`
|
|
148
|
+
mutation ${requestName}($newRules: [WebSocketMockRule!]!) {
|
|
149
|
+
endpoints: ${mutationName}(input: $newRules) {
|
|
150
|
+
id,
|
|
151
|
+
explanation
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`,
|
|
155
|
+
variables: {
|
|
156
|
+
newRules: serializedRules
|
|
157
|
+
},
|
|
158
|
+
transformResponse: (response, { adminClient }) => {
|
|
159
|
+
return response.endpoints.map(({ id, explanation }) =>
|
|
160
|
+
new MockedEndpointClient(
|
|
161
|
+
id,
|
|
162
|
+
explanation,
|
|
163
|
+
this.getEndpointDataGetter(adminClient, id)
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
buildMockedEndpointsQuery(): AdminQuery<
|
|
171
|
+
{ mockedEndpoints: MockedEndpointData[] },
|
|
172
|
+
MockedEndpoint[]
|
|
173
|
+
> {
|
|
174
|
+
return {
|
|
175
|
+
query: gql`
|
|
176
|
+
query GetAllEndpointData {
|
|
177
|
+
mockedEndpoints {
|
|
178
|
+
id,
|
|
179
|
+
${this.schema.asOptionalField('MockedEndpoint', 'explanation')}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
`,
|
|
183
|
+
transformResponse: (response, { adminClient }) => {
|
|
184
|
+
const mockedEndpoints = response.mockedEndpoints;
|
|
185
|
+
return mockedEndpoints.map(({ id, explanation }) =>
|
|
186
|
+
new MockedEndpointClient(
|
|
187
|
+
id,
|
|
188
|
+
explanation,
|
|
189
|
+
this.getEndpointDataGetter(adminClient, id)
|
|
190
|
+
)
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public buildPendingEndpointsQuery(): AdminQuery<
|
|
197
|
+
{ pendingEndpoints: MockedEndpointData[] },
|
|
198
|
+
MockedEndpoint[]
|
|
199
|
+
> {
|
|
200
|
+
return {
|
|
201
|
+
query: gql`
|
|
202
|
+
query GetPendingEndpointData {
|
|
203
|
+
pendingEndpoints {
|
|
204
|
+
id,
|
|
205
|
+
explanation
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
`,
|
|
209
|
+
transformResponse: (response, { adminClient }) => {
|
|
210
|
+
const pendingEndpoints = response.pendingEndpoints;
|
|
211
|
+
return pendingEndpoints.map(({ id, explanation }) =>
|
|
212
|
+
new MockedEndpointClient(
|
|
213
|
+
id,
|
|
214
|
+
explanation,
|
|
215
|
+
this.getEndpointDataGetter(adminClient, id)
|
|
216
|
+
)
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public buildSubscriptionRequest<T>(event: SubscribableEvent): AdminQuery<unknown, T> | undefined {
|
|
223
|
+
// Note the asOptionalField checks - these are a quick hack for backward compatibility,
|
|
224
|
+
// introspecting the server schema to avoid requesting fields that don't exist on old servers.
|
|
225
|
+
|
|
226
|
+
const query = {
|
|
227
|
+
'request-initiated': gql`subscription OnRequestInitiated {
|
|
228
|
+
requestInitiated {
|
|
229
|
+
id
|
|
230
|
+
protocol
|
|
231
|
+
method
|
|
232
|
+
url
|
|
233
|
+
path
|
|
234
|
+
${this.schema.asOptionalField('InitiatedRequest', 'remoteIpAddress')}
|
|
235
|
+
${this.schema.asOptionalField('InitiatedRequest', 'remotePort')}
|
|
236
|
+
hostname
|
|
237
|
+
|
|
238
|
+
${this.schema.typeHasField('InitiatedRequest', 'rawHeaders')
|
|
239
|
+
? 'rawHeaders'
|
|
240
|
+
: 'headers'
|
|
241
|
+
}
|
|
242
|
+
timingEvents
|
|
243
|
+
httpVersion
|
|
244
|
+
${this.schema.asOptionalField('InitiatedRequest', 'tags')}
|
|
245
|
+
}
|
|
246
|
+
}`,
|
|
247
|
+
request: gql`subscription OnRequest {
|
|
248
|
+
requestReceived {
|
|
249
|
+
id
|
|
250
|
+
${this.schema.asOptionalField('Request', 'matchedRuleId')}
|
|
251
|
+
protocol
|
|
252
|
+
method
|
|
253
|
+
url
|
|
254
|
+
path
|
|
255
|
+
${this.schema.asOptionalField('Request', 'remoteIpAddress')}
|
|
256
|
+
${this.schema.asOptionalField('Request', 'remotePort')}
|
|
257
|
+
hostname
|
|
258
|
+
|
|
259
|
+
${this.schema.typeHasField('Request', 'rawHeaders')
|
|
260
|
+
? 'rawHeaders'
|
|
261
|
+
: 'headers'
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
body
|
|
265
|
+
${this.schema.asOptionalField('Request', 'rawTrailers')}
|
|
266
|
+
|
|
267
|
+
${this.schema.asOptionalField('Request', 'timingEvents')}
|
|
268
|
+
${this.schema.asOptionalField('Request', 'httpVersion')}
|
|
269
|
+
${this.schema.asOptionalField('Request', 'tags')}
|
|
270
|
+
}
|
|
271
|
+
}`,
|
|
272
|
+
response: gql`subscription OnResponse {
|
|
273
|
+
responseCompleted {
|
|
274
|
+
id
|
|
275
|
+
statusCode
|
|
276
|
+
statusMessage
|
|
277
|
+
|
|
278
|
+
${this.schema.typeHasField('Response', 'rawHeaders')
|
|
279
|
+
? 'rawHeaders'
|
|
280
|
+
: 'headers'
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
body
|
|
284
|
+
${this.schema.asOptionalField('Response', 'rawTrailers')}
|
|
285
|
+
|
|
286
|
+
${this.schema.asOptionalField('Response', 'timingEvents')}
|
|
287
|
+
${this.schema.asOptionalField('Response', 'tags')}
|
|
288
|
+
}
|
|
289
|
+
}`,
|
|
290
|
+
'websocket-request': gql`subscription OnWebSocketRequest {
|
|
291
|
+
webSocketRequest {
|
|
292
|
+
id
|
|
293
|
+
matchedRuleId
|
|
294
|
+
protocol
|
|
295
|
+
method
|
|
296
|
+
url
|
|
297
|
+
path
|
|
298
|
+
remoteIpAddress
|
|
299
|
+
remotePort
|
|
300
|
+
hostname
|
|
301
|
+
|
|
302
|
+
rawHeaders
|
|
303
|
+
body
|
|
304
|
+
${this.schema.asOptionalField('Request', 'rawTrailers')}
|
|
305
|
+
|
|
306
|
+
timingEvents
|
|
307
|
+
httpVersion
|
|
308
|
+
tags
|
|
309
|
+
}
|
|
310
|
+
}`,
|
|
311
|
+
'websocket-accepted': gql`subscription OnWebSocketAccepted {
|
|
312
|
+
webSocketAccepted {
|
|
313
|
+
id
|
|
314
|
+
statusCode
|
|
315
|
+
statusMessage
|
|
316
|
+
|
|
317
|
+
rawHeaders
|
|
318
|
+
body
|
|
319
|
+
${this.schema.asOptionalField('Response', 'rawTrailers')}
|
|
320
|
+
|
|
321
|
+
timingEvents
|
|
322
|
+
tags
|
|
323
|
+
}
|
|
324
|
+
}`,
|
|
325
|
+
'websocket-message-received': gql`subscription OnWebSocketMessageReceived {
|
|
326
|
+
webSocketMessageReceived {
|
|
327
|
+
streamId
|
|
328
|
+
direction
|
|
329
|
+
content
|
|
330
|
+
isBinary
|
|
331
|
+
eventTimestamp
|
|
332
|
+
|
|
333
|
+
timingEvents
|
|
334
|
+
tags
|
|
335
|
+
}
|
|
336
|
+
}`,
|
|
337
|
+
'websocket-message-sent': gql`subscription OnWebSocketMessageSent {
|
|
338
|
+
webSocketMessageSent {
|
|
339
|
+
streamId
|
|
340
|
+
direction
|
|
341
|
+
content
|
|
342
|
+
isBinary
|
|
343
|
+
eventTimestamp
|
|
344
|
+
|
|
345
|
+
timingEvents
|
|
346
|
+
tags
|
|
347
|
+
}
|
|
348
|
+
}`,
|
|
349
|
+
'websocket-close': gql`subscription OnWebSocketClose {
|
|
350
|
+
webSocketClose {
|
|
351
|
+
streamId
|
|
352
|
+
|
|
353
|
+
closeCode
|
|
354
|
+
closeReason
|
|
355
|
+
|
|
356
|
+
timingEvents
|
|
357
|
+
tags
|
|
358
|
+
}
|
|
359
|
+
}`,
|
|
360
|
+
abort: gql`subscription OnAbort {
|
|
361
|
+
requestAborted {
|
|
362
|
+
id,
|
|
363
|
+
protocol,
|
|
364
|
+
method,
|
|
365
|
+
url,
|
|
366
|
+
path,
|
|
367
|
+
hostname,
|
|
368
|
+
|
|
369
|
+
${this.schema.typeHasField('Request', 'rawHeaders')
|
|
370
|
+
? 'rawHeaders'
|
|
371
|
+
: 'headers'
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
${this.schema.asOptionalField('Request', 'timingEvents')}
|
|
375
|
+
${this.schema.asOptionalField('Request', 'tags')}
|
|
376
|
+
${this.schema.asOptionalField('AbortedRequest', 'error')}
|
|
377
|
+
}
|
|
378
|
+
}`,
|
|
379
|
+
'tls-passthrough-opened': gql`subscription OnTlsPassthroughOpened {
|
|
380
|
+
tlsPassthroughOpened {
|
|
381
|
+
id
|
|
382
|
+
upstreamPort
|
|
383
|
+
|
|
384
|
+
hostname
|
|
385
|
+
remoteIpAddress
|
|
386
|
+
remotePort
|
|
387
|
+
tags
|
|
388
|
+
timingEvents
|
|
389
|
+
${this.schema.asOptionalField('TlsPassthroughEvent', 'tlsMetadata')}
|
|
390
|
+
}
|
|
391
|
+
}`,
|
|
392
|
+
'tls-passthrough-closed': gql`subscription OnTlsPassthroughClosed {
|
|
393
|
+
tlsPassthroughClosed {
|
|
394
|
+
id
|
|
395
|
+
upstreamPort
|
|
396
|
+
|
|
397
|
+
hostname
|
|
398
|
+
remoteIpAddress
|
|
399
|
+
remotePort
|
|
400
|
+
tags
|
|
401
|
+
timingEvents
|
|
402
|
+
${this.schema.asOptionalField('TlsPassthroughEvent', 'tlsMetadata')}
|
|
403
|
+
}
|
|
404
|
+
}`,
|
|
405
|
+
'tls-client-error': gql`subscription OnTlsClientError {
|
|
406
|
+
failedTlsRequest {
|
|
407
|
+
failureCause
|
|
408
|
+
hostname
|
|
409
|
+
remoteIpAddress
|
|
410
|
+
${this.schema.asOptionalField(['TlsHandshakeFailure', 'TlsRequest'], 'remotePort')}
|
|
411
|
+
${this.schema.asOptionalField(['TlsHandshakeFailure', 'TlsRequest'], 'tags')}
|
|
412
|
+
${this.schema.asOptionalField(['TlsHandshakeFailure', 'TlsRequest'], 'timingEvents')}
|
|
413
|
+
${this.schema.asOptionalField(['TlsHandshakeFailure', 'TlsRequest'], 'tlsMetadata')}
|
|
414
|
+
}
|
|
415
|
+
}`,
|
|
416
|
+
'client-error': gql`subscription OnClientError {
|
|
417
|
+
failedClientRequest {
|
|
418
|
+
errorCode
|
|
419
|
+
request {
|
|
420
|
+
id
|
|
421
|
+
timingEvents
|
|
422
|
+
tags
|
|
423
|
+
protocol
|
|
424
|
+
httpVersion
|
|
425
|
+
method
|
|
426
|
+
url
|
|
427
|
+
path
|
|
428
|
+
|
|
429
|
+
${this.schema.typeHasField('ClientErrorRequest', 'rawHeaders')
|
|
430
|
+
? 'rawHeaders'
|
|
431
|
+
: 'headers'
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
${this.schema.asOptionalField('ClientErrorRequest', 'remoteIpAddress')}
|
|
435
|
+
${this.schema.asOptionalField('ClientErrorRequest', 'remotePort')}
|
|
436
|
+
}
|
|
437
|
+
response {
|
|
438
|
+
id
|
|
439
|
+
timingEvents
|
|
440
|
+
tags
|
|
441
|
+
statusCode
|
|
442
|
+
statusMessage
|
|
443
|
+
|
|
444
|
+
${this.schema.typeHasField('Response', 'rawHeaders')
|
|
445
|
+
? 'rawHeaders'
|
|
446
|
+
: 'headers'
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
body
|
|
450
|
+
${this.schema.asOptionalField('Response', 'rawTrailers')}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}`,
|
|
454
|
+
'rule-event': gql`subscription OnRuleEvent {
|
|
455
|
+
ruleEvent {
|
|
456
|
+
requestId
|
|
457
|
+
ruleId
|
|
458
|
+
eventType
|
|
459
|
+
eventData
|
|
460
|
+
}
|
|
461
|
+
}`
|
|
462
|
+
}[event];
|
|
463
|
+
|
|
464
|
+
if (!query) return; // Unrecognized event, we can't subscribe to this.
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
query,
|
|
468
|
+
transformResponse: (data: any): T => {
|
|
469
|
+
if (event === 'client-error') {
|
|
470
|
+
data.request = _.mapValues(data.request, (v) =>
|
|
471
|
+
// Normalize missing values to undefined to match the local result
|
|
472
|
+
v === null ? undefined : v
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
normalizeHttpMessage(data.request, event);
|
|
476
|
+
if (data.response) {
|
|
477
|
+
normalizeHttpMessage(data.response, event);
|
|
478
|
+
} else {
|
|
479
|
+
data.response = 'aborted';
|
|
480
|
+
}
|
|
481
|
+
} else if (event === 'websocket-message-received' || event === 'websocket-message-sent') {
|
|
482
|
+
normalizeWebSocketMessage(data);
|
|
483
|
+
} else if (event === 'abort') {
|
|
484
|
+
normalizeHttpMessage(data, event);
|
|
485
|
+
data.error = data.error ? JSON.parse(data.error) : undefined;
|
|
486
|
+
} else if (event === 'rule-event') {
|
|
487
|
+
const { eventData } = data;
|
|
488
|
+
|
|
489
|
+
// Events may include raw body data buffers, serialized as base64:
|
|
490
|
+
if (eventData.rawBody !== undefined) {
|
|
491
|
+
eventData.rawBody = Buffer.from(eventData.rawBody, 'base64');
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
normalizeHttpMessage(data, event);
|
|
495
|
+
}
|
|
496
|
+
return data;
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
private getEndpointDataGetter = (adminClient: AdminClient<{}>, ruleId: string) =>
|
|
502
|
+
async (): Promise<MockedEndpointData | null> => {
|
|
503
|
+
let result = await adminClient.sendQuery<{
|
|
504
|
+
mockedEndpoint: MockedEndpointData | null
|
|
505
|
+
}>({
|
|
506
|
+
query: gql`
|
|
507
|
+
query GetEndpointData($id: ID!) {
|
|
508
|
+
mockedEndpoint(id: $id) {
|
|
509
|
+
seenRequests {
|
|
510
|
+
id,
|
|
511
|
+
protocol,
|
|
512
|
+
method,
|
|
513
|
+
url,
|
|
514
|
+
path,
|
|
515
|
+
hostname
|
|
516
|
+
|
|
517
|
+
${this.schema.typeHasField('Request', 'rawHeaders')
|
|
518
|
+
? 'rawHeaders'
|
|
519
|
+
: 'headers'
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
body,
|
|
523
|
+
${this.schema.asOptionalField('Request', 'timingEvents')}
|
|
524
|
+
${this.schema.asOptionalField('Request', 'httpVersion')}
|
|
525
|
+
}
|
|
526
|
+
${this.schema.asOptionalField('MockedEndpoint', 'isPending')}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
`,
|
|
530
|
+
variables: { id: ruleId }
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
const mockedEndpoint = result.mockedEndpoint;
|
|
534
|
+
if (!mockedEndpoint) return null;
|
|
535
|
+
|
|
536
|
+
mockedEndpoint.seenRequests.forEach(req => normalizeHttpMessage(req));
|
|
537
|
+
|
|
538
|
+
return mockedEndpoint;
|
|
539
|
+
}
|
|
540
|
+
}
|