@schmock/core 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AA4EA;;;;GAIG;AACH,qBAAa,oBAAoB;IAWnB,OAAO,CAAC,YAAY;IAVhC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,WAAW,CAA2C;IAC9D,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,SAAS,CAAmD;gBAEhD,YAAY,GAAE,OAAO,CAAC,YAAiB;IAa3D,WAAW,CACT,KAAK,EAAE,OAAO,CAAC,QAAQ,EACvB,SAAS,EAAE,OAAO,CAAC,SAAS,EAC5B,MAAM,EAAE,OAAO,CAAC,WAAW,GAC1B,IAAI;IAqFP,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,oBAAoB,GAAG,IAAI;IAIvD,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI;IAoBlC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE;IAS5E,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;IAS3D,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAS7D,WAAW,CACT,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAC3B,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,GAAG,SAAS;IAYpC,SAAS,IAAI,OAAO,CAAC,SAAS,EAAE;IAQhC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAMnC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAU1D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAK3D,OAAO,CAAC,IAAI;IAWZ,KAAK,IAAI,IAAI;IAeb,YAAY,IAAI,IAAI;IAKpB,UAAU,IAAI,IAAI;IAWlB,MAAM,CAAC,IAAI,SAAI,EAAE,QAAQ,SAAc,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;IAmFrE,KAAK,IAAI,IAAI;IAUP,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,UAAU,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,GAC/B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;IAgN5B;;;;OAIG;YACW,UAAU;IAgBxB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAwDrB;;;;;;;;;;OAUG;YACW,iBAAiB;IAqG/B;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;IA0BjB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;CActB"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAkFA;;;;GAIG;AACH,qBAAa,oBAAoB;IAWnB,OAAO,CAAC,YAAY;IAVhC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,WAAW,CAA2C;IAC9D,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,SAAS,CAAmD;gBAEhD,YAAY,GAAE,OAAO,CAAC,YAAiB;IAa3D,WAAW,CACT,KAAK,EAAE,OAAO,CAAC,QAAQ,EACvB,SAAS,EAAE,OAAO,CAAC,SAAS,EAC5B,MAAM,EAAE,OAAO,CAAC,WAAW,GAC1B,IAAI;IAqFP,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,oBAAoB,GAAG,IAAI;IAIvD,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI;IAoBlC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE;IAS5E,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;IAS3D,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAS7D,WAAW,CACT,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,EAC3B,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,GAAG,SAAS;IAYpC,SAAS,IAAI,OAAO,CAAC,SAAS,EAAE;IAQhC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAMnC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAU1D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAK3D,OAAO,CAAC,IAAI;IAWZ,KAAK,IAAI,IAAI;IAeb,YAAY,IAAI,IAAI;IAKpB,UAAU,IAAI,IAAI;IAWlB,MAAM,CAAC,IAAI,SAAI,EAAE,QAAQ,SAAc,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;IAuCrE,KAAK,IAAI,IAAI;IAUP,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,UAAU,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,GAC/B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;IAgN5B;;;;OAIG;YACW,UAAU;IAgBxB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAwDrB;;;;;;;;;;OAUG;YACW,iBAAiB;IAqG/B;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;IA0BjB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;CActB"}
package/dist/builder.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createServer } from "node:http";
2
2
  import { isStatusTuple, toHttpMethod } from "./constants.js";
3
3
  import { PluginError, RouteDefinitionError, RouteNotFoundError, SchmockError, } from "./errors.js";
4
+ import { collectBody, parseNodeHeaders, parseNodeQuery, writeSchmockResponse, } from "./http-helpers.js";
4
5
  import { parseRouteKey } from "./parser.js";
