Compare commits

...

4 Commits

5 changed files with 60 additions and 26 deletions

View File

@@ -1,5 +1,18 @@
# Changelog
## 2025-12-04 - 3.2.2 - fix(typedrequest)
Add skipHooks flag to TypedRequest to optionally suppress global hooks for internal requests
- Introduce public skipHooks boolean on TypedRequest (default false) with documentation comment explaining it should be used for internal/logging requests to prevent infinite loops.
- Guard calls to global hooks (onOutgoingRequest and onIncomingResponse) in TypedRequest.fire() so hooks are not invoked when skipHooks is true.
## 2025-12-04 - 3.2.1 - fix(typedrouter)
Use globalThis-backed globalHooks for TypedRouter to enable cross-bundle sharing; fix merging and clearing of global hooks.
- Replace static globalHooks field with getter/setter that stores hooks on globalThis so hooks are shared across bundles.
- Fix setGlobalHooks to merge new hooks with existing ones (avoiding accidental overwrite).
- Update clearGlobalHooks to clear the globalThis storage used for hooks.
## 2025-12-04 - 3.2.0 - feat(typedrouter)
Add request/response hooks and monitoring to TypedRouter; emit hooks from TypedRequest; improve VirtualStream encoding/decoding; re-export hook types

View File

@@ -1,6 +1,6 @@
{
"name": "@api.global/typedrequest",
"version": "3.2.0",
"version": "3.2.2",
"private": false,
"description": "A TypeScript library for making typed requests towards APIs, including facilities for handling requests, routing, and virtual stream handling.",
"main": "dist_ts/index.js",

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@api.global/typedrequest',
version: '3.2.0',
version: '3.2.2',
description: 'A TypeScript library for making typed requests towards APIs, including facilities for handling requests, routing, and virtual stream handling.'
}

View File

@@ -33,6 +33,12 @@ export class TypedRequest<T extends plugins.typedRequestInterfaces.ITypedRequest
public method: string;
/**
* When true, hooks will not be called for this request.
* Use this for internal/logging requests to prevent infinite loops.
*/
public skipHooks: boolean = false;
/**
* @param postEndPointArg
* @param methodArg
@@ -69,15 +75,17 @@ export class TypedRequest<T extends plugins.typedRequestInterfaces.ITypedRequest
}
});
// Hook: outgoing request
callGlobalHook('onOutgoingRequest', {
correlationId: payloadSending.correlation.id,
method: this.method,
direction: 'outgoing',
phase: 'request',
timestamp: requestStartTime,
payload: fireArg,
});
// Hook: outgoing request (skip if this is an internal request)
if (!this.skipHooks) {
callGlobalHook('onOutgoingRequest', {
correlationId: payloadSending.correlation.id,
method: this.method,
direction: 'outgoing',
phase: 'request',
timestamp: requestStartTime,
payload: fireArg,
});
}
let payloadReceiving: plugins.typedRequestInterfaces.ITypedRequest;
payloadReceiving = await this.postTrObject(payloadSending, useCacheArg);
@@ -89,17 +97,19 @@ export class TypedRequest<T extends plugins.typedRequestInterfaces.ITypedRequest
}
});
// Hook: incoming response (for this outgoing request)
callGlobalHook('onIncomingResponse', {
correlationId: payloadSending.correlation.id,
method: this.method,
direction: 'incoming',
phase: 'response',
timestamp: Date.now(),
durationMs: Date.now() - requestStartTime,
payload: payloadReceiving?.response,
error: payloadReceiving?.error?.text,
});
// Hook: incoming response (skip if this is an internal request)
if (!this.skipHooks) {
callGlobalHook('onIncomingResponse', {
correlationId: payloadSending.correlation.id,
method: this.method,
direction: 'incoming',
phase: 'response',
timestamp: Date.now(),
durationMs: Date.now() - requestStartTime,
payload: payloadReceiving?.response,
error: payloadReceiving?.error?.text,
});
}
return payloadReceiving.response;
}

View File

@@ -34,21 +34,32 @@ export interface ITypedRouterHooks {
* This is thought for reusing the same url endpoint for different methods
*/
export class TypedRouter {
// Static hooks for global traffic monitoring
public static globalHooks: ITypedRouterHooks = {};
// Use globalThis for cross-bundle hook sharing
public static get globalHooks(): ITypedRouterHooks {
if (!(globalThis as any).__typedRouterGlobalHooks) {
(globalThis as any).__typedRouterGlobalHooks = {};
}
return (globalThis as any).__typedRouterGlobalHooks;
}
public static set globalHooks(value: ITypedRouterHooks) {
(globalThis as any).__typedRouterGlobalHooks = value;
}
/**
* Set global hooks for monitoring all TypedRequest traffic
* Hooks are shared across all bundles via globalThis
*/
public static setGlobalHooks(hooks: ITypedRouterHooks): void {
TypedRouter.globalHooks = { ...TypedRouter.globalHooks, ...hooks };
const current = TypedRouter.globalHooks;
TypedRouter.globalHooks = { ...current, ...hooks };
}
/**
* Clear all global hooks
*/
public static clearGlobalHooks(): void {
TypedRouter.globalHooks = {};
(globalThis as any).__typedRouterGlobalHooks = {};
}
// Instance-level hooks (for per-router monitoring)