@schmock/cli 2.0.2 → 2.0.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.
- package/dist/bin.js +42 -32
- package/dist/index.js +42 -32
- package/package.json +3 -3
package/dist/bin.js
CHANGED
|
@@ -23985,14 +23985,14 @@ function parseRouteKey(routeKey) {
|
|
|
23985
23985
|
}
|
|
23986
23986
|
const [, method, path] = match;
|
|
23987
23987
|
const params = [];
|
|
23988
|
-
const
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
23992
|
-
|
|
23993
|
-
|
|
23994
|
-
|
|
23995
|
-
|
|
23988
|
+
const regexPath = path.split(/(:[a-zA-Z0-9_-]+)/g).map((segment) => {
|
|
23989
|
+
const paramMatch = segment.match(/^:([a-zA-Z0-9_-]+)$/);
|
|
23990
|
+
if (paramMatch) {
|
|
23991
|
+
params.push(paramMatch[1]);
|
|
23992
|
+
return "([^/]+)";
|
|
23993
|
+
}
|
|
23994
|
+
return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23995
|
+
}).join("");
|
|
23996
23996
|
const pattern = new RegExp(`^${regexPath}$`);
|
|
23997
23997
|
return {
|
|
23998
23998
|
method: toHttpMethod(method),
|
|
@@ -24198,6 +24198,7 @@ class CallableMockInstance {
|
|
|
24198
24198
|
const existing = this.routes.find((r) => r.method === parsed.method && r.path === parsed.path);
|
|
24199
24199
|
if (existing) {
|
|
24200
24200
|
this.logger.log("warning", `Duplicate route: ${route} — first registration wins`);
|
|
24201
|
+
return this;
|
|
24201
24202
|
}
|
|
24202
24203
|
const compiledRoute = {
|
|
24203
24204
|
pattern: parsed.pattern,
|
|
@@ -24210,9 +24211,7 @@ class CallableMockInstance {
|
|
|
24210
24211
|
this.routes.push(compiledRoute);
|
|
24211
24212
|
if (parsed.params.length === 0) {
|
|
24212
24213
|
const key = `${parsed.method} ${normalizePath(parsed.path)}`;
|
|
24213
|
-
|
|
24214
|
-
this.staticRoutes.set(key, compiledRoute);
|
|
24215
|
-
}
|
|
24214
|
+
this.staticRoutes.set(key, compiledRoute);
|
|
24216
24215
|
}
|
|
24217
24216
|
this.logger.log("route", `Route defined: ${route}`, {
|
|
24218
24217
|
contentType: config.contentType,
|
|
@@ -24494,6 +24493,10 @@ class CallableMockInstance {
|
|
|
24494
24493
|
timestamp: Date.now(),
|
|
24495
24494
|
response: { status: response.status, body: response.body }
|
|
24496
24495
|
});
|
|
24496
|
+
const maxHistorySize = this.globalConfig.maxHistorySize;
|
|
24497
|
+
if (typeof maxHistorySize === "number" && maxHistorySize >= 0 && this.requestHistory.length > maxHistorySize) {
|
|
24498
|
+
this.requestHistory.splice(0, this.requestHistory.length - maxHistorySize);
|
|
24499
|
+
}
|
|
24497
24500
|
this.emit("request:end", {
|
|
24498
24501
|
method,
|
|
24499
24502
|
path: requestPath,
|
|
@@ -24576,7 +24579,7 @@ function schmock(config) {
|
|
|
24576
24579
|
return callableInstance;
|
|
24577
24580
|
}
|
|
24578
24581
|
// ../openapi/package.json
|
|
24579
|
-
var version = "2.0.
|
|
24582
|
+
var version = "2.0.3";
|
|
24580
24583
|
|
|
24581
24584
|
// ../openapi/src/utils.ts
|
|
24582
24585
|
function isRecord(value) {
|
|
@@ -30005,19 +30008,21 @@ function validateSchema(schema, path = "$") {
|
|
|
30005
30008
|
validateSchema(schema.items, `${path}.items`);
|
|
30006
30009
|
}
|
|
30007
30010
|
}
|
|
30008
|
-
if (
|
|
30009
|
-
|
|
30010
|
-
|
|
30011
|
-
|
|
30012
|
-
|
|
30013
|
-
|
|
30014
|
-
|
|
30015
|
-
|
|
30016
|
-
|
|
30017
|
-
|
|
30018
|
-
|
|
30019
|
-
|
|
30020
|
-
|
|
30011
|
+
if (path === "$") {
|
|
30012
|
+
if (hasCircularReference(schema)) {
|
|
30013
|
+
throw new SchemaValidationError(path, "Schema contains circular references which are not supported");
|
|
30014
|
+
}
|
|
30015
|
+
if (schema.$ref === "#") {
|
|
30016
|
+
throw new SchemaValidationError(path, "Self-referencing schemas are not supported");
|
|
30017
|
+
}
|
|
30018
|
+
const depth = calculateNestingDepth(schema);
|
|
30019
|
+
if (depth > MAX_NESTING_DEPTH) {
|
|
30020
|
+
throw new ResourceLimitError("schema_nesting_depth", MAX_NESTING_DEPTH, depth);
|
|
30021
|
+
}
|
|
30022
|
+
if (depth >= DEEP_NESTING_THRESHOLD) {
|
|
30023
|
+
checkForDeepNestingWithArrays(schema, path);
|
|
30024
|
+
}
|
|
30025
|
+
checkArraySizeLimits(schema, path);
|
|
30021
30026
|
}
|
|
30022
30027
|
}
|
|
30023
30028
|
function hasCircularReference(schema, currentPath = new Set) {
|
|
@@ -31636,17 +31641,21 @@ function processContentNegotiation(context) {
|
|
|
31636
31641
|
}
|
|
31637
31642
|
return;
|
|
31638
31643
|
}
|
|
31639
|
-
|
|
31640
|
-
|
|
31641
|
-
|
|
31644
|
+
function createBodyValidatorContext() {
|
|
31645
|
+
return {
|
|
31646
|
+
ajv: new import_ajv.default({ allErrors: true }),
|
|
31647
|
+
cache: new WeakMap
|
|
31648
|
+
};
|
|
31649
|
+
}
|
|
31650
|
+
function validateRequestBody(context, validatorCtx) {
|
|
31642
31651
|
const requestBodySchema = getRouteRequestBody(context.route);
|
|
31643
31652
|
if (!requestBodySchema || context.body === undefined) {
|
|
31644
31653
|
return;
|
|
31645
31654
|
}
|
|
31646
|
-
let validate =
|
|
31655
|
+
let validate = validatorCtx.cache.get(requestBodySchema);
|
|
31647
31656
|
if (!validate) {
|
|
31648
|
-
validate = ajv.compile(requestBodySchema);
|
|
31649
|
-
|
|
31657
|
+
validate = validatorCtx.ajv.compile(requestBodySchema);
|
|
31658
|
+
validatorCtx.cache.set(requestBodySchema, validate);
|
|
31650
31659
|
}
|
|
31651
31660
|
if (!validate(context.body)) {
|
|
31652
31661
|
const errors = validate.errors?.map((e3) => ({
|
|
@@ -31766,6 +31775,7 @@ async function openapi(options) {
|
|
|
31766
31775
|
}
|
|
31767
31776
|
const securitySchemes = spec.securitySchemes;
|
|
31768
31777
|
const globalSecurity = spec.globalSecurity;
|
|
31778
|
+
const bodyValidatorCtx = createBodyValidatorContext();
|
|
31769
31779
|
return {
|
|
31770
31780
|
name: "@schmock/openapi",
|
|
31771
31781
|
version,
|
|
@@ -31827,7 +31837,7 @@ async function openapi(options) {
|
|
|
31827
31837
|
if (contentResult)
|
|
31828
31838
|
return contentResult;
|
|
31829
31839
|
if (options.validateRequests) {
|
|
31830
|
-
const validationResult = validateRequestBody(context);
|
|
31840
|
+
const validationResult = validateRequestBody(context, bodyValidatorCtx);
|
|
31831
31841
|
if (validationResult) {
|
|
31832
31842
|
return validationResult;
|
|
31833
31843
|
}
|
package/dist/index.js
CHANGED
|
@@ -23984,14 +23984,14 @@ function parseRouteKey(routeKey) {
|
|
|
23984
23984
|
}
|
|
23985
23985
|
const [, method, path] = match;
|
|
23986
23986
|
const params = [];
|
|
23987
|
-
const
|
|
23988
|
-
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
23992
|
-
|
|
23993
|
-
|
|
23994
|
-
|
|
23987
|
+
const regexPath = path.split(/(:[a-zA-Z0-9_-]+)/g).map((segment) => {
|
|
23988
|
+
const paramMatch = segment.match(/^:([a-zA-Z0-9_-]+)$/);
|
|
23989
|
+
if (paramMatch) {
|
|
23990
|
+
params.push(paramMatch[1]);
|
|
23991
|
+
return "([^/]+)";
|
|
23992
|
+
}
|
|
23993
|
+
return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23994
|
+
}).join("");
|
|
23995
23995
|
const pattern = new RegExp(`^${regexPath}$`);
|
|
23996
23996
|
return {
|
|
23997
23997
|
method: toHttpMethod(method),
|
|
@@ -24197,6 +24197,7 @@ class CallableMockInstance {
|
|
|
24197
24197
|
const existing = this.routes.find((r) => r.method === parsed.method && r.path === parsed.path);
|
|
24198
24198
|
if (existing) {
|
|
24199
24199
|
this.logger.log("warning", `Duplicate route: ${route} — first registration wins`);
|
|
24200
|
+
return this;
|
|
24200
24201
|
}
|
|
24201
24202
|
const compiledRoute = {
|
|
24202
24203
|
pattern: parsed.pattern,
|
|
@@ -24209,9 +24210,7 @@ class CallableMockInstance {
|
|
|
24209
24210
|
this.routes.push(compiledRoute);
|
|
24210
24211
|
if (parsed.params.length === 0) {
|
|
24211
24212
|
const key = `${parsed.method} ${normalizePath(parsed.path)}`;
|
|
24212
|
-
|
|
24213
|
-
this.staticRoutes.set(key, compiledRoute);
|
|
24214
|
-
}
|
|
24213
|
+
this.staticRoutes.set(key, compiledRoute);
|
|
24215
24214
|
}
|
|
24216
24215
|
this.logger.log("route", `Route defined: ${route}`, {
|
|
24217
24216
|
contentType: config.contentType,
|
|
@@ -24493,6 +24492,10 @@ class CallableMockInstance {
|
|
|
24493
24492
|
timestamp: Date.now(),
|
|
24494
24493
|
response: { status: response.status, body: response.body }
|
|
24495
24494
|
});
|
|
24495
|
+
const maxHistorySize = this.globalConfig.maxHistorySize;
|
|
24496
|
+
if (typeof maxHistorySize === "number" && maxHistorySize >= 0 && this.requestHistory.length > maxHistorySize) {
|
|
24497
|
+
this.requestHistory.splice(0, this.requestHistory.length - maxHistorySize);
|
|
24498
|
+
}
|
|
24496
24499
|
this.emit("request:end", {
|
|
24497
24500
|
method,
|
|
24498
24501
|
path: requestPath,
|
|
@@ -24575,7 +24578,7 @@ function schmock(config) {
|
|
|
24575
24578
|
return callableInstance;
|
|
24576
24579
|
}
|
|
24577
24580
|
// ../openapi/package.json
|
|
24578
|
-
var version = "2.0.
|
|
24581
|
+
var version = "2.0.3";
|
|
24579
24582
|
|
|
24580
24583
|
// ../openapi/src/utils.ts
|
|
24581
24584
|
function isRecord(value) {
|
|
@@ -30004,19 +30007,21 @@ function validateSchema(schema, path = "$") {
|
|
|
30004
30007
|
validateSchema(schema.items, `${path}.items`);
|
|
30005
30008
|
}
|
|
30006
30009
|
}
|
|
30007
|
-
if (
|
|
30008
|
-
|
|
30009
|
-
|
|
30010
|
-
|
|
30011
|
-
|
|
30012
|
-
|
|
30013
|
-
|
|
30014
|
-
|
|
30015
|
-
|
|
30016
|
-
|
|
30017
|
-
|
|
30018
|
-
|
|
30019
|
-
|
|
30010
|
+
if (path === "$") {
|
|
30011
|
+
if (hasCircularReference(schema)) {
|
|
30012
|
+
throw new SchemaValidationError(path, "Schema contains circular references which are not supported");
|
|
30013
|
+
}
|
|
30014
|
+
if (schema.$ref === "#") {
|
|
30015
|
+
throw new SchemaValidationError(path, "Self-referencing schemas are not supported");
|
|
30016
|
+
}
|
|
30017
|
+
const depth = calculateNestingDepth(schema);
|
|
30018
|
+
if (depth > MAX_NESTING_DEPTH) {
|
|
30019
|
+
throw new ResourceLimitError("schema_nesting_depth", MAX_NESTING_DEPTH, depth);
|
|
30020
|
+
}
|
|
30021
|
+
if (depth >= DEEP_NESTING_THRESHOLD) {
|
|
30022
|
+
checkForDeepNestingWithArrays(schema, path);
|
|
30023
|
+
}
|
|
30024
|
+
checkArraySizeLimits(schema, path);
|
|
30020
30025
|
}
|
|
30021
30026
|
}
|
|
30022
30027
|
function hasCircularReference(schema, currentPath = new Set) {
|
|
@@ -31635,17 +31640,21 @@ function processContentNegotiation(context) {
|
|
|
31635
31640
|
}
|
|
31636
31641
|
return;
|
|
31637
31642
|
}
|
|
31638
|
-
|
|
31639
|
-
|
|
31640
|
-
|
|
31643
|
+
function createBodyValidatorContext() {
|
|
31644
|
+
return {
|
|
31645
|
+
ajv: new import_ajv.default({ allErrors: true }),
|
|
31646
|
+
cache: new WeakMap
|
|
31647
|
+
};
|
|
31648
|
+
}
|
|
31649
|
+
function validateRequestBody(context, validatorCtx) {
|
|
31641
31650
|
const requestBodySchema = getRouteRequestBody(context.route);
|
|
31642
31651
|
if (!requestBodySchema || context.body === undefined) {
|
|
31643
31652
|
return;
|
|
31644
31653
|
}
|
|
31645
|
-
let validate =
|
|
31654
|
+
let validate = validatorCtx.cache.get(requestBodySchema);
|
|
31646
31655
|
if (!validate) {
|
|
31647
|
-
validate = ajv.compile(requestBodySchema);
|
|
31648
|
-
|
|
31656
|
+
validate = validatorCtx.ajv.compile(requestBodySchema);
|
|
31657
|
+
validatorCtx.cache.set(requestBodySchema, validate);
|
|
31649
31658
|
}
|
|
31650
31659
|
if (!validate(context.body)) {
|
|
31651
31660
|
const errors = validate.errors?.map((e3) => ({
|
|
@@ -31765,6 +31774,7 @@ async function openapi(options) {
|
|
|
31765
31774
|
}
|
|
31766
31775
|
const securitySchemes = spec.securitySchemes;
|
|
31767
31776
|
const globalSecurity = spec.globalSecurity;
|
|
31777
|
+
const bodyValidatorCtx = createBodyValidatorContext();
|
|
31768
31778
|
return {
|
|
31769
31779
|
name: "@schmock/openapi",
|
|
31770
31780
|
version,
|
|
@@ -31826,7 +31836,7 @@ async function openapi(options) {
|
|
|
31826
31836
|
if (contentResult)
|
|
31827
31837
|
return contentResult;
|
|
31828
31838
|
if (options.validateRequests) {
|
|
31829
|
-
const validationResult = validateRequestBody(context);
|
|
31839
|
+
const validationResult = validateRequestBody(context, bodyValidatorCtx);
|
|
31830
31840
|
if (validationResult) {
|
|
31831
31841
|
return validationResult;
|
|
31832
31842
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schmock/cli",
|
|
3
3
|
"description": "CLI for running Schmock mock servers from OpenAPI specs",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@schmock/core": "^2.0.
|
|
36
|
-
"@schmock/openapi": "^2.0.
|
|
35
|
+
"@schmock/core": "^2.0.3",
|
|
36
|
+
"@schmock/openapi": "^2.0.3"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@amiceli/vitest-cucumber": "^6.5.0",
|