5
6
  function errorMessage(error) {
6
7
  return error instanceof Error ? error.message : "Unknown error";
@@ -252,51 +253,11 @@ export class CallableMockInstance {
252
253
  const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
253
254
  const method = toHttpMethod(req.method ?? "GET");
254
255
  const path = url.pathname;
255
- const headers = {};
256
- for (const [key, value] of Object.entries(req.headers)) {
257
- if (typeof value === "string") {
258
- headers[key] = value;
259
- }
260
- }
261
- const query = {};
262
- url.searchParams.forEach((value, key) => {
263
- query[key] = value;
264
- });
265
- const chunks = [];
266
- req.on("data", (chunk) => chunks.push(chunk));
267
- req.on("end", () => {
268
- const raw = Buffer.concat(chunks).toString();
269
- let body;
270
- const contentType = headers["content-type"] ?? "";
271
- if (raw && contentType.includes("json")) {
272
- try {
273
- body = JSON.parse(raw);
274
- }
275
- catch {
276
- body = raw;
277
- }
278
- }
279
- else if (raw) {
280
- body = raw;
281
- }
282
- void this.handle(method, path, { headers, body, query }).then((schmockResponse) => {
283
- const responseHeaders = {
284
- ...schmockResponse.headers,
285
- };
286
- if (!responseHeaders["content-type"] &&
287
- schmockResponse.body !== undefined &&
288
- typeof schmockResponse.body !== "string") {
289
- responseHeaders["content-type"] = "application/json";
290
- }
291
- const responseBody = schmockResponse.body === undefined
292
- ? undefined
293
- : typeof schmockResponse.body === "string"
294
- ? schmockResponse.body
295
- : JSON.stringify(schmockResponse.body);
296
- res.writeHead(schmockResponse.status, responseHeaders);
297
- res.end(responseBody);
298
- });
299
- });
256
+ const headers = parseNodeHeaders(req);
257
+ const query = parseNodeQuery(url);
258
+ void collectBody(req, headers).then((body) => this.handle(method, path, { headers, body, query }).then((schmockResponse) => {
259
+ writeSchmockResponse(res, schmockResponse);
260
+ }));
300
261
  });
301
262
  this.server = httpServer;
