@sebspark/openapi-express 5.2.0 → 5.3.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/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +21 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/router.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/router.ts"],"mappings":";;;;cAmCa,WAAA,GACX,GAAA,EAAK,mBAAA,EACL,OAAA,GAAS,gBAAA,KACR,MAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ATTR_ERROR_TYPE, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, ATTR_NETWORK_PROTOCOL_VERSION, ATTR_SERVER_ADDRESS, ATTR_URL_PATH, ATTR_URL_SCHEME, METRIC_HTTP_SERVER_REQUEST_DURATION } from "@opentelemetry/semantic-conventions";
|
|
1
|
+
import { ATTR_CLIENT_ADDRESS, ATTR_ERROR_TYPE, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, ATTR_NETWORK_PROTOCOL_VERSION, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_PATH, ATTR_URL_QUERY, ATTR_URL_SCHEME, ATTR_USER_AGENT_ORIGINAL, METRIC_HTTP_SERVER_REQUEST_DURATION } from "@opentelemetry/semantic-conventions";
|
|
2
2
|
import { createHttpError } from "@sebspark/openapi-core";
|
|
3
3
|
import { SpanStatusCode, getLogger, getTracer } from "@sebspark/otel";
|
|
4
4
|
import { Router, json } from "express";
|
|
@@ -17,14 +17,23 @@ const TypedRouter = (api, options = {}) => {
|
|
|
17
17
|
const handler = async (req, res, next) => {
|
|
18
18
|
const startTime = performance.now();
|
|
19
19
|
const span = tracer.startSpan(`${method.toUpperCase()} ${url}`);
|
|
20
|
-
|
|
20
|
+
const query = req.url.split("?")[1];
|
|
21
|
+
const port = req.socket.localPort;
|
|
22
|
+
const ip = req.ip;
|
|
23
|
+
const userAgent = req.get("user-agent");
|
|
24
|
+
const requestAttributes = {
|
|
21
25
|
[ATTR_HTTP_REQUEST_METHOD]: req.method,
|
|
22
26
|
[ATTR_HTTP_ROUTE]: url,
|
|
23
27
|
[ATTR_URL_PATH]: req.path,
|
|
28
|
+
...query && { [ATTR_URL_QUERY]: query },
|
|
24
29
|
[ATTR_URL_SCHEME]: req.protocol,
|
|
25
30
|
[ATTR_SERVER_ADDRESS]: req.hostname,
|
|
26
|
-
[
|
|
27
|
-
|
|
31
|
+
...port && { [ATTR_SERVER_PORT]: port },
|
|
32
|
+
[ATTR_NETWORK_PROTOCOL_VERSION]: req.httpVersion,
|
|
33
|
+
...ip && { [ATTR_CLIENT_ADDRESS]: ip },
|
|
34
|
+
...userAgent && { [ATTR_USER_AGENT_ORIGINAL]: userAgent }
|
|
35
|
+
};
|
|
36
|
+
span.setAttributes(requestAttributes);
|
|
28
37
|
try {
|
|
29
38
|
const [status, response] = await route.handler(req);
|
|
30
39
|
res.status(status);
|
|
@@ -38,7 +47,10 @@ const TypedRouter = (api, options = {}) => {
|
|
|
38
47
|
if (headers) for (const [name, value] of Object.entries(headers)) res.setHeader(name, value);
|
|
39
48
|
if (data) res.send(data);
|
|
40
49
|
else res.end();
|
|
41
|
-
logger.info(`${method.toUpperCase()} ${url} ${status}`, {
|
|
50
|
+
logger.info(`${method.toUpperCase()} ${url} ${status}`, {
|
|
51
|
+
...requestAttributes,
|
|
52
|
+
[METRIC_HTTP_SERVER_REQUEST_DURATION]: (performance.now() - startTime) / 1e3
|
|
53
|
+
});
|
|
42
54
|
} catch (error) {
|
|
43
55
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
44
56
|
span.recordException(err);
|
|
@@ -48,7 +60,10 @@ const TypedRouter = (api, options = {}) => {
|
|
|
48
60
|
});
|
|
49
61
|
span.setAttribute(ATTR_ERROR_TYPE, err.constructor.name);
|
|
50
62
|
if (err.statusCode) span.setAttributes({ [ATTR_HTTP_RESPONSE_STATUS_CODE]: err.statusCode });
|
|
51
|
-
logger.error(`${method.toUpperCase()} ${url}`, err, {
|
|
63
|
+
logger.error(`${method.toUpperCase()} ${url}`, err, {
|
|
64
|
+
...requestAttributes,
|
|
65
|
+
[METRIC_HTTP_SERVER_REQUEST_DURATION]: (performance.now() - startTime) / 1e3
|
|
66
|
+
});
|
|
52
67
|
next(error);
|
|
53
68
|
} finally {
|
|
54
69
|
span.setAttribute(METRIC_HTTP_SERVER_REQUEST_DURATION, (performance.now() - startTime) / 1e3);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["pkg.name"],"sources":["../package.json","../src/router.ts"],"sourcesContent":["","import {\n ATTR_ERROR_TYPE,\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_HTTP_ROUTE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n METRIC_HTTP_SERVER_REQUEST_DURATION,\n} from '@opentelemetry/semantic-conventions'\nimport {\n type APIResponse,\n type APIServerDefinition,\n type APIServerOptions,\n createHttpError,\n type HttpError,\n type Verb,\n} from '@sebspark/openapi-core'\nimport { getLogger, getTracer, SpanStatusCode } from '@sebspark/otel'\nimport {\n type ErrorRequestHandler,\n json,\n type NextFunction,\n type Request,\n type RequestHandler,\n type Response,\n Router,\n} from 'express'\nimport pkg from '../package.json' with { type: 'json' }\n\nexport const TypedRouter = (\n api: APIServerDefinition,\n options: APIServerOptions = {}\n): Router => {\n const logger = getLogger(pkg.name)\n const tracer = getTracer(pkg.name)\n const router = Router()\n\n router.use(json() as unknown as RequestHandler)\n\n // Add global pre to router\n const preUsings = Array.isArray(options.pre)\n ? options.pre\n : options.pre\n ? [options.pre]\n : []\n for (const pre of preUsings) {\n router.use(pre)\n }\n\n // loop through urls on server definition\n for (const [url, methods] of Object.entries(api)) {\n // loop through methods on url\n for (const [method, route] of Object.entries(methods)) {\n // Build handler for url/method\n const handler = async (\n req: Request,\n res: Response,\n next: NextFunction\n ) => {\n const startTime = performance.now()\n const span = tracer.startSpan(`${method.toUpperCase()} ${url}`)\n
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["pkg.name"],"sources":["../package.json","../src/router.ts"],"sourcesContent":["","import {\n ATTR_CLIENT_ADDRESS,\n ATTR_ERROR_TYPE,\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_HTTP_ROUTE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_PATH,\n ATTR_URL_QUERY,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n METRIC_HTTP_SERVER_REQUEST_DURATION,\n} from '@opentelemetry/semantic-conventions'\nimport {\n type APIResponse,\n type APIServerDefinition,\n type APIServerOptions,\n createHttpError,\n type HttpError,\n type Verb,\n} from '@sebspark/openapi-core'\nimport { getLogger, getTracer, SpanStatusCode } from '@sebspark/otel'\nimport {\n type ErrorRequestHandler,\n json,\n type NextFunction,\n type Request,\n type RequestHandler,\n type Response,\n Router,\n} from 'express'\nimport pkg from '../package.json' with { type: 'json' }\n\nexport const TypedRouter = (\n api: APIServerDefinition,\n options: APIServerOptions = {}\n): Router => {\n const logger = getLogger(pkg.name)\n const tracer = getTracer(pkg.name)\n const router = Router()\n\n router.use(json() as unknown as RequestHandler)\n\n // Add global pre to router\n const preUsings = Array.isArray(options.pre)\n ? options.pre\n : options.pre\n ? [options.pre]\n : []\n for (const pre of preUsings) {\n router.use(pre)\n }\n\n // loop through urls on server definition\n for (const [url, methods] of Object.entries(api)) {\n // loop through methods on url\n for (const [method, route] of Object.entries(methods)) {\n // Build handler for url/method\n const handler = async (\n req: Request,\n res: Response,\n next: NextFunction\n ) => {\n const startTime = performance.now()\n const span = tracer.startSpan(`${method.toUpperCase()} ${url}`)\n const query = req.url.split('?')[1]\n const port = req.socket.localPort\n const ip = req.ip\n const userAgent = req.get('user-agent')\n const requestAttributes = {\n [ATTR_HTTP_REQUEST_METHOD]: req.method,\n [ATTR_HTTP_ROUTE]: url,\n [ATTR_URL_PATH]: req.path,\n ...(query && { [ATTR_URL_QUERY]: query }),\n [ATTR_URL_SCHEME]: req.protocol,\n [ATTR_SERVER_ADDRESS]: req.hostname,\n ...(port && { [ATTR_SERVER_PORT]: port }),\n [ATTR_NETWORK_PROTOCOL_VERSION]: req.httpVersion,\n ...(ip && { [ATTR_CLIENT_ADDRESS]: ip }),\n ...(userAgent && { [ATTR_USER_AGENT_ORIGINAL]: userAgent }),\n }\n span.setAttributes(requestAttributes)\n\n try {\n const [status, response] = await route.handler(req)\n res.status(status)\n\n span.setAttributes({ [ATTR_HTTP_RESPONSE_STATUS_CODE]: status })\n span.setStatus({ code: SpanStatusCode.OK })\n\n if (!response) {\n res.end()\n return\n }\n\n const { headers, data } = response as APIResponse<\n unknown,\n Record<string, string>\n >\n\n if (headers) {\n for (const [name, value] of Object.entries(headers)) {\n res.setHeader(name, value)\n }\n }\n\n if (data) {\n res.send(data)\n } else {\n res.end()\n }\n\n logger.info(`${method.toUpperCase()} ${url} ${status}`, {\n ...requestAttributes,\n [METRIC_HTTP_SERVER_REQUEST_DURATION]:\n (performance.now() - startTime) / 1000,\n })\n } catch (error) {\n const err = (\n error instanceof Error ? error : new Error(String(error))\n ) as HttpError\n span.recordException(err)\n span.setStatus({ code: SpanStatusCode.ERROR, message: err.message })\n span.setAttribute(ATTR_ERROR_TYPE, err.constructor.name)\n\n if (err.statusCode) {\n span.setAttributes({\n [ATTR_HTTP_RESPONSE_STATUS_CODE]: err.statusCode,\n })\n }\n\n logger.error(`${method.toUpperCase()} ${url}`, err, {\n ...requestAttributes,\n [METRIC_HTTP_SERVER_REQUEST_DURATION]:\n (performance.now() - startTime) / 1000,\n })\n\n next(error)\n } finally {\n span.setAttribute(\n METRIC_HTTP_SERVER_REQUEST_DURATION,\n (performance.now() - startTime) / 1000\n )\n span.end()\n }\n }\n\n const pre = Array.isArray(route.pre)\n ? route.pre\n : route.pre\n ? [route.pre]\n : []\n const handlers = pre.concat(handler as RequestHandler)\n\n router[method as Verb](url, ...handlers)\n }\n }\n\n router.use(errorHandler)\n\n return router\n}\n\nconst errorHandler: ErrorRequestHandler = (err, _req, res, next) => {\n let error: HttpError = err\n\n if (!error.message || !error.statusCode) {\n const internal =\n err instanceof Error\n ? err\n : typeof err === 'string'\n ? new Error(err)\n : new Error(JSON.stringify(err || ''))\n error = createHttpError(500, undefined, internal)\n }\n\n const showStack = process.env.NODE_ENV !== 'production'\n res.status(error.statusCode).send(error.toJSON(showStack))\n next(error)\n}\n"],"mappings":"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"}
|