@scalar/mock-server 0.1.63 → 0.1.65

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @scalar/mock-server
2
2
 
3
+ ## 0.1.65
4
+
5
+ ### Patch Changes
6
+
7
+ - 742ef52: feat: add wildcard CORS headers
8
+ - 46a3a94: feat: return responses other than 200
9
+
10
+ ## 0.1.64
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [624604e]
15
+ - @scalar/oas-utils@0.1.11
16
+
3
17
  ## 0.1.63
4
18
 
5
19
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -3,12 +3,12 @@
3
3
  var oasUtils = require('@scalar/oas-utils');
4
4
  var openapiParser = require('@scalar/openapi-parser');
5
5
  var hono = require('hono');
6
+ var cors = require('hono/cors');
6
7
 
7
- function normalize(openapi) {
8
- if (typeof openapi === "string") {
9
- openapi = JSON.parse(openapi);
10
- }
11
- return openapi;
8
+ function findPreferredResponseKey(responses) {
9
+ return ["default", "200", "201", "204", "404", "500"].find(
10
+ (key) => responses?.includes(key) ?? false
11
+ );
12
12
  }
13
13
 
14
14
  function routeFromPath(path) {
@@ -18,6 +18,7 @@ function routeFromPath(path) {
18
18
  async function createMockServer(options) {
19
19
  const app = new hono.Hono();
20
20
  const result = await openapiParser.openapi().load(options?.specification ?? {}).resolve();
21
+ app.use(cors.cors());
21
22
  app.get("/openapi.json", (c) => {
22
23
  if (!options?.specification) {
23
24
  return c.text("Not found", 404);
@@ -42,11 +43,18 @@ async function createMockServer(options) {
42
43
  });
43
44
  }
44
45
  const operation = result.schema?.paths?.[path]?.[method];
45
- const jsonResponseConfiguration = operation.responses?.["200"]?.content["application/json"];
46
- const response = jsonResponseConfiguration?.example ? jsonResponseConfiguration.example : jsonResponseConfiguration?.schema ? oasUtils.getExampleFromSchema(jsonResponseConfiguration.schema, {
46
+ const preferredResponseKey = findPreferredResponseKey(
47
+ Object.keys(operation.responses ?? {})
48
+ );
49
+ const jsonResponse = preferredResponseKey ? operation.responses?.[preferredResponseKey]?.content["application/json"] : null;
50
+ const response = jsonResponse?.example ? jsonResponse.example : jsonResponse?.schema ? oasUtils.getExampleFromSchema(jsonResponse.schema, {
47
51
  emptyString: "\u2026"
48
52
  }) : null;
49
- return c.json(response);
53
+ const statusCode = parseInt(
54
+ preferredResponseKey === "default" ? "200" : preferredResponseKey ?? "200",
55
+ 10
56
+ );
57
+ return c.json(response, statusCode);
50
58
  });
51
59
  });
52
60
  });
@@ -54,6 +62,6 @@ async function createMockServer(options) {
54
62
  }
55
63
 
56
64
  exports.createMockServer = createMockServer;
57
- exports.normalize = normalize;
65
+ exports.findPreferredResponseKey = findPreferredResponseKey;
58
66
  exports.routeFromPath = routeFromPath;
59
67
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils/normalize.ts","../src/utils/routeFromPath.ts","../src/createMockServer.ts"],"sourcesContent":["/**\n * Normalize OpenAPI JSON string, YAML string to object\n */\nexport function normalize(openapi: string | Record<string, any>) {\n if (typeof openapi === 'string') {\n openapi = JSON.parse(openapi)\n }\n\n return openapi\n}\n","/**\n * Convert path to route\n * Example: /posts/{id} -> /posts/:id\n */\nexport function routeFromPath(path: string) {\n return path.replace(/{/g, ':').replace(/}/g, '')\n}\n","import { type Operation, getExampleFromSchema } from '@scalar/oas-utils'\nimport { openapi } from '@scalar/openapi-parser'\nimport { type Context, Hono } from 'hono'\n\nimport { routeFromPath } from './utils'\n\n/**\n * Create a mock server instance\n */\nexport async function createMockServer(options?: {\n specification: string | Record<string, any>\n onRequest?: (data: { context: Context; operation: Operation }) => void\n}) {\n const app = new Hono()\n\n // Resolve references\n const result = await openapi()\n .load(options?.specification ?? {})\n .resolve()\n\n // OpenAPI JSON file\n app.get('/openapi.json', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.json(openapi().load(options.specification).get())\n })\n\n // OpenAPI YAML file\n app.get('/openapi.yaml', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.text(openapi().load(options.specification).toYaml())\n })\n\n // Paths\n Object.keys(result.schema?.paths ?? {}).forEach((path) => {\n // Request methods\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // Route\n // @ts-expect-error Needs a proper type\n app[method](route, (c: Context) => {\n // Call onRequest callback\n if (options?.onRequest) {\n options.onRequest({\n context: c,\n // @ts-expect-error Needs a proper type\n operation: result.schema.paths[path][method],\n })\n }\n\n // Response\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n const jsonResponseConfiguration =\n operation.responses?.['200']?.content['application/json']\n\n const response = jsonResponseConfiguration?.example\n ? jsonResponseConfiguration.example\n : jsonResponseConfiguration?.schema\n ? getExampleFromSchema(jsonResponseConfiguration.schema, {\n emptyString: '…',\n })\n : null\n\n return c.json(response)\n })\n })\n })\n\n return app\n}\n"],"names":["Hono","openapi","getExampleFromSchema"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils/findPreferredResponseKey.ts","../src/utils/routeFromPath.ts","../src/createMockServer.ts"],"sourcesContent":["/**\n * Find the preferred response key: default, 200, 201 …\n */\nexport function findPreferredResponseKey(responses?: string[]) {\n return ['default', '200', '201', '204', '404', '500'].find(\n (key) => responses?.includes(key) ?? false,\n )\n}\n","/**\n * Convert path to route\n * Example: /posts/{id} -> /posts/:id\n */\nexport function routeFromPath(path: string) {\n return path.replace(/{/g, ':').replace(/}/g, '')\n}\n","import { getExampleFromSchema } from '@scalar/oas-utils'\nimport { type ResolvedOpenAPI, openapi } from '@scalar/openapi-parser'\nimport { type Context, Hono } from 'hono'\nimport { cors } from 'hono/cors'\nimport type { StatusCode } from 'hono/utils/http-status'\n\nimport { findPreferredResponseKey, routeFromPath } from './utils'\n\n/**\n * Create a mock server instance\n */\nexport async function createMockServer(options?: {\n specification: string | Record<string, any>\n onRequest?: (data: {\n context: Context\n operation: ResolvedOpenAPI.Operation\n }) => void\n}) {\n const app = new Hono()\n\n // Resolve references\n const result = await openapi()\n .load(options?.specification ?? {})\n .resolve()\n\n // CORS headers\n app.use(cors())\n\n // OpenAPI JSON file\n app.get('/openapi.json', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.json(openapi().load(options.specification).get())\n })\n\n // OpenAPI YAML file\n app.get('/openapi.yaml', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.text(openapi().load(options.specification).toYaml())\n })\n\n // Paths\n Object.keys(result.schema?.paths ?? {}).forEach((path) => {\n // Request methods\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // Route\n // @ts-expect-error Needs a proper type\n app[method](route, (c: Context) => {\n // Call onRequest callback\n if (options?.onRequest) {\n options.onRequest({\n context: c,\n // @ts-expect-error Needs a proper type\n operation: result.schema.paths[path][method],\n })\n }\n\n // Response\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n // default, 200, 201 …\n const preferredResponseKey = findPreferredResponseKey(\n Object.keys(operation.responses ?? {}),\n )\n\n // Focus on JSON for now\n const jsonResponse = preferredResponseKey\n ? operation.responses?.[preferredResponseKey]?.content[\n 'application/json'\n ]\n : null\n\n // Get or generate JSON\n const response = jsonResponse?.example\n ? jsonResponse.example\n : jsonResponse?.schema\n ? getExampleFromSchema(jsonResponse.schema, {\n emptyString: '…',\n })\n : null\n\n // Status code\n const statusCode = parseInt(\n preferredResponseKey === 'default'\n ? '200'\n : preferredResponseKey ?? '200',\n 10,\n ) as StatusCode\n\n return c.json(response, statusCode)\n })\n })\n })\n\n return app\n}\n"],"names":["Hono","openapi","cors","getExampleFromSchema"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import * as hono from 'hono';
3
3
  import { Context, Hono } from 'hono';
4
- import { Operation } from '@scalar/oas-utils';
4
+ import { ResolvedOpenAPI } from '@scalar/openapi-parser';
5
5
 
6
6
  /**
7
7
  * Create a mock server instance
@@ -10,14 +10,14 @@ declare function createMockServer(options?: {
10
10
  specification: string | Record<string, any>;
11
11
  onRequest?: (data: {
12
12
  context: Context;
13
- operation: Operation;
13
+ operation: ResolvedOpenAPI.Operation;
14
14
  }) => void;
15
15
  }): Promise<Hono<hono.Env, hono_types.BlankSchema, "/">>;
16
16
 
17
17
  /**
18
- * Normalize OpenAPI JSON string, YAML string to object
18
+ * Find the preferred response key: default, 200, 201
19
19
  */
20
- declare function normalize(openapi: string | Record<string, any>): string | Record<string, any>;
20
+ declare function findPreferredResponseKey(responses?: string[]): string | undefined;
21
21
 
22
22
  /**
23
23
  * Convert path to route
@@ -25,4 +25,4 @@ declare function normalize(openapi: string | Record<string, any>): string | Reco
25
25
  */
26
26
  declare function routeFromPath(path: string): string;
27
27
 
28
- export { createMockServer, normalize, routeFromPath };
28
+ export { createMockServer, findPreferredResponseKey, routeFromPath };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { getExampleFromSchema } from '@scalar/oas-utils';
2
2
  import { openapi } from '@scalar/openapi-parser';
3
3
  import { Hono } from 'hono';
4
+ import { cors } from 'hono/cors';
4
5
 
5
- function normalize(openapi) {
6
- if (typeof openapi === "string") {
7
- openapi = JSON.parse(openapi);
8
- }
9
- return openapi;
6
+ function findPreferredResponseKey(responses) {
7
+ return ["default", "200", "201", "204", "404", "500"].find(
8
+ (key) => responses?.includes(key) ?? false
9
+ );
10
10
  }
11
11
 
12
12
  function routeFromPath(path) {
@@ -16,6 +16,7 @@ function routeFromPath(path) {
16
16
  async function createMockServer(options) {
17
17
  const app = new Hono();
18
18
  const result = await openapi().load(options?.specification ?? {}).resolve();
19
+ app.use(cors());
19
20
  app.get("/openapi.json", (c) => {
20
21
  if (!options?.specification) {
21
22
  return c.text("Not found", 404);
@@ -40,16 +41,23 @@ async function createMockServer(options) {
40
41
  });
41
42
  }
42
43
  const operation = result.schema?.paths?.[path]?.[method];
43
- const jsonResponseConfiguration = operation.responses?.["200"]?.content["application/json"];
44
- const response = jsonResponseConfiguration?.example ? jsonResponseConfiguration.example : jsonResponseConfiguration?.schema ? getExampleFromSchema(jsonResponseConfiguration.schema, {
44
+ const preferredResponseKey = findPreferredResponseKey(
45
+ Object.keys(operation.responses ?? {})
46
+ );
47
+ const jsonResponse = preferredResponseKey ? operation.responses?.[preferredResponseKey]?.content["application/json"] : null;
48
+ const response = jsonResponse?.example ? jsonResponse.example : jsonResponse?.schema ? getExampleFromSchema(jsonResponse.schema, {
45
49
  emptyString: "\u2026"
46
50
  }) : null;
47
- return c.json(response);
51
+ const statusCode = parseInt(
52
+ preferredResponseKey === "default" ? "200" : preferredResponseKey ?? "200",
53
+ 10
54
+ );
55
+ return c.json(response, statusCode);
48
56
  });
49
57
  });
50
58
  });
51
59
  return app;
52
60
  }
53
61
 
54
- export { createMockServer, normalize, routeFromPath };
62
+ export { createMockServer, findPreferredResponseKey, routeFromPath };
55
63
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/normalize.ts","../src/utils/routeFromPath.ts","../src/createMockServer.ts"],"sourcesContent":["/**\n * Normalize OpenAPI JSON string, YAML string to object\n */\nexport function normalize(openapi: string | Record<string, any>) {\n if (typeof openapi === 'string') {\n openapi = JSON.parse(openapi)\n }\n\n return openapi\n}\n","/**\n * Convert path to route\n * Example: /posts/{id} -> /posts/:id\n */\nexport function routeFromPath(path: string) {\n return path.replace(/{/g, ':').replace(/}/g, '')\n}\n","import { type Operation, getExampleFromSchema } from '@scalar/oas-utils'\nimport { openapi } from '@scalar/openapi-parser'\nimport { type Context, Hono } from 'hono'\n\nimport { routeFromPath } from './utils'\n\n/**\n * Create a mock server instance\n */\nexport async function createMockServer(options?: {\n specification: string | Record<string, any>\n onRequest?: (data: { context: Context; operation: Operation }) => void\n}) {\n const app = new Hono()\n\n // Resolve references\n const result = await openapi()\n .load(options?.specification ?? {})\n .resolve()\n\n // OpenAPI JSON file\n app.get('/openapi.json', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.json(openapi().load(options.specification).get())\n })\n\n // OpenAPI YAML file\n app.get('/openapi.yaml', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.text(openapi().load(options.specification).toYaml())\n })\n\n // Paths\n Object.keys(result.schema?.paths ?? {}).forEach((path) => {\n // Request methods\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // Route\n // @ts-expect-error Needs a proper type\n app[method](route, (c: Context) => {\n // Call onRequest callback\n if (options?.onRequest) {\n options.onRequest({\n context: c,\n // @ts-expect-error Needs a proper type\n operation: result.schema.paths[path][method],\n })\n }\n\n // Response\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n const jsonResponseConfiguration =\n operation.responses?.['200']?.content['application/json']\n\n const response = jsonResponseConfiguration?.example\n ? jsonResponseConfiguration.example\n : jsonResponseConfiguration?.schema\n ? getExampleFromSchema(jsonResponseConfiguration.schema, {\n emptyString: '…',\n })\n : null\n\n return c.json(response)\n })\n })\n })\n\n return app\n}\n"],"names":[],"mappings":";;;;AAGO,SAAS,UAAU,OAAuC,EAAA;AAC/D,EAAI,IAAA,OAAO,YAAY,QAAU,EAAA;AAC/B,IAAU,OAAA,GAAA,IAAA,CAAK,MAAM,OAAO,CAAA,CAAA;AAAA,GAC9B;AAEA,EAAO,OAAA,OAAA,CAAA;AACT;;ACLO,SAAS,cAAc,IAAc,EAAA;AAC1C,EAAA,OAAO,KAAK,OAAQ,CAAA,IAAA,EAAM,GAAG,CAAE,CAAA,OAAA,CAAQ,MAAM,EAAE,CAAA,CAAA;AACjD;;ACGA,eAAsB,iBAAiB,OAGpC,EAAA;AACD,EAAM,MAAA,GAAA,GAAM,IAAI,IAAK,EAAA,CAAA;AAGrB,EAAM,MAAA,MAAA,GAAS,MAAM,OAAA,EAClB,CAAA,IAAA,CAAK,SAAS,aAAiB,IAAA,EAAE,CAAA,CACjC,OAAQ,EAAA,CAAA;AAGX,EAAI,GAAA,CAAA,GAAA,CAAI,eAAiB,EAAA,CAAC,CAAM,KAAA;AAC9B,IAAI,IAAA,CAAC,SAAS,aAAe,EAAA;AAC3B,MAAO,OAAA,CAAA,CAAE,IAAK,CAAA,WAAA,EAAa,GAAG,CAAA,CAAA;AAAA,KAChC;AAEA,IAAO,OAAA,CAAA,CAAE,KAAK,OAAQ,EAAA,CAAE,KAAK,OAAQ,CAAA,aAAa,CAAE,CAAA,GAAA,EAAK,CAAA,CAAA;AAAA,GAC1D,CAAA,CAAA;AAGD,EAAI,GAAA,CAAA,GAAA,CAAI,eAAiB,EAAA,CAAC,CAAM,KAAA;AAC9B,IAAI,IAAA,CAAC,SAAS,aAAe,EAAA;AAC3B,MAAO,OAAA,CAAA,CAAE,IAAK,CAAA,WAAA,EAAa,GAAG,CAAA,CAAA;AAAA,KAChC;AAEA,IAAO,OAAA,CAAA,CAAE,KAAK,OAAQ,EAAA,CAAE,KAAK,OAAQ,CAAA,aAAa,CAAE,CAAA,MAAA,EAAQ,CAAA,CAAA;AAAA,GAC7D,CAAA,CAAA;AAGD,EAAO,MAAA,CAAA,IAAA,CAAK,OAAO,MAAQ,EAAA,KAAA,IAAS,EAAE,CAAA,CAAE,OAAQ,CAAA,CAAC,IAAS,KAAA;AAExD,IAAO,MAAA,CAAA,IAAA,CAAK,MAAO,CAAA,MAAA,EAAQ,KAAQ,GAAA,IAAI,CAAK,IAAA,EAAE,CAAA,CAAE,OAAQ,CAAA,CAAC,MAAW,KAAA;AAClE,MAAM,MAAA,KAAA,GAAQ,cAAc,IAAI,CAAA,CAAA;AAIhC,MAAA,GAAA,CAAI,MAAM,CAAA,CAAE,KAAO,EAAA,CAAC,CAAe,KAAA;AAEjC,QAAA,IAAI,SAAS,SAAW,EAAA;AACtB,UAAA,OAAA,CAAQ,SAAU,CAAA;AAAA,YAChB,OAAS,EAAA,CAAA;AAAA;AAAA,YAET,WAAW,MAAO,CAAA,MAAA,CAAO,KAAM,CAAA,IAAI,EAAE,MAAM,CAAA;AAAA,WAC5C,CAAA,CAAA;AAAA,SACH;AAIA,QAAA,MAAM,YAAY,MAAO,CAAA,MAAA,EAAQ,KAAQ,GAAA,IAAI,IAAI,MAAM,CAAA,CAAA;AAEvD,QAAA,MAAM,4BACJ,SAAU,CAAA,SAAA,GAAY,KAAK,CAAA,EAAG,QAAQ,kBAAkB,CAAA,CAAA;AAE1D,QAAM,MAAA,QAAA,GAAW,2BAA2B,OACxC,GAAA,yBAAA,CAA0B,UAC1B,yBAA2B,EAAA,MAAA,GACzB,oBAAqB,CAAA,yBAAA,CAA0B,MAAQ,EAAA;AAAA,UACrD,WAAa,EAAA,QAAA;AAAA,SACd,CACD,GAAA,IAAA,CAAA;AAEN,QAAO,OAAA,CAAA,CAAE,KAAK,QAAQ,CAAA,CAAA;AAAA,OACvB,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AAED,EAAO,OAAA,GAAA,CAAA;AACT;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/findPreferredResponseKey.ts","../src/utils/routeFromPath.ts","../src/createMockServer.ts"],"sourcesContent":["/**\n * Find the preferred response key: default, 200, 201 …\n */\nexport function findPreferredResponseKey(responses?: string[]) {\n return ['default', '200', '201', '204', '404', '500'].find(\n (key) => responses?.includes(key) ?? false,\n )\n}\n","/**\n * Convert path to route\n * Example: /posts/{id} -> /posts/:id\n */\nexport function routeFromPath(path: string) {\n return path.replace(/{/g, ':').replace(/}/g, '')\n}\n","import { getExampleFromSchema } from '@scalar/oas-utils'\nimport { type ResolvedOpenAPI, openapi } from '@scalar/openapi-parser'\nimport { type Context, Hono } from 'hono'\nimport { cors } from 'hono/cors'\nimport type { StatusCode } from 'hono/utils/http-status'\n\nimport { findPreferredResponseKey, routeFromPath } from './utils'\n\n/**\n * Create a mock server instance\n */\nexport async function createMockServer(options?: {\n specification: string | Record<string, any>\n onRequest?: (data: {\n context: Context\n operation: ResolvedOpenAPI.Operation\n }) => void\n}) {\n const app = new Hono()\n\n // Resolve references\n const result = await openapi()\n .load(options?.specification ?? {})\n .resolve()\n\n // CORS headers\n app.use(cors())\n\n // OpenAPI JSON file\n app.get('/openapi.json', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.json(openapi().load(options.specification).get())\n })\n\n // OpenAPI YAML file\n app.get('/openapi.yaml', (c) => {\n if (!options?.specification) {\n return c.text('Not found', 404)\n }\n\n return c.text(openapi().load(options.specification).toYaml())\n })\n\n // Paths\n Object.keys(result.schema?.paths ?? {}).forEach((path) => {\n // Request methods\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // Route\n // @ts-expect-error Needs a proper type\n app[method](route, (c: Context) => {\n // Call onRequest callback\n if (options?.onRequest) {\n options.onRequest({\n context: c,\n // @ts-expect-error Needs a proper type\n operation: result.schema.paths[path][method],\n })\n }\n\n // Response\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n // default, 200, 201 …\n const preferredResponseKey = findPreferredResponseKey(\n Object.keys(operation.responses ?? {}),\n )\n\n // Focus on JSON for now\n const jsonResponse = preferredResponseKey\n ? operation.responses?.[preferredResponseKey]?.content[\n 'application/json'\n ]\n : null\n\n // Get or generate JSON\n const response = jsonResponse?.example\n ? jsonResponse.example\n : jsonResponse?.schema\n ? getExampleFromSchema(jsonResponse.schema, {\n emptyString: '…',\n })\n : null\n\n // Status code\n const statusCode = parseInt(\n preferredResponseKey === 'default'\n ? '200'\n : preferredResponseKey ?? '200',\n 10,\n ) as StatusCode\n\n return c.json(response, statusCode)\n })\n })\n })\n\n return app\n}\n"],"names":[],"mappings":";;;;;AAGO,SAAS,yBAAyB,SAAsB,EAAA;AAC7D,EAAA,OAAO,CAAC,SAAW,EAAA,KAAA,EAAO,OAAO,KAAO,EAAA,KAAA,EAAO,KAAK,CAAE,CAAA,IAAA;AAAA,IACpD,CAAC,GAAA,KAAQ,SAAW,EAAA,QAAA,CAAS,GAAG,CAAK,IAAA,KAAA;AAAA,GACvC,CAAA;AACF;;ACHO,SAAS,cAAc,IAAc,EAAA;AAC1C,EAAA,OAAO,KAAK,OAAQ,CAAA,IAAA,EAAM,GAAG,CAAE,CAAA,OAAA,CAAQ,MAAM,EAAE,CAAA,CAAA;AACjD;;ACKA,eAAsB,iBAAiB,OAMpC,EAAA;AACD,EAAM,MAAA,GAAA,GAAM,IAAI,IAAK,EAAA,CAAA;AAGrB,EAAM,MAAA,MAAA,GAAS,MAAM,OAAA,EAClB,CAAA,IAAA,CAAK,SAAS,aAAiB,IAAA,EAAE,CAAA,CACjC,OAAQ,EAAA,CAAA;AAGX,EAAI,GAAA,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAGd,EAAI,GAAA,CAAA,GAAA,CAAI,eAAiB,EAAA,CAAC,CAAM,KAAA;AAC9B,IAAI,IAAA,CAAC,SAAS,aAAe,EAAA;AAC3B,MAAO,OAAA,CAAA,CAAE,IAAK,CAAA,WAAA,EAAa,GAAG,CAAA,CAAA;AAAA,KAChC;AAEA,IAAO,OAAA,CAAA,CAAE,KAAK,OAAQ,EAAA,CAAE,KAAK,OAAQ,CAAA,aAAa,CAAE,CAAA,GAAA,EAAK,CAAA,CAAA;AAAA,GAC1D,CAAA,CAAA;AAGD,EAAI,GAAA,CAAA,GAAA,CAAI,eAAiB,EAAA,CAAC,CAAM,KAAA;AAC9B,IAAI,IAAA,CAAC,SAAS,aAAe,EAAA;AAC3B,MAAO,OAAA,CAAA,CAAE,IAAK,CAAA,WAAA,EAAa,GAAG,CAAA,CAAA;AAAA,KAChC;AAEA,IAAO,OAAA,CAAA,CAAE,KAAK,OAAQ,EAAA,CAAE,KAAK,OAAQ,CAAA,aAAa,CAAE,CAAA,MAAA,EAAQ,CAAA,CAAA;AAAA,GAC7D,CAAA,CAAA;AAGD,EAAO,MAAA,CAAA,IAAA,CAAK,OAAO,MAAQ,EAAA,KAAA,IAAS,EAAE,CAAA,CAAE,OAAQ,CAAA,CAAC,IAAS,KAAA;AAExD,IAAO,MAAA,CAAA,IAAA,CAAK,MAAO,CAAA,MAAA,EAAQ,KAAQ,GAAA,IAAI,CAAK,IAAA,EAAE,CAAA,CAAE,OAAQ,CAAA,CAAC,MAAW,KAAA;AAClE,MAAM,MAAA,KAAA,GAAQ,cAAc,IAAI,CAAA,CAAA;AAIhC,MAAA,GAAA,CAAI,MAAM,CAAA,CAAE,KAAO,EAAA,CAAC,CAAe,KAAA;AAEjC,QAAA,IAAI,SAAS,SAAW,EAAA;AACtB,UAAA,OAAA,CAAQ,SAAU,CAAA;AAAA,YAChB,OAAS,EAAA,CAAA;AAAA;AAAA,YAET,WAAW,MAAO,CAAA,MAAA,CAAO,KAAM,CAAA,IAAI,EAAE,MAAM,CAAA;AAAA,WAC5C,CAAA,CAAA;AAAA,SACH;AAIA,QAAA,MAAM,YAAY,MAAO,CAAA,MAAA,EAAQ,KAAQ,GAAA,IAAI,IAAI,MAAM,CAAA,CAAA;AAGvD,QAAA,MAAM,oBAAuB,GAAA,wBAAA;AAAA,UAC3B,MAAO,CAAA,IAAA,CAAK,SAAU,CAAA,SAAA,IAAa,EAAE,CAAA;AAAA,SACvC,CAAA;AAGA,QAAM,MAAA,YAAA,GAAe,uBACjB,SAAU,CAAA,SAAA,GAAY,oBAAoB,CAAG,EAAA,OAAA,CAC3C,kBACF,CACA,GAAA,IAAA,CAAA;AAGJ,QAAM,MAAA,QAAA,GAAW,cAAc,OAC3B,GAAA,YAAA,CAAa,UACb,YAAc,EAAA,MAAA,GACZ,oBAAqB,CAAA,YAAA,CAAa,MAAQ,EAAA;AAAA,UACxC,WAAa,EAAA,QAAA;AAAA,SACd,CACD,GAAA,IAAA,CAAA;AAGN,QAAA,MAAM,UAAa,GAAA,QAAA;AAAA,UACjB,oBAAA,KAAyB,SACrB,GAAA,KAAA,GACA,oBAAwB,IAAA,KAAA;AAAA,UAC5B,EAAA;AAAA,SACF,CAAA;AAEA,QAAO,OAAA,CAAA,CAAE,IAAK,CAAA,QAAA,EAAU,UAAU,CAAA,CAAA;AAAA,OACnC,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AAED,EAAO,OAAA,GAAA,CAAA;AACT;;;;"}
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "swagger",
17
17
  "cli"
18
18
  ],
19
- "version": "0.1.63",
19
+ "version": "0.1.65",
20
20
  "engines": {
21
21
  "node": ">=18"
22
22
  },
@@ -35,7 +35,7 @@
35
35
  "@hono/node-server": "^1.11.0",
36
36
  "@scalar/openapi-parser": "^0.3.2",
37
37
  "hono": "^4.2.7",
38
- "@scalar/oas-utils": "0.1.10"
38
+ "@scalar/oas-utils": "0.1.11"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^20.8.4",