@trojs/openapi-server 3.3.1 → 3.4.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@trojs/openapi-server",
3
3
  "description": "OpenAPI Server",
4
- "version": "3.3.1",
4
+ "version": "3.4.3",
5
5
  "author": {
6
6
  "name": "Pieter Wigboldus",
7
7
  "url": "https://trojs.org/"
@@ -13,9 +13,12 @@
13
13
  "lint:fix": "eslint --fix",
14
14
  "test": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter=lcov --test-reporter-destination=stdout --test-reporter-destination=./coverage/lcov.info",
15
15
  "cpd": "node_modules/jscpd/bin/jscpd src",
16
- "vulnerabilities": "npm audit --omit=dev"
16
+ "vulnerabilities": "npm audit --omit=dev",
17
+ "build:types": "tsc",
18
+ "prepublishOnly": "rm -rf types && npm run build:types"
17
19
  },
18
20
  "type": "module",
21
+ "types": "types/server.d.ts",
19
22
  "files": [
20
23
  "src/api.js",
21
24
  "src/openapi.js",
@@ -29,25 +32,27 @@
29
32
  "src/handlers/not-found.js",
30
33
  "src/handlers/request-validation.js",
31
34
  "src/handlers/response-validation.js",
32
- "src/handlers/unauthorized.js"
35
+ "src/handlers/unauthorized.js",
36
+ "types/**"
33
37
  ],
34
38
  "main": "src/server.js",
35
39
  "devDependencies": {
36
- "@trojs/lint": "^0.3.0",
37
- "@types/node": "^22.0.0",
40
+ "@trojs/lint": "^0.4.0",
41
+ "@types/node": "^24.0.0",
38
42
  "@types/express-serve-static-core": "^5.0.0",
39
43
  "eslint": "^9.15.0",
40
44
  "globals": "^16.0.0",
41
45
  "jscpd": "^4.0.5",
42
46
  "prettier": "^3.3.3",
43
- "supertest": "^7.0.0"
47
+ "supertest": "^7.0.0",
48
+ "typescript": "^5.9.2"
44
49
  },
45
50
  "repository": {
46
51
  "type": "git",
47
52
  "url": "https://github.com/trojs/openapi-server"
48
53
  },
49
54
  "engines": {
50
- "node": ">= 20 < 21 || >= 22 < 23"
55
+ "node": ">= 20 < 21 || >= 22 < 25"
51
56
  },
