@scalar/mock-server 0.1.71 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @scalar/mock-server
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7f8ef74: chore: remove aliasing
8
+
9
+ ### Patch Changes
10
+
11
+ - b38c7ed: Update build configs to a standardized format
12
+ - 6fbb57e: feat: release all the packages
13
+ - Updated dependencies [7f8ef74]
14
+ - Updated dependencies [96347a1]
15
+ - Updated dependencies [8494349]
16
+ - Updated dependencies [6fbb57e]
17
+ - @scalar/oas-utils@0.2.0
18
+
19
+ ## 0.1.72
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [c951512]
24
+ - @scalar/oas-utils@0.1.17
25
+
3
26
  ## 0.1.71
4
27
 
5
28
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var oasUtils = require('@scalar/oas-utils');
3
+ var specGetters = require('@scalar/oas-utils/spec-getters');
4
4
  var openapiParser = require('@scalar/openapi-parser');
5
5
  var hono = require('hono');
6
6
  var cors = require('hono/cors');
@@ -101,7 +101,7 @@ async function createMockServer(options) {
101
101
  Object.keys(operation.responses ?? {})
102
102
  );
103
103
  const jsonResponse = preferredResponseKey ? operation.responses?.[preferredResponseKey]?.content?.["application/json"] : null;
104
- const response = jsonResponse?.example ? jsonResponse.example : jsonResponse?.schema ? oasUtils.getExampleFromSchema(jsonResponse.schema, {
104
+ const response = jsonResponse?.example ? jsonResponse.example : jsonResponse?.schema ? specGetters.getExampleFromSchema(jsonResponse.schema, {
105
105
  emptyString: "\u2026",
106
106
  variables: c.req.param()
107
107
  }) : null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils/findPreferredResponseKey.ts","../src/utils/routeFromPath.ts","../src/utils/isAuthenticationRequired.ts","../src/utils/anyBasicAuthentication.ts","../src/utils/isBasicAuthenticationRequired.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 type { OpenAPIV3 } from '@scalar/openapi-parser'\n\n/**\n * Check whether the given security scheme key is in the `security` configuration for this operation.\n **/\nexport function isAuthenticationRequired(\n security?: OpenAPIV3.SecurityRequirementObject[],\n): boolean {\n // If security is not defined, auth is not required.\n if (!security) {\n return false\n }\n\n // Don’t require auth if security is just an empty array []\n if (Array.isArray(security) && !security.length) {\n return false\n }\n\n // Includes empty object = auth is not required\n if (\n (security ?? []).some(\n (securityRequirement) => !Object.keys(securityRequirement).length,\n )\n ) {\n return false\n }\n\n return true\n}\n","import type { Context } from 'hono'\nimport { HTTPException } from 'hono/http-exception'\n\n/**\n * Middleware to check for any basic authentication header\n */\nexport function anyBasicAuthentication() {\n return async function (ctx: Context, next: () => Promise<void>) {\n // Check if the request has an Authorization header\n // Note: We don’t care *what* credentials are sent, though.\n if (ctx.req.header('Authorization')?.startsWith('Basic ')) {\n return await next()\n }\n\n // Unauthorized\n throw new HTTPException(401, {\n res: new Response('Unauthorized', {\n status: 401,\n headers: {\n 'WWW-Authenticate': 'Basic realm=\"Authentication Required\"',\n },\n }),\n })\n }\n}\n","import type {\n OpenAPI,\n OpenAPIV3_1,\n ResolvedOpenAPI,\n} from '@scalar/openapi-parser'\n\nexport function isBasicAuthenticationRequired(\n operation: OpenAPI.Operation,\n schema?: ResolvedOpenAPI.Document,\n) {\n const allowedSecuritySchemes = operation.security?.map(\n (securityScheme: OpenAPIV3_1.SecurityRequirementObject) => {\n return Object.keys(securityScheme)[0]\n },\n )\n // Check if one of them is HTTP Basic Auth\n const httpBasicAuthIsRequired =\n allowedSecuritySchemes?.findIndex((securitySchemeKey: string) => {\n const securityScheme =\n schema?.components?.securitySchemes?.[securitySchemeKey]\n\n return (\n securityScheme?.type === 'http' && securityScheme?.scheme === 'basic'\n )\n }) !== undefined\n return httpBasicAuthIsRequired\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 {\n findPreferredResponseKey,\n isAuthenticationRequired,\n routeFromPath,\n} from './utils'\nimport { anyBasicAuthentication } from './utils/anyBasicAuthentication'\nimport { isBasicAuthenticationRequired } from './utils/isBasicAuthenticationRequired'\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 // Operations\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n // Check if authentication is required\n const requiresAuthentication = isAuthenticationRequired(\n operation.security,\n )\n // Get all available authentication methods\n const requiresBasicAuthentication = isBasicAuthenticationRequired(\n operation,\n result?.schema,\n )\n\n // Add HTTP basic authentication\n if (requiresAuthentication && requiresBasicAuthentication) {\n // @ts-expect-error Needs a proper type\n app[method](route, anyBasicAuthentication())\n }\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 operation,\n })\n }\n\n // Response\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 variables: c.req.param(),\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":["HTTPException","Hono","openapi","cors","getExampleFromSchema"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils/findPreferredResponseKey.ts","../src/utils/routeFromPath.ts","../src/utils/isAuthenticationRequired.ts","../src/utils/anyBasicAuthentication.ts","../src/utils/isBasicAuthenticationRequired.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 type { OpenAPIV3 } from '@scalar/openapi-parser'\n\n/**\n * Check whether the given security scheme key is in the `security` configuration for this operation.\n **/\nexport function isAuthenticationRequired(\n security?: OpenAPIV3.SecurityRequirementObject[],\n): boolean {\n // If security is not defined, auth is not required.\n if (!security) {\n return false\n }\n\n // Don’t require auth if security is just an empty array []\n if (Array.isArray(security) && !security.length) {\n return false\n }\n\n // Includes empty object = auth is not required\n if (\n (security ?? []).some(\n (securityRequirement) => !Object.keys(securityRequirement).length,\n )\n ) {\n return false\n }\n\n return true\n}\n","import type { Context } from 'hono'\nimport { HTTPException } from 'hono/http-exception'\n\n/**\n * Middleware to check for any basic authentication header\n */\nexport function anyBasicAuthentication() {\n return async function (ctx: Context, next: () => Promise<void>) {\n // Check if the request has an Authorization header\n // Note: We don’t care *what* credentials are sent, though.\n if (ctx.req.header('Authorization')?.startsWith('Basic ')) {\n return await next()\n }\n\n // Unauthorized\n throw new HTTPException(401, {\n res: new Response('Unauthorized', {\n status: 401,\n headers: {\n 'WWW-Authenticate': 'Basic realm=\"Authentication Required\"',\n },\n }),\n })\n }\n}\n","import type {\n OpenAPI,\n OpenAPIV3_1,\n ResolvedOpenAPI,\n} from '@scalar/openapi-parser'\n\nexport function isBasicAuthenticationRequired(\n operation: OpenAPI.Operation,\n schema?: ResolvedOpenAPI.Document,\n) {\n const allowedSecuritySchemes = operation.security?.map(\n (securityScheme: OpenAPIV3_1.SecurityRequirementObject) => {\n return Object.keys(securityScheme)[0]\n },\n )\n // Check if one of them is HTTP Basic Auth\n const httpBasicAuthIsRequired =\n allowedSecuritySchemes?.findIndex((securitySchemeKey: string) => {\n const securityScheme =\n schema?.components?.securitySchemes?.[securitySchemeKey]\n\n return (\n securityScheme?.type === 'http' && securityScheme?.scheme === 'basic'\n )\n }) !== undefined\n return httpBasicAuthIsRequired\n}\n","import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters'\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 {\n findPreferredResponseKey,\n isAuthenticationRequired,\n routeFromPath,\n} from './utils'\nimport { anyBasicAuthentication } from './utils/anyBasicAuthentication'\nimport { isBasicAuthenticationRequired } from './utils/isBasicAuthenticationRequired'\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 // Operations\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n // Check if authentication is required\n const requiresAuthentication = isAuthenticationRequired(\n operation.security,\n )\n // Get all available authentication methods\n const requiresBasicAuthentication = isBasicAuthenticationRequired(\n operation,\n result?.schema,\n )\n\n // Add HTTP basic authentication\n if (requiresAuthentication && requiresBasicAuthentication) {\n // @ts-expect-error Needs a proper type\n app[method](route, anyBasicAuthentication())\n }\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 operation,\n })\n }\n\n // Response\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 variables: c.req.param(),\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":["HTTPException","Hono","openapi","cors","getExampleFromSchema"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getExampleFromSchema } from '@scalar/oas-utils';
1
+ import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters';
2
2
  import { openapi } from '@scalar/openapi-parser';
3
3
  import { Hono } from 'hono';
4
4
  import { cors } from 'hono/cors';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/findPreferredResponseKey.ts","../src/utils/routeFromPath.ts","../src/utils/isAuthenticationRequired.ts","../src/utils/anyBasicAuthentication.ts","../src/utils/isBasicAuthenticationRequired.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 type { OpenAPIV3 } from '@scalar/openapi-parser'\n\n/**\n * Check whether the given security scheme key is in the `security` configuration for this operation.\n **/\nexport function isAuthenticationRequired(\n security?: OpenAPIV3.SecurityRequirementObject[],\n): boolean {\n // If security is not defined, auth is not required.\n if (!security) {\n return false\n }\n\n // Don’t require auth if security is just an empty array []\n if (Array.isArray(security) && !security.length) {\n return false\n }\n\n // Includes empty object = auth is not required\n if (\n (security ?? []).some(\n (securityRequirement) => !Object.keys(securityRequirement).length,\n )\n ) {\n return false\n }\n\n return true\n}\n","import type { Context } from 'hono'\nimport { HTTPException } from 'hono/http-exception'\n\n/**\n * Middleware to check for any basic authentication header\n */\nexport function anyBasicAuthentication() {\n return async function (ctx: Context, next: () => Promise<void>) {\n // Check if the request has an Authorization header\n // Note: We don’t care *what* credentials are sent, though.\n if (ctx.req.header('Authorization')?.startsWith('Basic ')) {\n return await next()\n }\n\n // Unauthorized\n throw new HTTPException(401, {\n res: new Response('Unauthorized', {\n status: 401,\n headers: {\n 'WWW-Authenticate': 'Basic realm=\"Authentication Required\"',\n },\n }),\n })\n }\n}\n","import type {\n OpenAPI,\n OpenAPIV3_1,\n ResolvedOpenAPI,\n} from '@scalar/openapi-parser'\n\nexport function isBasicAuthenticationRequired(\n operation: OpenAPI.Operation,\n schema?: ResolvedOpenAPI.Document,\n) {\n const allowedSecuritySchemes = operation.security?.map(\n (securityScheme: OpenAPIV3_1.SecurityRequirementObject) => {\n return Object.keys(securityScheme)[0]\n },\n )\n // Check if one of them is HTTP Basic Auth\n const httpBasicAuthIsRequired =\n allowedSecuritySchemes?.findIndex((securitySchemeKey: string) => {\n const securityScheme =\n schema?.components?.securitySchemes?.[securitySchemeKey]\n\n return (\n securityScheme?.type === 'http' && securityScheme?.scheme === 'basic'\n )\n }) !== undefined\n return httpBasicAuthIsRequired\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 {\n findPreferredResponseKey,\n isAuthenticationRequired,\n routeFromPath,\n} from './utils'\nimport { anyBasicAuthentication } from './utils/anyBasicAuthentication'\nimport { isBasicAuthenticationRequired } from './utils/isBasicAuthenticationRequired'\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 // Operations\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n // Check if authentication is required\n const requiresAuthentication = isAuthenticationRequired(\n operation.security,\n )\n // Get all available authentication methods\n const requiresBasicAuthentication = isBasicAuthenticationRequired(\n operation,\n result?.schema,\n )\n\n // Add HTTP basic authentication\n if (requiresAuthentication && requiresBasicAuthentication) {\n // @ts-expect-error Needs a proper type\n app[method](route, anyBasicAuthentication())\n }\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 operation,\n })\n }\n\n // Response\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 variables: c.req.param(),\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":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/findPreferredResponseKey.ts","../src/utils/routeFromPath.ts","../src/utils/isAuthenticationRequired.ts","../src/utils/anyBasicAuthentication.ts","../src/utils/isBasicAuthenticationRequired.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 type { OpenAPIV3 } from '@scalar/openapi-parser'\n\n/**\n * Check whether the given security scheme key is in the `security` configuration for this operation.\n **/\nexport function isAuthenticationRequired(\n security?: OpenAPIV3.SecurityRequirementObject[],\n): boolean {\n // If security is not defined, auth is not required.\n if (!security) {\n return false\n }\n\n // Don’t require auth if security is just an empty array []\n if (Array.isArray(security) && !security.length) {\n return false\n }\n\n // Includes empty object = auth is not required\n if (\n (security ?? []).some(\n (securityRequirement) => !Object.keys(securityRequirement).length,\n )\n ) {\n return false\n }\n\n return true\n}\n","import type { Context } from 'hono'\nimport { HTTPException } from 'hono/http-exception'\n\n/**\n * Middleware to check for any basic authentication header\n */\nexport function anyBasicAuthentication() {\n return async function (ctx: Context, next: () => Promise<void>) {\n // Check if the request has an Authorization header\n // Note: We don’t care *what* credentials are sent, though.\n if (ctx.req.header('Authorization')?.startsWith('Basic ')) {\n return await next()\n }\n\n // Unauthorized\n throw new HTTPException(401, {\n res: new Response('Unauthorized', {\n status: 401,\n headers: {\n 'WWW-Authenticate': 'Basic realm=\"Authentication Required\"',\n },\n }),\n })\n }\n}\n","import type {\n OpenAPI,\n OpenAPIV3_1,\n ResolvedOpenAPI,\n} from '@scalar/openapi-parser'\n\nexport function isBasicAuthenticationRequired(\n operation: OpenAPI.Operation,\n schema?: ResolvedOpenAPI.Document,\n) {\n const allowedSecuritySchemes = operation.security?.map(\n (securityScheme: OpenAPIV3_1.SecurityRequirementObject) => {\n return Object.keys(securityScheme)[0]\n },\n )\n // Check if one of them is HTTP Basic Auth\n const httpBasicAuthIsRequired =\n allowedSecuritySchemes?.findIndex((securitySchemeKey: string) => {\n const securityScheme =\n schema?.components?.securitySchemes?.[securitySchemeKey]\n\n return (\n securityScheme?.type === 'http' && securityScheme?.scheme === 'basic'\n )\n }) !== undefined\n return httpBasicAuthIsRequired\n}\n","import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters'\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 {\n findPreferredResponseKey,\n isAuthenticationRequired,\n routeFromPath,\n} from './utils'\nimport { anyBasicAuthentication } from './utils/anyBasicAuthentication'\nimport { isBasicAuthenticationRequired } from './utils/isBasicAuthenticationRequired'\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 // Operations\n Object.keys(result.schema?.paths?.[path] ?? {}).forEach((method) => {\n const route = routeFromPath(path)\n\n // @ts-expect-error Needs a proper type\n const operation = result.schema?.paths?.[path]?.[method]\n\n // Check if authentication is required\n const requiresAuthentication = isAuthenticationRequired(\n operation.security,\n )\n // Get all available authentication methods\n const requiresBasicAuthentication = isBasicAuthenticationRequired(\n operation,\n result?.schema,\n )\n\n // Add HTTP basic authentication\n if (requiresAuthentication && requiresBasicAuthentication) {\n // @ts-expect-error Needs a proper type\n app[method](route, anyBasicAuthentication())\n }\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 operation,\n })\n }\n\n // Response\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 variables: c.req.param(),\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":"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"}
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "swagger",
17
17
  "cli"
18
18
  ],
19
- "version": "0.1.71",
19
+ "version": "0.2.0",
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.16"
38
+ "@scalar/oas-utils": "0.2.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^20.8.4",
@@ -47,7 +47,8 @@
47
47
  "tslib": "^2.6.2",
48
48
  "typescript": "^5.4.3",
49
49
  "vite-node": "^1.3.1",
50
- "@scalar/galaxy": "0.1.4"
50
+ "@scalar/galaxy": "0.2.0",
51
+ "@scalar/build-tooling": "0.1.5"
51
52
  },
52
53
  "scripts": {
53
54
  "build": "rm -Rf dist/ && rollup -c",