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.

Files changed (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +123 -3
  3. package/custom-typings/Function.d.ts +4 -0
  4. package/custom-typings/cors-gate.d.ts +13 -0
  5. package/custom-typings/http-proxy-agent.d.ts +9 -0
  6. package/custom-typings/node-type-extensions.d.ts +115 -0
  7. package/custom-typings/proxy-agent-modules.d.ts +5 -0
  8. package/custom-typings/request-promise-native.d.ts +28 -0
  9. package/custom-typings/zstd-codec.d.ts +20 -0
  10. package/dist/admin/admin-bin.d.ts +3 -0
  11. package/dist/admin/admin-bin.d.ts.map +1 -0
  12. package/dist/admin/admin-bin.js +61 -0
  13. package/dist/admin/admin-bin.js.map +1 -0
  14. package/dist/admin/admin-plugin-types.d.ts +29 -0
  15. package/dist/admin/admin-plugin-types.d.ts.map +1 -0
  16. package/dist/admin/admin-plugin-types.js +3 -0
  17. package/dist/admin/admin-plugin-types.js.map +1 -0
  18. package/dist/admin/admin-server.d.ts +98 -0
  19. package/dist/admin/admin-server.d.ts.map +1 -0
  20. package/dist/admin/admin-server.js +426 -0
  21. package/dist/admin/admin-server.js.map +1 -0
  22. package/dist/admin/graphql-utils.d.ts +4 -0
  23. package/dist/admin/graphql-utils.d.ts.map +1 -0
  24. package/dist/admin/graphql-utils.js +28 -0
  25. package/dist/admin/graphql-utils.js.map +1 -0
  26. package/dist/admin/mockttp-admin-model.d.ts +7 -0
  27. package/dist/admin/mockttp-admin-model.d.ts.map +1 -0
  28. package/dist/admin/mockttp-admin-model.js +214 -0
  29. package/dist/admin/mockttp-admin-model.js.map +1 -0
  30. package/dist/admin/mockttp-admin-plugin.d.ts +28 -0
  31. package/dist/admin/mockttp-admin-plugin.d.ts.map +1 -0
  32. package/dist/admin/mockttp-admin-plugin.js +37 -0
  33. package/dist/admin/mockttp-admin-plugin.js.map +1 -0
  34. package/dist/admin/mockttp-admin-server.d.ts +16 -0
  35. package/dist/admin/mockttp-admin-server.d.ts.map +1 -0
  36. package/dist/admin/mockttp-admin-server.js +17 -0
  37. package/dist/admin/mockttp-admin-server.js.map +1 -0
  38. package/dist/admin/mockttp-schema.d.ts +2 -0
  39. package/dist/admin/mockttp-schema.d.ts.map +1 -0
  40. package/dist/admin/mockttp-schema.js +225 -0
  41. package/dist/admin/mockttp-schema.js.map +1 -0
  42. package/dist/client/admin-client.d.ts +112 -0
  43. package/dist/client/admin-client.d.ts.map +1 -0
  44. package/dist/client/admin-client.js +511 -0
  45. package/dist/client/admin-client.js.map +1 -0
  46. package/dist/client/admin-query.d.ts +13 -0
  47. package/dist/client/admin-query.d.ts.map +1 -0
  48. package/dist/client/admin-query.js +26 -0
  49. package/dist/client/admin-query.js.map +1 -0
  50. package/dist/client/mocked-endpoint-client.d.ts +12 -0
  51. package/dist/client/mocked-endpoint-client.d.ts.map +1 -0
  52. package/dist/client/mocked-endpoint-client.js +33 -0
  53. package/dist/client/mocked-endpoint-client.js.map +1 -0
  54. package/dist/client/mockttp-admin-request-builder.d.ts +38 -0
  55. package/dist/client/mockttp-admin-request-builder.d.ts.map +1 -0
  56. package/dist/client/mockttp-admin-request-builder.js +462 -0
  57. package/dist/client/mockttp-admin-request-builder.js.map +1 -0
  58. package/dist/client/mockttp-client.d.ts +56 -0
  59. package/dist/client/mockttp-client.d.ts.map +1 -0
  60. package/dist/client/mockttp-client.js +112 -0
  61. package/dist/client/mockttp-client.js.map +1 -0
  62. package/dist/client/schema-introspection.d.ts +11 -0
  63. package/dist/client/schema-introspection.d.ts.map +1 -0
  64. package/dist/client/schema-introspection.js +128 -0
  65. package/dist/client/schema-introspection.js.map +1 -0
  66. package/dist/main.browser.d.ts +49 -0
  67. package/dist/main.browser.d.ts.map +1 -0
  68. package/dist/main.browser.js +57 -0
  69. package/dist/main.browser.js.map +1 -0
  70. package/dist/main.d.ts +86 -0
  71. package/dist/main.d.ts.map +1 -0
  72. package/dist/main.js +108 -0
  73. package/dist/main.js.map +1 -0
  74. package/dist/mockttp.d.ts +774 -0
  75. package/dist/mockttp.d.ts.map +1 -0
  76. package/dist/mockttp.js +81 -0
  77. package/dist/mockttp.js.map +1 -0
  78. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts +5 -0
  79. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts.map +1 -0
  80. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js +12 -0
  81. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js.map +1 -0
  82. package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts +8 -0
  83. package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts.map +1 -0
  84. package/dist/pluggable-admin-api/mockttp-pluggable-admin.js +13 -0
  85. package/dist/pluggable-admin-api/mockttp-pluggable-admin.js.map +1 -0
  86. package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts +6 -0
  87. package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts.map +1 -0
  88. package/dist/pluggable-admin-api/pluggable-admin.browser.js +13 -0
  89. package/dist/pluggable-admin-api/pluggable-admin.browser.js.map +1 -0
  90. package/dist/pluggable-admin-api/pluggable-admin.d.ts +18 -0
  91. package/dist/pluggable-admin-api/pluggable-admin.d.ts.map +1 -0
  92. package/dist/pluggable-admin-api/pluggable-admin.js +20 -0
  93. package/dist/pluggable-admin-api/pluggable-admin.js.map +1 -0
  94. package/dist/rules/base-rule-builder.d.ts +185 -0
  95. package/dist/rules/base-rule-builder.d.ts.map +1 -0
  96. package/dist/rules/base-rule-builder.js +251 -0
  97. package/dist/rules/base-rule-builder.js.map +1 -0
  98. package/dist/rules/completion-checkers.d.ts +41 -0
  99. package/dist/rules/completion-checkers.d.ts.map +1 -0
  100. package/dist/rules/completion-checkers.js +87 -0
  101. package/dist/rules/completion-checkers.js.map +1 -0
  102. package/dist/rules/http-agents.d.ts +11 -0
  103. package/dist/rules/http-agents.d.ts.map +1 -0
  104. package/dist/rules/http-agents.js +91 -0
  105. package/dist/rules/http-agents.js.map +1 -0
  106. package/dist/rules/matchers.d.ts +214 -0
  107. package/dist/rules/matchers.d.ts.map +1 -0
  108. package/dist/rules/matchers.js +515 -0
  109. package/dist/rules/matchers.js.map +1 -0
  110. package/dist/rules/passthrough-handling-definitions.d.ts +106 -0
  111. package/dist/rules/passthrough-handling-definitions.d.ts.map +1 -0
  112. package/dist/rules/passthrough-handling-definitions.js +3 -0
  113. package/dist/rules/passthrough-handling-definitions.js.map +1 -0
  114. package/dist/rules/passthrough-handling.d.ts +33 -0
  115. package/dist/rules/passthrough-handling.d.ts.map +1 -0
  116. package/dist/rules/passthrough-handling.js +294 -0
  117. package/dist/rules/passthrough-handling.js.map +1 -0
  118. package/dist/rules/proxy-config.d.ts +76 -0
  119. package/dist/rules/proxy-config.d.ts.map +1 -0
  120. package/dist/rules/proxy-config.js +48 -0
  121. package/dist/rules/proxy-config.js.map +1 -0
  122. package/dist/rules/requests/request-handler-definitions.d.ts +600 -0
  123. package/dist/rules/requests/request-handler-definitions.d.ts.map +1 -0
  124. package/dist/rules/requests/request-handler-definitions.js +423 -0
  125. package/dist/rules/requests/request-handler-definitions.js.map +1 -0
  126. package/dist/rules/requests/request-handlers.d.ts +65 -0
  127. package/dist/rules/requests/request-handlers.d.ts.map +1 -0
  128. package/dist/rules/requests/request-handlers.js +1014 -0
  129. package/dist/rules/requests/request-handlers.js.map +1 -0
  130. package/dist/rules/requests/request-rule-builder.d.ts +255 -0
  131. package/dist/rules/requests/request-rule-builder.d.ts.map +1 -0
  132. package/dist/rules/requests/request-rule-builder.js +340 -0
  133. package/dist/rules/requests/request-rule-builder.js.map +1 -0
  134. package/dist/rules/requests/request-rule.d.ts +36 -0
  135. package/dist/rules/requests/request-rule.d.ts.map +1 -0
  136. package/dist/rules/requests/request-rule.js +100 -0
  137. package/dist/rules/requests/request-rule.js.map +1 -0
  138. package/dist/rules/rule-deserialization.d.ts +8 -0
  139. package/dist/rules/rule-deserialization.d.ts.map +1 -0
  140. package/dist/rules/rule-deserialization.js +27 -0
  141. package/dist/rules/rule-deserialization.js.map +1 -0
  142. package/dist/rules/rule-parameters.d.ts +21 -0
  143. package/dist/rules/rule-parameters.d.ts.map +1 -0
  144. package/dist/rules/rule-parameters.js +31 -0
  145. package/dist/rules/rule-parameters.js.map +1 -0
  146. package/dist/rules/rule-serialization.d.ts +7 -0
  147. package/dist/rules/rule-serialization.d.ts.map +1 -0
  148. package/dist/rules/rule-serialization.js +25 -0
  149. package/dist/rules/rule-serialization.js.map +1 -0
  150. package/dist/rules/websockets/websocket-handler-definitions.d.ts +78 -0
  151. package/dist/rules/websockets/websocket-handler-definitions.d.ts.map +1 -0
  152. package/dist/rules/websockets/websocket-handler-definitions.js +118 -0
  153. package/dist/rules/websockets/websocket-handler-definitions.js.map +1 -0
  154. package/dist/rules/websockets/websocket-handlers.d.ts +39 -0
  155. package/dist/rules/websockets/websocket-handlers.d.ts.map +1 -0
  156. package/dist/rules/websockets/websocket-handlers.js +356 -0
  157. package/dist/rules/websockets/websocket-handlers.js.map +1 -0
  158. package/dist/rules/websockets/websocket-rule-builder.d.ts +173 -0
  159. package/dist/rules/websockets/websocket-rule-builder.d.ts.map +1 -0
  160. package/dist/rules/websockets/websocket-rule-builder.js +232 -0
  161. package/dist/rules/websockets/websocket-rule-builder.js.map +1 -0
  162. package/dist/rules/websockets/websocket-rule.d.ts +34 -0
  163. package/dist/rules/websockets/websocket-rule.d.ts.map +1 -0
  164. package/dist/rules/websockets/websocket-rule.js +87 -0
  165. package/dist/rules/websockets/websocket-rule.js.map +1 -0
  166. package/dist/serialization/body-serialization.d.ts +43 -0
  167. package/dist/serialization/body-serialization.d.ts.map +1 -0
  168. package/dist/serialization/body-serialization.js +70 -0
  169. package/dist/serialization/body-serialization.js.map +1 -0
  170. package/dist/serialization/serialization.d.ts +63 -0
  171. package/dist/serialization/serialization.d.ts.map +1 -0
  172. package/dist/serialization/serialization.js +263 -0
  173. package/dist/serialization/serialization.js.map +1 -0
  174. package/dist/server/http-combo-server.d.ts +13 -0
  175. package/dist/server/http-combo-server.d.ts.map +1 -0
  176. package/dist/server/http-combo-server.js +330 -0
  177. package/dist/server/http-combo-server.js.map +1 -0
  178. package/dist/server/mocked-endpoint.d.ts +14 -0
  179. package/dist/server/mocked-endpoint.d.ts.map +1 -0
  180. package/dist/server/mocked-endpoint.js +40 -0
  181. package/dist/server/mocked-endpoint.js.map +1 -0
  182. package/dist/server/mockttp-server.d.ts +87 -0
  183. package/dist/server/mockttp-server.d.ts.map +1 -0
  184. package/dist/server/mockttp-server.js +859 -0
  185. package/dist/server/mockttp-server.js.map +1 -0
  186. package/dist/types.d.ts +359 -0
  187. package/dist/types.d.ts.map +1 -0
  188. package/dist/types.js +20 -0
  189. package/dist/types.js.map +1 -0
  190. package/dist/util/buffer-utils.d.ts +13 -0
  191. package/dist/util/buffer-utils.d.ts.map +1 -0
  192. package/dist/util/buffer-utils.js +141 -0
  193. package/dist/util/buffer-utils.js.map +1 -0
  194. package/dist/util/dns.d.ts +11 -0
  195. package/dist/util/dns.d.ts.map +1 -0
  196. package/dist/util/dns.js +47 -0
  197. package/dist/util/dns.js.map +1 -0
  198. package/dist/util/error.d.ts +9 -0
  199. package/dist/util/error.d.ts.map +1 -0
  200. package/dist/util/error.js +11 -0
  201. package/dist/util/error.js.map +1 -0
  202. package/dist/util/header-utils.d.ts +35 -0
  203. package/dist/util/header-utils.d.ts.map +1 -0
  204. package/dist/util/header-utils.js +200 -0
  205. package/dist/util/header-utils.js.map +1 -0
  206. package/dist/util/openssl-compat.d.ts +2 -0
  207. package/dist/util/openssl-compat.d.ts.map +1 -0
  208. package/dist/util/openssl-compat.js +26 -0
  209. package/dist/util/openssl-compat.js.map +1 -0
  210. package/dist/util/promise.d.ts +10 -0
  211. package/dist/util/promise.d.ts.map +1 -0
  212. package/dist/util/promise.js +25 -0
  213. package/dist/util/promise.js.map +1 -0
  214. package/dist/util/request-utils.d.ts +46 -0
  215. package/dist/util/request-utils.d.ts.map +1 -0
  216. package/dist/util/request-utils.js +462 -0
  217. package/dist/util/request-utils.js.map +1 -0
  218. package/dist/util/server-utils.d.ts +2 -0
  219. package/dist/util/server-utils.d.ts.map +1 -0
  220. package/dist/util/server-utils.js +14 -0
  221. package/dist/util/server-utils.js.map +1 -0
  222. package/dist/util/socket-util.d.ts +28 -0
  223. package/dist/util/socket-util.d.ts.map +1 -0
  224. package/dist/util/socket-util.js +174 -0
  225. package/dist/util/socket-util.js.map +1 -0
  226. package/dist/util/tls.d.ts +68 -0
  227. package/dist/util/tls.d.ts.map +1 -0
  228. package/dist/util/tls.js +220 -0
  229. package/dist/util/tls.js.map +1 -0
  230. package/dist/util/type-utils.d.ts +14 -0
  231. package/dist/util/type-utils.d.ts.map +1 -0
  232. package/dist/util/type-utils.js +3 -0
  233. package/dist/util/type-utils.js.map +1 -0
  234. package/dist/util/url.d.ts +17 -0
  235. package/dist/util/url.d.ts.map +1 -0
  236. package/dist/util/url.js +96 -0
  237. package/dist/util/url.js.map +1 -0
  238. package/dist/util/util.d.ts +8 -0
  239. package/dist/util/util.d.ts.map +1 -0
  240. package/dist/util/util.js +41 -0
  241. package/dist/util/util.js.map +1 -0
  242. package/docs/api-docs-landing-page.md +11 -0
  243. package/docs/runkitExample.js +16 -0
  244. package/docs/setup.md +136 -0
  245. package/nfyb8qx5.cjs +1 -0
  246. package/package.json +194 -4
  247. package/src/admin/admin-bin.ts +62 -0
  248. package/src/admin/admin-plugin-types.ts +29 -0
  249. package/src/admin/admin-server.ts +619 -0
  250. package/src/admin/graphql-utils.ts +28 -0
  251. package/src/admin/mockttp-admin-model.ts +264 -0
  252. package/src/admin/mockttp-admin-plugin.ts +59 -0
  253. package/src/admin/mockttp-admin-server.ts +27 -0
  254. package/src/admin/mockttp-schema.ts +222 -0
  255. package/src/client/admin-client.ts +652 -0
  256. package/src/client/admin-query.ts +52 -0
  257. package/src/client/mocked-endpoint-client.ts +32 -0
  258. package/src/client/mockttp-admin-request-builder.ts +540 -0
  259. package/src/client/mockttp-client.ts +178 -0
  260. package/src/client/schema-introspection.ts +131 -0
  261. package/src/main.browser.ts +60 -0
  262. package/src/main.ts +160 -0
  263. package/src/mockttp.ts +926 -0
  264. package/src/pluggable-admin-api/mockttp-pluggable-admin.browser.ts +7 -0
  265. package/src/pluggable-admin-api/mockttp-pluggable-admin.ts +13 -0
  266. package/src/pluggable-admin-api/pluggable-admin.browser.ts +9 -0
  267. package/src/pluggable-admin-api/pluggable-admin.ts +36 -0
  268. package/src/rules/base-rule-builder.ts +312 -0
  269. package/src/rules/completion-checkers.ts +90 -0
  270. package/src/rules/http-agents.ts +119 -0
  271. package/src/rules/matchers.ts +665 -0
  272. package/src/rules/passthrough-handling-definitions.ts +111 -0
  273. package/src/rules/passthrough-handling.ts +376 -0
  274. package/src/rules/proxy-config.ts +136 -0
  275. package/src/rules/requests/request-handler-definitions.ts +1089 -0
  276. package/src/rules/requests/request-handlers.ts +1369 -0
  277. package/src/rules/requests/request-rule-builder.ts +481 -0
  278. package/src/rules/requests/request-rule.ts +148 -0
  279. package/src/rules/rule-deserialization.ts +55 -0
  280. package/src/rules/rule-parameters.ts +41 -0
  281. package/src/rules/rule-serialization.ts +29 -0
  282. package/src/rules/websockets/websocket-handler-definitions.ts +196 -0
  283. package/src/rules/websockets/websocket-handlers.ts +509 -0
  284. package/src/rules/websockets/websocket-rule-builder.ts +275 -0
  285. package/src/rules/websockets/websocket-rule.ts +136 -0
  286. package/src/serialization/body-serialization.ts +84 -0
  287. package/src/serialization/serialization.ts +373 -0
  288. package/src/server/http-combo-server.ts +424 -0
  289. package/src/server/mocked-endpoint.ts +44 -0
  290. package/src/server/mockttp-server.ts +1110 -0
  291. package/src/types.ts +433 -0
  292. package/src/util/buffer-utils.ts +164 -0
  293. package/src/util/dns.ts +52 -0
  294. package/src/util/error.ts +18 -0
  295. package/src/util/header-utils.ts +220 -0
  296. package/src/util/openssl-compat.ts +26 -0
  297. package/src/util/promise.ts +31 -0
  298. package/src/util/request-utils.ts +607 -0
  299. package/src/util/server-utils.ts +18 -0
  300. package/src/util/socket-util.ts +193 -0
  301. package/src/util/tls.ts +348 -0
  302. package/src/util/type-utils.ts +15 -0
  303. package/src/util/url.ts +113 -0
  304. package/src/util/util.ts +39 -0
@@ -0,0 +1,481 @@
1
+ import { merge, isString, isBuffer } from "lodash";
2
+ import { Readable } from "stream";
3
+
4
+ import { Headers, CompletedRequest, Method, MockedEndpoint, Trailers } from "../../types";
5
+ import type { RequestRuleData } from "./request-rule";
6
+
7
+ import {
8
+ SimpleHandlerDefinition,
9
+ PassThroughHandlerDefinition,
10
+ CallbackHandlerDefinition,
11
+ CallbackResponseResult,
12
+ StreamHandlerDefinition,
13
+ CloseConnectionHandlerDefinition,
14
+ TimeoutHandlerDefinition,
15
+ PassThroughHandlerOptions,
16
+ FileHandlerDefinition,
17
+ JsonRpcResponseHandlerDefinition,
18
+ ResetConnectionHandlerDefinition,
19
+ CallbackResponseMessageResult
20
+ } from "./request-handler-definitions";
21
+ import { MaybePromise } from "../../util/type-utils";
22
+ import { byteLength } from "../../util/util";
23
+ import { BaseRuleBuilder } from "../base-rule-builder";
24
+ import { MethodMatcher, RegexPathMatcher, SimplePathMatcher, WildcardMatcher } from "../matchers";
25
+
26
+ /**
27
+ * @class RequestRuleBuilder
28
+
29
+ * A builder for defining mock rules. Create one using a method like
30
+ * `.forGet(path)` or `.forPost(path)` on a Mockttp instance, then call
31
+ * whatever methods you'd like here to define more precise request
32
+ * matching behaviour, control how the request is handled, and how
33
+ * many times this rule should be applied.
34
+ *
35
+ * When you're done, call a `.thenX()` method to register the configured rule
36
+ * with the server. These return a promise for a MockedEndpoint, which can be
37
+ * used to verify the details of the requests matched by the rule.
38
+ *
39
+ * This returns a promise because rule registration can be asynchronous,
40
+ * either when using a remote server or testing in the browser. Wait for the
41
+ * promise returned by `.thenX()` methods to guarantee that the rule has taken
42
+ * effect before sending requests to it.
43
+ */
44
+ export class RequestRuleBuilder extends BaseRuleBuilder {
45
+
46
+ private addRule: (rule: RequestRuleData) => Promise<MockedEndpoint>;
47
+
48
+ /**
49
+ * Mock rule builders should be constructed through the Mockttp instance you're
50
+ * using, not directly. You shouldn't ever need to call this constructor.
51
+ */
52
+ constructor(addRule: (rule: RequestRuleData) => Promise<MockedEndpoint>)
53
+ constructor(
54
+ method: Method,
55
+ path: string | RegExp | undefined,
56
+ addRule: (rule: RequestRuleData) => Promise<MockedEndpoint>
57
+ )
58
+ constructor(
59
+ methodOrAddRule: Method | ((rule: RequestRuleData) => Promise<MockedEndpoint>),
60
+ path?: string | RegExp,
61
+ addRule?: (rule: RequestRuleData) => Promise<MockedEndpoint>
62
+ ) {
63
+ super();
64
+
65
+ // Add the basic method and path matchers inititally, if provided:
66
+ const method = methodOrAddRule instanceof Function ? undefined : methodOrAddRule;
67
+ if (method === undefined && path === undefined) {
68
+ this.matchers.push(new WildcardMatcher());
69
+ } else {
70
+ if (method !== undefined) {
71
+ this.matchers.push(new MethodMatcher(method));
72
+ }
73
+
74
+ if (path instanceof RegExp) {
75
+ this.matchers.push(new RegexPathMatcher(path));
76
+ } else if (typeof path === 'string') {
77
+ this.matchers.push(new SimplePathMatcher(path));
78
+ }
79
+ }
80
+
81
+ // Store the addRule callback:
82
+ if (methodOrAddRule instanceof Function) {
83
+ this.addRule = methodOrAddRule;
84
+ } else {
85
+ this.addRule = addRule!;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Reply to matched requests with a given status code and (optionally) status message,
91
+ * body, headers & trailers.
92
+ *
93
+ * If one string argument is provided, it's used as the body. If two are
94
+ * provided (even if one is empty) then the 1st is the status message, and
95
+ * the 2nd the body. If no headers are provided, only the standard required
96
+ * headers are set, e.g. Date and Transfer-Encoding.
97
+ *
98
+ * Calling this method registers the rule with the server, so it
99
+ * starts to handle requests.
100
+ *
101
+ * This method returns a promise that resolves with a mocked endpoint.
102
+ * Wait for the promise to confirm that the rule has taken effect
103
+ * before sending requests to be matched. The mocked endpoint
104
+ * can be used to assert on the requests matched by this rule.
105
+ *
106
+ * @category Responses
107
+ */
108
+ thenReply(
109
+ status: number,
110
+ data?: string | Buffer,
111
+ headers?: Headers,
112
+ trailers?: Trailers
113
+ ): Promise<MockedEndpoint>;
114
+ thenReply(
115
+ status: number,
116
+ statusMessage: string,
117
+ data: string | Buffer,
118
+ headers?: Headers,
119
+ trailers?: Trailers
120
+ ): Promise<MockedEndpoint>
121
+ thenReply(
122
+ status: number,
123
+ dataOrMessage?: string | Buffer,
124
+ dataOrHeaders?: string | Buffer | Headers,
125
+ headersOrTrailers?: Headers | Trailers,
126
+ trailers?: Trailers
127
+ ): Promise<MockedEndpoint> {
128
+ let data: string | Buffer | undefined;
129
+ let statusMessage: string | undefined;
130
+ let headers: Headers | undefined;
131
+
132
+ if (isBuffer(dataOrHeaders) || isString(dataOrHeaders)) {
133
+ data = dataOrHeaders as (Buffer | string);
134
+ statusMessage = dataOrMessage as string;
135
+ headers = headersOrTrailers as Headers;
136
+ } else {
137
+ data = dataOrMessage as string | Buffer | undefined;
138
+ headers = dataOrHeaders as Headers | undefined;
139
+ trailers = headersOrTrailers as Trailers | undefined;
140
+ }
141
+
142
+ const rule: RequestRuleData = {
143
+ ...this.buildBaseRuleData(),
144
+ handler: new SimpleHandlerDefinition(
145
+ status,
146
+ statusMessage,
147
+ data,
148
+ headers,
149
+ trailers
150
+ )
151
+ };
152
+
153
+ return this.addRule(rule);
154
+ }
155
+
156
+ /**
157
+ * Reply to matched requests with the given status & JSON and (optionally)
158
+ * extra headers.
159
+ *
160
+ * This method is (approximately) shorthand for:
161
+ * server.forGet(...).thenReply(status, JSON.stringify(data), { 'Content-Type': 'application/json' })
162
+ *
163
+ * Calling this method registers the rule with the server, so it
164
+ * starts to handle requests.
165
+ *
166
+ * This method returns a promise that resolves with a mocked endpoint.
167
+ * Wait for the promise to confirm that the rule has taken effect
168
+ * before sending requests to be matched. The mocked endpoint
169
+ * can be used to assert on the requests matched by this rule.
170
+ *
171
+ * @category Responses
172
+ */
173
+ thenJson(status: number, data: object, headers: Headers = {}): Promise<MockedEndpoint> {
174
+ const jsonData = JSON.stringify(data);
175
+
176
+ headers = merge({
177
+ 'Content-Type': 'application/json',
178
+
179
+ 'Content-Length': byteLength(jsonData).toString(),
180
+ 'Connection': 'keep-alive'
181
+ // ^ Neither strictly required, but without both Node will close the server
182
+ // connection after the response is sent, which can confuse clients.
183
+ }, headers);
184
+
185
+ const rule: RequestRuleData = {
186
+ ...this.buildBaseRuleData(),
187
+ handler: new SimpleHandlerDefinition(status, undefined, jsonData, headers)
188
+ };
189
+
190
+ return this.addRule(rule);
191
+ }
192
+
193
+ /**
194
+ * Call the given callback for any matched requests that are received,
195
+ * and build a response from the result.
196
+ *
197
+ * The callback should return a response object with the fields as
198
+ * defined by {@link CallbackResponseMessageResult} to define the response,
199
+ * or the string 'close' to immediately close the connection. The callback
200
+ * can be asynchronous, in which case it should return this value wrapped
201
+ * in a promise.
202
+ *
203
+ * If the callback throws an exception, the server will return a 500
204
+ * with the exception message.
205
+ *
206
+ * Calling this method registers the rule with the server, so it
207
+ * starts to handle requests.
208
+ *
209
+ * This method returns a promise that resolves with a mocked endpoint.
210
+ * Wait for the promise to confirm that the rule has taken effect
211
+ * before sending requests to be matched. The mocked endpoint
212
+ * can be used to assert on the requests matched by this rule.
213
+ *
214
+ * @category Responses
215
+ */
216
+ thenCallback(callback:
217
+ (request: CompletedRequest) => MaybePromise<CallbackResponseResult>
218
+ ): Promise<MockedEndpoint> {
219
+ const rule: RequestRuleData = {
220
+ ...this.buildBaseRuleData(),
221
+ handler: new CallbackHandlerDefinition(callback)
222
+ }
223
+
224
+ return this.addRule(rule);
225
+ }
226
+
227
+ /**
228
+ * Respond immediately with the given status (and optionally, headers),
229
+ * and then stream the given stream directly as the response body.
230
+ *
231
+ * Note that streams can typically only be read once, and as such
232
+ * this rule will only successfully trigger once. Subsequent requests
233
+ * will receive a 500 and an explanatory error message. To mock
234
+ * repeated requests with streams, create multiple streams and mock
235
+ * them independently.
236
+ *
237
+ * Calling this method registers the rule with the server, so it
238
+ * starts to handle requests.
239
+ *
240
+ * This method returns a promise that resolves with a mocked endpoint.
241
+ * Wait for the promise to confirm that the rule has taken effect
242
+ * before sending requests to be matched. The mocked endpoint
243
+ * can be used to assert on the requests matched by this rule.
244
+ *
245
+ * @category Responses
246
+ */
247
+ thenStream(status: number, stream: Readable, headers?: Headers): Promise<MockedEndpoint> {
248
+ const rule: RequestRuleData = {
249
+ ...this.buildBaseRuleData(),
250
+ handler: new StreamHandlerDefinition(status, stream, headers)
251
+ }
252
+
253
+ return this.addRule(rule);
254
+ }
255
+
256
+ /**
257
+ * Reply to matched requests with a given status code and the current contents
258
+ * of a given file. The status message and headers can also be optionally
259
+ * provided here. If no headers are provided, only the standard required
260
+ * headers are set.
261
+ *
262
+ * The file is read near-fresh for each request, and external changes to its
263
+ * content will be immediately appear in all subsequent requests.
264
+ *
265
+ * If one string argument is provided, it's used as the body file path.
266
+ * If two are provided (even if one is empty), then 1st is the status message,
267
+ * and the 2nd the body. This matches the argument order of thenReply().
268
+ *
269
+ * Calling this method registers the rule with the server, so it
270
+ * starts to handle requests.
271
+ *
272
+ * This method returns a promise that resolves with a mocked endpoint.
273
+ * Wait for the promise to confirm that the rule has taken effect
274
+ * before sending requests to be matched. The mocked endpoint
275
+ * can be used to assert on the requests matched by this rule.
276
+ *
277
+ * @category Responses
278
+ */
279
+ thenFromFile(status: number, filePath: string, headers?: Headers): Promise<MockedEndpoint>;
280
+ thenFromFile(status: number, statusMessage: string, filePath: string, headers?: Headers): Promise<MockedEndpoint>
281
+ thenFromFile(
282
+ status: number,
283
+ pathOrMessage: string,
284
+ pathOrHeaders?: string | Headers,
285
+ headers?: Headers
286
+ ): Promise<MockedEndpoint> {
287
+ let path: string;
288
+ let statusMessage: string | undefined;
289
+ if (isString(pathOrHeaders)) {
290
+ path = pathOrHeaders;
291
+ statusMessage = pathOrMessage as string;
292
+ } else {
293
+ path = pathOrMessage;
294
+ headers = pathOrHeaders as Headers | undefined;
295
+ }
296
+
297
+ const rule: RequestRuleData = {
298
+ ...this.buildBaseRuleData(),
299
+ handler: new FileHandlerDefinition(status, statusMessage, path, headers)
300
+ };
301
+
302
+ return this.addRule(rule);
303
+ }
304
+
305
+ /**
306
+ * Pass matched requests through to their real destination. This works
307
+ * for proxied requests only, direct requests will be rejected with
308
+ * an error.
309
+ *
310
+ * This method takes options to configure how the request is passed
311
+ * through. See {@link PassThroughHandlerOptions} for the full details
312
+ * of the options available.
313
+ *
314
+ * Calling this method registers the rule with the server, so it
315
+ * starts to handle requests.
316
+ *
317
+ * This method returns a promise that resolves with a mocked endpoint.
318
+ * Wait for the promise to confirm that the rule has taken effect
319
+ * before sending requests to be matched. The mocked endpoint
320
+ * can be used to assert on the requests matched by this rule.
321
+ *
322
+ * @category Responses
323
+ */
324
+ thenPassThrough(options?: PassThroughHandlerOptions): Promise<MockedEndpoint> {
325
+ const rule: RequestRuleData = {
326
+ ...this.buildBaseRuleData(),
327
+ handler: new PassThroughHandlerDefinition(options)
328
+ };
329
+
330
+ return this.addRule(rule);
331
+ }
332
+
333
+ /**
334
+ * Forward matched requests on to the specified forwardToUrl. The url
335
+ * specified must not include a path. Otherwise, an error is thrown.
336
+ * The path portion of the original request url is used instead.
337
+ *
338
+ * The url may optionally contain a protocol. If it does, it will override
339
+ * the protocol (and potentially the port, if unspecified) of the request.
340
+ * If no protocol is specified, the protocol (and potentially the port)
341
+ * of the original request URL will be used instead.
342
+ *
343
+ * This method takes options to configure how the request is passed
344
+ * through. See {@link PassThroughHandlerOptions} for the full details
345
+ * of the options available.
346
+ *
347
+ * Calling this method registers the rule with the server, so it
348
+ * starts to handle requests.
349
+ *
350
+ * This method returns a promise that resolves with a mocked endpoint.
351
+ * Wait for the promise to confirm that the rule has taken effect
352
+ * before sending requests to be matched. The mocked endpoint
353
+ * can be used to assert on the requests matched by this rule.
354
+ *
355
+ * @category Responses
356
+ */
357
+ async thenForwardTo(
358
+ forwardToLocation: string,
359
+ options: Omit<PassThroughHandlerOptions, 'forwarding'> & {
360
+ forwarding?: Omit<PassThroughHandlerOptions['forwarding'], 'targetHost'>
361
+ } = {}
362
+ ): Promise<MockedEndpoint> {
363
+ const rule: RequestRuleData = {
364
+ ...this.buildBaseRuleData(),
365
+ handler: new PassThroughHandlerDefinition({
366
+ ...options,
367
+ forwarding: {
368
+ ...options.forwarding,
369
+ targetHost: forwardToLocation
370
+ }
371
+ })
372
+ };
373
+
374
+ return this.addRule(rule);
375
+ }
376
+
377
+ /**
378
+ * Close connections that match this rule immediately, without
379
+ * any status code or response.
380
+ *
381
+ * Calling this method registers the rule with the server, so it
382
+ * starts to handle requests.
383
+ *
384
+ * This method returns a promise that resolves with a mocked endpoint.
385
+ * Wait for the promise to confirm that the rule has taken effect
386
+ * before sending requests to be matched. The mocked endpoint
387
+ * can be used to assert on the requests matched by this rule.
388
+ *
389
+ * @category Responses
390
+ */
391
+ thenCloseConnection(): Promise<MockedEndpoint> {
392
+ const rule: RequestRuleData = {
393
+ ...this.buildBaseRuleData(),
394
+ handler: new CloseConnectionHandlerDefinition()
395
+ };
396
+
397
+ return this.addRule(rule);
398
+ }
399
+
400
+ /**
401
+ * Reset connections that match this rule immediately, sending a TCP
402
+ * RST packet directly, without any status code or response, and without
403
+ * cleanly closing the TCP connection.
404
+ *
405
+ * This is only supported in Node.js versions (>=16.17, >=18.3.0, or
406
+ * later), where `net.Socket` includes the `resetAndDestroy` method.
407
+ *
408
+ * Calling this method registers the rule with the server, so it
409
+ * starts to handle requests.
410
+ *
411
+ * This method returns a promise that resolves with a mocked endpoint.
412
+ * Wait for the promise to confirm that the rule has taken effect
413
+ * before sending requests to be matched. The mocked endpoint
414
+ * can be used to assert on the requests matched by this rule.
415
+ *
416
+ * @category Responses
417
+ */
418
+ thenResetConnection(): Promise<MockedEndpoint> {
419
+ const rule: RequestRuleData = {
420
+ ...this.buildBaseRuleData(),
421
+ handler: new ResetConnectionHandlerDefinition()
422
+ };
423
+
424
+ return this.addRule(rule);
425
+ }
426
+
427
+ /**
428
+ * Hold open connections that match this rule, but never respond
429
+ * with anything at all, typically causing a timeout on the client side.
430
+ *
431
+ * Calling this method registers the rule with the server, so it
432
+ * starts to handle requests.
433
+ *
434
+ * This method returns a promise that resolves with a mocked endpoint.
435
+ * Wait for the promise to confirm that the rule has taken effect
436
+ * before sending requests to be matched. The mocked endpoint
437
+ * can be used to assert on the requests matched by this rule.
438
+ *
439
+ * @category Responses
440
+ */
441
+ thenTimeout(): Promise<MockedEndpoint> {
442
+ const rule: RequestRuleData = {
443
+ ...this.buildBaseRuleData(),
444
+ handler: new TimeoutHandlerDefinition()
445
+ };
446
+
447
+ return this.addRule(rule);
448
+ }
449
+
450
+ /**
451
+ * Send a successful JSON-RPC response to a JSON-RPC request. The response data
452
+ * can be any JSON-serializable value. If a matching request is received that
453
+ * is not a valid JSON-RPC request, it will be rejected with an HTTP error.
454
+ *
455
+ * @category Responses
456
+ */
457
+ thenSendJsonRpcResult(result: any) {
458
+ const rule = {
459
+ ...this.buildBaseRuleData(),
460
+ handler: new JsonRpcResponseHandlerDefinition({ result })
461
+ };
462
+
463
+ return this.addRule(rule);
464
+ }
465
+
466
+ /**
467
+ * Send a failing error JSON-RPC response to a JSON-RPC request. The error data
468
+ * can be any JSON-serializable value. If a matching request is received that
469
+ * is not a valid JSON-RPC request, it will be rejected with an HTTP error.
470
+ *
471
+ * @category Responses
472
+ */
473
+ thenSendJsonRpcError(error: any) {
474
+ const rule = {
475
+ ...this.buildBaseRuleData(),
476
+ handler: new JsonRpcResponseHandlerDefinition({ error })
477
+ };
478
+
479
+ return this.addRule(rule);
480
+ }
481
+ }
@@ -0,0 +1,148 @@
1
+ import * as _ from 'lodash';
2
+ import { v4 as uuid } from "uuid";
3
+
4
+ import { OngoingRequest, CompletedRequest, OngoingResponse, Explainable, RulePriority } from "../../types";
5
+ import { buildBodyReader, buildInitiatedRequest, waitForCompletedRequest } from '../../util/request-utils';
6
+ import { MaybePromise } from '../../util/type-utils';
7
+
8
+ import * as matchers from "../matchers";
9
+ import type { RequestHandlerDefinition } from "./request-handler-definitions";
10
+ import { HandlerLookup, RequestHandler } from "./request-handlers";
11
+ import * as completionCheckers from "../completion-checkers";
12
+ import { validateMockRuleData } from '../rule-serialization';
13
+
14
+ // The internal representation of a mocked endpoint
15
+ export interface RequestRule extends Explainable {
16
+ id: string;
17
+ requests: Promise<CompletedRequest>[];
18
+
19
+ // We don't extend the main interfaces for these, because MockRules are not Serializable
20
+ matches(request: OngoingRequest): MaybePromise<boolean>;
21
+ handle(request: OngoingRequest, response: OngoingResponse, options: {
22
+ record: boolean,
23
+ emitEventCallback?: (type: string, event: unknown) => void
24
+ }): Promise<void>;
25
+ isComplete(): boolean | null;
26
+ }
27
+
28
+ export interface RequestRuleData {
29
+ id?: string;
30
+ priority?: number; // Higher is higher, by default 0 is fallback, 1 is normal, must be positive
31
+ matchers: matchers.RequestMatcher[];
32
+ handler: RequestHandler | RequestHandlerDefinition;
33
+ completionChecker?: completionCheckers.RuleCompletionChecker;
34
+ }
35
+
36
+ export class RequestRule implements RequestRule {
37
+ private matchers: matchers.RequestMatcher[];
38
+ private handler: RequestHandler;
39
+ private completionChecker?: completionCheckers.RuleCompletionChecker;
40
+
41
+ public id: string;
42
+ public readonly priority: number;
43
+ public requests: Promise<CompletedRequest>[] = [];
44
+ public requestCount = 0;
45
+
46
+ constructor(data: RequestRuleData) {
47
+ validateMockRuleData(data);
48
+
49
+ this.id = data.id || uuid();
50
+ this.priority = data.priority ?? RulePriority.DEFAULT;
51
+ this.matchers = data.matchers;
52
+ this.completionChecker = data.completionChecker;
53
+
54
+ if ('handle' in data.handler) {
55
+ this.handler = data.handler;
56
+ } else {
57
+ // We transform the definition into a real handler, by creating an instance of the raw handler (which is
58
+ // a subtype of the definition with the same constructor) and copying the fields across.
59
+ this.handler = Object.assign(
60
+ Object.create(HandlerLookup[data.handler.type].prototype),
61
+ data.handler
62
+ );
63
+ }
64
+ }
65
+
66
+ matches(request: OngoingRequest) {
67
+ return matchers.matchesAll(request, this.matchers);
68
+ }
69
+
70
+ handle(req: OngoingRequest, res: OngoingResponse, options: {
71
+ record?: boolean,
72
+ emitEventCallback?: (type: string, event: unknown) => void
73
+ }): Promise<void> {
74
+ let handlerPromise = (async () => { // Catch (a)sync errors
75
+ return this.handler.handle(req, res, {
76
+ emitEventCallback: options.emitEventCallback
77
+ });
78
+ })();
79
+
80
+ // Requests are added to rule.requests as soon as they start being handled,
81
+ // as promises, which resolve only when the response & request body is complete.
82
+ if (options.record) {
83
+ this.requests.push(
84
+ Promise.race([
85
+ // When the handler resolves, the request is completed:
86
+ handlerPromise,
87
+ // If the response is closed before the handler completes (due to aborts, handler
88
+ // timeouts, whatever) then that also counts as the request being completed:
89
+ new Promise((resolve) => res.on('close', resolve))
90
+ ])
91
+ .catch(() => {}) // Ignore handler errors here - we're only tracking the request
92
+ .then(() => waitForCompletedRequest(req))
93
+ .catch((): CompletedRequest => {
94
+ // If for some reason the request is not completed, we still want to record it.
95
+ // TODO: Update the body to return the data that has been received so far.
96
+ const initiatedRequest = buildInitiatedRequest(req);
97
+ return {
98
+ ...initiatedRequest,
99
+ body: buildBodyReader(Buffer.from([]), req.headers),
100
+ rawTrailers: [],
101
+ trailers: {}
102
+ };
103
+ })
104
+ );
105
+ }
106
+
107
+ // Even if traffic recording is disabled, the number of matched
108
+ // requests is still tracked
109
+ this.requestCount += 1;
110
+
111
+ return handlerPromise as Promise<any>;
112
+ }
113
+
114
+ isComplete(): boolean | null {
115
+ if (this.completionChecker) {
116
+ // If we have a specific rule, use that
117
+ return this.completionChecker.isComplete(this.requestCount);
118
+ } else if (this.requestCount === 0) {
119
+ // Otherwise, by default we're definitely incomplete if we've seen no requests
120
+ return false;
121
+ } else {
122
+ // And we're _maybe_ complete if we've seen at least one request. In reality, we're incomplete
123
+ // but we should be used anyway if we're at any point we're the last matching rule for a request.
124
+ return null;
125
+ }
126
+ }
127
+
128
+ explain(withoutExactCompletion = false): string {
129
+ let explanation = `Match requests ${matchers.explainMatchers(this.matchers)}, ` +
130
+ `and then ${this.handler.explain()}`;
131
+
132
+ if (this.completionChecker) {
133
+ explanation += `, ${this.completionChecker.explain(
134
+ withoutExactCompletion ? undefined : this.requestCount
135
+ )}.`;
136
+ } else {
137
+ explanation += '.';
138
+ }
139
+
140
+ return explanation;
141
+ }
142
+
143
+ dispose() {
144
+ this.handler.dispose();
145
+ this.matchers.forEach(m => m.dispose());
146
+ if (this.completionChecker) this.completionChecker.dispose();
147
+ }
148
+ }
@@ -0,0 +1,55 @@
1
+ import { Duplex } from "stream";
2
+
3
+ import { Serialized, deserialize } from "../serialization/serialization";
4
+
5
+ import type { RuleParameters } from "./rule-parameters";
6
+
7
+ import type { RequestRuleData } from "./requests/request-rule";
8
+ import type { WebSocketRuleData } from "./websockets/websocket-rule";
9
+
10
+ import * as matchers from "./matchers";
11
+ import * as completionCheckers from "./completion-checkers";
12
+
13
+ import { HandlerLookup } from "./requests/request-handlers";
14
+ import { WsHandlerLookup } from './websockets/websocket-handlers';
15
+
16
+ export function deserializeRuleData(
17
+ data: Serialized<RequestRuleData>,
18
+ stream: Duplex,
19
+ ruleParameters: RuleParameters
20
+ ): RequestRuleData {
21
+ return {
22
+ id: data.id,
23
+ priority: data.priority,
24
+ matchers: data.matchers.map((m) =>
25
+ deserialize(m, stream, ruleParameters, matchers.MatcherLookup)
26
+ ),
27
+ handler: deserialize(data.handler, stream, ruleParameters, HandlerLookup),
28
+ completionChecker: data.completionChecker && deserialize(
29
+ data.completionChecker,
30
+ stream,
31
+ ruleParameters,
32
+ completionCheckers.CompletionCheckerLookup
33
+ )
34
+ };
35
+ }
36
+
37
+ export function deserializeWebSocketRuleData(
38
+ data: Serialized<WebSocketRuleData>,
39
+ stream: Duplex,
40
+ ruleParameters: RuleParameters
41
+ ): WebSocketRuleData {
42
+ return {
43
+ id: data.id,
44
+ matchers: data.matchers.map((m) =>
45
+ deserialize(m, stream, ruleParameters, matchers.MatcherLookup)
46
+ ),
47
+ handler: deserialize(data.handler, stream, ruleParameters, WsHandlerLookup),
48
+ completionChecker: data.completionChecker && deserialize(
49
+ data.completionChecker,
50
+ stream,
51
+ ruleParameters,
52
+ completionCheckers.CompletionCheckerLookup
53
+ )
54
+ };
55
+ }