@twin.org/api-processors 0.0.3-next.2 → 0.0.3-next.4

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.
@@ -72,10 +72,14 @@ export class LoggingProcessor {
72
72
  level: "info",
73
73
  source: LoggingProcessor.CLASS_NAME,
74
74
  ts: Date.now(),
75
- message: `===> ${request.method} ${requestUrl}`,
76
- data: this._includeBody && isJson
77
- ? this.processJson("body", ObjectHelper.clone(request?.body))
78
- : undefined
75
+ message: "requestMessage",
76
+ data: {
77
+ method: request.method,
78
+ requestUrl,
79
+ body: this._includeBody && isJson
80
+ ? this.processJson("body", ObjectHelper.clone(request?.body))
81
+ : undefined
82
+ }
79
83
  });
80
84
  }
81
85
  /**
@@ -126,15 +130,36 @@ export class LoggingProcessor {
126
130
  requestUrl = request.url;
127
131
  }
128
132
  }
129
- await this._logging?.log({
130
- level: Is.number(response.statusCode) && response.statusCode >= HttpStatusCode.badRequest
131
- ? "error"
132
- : "info",
133
- source: LoggingProcessor.CLASS_NAME,
134
- ts: Date.now(),
135
- message: `<=== ${response.statusCode ?? ""} ${request.method} ${requestUrl} duration: ${elapsedMicroSeconds}µs`,
136
- data
137
- });
133
+ if (Is.number(response.statusCode) && response.statusCode >= HttpStatusCode.badRequest) {
134
+ await this._logging?.log({
135
+ level: "error",
136
+ source: LoggingProcessor.CLASS_NAME,
137
+ ts: Date.now(),
138
+ message: "responseMessage",
139
+ data: {
140
+ statusCode: response.statusCode,
141
+ method: request.method,
142
+ requestUrl: requestUrl ?? "",
143
+ elapsedMicroSeconds,
144
+ ...data
145
+ }
146
+ });
147
+ }
148
+ else {
149
+ await this._logging?.log({
150
+ level: "info",
151
+ source: LoggingProcessor.CLASS_NAME,
152
+ ts: Date.now(),
153
+ message: "responseMessage",
154
+ data: {
155
+ statusCode: response.statusCode,
156
+ method: request.method,
157
+ requestUrl: requestUrl ?? "",
158
+ elapsedMicroSeconds,
159
+ ...data
160
+ }
161
+ });
162
+ }
138
163
  }
139
164
  /**
140
165
  * Process the JSON.
@@ -1 +1 @@
1
- {"version":3,"file":"loggingProcessor.js","sourceRoot":"","sources":["../../../src/logging/loggingProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIBaseRoute,\n\tIBaseRouteProcessor,\n\tIHttpResponse,\n\tIHttpServerRequest\n} from \"@twin.org/api-models\";\nimport type { IContextIds } from \"@twin.org/context\";\nimport { Coerce, ComponentFactory, Is, ObjectHelper } from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HeaderTypes, HttpStatusCode, MimeTypes } from \"@twin.org/web\";\nimport type { ILoggingProcessorConstructorOptions } from \"../models/ILoggingProcessorConstructorOptions.js\";\n\n/**\n * Process the REST request and log its information.\n */\nexport class LoggingProcessor implements IBaseRouteProcessor {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<LoggingProcessor>();\n\n\t/**\n\t * The component for logging the information.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * Include the body objects when logging the information.\n\t * @internal\n\t */\n\tprivate readonly _includeBody: boolean;\n\n\t/**\n\t * Show the full base64 content for data, default to abbreviate.\n\t * @internal\n\t */\n\tprivate readonly _fullBase64: boolean;\n\n\t/**\n\t * List of property names to obfuscate, defaults to \"password\".\n\t * @internal\n\t */\n\tprivate readonly _obfuscateProperties: string[];\n\n\t/**\n\t * Create a new instance of LoggingProcessor.\n\t * @param options Options for the processor.\n\t */\n\tconstructor(options?: ILoggingProcessorConstructorOptions) {\n\t\tthis._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? \"logging\");\n\t\tthis._includeBody = options?.config?.includeBody ?? false;\n\t\tthis._fullBase64 = options?.config?.fullBase64 ?? false;\n\t\tthis._obfuscateProperties = options?.config?.obfuscateProperties ?? [\"password\"];\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn LoggingProcessor.CLASS_NAME;\n\t}\n\n\t/**\n\t * Pre process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t */\n\tpublic async pre(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tconst now = process.hrtime.bigint();\n\t\tprocessorState.requestStart = now;\n\n\t\tconst contentType = request.headers?.[HeaderTypes.ContentType];\n\t\tconst isJson = this.isMimeJson(contentType);\n\n\t\tlet requestUrl = \"\";\n\t\tif (Is.stringValue(request.url)) {\n\t\t\t// Socket paths do not have a prefix so just use the whole url.\n\t\t\tif (request.url.startsWith(\"http\")) {\n\t\t\t\trequestUrl = new URL(request.url).pathname;\n\t\t\t} else {\n\t\t\t\trequestUrl = request.url;\n\t\t\t}\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: LoggingProcessor.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: `===> ${request.method} ${requestUrl}`,\n\t\t\tdata:\n\t\t\t\tthis._includeBody && isJson\n\t\t\t\t\t? (this.processJson(\"body\", ObjectHelper.clone(request?.body)) as {\n\t\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t\t})\n\t\t\t\t\t: undefined\n\t\t});\n\t}\n\n\t/**\n\t * Post process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t */\n\tpublic async post(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tlet data: { [id: string]: unknown } | undefined;\n\t\tif (this._includeBody) {\n\t\t\tconst contentType = response.headers?.[HeaderTypes.ContentType];\n\t\t\tconst isJson = this.isMimeJson(contentType);\n\t\t\tconst contentLength = response.headers?.[HeaderTypes.ContentLength];\n\t\t\tif (isJson) {\n\t\t\t\tdata = {\n\t\t\t\t\tbody: this.processJson(\"body\", ObjectHelper.clone(response.body))\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tconst dataParts: { [id: string]: string } = {};\n\t\t\t\tif (Is.stringValue(contentType)) {\n\t\t\t\t\tdataParts[\"Content Type\"] = contentType;\n\t\t\t\t}\n\t\t\t\tif (Is.stringValue(contentLength)) {\n\t\t\t\t\tdataParts[\"Content Length\"] = contentLength;\n\t\t\t\t}\n\t\t\t\tif (Object.keys(dataParts).length > 0) {\n\t\t\t\t\tdata = {\n\t\t\t\t\t\theaders: dataParts\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst now = process.hrtime.bigint();\n\t\tconst start = Coerce.bigint(processorState.requestStart) ?? now;\n\t\tconst elapsed = now - start;\n\t\tconst elapsedMicroSeconds = Math.floor(Number(elapsed) / 1000);\n\n\t\tlet requestUrl = \"\";\n\t\tif (Is.stringValue(request.url)) {\n\t\t\t// Socket paths do not have a prefix so just use the whole url.\n\t\t\tif (request.url.startsWith(\"http\")) {\n\t\t\t\trequestUrl = new URL(request.url).pathname;\n\t\t\t} else {\n\t\t\t\trequestUrl = request.url;\n\t\t\t}\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel:\n\t\t\t\tIs.number(response.statusCode) && response.statusCode >= HttpStatusCode.badRequest\n\t\t\t\t\t? \"error\"\n\t\t\t\t\t: \"info\",\n\t\t\tsource: LoggingProcessor.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: `<=== ${response.statusCode ?? \"\"} ${request.method} ${requestUrl} duration: ${elapsedMicroSeconds}µs`,\n\t\t\tdata\n\t\t});\n\t}\n\n\t/**\n\t * Process the JSON.\n\t * @param propValue The property to process.\n\t * @returns The processed property.\n\t * @internal\n\t */\n\tprivate processJson(propName: string, propValue: unknown): unknown {\n\t\tif (Is.array(propValue)) {\n\t\t\tfor (let i = 0; i < propValue.length; i++) {\n\t\t\t\tpropValue[i] = this.processJson(`${i}`, propValue[i]);\n\t\t\t}\n\t\t} else if (Is.object(propValue)) {\n\t\t\tfor (const key of Object.keys(propValue)) {\n\t\t\t\tpropValue[key] = this.processJson(key, propValue[key]);\n\t\t\t}\n\t\t} else if (!this._fullBase64 && Is.stringBase64(propValue) && propValue.length > 256) {\n\t\t\tpropValue = \"<base64>\";\n\t\t} else if (\n\t\t\tIs.string(propValue) &&\n\t\t\tthis._obfuscateProperties.some(op => new RegExp(op).test(propName))\n\t\t) {\n\t\t\tpropValue = \"**************\";\n\t\t}\n\n\t\treturn propValue;\n\t}\n\n\t/**\n\t * Check if the content type is JSON.\n\t * @param contentType The content type to check.\n\t * @returns True if the content type is JSON, false otherwise.\n\t * @internal\n\t */\n\tprivate isMimeJson(contentType: string | string[] | undefined): boolean {\n\t\treturn Is.stringValue(contentType)\n\t\t\t? contentType.includes(MimeTypes.Json) || contentType.includes(MimeTypes.JsonLd)\n\t\t\t: false;\n\t}\n}\n"]}
1
+ {"version":3,"file":"loggingProcessor.js","sourceRoot":"","sources":["../../../src/logging/loggingProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIBaseRoute,\n\tIBaseRouteProcessor,\n\tIHttpResponse,\n\tIHttpServerRequest\n} from \"@twin.org/api-models\";\nimport type { IContextIds } from \"@twin.org/context\";\nimport { Coerce, ComponentFactory, Is, ObjectHelper } from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HeaderTypes, HttpStatusCode, MimeTypes } from \"@twin.org/web\";\nimport type { ILoggingProcessorConstructorOptions } from \"../models/ILoggingProcessorConstructorOptions.js\";\n\n/**\n * Process the REST request and log its information.\n */\nexport class LoggingProcessor implements IBaseRouteProcessor {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<LoggingProcessor>();\n\n\t/**\n\t * The component for logging the information.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * Include the body objects when logging the information.\n\t * @internal\n\t */\n\tprivate readonly _includeBody: boolean;\n\n\t/**\n\t * Show the full base64 content for data, default to abbreviate.\n\t * @internal\n\t */\n\tprivate readonly _fullBase64: boolean;\n\n\t/**\n\t * List of property names to obfuscate, defaults to \"password\".\n\t * @internal\n\t */\n\tprivate readonly _obfuscateProperties: string[];\n\n\t/**\n\t * Create a new instance of LoggingProcessor.\n\t * @param options Options for the processor.\n\t */\n\tconstructor(options?: ILoggingProcessorConstructorOptions) {\n\t\tthis._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? \"logging\");\n\t\tthis._includeBody = options?.config?.includeBody ?? false;\n\t\tthis._fullBase64 = options?.config?.fullBase64 ?? false;\n\t\tthis._obfuscateProperties = options?.config?.obfuscateProperties ?? [\"password\"];\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn LoggingProcessor.CLASS_NAME;\n\t}\n\n\t/**\n\t * Pre process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t */\n\tpublic async pre(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tconst now = process.hrtime.bigint();\n\t\tprocessorState.requestStart = now;\n\n\t\tconst contentType = request.headers?.[HeaderTypes.ContentType];\n\t\tconst isJson = this.isMimeJson(contentType);\n\n\t\tlet requestUrl = \"\";\n\t\tif (Is.stringValue(request.url)) {\n\t\t\t// Socket paths do not have a prefix so just use the whole url.\n\t\t\tif (request.url.startsWith(\"http\")) {\n\t\t\t\trequestUrl = new URL(request.url).pathname;\n\t\t\t} else {\n\t\t\t\trequestUrl = request.url;\n\t\t\t}\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: LoggingProcessor.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"requestMessage\",\n\t\t\tdata: {\n\t\t\t\tmethod: request.method,\n\t\t\t\trequestUrl,\n\t\t\t\tbody:\n\t\t\t\t\tthis._includeBody && isJson\n\t\t\t\t\t\t? (this.processJson(\"body\", ObjectHelper.clone(request?.body)) as {\n\t\t\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: undefined\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Post process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t */\n\tpublic async post(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tlet data: { [id: string]: unknown } | undefined;\n\t\tif (this._includeBody) {\n\t\t\tconst contentType = response.headers?.[HeaderTypes.ContentType];\n\t\t\tconst isJson = this.isMimeJson(contentType);\n\t\t\tconst contentLength = response.headers?.[HeaderTypes.ContentLength];\n\t\t\tif (isJson) {\n\t\t\t\tdata = {\n\t\t\t\t\tbody: this.processJson(\"body\", ObjectHelper.clone(response.body))\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tconst dataParts: { [id: string]: string } = {};\n\t\t\t\tif (Is.stringValue(contentType)) {\n\t\t\t\t\tdataParts[\"Content Type\"] = contentType;\n\t\t\t\t}\n\t\t\t\tif (Is.stringValue(contentLength)) {\n\t\t\t\t\tdataParts[\"Content Length\"] = contentLength;\n\t\t\t\t}\n\t\t\t\tif (Object.keys(dataParts).length > 0) {\n\t\t\t\t\tdata = {\n\t\t\t\t\t\theaders: dataParts\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst now = process.hrtime.bigint();\n\t\tconst start = Coerce.bigint(processorState.requestStart) ?? now;\n\t\tconst elapsed = now - start;\n\t\tconst elapsedMicroSeconds = Math.floor(Number(elapsed) / 1000);\n\n\t\tlet requestUrl = \"\";\n\t\tif (Is.stringValue(request.url)) {\n\t\t\t// Socket paths do not have a prefix so just use the whole url.\n\t\t\tif (request.url.startsWith(\"http\")) {\n\t\t\t\trequestUrl = new URL(request.url).pathname;\n\t\t\t} else {\n\t\t\t\trequestUrl = request.url;\n\t\t\t}\n\t\t}\n\n\t\tif (Is.number(response.statusCode) && response.statusCode >= HttpStatusCode.badRequest) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: LoggingProcessor.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"responseMessage\",\n\t\t\t\tdata: {\n\t\t\t\t\tstatusCode: response.statusCode,\n\t\t\t\t\tmethod: request.method,\n\t\t\t\t\trequestUrl: requestUrl ?? \"\",\n\t\t\t\t\telapsedMicroSeconds,\n\t\t\t\t\t...data\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: LoggingProcessor.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"responseMessage\",\n\t\t\t\tdata: {\n\t\t\t\t\tstatusCode: response.statusCode,\n\t\t\t\t\tmethod: request.method,\n\t\t\t\t\trequestUrl: requestUrl ?? \"\",\n\t\t\t\t\telapsedMicroSeconds,\n\t\t\t\t\t...data\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Process the JSON.\n\t * @param propValue The property to process.\n\t * @returns The processed property.\n\t * @internal\n\t */\n\tprivate processJson(propName: string, propValue: unknown): unknown {\n\t\tif (Is.array(propValue)) {\n\t\t\tfor (let i = 0; i < propValue.length; i++) {\n\t\t\t\tpropValue[i] = this.processJson(`${i}`, propValue[i]);\n\t\t\t}\n\t\t} else if (Is.object(propValue)) {\n\t\t\tfor (const key of Object.keys(propValue)) {\n\t\t\t\tpropValue[key] = this.processJson(key, propValue[key]);\n\t\t\t}\n\t\t} else if (!this._fullBase64 && Is.stringBase64(propValue) && propValue.length > 256) {\n\t\t\tpropValue = \"<base64>\";\n\t\t} else if (\n\t\t\tIs.string(propValue) &&\n\t\t\tthis._obfuscateProperties.some(op => new RegExp(op).test(propName))\n\t\t) {\n\t\t\tpropValue = \"**************\";\n\t\t}\n\n\t\treturn propValue;\n\t}\n\n\t/**\n\t * Check if the content type is JSON.\n\t * @param contentType The content type to check.\n\t * @returns True if the content type is JSON, false otherwise.\n\t * @internal\n\t */\n\tprivate isMimeJson(contentType: string | string[] | undefined): boolean {\n\t\treturn Is.stringValue(contentType)\n\t\t\t? contentType.includes(MimeTypes.Json) || contentType.includes(MimeTypes.JsonLd)\n\t\t\t: false;\n\t}\n}\n"]}
package/docs/changelog.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @twin.org/api-processors - Changelog
2
2
 
