@webpieces/core-util 0.3.285 → 0.3.287
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 +1 -1
- package/src/ContextKey.d.ts +33 -15
- package/src/ContextKey.js +37 -15
- package/src/ContextKey.js.map +1 -1
- package/src/http/ContextMgr.d.ts +17 -34
- package/src/http/ContextMgr.js +21 -33
- package/src/http/ContextMgr.js.map +1 -1
- package/src/http/ContextReader.d.ts +14 -23
- package/src/http/ContextReader.js.map +1 -1
- package/src/http/HeaderMethods.d.ts +16 -60
- package/src/http/HeaderMethods.js +25 -92
- package/src/http/HeaderMethods.js.map +1 -1
- package/src/http/HeaderRegistry.d.ts +44 -37
- package/src/http/HeaderRegistry.js +88 -70
- package/src/http/HeaderRegistry.js.map +1 -1
- package/src/http/RequestIdChainProcessor.js +3 -2
- package/src/http/RequestIdChainProcessor.js.map +1 -1
- package/src/http/WebpiecesCoreHeaders.d.ts +29 -38
- package/src/http/WebpiecesCoreHeaders.js +28 -48
- package/src/http/WebpiecesCoreHeaders.js.map +1 -1
- package/src/http/recorder/TestCaseRecorder.js +1 -1
- package/src/http/recorder/TestCaseRecorder.js.map +1 -1
- package/src/index.d.ts +0 -4
- package/src/index.js +2 -8
- package/src/index.js.map +1 -1
- package/src/logging/LogManager.d.ts +5 -0
- package/src/logging/LogManager.js +13 -0
- package/src/logging/LogManager.js.map +1 -1
- package/src/Header.d.ts +0 -22
- package/src/Header.js +0 -3
- package/src/Header.js.map +0 -1
- package/src/http/HeaderTypes.d.ts +0 -29
- package/src/http/HeaderTypes.js +0 -33
- package/src/http/HeaderTypes.js.map +0 -1
- package/src/http/PlatformHeader.d.ts +0 -51
- package/src/http/PlatformHeader.js +0 -63
- package/src/http/PlatformHeader.js.map +0 -1
- package/src/http/PlatformHeadersExtension.d.ts +0 -51
- package/src/http/PlatformHeadersExtension.js +0 -59
- package/src/http/PlatformHeadersExtension.js.map +0 -1
package/package.json
CHANGED
package/src/ContextKey.d.ts
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
|
-
import { Header } from './Header';
|
|
2
1
|
/**
|
|
3
|
-
* ContextKey -
|
|
2
|
+
* ContextKey - a single key that travels in the request's "magic context"
|
|
3
|
+
* (RequestContext on the server, MutableContextStore in the browser).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* This ONE class replaces the old split of `Header` (interface) + `PlatformHeader`
|
|
6
|
+
* (class) + `ContextKey` (class). Every context value — whether it rides over HTTP
|
|
7
|
+
* (request-id, tenant, authorization) or stays in-process (method-meta, the
|
|
8
|
+
* TestCaseRecorder) — is a `ContextKey`.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
10
|
+
* The fields are named for what they DO (flipped from the old model):
|
|
11
|
+
* - `name` ALWAYS set. The context storage key, the log/MDC key, and the
|
|
12
|
+
* recorder name. e.g. 'requestId', 'tenantId', 'authorization'.
|
|
13
|
+
* - `httpHeader` OPTIONAL. When set, this key is transferred over the wire under
|
|
14
|
+
* this HTTP header name (inbound request -> context, and context ->
|
|
15
|
+
* outbound request). e.g. 'x-request-id'. When UNSET, the key is
|
|
16
|
+
* context-only and never leaves the process (method-meta, recorder).
|
|
17
|
+
* - `isSecured` When true, the value is masked (partially) in logs.
|
|
18
|
+
* - `isLogged` Defaults to true. When false, the value is NEVER logged (used for
|
|
19
|
+
* object-valued/internal keys like the recorder or method-meta that
|
|
20
|
+
* must not be serialized into log lines).
|
|
9
21
|
*
|
|
10
|
-
*
|
|
11
|
-
* ```typescript
|
|
12
|
-
* const MY_KEY = new ContextKey('my-app-key');
|
|
13
|
-
* RequestContext.putHeader(MY_KEY, someValue);
|
|
14
|
-
* const value = RequestContext.getHeader(MY_KEY);
|
|
15
|
-
* ```
|
|
22
|
+
* Per CLAUDE.md: data-only structures are classes, not interfaces.
|
|
16
23
|
*/
|
|
17
|
-
export declare class ContextKey
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
export declare class ContextKey {
|
|
25
|
+
/** Context storage key + log/MDC key + recorder name. Always set. */
|
|
26
|
+
readonly name: string;
|
|
27
|
+
/**
|
|
28
|
+
* HTTP header name when this key is transferred over the wire (e.g.
|
|
29
|
+
* 'x-request-id'). Undefined = context-only, never transferred.
|
|
30
|
+
*/
|
|
31
|
+
readonly httpHeader?: string;
|
|
32
|
+
/** Mask this value (partially) in logs. */
|
|
33
|
+
readonly isSecured: boolean;
|
|
34
|
+
/** Whether this key is logged at all. Default true; false = never logged. */
|
|
35
|
+
readonly isLogged: boolean;
|
|
36
|
+
constructor(name: string, httpHeader?: string, isSecured?: boolean, isLogged?: boolean);
|
|
37
|
+
/** True when this key is transferred over HTTP (has an httpHeader). */
|
|
38
|
+
isTransferred(): boolean;
|
|
21
39
|
}
|
package/src/ContextKey.js
CHANGED
|
@@ -2,27 +2,49 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ContextKey = void 0;
|
|
4
4
|
/**
|
|
5
|
-
* ContextKey -
|
|
5
|
+
* ContextKey - a single key that travels in the request's "magic context"
|
|
6
|
+
* (RequestContext on the server, MutableContextStore in the browser).
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
8
|
+
* This ONE class replaces the old split of `Header` (interface) + `PlatformHeader`
|
|
9
|
+
* (class) + `ContextKey` (class). Every context value — whether it rides over HTTP
|
|
10
|
+
* (request-id, tenant, authorization) or stays in-process (method-meta, the
|
|
11
|
+
* TestCaseRecorder) — is a `ContextKey`.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
13
|
+
* The fields are named for what they DO (flipped from the old model):
|
|
14
|
+
* - `name` ALWAYS set. The context storage key, the log/MDC key, and the
|
|
15
|
+
* recorder name. e.g. 'requestId', 'tenantId', 'authorization'.
|
|
16
|
+
* - `httpHeader` OPTIONAL. When set, this key is transferred over the wire under
|
|
17
|
+
* this HTTP header name (inbound request -> context, and context ->
|
|
18
|
+
* outbound request). e.g. 'x-request-id'. When UNSET, the key is
|
|
19
|
+
* context-only and never leaves the process (method-meta, recorder).
|
|
20
|
+
* - `isSecured` When true, the value is masked (partially) in logs.
|
|
21
|
+
* - `isLogged` Defaults to true. When false, the value is NEVER logged (used for
|
|
22
|
+
* object-valued/internal keys like the recorder or method-meta that
|
|
23
|
+
* must not be serialized into log lines).
|
|
11
24
|
*
|
|
12
|
-
*
|
|
13
|
-
* ```typescript
|
|
14
|
-
* const MY_KEY = new ContextKey('my-app-key');
|
|
15
|
-
* RequestContext.putHeader(MY_KEY, someValue);
|
|
16
|
-
* const value = RequestContext.getHeader(MY_KEY);
|
|
17
|
-
* ```
|
|
25
|
+
* Per CLAUDE.md: data-only structures are classes, not interfaces.
|
|
18
26
|
*/
|
|
19
27
|
class ContextKey {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
/** Context storage key + log/MDC key + recorder name. Always set. */
|
|
29
|
+
name;
|
|
30
|
+
/**
|
|
31
|
+
* HTTP header name when this key is transferred over the wire (e.g.
|
|
32
|
+
* 'x-request-id'). Undefined = context-only, never transferred.
|
|
33
|
+
*/
|
|
34
|
+
httpHeader;
|
|
35
|
+
/** Mask this value (partially) in logs. */
|
|
36
|
+
isSecured;
|
|
37
|
+
/** Whether this key is logged at all. Default true; false = never logged. */
|
|
38
|
+
isLogged;
|
|
39
|
+
constructor(name, httpHeader, isSecured = false, isLogged = true) {
|
|
40
|
+
this.name = name;
|
|
41
|
+
this.httpHeader = httpHeader;
|
|
42
|
+
this.isSecured = isSecured;
|
|
43
|
+
this.isLogged = isLogged;
|
|
23
44
|
}
|
|
24
|
-
|
|
25
|
-
|
|
45
|
+
/** True when this key is transferred over HTTP (has an httpHeader). */
|
|
46
|
+
isTransferred() {
|
|
47
|
+
return this.httpHeader !== undefined;
|
|
26
48
|
}
|
|
27
49
|
}
|
|
28
50
|
exports.ContextKey = ContextKey;
|
package/src/ContextKey.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextKey.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/ContextKey.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ContextKey.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/ContextKey.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAa,UAAU;IACnB,qEAAqE;IAC5D,IAAI,CAAS;IAEtB;;;OAGG;IACM,UAAU,CAAU;IAE7B,2CAA2C;IAClC,SAAS,CAAU;IAE5B,6EAA6E;IACpE,QAAQ,CAAU;IAE3B,YACI,IAAY,EACZ,UAAmB,EACnB,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,IAAI;QAEf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED,uEAAuE;IACvE,aAAa;QACT,OAAO,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC;IACzC,CAAC;CACJ;AAhCD,gCAgCC","sourcesContent":["/**\n * ContextKey - a single key that travels in the request's \"magic context\"\n * (RequestContext on the server, MutableContextStore in the browser).\n *\n * This ONE class replaces the old split of `Header` (interface) + `PlatformHeader`\n * (class) + `ContextKey` (class). Every context value — whether it rides over HTTP\n * (request-id, tenant, authorization) or stays in-process (method-meta, the\n * TestCaseRecorder) — is a `ContextKey`.\n *\n * The fields are named for what they DO (flipped from the old model):\n * - `name` ALWAYS set. The context storage key, the log/MDC key, and the\n * recorder name. e.g. 'requestId', 'tenantId', 'authorization'.\n * - `httpHeader` OPTIONAL. When set, this key is transferred over the wire under\n * this HTTP header name (inbound request -> context, and context ->\n * outbound request). e.g. 'x-request-id'. When UNSET, the key is\n * context-only and never leaves the process (method-meta, recorder).\n * - `isSecured` When true, the value is masked (partially) in logs.\n * - `isLogged` Defaults to true. When false, the value is NEVER logged (used for\n * object-valued/internal keys like the recorder or method-meta that\n * must not be serialized into log lines).\n *\n * Per CLAUDE.md: data-only structures are classes, not interfaces.\n */\nexport class ContextKey {\n /** Context storage key + log/MDC key + recorder name. Always set. */\n readonly name: string;\n\n /**\n * HTTP header name when this key is transferred over the wire (e.g.\n * 'x-request-id'). Undefined = context-only, never transferred.\n */\n readonly httpHeader?: string;\n\n /** Mask this value (partially) in logs. */\n readonly isSecured: boolean;\n\n /** Whether this key is logged at all. Default true; false = never logged. */\n readonly isLogged: boolean;\n\n constructor(\n name: string,\n httpHeader?: string,\n isSecured = false,\n isLogged = true,\n ) {\n this.name = name;\n this.httpHeader = httpHeader;\n this.isSecured = isSecured;\n this.isLogged = isLogged;\n }\n\n /** True when this key is transferred over HTTP (has an httpHeader). */\n isTransferred(): boolean {\n return this.httpHeader !== undefined;\n }\n}\n"]}
|
package/src/http/ContextMgr.d.ts
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
import { ContextReader } from './ContextReader';
|
|
2
2
|
import { HeaderMethods } from './HeaderMethods';
|
|
3
|
-
import { HeaderRegistry } from './HeaderRegistry';
|
|
4
3
|
/**
|
|
5
|
-
* ContextMgr -
|
|
4
|
+
* ContextMgr - propagates the magic context onto outbound HTTP requests.
|
|
6
5
|
*
|
|
7
|
-
* Passed to createApiClient() via ClientConfig.contextMgr
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Passed to createApiClient() via ClientConfig.contextMgr: every transferred key
|
|
7
|
+
* (httpHeader set) in the GLOBAL {@link HeaderRegistry} is read from the ContextReader
|
|
8
|
+
* and added to outbound requests. The registry is a process global (configured once at
|
|
9
|
+
* startup, like LogManager), so ContextMgr no longer takes a registry argument.
|
|
10
10
|
*
|
|
11
|
-
* Browser-safe (no AsyncLocalStorage): the server-side reader
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* so ContextMgr itself lives here in browser+node core-util.
|
|
15
|
-
*
|
|
16
|
-
* BREAKING (migration from the PlatformHeader[] constructor):
|
|
17
|
-
* new ContextMgr(reader, headerArray)
|
|
18
|
-
* becomes
|
|
19
|
-
* new ContextMgr(reader, new HeaderRegistry([new PlatformHeadersExtension(headerArray)]))
|
|
11
|
+
* Browser-safe (no AsyncLocalStorage): the server-side reader (RequestContextReader,
|
|
12
|
+
* in @webpieces/core-context) and the browser store (MutableContextStore, in
|
|
13
|
+
* @webpieces/http-client) both implement ContextReader.
|
|
20
14
|
*
|
|
21
15
|
* Example usage:
|
|
22
16
|
* ```typescript
|
|
23
17
|
* // Node.js server-side (reads the magic context from RequestContext):
|
|
24
|
-
* const contextMgr = new ContextMgr(new RequestContextReader()
|
|
18
|
+
* const contextMgr = new ContextMgr(new RequestContextReader());
|
|
25
19
|
*
|
|
26
20
|
* // Browser client-side (app-managed store, no AsyncLocalStorage):
|
|
27
|
-
* const
|
|
28
|
-
* const contextMgr = new ContextMgr(store, registry);
|
|
21
|
+
* const contextMgr = new ContextMgr(new MutableContextStore());
|
|
29
22
|
*
|
|
30
23
|
* // Both cases:
|
|
31
24
|
* const config = new ClientConfig('http://api.example.com', contextMgr);
|
|
@@ -34,15 +27,10 @@ import { HeaderRegistry } from './HeaderRegistry';
|
|
|
34
27
|
*/
|
|
35
28
|
export declare class ContextMgr {
|
|
36
29
|
/**
|
|
37
|
-
* The context reader that provides
|
|
30
|
+
* The context reader that provides context-key values.
|
|
38
31
|
* Different implementations for Node.js vs browser.
|
|
39
32
|
*/
|
|
40
33
|
readonly contextReader: ContextReader;
|
|
41
|
-
/**
|
|
42
|
-
* The single source of truth for which headers exist and how they behave
|
|
43
|
-
* (transferred/secured/MDC). Shared with the server-side filters.
|
|
44
|
-
*/
|
|
45
|
-
readonly registry: HeaderRegistry;
|
|
46
34
|
/**
|
|
47
35
|
* When true (default), outbound calls send the current x-request-id as
|
|
48
36
|
* x-previous-request-id (and drop x-request-id) so each hop in a
|
|
@@ -52,15 +40,10 @@ export declare class ContextMgr {
|
|
|
52
40
|
private chainProcessor;
|
|
53
41
|
constructor(
|
|
54
42
|
/**
|
|
55
|
-
* The context reader that provides
|
|
43
|
+
* The context reader that provides context-key values.
|
|
56
44
|
* Different implementations for Node.js vs browser.
|
|
57
45
|
*/
|
|
58
46
|
contextReader: ContextReader,
|
|
59
|
-
/**
|
|
60
|
-
* The single source of truth for which headers exist and how they behave
|
|
61
|
-
* (transferred/secured/MDC). Shared with the server-side filters.
|
|
62
|
-
*/
|
|
63
|
-
registry: HeaderRegistry,
|
|
64
47
|
/**
|
|
65
48
|
* When true (default), outbound calls send the current x-request-id as
|
|
66
49
|
* x-previous-request-id (and drop x-request-id) so each hop in a
|
|
@@ -68,16 +51,16 @@ export declare class ContextMgr {
|
|
|
68
51
|
*/
|
|
69
52
|
chainRequestIds?: boolean);
|
|
70
53
|
/**
|
|
71
|
-
* Build the headers to send on an outbound request: every transferred
|
|
72
|
-
*
|
|
73
|
-
* then request-id chaining applied (unless opted out).
|
|
54
|
+
* Build the headers to send on an outbound request: every transferred key
|
|
55
|
+
* (httpHeader set) with a non-empty value in the context, emitted under its
|
|
56
|
+
* `httpHeader` wire name, then request-id chaining applied (unless opted out).
|
|
74
57
|
*
|
|
75
58
|
* Values are RAW (unmasked) - this map goes on the wire, not in logs.
|
|
76
59
|
*/
|
|
77
60
|
buildOutboundHeaders(): Map<string, string>;
|
|
78
61
|
/**
|
|
79
|
-
* Build the header map for LOGGING: secured
|
|
80
|
-
*
|
|
62
|
+
* Build the header map for LOGGING: secured values masked, keyed by each key's
|
|
63
|
+
* `name`, only for keys with isLogged=true.
|
|
81
64
|
*/
|
|
82
65
|
buildHeadersForLogging(headerMethods: HeaderMethods): Map<string, string>;
|
|
83
66
|
}
|
package/src/http/ContextMgr.js
CHANGED
|
@@ -1,32 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ContextMgr = void 0;
|
|
4
|
+
const HeaderRegistry_1 = require("./HeaderRegistry");
|
|
4
5
|
const RequestIdChainProcessor_1 = require("./RequestIdChainProcessor");
|
|
5
6
|
/**
|
|
6
|
-
* ContextMgr -
|
|
7
|
+
* ContextMgr - propagates the magic context onto outbound HTTP requests.
|
|
7
8
|
*
|
|
8
|
-
* Passed to createApiClient() via ClientConfig.contextMgr
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Passed to createApiClient() via ClientConfig.contextMgr: every transferred key
|
|
10
|
+
* (httpHeader set) in the GLOBAL {@link HeaderRegistry} is read from the ContextReader
|
|
11
|
+
* and added to outbound requests. The registry is a process global (configured once at
|
|
12
|
+
* startup, like LogManager), so ContextMgr no longer takes a registry argument.
|
|
11
13
|
*
|
|
12
|
-
* Browser-safe (no AsyncLocalStorage): the server-side reader
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* so ContextMgr itself lives here in browser+node core-util.
|
|
16
|
-
*
|
|
17
|
-
* BREAKING (migration from the PlatformHeader[] constructor):
|
|
18
|
-
* new ContextMgr(reader, headerArray)
|
|
19
|
-
* becomes
|
|
20
|
-
* new ContextMgr(reader, new HeaderRegistry([new PlatformHeadersExtension(headerArray)]))
|
|
14
|
+
* Browser-safe (no AsyncLocalStorage): the server-side reader (RequestContextReader,
|
|
15
|
+
* in @webpieces/core-context) and the browser store (MutableContextStore, in
|
|
16
|
+
* @webpieces/http-client) both implement ContextReader.
|
|
21
17
|
*
|
|
22
18
|
* Example usage:
|
|
23
19
|
* ```typescript
|
|
24
20
|
* // Node.js server-side (reads the magic context from RequestContext):
|
|
25
|
-
* const contextMgr = new ContextMgr(new RequestContextReader()
|
|
21
|
+
* const contextMgr = new ContextMgr(new RequestContextReader());
|
|
26
22
|
*
|
|
27
23
|
* // Browser client-side (app-managed store, no AsyncLocalStorage):
|
|
28
|
-
* const
|
|
29
|
-
* const contextMgr = new ContextMgr(store, registry);
|
|
24
|
+
* const contextMgr = new ContextMgr(new MutableContextStore());
|
|
30
25
|
*
|
|
31
26
|
* // Both cases:
|
|
32
27
|
* const config = new ClientConfig('http://api.example.com', contextMgr);
|
|
@@ -35,20 +30,14 @@ const RequestIdChainProcessor_1 = require("./RequestIdChainProcessor");
|
|
|
35
30
|
*/
|
|
36
31
|
class ContextMgr {
|
|
37
32
|
contextReader;
|
|
38
|
-
registry;
|
|
39
33
|
chainRequestIds;
|
|
40
34
|
chainProcessor;
|
|
41
35
|
constructor(
|
|
42
36
|
/**
|
|
43
|
-
* The context reader that provides
|
|
37
|
+
* The context reader that provides context-key values.
|
|
44
38
|
* Different implementations for Node.js vs browser.
|
|
45
39
|
*/
|
|
46
40
|
contextReader,
|
|
47
|
-
/**
|
|
48
|
-
* The single source of truth for which headers exist and how they behave
|
|
49
|
-
* (transferred/secured/MDC). Shared with the server-side filters.
|
|
50
|
-
*/
|
|
51
|
-
registry,
|
|
52
41
|
/**
|
|
53
42
|
* When true (default), outbound calls send the current x-request-id as
|
|
54
43
|
* x-previous-request-id (and drop x-request-id) so each hop in a
|
|
@@ -56,23 +45,22 @@ class ContextMgr {
|
|
|
56
45
|
*/
|
|
57
46
|
chainRequestIds = true) {
|
|
58
47
|
this.contextReader = contextReader;
|
|
59
|
-
this.registry = registry;
|
|
60
48
|
this.chainRequestIds = chainRequestIds;
|
|
61
49
|
this.chainProcessor = new RequestIdChainProcessor_1.RequestIdChainProcessor();
|
|
62
50
|
}
|
|
63
51
|
/**
|
|
64
|
-
* Build the headers to send on an outbound request: every transferred
|
|
65
|
-
*
|
|
66
|
-
* then request-id chaining applied (unless opted out).
|
|
52
|
+
* Build the headers to send on an outbound request: every transferred key
|
|
53
|
+
* (httpHeader set) with a non-empty value in the context, emitted under its
|
|
54
|
+
* `httpHeader` wire name, then request-id chaining applied (unless opted out).
|
|
67
55
|
*
|
|
68
56
|
* Values are RAW (unmasked) - this map goes on the wire, not in logs.
|
|
69
57
|
*/
|
|
70
58
|
buildOutboundHeaders() {
|
|
71
59
|
const outbound = new Map();
|
|
72
|
-
for (const
|
|
73
|
-
const value = this.contextReader.read(
|
|
60
|
+
for (const key of HeaderRegistry_1.HeaderRegistry.get().getTransferredKeys()) {
|
|
61
|
+
const value = this.contextReader.read(key);
|
|
74
62
|
if (value !== undefined && value !== null && value !== '') {
|
|
75
|
-
outbound.set(
|
|
63
|
+
outbound.set(key.httpHeader, value);
|
|
76
64
|
}
|
|
77
65
|
}
|
|
78
66
|
if (this.chainRequestIds) {
|
|
@@ -81,11 +69,11 @@ class ContextMgr {
|
|
|
81
69
|
return outbound;
|
|
82
70
|
}
|
|
83
71
|
/**
|
|
84
|
-
* Build the header map for LOGGING: secured
|
|
85
|
-
*
|
|
72
|
+
* Build the header map for LOGGING: secured values masked, keyed by each key's
|
|
73
|
+
* `name`, only for keys with isLogged=true.
|
|
86
74
|
*/
|
|
87
75
|
buildHeadersForLogging(headerMethods) {
|
|
88
|
-
return headerMethods.buildSecureMapForLogs(
|
|
76
|
+
return headerMethods.buildSecureMapForLogs(HeaderRegistry_1.HeaderRegistry.get().getLoggedKeys(), this.contextReader);
|
|
89
77
|
}
|
|
90
78
|
}
|
|
91
79
|
exports.ContextMgr = ContextMgr;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextMgr.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ContextMgr.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ContextMgr.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ContextMgr.ts"],"names":[],"mappings":";;;AAEA,qDAAkD;AAClD,uEAAoE;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAa,UAAU;IAQC;IAOA;IAdZ,cAAc,CAA0B;IAEhD;IACI;;;OAGG;IACa,aAA4B;IAE5C;;;;OAIG;IACa,kBAA2B,IAAI;QAP/B,kBAAa,GAAb,aAAa,CAAe;QAO5B,oBAAe,GAAf,eAAe,CAAgB;QAE/C,IAAI,CAAC,cAAc,GAAG,IAAI,iDAAuB,EAAE,CAAC;IACxD,CAAC;IAED;;;;;;OAMG;IACH,oBAAoB;QAChB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;QAE3C,KAAK,MAAM,GAAG,IAAI,+BAAc,CAAC,GAAG,EAAE,CAAC,kBAAkB,EAAE,EAAE,CAAC;YAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBACxD,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,UAAW,EAAE,KAAK,CAAC,CAAC;YACzC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,sBAAsB,CAAC,aAA4B;QAC/C,OAAO,aAAa,CAAC,qBAAqB,CAAC,+BAAc,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACzG,CAAC;CACJ;AAnDD,gCAmDC","sourcesContent":["import { ContextReader } from './ContextReader';\nimport { HeaderMethods } from './HeaderMethods';\nimport { HeaderRegistry } from './HeaderRegistry';\nimport { RequestIdChainProcessor } from './RequestIdChainProcessor';\n\n/**\n * ContextMgr - propagates the magic context onto outbound HTTP requests.\n *\n * Passed to createApiClient() via ClientConfig.contextMgr: every transferred key\n * (httpHeader set) in the GLOBAL {@link HeaderRegistry} is read from the ContextReader\n * and added to outbound requests. The registry is a process global (configured once at\n * startup, like LogManager), so ContextMgr no longer takes a registry argument.\n *\n * Browser-safe (no AsyncLocalStorage): the server-side reader (RequestContextReader,\n * in @webpieces/core-context) and the browser store (MutableContextStore, in\n * @webpieces/http-client) both implement ContextReader.\n *\n * Example usage:\n * ```typescript\n * // Node.js server-side (reads the magic context from RequestContext):\n * const contextMgr = new ContextMgr(new RequestContextReader());\n *\n * // Browser client-side (app-managed store, no AsyncLocalStorage):\n * const contextMgr = new ContextMgr(new MutableContextStore());\n *\n * // Both cases:\n * const config = new ClientConfig('http://api.example.com', contextMgr);\n * const client = createApiClient(SaveApi, config);\n * ```\n */\nexport class ContextMgr {\n private chainProcessor: RequestIdChainProcessor;\n\n constructor(\n /**\n * The context reader that provides context-key values.\n * Different implementations for Node.js vs browser.\n */\n public readonly contextReader: ContextReader,\n\n /**\n * When true (default), outbound calls send the current x-request-id as\n * x-previous-request-id (and drop x-request-id) so each hop in a\n * distributed trace gets its own id chained to its caller's.\n */\n public readonly chainRequestIds: boolean = true,\n ) {\n this.chainProcessor = new RequestIdChainProcessor();\n }\n\n /**\n * Build the headers to send on an outbound request: every transferred key\n * (httpHeader set) with a non-empty value in the context, emitted under its\n * `httpHeader` wire name, then request-id chaining applied (unless opted out).\n *\n * Values are RAW (unmasked) - this map goes on the wire, not in logs.\n */\n buildOutboundHeaders(): Map<string, string> {\n const outbound = new Map<string, string>();\n\n for (const key of HeaderRegistry.get().getTransferredKeys()) {\n const value = this.contextReader.read(key);\n if (value !== undefined && value !== null && value !== '') {\n outbound.set(key.httpHeader!, value);\n }\n }\n\n if (this.chainRequestIds) {\n this.chainProcessor.process(outbound);\n }\n\n return outbound;\n }\n\n /**\n * Build the header map for LOGGING: secured values masked, keyed by each key's\n * `name`, only for keys with isLogged=true.\n */\n buildHeadersForLogging(headerMethods: HeaderMethods): Map<string, string> {\n return headerMethods.buildSecureMapForLogs(HeaderRegistry.get().getLoggedKeys(), this.contextReader);\n }\n}\n"]}
|
|
@@ -1,37 +1,28 @@
|
|
|
1
1
|
import { ContextKey } from '../ContextKey';
|
|
2
|
-
import { PlatformHeader } from './PlatformHeader';
|
|
3
2
|
/**
|
|
4
|
-
* ContextReader -
|
|
3
|
+
* ContextReader - reads context-key values from the ambient magic context.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* There are exactly TWO implementations, one per environment:
|
|
6
|
+
* - Node/server: `RequestContextReader` (in @webpieces/core-context) — reads the
|
|
7
|
+
* AsyncLocalStorage-backed RequestContext.
|
|
8
|
+
* - Browser: `MutableContextStore` (in @webpieces/http-client) — a mutable in-memory
|
|
9
|
+
* store the app sets as values become known (login token, tenant, ...).
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* both server (Inversify) and client (Angular/React, browser) environments.
|
|
11
|
+
* Defined in core-util (browser + Node safe, DI-independent) so both sides can use it
|
|
12
|
+
* without a circular dependency.
|
|
15
13
|
*
|
|
16
14
|
* This is a business-logic interface (per CLAUDE.md: behavior = interface).
|
|
17
15
|
*/
|
|
18
16
|
export interface ContextReader {
|
|
19
17
|
/**
|
|
20
|
-
* Read the value of a
|
|
21
|
-
* Returns undefined if header not available.
|
|
22
|
-
*
|
|
23
|
-
* @param header - The platform header to read
|
|
24
|
-
* @returns The header value, or undefined if not present
|
|
18
|
+
* Read the string value of a context key. Returns undefined if not present.
|
|
25
19
|
*/
|
|
26
|
-
read(
|
|
20
|
+
read(key: ContextKey): string | undefined;
|
|
27
21
|
/**
|
|
28
|
-
* OPTIONAL: read a non-
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* RequestContext; browser readers may omit it (no server-side recording
|
|
33
|
-
* in browsers - same as Java). This keeps http-client free of any
|
|
34
|
-
* Node-only imports while still letting it find the recorder.
|
|
22
|
+
* OPTIONAL: read a non-string context value (e.g. the active TestCaseRecorder
|
|
23
|
+
* under RecorderKeys.RECORDER). Server-side readers implement this over the
|
|
24
|
+
* RequestContext; browser readers may omit it (no server-side recording in
|
|
25
|
+
* browsers — same as Java).
|
|
35
26
|
*/
|
|
36
27
|
readValue?(key: ContextKey): unknown;
|
|
37
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextReader.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ContextReader.ts"],"names":[],"mappings":"","sourcesContent":["import { ContextKey } from '../ContextKey';\
|
|
1
|
+
{"version":3,"file":"ContextReader.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ContextReader.ts"],"names":[],"mappings":"","sourcesContent":["import { ContextKey } from '../ContextKey';\n\n/**\n * ContextReader - reads context-key values from the ambient magic context.\n *\n * There are exactly TWO implementations, one per environment:\n * - Node/server: `RequestContextReader` (in @webpieces/core-context) — reads the\n * AsyncLocalStorage-backed RequestContext.\n * - Browser: `MutableContextStore` (in @webpieces/http-client) — a mutable in-memory\n * store the app sets as values become known (login token, tenant, ...).\n *\n * Defined in core-util (browser + Node safe, DI-independent) so both sides can use it\n * without a circular dependency.\n *\n * This is a business-logic interface (per CLAUDE.md: behavior = interface).\n */\nexport interface ContextReader {\n /**\n * Read the string value of a context key. Returns undefined if not present.\n */\n read(key: ContextKey): string | undefined;\n\n /**\n * OPTIONAL: read a non-string context value (e.g. the active TestCaseRecorder\n * under RecorderKeys.RECORDER). Server-side readers implement this over the\n * RequestContext; browser readers may omit it (no server-side recording in\n * browsers — same as Java).\n */\n // webpieces-disable no-any-unknown -- context values are heterogeneous (recorder, meta objects)\n readValue?(key: ContextKey): unknown;\n}\n"]}
|
|
@@ -1,71 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ContextKey } from '../ContextKey';
|
|
2
2
|
import { ContextReader } from './ContextReader';
|
|
3
3
|
/**
|
|
4
|
-
* HeaderMethods -
|
|
4
|
+
* HeaderMethods - stateless utility for turning context keys + a ContextReader into
|
|
5
|
+
* the maps the framework needs (outbound transfer, masked log map).
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Pattern: Stateless utility class (pure functions, can be instantiated or injected)
|
|
10
|
-
* - Server: Can inject empty instance, use static-like methods
|
|
11
|
-
* - Client: new HeaderMethods() (no DI needed)
|
|
12
|
-
*
|
|
13
|
-
* Usage:
|
|
14
|
-
* ```typescript
|
|
15
|
-
* // Server-side (ContextFilter)
|
|
16
|
-
* constructor(@inject() headerMethods: HeaderMethods) {
|
|
17
|
-
* const allHeaders = [... flatten from extensions ...];
|
|
18
|
-
* this.transferHeaders = headerMethods.findTransferHeaders(allHeaders);
|
|
19
|
-
* }
|
|
20
|
-
*
|
|
21
|
-
* // Client-side (ClientFactory)
|
|
22
|
-
* const headerMethods = new HeaderMethods();
|
|
23
|
-
* const loggableHeaders = headerMethods.findLoggableHeaders(allHeaders, requestHeaders);
|
|
24
|
-
* ```
|
|
7
|
+
* Works in both server (Node) and browser environments; a plain `new HeaderMethods()`
|
|
8
|
+
* (no DI). The set of keys is supplied by the caller (from HeaderRegistry).
|
|
25
9
|
*/
|
|
26
10
|
export declare class HeaderMethods {
|
|
11
|
+
/** Keys that transfer over the wire (httpHeader set). */
|
|
12
|
+
findTransferKeys(keys: ContextKey[]): ContextKey[];
|
|
13
|
+
/** Keys whose values are masked in logs (isSecured=true). */
|
|
14
|
+
securedKeys(keys: ContextKey[]): ContextKey[];
|
|
27
15
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @param headers - Array of PlatformHeader definitions
|
|
31
|
-
* @returns Filtered array of headers with isWantTransferred=true
|
|
32
|
-
*/
|
|
33
|
-
findTransferHeaders(headers: PlatformHeader[]): PlatformHeader[];
|
|
34
|
-
/**
|
|
35
|
-
* Split headers into secure and public categories.
|
|
36
|
-
*
|
|
37
|
-
* @param headers - Array of PlatformHeader definitions
|
|
38
|
-
* @returns SplitHeaders with secureHeaders (isSecured=true) and publicHeaders (isSecured=false)
|
|
39
|
-
*/
|
|
40
|
-
secureHeaders(headers: PlatformHeader[]): PlatformHeader[];
|
|
41
|
-
/**
|
|
42
|
-
* Get all headers that should be logged.
|
|
43
|
-
* All headers are loggable - secure headers will be masked by formatHeadersForLogging.
|
|
44
|
-
*
|
|
45
|
-
* @param headers - Array of PlatformHeader definitions
|
|
46
|
-
* @returns All headers (they're all loggable, just some are masked)
|
|
47
|
-
*/
|
|
48
|
-
findLoggableHeaders(headers: PlatformHeader[]): PlatformHeader[];
|
|
49
|
-
buildSecureMapForLogs(platformHeaders: PlatformHeader[], contextReader: ContextReader): Map<string, any>;
|
|
50
|
-
/**
|
|
51
|
-
* Format headers for logging with secure masking.
|
|
52
|
-
* Takes filtered PlatformHeaders and actual header values from request.
|
|
53
|
-
*
|
|
54
|
-
* Masking rules for secure headers (isSecured=true):
|
|
55
|
-
* - Length > 15: Show first 3 and last 3 characters with "..." between
|
|
56
|
-
* - Length 8-15: Show first 2 characters with "..."
|
|
57
|
-
* - Length < 8: Show "<secure key too short to log>"
|
|
58
|
-
*
|
|
59
|
-
* @param loggableHeaders - Filtered PlatformHeaders to log
|
|
60
|
-
* @param headerMap - Map of header name (lowercase) -> array of values from request
|
|
61
|
-
* @returns Record of header name -> masked or full value for logging
|
|
16
|
+
* Build the map for LOGGING from the given keys: each logged key (isLogged=true)
|
|
17
|
+
* with a value present is added under its `name`, masked when isSecured.
|
|
62
18
|
*/
|
|
63
|
-
|
|
19
|
+
buildSecureMapForLogs(keys: ContextKey[], contextReader: ContextReader): Map<string, string>;
|
|
64
20
|
/**
|
|
65
|
-
* Mask a secure
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
21
|
+
* Mask a secure value based on its length.
|
|
22
|
+
* - Length > 15: first 3 + "..." + last 3
|
|
23
|
+
* - Length 8-15: first 2 + "..."
|
|
24
|
+
* - Length < 8: "<secure key too short to log>"
|
|
69
25
|
*/
|
|
70
26
|
private maskSecureValue;
|
|
71
27
|
}
|