From b730a977dcf26c98705afa37f1deddad41b27082 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Wed, 3 Dec 2025 23:51:47 +0000 Subject: [PATCH] fix(virtualstream): Expose transport localData to handlers via TypedTools; improve VirtualStream payload encode/decode to preserve built-ins and handle nested arrays/objects --- changelog.md | 8 ++++++++ ts/00_commitinfo_data.ts | 2 +- ts/classes.typedhandler.ts | 4 ++++ ts/classes.typedtools.ts | 6 ++++++ ts/classes.virtualstream.ts | 14 +++++++++++++- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 7c31dc9..906dc4a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-12-03 - 3.1.11 - fix(virtualstream) +Expose transport localData to handlers via TypedTools; improve VirtualStream payload encode/decode to preserve built-ins and handle nested arrays/objects + +- TypedHandler: pass typedRequest.localData into a TypedTools instance so handlers can access transport-layer context (e.g. websocket peer). +- TypedTools: add a public localData property to store transport-specific context available to handlers. +- VirtualStream.decodePayloadFromNetwork: preserve built-in objects (Set, Map, Date, RegExp, Error, Promise or thenable) to avoid incorrect transformation. +- VirtualStream.encodePayloadForNetwork / decodePayloadFromNetwork: added proper recursion for arrays and objects to correctly handle nested payloads and virtual streams, with path tracking to support deduplication logic. + ## 2024-10-16 - 3.1.10 - fix(VirtualStream) Fix stream closure logic in `writeToWebstream` method diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 0f61222..e811f8f 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@api.global/typedrequest', - version: '3.1.10', + version: '3.1.11', description: 'A TypeScript library for making typed requests towards APIs, including facilities for handling requests, routing, and virtual stream handling.' } diff --git a/ts/classes.typedhandler.ts b/ts/classes.typedhandler.ts index bc90ecb..b3215a4 100644 --- a/ts/classes.typedhandler.ts +++ b/ts/classes.typedhandler.ts @@ -31,6 +31,10 @@ export class TypedHandler { if (e instanceof TypedResponseError) { typedResponseError = e; diff --git a/ts/classes.typedtools.ts b/ts/classes.typedtools.ts index 210608c..c379c29 100644 --- a/ts/classes.typedtools.ts +++ b/ts/classes.typedtools.ts @@ -2,6 +2,12 @@ import { TypedResponseError } from './classes.typedresponseerror.js'; import * as plugins from './plugins.js'; export class TypedTools { + /** + * Local data passed from the transport layer. + * This can contain connection-specific context like the WebSocket peer. + */ + public localData: Record = {}; + public async passGuards(guardsArg: plugins.smartguard.Guard[], dataArg: T) { const guardSet = new plugins.smartguard.GuardSet(guardsArg); const guardResult = await guardSet.allGuardsPass(dataArg); diff --git a/ts/classes.virtualstream.ts b/ts/classes.virtualstream.ts index a614953..edcfe6f 100644 --- a/ts/classes.virtualstream.ts +++ b/ts/classes.virtualstream.ts @@ -82,7 +82,7 @@ export class VirtualStream implements plugins.typedRequestInterf } public static decodePayloadFromNetwork(objectPayload: any, commFunctions: ICommFunctions): any { - + if ( plugins.smartbuffer.isBufferLike(objectPayload) || objectPayload instanceof TypedRouter @@ -90,6 +90,18 @@ export class VirtualStream implements plugins.typedRequestInterf return objectPayload; } if (objectPayload !== null && typeof objectPayload === 'object') { + // Preserve built-in objects that shouldn't be transformed + if ( + objectPayload instanceof Set || + objectPayload instanceof Map || + objectPayload instanceof Date || + objectPayload instanceof RegExp || + objectPayload instanceof Error || + objectPayload instanceof Promise || + typeof objectPayload.then === 'function' + ) { + return objectPayload; + } if (objectPayload._isVirtualStream) { const virtualStream = new VirtualStream(); virtualStream.streamId = objectPayload.streamId;