3
+ ## [0.0.3-next.4](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.3...api-processors-v0.0.3-next.4) (2025-11-14)
4
+
5
+
6
+ ### Features
7
+
8
+ * add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
9
+ * add json-ld mime type processor and auth admin component ([8861791](https://github.com/twinfoundation/api/commit/88617916e23bfbca023dbae1976fe421983a02ff))
10
+ * add logging component type to request contexts ([210de1b](https://github.com/twinfoundation/api/commit/210de1b9e1c91079b59a2b90ddd57569668d647d))
11
+ * add root, favicon routes ([71da1c3](https://github.com/twinfoundation/api/commit/71da1c3a93c349588aff7084d1d8d6a29a277da8))
12
+ * add socket id, connect and disconnect ([20b0d0e](https://github.com/twinfoundation/api/commit/20b0d0ec279cab46141fee09de2c4a7087cdce16))
13
+ * add validate-locales ([cdba610](https://github.com/twinfoundation/api/commit/cdba610a0acb5022d2e3ce729732e6646a297e5e))
14
+ * eslint migration to flat config ([0dd5820](https://github.com/twinfoundation/api/commit/0dd5820e3af97350fd08b8d226f4a6c1a9246805))
15
+ * logging naming consistency ([a4a6ef2](https://github.com/twinfoundation/api/commit/a4a6ef2de5049045589eb78b177ff62e744bde9d))
16
+ * remove unused namespace ([08478f2](https://github.com/twinfoundation/api/commit/08478f27efda9beb0271fdb22f6972e918361965))
17
+ * update dependencies ([1171dc4](https://github.com/twinfoundation/api/commit/1171dc416a9481737f6a640e3cf30145768f37e9))
18
+ * update framework core ([d8eebf2](https://github.com/twinfoundation/api/commit/d8eebf267fa2a0abaa84e58590496e9d20490cfa))
19
+ * update IComponent signatures ([915ce37](https://github.com/twinfoundation/api/commit/915ce37712326ab4aa6869c350eabaa4622e8430))
20
+ * use shared store mechanism ([#19](https://github.com/twinfoundation/api/issues/19)) ([32116df](https://github.com/twinfoundation/api/commit/32116df3b4380a30137f5056f242a5c99afa2df9))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * locales ([1b84d8e](https://github.com/twinfoundation/api/commit/1b84d8eb4dbe2302897e184e6389892b7ba12608))
26
+
27
+
28
+ ### Dependencies
29
+
30
+ * The following workspace dependencies were updated
31
+ * dependencies
32
+ * @twin.org/api-models bumped from 0.0.3-next.3 to 0.0.3-next.4
33
+
34
+ ## [0.0.3-next.3](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.2...api-processors-v0.0.3-next.3) (2025-11-14)
35
+
36
+
37
+ ### Miscellaneous Chores
38
+
39
+ * **api-processors:** Synchronize repo versions
40
+
41
+
42
+ ### Dependencies
43
+
44
+ * The following workspace dependencies were updated
45
+ * dependencies
46
+ * @twin.org/api-models bumped from 0.0.3-next.2 to 0.0.3-next.3
47
+
3
48
  ## [0.0.3-next.2](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.1...api-processors-v0.0.3-next.2) (2025-11-12)
4
49
 
5
50
 
package/locales/en.json CHANGED
@@ -8,6 +8,15 @@
8
8
  },
9
9
  "jsonLdMimeTypeProcessor": {
10
10
  "invalidJsonLd": "The JSON-LD content is invalid or missing '@context'."
11
+ },
12
+ "loggingProcessor": {
13
+ "responseMessage": "<=== {statusCode} {method} {requestUrl} duration: {elapsedMicroSeconds}µs"
14
+ }
15
+ },
16
+ "info": {
17
+ "loggingProcessor": {
18
+ "requestMessage": "===> {method} {requestUrl}",
19
+ "responseMessage": "<=== {statusCode} {method} {requestUrl} duration: {elapsedMicroSeconds}µs"
11
20
  }
12
21
  }
13
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/api-processors",
3
- "version": "0.0.3-next.2",
3
+ "version": "0.0.3-next.4",
4
4
  "description": "Route processors for use with API servers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/api-models": "0.0.3-next.2",
17
+ "@twin.org/api-models": "0.0.3-next.4",
18
18
  "@twin.org/context": "next",
19
19
  "@twin.org/core": "next",
20
20
  "@twin.org/logging-models": "next",