@webpieces/http-client 0.3.166 → 0.3.167
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 +2 -2
- package/src/ClientFactory.js +12 -0
- package/src/ClientFactory.js.map +1 -1
- package/src/ContextMgr.js +2 -0
- package/src/ContextMgr.js.map +1 -1
- package/src/ContextReader.js +2 -0
- package/src/ContextReader.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/http-client",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.167",
|
|
4
4
|
"description": "HTTP client for WebPieces framework",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@webpieces/http-api": "0.3.
|
|
24
|
+
"@webpieces/http-api": "0.3.167"
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/ClientFactory.js
CHANGED
|
@@ -8,6 +8,13 @@ const ClientErrorTranslator_1 = require("./ClientErrorTranslator");
|
|
|
8
8
|
* Configuration options for HTTP client.
|
|
9
9
|
*/
|
|
10
10
|
class ClientConfig {
|
|
11
|
+
/** Base URL for all requests (e.g., 'http://localhost:3000') */
|
|
12
|
+
baseUrl;
|
|
13
|
+
/**
|
|
14
|
+
* Optional context manager for automatic header propagation.
|
|
15
|
+
* When provided, headers will be read from the ContextReader and added to requests.
|
|
16
|
+
*/
|
|
17
|
+
contextMgr;
|
|
11
18
|
constructor(baseUrl, contextMgr) {
|
|
12
19
|
this.baseUrl = baseUrl;
|
|
13
20
|
this.contextMgr = contextMgr;
|
|
@@ -120,6 +127,11 @@ function createApiClient(apiPrototype, config, contextMgr) {
|
|
|
120
127
|
* LogApiCall is injected for consistent logging across the framework.
|
|
121
128
|
*/
|
|
122
129
|
class ProxyClient {
|
|
130
|
+
config;
|
|
131
|
+
logApiCall;
|
|
132
|
+
headerMethods;
|
|
133
|
+
contextMgr;
|
|
134
|
+
routeMap;
|
|
123
135
|
constructor(config, logApiCall, headerMethods, routes, contextMgr) {
|
|
124
136
|
this.config = config;
|
|
125
137
|
this.logApiCall = logApiCall;
|
package/src/ClientFactory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ClientFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isApiPath,\n getApiPath,\n getEndpoints,\n RouteMetadata,\n ProtocolError,\n HeaderMethods,\n LogApiCall,\n} from '@webpieces/http-api';\nimport { ClientErrorTranslator } from './ClientErrorTranslator';\nimport { ContextMgr } from './ContextMgr';\n\n/**\n * Type representing a class constructor whose prototype is T.\n * Used as the apiPrototype parameter for createApiClient.\n */\ntype ApiPrototype<T> = Function & { prototype: T };\n\n/**\n * Configuration options for HTTP client.\n */\nexport class ClientConfig {\n /** Base URL for all requests (e.g., 'http://localhost:3000') */\n baseUrl: string;\n\n /**\n * Optional context manager for automatic header propagation.\n * When provided, headers will be read from the ContextReader and added to requests.\n */\n contextMgr?: ContextMgr;\n\n constructor(baseUrl: string, contextMgr?: ContextMgr) {\n this.baseUrl = baseUrl;\n this.contextMgr = contextMgr;\n }\n}\n\n/**\n * Return type for the Proxy get trap — either an async method or undefined for framework inspection.\n */\n// webpieces-disable no-any-unknown -- Proxy get trap returns generic response promises\ntype ProxyGetResult = (...args: never[]) => Promise<unknown>;\n\n/**\n * Properties accessed by DI frameworks (Angular, Vue), debuggers, Promise checks, and serializers.\n * These should return undefined instead of throwing, allowing frameworks to inspect the proxy.\n *\n * Why this exists:\n * - Angular's injector profiler accesses `constructor` after useFactory returns\n * - Promise.resolve() checks for `then` to detect thenables\n * - JSON.stringify checks for `toJSON`\n * - Debuggers access `prototype`, `__proto__`, etc.\n */\nconst FRAMEWORK_INSPECTION_PROPERTIES = new Set([\n 'constructor', // Angular DI profiler, class inspection\n 'prototype', // Prototype chain inspection\n '__proto__', // Legacy prototype access\n 'name', // Angular isNotFound() check, function/class name inspection\n 'then', // Promise/thenable detection\n 'catch', // Promise check\n 'finally', // Promise check\n 'toJSON', // JSON.stringify\n 'valueOf', // Type coercion\n 'toString', // String coercion\n 'nodeType', // DOM element check\n 'tagName', // DOM element check\n '$$typeof', // React element/component check\n '$typeof', // React internal\n '_isVue', // Vue internal\n 'ngOnInit', // Angular lifecycle hook check\n 'ngOnDestroy', // Angular lifecycle hook check\n 'ngOnChanges', // Angular lifecycle hook check\n 'asymmetricMatch', // Jest matcher protocol\n]);\n\n/**\n * Creates a type-safe HTTP client from an API prototype with @ApiPath/@Endpoint decorators.\n *\n * This is the client-side equivalent of ApiRoutingFactory.\n * - Server: ApiRoutingFactory reads decorators -> routes HTTP requests to controllers\n * - Client: createApiClient reads decorators -> generates HTTP requests from method calls\n *\n * Usage:\n * ```typescript\n * const config = new ClientConfig('http://localhost:3000');\n * const client = createApiClient(SaveApi, config);\n * const response = await client.save({ query: 'test' }); // Type-safe!\n * ```\n *\n * @param apiPrototype - The API prototype class with @ApiPath/@Endpoint decorators\n * @param config - Client configuration with baseUrl\n * @param contextMgr - Optional context manager for header propagation\n * @returns A proxy object that implements the API interface\n */\nexport function createApiClient<T extends object>(\n apiPrototype: ApiPrototype<T>,\n config: ClientConfig,\n contextMgr?: ContextMgr\n): T {\n // Validate that the API prototype is marked with @ApiPath\n if (!isApiPath(apiPrototype)) {\n const className = apiPrototype.name || 'Unknown';\n throw new Error(`Class ${className} must be decorated with @ApiPath()`);\n }\n\n const basePath = getApiPath(apiPrototype)!;\n const endpoints = getEndpoints(apiPrototype) || {};\n\n // Build RouteMetadata array from @ApiPath + @Endpoint metadata\n const routes: RouteMetadata[] = [];\n for (const [methodName, endpointPath] of Object.entries(endpoints)) {\n const fullPath = basePath + endpointPath;\n routes.push(new RouteMetadata('POST', fullPath, methodName));\n }\n\n // Create ProxyClient with injected LogApiCall\n // Our own little DI going on here as angular and nodejs are using 2 different DI systems\n const proxyClient = new ProxyClient(\n config, new LogApiCall(), new HeaderMethods(), routes, contextMgr);\n\n // Create a proxy that intercepts method calls and makes HTTP requests\n return new Proxy({} as T, {\n get(target, prop: string | symbol): ProxyGetResult | undefined {\n // Symbols (Symbol.toStringTag, Symbol.iterator, etc.) - throw for now to learn if this happens\n if (typeof prop !== 'string') {\n throw new Error(\n `Proxy accessed with non-string property: ${String(prop)} (type: ${typeof prop}). ` +\n `Please report this so we can add it to the whitelist.`\n );\n }\n\n // Framework inspection properties - return undefined to allow inspection\n // WITHOUT throwing. This is critical for Angular DI, Promise checks, etc.\n if (FRAMEWORK_INSPECTION_PROPERTIES.has(prop)) {\n return undefined;\n }\n\n // Check if this property is actually a route method\n if (!proxyClient.hasRoute(prop)) {\n // For unknown properties (likely typos), throw a helpful error\n throw new Error(\n `No route found for method '${prop}'. ` +\n `Check for typos or ensure the method has @Endpoint() decorator.`\n );\n }\n\n const route = proxyClient.getRoute(prop);\n\n // Return a function that makes the HTTP request\n return async (...args: any[]) => {\n return proxyClient.makeRequest(route, args);\n };\n },\n });\n}\n\n/**\n * ProxyClient - HTTP client implementation with logging.\n *\n * This class handles:\n * - Making HTTP requests based on route metadata\n * - Header propagation via ContextMgr\n * - Logging via LogApiCall\n * - Error translation via ClientErrorTranslator\n *\n * LogApiCall is injected for consistent logging across the framework.\n */\nexport class ProxyClient {\n private routeMap: Map<string, RouteMetadata>;\n\n constructor(\n private config: ClientConfig,\n private logApiCall: LogApiCall,\n private headerMethods: HeaderMethods,\n routes: RouteMetadata[],\n private contextMgr?: ContextMgr,\n ) {\n // Create a map of method name -> route metadata for fast lookup\n this.routeMap = new Map<string, RouteMetadata>();\n for (const route of routes) {\n this.routeMap.set(route.methodName, route);\n }\n }\n\n /**\n * Check if a route exists for the given method name.\n */\n hasRoute(methodName: string): boolean {\n return this.routeMap.has(methodName);\n }\n\n /**\n * Get route metadata for a method name.\n * @throws Error if no route found\n */\n getRoute(methodName: string): RouteMetadata {\n const route = this.routeMap.get(methodName);\n if (!route) {\n throw new Error(`No route found for method ${methodName}`);\n }\n return route;\n }\n\n /**\n * Make an HTTP request based on route metadata and arguments.\n *\n * All endpoints are POST-only. The request body is the first argument.\n */\n async makeRequest(route: RouteMetadata, args: any[]): Promise<any> {\n const { httpMethod, path } = route;\n\n // Build the full URL\n const url = `${this.config.baseUrl}${path}`;\n\n // Build base headers for the HTTP request\n const httpHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Add context headers to httpHeaders (unmasked, for actual HTTP request)\n if (this.contextMgr) {\n for (const header of this.contextMgr.headerSet) {\n const value = this.contextMgr.contextReader.read(header);\n if (value) {\n httpHeaders[header.headerName] = value;\n }\n }\n }\n\n // Build masked headers map for logging\n const headersForLogging = this.contextMgr\n ? this.headerMethods.buildSecureMapForLogs(this.contextMgr.headerSet, this.contextMgr.contextReader)\n : new Map<string, any>();\n\n // Build request options\n const options: RequestInit = {\n method: httpMethod,\n headers: httpHeaders,\n };\n\n // POST body is the first argument as JSON\n let requestDto: unknown;\n if (args.length > 0) {\n requestDto = args[0];\n options.body = JSON.stringify(requestDto);\n }\n\n // Wrap fetch in a method for LogApiCall.execute\n const method = async (): Promise<unknown> => {\n return this.executeFetch(url, options);\n };\n\n return await this.logApiCall.execute(\"CLIENT\", route, requestDto, headersForLogging, method);\n }\n\n /**\n * Execute the fetch request and handle response.\n */\n private async executeFetch(url: string, options: RequestInit): Promise<unknown> {\n const response = await fetch(url, options);\n\n if (response.ok) {\n return await response.json();\n }\n\n // Handle errors (non-2xx responses)\n // Try to parse ProtocolError from response body\n const protocolError = (await response.json()) as ProtocolError;\n\n // Reconstruct appropriate HttpError subclass and throw\n throw ClientErrorTranslator.translateError(response, protocolError);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ClientFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ClientFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isApiPath,\n getApiPath,\n getEndpoints,\n RouteMetadata,\n ProtocolError,\n HeaderMethods,\n LogApiCall,\n} from '@webpieces/http-api';\nimport { ClientErrorTranslator } from './ClientErrorTranslator';\nimport { ContextMgr } from './ContextMgr';\n\n/**\n * Type representing a class constructor whose prototype is T.\n * Used as the apiPrototype parameter for createApiClient.\n */\ntype ApiPrototype<T> = Function & { prototype: T };\n\n/**\n * Configuration options for HTTP client.\n */\nexport class ClientConfig {\n /** Base URL for all requests (e.g., 'http://localhost:3000') */\n baseUrl: string;\n\n /**\n * Optional context manager for automatic header propagation.\n * When provided, headers will be read from the ContextReader and added to requests.\n */\n contextMgr?: ContextMgr;\n\n constructor(baseUrl: string, contextMgr?: ContextMgr) {\n this.baseUrl = baseUrl;\n this.contextMgr = contextMgr;\n }\n}\n\n/**\n * Return type for the Proxy get trap — either an async method or undefined for framework inspection.\n */\n// webpieces-disable no-any-unknown -- Proxy get trap returns generic response promises\ntype ProxyGetResult = (...args: never[]) => Promise<unknown>;\n\n/**\n * Properties accessed by DI frameworks (Angular, Vue), debuggers, Promise checks, and serializers.\n * These should return undefined instead of throwing, allowing frameworks to inspect the proxy.\n *\n * Why this exists:\n * - Angular's injector profiler accesses `constructor` after useFactory returns\n * - Promise.resolve() checks for `then` to detect thenables\n * - JSON.stringify checks for `toJSON`\n * - Debuggers access `prototype`, `__proto__`, etc.\n */\nconst FRAMEWORK_INSPECTION_PROPERTIES = new Set([\n 'constructor', // Angular DI profiler, class inspection\n 'prototype', // Prototype chain inspection\n '__proto__', // Legacy prototype access\n 'name', // Angular isNotFound() check, function/class name inspection\n 'then', // Promise/thenable detection\n 'catch', // Promise check\n 'finally', // Promise check\n 'toJSON', // JSON.stringify\n 'valueOf', // Type coercion\n 'toString', // String coercion\n 'nodeType', // DOM element check\n 'tagName', // DOM element check\n '$$typeof', // React element/component check\n '$typeof', // React internal\n '_isVue', // Vue internal\n 'ngOnInit', // Angular lifecycle hook check\n 'ngOnDestroy', // Angular lifecycle hook check\n 'ngOnChanges', // Angular lifecycle hook check\n 'asymmetricMatch', // Jest matcher protocol\n]);\n\n/**\n * Creates a type-safe HTTP client from an API prototype with @ApiPath/@Endpoint decorators.\n *\n * This is the client-side equivalent of ApiRoutingFactory.\n * - Server: ApiRoutingFactory reads decorators -> routes HTTP requests to controllers\n * - Client: createApiClient reads decorators -> generates HTTP requests from method calls\n *\n * Usage:\n * ```typescript\n * const config = new ClientConfig('http://localhost:3000');\n * const client = createApiClient(SaveApi, config);\n * const response = await client.save({ query: 'test' }); // Type-safe!\n * ```\n *\n * @param apiPrototype - The API prototype class with @ApiPath/@Endpoint decorators\n * @param config - Client configuration with baseUrl\n * @param contextMgr - Optional context manager for header propagation\n * @returns A proxy object that implements the API interface\n */\nexport function createApiClient<T extends object>(\n apiPrototype: ApiPrototype<T>,\n config: ClientConfig,\n contextMgr?: ContextMgr\n): T {\n // Validate that the API prototype is marked with @ApiPath\n if (!isApiPath(apiPrototype)) {\n const className = apiPrototype.name || 'Unknown';\n throw new Error(`Class ${className} must be decorated with @ApiPath()`);\n }\n\n const basePath = getApiPath(apiPrototype)!;\n const endpoints = getEndpoints(apiPrototype) || {};\n\n // Build RouteMetadata array from @ApiPath + @Endpoint metadata\n const routes: RouteMetadata[] = [];\n for (const [methodName, endpointPath] of Object.entries(endpoints)) {\n const fullPath = basePath + endpointPath;\n routes.push(new RouteMetadata('POST', fullPath, methodName));\n }\n\n // Create ProxyClient with injected LogApiCall\n // Our own little DI going on here as angular and nodejs are using 2 different DI systems\n const proxyClient = new ProxyClient(\n config, new LogApiCall(), new HeaderMethods(), routes, contextMgr);\n\n // Create a proxy that intercepts method calls and makes HTTP requests\n return new Proxy({} as T, {\n get(target, prop: string | symbol): ProxyGetResult | undefined {\n // Symbols (Symbol.toStringTag, Symbol.iterator, etc.) - throw for now to learn if this happens\n if (typeof prop !== 'string') {\n throw new Error(\n `Proxy accessed with non-string property: ${String(prop)} (type: ${typeof prop}). ` +\n `Please report this so we can add it to the whitelist.`\n );\n }\n\n // Framework inspection properties - return undefined to allow inspection\n // WITHOUT throwing. This is critical for Angular DI, Promise checks, etc.\n if (FRAMEWORK_INSPECTION_PROPERTIES.has(prop)) {\n return undefined;\n }\n\n // Check if this property is actually a route method\n if (!proxyClient.hasRoute(prop)) {\n // For unknown properties (likely typos), throw a helpful error\n throw new Error(\n `No route found for method '${prop}'. ` +\n `Check for typos or ensure the method has @Endpoint() decorator.`\n );\n }\n\n const route = proxyClient.getRoute(prop);\n\n // Return a function that makes the HTTP request\n return async (...args: any[]) => {\n return proxyClient.makeRequest(route, args);\n };\n },\n });\n}\n\n/**\n * ProxyClient - HTTP client implementation with logging.\n *\n * This class handles:\n * - Making HTTP requests based on route metadata\n * - Header propagation via ContextMgr\n * - Logging via LogApiCall\n * - Error translation via ClientErrorTranslator\n *\n * LogApiCall is injected for consistent logging across the framework.\n */\nexport class ProxyClient {\n private routeMap: Map<string, RouteMetadata>;\n\n constructor(\n private config: ClientConfig,\n private logApiCall: LogApiCall,\n private headerMethods: HeaderMethods,\n routes: RouteMetadata[],\n private contextMgr?: ContextMgr,\n ) {\n // Create a map of method name -> route metadata for fast lookup\n this.routeMap = new Map<string, RouteMetadata>();\n for (const route of routes) {\n this.routeMap.set(route.methodName, route);\n }\n }\n\n /**\n * Check if a route exists for the given method name.\n */\n hasRoute(methodName: string): boolean {\n return this.routeMap.has(methodName);\n }\n\n /**\n * Get route metadata for a method name.\n * @throws Error if no route found\n */\n getRoute(methodName: string): RouteMetadata {\n const route = this.routeMap.get(methodName);\n if (!route) {\n throw new Error(`No route found for method ${methodName}`);\n }\n return route;\n }\n\n /**\n * Make an HTTP request based on route metadata and arguments.\n *\n * All endpoints are POST-only. The request body is the first argument.\n */\n async makeRequest(route: RouteMetadata, args: any[]): Promise<any> {\n const { httpMethod, path } = route;\n\n // Build the full URL\n const url = `${this.config.baseUrl}${path}`;\n\n // Build base headers for the HTTP request\n const httpHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Add context headers to httpHeaders (unmasked, for actual HTTP request)\n if (this.contextMgr) {\n for (const header of this.contextMgr.headerSet) {\n const value = this.contextMgr.contextReader.read(header);\n if (value) {\n httpHeaders[header.headerName] = value;\n }\n }\n }\n\n // Build masked headers map for logging\n const headersForLogging = this.contextMgr\n ? this.headerMethods.buildSecureMapForLogs(this.contextMgr.headerSet, this.contextMgr.contextReader)\n : new Map<string, any>();\n\n // Build request options\n const options: RequestInit = {\n method: httpMethod,\n headers: httpHeaders,\n };\n\n // POST body is the first argument as JSON\n let requestDto: unknown;\n if (args.length > 0) {\n requestDto = args[0];\n options.body = JSON.stringify(requestDto);\n }\n\n // Wrap fetch in a method for LogApiCall.execute\n const method = async (): Promise<unknown> => {\n return this.executeFetch(url, options);\n };\n\n return await this.logApiCall.execute(\"CLIENT\", route, requestDto, headersForLogging, method);\n }\n\n /**\n * Execute the fetch request and handle response.\n */\n private async executeFetch(url: string, options: RequestInit): Promise<unknown> {\n const response = await fetch(url, options);\n\n if (response.ok) {\n return await response.json();\n }\n\n // Handle errors (non-2xx responses)\n // Try to parse ProtocolError from response body\n const protocolError = (await response.json()) as ProtocolError;\n\n // Reconstruct appropriate HttpError subclass and throw\n throw ClientErrorTranslator.translateError(response, protocolError);\n }\n}\n"]}
|
package/src/ContextMgr.js
CHANGED
package/src/ContextMgr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextMgr.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ContextMgr.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"ContextMgr.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ContextMgr.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAa,UAAU;IAMC;IAMA;IAXpB;IACI;;;OAGG;IACa,aAA4B;IAE5C;;;OAGG;IACa,SAA2B;QAN3B,kBAAa,GAAb,aAAa,CAAe;QAM5B,cAAS,GAAT,SAAS,CAAkB;IAC5C,CAAC;IAEJ;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,UAAkB;QACnB,wCAAwC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QAErE,yCAAyC;QACzC,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,kDAAkD;QAClD,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;YAC5B,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,iCAAiC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE9C,+BAA+B;QAC/B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxD,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,OAAO,SAAS,CAAC;IACrB,CAAC;CACJ;AArDD,gCAqDC","sourcesContent":["import { PlatformHeader, ContextReader } from '@webpieces/http-api';\n\n/**\n * ContextMgr - Manages context reader and header set for HTTP clients.\n *\n * Passed to createClient() via ClientConfig to enable automatic header propagation.\n * Combines a ContextReader (how to read header values) with a header set\n * (which headers to propagate).\n *\n * Example usage:\n * ```typescript\n * // Node.js server-side (reads from RequestContext)\n * const contextMgr = new ContextMgr(\n * new RequestContextReader(),\n * [...WebpiecesCoreHeaders.getAllHeaders(), ...CompanyHeaders.getAllHeaders()]\n * );\n *\n * // Browser client-side (reads from static map)\n * const headers = new Map([['Authorization', getToken()]]);\n * const contextMgr = new ContextMgr(\n * new StaticContextReader(headers),\n * [WebpiecesCoreHeaders.REQUEST_ID]\n * );\n *\n * // Both cases\n * const config = new ClientConfig('http://api.example.com', contextMgr);\n * const client = createClient(SaveApi, config);\n * ```\n */\nexport class ContextMgr {\n constructor(\n /**\n * The context reader that provides header values.\n * Different implementations for Node.js vs browser.\n */\n public readonly contextReader: ContextReader,\n\n /**\n * The set of platform headers to read and propagate.\n * Only headers in this set will be added to requests.\n */\n public readonly headerSet: PlatformHeader[]\n ) {}\n\n /**\n * Read a single header value by header name.\n *\n * Returns undefined if:\n * - Header name not found in headerSet\n * - Header has isWantTransferred=false\n * - contextReader returns undefined/null/empty string\n *\n * This method is called by ClientFactory for each header in the headerSet,\n * allowing a single loop instead of the previous double-loop pattern.\n *\n * @param headerName - The HTTP header name (e.g., 'x-request-id')\n * @returns The header value, or undefined if not available/transferable\n */\n read(headerName: string): string | undefined {\n // Find the header definition in our set\n const header = this.headerSet.find(h => h.headerName === headerName);\n\n // Not in our header set - don't transfer\n if (!header) {\n return undefined;\n }\n\n // Header not marked for transfer - don't transfer\n if (!header.isWantTransferred) {\n return undefined;\n }\n\n // Read value from context reader\n const value = this.contextReader.read(header);\n\n // Only return non-empty values\n if (value !== undefined && value !== null && value !== '') {\n return value;\n }\n\n return undefined;\n }\n}\n"]}
|
package/src/ContextReader.js
CHANGED
|
@@ -18,6 +18,7 @@ exports.CompositeContextReader = exports.StaticContextReader = void 0;
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
class StaticContextReader {
|
|
21
|
+
headers;
|
|
21
22
|
constructor(headers) {
|
|
22
23
|
this.headers = headers;
|
|
23
24
|
}
|
|
@@ -44,6 +45,7 @@ exports.StaticContextReader = StaticContextReader;
|
|
|
44
45
|
* ```
|
|
45
46
|
*/
|
|
46
47
|
class CompositeContextReader {
|
|
48
|
+
readers;
|
|
47
49
|
constructor(readers) {
|
|
48
50
|
this.readers = readers;
|
|
49
51
|
}
|
package/src/ContextReader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextReader.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ContextReader.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAa,mBAAmB;
|
|
1
|
+
{"version":3,"file":"ContextReader.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ContextReader.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAa,mBAAmB;IACR;IAApB,YAAoB,OAA4B;QAA5B,YAAO,GAAP,OAAO,CAAqB;IAAG,CAAC;IAEpD,IAAI,CAAC,MAAsB;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;CACJ;AAND,kDAMC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,sBAAsB;IACX;IAApB,YAAoB,OAAwB;QAAxB,YAAO,GAAP,OAAO,CAAiB;IAAG,CAAC;IAEhD,IAAI,CAAC,MAAsB;QACvB,yDAAyD;QACzD,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACtB,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;CACJ;AAbD,wDAaC","sourcesContent":["import { PlatformHeader, ContextReader } from '@webpieces/http-api';\n\n/**\n * StaticContextReader - Returns static header values from a Map.\n *\n * Useful for:\n * - Browser environments where headers are manually managed\n * - Testing with fixed header values\n * - Angular services that read from localStorage/sessionStorage\n *\n * Example:\n * ```typescript\n * const headers = new Map<string, string>();\n * headers.set('x-api-version', 'v1');\n * headers.set('Authorization', getAuthToken());\n * const reader = new StaticContextReader(headers);\n * ```\n */\nexport class StaticContextReader implements ContextReader {\n constructor(private headers: Map<string, string>) {}\n\n read(header: PlatformHeader): string | undefined {\n return this.headers.get(header.headerName);\n }\n}\n\n/**\n * CompositeContextReader - Tries multiple readers in order.\n *\n * Later readers override earlier ones (last one wins).\n * Useful for layered header sources:\n * 1. RequestContext (base layer, from incoming request)\n * 2. Config headers (middle layer, from ClientConfig)\n * 3. Dynamic headers (top layer, runtime-computed values)\n *\n * Example:\n * ```typescript\n * const reader = new CompositeContextReader([\n * new RequestContextReader(), // Try context first\n * new StaticContextReader(config), // Fall back to config\n * ]);\n * ```\n */\nexport class CompositeContextReader implements ContextReader {\n constructor(private readers: ContextReader[]) {}\n\n read(header: PlatformHeader): string | undefined {\n // Try readers in reverse order (last one wins/overrides)\n for (let i = this.readers.length - 1; i >= 0; i--) {\n const value = this.readers[i].read(header);\n if (value !== undefined) {\n return value;\n }\n }\n return undefined;\n }\n}\n"]}
|