@twin.org/api-processors 0.0.3-next.1 → 0.0.3-next.10

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))\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,166 @@
1
1
  # @twin.org/api-processors - Changelog
2
2
 
3
+ ## [0.0.3-next.10](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.9...api-processors-v0.0.3-next.10) (2026-01-05)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **api-processors:** Synchronize repo versions
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/api-models bumped from 0.0.3-next.9 to 0.0.3-next.10
16
+
17
+ ## [0.0.3-next.9](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.8...api-processors-v0.0.3-next.9) (2026-01-05)
18
+
19
+
20
+ ### Features
21
+
22
+ * add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
23
+ * add json-ld mime type processor and auth admin component ([8861791](https://github.com/twinfoundation/api/commit/88617916e23bfbca023dbae1976fe421983a02ff))
24
+ * add logging component type to request contexts ([210de1b](https://github.com/twinfoundation/api/commit/210de1b9e1c91079b59a2b90ddd57569668d647d))
25
+ * add root, favicon routes ([71da1c3](https://github.com/twinfoundation/api/commit/71da1c3a93c349588aff7084d1d8d6a29a277da8))
26
+ * add socket id, connect and disconnect ([20b0d0e](https://github.com/twinfoundation/api/commit/20b0d0ec279cab46141fee09de2c4a7087cdce16))
27
+ * add validate-locales ([cdba610](https://github.com/twinfoundation/api/commit/cdba610a0acb5022d2e3ce729732e6646a297e5e))
28
+ * eslint migration to flat config ([0dd5820](https://github.com/twinfoundation/api/commit/0dd5820e3af97350fd08b8d226f4a6c1a9246805))
29
+ * logging naming consistency ([a4a6ef2](https://github.com/twinfoundation/api/commit/a4a6ef2de5049045589eb78b177ff62e744bde9d))
30
+ * remove unused namespace ([08478f2](https://github.com/twinfoundation/api/commit/08478f27efda9beb0271fdb22f6972e918361965))
31
+ * update dependencies ([1171dc4](https://github.com/twinfoundation/api/commit/1171dc416a9481737f6a640e3cf30145768f37e9))
32
+ * update framework core ([d8eebf2](https://github.com/twinfoundation/api/commit/d8eebf267fa2a0abaa84e58590496e9d20490cfa))
33
+ * update IComponent signatures ([915ce37](https://github.com/twinfoundation/api/commit/915ce37712326ab4aa6869c350eabaa4622e8430))
34
+ * use shared store mechanism ([#19](https://github.com/twinfoundation/api/issues/19)) ([32116df](https://github.com/twinfoundation/api/commit/32116df3b4380a30137f5056f242a5c99afa2df9))
35
+
36
+
37
+ ### Bug Fixes
38
+
39
+ * error handling make sure primary error takes precedence ([84b61f2](https://github.com/twinfoundation/api/commit/84b61f27fe5e4919c0c9f9a1edc8ff46dc45c1f7))
40
+ * locales ([1b84d8e](https://github.com/twinfoundation/api/commit/1b84d8eb4dbe2302897e184e6389892b7ba12608))
41
+
42
+
43
+ ### Dependencies
44
+
45
+ * The following workspace dependencies were updated
46
+ * dependencies
47
+ * @twin.org/api-models bumped from 0.0.3-next.8 to 0.0.3-next.9
48
+
49
+ ## [0.0.3-next.8](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.7...api-processors-v0.0.3-next.8) (2025-12-17)
50
+
51
+
52
+ ### Miscellaneous Chores
53
+
54
+ * **api-processors:** Synchronize repo versions
55
+
56
+
57
+ ### Dependencies
58
+
59
+ * The following workspace dependencies were updated
60
+ * dependencies
61
+ * @twin.org/api-models bumped from 0.0.3-next.7 to 0.0.3-next.8
62
+
63
+ ## [0.0.3-next.7](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.6...api-processors-v0.0.3-next.7) (2025-11-26)
64
+
65
+
66
+ ### Bug Fixes
67
+
68
+ * error handling make sure primary error takes precedence ([84b61f2](https://github.com/twinfoundation/api/commit/84b61f27fe5e4919c0c9f9a1edc8ff46dc45c1f7))
69
+
70
+
71
+ ### Dependencies
72
+
73
+ * The following workspace dependencies were updated
74
+ * dependencies
75
+ * @twin.org/api-models bumped from 0.0.3-next.6 to 0.0.3-next.7
76
+
77
+ ## [0.0.3-next.6](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.5...api-processors-v0.0.3-next.6) (2025-11-20)
78
+
79
+
80
+ ### Miscellaneous Chores
81
+
82
+ * **api-processors:** Synchronize repo versions
83
+
84
+
85
+ ### Dependencies
86
+
87
+ * The following workspace dependencies were updated
88
+ * dependencies
89
+ * @twin.org/api-models bumped from 0.0.3-next.5 to 0.0.3-next.6
90
+
91
+ ## [0.0.3-next.5](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.4...api-processors-v0.0.3-next.5) (2025-11-14)
92
+
93
+
94
+ ### Miscellaneous Chores
95
+
96
+ * **api-processors:** Synchronize repo versions
97
+
98
+
99
+ ### Dependencies
100
+
101
+ * The following workspace dependencies were updated
102
+ * dependencies
103
+ * @twin.org/api-models bumped from 0.0.3-next.4 to 0.0.3-next.5
104
+
105
+ ## [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)
106
+
107
+
108
+ ### Features
109
+
110
+ * add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
111
+ * add json-ld mime type processor and auth admin component ([8861791](https://github.com/twinfoundation/api/commit/88617916e23bfbca023dbae1976fe421983a02ff))
112
+ * add logging component type to request contexts ([210de1b](https://github.com/twinfoundation/api/commit/210de1b9e1c91079b59a2b90ddd57569668d647d))
113
+ * add root, favicon routes ([71da1c3](https://github.com/twinfoundation/api/commit/71da1c3a93c349588aff7084d1d8d6a29a277da8))
114
+ * add socket id, connect and disconnect ([20b0d0e](https://github.com/twinfoundation/api/commit/20b0d0ec279cab46141fee09de2c4a7087cdce16))
115
+ * add validate-locales ([cdba610](https://github.com/twinfoundation/api/commit/cdba610a0acb5022d2e3ce729732e6646a297e5e))
116
+ * eslint migration to flat config ([0dd5820](https://github.com/twinfoundation/api/commit/0dd5820e3af97350fd08b8d226f4a6c1a9246805))
117
+ * logging naming consistency ([a4a6ef2](https://github.com/twinfoundation/api/commit/a4a6ef2de5049045589eb78b177ff62e744bde9d))
118
+ * remove unused namespace ([08478f2](https://github.com/twinfoundation/api/commit/08478f27efda9beb0271fdb22f6972e918361965))
119
+ * update dependencies ([1171dc4](https://github.com/twinfoundation/api/commit/1171dc416a9481737f6a640e3cf30145768f37e9))
120
+ * update framework core ([d8eebf2](https://github.com/twinfoundation/api/commit/d8eebf267fa2a0abaa84e58590496e9d20490cfa))
121
+ * update IComponent signatures ([915ce37](https://github.com/twinfoundation/api/commit/915ce37712326ab4aa6869c350eabaa4622e8430))
122
+ * use shared store mechanism ([#19](https://github.com/twinfoundation/api/issues/19)) ([32116df](https://github.com/twinfoundation/api/commit/32116df3b4380a30137f5056f242a5c99afa2df9))
123
+
124
+
125
+ ### Bug Fixes
126
+
127
+ * locales ([1b84d8e](https://github.com/twinfoundation/api/commit/1b84d8eb4dbe2302897e184e6389892b7ba12608))
128
+
129
+
130
+ ### Dependencies
131
+
132
+ * The following workspace dependencies were updated
133
+ * dependencies
134
+ * @twin.org/api-models bumped from 0.0.3-next.3 to 0.0.3-next.4
135
+
136
+ ## [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)
137
+
138
+
139
+ ### Miscellaneous Chores
140
+
141
+ * **api-processors:** Synchronize repo versions
142
+
143
+
144
+ ### Dependencies
145
+
146
+ * The following workspace dependencies were updated
147
+ * dependencies
148
+ * @twin.org/api-models bumped from 0.0.3-next.2 to 0.0.3-next.3
149
+
150
+ ## [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)
151
+
152
+
153
+ ### Miscellaneous Chores
154
+
155
+ * **api-processors:** Synchronize repo versions
156
+
157
+
158
+ ### Dependencies
159
+
160
+ * The following workspace dependencies were updated
161
+ * dependencies
162
+ * @twin.org/api-models bumped from 0.0.3-next.1 to 0.0.3-next.2
163
+
3
164
  ## [0.0.3-next.1](https://github.com/twinfoundation/api/compare/api-processors-v0.0.3-next.0...api-processors-v0.0.3-next.1) (2025-11-10)
4
165
 
5
166
 
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.1",
3
+ "version": "0.0.3-next.10",
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.1",
17
+ "@twin.org/api-models": "0.0.3-next.10",
18
18
  "@twin.org/context": "next",
19
19
  "@twin.org/core": "next",
20
20
  "@twin.org/logging-models": "next",