302
263
  return new Promise((resolve, reject) => {
@@ -0,0 +1,22 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ /**
3
+ * Convert Node.js IncomingMessage headers to a flat Record<string, string>.
4
+ * Drops array-valued headers (keeps only string values).
5
+ */
6
+ export declare function parseNodeHeaders(req: IncomingMessage): Record<string, string>;
7
+ /**
8
+ * Extract query parameters from a URL as a flat Record<string, string>.
9
+ */
10
+ export declare function parseNodeQuery(url: URL): Record<string, string>;
11
+ /**
12
+ * Collect and parse the request body from a Node.js IncomingMessage.
13
+ * Returns parsed JSON if content-type includes "json", otherwise the raw string.
14
+ * Returns undefined for empty bodies.
15
+ */
16
+ export declare function collectBody(req: IncomingMessage, headers: Record<string, string>): Promise<unknown>;
17
+ /**
18
+ * Write a Schmock Response to a Node.js ServerResponse.
19
+ * Serializes non-string bodies as JSON and sets content-type when missing.
20
+ */
21
+ export declare function writeSchmockResponse(res: ServerResponse, response: Schmock.Response, extraHeaders?: Record<string, string>): void;
22
+ //# sourceMappingURL=http-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-helpers.d.ts","sourceRoot":"","sources":["../src/http-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAM/D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,OAAO,CAAC,CAsBlB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,IAAI,CAuBN"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Convert Node.js IncomingMessage headers to a flat Record<string, string>.
3
+ * Drops array-valued headers (keeps only string values).
4
+ */
5
+ export function parseNodeHeaders(req) {
6
+ const headers = {};
7
+ for (const [key, value] of Object.entries(req.headers)) {
8
+ if (typeof value === "string") {
9
+ headers[key] = value;
10
+ }
11
+ }
12
+ return headers;
13
+ }
14
+ /**
15
+ * Extract query parameters from a URL as a flat Record<string, string>.
16
+ */
17
+ export function parseNodeQuery(url) {
18
+ const query = {};
19
+ url.searchParams.forEach((value, key) => {
20
+ query[key] = value;
21
+ });
22
+ return query;
23
+ }
24
+ /**
25
+ * Collect and parse the request body from a Node.js IncomingMessage.
26
+ * Returns parsed JSON if content-type includes "json", otherwise the raw string.
27
+ * Returns undefined for empty bodies.
28
+ */
29
+ export function collectBody(req, headers) {
30
+ return new Promise((resolve) => {
31
+ const chunks = [];
32
+ req.on("data", (chunk) => chunks.push(chunk));
33
+ req.on("end", () => {
34
+ const raw = Buffer.concat(chunks).toString();
35
+ if (!raw) {
36
+ resolve(undefined);
37
+ return;
38
+ }
39
+ const contentType = headers["content-type"] ?? "";
40
+ if (contentType.includes("json")) {
41
+ try {
42
+ resolve(JSON.parse(raw));
43
+ }
44
+ catch {
45
+ resolve(raw);
46
+ }
47
+ }
48
+ else {
49
+ resolve(raw);
50
+ }
51
+ });
52
+ });
53
+ }
54
+ /**
55
+ * Write a Schmock Response to a Node.js ServerResponse.
56
+ * Serializes non-string bodies as JSON and sets content-type when missing.
57
+ */
58
+ export function writeSchmockResponse(res, response, extraHeaders) {
59
+ const responseHeaders = {
60
+ ...response.headers,
61
+ ...extraHeaders,
62
+ };
63
+ if (!responseHeaders["content-type"] &&
64
+ response.body !== undefined &&
65
+ typeof response.body !== "string") {
66
+ responseHeaders["content-type"] = "application/json";
67
+ }
68
+ const responseBody = response.body === undefined
69
+ ? undefined
70
+ : typeof response.body === "string"
71
+ ? response.body
72
+ : JSON.stringify(response.body);
73
+ res.writeHead(response.status, responseHeaders);
74
+ res.end(responseBody);
75
+ }
package/dist/index.d.ts CHANGED
@@ -24,5 +24,6 @@
24
24
  export declare function schmock(config?: Schmock.GlobalConfig): Schmock.CallableMockInstance;
25
25
  export { HTTP_METHODS, isHttpMethod, isStatusTuple, ROUTE_NOT_FOUND_CODE, toHttpMethod, } from "./constants.js";
26
26
  export { PluginError, ResourceLimitError, ResponseGenerationError, RouteDefinitionError, RouteNotFoundError, RouteParseError, SchemaGenerationError, SchemaValidationError, SchmockError, } from "./errors.js";
27
+ export { collectBody, parseNodeHeaders, parseNodeQuery, writeSchmockResponse, } from "./http-helpers.js";
27
28
  export type { CallableMockInstance, Generator, GeneratorFunction, GlobalConfig, HttpMethod, Plugin, PluginContext, PluginResult, RequestContext, RequestOptions, RequestRecord, Response, ResponseBody, ResponseResult, RouteConfig, RouteInfo, RouteKey, ServerInfo, StaticData, } from "./types.js";
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CACrB,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,GAC5B,OAAO,CAAC,oBAAoB,CA6C9B;AAGD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,MAAM,EACN,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,WAAW,EACX,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CACrB,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,GAC5B,OAAO,CAAC,oBAAoB,CA6C9B;AAGD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,MAAM,EACN,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,WAAW,EACX,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -62,3 +62,5 @@ export function schmock(config) {
62
62
  export { HTTP_METHODS, isHttpMethod, isStatusTuple, ROUTE_NOT_FOUND_CODE, toHttpMethod, } from "./constants.js";
63
63
  // Re-export errors
64
64
  export { PluginError, ResourceLimitError, ResponseGenerationError, RouteDefinitionError, RouteNotFoundError, RouteParseError, SchemaGenerationError, SchemaValidationError, SchmockError, } from "./errors.js";
65
+ // Re-export HTTP server helpers
66
+ export { collectBody, parseNodeHeaders, parseNodeQuery, writeSchmockResponse, } from "./http-helpers.js";
package/dist/types.d.ts CHANGED
@@ -17,4 +17,13 @@ export type StaticData = Schmock.StaticData;
17
17
  export type RequestRecord = Schmock.RequestRecord;
18
18
  export type ServerInfo = Schmock.ServerInfo;
19
19
  export type RouteInfo = Schmock.RouteInfo;
20
+ export type SchemaGenerationContext = Schmock.SchemaGenerationContext;
21
+ export type FakerPluginOptions = Schmock.FakerPluginOptions;
22
+ export type ExpressAdapterOptions = Schmock.ExpressAdapterOptions;
23
+ export type AngularAdapterOptions = Schmock.AngularAdapterOptions;
24
+ export type OpenApiOptions = Schmock.OpenApiOptions;
25
+ export type SeedSource = Schmock.SeedSource;
26
+ export type SeedConfig = Schmock.SeedConfig;
27
+ export type CliOptions = Schmock.CliOptions;
28
+ export type CliServer = Schmock.CliServer;
20
29
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;AACxC,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;AAChD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;AACxC,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;AAChD,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;AAC9C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;AAC1C,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;AAC1D,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;AAChE,MAAM,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;AACpC,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;AAChD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;AACxC,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;AAChD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;AACxC,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;AAChD,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;AAC9C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;AAC1C,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;AAC1D,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;AAChE,MAAM,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;AACpC,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;AAChD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;AAC1C,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;AAC5D,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;AAClE,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;AACpD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;AAC5C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@schmock/core",
3
3
  "description": "Core functionality for Schmock",
4
- "version": "1.7.0",
4
+ "version": "1.8.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
package/src/builder.ts CHANGED
@@ -7,6 +7,12 @@ import {
7
7
  RouteNotFoundError,
8
8
  SchmockError,
9
9
  } from "./errors.js";
10
+ import {
11
+ collectBody,
12
+ parseNodeHeaders,
13
+ parseNodeQuery,
14
+ writeSchmockResponse,
15
+ } from "./http-helpers.js";
10
16
  import { parseRouteKey } from "./parser.js";
11
17
 
12
18
  function errorMessage(error: unknown): string {
@@ -341,60 +347,16 @@ export class CallableMockInstance {
341
347
  const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
342
348
  const method = toHttpMethod(req.method ?? "GET");
343
349
  const path = url.pathname;
350
+ const headers = parseNodeHeaders(req);
351
+ const query = parseNodeQuery(url);
344
352
 
345
- const headers: Record<string, string> = {};
346
- for (const [key, value] of Object.entries(req.headers)) {
347
- if (typeof value === "string") {
348
- headers[key] = value;
349
- }
350
- }
351
-
352
- const query: Record<string, string> = {};
353
- url.searchParams.forEach((value, key) => {
354
- query[key] = value;
355
- });
356
-
357
- const chunks: Buffer[] = [];
358
- req.on("data", (chunk: Buffer) => chunks.push(chunk));
359
- req.on("end", () => {
360
- const raw = Buffer.concat(chunks).toString();
361
- let body: unknown;
362
- const contentType = headers["content-type"] ?? "";
363
- if (raw && contentType.includes("json")) {
364
- try {
365
- body = JSON.parse(raw);
366
- } catch {
367
- body = raw;
368
- }
369
- } else if (raw) {
370
- body = raw;
371
- }
372
-
373
- void this.handle(method, path, { headers, body, query }).then(
353
+ void collectBody(req, headers).then((body) =>
354
+ this.handle(method, path, { headers, body, query }).then(
374
355
  (schmockResponse) => {
375
- const responseHeaders: Record<string, string> = {
376
- ...schmockResponse.headers,
377
- };
378
- if (
379
- !responseHeaders["content-type"] &&
380
- schmockResponse.body !== undefined &&
381
- typeof schmockResponse.body !== "string"
382
- ) {
383
- responseHeaders["content-type"] = "application/json";
384
- }
385
-
386
- const responseBody =
387
- schmockResponse.body === undefined
388
- ? undefined
389
- : typeof schmockResponse.body === "string"
390
- ? schmockResponse.body
391
- : JSON.stringify(schmockResponse.body);
392
-
393
- res.writeHead(schmockResponse.status, responseHeaders);
394
- res.end(responseBody);
356
+ writeSchmockResponse(res, schmockResponse);
395
357
  },
396
- );
397
- });
358
+ ),
359
+ );
398
360
  });
399
361
 
400
362
  this.server = httpServer;
@@ -0,0 +1,91 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+
3
+ /**
4
+ * Convert Node.js IncomingMessage headers to a flat Record<string, string>.
5
+ * Drops array-valued headers (keeps only string values).
6
+ */
7
+ export function parseNodeHeaders(req: IncomingMessage): Record<string, string> {
8
+ const headers: Record<string, string> = {};
9
+ for (const [key, value] of Object.entries(req.headers)) {
10
+ if (typeof value === "string") {
11
+ headers[key] = value;
12
+ }
13
+ }
14
+ return headers;
15
+ }
16
+
17
+ /**
18
+ * Extract query parameters from a URL as a flat Record<string, string>.
19
+ */
20
+ export function parseNodeQuery(url: URL): Record<string, string> {
21
+ const query: Record<string, string> = {};
22
+ url.searchParams.forEach((value, key) => {
23
+ query[key] = value;
24
+ });
25
+ return query;
26
+ }
27
+
28
+ /**
29
+ * Collect and parse the request body from a Node.js IncomingMessage.
30
+ * Returns parsed JSON if content-type includes "json", otherwise the raw string.
31
+ * Returns undefined for empty bodies.
32
+ */
33
+ export function collectBody(
34
+ req: IncomingMessage,
35
+ headers: Record<string, string>,
36
+ ): Promise<unknown> {
37
+ return new Promise((resolve) => {
38
+ const chunks: Buffer[] = [];
39
+ req.on("data", (chunk: Buffer) => chunks.push(chunk));
40
+ req.on("end", () => {
41
+ const raw = Buffer.concat(chunks).toString();
42
+ if (!raw) {
43
+ resolve(undefined);
44
+ return;
45
+ }
46
+ const contentType = headers["content-type"] ?? "";
47
+ if (contentType.includes("json")) {
48
+ try {
49
+ resolve(JSON.parse(raw));
50
+ } catch {
51
+ resolve(raw);
52
+ }
53
+ } else {
54
+ resolve(raw);
55
+ }
56
+ });
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Write a Schmock Response to a Node.js ServerResponse.
62
+ * Serializes non-string bodies as JSON and sets content-type when missing.
63
+ */
64
+ export function writeSchmockResponse(
65
+ res: ServerResponse,
66
+ response: Schmock.Response,
67
+ extraHeaders?: Record<string, string>,
68
+ ): void {
69
+ const responseHeaders: Record<string, string> = {
70
+ ...response.headers,
71
+ ...extraHeaders,
72
+ };
73
+
74
+ if (
75
+ !responseHeaders["content-type"] &&
76
+ response.body !== undefined &&
77
+ typeof response.body !== "string"
78
+ ) {
79
+ responseHeaders["content-type"] = "application/json";
80
+ }
81
+
82
+ const responseBody =
83
+ response.body === undefined
84
+ ? undefined
85
+ : typeof response.body === "string"
86
+ ? response.body
87
+ : JSON.stringify(response.body);
88
+
89
+ res.writeHead(response.status, responseHeaders);
90
+ res.end(responseBody);
91
+ }
package/src/index.ts CHANGED
@@ -92,6 +92,13 @@ export {
92
92
  SchemaValidationError,
93
93
  SchmockError,
94
94
  } from "./errors.js";
95
+ // Re-export HTTP server helpers
96
+ export {
97
+ collectBody,
98
+ parseNodeHeaders,
99
+ parseNodeQuery,
100
+ writeSchmockResponse,
101
+ } from "./http-helpers.js";
95
102
  // Re-export types
96
103
  export type {
97
104
  CallableMockInstance,
package/src/types.ts CHANGED
@@ -20,3 +20,12 @@ export type StaticData = Schmock.StaticData;
20
20
  export type RequestRecord = Schmock.RequestRecord;
21
21
  export type ServerInfo = Schmock.ServerInfo;
22
22
  export type RouteInfo = Schmock.RouteInfo;
23
+ export type SchemaGenerationContext = Schmock.SchemaGenerationContext;
24
+ export type FakerPluginOptions = Schmock.FakerPluginOptions;
25
+ export type ExpressAdapterOptions = Schmock.ExpressAdapterOptions;
26
+ export type AngularAdapterOptions = Schmock.AngularAdapterOptions;
27
+ export type OpenApiOptions = Schmock.OpenApiOptions;
28
+ export type SeedSource = Schmock.SeedSource;
29
+ export type SeedConfig = Schmock.SeedConfig;
30
+ export type CliOptions = Schmock.CliOptions;
31
+ export type CliServer = Schmock.CliServer;