@webpieces/http-server 0.3.233 → 0.3.235
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/InProcessApiClientFactory.d.ts +34 -0
- package/src/InProcessApiClientFactory.js +77 -0
- package/src/InProcessApiClientFactory.js.map +1 -0
- package/src/WebpiecesRouteCreator.d.ts +90 -0
- package/src/WebpiecesRouteCreator.js +157 -0
- package/src/WebpiecesRouteCreator.js.map +1 -0
- package/src/WebpiecesServerImpl.d.ts +2 -10
- package/src/WebpiecesServerImpl.js +12 -84
- package/src/WebpiecesServerImpl.js.map +1 -1
- package/src/filters/ContextFilter.d.ts +3 -3
- package/src/filters/ContextFilter.js +9 -15
- package/src/filters/ContextFilter.js.map +1 -1
- package/src/filters/LogApiFilter.d.ts +2 -2
- package/src/filters/LogApiFilter.js +8 -10
- package/src/filters/LogApiFilter.js.map +1 -1
- package/src/filters/RecordingFilter.d.ts +30 -0
- package/src/filters/RecordingFilter.js +91 -0
- package/src/filters/RecordingFilter.js.map +1 -0
- package/src/headers/WebpiecesCoreHeaders.d.ts +4 -37
- package/src/headers/WebpiecesCoreHeaders.js +5 -48
- package/src/headers/WebpiecesCoreHeaders.js.map +1 -1
- package/src/index.d.ts +8 -1
- package/src/index.js +18 -1
- package/src/index.js.map +1 -1
- package/src/modules/WebpiecesModule.js +9 -0
- package/src/modules/WebpiecesModule.js.map +1 -1
- package/src/recorder/SpecGenerator.d.ts +16 -0
- package/src/recorder/SpecGenerator.js +70 -0
- package/src/recorder/SpecGenerator.js.map +1 -0
- package/src/recorder/TestCaseRecorderImpl.d.ts +33 -0
- package/src/recorder/TestCaseRecorderImpl.js +75 -0
- package/src/recorder/TestCaseRecorderImpl.js.map +1 -0
- package/src/recorder/recordable.d.ts +16 -0
- package/src/recorder/recordable.js +52 -0
- package/src/recorder/recordable.js.map +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebpiecesServerImpl.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/WebpiecesServerImpl.ts"],"names":[],"mappings":"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","sourcesContent":["import express, {Express} from 'express';\nimport {Container, ContainerModule, inject, injectable} from 'inversify';\nimport {buildProviderModule} from '@inversifyjs/binding-decorators';\nimport {\n ExpressRouteHandler,\n getApiPath,\n getAuthMeta,\n getEndpoints,\n MethodMeta,\n provideSingleton,\n RouteBuilderImpl, RouteMetadata,\n WebAppMeta,\n WEBAPP_META_TOKEN,\n WebpiecesConfig,\n} from '@webpieces/http-routing';\nimport {WebpiecesServer} from './WebpiecesServer';\nimport {WebpiecesMiddleware} from './WebpiecesMiddleware';\nimport {RequestContext} from '@webpieces/core-context';\nimport {Service, WpResponse} from \"@webpieces/http-filters\";\n\n/**\n * WebpiecesServerImpl - Internal server implementation.\n *\n * This class implements the WebpiecesServer interface and contains\n * all the actual server logic. It is created by WebpiecesFactory.create().\n *\n * This class uses a two-container pattern similar to Java WebPieces:\n * 1. webpiecesContainer: Core WebPieces framework bindings\n * 2. appContainer: User's application bindings (child of webpiecesContainer)\n *\n * This separation allows:\n * - Clean separation of concerns\n * - Better testability\n * - Ability to override framework bindings in tests\n *\n * The server:\n * 1. Initializes both DI containers from WebAppMeta.getDIModules()\n * 2. Registers routes using explicit RouteBuilderImpl\n * 3. Creates filter chains\n * 4. Supports both HTTP server mode and testing mode (no HTTP)\n *\n * DI Pattern: This class is registered in webpiecesContainer via @provideSingleton()\n * and resolved by WebpiecesFactory. It receives RouteBuilder via constructor injection.\n */\n@provideSingleton()\n@injectable()\nexport class WebpiecesServerImpl implements WebpiecesServer {\n private webpiecesContainer!: Container;\n\n /**\n * Application container: User's application bindings.\n * This is a child container of webpiecesContainer, so it can access\n * framework bindings while keeping app bindings separate.\n */\n private appContainer!: Container;\n\n private initialized = false;\n private app?: Express;\n private server?: ReturnType<Express['listen']>;\n private port: number = 8200;\n\n constructor(\n @inject(WEBAPP_META_TOKEN) private meta: WebAppMeta,\n @inject(RouteBuilderImpl) private routeBuilder: RouteBuilderImpl,\n @inject(WebpiecesMiddleware) private middleware: WebpiecesMiddleware,\n ) {}\n\n /**\n * Initialize the server asynchronously.\n * This is called by WebpiecesFactory.create() after resolving this class from DI.\n * This method is internal and not exposed on the WebpiecesServer interface.\n *\n * @param webpiecesContainer - The framework container\n * @param meta - User-provided WebAppMeta with DI modules and routes\n * @param appOverrides - Optional ContainerModule for app test overrides (loaded LAST)\n */\n async initialize(\n webpiecesContainer: Container,\n appOverrides?: ContainerModule\n ): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.webpiecesContainer = webpiecesContainer;\n\n // Create application container as child of framework container\n this.appContainer = new Container({ parent: this.webpiecesContainer });\n\n // Set container on RouteBuilder (late binding - appContainer didn't exist in constructor)\n this.routeBuilder.setContainer(this.appContainer);\n\n // 1. Load DI modules asynchronously\n await this.loadDIModules(appOverrides);\n\n // 2. Register routes and filters\n this.registerRoutes();\n\n this.initialized = true;\n }\n\n /**\n * Load DI modules from WebAppMeta.\n *\n * Currently, all user modules are loaded into the application container.\n * In the future, we could separate:\n * - WebPieces framework modules -> webpiecesContainer\n * - Application modules -> appContainer\n *\n * For now, everything goes into appContainer which has access to webpiecesContainer.\n *\n * @param appOverrides - Optional ContainerModule for app test overrides (loaded LAST to override bindings)\n */\n private async loadDIModules(appOverrides?: ContainerModule): Promise<void> {\n const modules = this.meta.getDIModules();\n\n // Load buildProviderModule to auto-scan for @provideSingleton decorators\n await this.appContainer.load(buildProviderModule());\n\n // Load all modules into application container\n // (webpiecesContainer is currently empty, reserved for future framework bindings)\n for (const module of modules) {\n await this.appContainer.load(module);\n }\n\n // Load appOverrides LAST so they can override existing bindings\n if (appOverrides) {\n await this.appContainer.load(appOverrides);\n }\n }\n\n /**\n * Register routes from WebAppMeta.\n *\n * Creates an explicit RouteBuilderImpl instead of an anonymous object.\n * This improves:\n * - Traceability: Can Cmd+Click on addRoute to see implementation\n * - Debugging: Explicit class shows up in stack traces\n * - Understanding: Clear class name vs anonymous object\n */\n private registerRoutes(): void {\n const routeConfigs = this.meta.getRoutes();\n\n // Configure routes using the explicit RouteBuilder\n for (const routeConfig of routeConfigs) {\n routeConfig.configure(this.routeBuilder);\n }\n }\n\n /**\n * Start the HTTP server with Express.\n * Returns a Promise that resolves when the server is listening,\n * or rejects if the server fails to start.\n *\n * @param port - The port to listen on (default: 8080)\n * @returns Promise that resolves when server is ready\n */\n async start(port: number = 8200, testMode?: boolean): Promise<void> {\n if (!this.initialized) {\n throw new Error('Server not initialized. Call initialize() before start().');\n }\n\n this.port = port;\n\n if(testMode) {\n //In testMode, we eliminate express ENTIRELY and use\n //Router, method filters and controllers so that we can test full stack\n return;\n }\n\n // Create Express app\n this.app = express();\n\n // Layer 1: Global Error Handler (OUTERMOST - runs FIRST)\n // Catches all unhandled errors and returns HTML 500 page\n this.app.use(this.middleware.globalErrorHandler.bind(this.middleware));\n\n // Layer 2: CORS for localhost development\n this.app.use(this.middleware.corsForLocalhost());\n\n // Layer 3: Request/Response Logging\n this.app.use(this.middleware.logNextLayer.bind(this.middleware));\n\n // Register routes\n const routeCount = this.registerExpressRoutes();\n\n // Start listening - wrap in Promise\n const promise = new Promise<void>((resolve, reject) => {\n this.server = this.app!.listen(this.port, (error?: Error) => {\n if (error) {\n console.error(`[WebpiecesServer] Failed to start server:`, error);\n reject(error);\n return;\n }\n console.log(`[WebpiecesServer] Server listening on http://localhost:${this.port}`);\n console.log(`[WebpiecesServer] Registered ${routeCount} routes`);\n resolve();\n });\n });\n\n await promise;\n }\n\n /**\n * Register Express routes - the SINGLE loop over routes.\n * For each route: createHandler (sets up filter chain) → wrapExpress → registerHandler.\n *\n * @returns Number of routes registered\n */\n private registerExpressRoutes(): number {\n if (!this.app) {\n throw new Error('Express app not initialized');\n }\n\n const routes = this.routeBuilder.getRoutes();\n let count = 0;\n\n for (const routeWithMeta of routes) {\n const service = this.routeBuilder.createRouteHandler(routeWithMeta);\n const routeMeta = routeWithMeta.definition.routeMeta;\n\n // Create ExpressWrapper directly (handles full request/response cycle)\n const wrapper = this.middleware.createExpressWrapper(service, routeMeta);\n\n this.registerHandler(\n routeMeta.httpMethod,\n routeMeta.path,\n wrapper.execute.bind(wrapper),\n );\n count++;\n }\n\n return count;\n }\n\n registerHandler(httpMethod: string, path: string, expressHandler: ExpressRouteHandler) {\n if (!this.app) {\n throw new Error('Express app not initialized');\n }\n\n switch (httpMethod.toLowerCase()) {\n case 'get':\n this.app.get(path, expressHandler);\n break;\n case 'post':\n this.app.post(path, expressHandler);\n break;\n case 'put':\n this.app.put(path, expressHandler);\n break;\n case 'delete':\n this.app.delete(path, expressHandler);\n break;\n case 'patch':\n this.app.patch(path, expressHandler);\n break;\n default:\n console.warn(`[WebpiecesServer] Unknown HTTP method: ${httpMethod}`);\n }\n }\n\n /**\n * Stop the HTTP server.\n * Returns a Promise that resolves when the server is stopped,\n * or rejects if there's an error stopping the server.\n *\n * @returns Promise that resolves when server is stopped\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n return new Promise<void>((resolve, reject) => {\n this.server!.close((err?: Error) => {\n if (err) {\n console.error('[WebpiecesServer] Error stopping server:', err);\n reject(err);\n return;\n }\n console.log('[WebpiecesServer] Server stopped');\n resolve();\n });\n });\n }\n\n /**\n * Get the application DI container.\n *\n * Useful for testing to verify state or access services directly.\n *\n * @returns The application Container\n */\n getContainer(): Container {\n return this.appContainer;\n }\n\n /**\n * Create an API client proxy for testing.\n *\n * This creates a client that routes calls through the full filter chain\n * and controller, but WITHOUT any HTTP overhead. Perfect for testing!\n *\n * The client uses the ApiPrototype class to discover routes via decorators,\n * then creates pre-configured invoker functions for each API method.\n *\n * IMPORTANT: This loops over the API methods (from decorators), NOT all routes.\n * For each API method, it sets up the filter chain ONCE during proxy creation,\n * so subsequent calls reuse the same filter chain (efficient!).\n *\n * @param apiPrototype - The API prototype class with routing decorators (can be abstract)\n * @returns A proxy that implements the API interface\n *\n * Example:\n * ```typescript\n * const saveApi = server.createApiClient<SaveApi>(SaveApi);\n * const response = await saveApi.save(request);\n * ```\n */\n createApiClient<T>(apiPrototype: abstract new (...args: any[]) => T): T {\n if (!this.initialized) {\n throw new Error('Server not initialized. Call initialize() before createApiClient().');\n }\n\n // Get endpoints from the API prototype using @ApiPath/@Endpoint decorators\n const basePath = getApiPath(apiPrototype) || '';\n const endpoints = getEndpoints(apiPrototype) || {};\n\n // Create proxy object\n const proxy: Record<string, unknown> = {};\n\n // Loop over API endpoints and create proxy functions\n for (const [methodName, endpointPath] of Object.entries(endpoints)) {\n const httpMethod = 'POST';\n const path = basePath + endpointPath;\n\n const authMeta = getAuthMeta(apiPrototype, methodName);\n const routeMeta = new RouteMetadata(httpMethod, path, methodName, apiPrototype.name, authMeta);\n\n // Create invoker service ONCE (sets up filter chain once, not on every call!)\n const service = this.routeBuilder.createRouteInvoker(httpMethod, path);\n\n // Proxy method creates MethodMeta and calls the pre-configured service\n // IMPORTANT: Tests MUST wrap calls in RequestContext.run() themselves\n // This forces explicit context setup in tests, matching production behavior\n proxy[methodName] = async (requestDto: unknown): Promise<unknown> => {\n // Verify we're inside an active RequestContext\n // This helps test authors know they need to wrap their test in RequestContext.run()\n if (!RequestContext.isActive()) {\n //Many devs may not activate headers\n return RequestContext.run(async () => {\n return await this.runMethod(routeMeta, requestDto, service);\n });\n }\n return await this.runMethod(routeMeta, requestDto, service);\n };\n }\n\n return proxy as T;\n }\n\n private async runMethod(routeMeta: RouteMetadata, requestDto: unknown, service: Service<MethodMeta, WpResponse<unknown>>) {\n // Create MethodMeta without headers (test mode - no HTTP involved)\n // requestHeaders is optional, so we can omit it\n const meta = new MethodMeta(routeMeta, undefined, requestDto);\n const responseWrapper = await service.invoke(meta);\n return responseWrapper.response;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WebpiecesServerImpl.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/WebpiecesServerImpl.ts"],"names":[],"mappings":"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","sourcesContent":["import express, {Express} from 'express';\nimport {Container, ContainerModule, inject, injectable} from 'inversify';\nimport {buildProviderModule} from '@inversifyjs/binding-decorators';\nimport {\n provideSingleton,\n RouteBuilderImpl,\n WebAppMeta,\n WEBAPP_META_TOKEN,\n} from '@webpieces/http-routing';\nimport {WebpiecesServer} from './WebpiecesServer';\nimport {WebpiecesMiddleware} from './WebpiecesMiddleware';\nimport {WebpiecesRouteCreator} from './WebpiecesRouteCreator';\nimport {InProcessApiClientFactory} from './InProcessApiClientFactory';\n\n/**\n * WebpiecesServerImpl - Internal server implementation.\n *\n * This class implements the WebpiecesServer interface and contains\n * all the actual server logic. It is created by WebpiecesFactory.create().\n *\n * This class uses a two-container pattern similar to Java WebPieces:\n * 1. webpiecesContainer: Core WebPieces framework bindings\n * 2. appContainer: User's application bindings (child of webpiecesContainer)\n *\n * This separation allows:\n * - Clean separation of concerns\n * - Better testability\n * - Ability to override framework bindings in tests\n *\n * The server:\n * 1. Initializes both DI containers from WebAppMeta.getDIModules()\n * 2. Registers routes using explicit RouteBuilderImpl\n * 3. Creates filter chains\n * 4. Supports both HTTP server mode and testing mode (no HTTP)\n *\n * DI Pattern: This class is registered in webpiecesContainer via @provideSingleton()\n * and resolved by WebpiecesFactory. It receives RouteBuilder via constructor injection.\n */\n@provideSingleton()\n@injectable()\nexport class WebpiecesServerImpl implements WebpiecesServer {\n private webpiecesContainer!: Container;\n\n /**\n * Application container: User's application bindings.\n * This is a child container of webpiecesContainer, so it can access\n * framework bindings while keeping app bindings separate.\n */\n private appContainer!: Container;\n\n private initialized = false;\n private app?: Express;\n private server?: ReturnType<Express['listen']>;\n private port: number = 8200;\n\n constructor(\n @inject(WEBAPP_META_TOKEN) private meta: WebAppMeta,\n @inject(RouteBuilderImpl) private routeBuilder: RouteBuilderImpl,\n @inject(WebpiecesMiddleware) private middleware: WebpiecesMiddleware,\n ) {}\n\n /**\n * Initialize the server asynchronously.\n * This is called by WebpiecesFactory.create() after resolving this class from DI.\n * This method is internal and not exposed on the WebpiecesServer interface.\n *\n * @param webpiecesContainer - The framework container\n * @param meta - User-provided WebAppMeta with DI modules and routes\n * @param appOverrides - Optional ContainerModule for app test overrides (loaded LAST)\n */\n async initialize(\n webpiecesContainer: Container,\n appOverrides?: ContainerModule\n ): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.webpiecesContainer = webpiecesContainer;\n\n // Create application container as child of framework container\n this.appContainer = new Container({ parent: this.webpiecesContainer });\n\n // Set container on RouteBuilder (late binding - appContainer didn't exist in constructor)\n this.routeBuilder.setContainer(this.appContainer);\n\n // 1. Load DI modules asynchronously\n await this.loadDIModules(appOverrides);\n\n // 2. Register routes and filters\n this.registerRoutes();\n\n this.initialized = true;\n }\n\n /**\n * Load DI modules from WebAppMeta.\n *\n * Currently, all user modules are loaded into the application container.\n * In the future, we could separate:\n * - WebPieces framework modules -> webpiecesContainer\n * - Application modules -> appContainer\n *\n * For now, everything goes into appContainer which has access to webpiecesContainer.\n *\n * @param appOverrides - Optional ContainerModule for app test overrides (loaded LAST to override bindings)\n */\n private async loadDIModules(appOverrides?: ContainerModule): Promise<void> {\n const modules = this.meta.getDIModules();\n\n // Load buildProviderModule to auto-scan for @provideSingleton decorators\n await this.appContainer.load(buildProviderModule());\n\n // Load all modules into application container\n // (webpiecesContainer is currently empty, reserved for future framework bindings)\n for (const module of modules) {\n await this.appContainer.load(module);\n }\n\n // Load appOverrides LAST so they can override existing bindings\n if (appOverrides) {\n await this.appContainer.load(appOverrides);\n }\n }\n\n /**\n * Register routes from WebAppMeta.\n *\n * Creates an explicit RouteBuilderImpl instead of an anonymous object.\n * This improves:\n * - Traceability: Can Cmd+Click on addRoute to see implementation\n * - Debugging: Explicit class shows up in stack traces\n * - Understanding: Clear class name vs anonymous object\n */\n private registerRoutes(): void {\n const routeConfigs = this.meta.getRoutes();\n\n // Configure routes using the explicit RouteBuilder\n for (const routeConfig of routeConfigs) {\n routeConfig.configure(this.routeBuilder);\n }\n }\n\n /**\n * Start the HTTP server with Express.\n * Returns a Promise that resolves when the server is listening,\n * or rejects if the server fails to start.\n *\n * @param port - The port to listen on (default: 8080)\n * @returns Promise that resolves when server is ready\n */\n async start(port: number = 8200, testMode?: boolean): Promise<void> {\n if (!this.initialized) {\n throw new Error('Server not initialized. Call initialize() before start().');\n }\n\n this.port = port;\n\n if(testMode) {\n //In testMode, we eliminate express ENTIRELY and use\n //Router, method filters and controllers so that we can test full stack\n return;\n }\n\n // Create Express app\n this.app = express();\n\n // Layer 1: Global Error Handler (OUTERMOST - runs FIRST)\n // Catches all unhandled errors and returns HTML 500 page\n this.app.use(this.middleware.globalErrorHandler.bind(this.middleware));\n\n // Layer 2: CORS for localhost development\n this.app.use(this.middleware.corsForLocalhost());\n\n // Layer 3: Request/Response Logging\n this.app.use(this.middleware.logNextLayer.bind(this.middleware));\n\n // Register routes via the shared adapter (same code path as the\n // embeddable WebpiecesRouteCreator used by legacy Express apps)\n const routeCreator = new WebpiecesRouteCreator(\n this.app,\n this.appContainer,\n this.routeBuilder,\n this.middleware,\n );\n const routeCount = routeCreator.mountRegisteredRoutes();\n\n // Start listening - wrap in Promise\n const promise = new Promise<void>((resolve, reject) => {\n this.server = this.app!.listen(this.port, (error?: Error) => {\n if (error) {\n console.error(`[WebpiecesServer] Failed to start server:`, error);\n reject(error);\n return;\n }\n console.log(`[WebpiecesServer] Server listening on http://localhost:${this.port}`);\n console.log(`[WebpiecesServer] Registered ${routeCount} routes`);\n resolve();\n });\n });\n\n await promise;\n }\n\n /**\n * Stop the HTTP server.\n * Returns a Promise that resolves when the server is stopped,\n * or rejects if there's an error stopping the server.\n *\n * @returns Promise that resolves when server is stopped\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n return new Promise<void>((resolve, reject) => {\n this.server!.close((err?: Error) => {\n if (err) {\n console.error('[WebpiecesServer] Error stopping server:', err);\n reject(err);\n return;\n }\n console.log('[WebpiecesServer] Server stopped');\n resolve();\n });\n });\n }\n\n /**\n * Get the application DI container.\n *\n * Useful for testing to verify state or access services directly.\n *\n * @returns The application Container\n */\n getContainer(): Container {\n return this.appContainer;\n }\n\n /**\n * Create an API client proxy for testing.\n *\n * This creates a client that routes calls through the full filter chain\n * and controller, but WITHOUT any HTTP overhead. Perfect for testing!\n *\n * The client uses the ApiPrototype class to discover routes via decorators,\n * then creates pre-configured invoker functions for each API method.\n *\n * IMPORTANT: This loops over the API methods (from decorators), NOT all routes.\n * For each API method, it sets up the filter chain ONCE during proxy creation,\n * so subsequent calls reuse the same filter chain (efficient!).\n *\n * @param apiPrototype - The API prototype class with routing decorators (can be abstract)\n * @returns A proxy that implements the API interface\n *\n * Example:\n * ```typescript\n * const saveApi = server.createApiClient<SaveApi>(SaveApi);\n * const response = await saveApi.save(request);\n * ```\n */\n // webpieces-disable no-any-unknown -- abstract constructor signature requires any[] args\n createApiClient<T>(apiPrototype: abstract new (...args: any[]) => T): T {\n if (!this.initialized) {\n throw new Error('Server not initialized. Call initialize() before createApiClient().');\n }\n\n // Delegates to the shared factory (same code path as WebpiecesRouteCreator.createApiClient)\n if (!this.clientFactory) {\n this.clientFactory = new InProcessApiClientFactory(this.routeBuilder);\n }\n return this.clientFactory.createApiClient(apiPrototype);\n }\n\n private clientFactory?: InProcessApiClientFactory;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MethodMeta } from '@webpieces/http-routing';
|
|
2
2
|
import { Filter, WpResponse, Service } from '@webpieces/http-filters';
|
|
3
|
-
import {
|
|
3
|
+
import { HeaderRegistry } from '@webpieces/http-api';
|
|
4
4
|
/**
|
|
5
5
|
* ContextFilter - Transfers platform headers and stores request metadata in RequestContext.
|
|
6
6
|
* Priority: 2000 (executes first in filter chain)
|
|
@@ -21,8 +21,8 @@ import { PlatformHeadersExtension, HeaderMethods } from '@webpieces/http-api';
|
|
|
21
21
|
* 7. Context auto-clears when RequestContext.run() completes
|
|
22
22
|
*/
|
|
23
23
|
export declare class ContextFilter extends Filter<MethodMeta, WpResponse<unknown>> {
|
|
24
|
-
private
|
|
25
|
-
constructor(
|
|
24
|
+
private transferredHeaders;
|
|
25
|
+
constructor(registry: HeaderRegistry);
|
|
26
26
|
filter(meta: MethodMeta, nextFilter: Service<MethodMeta, WpResponse<unknown>>): Promise<WpResponse<unknown>>;
|
|
27
27
|
/**
|
|
28
28
|
* Transfer platform headers from MethodMeta.requestHeaders to RequestContext.
|
|
@@ -29,17 +29,13 @@ const ContextKeys_1 = require("../headers/ContextKeys");
|
|
|
29
29
|
* 7. Context auto-clears when RequestContext.run() completes
|
|
30
30
|
*/
|
|
31
31
|
let ContextFilter = class ContextFilter extends http_filters_1.Filter {
|
|
32
|
-
|
|
33
|
-
constructor(
|
|
32
|
+
transferredHeaders;
|
|
33
|
+
constructor(registry) {
|
|
34
34
|
super();
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
// Create HeaderMethods helper with flattened headers
|
|
41
|
-
this.headerMethods = headerMethods.findTransferHeaders(allHeaders);
|
|
42
|
-
console.log(`[ContextFilter] Collected ${allHeaders.length} platform headers from ${extensions.length} extensions`);
|
|
35
|
+
// The registry is the single source of truth (all modules' extensions,
|
|
36
|
+
// duplicate-validated at startup)
|
|
37
|
+
this.transferredHeaders = registry.getTransferredHeaders();
|
|
38
|
+
console.log(`[ContextFilter] Using ${registry.getHeaders().length} platform headers from HeaderRegistry (${this.transferredHeaders.length} transferred)`);
|
|
43
39
|
}
|
|
44
40
|
async filter(meta, nextFilter) {
|
|
45
41
|
// Transfer platform headers from MethodMeta.requestHeaders to RequestContext
|
|
@@ -63,7 +59,7 @@ let ContextFilter = class ContextFilter extends http_filters_1.Filter {
|
|
|
63
59
|
return;
|
|
64
60
|
}
|
|
65
61
|
// Transfer each header to RequestContext using RequestContext.putHeader()
|
|
66
|
-
for (const header of this.
|
|
62
|
+
for (const header of this.transferredHeaders) {
|
|
67
63
|
// Get values from requestHeaders (case-insensitive lookup)
|
|
68
64
|
const values = meta.requestHeaders.get(header.headerName.toLowerCase());
|
|
69
65
|
if (values && values.length > 0) {
|
|
@@ -98,9 +94,7 @@ exports.ContextFilter = ContextFilter;
|
|
|
98
94
|
exports.ContextFilter = ContextFilter = tslib_1.__decorate([
|
|
99
95
|
(0, http_routing_1.provideSingleton)(),
|
|
100
96
|
(0, inversify_1.injectable)(),
|
|
101
|
-
tslib_1.__param(0, (0, inversify_1.
|
|
102
|
-
tslib_1.
|
|
103
|
-
tslib_1.__param(1, (0, inversify_1.inject)(http_api_1.HeaderMethods)),
|
|
104
|
-
tslib_1.__metadata("design:paramtypes", [Array, http_api_1.HeaderMethods])
|
|
97
|
+
tslib_1.__param(0, (0, inversify_1.inject)(http_api_1.HeaderRegistry)),
|
|
98
|
+
tslib_1.__metadata("design:paramtypes", [http_api_1.HeaderRegistry])
|
|
105
99
|
], ContextFilter);
|
|
106
100
|
//# sourceMappingURL=ContextFilter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/filters/ContextFilter.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"ContextFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/filters/ContextFilter.ts"],"names":[],"mappings":";;;;AAAA,yCAA6C;AAC7C,0DAAuE;AACvE,0DAAyD;AACzD,0DAAsE;AACtE,kDAAqE;AACrE,0EAAqE;AACrE,wDAAmD;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AAGI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,qBAAuC;IAC9D,kBAAkB,CAAmB;IAE7C,YAC4B,QAAwB;QAEhD,KAAK,EAAE,CAAC;QAER,uEAAuE;QACvE,kCAAkC;QAClC,IAAI,CAAC,kBAAkB,GAAG,QAAQ,CAAC,qBAAqB,EAAE,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,0CAA0C,IAAI,CAAC,kBAAkB,CAAC,MAAM,eAAe,CAAC,CAAC;IAC9J,CAAC;IAED,KAAK,CAAC,MAAM,CACR,IAAgB,EAChB,UAAoD;QAEpD,6EAA6E;QAC7E,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAE3B,4EAA4E;QAC5E,6BAAc,CAAC,SAAS,CAAC,yBAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACxD,6BAAc,CAAC,SAAS,CAAC,yBAAW,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,6BAAc,CAAC,SAAS,CAAC,yBAAW,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAEnE,iCAAiC;QACjC,OAAO,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrC,0EAA0E;IAC9E,CAAC;IAED;;;OAGG;IACK,eAAe,CAAC,IAAgB;QACpC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACvB,4EAA4E;YAC5E,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,OAAO;QACX,CAAC;QAED,0EAA0E;QAC1E,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC3C,2DAA2D;YAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;YACxE,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,oEAAoE;gBACpE,6BAAc,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAChD,CAAC;QACL,CAAC;QAED,gFAAgF;QAChF,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAEhC,8DAA8D;QAC9D,IAAI,CAAC,eAAe,EAAE,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACK,eAAe;QACnB,IAAI,CAAC,6BAAc,CAAC,SAAS,CAAC,2CAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3C,6BAAc,CAAC,SAAS,CAAC,2CAAoB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACzE,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,iBAAiB;QACrB,OAAO,eAAe,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACtF,CAAC;CACJ,CAAA;AA9EY,sCAAa;wBAAb,aAAa;IAFzB,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;IAKJ,mBAAA,IAAA,kBAAM,EAAC,yBAAc,CAAC,CAAA;6CAAW,yBAAc;GAJ3C,aAAa,CA8EzB","sourcesContent":["import {inject, injectable} from 'inversify';\nimport { provideSingleton, MethodMeta } from '@webpieces/http-routing';\nimport { RequestContext } from '@webpieces/core-context';\nimport { Filter, WpResponse, Service } from '@webpieces/http-filters';\nimport { PlatformHeader, HeaderRegistry } from '@webpieces/http-api';\nimport {WebpiecesCoreHeaders} from \"../headers/WebpiecesCoreHeaders\";\nimport {ContextKeys} from \"../headers/ContextKeys\";\n\n/**\n * ContextFilter - Transfers platform headers and stores request metadata in RequestContext.\n * Priority: 2000 (executes first in filter chain)\n *\n * NEW: Now handles header transfer from RouterRequest to RequestContext\n * - Injects PlatformHeadersExtension instances via @multiInject (safe because filter created after modules load)\n * - Reads headers from RouterRequest (Express-independent)\n * - Transfers only headers marked with isWantTransferred=true\n * - Generates REQUEST_ID if not present\n *\n * RequestContext lifecycle:\n * 1. ExpressWrapper.execute() calls RequestContext.run() (establishes context)\n * 2. ExpressWrapper creates RouterReqResp and MethodMeta\n * 3. Filter chain executes, starting with ContextFilter\n * 4. ContextFilter transfers headers from RouterRequest to RequestContext\n * 5. ContextFilter stores metadata (METHOD_META, REQUEST_PATH, HTTP_METHOD)\n * 6. Downstream filters and controller can access headers + metadata\n * 7. Context auto-clears when RequestContext.run() completes\n */\n@provideSingleton()\n@injectable()\nexport class ContextFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n private transferredHeaders: PlatformHeader[];\n\n constructor(\n @inject(HeaderRegistry) registry: HeaderRegistry\n ) {\n super();\n\n // The registry is the single source of truth (all modules' extensions,\n // duplicate-validated at startup)\n this.transferredHeaders = registry.getTransferredHeaders();\n\n console.log(`[ContextFilter] Using ${registry.getHeaders().length} platform headers from HeaderRegistry (${this.transferredHeaders.length} transferred)`);\n }\n\n async filter(\n meta: MethodMeta,\n nextFilter: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n // Transfer platform headers from MethodMeta.requestHeaders to RequestContext\n this.transferHeaders(meta);\n\n // Store request metadata in context for other filters/controllers to access\n RequestContext.putHeader(ContextKeys.METHOD_META, meta);\n RequestContext.putHeader(ContextKeys.REQUEST_PATH, meta.path);\n RequestContext.putHeader(ContextKeys.HTTP_METHOD, meta.httpMethod);\n\n // Execute next filter/controller\n return await nextFilter.invoke(meta);\n // RequestContext is auto-cleared by ExpressWrapper when request completes\n }\n\n /**\n * Transfer platform headers from MethodMeta.requestHeaders to RequestContext.\n * Uses HeaderMethods.findTransferHeaders() to filter by isWantTransferred=true.\n */\n private transferHeaders(meta: MethodMeta): void {\n if (!meta.requestHeaders) {\n // No headers in test mode (createApiClient creates context but not headers)\n this.ensureRequestId();\n return;\n }\n\n // Transfer each header to RequestContext using RequestContext.putHeader()\n for (const header of this.transferredHeaders) {\n // Get values from requestHeaders (case-insensitive lookup)\n const values = meta.requestHeaders.get(header.headerName.toLowerCase());\n if (values && values.length > 0) {\n // Use RequestContext.putHeader() which calls header.getHeaderName()\n RequestContext.putHeader(header, values[0]);\n }\n }\n\n // Clear request headers from MethodMeta - MUST FORCE USAGE of RequestContext!!!\n meta.requestHeaders = undefined;\n\n // Generate REQUEST_ID if not present (first service in chain)\n this.ensureRequestId();\n }\n\n /**\n * Ensure REQUEST_ID is set in RequestContext.\n * Generates one if not present.\n */\n private ensureRequestId(): void {\n if (!RequestContext.hasHeader(WebpiecesCoreHeaders.REQUEST_ID)) {\n const requestId = this.generateRequestId();\n RequestContext.putHeader(WebpiecesCoreHeaders.REQUEST_ID, requestId);\n }\n }\n\n /**\n * Generate a unique request ID.\n * Format: req-{timestamp}-{random}\n */\n private generateRequestId(): string {\n return `svrGenReqId-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n }\n}\n\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MethodMeta } from '@webpieces/http-routing';
|
|
2
2
|
import { Filter, WpResponse, Service } from '@webpieces/http-filters';
|
|
3
|
-
import {
|
|
3
|
+
import { HeaderMethods, HeaderRegistry } from '@webpieces/http-api';
|
|
4
4
|
/**
|
|
5
5
|
* LogApiFilter - Structured API logging for all requests/responses.
|
|
6
6
|
* Priority: 1800 (after ContextFilter at 2000, before custom filters)
|
|
@@ -21,6 +21,6 @@ export declare class LogApiFilter extends Filter<MethodMeta, WpResponse<unknown>
|
|
|
21
21
|
private headerMethods;
|
|
22
22
|
private logApiCall;
|
|
23
23
|
private allHeaders;
|
|
24
|
-
constructor(
|
|
24
|
+
constructor(registry: HeaderRegistry, headerMethods: HeaderMethods);
|
|
25
25
|
filter(meta: MethodMeta, nextFilter: Service<MethodMeta, WpResponse<unknown>>): Promise<WpResponse<unknown>>;
|
|
26
26
|
}
|
|
@@ -26,15 +26,13 @@ let LogApiFilter = class LogApiFilter extends http_filters_1.Filter {
|
|
|
26
26
|
headerMethods;
|
|
27
27
|
logApiCall;
|
|
28
28
|
allHeaders;
|
|
29
|
-
constructor(
|
|
29
|
+
constructor(registry, headerMethods) {
|
|
30
30
|
super();
|
|
31
31
|
this.headerMethods = headerMethods;
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
console.log(`[LogApiFilter] Collected ${this.allHeaders.length} platform headers from ${extensions.length} extensions`);
|
|
32
|
+
// The registry is the single source of truth (all modules' extensions,
|
|
33
|
+
// duplicate-validated at startup). Log map keys use loggerMdcKey when set.
|
|
34
|
+
this.allHeaders = registry.getHeaders();
|
|
35
|
+
console.log(`[LogApiFilter] Using ${this.allHeaders.length} platform headers from HeaderRegistry`);
|
|
38
36
|
this.logApiCall = new http_api_1.LogApiCall();
|
|
39
37
|
}
|
|
40
38
|
async filter(meta, nextFilter) {
|
|
@@ -54,9 +52,9 @@ exports.LogApiFilter = LogApiFilter;
|
|
|
54
52
|
exports.LogApiFilter = LogApiFilter = tslib_1.__decorate([
|
|
55
53
|
(0, http_routing_1.provideSingleton)(),
|
|
56
54
|
(0, inversify_1.injectable)(),
|
|
57
|
-
tslib_1.__param(0, (0, inversify_1.
|
|
58
|
-
tslib_1.__param(0, (0, inversify_1.optional)()),
|
|
55
|
+
tslib_1.__param(0, (0, inversify_1.inject)(http_api_1.HeaderRegistry)),
|
|
59
56
|
tslib_1.__param(1, (0, inversify_1.inject)(http_api_1.HeaderMethods)),
|
|
60
|
-
tslib_1.__metadata("design:paramtypes", [
|
|
57
|
+
tslib_1.__metadata("design:paramtypes", [http_api_1.HeaderRegistry,
|
|
58
|
+
http_api_1.HeaderMethods])
|
|
61
59
|
], LogApiFilter);
|
|
62
60
|
//# sourceMappingURL=LogApiFilter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogApiFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/filters/LogApiFilter.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"LogApiFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/filters/LogApiFilter.ts"],"names":[],"mappings":";;;;AAAA,yCAA6C;AAC7C,0DAA2F;AAC3F,0DAAsE;AACtE,kDAK6B;AAE7B;;;;;;;;;;;;;;;GAeG;AAGI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,qBAAuC;IAMlC;IAL3B,UAAU,CAAa;IACvB,UAAU,CAAmB;IAErC,YAC4B,QAAwB,EACjB,aAA4B;QAE3D,KAAK,EAAE,CAAC;QAFuB,kBAAa,GAAb,aAAa,CAAe;QAI3D,uEAAuE;QACvE,2EAA2E;QAC3E,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;QAExC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,UAAU,CAAC,MAAM,uCAAuC,CAAC,CAAC;QAEnG,IAAI,CAAC,UAAU,GAAG,IAAI,qBAAU,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,MAAM,CACR,IAAgB,EAChB,UAAoD;QAEpD,0FAA0F;QAC1F,MAAM,aAAa,GAAG,IAAI,mCAAoB,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAEzF,+DAA+D;QAC/D,MAAM,MAAM,GAAG,KAAK,IAAsB,EAAE;YACxC,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACjD,OAAO,UAAU,CAAC,QAAQ,CAAC;QAC/B,CAAC,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACxG,OAAO,IAAI,yBAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;CACJ,CAAA;AApCY,oCAAY;uBAAZ,YAAY;IAFxB,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;IAMJ,mBAAA,IAAA,kBAAM,EAAC,yBAAc,CAAC,CAAA;IACtB,mBAAA,IAAA,kBAAM,EAAC,wBAAa,CAAC,CAAA;6CADY,yBAAc;QACF,wBAAa;GANtD,YAAY,CAoCxB","sourcesContent":["import {inject, injectable} from 'inversify';\nimport {provideSingleton, MethodMeta, RequestContextReader} from '@webpieces/http-routing';\nimport { Filter, WpResponse, Service } from '@webpieces/http-filters';\nimport {\n PlatformHeader,\n HeaderMethods,\n HeaderRegistry,\n LogApiCall,\n} from '@webpieces/http-api';\n\n/**\n * LogApiFilter - Structured API logging for all requests/responses.\n * Priority: 1800 (after ContextFilter at 2000, before custom filters)\n *\n * Logging patterns (via LogApiCall):\n * - [API-SVR-req] Class.method /url request={...} headers={...}\n * - [API-SVR-resp-SUCCESS] Class.method response={...}\n * - [API-SVR-resp-FAIL] Class.method error=... (server errors: 500, 502, 504)\n * - [API-SVR-resp-OTHER] Class.method errorType=... (user errors: 400, 401, 403, 404, 266)\n *\n * Headers are read from RequestContext (NOT from meta.requestHeaders which is undefined\n * after ContextFilter runs at priority 2000).\n *\n * User errors (HttpBadRequestError, etc.) are logged as OTHER, not FAIL,\n * because they are expected behavior from the server's perspective.\n */\n@provideSingleton()\n@injectable()\nexport class LogApiFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n private logApiCall: LogApiCall;\n private allHeaders: PlatformHeader[];\n\n constructor(\n @inject(HeaderRegistry) registry: HeaderRegistry,\n @inject(HeaderMethods) private headerMethods: HeaderMethods\n ) {\n super();\n\n // The registry is the single source of truth (all modules' extensions,\n // duplicate-validated at startup). Log map keys use loggerMdcKey when set.\n this.allHeaders = registry.getHeaders();\n\n console.log(`[LogApiFilter] Using ${this.allHeaders.length} platform headers from HeaderRegistry`);\n\n this.logApiCall = new LogApiCall();\n }\n\n async filter(\n meta: MethodMeta,\n nextFilter: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n // Build header map from RequestContext (headers are already transferred by ContextFilter)\n const contextReader = new RequestContextReader();\n const headers = this.headerMethods.buildSecureMapForLogs(this.allHeaders, contextReader);\n\n // Wrap nextFilter.invoke in a method that returns the response\n const method = async (): Promise<unknown> => {\n const wpResponse = await nextFilter.invoke(meta);\n return wpResponse.response;\n };\n\n const response = await this.logApiCall.execute(\"SVR\", meta.routeMeta, meta.requestDto, headers, method);\n return new WpResponse(response);\n }\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MethodMeta, WebpiecesConfig } from '@webpieces/http-routing';
|
|
2
|
+
import { Filter, WpResponse, Service } from '@webpieces/http-filters';
|
|
3
|
+
import { HeaderRegistry } from '@webpieces/http-api';
|
|
4
|
+
/**
|
|
5
|
+
* RecordingFilter - Records a request as a replayable test case (port of Java
|
|
6
|
+
* RecordingFilter).
|
|
7
|
+
*
|
|
8
|
+
* Suggested priority: 1850 (after ContextFilter 2000 so the RECORDING header
|
|
9
|
+
* has been transferred to the context, after AuthFilter 1900 so only real
|
|
10
|
+
* authorized flows are recorded, before LogApiFilter 1800).
|
|
11
|
+
*
|
|
12
|
+
* Activates when WebpiecesConfig.recordingAlwaysOn is set OR the request
|
|
13
|
+
* carries WebpiecesCoreHeaders.RECORDING (x-webpieces-recording). While
|
|
14
|
+
* active, a TestCaseRecorderImpl travels in the RequestContext under
|
|
15
|
+
* RecorderKeys.RECORDER; the http-client proxy and recordable() wrappers add
|
|
16
|
+
* every downstream call. On completion the fixture + generated spec are
|
|
17
|
+
* logged (and written to config.recordingDir when set).
|
|
18
|
+
*
|
|
19
|
+
* Recording NEVER alters the response - failures inside the recorder are
|
|
20
|
+
* caught and logged.
|
|
21
|
+
*/
|
|
22
|
+
export declare class RecordingFilter extends Filter<MethodMeta, WpResponse<unknown>> {
|
|
23
|
+
private config;
|
|
24
|
+
private registry;
|
|
25
|
+
private headerMethods;
|
|
26
|
+
constructor(config: WebpiecesConfig, registry: HeaderRegistry);
|
|
27
|
+
filter(meta: MethodMeta, nextFilter: Service<MethodMeta, WpResponse<unknown>>): Promise<WpResponse<unknown>>;
|
|
28
|
+
private isRecordingRequested;
|
|
29
|
+
private buildServerEndpoint;
|
|
30
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecordingFilter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const inversify_1 = require("inversify");
|
|
6
|
+
const http_routing_1 = require("@webpieces/http-routing");
|
|
7
|
+
const core_context_1 = require("@webpieces/core-context");
|
|
8
|
+
const http_filters_1 = require("@webpieces/http-filters");
|
|
9
|
+
const http_api_1 = require("@webpieces/http-api");
|
|
10
|
+
const TestCaseRecorderImpl_1 = require("../recorder/TestCaseRecorderImpl");
|
|
11
|
+
/**
|
|
12
|
+
* RecordingFilter - Records a request as a replayable test case (port of Java
|
|
13
|
+
* RecordingFilter).
|
|
14
|
+
*
|
|
15
|
+
* Suggested priority: 1850 (after ContextFilter 2000 so the RECORDING header
|
|
16
|
+
* has been transferred to the context, after AuthFilter 1900 so only real
|
|
17
|
+
* authorized flows are recorded, before LogApiFilter 1800).
|
|
18
|
+
*
|
|
19
|
+
* Activates when WebpiecesConfig.recordingAlwaysOn is set OR the request
|
|
20
|
+
* carries WebpiecesCoreHeaders.RECORDING (x-webpieces-recording). While
|
|
21
|
+
* active, a TestCaseRecorderImpl travels in the RequestContext under
|
|
22
|
+
* RecorderKeys.RECORDER; the http-client proxy and recordable() wrappers add
|
|
23
|
+
* every downstream call. On completion the fixture + generated spec are
|
|
24
|
+
* logged (and written to config.recordingDir when set).
|
|
25
|
+
*
|
|
26
|
+
* Recording NEVER alters the response - failures inside the recorder are
|
|
27
|
+
* caught and logged.
|
|
28
|
+
*/
|
|
29
|
+
let RecordingFilter = class RecordingFilter extends http_filters_1.Filter {
|
|
30
|
+
config;
|
|
31
|
+
registry;
|
|
32
|
+
headerMethods = new http_api_1.HeaderMethods();
|
|
33
|
+
constructor(config, registry) {
|
|
34
|
+
super();
|
|
35
|
+
this.config = config;
|
|
36
|
+
this.registry = registry;
|
|
37
|
+
}
|
|
38
|
+
// webpieces-disable no-any-unknown -- Filter generic params use unknown for response type flexibility
|
|
39
|
+
async filter(meta, nextFilter) {
|
|
40
|
+
if (!this.isRecordingRequested()) {
|
|
41
|
+
return await nextFilter.invoke(meta);
|
|
42
|
+
}
|
|
43
|
+
const recorder = new TestCaseRecorderImpl_1.TestCaseRecorderImpl();
|
|
44
|
+
core_context_1.RequestContext.putHeader(http_api_1.RecorderKeys.RECORDER, recorder);
|
|
45
|
+
const serverEndpoint = this.buildServerEndpoint(meta);
|
|
46
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- capture failure into the recording, then rethrow unchanged
|
|
47
|
+
try {
|
|
48
|
+
const response = await nextFilter.invoke(meta);
|
|
49
|
+
serverEndpoint.successResponse = response.response;
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const error = (0, http_api_1.toError)(err);
|
|
54
|
+
serverEndpoint.failureResponse = new http_api_1.RecordedError(error.name, error.message);
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
core_context_1.RequestContext.remove(http_api_1.RecorderKeys.RECORDER.getHeaderName());
|
|
59
|
+
recorder.spitOutTestCase(serverEndpoint, this.config.recordingDir);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
isRecordingRequested() {
|
|
63
|
+
if (this.config.recordingAlwaysOn) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
// ContextFilter (priority 2000) already transferred the header into context
|
|
67
|
+
return core_context_1.RequestContext.hasHeader(http_api_1.WebpiecesCoreHeaders.RECORDING);
|
|
68
|
+
}
|
|
69
|
+
buildServerEndpoint(meta) {
|
|
70
|
+
// Masked snapshot of the magic context (secured values masked, MDC keys)
|
|
71
|
+
const logMap = this.headerMethods.buildSecureMapForLogs(this.registry.getHeaders(), new http_routing_1.RequestContextReader());
|
|
72
|
+
const ctxSnapshot = {};
|
|
73
|
+
for (const entry of logMap.entries()) {
|
|
74
|
+
ctxSnapshot[entry[0]] = entry[1];
|
|
75
|
+
}
|
|
76
|
+
const apiName = meta.routeMeta.controllerClassName ?? 'UnknownController';
|
|
77
|
+
return new http_api_1.RecordedEndpoint(apiName, meta.methodName, [meta.requestDto], ctxSnapshot);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
exports.RecordingFilter = RecordingFilter;
|
|
81
|
+
exports.RecordingFilter = RecordingFilter = tslib_1.__decorate([
|
|
82
|
+
(0, http_routing_1.provideSingleton)(),
|
|
83
|
+
(0, inversify_1.injectable)()
|
|
84
|
+
// webpieces-disable no-any-unknown -- Filter generic params use unknown for response type flexibility
|
|
85
|
+
,
|
|
86
|
+
tslib_1.__param(0, (0, inversify_1.inject)(http_routing_1.WEBPIECES_CONFIG_TOKEN)),
|
|
87
|
+
tslib_1.__param(1, (0, inversify_1.inject)(http_api_1.HeaderRegistry)),
|
|
88
|
+
tslib_1.__metadata("design:paramtypes", [http_routing_1.WebpiecesConfig,
|
|
89
|
+
http_api_1.HeaderRegistry])
|
|
90
|
+
], RecordingFilter);
|
|
91
|
+
//# sourceMappingURL=RecordingFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordingFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/filters/RecordingFilter.ts"],"names":[],"mappings":"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","sourcesContent":["import { inject, injectable } from 'inversify';\nimport {\n provideSingleton,\n MethodMeta,\n RequestContextReader,\n WebpiecesConfig,\n WEBPIECES_CONFIG_TOKEN,\n} from '@webpieces/http-routing';\nimport { RequestContext } from '@webpieces/core-context';\nimport { Filter, WpResponse, Service } from '@webpieces/http-filters';\nimport {\n HeaderMethods,\n HeaderRegistry,\n RecordedEndpoint,\n RecordedError,\n RecorderKeys,\n WebpiecesCoreHeaders,\n toError,\n} from '@webpieces/http-api';\nimport { TestCaseRecorderImpl } from '../recorder/TestCaseRecorderImpl';\n\n/**\n * RecordingFilter - Records a request as a replayable test case (port of Java\n * RecordingFilter).\n *\n * Suggested priority: 1850 (after ContextFilter 2000 so the RECORDING header\n * has been transferred to the context, after AuthFilter 1900 so only real\n * authorized flows are recorded, before LogApiFilter 1800).\n *\n * Activates when WebpiecesConfig.recordingAlwaysOn is set OR the request\n * carries WebpiecesCoreHeaders.RECORDING (x-webpieces-recording). While\n * active, a TestCaseRecorderImpl travels in the RequestContext under\n * RecorderKeys.RECORDER; the http-client proxy and recordable() wrappers add\n * every downstream call. On completion the fixture + generated spec are\n * logged (and written to config.recordingDir when set).\n *\n * Recording NEVER alters the response - failures inside the recorder are\n * caught and logged.\n */\n@provideSingleton()\n@injectable()\n// webpieces-disable no-any-unknown -- Filter generic params use unknown for response type flexibility\nexport class RecordingFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n private headerMethods = new HeaderMethods();\n\n constructor(\n @inject(WEBPIECES_CONFIG_TOKEN) private config: WebpiecesConfig,\n @inject(HeaderRegistry) private registry: HeaderRegistry,\n ) {\n super();\n }\n\n // webpieces-disable no-any-unknown -- Filter generic params use unknown for response type flexibility\n async filter(\n meta: MethodMeta,\n nextFilter: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n if (!this.isRecordingRequested()) {\n return await nextFilter.invoke(meta);\n }\n\n const recorder = new TestCaseRecorderImpl();\n RequestContext.putHeader(RecorderKeys.RECORDER, recorder);\n\n const serverEndpoint = this.buildServerEndpoint(meta);\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- capture failure into the recording, then rethrow unchanged\n try {\n const response = await nextFilter.invoke(meta);\n serverEndpoint.successResponse = response.response;\n return response;\n } catch (err: unknown) {\n const error = toError(err);\n serverEndpoint.failureResponse = new RecordedError(error.name, error.message);\n throw err;\n } finally {\n RequestContext.remove(RecorderKeys.RECORDER.getHeaderName());\n recorder.spitOutTestCase(serverEndpoint, this.config.recordingDir);\n }\n }\n\n private isRecordingRequested(): boolean {\n if (this.config.recordingAlwaysOn) {\n return true;\n }\n // ContextFilter (priority 2000) already transferred the header into context\n return RequestContext.hasHeader(WebpiecesCoreHeaders.RECORDING);\n }\n\n private buildServerEndpoint(meta: MethodMeta): RecordedEndpoint {\n // Masked snapshot of the magic context (secured values masked, MDC keys)\n const logMap = this.headerMethods.buildSecureMapForLogs(this.registry.getHeaders(), new RequestContextReader());\n const ctxSnapshot: Record<string, string> = {};\n for (const entry of logMap.entries()) {\n ctxSnapshot[entry[0]] = entry[1];\n }\n\n const apiName = meta.routeMeta.controllerClassName ?? 'UnknownController';\n return new RecordedEndpoint(apiName, meta.methodName, [meta.requestDto], ctxSnapshot);\n }\n}\n"]}
|
|
@@ -1,39 +1,6 @@
|
|
|
1
|
-
import { PlatformHeader } from '@webpieces/http-api';
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Request tracking across services
|
|
7
|
-
* - Distributed tracing
|
|
8
|
-
* - Request correlation
|
|
9
|
-
* - Metrics and monitoring
|
|
10
|
-
*
|
|
11
|
-
* Pattern inspired by Java MicroSvcHeader enum.
|
|
2
|
+
* WebpiecesCoreHeaders moved to @webpieces/http-api (browser-safe) so the
|
|
3
|
+
* http-client can reference REQUEST_ID/PREVIOUS_REQUEST_ID for request-id
|
|
4
|
+
* chaining. Re-exported here for backward compatibility with existing imports.
|
|
12
5
|
*/
|
|
13
|
-
export
|
|
14
|
-
/**
|
|
15
|
-
* Unique ID for this request.
|
|
16
|
-
* Generated by the server if not provided.
|
|
17
|
-
* Used for distributed tracing and log correlation.
|
|
18
|
-
*/
|
|
19
|
-
static readonly REQUEST_ID: PlatformHeader;
|
|
20
|
-
/**
|
|
21
|
-
* ID of the previous request in the call chain.
|
|
22
|
-
* When service A calls service B, B receives A's REQUEST_ID as PREVIOUS_REQUEST_ID.
|
|
23
|
-
* Used for building distributed trace trees.
|
|
24
|
-
*/
|
|
25
|
-
static readonly PREVIOUS_REQUEST_ID: PlatformHeader;
|
|
26
|
-
/**
|
|
27
|
-
* Correlation ID that spans multiple related requests.
|
|
28
|
-
* Typically set by the API gateway or first service in the chain.
|
|
29
|
-
* All services in the call chain use the same CORRELATION_ID.
|
|
30
|
-
*/
|
|
31
|
-
static readonly CORRELATION_ID: PlatformHeader;
|
|
32
|
-
/**
|
|
33
|
-
* Get all core headers as an array.
|
|
34
|
-
* Used by WebpiecesModule to bind headers to DI container.
|
|
35
|
-
*
|
|
36
|
-
* @returns Array of all core platform headers
|
|
37
|
-
*/
|
|
38
|
-
static getAllHeaders(): PlatformHeader[];
|
|
39
|
-
}
|
|
6
|
+
export { WebpiecesCoreHeaders } from '@webpieces/http-api';
|
|
@@ -1,54 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WebpiecesCoreHeaders = void 0;
|
|
4
|
-
const http_api_1 = require("@webpieces/http-api");
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - Request tracking across services
|
|
10
|
-
* - Distributed tracing
|
|
11
|
-
* - Request correlation
|
|
12
|
-
* - Metrics and monitoring
|
|
13
|
-
*
|
|
14
|
-
* Pattern inspired by Java MicroSvcHeader enum.
|
|
5
|
+
* WebpiecesCoreHeaders moved to @webpieces/http-api (browser-safe) so the
|
|
6
|
+
* http-client can reference REQUEST_ID/PREVIOUS_REQUEST_ID for request-id
|
|
7
|
+
* chaining. Re-exported here for backward compatibility with existing imports.
|
|
15
8
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* Unique ID for this request.
|
|
19
|
-
* Generated by the server if not provided.
|
|
20
|
-
* Used for distributed tracing and log correlation.
|
|
21
|
-
*/
|
|
22
|
-
static REQUEST_ID = new http_api_1.PlatformHeader('x-request-id', true, // transfer (propagate to downstream services)
|
|
23
|
-
false, // not secured (it's just an ID)
|
|
24
|
-
true // use for metrics dimensions
|
|
25
|
-
);
|
|
26
|
-
/**
|
|
27
|
-
* ID of the previous request in the call chain.
|
|
28
|
-
* When service A calls service B, B receives A's REQUEST_ID as PREVIOUS_REQUEST_ID.
|
|
29
|
-
* Used for building distributed trace trees.
|
|
30
|
-
*/
|
|
31
|
-
static PREVIOUS_REQUEST_ID = new http_api_1.PlatformHeader('x-previous-request-id', true, false, false);
|
|
32
|
-
/**
|
|
33
|
-
* Correlation ID that spans multiple related requests.
|
|
34
|
-
* Typically set by the API gateway or first service in the chain.
|
|
35
|
-
* All services in the call chain use the same CORRELATION_ID.
|
|
36
|
-
*/
|
|
37
|
-
static CORRELATION_ID = new http_api_1.PlatformHeader('x-correlation-id', true, false, true // use for metrics dimensions
|
|
38
|
-
);
|
|
39
|
-
/**
|
|
40
|
-
* Get all core headers as an array.
|
|
41
|
-
* Used by WebpiecesModule to bind headers to DI container.
|
|
42
|
-
*
|
|
43
|
-
* @returns Array of all core platform headers
|
|
44
|
-
*/
|
|
45
|
-
static getAllHeaders() {
|
|
46
|
-
return [
|
|
47
|
-
WebpiecesCoreHeaders.REQUEST_ID,
|
|
48
|
-
WebpiecesCoreHeaders.PREVIOUS_REQUEST_ID,
|
|
49
|
-
WebpiecesCoreHeaders.CORRELATION_ID,
|
|
50
|
-
];
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
exports.WebpiecesCoreHeaders = WebpiecesCoreHeaders;
|
|
9
|
+
var http_api_1 = require("@webpieces/http-api");
|
|
10
|
+
Object.defineProperty(exports, "WebpiecesCoreHeaders", { enumerable: true, get: function () { return http_api_1.WebpiecesCoreHeaders; } });
|
|
54
11
|
//# sourceMappingURL=WebpiecesCoreHeaders.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebpiecesCoreHeaders.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/headers/WebpiecesCoreHeaders.ts"],"names":[],"mappings":";;;AAAA
|
|
1
|
+
{"version":3,"file":"WebpiecesCoreHeaders.js","sourceRoot":"","sources":["../../../../../../packages/http/http-server/src/headers/WebpiecesCoreHeaders.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,gDAA2D;AAAlD,gHAAA,oBAAoB,OAAA","sourcesContent":["/**\n * WebpiecesCoreHeaders moved to @webpieces/http-api (browser-safe) so the\n * http-client can reference REQUEST_ID/PREVIOUS_REQUEST_ID for request-id\n * chaining. Re-exported here for backward compatibility with existing imports.\n */\nexport { WebpiecesCoreHeaders } from '@webpieces/http-api';\n"]}
|
package/src/index.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
export { WebpiecesServer } from './WebpiecesServer';
|
|
2
2
|
export { WebpiecesFactory } from './WebpiecesFactory';
|
|
3
3
|
export { WebpiecesMiddleware } from './WebpiecesMiddleware';
|
|
4
|
+
export { WebpiecesRouteCreator } from './WebpiecesRouteCreator';
|
|
5
|
+
export { InProcessApiClientFactory } from './InProcessApiClientFactory';
|
|
4
6
|
export { ContextFilter } from './filters/ContextFilter';
|
|
5
7
|
export { LogApiFilter } from './filters/LogApiFilter';
|
|
8
|
+
export { RecordingFilter } from './filters/RecordingFilter';
|
|
9
|
+
export { TestCaseRecorderImpl } from './recorder/TestCaseRecorderImpl';
|
|
10
|
+
export { SpecGenerator } from './recorder/SpecGenerator';
|
|
11
|
+
export { recordable } from './recorder/recordable';
|
|
6
12
|
export { WebpiecesModule } from './modules/WebpiecesModule';
|
|
7
13
|
export { WebpiecesCoreHeaders } from './headers/WebpiecesCoreHeaders';
|
|
8
|
-
export {
|
|
14
|
+
export { HeaderRegistry } from '@webpieces/http-api';
|
|
15
|
+
export { RouteHandler, ExpressRouteHandler, MethodMeta, RouteBuilderImpl, RouteHandlerWithMeta, FilterWithMeta, HttpFilter, FilterMatcher, FilterDefinition, } from '@webpieces/http-routing';
|
package/src/index.js
CHANGED
|
@@ -1,20 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FilterMatcher = exports.FilterWithMeta = exports.RouteHandlerWithMeta = exports.RouteBuilderImpl = exports.MethodMeta = exports.RouteHandler = exports.WebpiecesCoreHeaders = exports.WebpiecesModule = exports.LogApiFilter = exports.ContextFilter = exports.WebpiecesMiddleware = exports.WebpiecesFactory = void 0;
|
|
3
|
+
exports.FilterDefinition = exports.FilterMatcher = exports.FilterWithMeta = exports.RouteHandlerWithMeta = exports.RouteBuilderImpl = exports.MethodMeta = exports.RouteHandler = exports.HeaderRegistry = exports.WebpiecesCoreHeaders = exports.WebpiecesModule = exports.recordable = exports.SpecGenerator = exports.TestCaseRecorderImpl = exports.RecordingFilter = exports.LogApiFilter = exports.ContextFilter = exports.InProcessApiClientFactory = exports.WebpiecesRouteCreator = exports.WebpiecesMiddleware = exports.WebpiecesFactory = void 0;
|
|
4
4
|
var WebpiecesFactory_1 = require("./WebpiecesFactory");
|
|
5
5
|
Object.defineProperty(exports, "WebpiecesFactory", { enumerable: true, get: function () { return WebpiecesFactory_1.WebpiecesFactory; } });
|
|
6
6
|
var WebpiecesMiddleware_1 = require("./WebpiecesMiddleware");
|
|
7
7
|
Object.defineProperty(exports, "WebpiecesMiddleware", { enumerable: true, get: function () { return WebpiecesMiddleware_1.WebpiecesMiddleware; } });
|
|
8
|
+
var WebpiecesRouteCreator_1 = require("./WebpiecesRouteCreator");
|
|
9
|
+
Object.defineProperty(exports, "WebpiecesRouteCreator", { enumerable: true, get: function () { return WebpiecesRouteCreator_1.WebpiecesRouteCreator; } });
|
|
10
|
+
var InProcessApiClientFactory_1 = require("./InProcessApiClientFactory");
|
|
11
|
+
Object.defineProperty(exports, "InProcessApiClientFactory", { enumerable: true, get: function () { return InProcessApiClientFactory_1.InProcessApiClientFactory; } });
|
|
8
12
|
var ContextFilter_1 = require("./filters/ContextFilter");
|
|
9
13
|
Object.defineProperty(exports, "ContextFilter", { enumerable: true, get: function () { return ContextFilter_1.ContextFilter; } });
|
|
10
14
|
var LogApiFilter_1 = require("./filters/LogApiFilter");
|
|
11
15
|
Object.defineProperty(exports, "LogApiFilter", { enumerable: true, get: function () { return LogApiFilter_1.LogApiFilter; } });
|
|
16
|
+
var RecordingFilter_1 = require("./filters/RecordingFilter");
|
|
17
|
+
Object.defineProperty(exports, "RecordingFilter", { enumerable: true, get: function () { return RecordingFilter_1.RecordingFilter; } });
|
|
18
|
+
// Test-case recording (contract lives in @webpieces/http-api)
|
|
19
|
+
var TestCaseRecorderImpl_1 = require("./recorder/TestCaseRecorderImpl");
|
|
20
|
+
Object.defineProperty(exports, "TestCaseRecorderImpl", { enumerable: true, get: function () { return TestCaseRecorderImpl_1.TestCaseRecorderImpl; } });
|
|
21
|
+
var SpecGenerator_1 = require("./recorder/SpecGenerator");
|
|
22
|
+
Object.defineProperty(exports, "SpecGenerator", { enumerable: true, get: function () { return SpecGenerator_1.SpecGenerator; } });
|
|
23
|
+
var recordable_1 = require("./recorder/recordable");
|
|
24
|
+
Object.defineProperty(exports, "recordable", { enumerable: true, get: function () { return recordable_1.recordable; } });
|
|
12
25
|
// Platform Headers
|
|
13
26
|
var WebpiecesModule_1 = require("./modules/WebpiecesModule");
|
|
14
27
|
Object.defineProperty(exports, "WebpiecesModule", { enumerable: true, get: function () { return WebpiecesModule_1.WebpiecesModule; } });
|
|
15
28
|
var WebpiecesCoreHeaders_1 = require("./headers/WebpiecesCoreHeaders");
|
|
16
29
|
Object.defineProperty(exports, "WebpiecesCoreHeaders", { enumerable: true, get: function () { return WebpiecesCoreHeaders_1.WebpiecesCoreHeaders; } });
|
|
30
|
+
var http_api_1 = require("@webpieces/http-api");
|
|
31
|
+
Object.defineProperty(exports, "HeaderRegistry", { enumerable: true, get: function () { return http_api_1.HeaderRegistry; } });
|
|
17
32
|
// Re-export from http-routing for backward compatibility
|
|
33
|
+
// (FilterDefinition re-exported for one-import adapter ergonomics)
|
|
18
34
|
var http_routing_1 = require("@webpieces/http-routing");
|
|
19
35
|
Object.defineProperty(exports, "RouteHandler", { enumerable: true, get: function () { return http_routing_1.RouteHandler; } });
|
|
20
36
|
Object.defineProperty(exports, "MethodMeta", { enumerable: true, get: function () { return http_routing_1.MethodMeta; } });
|
|
@@ -22,4 +38,5 @@ Object.defineProperty(exports, "RouteBuilderImpl", { enumerable: true, get: func
|
|
|
22
38
|
Object.defineProperty(exports, "RouteHandlerWithMeta", { enumerable: true, get: function () { return http_routing_1.RouteHandlerWithMeta; } });
|
|
23
39
|
Object.defineProperty(exports, "FilterWithMeta", { enumerable: true, get: function () { return http_routing_1.FilterWithMeta; } });
|
|
24
40
|
Object.defineProperty(exports, "FilterMatcher", { enumerable: true, get: function () { return http_routing_1.FilterMatcher; } });
|
|
41
|
+
Object.defineProperty(exports, "FilterDefinition", { enumerable: true, get: function () { return http_routing_1.FilterDefinition; } });
|
|
25
42
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/index.ts"],"names":[],"mappings":";;;AACA,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,6DAA4D;AAAnD,0HAAA,mBAAmB,OAAA;AAC5B,yDAAwD;AAA/C,8GAAA,aAAa,OAAA;AACtB,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/index.ts"],"names":[],"mappings":";;;AACA,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,6DAA4D;AAAnD,0HAAA,mBAAmB,OAAA;AAC5B,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA;AAC9B,yEAAwE;AAA/D,sIAAA,yBAAyB,OAAA;AAClC,yDAAwD;AAA/C,8GAAA,aAAa,OAAA;AACtB,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AACrB,6DAA4D;AAAnD,kHAAA,eAAe,OAAA;AAExB,8DAA8D;AAC9D,wEAAuE;AAA9D,4HAAA,oBAAoB,OAAA;AAC7B,0DAAyD;AAAhD,8GAAA,aAAa,OAAA;AACtB,oDAAmD;AAA1C,wGAAA,UAAU,OAAA;AAEnB,mBAAmB;AACnB,6DAA4D;AAAnD,kHAAA,eAAe,OAAA;AACxB,uEAAsE;AAA7D,4HAAA,oBAAoB,OAAA;AAC7B,gDAAqD;AAA5C,0GAAA,cAAc,OAAA;AAEvB,yDAAyD;AACzD,mEAAmE;AACnE,wDAUiC;AAT7B,4GAAA,YAAY,OAAA;AAEZ,0GAAA,UAAU,OAAA;AACV,gHAAA,gBAAgB,OAAA;AAChB,oHAAA,oBAAoB,OAAA;AACpB,8GAAA,cAAc,OAAA;AAEd,6GAAA,aAAa,OAAA;AACb,gHAAA,gBAAgB,OAAA","sourcesContent":["export { WebpiecesServer } from './WebpiecesServer';\nexport { WebpiecesFactory } from './WebpiecesFactory';\nexport { WebpiecesMiddleware } from './WebpiecesMiddleware';\nexport { WebpiecesRouteCreator } from './WebpiecesRouteCreator';\nexport { InProcessApiClientFactory } from './InProcessApiClientFactory';\nexport { ContextFilter } from './filters/ContextFilter';\nexport { LogApiFilter } from './filters/LogApiFilter';\nexport { RecordingFilter } from './filters/RecordingFilter';\n\n// Test-case recording (contract lives in @webpieces/http-api)\nexport { TestCaseRecorderImpl } from './recorder/TestCaseRecorderImpl';\nexport { SpecGenerator } from './recorder/SpecGenerator';\nexport { recordable } from './recorder/recordable';\n\n// Platform Headers\nexport { WebpiecesModule } from './modules/WebpiecesModule';\nexport { WebpiecesCoreHeaders } from './headers/WebpiecesCoreHeaders';\nexport { HeaderRegistry } from '@webpieces/http-api';\n\n// Re-export from http-routing for backward compatibility\n// (FilterDefinition re-exported for one-import adapter ergonomics)\nexport {\n RouteHandler,\n ExpressRouteHandler,\n MethodMeta,\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n FilterWithMeta,\n HttpFilter,\n FilterMatcher,\n FilterDefinition,\n} from '@webpieces/http-routing';\n"]}
|