52
57
  "keywords": [
53
58
  "openapi",
@@ -20,7 +20,7 @@ import { parseParams } from './params.js'
20
20
  * @returns {Function}
21
21
  */
22
22
  export const makeExpressCallback
23
- = ({ controller, specification, errorDetails, logger, meta, mock }) =>
23
+ = ({ controller, specification, errorDetails, logger, meta, mock }) =>
24
24
  /**
25
25
  * Handle controller
26
26
  * @async
@@ -29,68 +29,68 @@ export const makeExpressCallback
29
29
  * @param {Response} response
30
30
  * @returns {Promise<any>}
31
31
  */
32
- async (context, request, response) => {
33
- try {
34
- const allParameters = {
35
- ...(context.request?.params || {}),
36
- ...(context.request?.query || {})
37
- }
38
- const parameters = parseParams({
39
- query: allParameters,
40
- spec: context.operation.parameters,
41
- mock
42
- })
43
- const url = `${request.protocol}://${request.get('Host')}${request.originalUrl}`
44
-
45
- const responseBody = await controller({
46
- context,
47
- request,
48
- response,
49
- parameters,
50
- specification,
51
- post: request.body,
52
- url,
53
- logger,
54
- meta
55
- })
56
- logger.debug({
57
- url,
58
- parameters,
59
- post: request.body,
60
- response: responseBody
61
- })
32
+ async (context, request, response) => {
33
+ try {
34
+ const allParameters = {
35
+ ...(context.request?.params || {}),
36
+ ...(context.request?.query || {})
37
+ }
38
+ const parameters = parseParams({
39
+ query: allParameters,
40
+ spec: context.operation.parameters,
41
+ mock
42
+ })
43
+ const url = `${request.protocol}://${request.get('Host')}${request.originalUrl}`
62
44
 
63
- return responseBody
64
- } catch (error) {
65
- const errorCodeStatus = getStatusByError(error)
45
+ const responseBody = await controller({
46
+ context,
47
+ request,
48
+ response,
49
+ parameters,
50
+ specification,
51
+ post: request.body,
52
+ url,
53
+ logger,
54
+ meta
55
+ })
56
+ logger.debug({
57
+ url,
58
+ parameters,
59
+ post: request.body,
60
+ response: responseBody
61
+ })
66
62
 
67
- if (errorCodeStatus >= 500) {
68
- logger.error(error)
69
- } else {
70
- logger.warn(error)
71
- }
63
+ return responseBody
64
+ } catch (error) {
65
+ const errorCodeStatus = getStatusByError(error)
72
66
 
73
- response.status(errorCodeStatus)
67
+ if (errorCodeStatus >= 500) {
68
+ logger.error(error)
69
+ } else {
70
+ logger.warn(error)
71
+ }
74
72
 
75
- if (errorDetails) {
76
- return {
77
- errors: [
78
- {
79
- message: error.message,
80
- value: error.valueOf(),
81
- type: error.constructor.name
82
- }
83
- ],
84
- status: errorCodeStatus,
85
- timestamp: new Date(),
86
- message: error.message
87
- }
88
- }
73
+ response.status(errorCodeStatus)
89
74
 
75
+ if (errorDetails) {
90
76
  return {
77
+ errors: [
78
+ {
79
+ message: error.message,
80
+ value: error.valueOf(),
81
+ type: error.constructor.name
82
+ }
83
+ ],
91
84
  status: errorCodeStatus,
92
85
  timestamp: new Date(),
93
86
  message: error.message
94
87
  }
95
88
  }
89
+
90
+ return {
91
+ status: errorCodeStatus,
92
+ timestamp: new Date(),
93
+ message: error.message
94
+ }
96
95
  }
96
+ }
package/src/router.js CHANGED
@@ -82,7 +82,7 @@ export const setupRouter = ({
82
82
 
83
83
  api.register('notImplemented', (context) => {
84
84
  const { mock: mockImplementation }
85
- = context.api.mockResponseForOperation(context.operation.operationId)
85
+ = context.api.mockResponseForOperation(context.operation.operationId)
86
86
  return mockImplementation
87
87
  })
88
88
 
package/types/api.d.ts ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @typedef {import('openapi-backend').Handler} Handler
3
+ * @typedef {import('ajv').Options} AjvOpts
4
+ * @typedef {object} Logger
5
+ * @property {Function} error
6
+ * @property {Function} warn
7
+ * @property {Function} info
8
+ * @property {Function} debug
9
+ * @typedef {object} SecurityHandler
10
+ * @property {string} name
11
+ * @property {Handler} handler
12
+ * @typedef {object} ApiSchema
13
+ * @property {string} version
14
+ * @property {object} specification
15
+ * @property {object} controllers
16
+ * @property {string=} apiRoot
17
+ * @property {boolean=} strictSpecification
18
+ * @property {boolean=} errorDetails
19
+ * @property {Logger=} logger
20
+ * @property {object=} meta
21
+ * @property {SecurityHandler[]=} securityHandlers
22
+ * @property {boolean=} swagger
23
+ * @property {boolean=} apiDocs
24
+ * @property {AjvOpts=} ajvOptions
25
+ * @property {any[]=} middleware
26
+ */
27
+ /**
28
+ * Setup the server for a specific API, so every server can run multiple instances of the API,
29
+ * like different versions, for e.g. different clients
30
+ */
31
+ export class Api {
32
+ /**
33
+ * Create a new instance of the API
34
+ * @class
35
+ * @param {ApiSchema} params
36
+ */
37
+ constructor({ version, specification, controllers, apiRoot, strictSpecification, errorDetails, logger, meta, securityHandlers, swagger, apiDocs, ajvOptions, middleware }: ApiSchema);
38
+ version: string;
39
+ specification: object;
40
+ controllers: object;
41
+ apiRoot: string | undefined;
42
+ strictSpecification: boolean | undefined;
43
+ errorDetails: boolean;
44
+ logger: Logger;
45
+ meta: object;
46
+ securityHandlers: SecurityHandler[];
47
+ swagger: boolean;
48
+ apiDocs: boolean;
49
+ ajvOptions: import("ajv").Options;
50
+ middleware: any[];
51
+ setup(): any;
52
+ }
53
+ export type Handler = import("openapi-backend").Handler;
54
+ export type AjvOpts = import("ajv").Options;
55
+ export type Logger = {
56
+ error: Function;
57
+ warn: Function;
58
+ info: Function;
59
+ debug: Function;
60
+ };
61
+ export type SecurityHandler = {
62
+ name: string;
63
+ handler: Handler;
64
+ };
65
+ export type ApiSchema = {
66
+ version: string;
67
+ specification: object;
68
+ controllers: object;
69
+ apiRoot?: string | undefined;
70
+ strictSpecification?: boolean | undefined;
71
+ errorDetails?: boolean | undefined;
72
+ logger?: Logger | undefined;
73
+ meta?: object | undefined;
74
+ securityHandlers?: SecurityHandler[] | undefined;
75
+ swagger?: boolean | undefined;
76
+ apiDocs?: boolean | undefined;
77
+ ajvOptions?: AjvOpts | undefined;
78
+ middleware?: any[] | undefined;
79
+ };
80
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;GAGG;AAEH;IACE;;;;OAIG;IACH,2KAFW,SAAS,EA8BnB;IAbC,gBAAsB;IACtB,sBAAkC;IAClC,oBAA8B;IAC9B,4BAAsB;IACtB,yCAA8C;IAC9C,sBAAyC;IACzC,eAA+B;IAC/B,aAAsB;IACtB,oCAA8C;IAC9C,iBAA8B;IAC9B,iBAA8B;IAC9B,kCAAoD;IACpD,kBAA4B;IAG9B,aAoDC;CACF;sBAxHY,OAAO,iBAAiB,EAAE,OAAO;sBACjC,OAAO,KAAK,EAAE,OAAO;;;;;;;;UAOpB,MAAM;aACN,OAAO;;;aAEP,MAAM;mBACN,MAAM;iBACN,MAAM;cACN,MAAM,YAAC;0BACP,OAAO,YAAC;mBACR,OAAO,YAAC;aACR,MAAM,YAAC;WACP,MAAM,YAAC;uBACP,eAAe,EAAE,YAAC;cAClB,OAAO,YAAC;cACR,OAAO,YAAC;iBACR,OAAO,YAAC;iBACR,GAAG,EAAE,YAAC"}
@@ -0,0 +1,3 @@
1
+ declare function _default(error: Error): number;
2
+ export default _default;
3
+ //# sourceMappingURL=error-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-status.d.ts","sourceRoot":"","sources":["../src/error-status.js"],"names":[],"mappings":"AAqBe,iCAHJ,KAAK,GACH,MAAM,CAIR"}
@@ -0,0 +1,13 @@
1
+ export function makeExpressCallback({ controller, specification, errorDetails, logger, meta, mock }: {
2
+ controller: Function;
3
+ specification: object;
4
+ errorDetails?: boolean | undefined;
5
+ logger?: Logger | undefined;
6
+ meta?: object | undefined;
7
+ mock?: boolean | undefined;
8
+ }): Function;
9
+ export type Request = import("express-serve-static-core").Request;
10
+ export type Response = import("express-serve-static-core").Response;
11
+ export type Context = import("openapi-backend").Context;
12
+ export type Logger = import("./api.js").Logger;
13
+ //# sourceMappingURL=express-callback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express-callback.d.ts","sourceRoot":"","sources":["../src/express-callback.js"],"names":[],"mappings":"AAqBO,qGARJ;IAAyB,UAAU;IACZ,aAAa,EAA5B,MAAM;IACW,YAAY,GAA7B,OAAO,YAAC;IACQ,MAAM,GAAtB,MAAM,YAAC;IACS,IAAI,GAApB,MAAM,YAAC;IACU,IAAI,GAArB,OAAO,YAAC;CAChB,YA4EE;sBA3FQ,OAAO,2BAA2B,EAAE,OAAO;uBAC3C,OAAO,2BAA2B,EAAE,QAAQ;sBAC5C,OAAO,iBAAiB,EAAE,OAAO;qBACjC,OAAO,UAAU,EAAE,MAAM"}
@@ -0,0 +1,6 @@
1
+ export function notFound(_context: any, request: any, response: any): {
2
+ status: number;
3
+ timestamp: Date;
4
+ message: string;
5
+ };
6
+ //# sourceMappingURL=not-found.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-found.d.ts","sourceRoot":"","sources":["../../src/handlers/not-found.js"],"names":[],"mappings":"AAAO;;;;EAON"}
@@ -0,0 +1,7 @@
1
+ export function requestValidation(context: any, request: any, response: any): {
2
+ errors: any;
3
+ status: number;
4
+ timestamp: Date;
5
+ message: string;
6
+ };
7
+ //# sourceMappingURL=request-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-validation.d.ts","sourceRoot":"","sources":["../../src/handlers/request-validation.js"],"names":[],"mappings":"AAAO;;;;;EAQN"}
@@ -0,0 +1,3 @@
1
+ declare function _default(logger: any): (context: any, request: any, response: any) => any;
2
+ export default _default;
3
+ //# sourceMappingURL=response-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-validation.d.ts","sourceRoot":"","sources":["../../src/handlers/response-validation.js"],"names":[],"mappings":"AAAe,yCAAa,YAAO,EAAE,YAAO,EAAE,aAAQ,SAsCrD"}
@@ -0,0 +1,6 @@
1
+ export function unauthorized(context: any, request: any, response: any): Promise<{
2
+ status: number;
3
+ timestamp: Date;
4
+ message: string;
5
+ }>;
6
+ //# sourceMappingURL=unauthorized.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unauthorized.d.ts","sourceRoot":"","sources":["../../src/handlers/unauthorized.js"],"names":[],"mappings":"AAAO;;;;GAON"}
@@ -0,0 +1,7 @@
1
+ export function openAPI({ file, base }: {
2
+ file: string;
3
+ base?: string | undefined;
4
+ }): Promise<{
5
+ openAPISpecification: object;
6
+ }>;
7
+ //# sourceMappingURL=openapi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.js"],"names":[],"mappings":"AAUO,wCAJJ;IAAuB,IAAI,EAAnB,MAAM;IACU,IAAI,GAApB,MAAM,YAAC;CACf,GAAU,OAAO,CAAC;IAAE,oBAAoB,EAAE,MAAM,CAAC;CAAE,CAAC,CAMtD"}
@@ -0,0 +1,4 @@
1
+ export function operationIds({ specification }: {
2
+ specification: object;
3
+ }): string[];
4
+ //# sourceMappingURL=operation-ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-ids.d.ts","sourceRoot":"","sources":["../src/operation-ids.js"],"names":[],"mappings":"AAQO,gDAHJ;IAAuB,aAAa,EAA5B,MAAM;CACd,GAAU,MAAM,EAAE,CASV"}
@@ -0,0 +1,6 @@
1
+ export function parseParams({ query, spec, mock }: {
2
+ query: object;
3
+ spec: object;
4
+ mock?: boolean | undefined;
5
+ }): object;
6
+ //# sourceMappingURL=params.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../src/params.js"],"names":[],"mappings":"AAUO,mDALJ;IAAuB,KAAK,EAApB,MAAM;IACS,IAAI,EAAnB,MAAM;IACW,IAAI,GAArB,OAAO,YAAC;CAChB,GAAU,MAAM,CAwCT"}
@@ -0,0 +1,22 @@
1
+ export function setupRouter({ openAPISpecification, controllers, apiRoot, strictSpecification, errorDetails, logger, meta, securityHandlers, ajvOptions, customizeAjv, mock }: {
2
+ openAPISpecification: object;
3
+ controllers: object;
4
+ apiRoot?: string | undefined;
5
+ strictSpecification?: boolean | undefined;
6
+ errorDetails?: boolean | undefined;
7
+ logger?: Logger | undefined;
8
+ meta?: object | undefined;
9
+ securityHandlers?: SecurityHandler[] | undefined;
10
+ ajvOptions?: AjvOpts | undefined;
11
+ customizeAjv?: AjvCustomizer | undefined;
12
+ mock?: boolean | undefined;
13
+ }): {
14
+ api: OpenAPIBackend<any>;
15
+ openAPISpecification: object;
16
+ };
17
+ export type Logger = import("./api.js").Logger;
18
+ export type SecurityHandler = import("./api.js").SecurityHandler;
19
+ export type AjvOpts = import("ajv").Options;
20
+ export type AjvCustomizer = import("openapi-backend").AjvCustomizer;
21
+ import { OpenAPIBackend } from 'openapi-backend';
22
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.js"],"names":[],"mappings":"AAgCO,+KAbJ;IAAuB,oBAAoB,EAAnC,MAAM;IACS,WAAW,EAA1B,MAAM;IACU,OAAO,GAAvB,MAAM,YAAC;IACU,mBAAmB,GAApC,OAAO,YAAC;IACS,YAAY,GAA7B,OAAO,YAAC;IACQ,MAAM,GAAtB,MAAM,YAAC;IACS,IAAI,GAApB,MAAM,YAAC;IACoB,gBAAgB,GAA3C,eAAe,EAAE,YAAC;IACD,UAAU,GAA3B,OAAO,YAAC;IACe,YAAY,GAAnC,aAAa,YAAC;IACG,IAAI,GAArB,OAAO,YAAC;CAChB,GAAU;IAAE,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAA;CAAE,CAkEtE;qBAtFY,OAAO,UAAU,EAAE,MAAM;8BACzB,OAAO,UAAU,EAAE,eAAe;sBAClC,OAAO,KAAK,EAAE,OAAO;4BACrB,OAAO,iBAAiB,EAAE,aAAa;+BAbrB,iBAAiB"}
@@ -0,0 +1,41 @@
1
+ export function setupServer({ apis, origin, staticFolder, sentry, poweredBy, version, middleware, maximumBodySize }: {
2
+ apis: ApiSchema[];
3
+ origin?: string | undefined;
4
+ staticFolder?: string | undefined;
5
+ sentry?: SentryConfig | undefined;
6
+ poweredBy?: string | undefined;
7
+ version?: string | undefined;
8
+ middleware?: any[] | undefined;
9
+ maximumBodySize?: (string | number) | undefined;
10
+ }): Promise<{
11
+ app: Express;
12
+ }>;
13
+ export type Request = import("express-serve-static-core").Request;
14
+ export type Response = import("express-serve-static-core").Response;
15
+ export type Context = import("openapi-backend").Context;
16
+ export type ApiSchema = import("./api.js").ApiSchema;
17
+ export type Logger = import("./api.js").Logger;
18
+ export type Express = any;
19
+ export type Integration = any;
20
+ export type Controller<T extends object = object> = {
21
+ context?: Context | undefined;
22
+ request?: Request | undefined;
23
+ response?: Response | undefined;
24
+ parameters?: object | undefined;
25
+ specification?: object | undefined;
26
+ post?: T | undefined;
27
+ url?: string | undefined;
28
+ logger?: Logger | undefined;
29
+ meta?: object | undefined;
30
+ };
31
+ export type SentryConfig = {
32
+ dsn?: string | undefined;
33
+ tracesSampleRate?: number | undefined;
34
+ profilesSampleRate?: number | undefined;
35
+ release?: string | undefined;
36
+ integrations?: Integration[] | undefined;
37
+ };
38
+ import { openAPI } from './openapi.js';
39
+ import { Api } from './api.js';
40
+ export { openAPI, Api };
41
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.js"],"names":[],"mappings":"AAyEO,qHAVJ;IAA4B,IAAI,EAAxB,SAAS,EAAE;IACK,MAAM,GAAtB,MAAM,YAAC;IACS,YAAY,GAA5B,MAAM,YAAC;IACe,MAAM,GAA5B,YAAY,YAAC;IACG,SAAS,GAAzB,MAAM,YAAC;IACS,OAAO,GAAvB,MAAM,YAAC;IACQ,UAAU,GAAzB,GAAG,EAAE,YAAC;IACiB,eAAe,GAAtC,CAAA,MAAM,GAAC,MAAM,aAAC;CACtB,GAAU,OAAO,CAAC;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC,CAuDrC;sBAnGY,OAAO,2BAA2B,EAAE,OAAO;uBAC3C,OAAO,2BAA2B,EAAE,QAAQ;sBAC5C,OAAO,iBAAiB,EAAE,OAAO;wBACjC,OAAO,UAAU,EAAE,SAAS;qBAC5B,OAAO,UAAU,EAAE,MAAM;;;uBAMf,CAAC,SAAX,MAAQ;cAEP,OAAO,YAAC;cACR,OAAO,YAAC;eACR,QAAQ,YAAC;iBACT,MAAM,YAAC;oBACP,MAAM,YAAC;WACP,CAAC,YAAC;UACF,MAAM,YAAC;aACP,MAAM,YAAC;WACP,MAAM,YAAC;;;UAKP,MAAM,YAAC;uBACP,MAAM,YAAC;yBACP,MAAM,YAAC;cACP,MAAM,YAAC;mBACP,WAAW,EAAE,YAAC;;wBAlDJ,cAAc;oBAClB,UAAU"}
@@ -0,0 +1,18 @@
1
+ export namespace types {
2
+ let string: StringConstructor;
3
+ let array: ArrayConstructor;
4
+ let object: ObjectConstructor;
5
+ let number: NumberConstructor;
6
+ let integer: NumberConstructor;
7
+ let boolean: BooleanConstructor;
8
+ let url: {
9
+ new (url: string | URL, base?: string | URL): URL;
10
+ prototype: URL;
11
+ canParse(url: string | URL, base?: string | URL): boolean;
12
+ createObjectURL(obj: Blob | MediaSource): string;
13
+ parse(url: string | URL, base?: string | URL): URL | null;
14
+ revokeObjectURL(url: string): void;
15
+ };
16
+ let date: DateConstructor;
17
+ }
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.js"],"names":[],"mappings":""}