From 3f042a4cbf2c8141d1c3d2a03d25fd3056fa20a4 Mon Sep 17 00:00:00 2001 From: unnoq Date: Fri, 21 Mar 2025 14:25:20 +0700 Subject: [PATCH] fix(client, server): prevent toJSON problem --- .../standard/rpc-json-serializer.test.ts | 19 ++++++++++++++++++- .../adapters/standard/rpc-json-serializer.ts | 9 +++++++++ .../standard/openapi-json-serializer.test.ts | 8 ++++++++ .../standard/openapi-json-serializer.ts | 9 +++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/client/src/adapters/standard/rpc-json-serializer.test.ts b/packages/client/src/adapters/standard/rpc-json-serializer.test.ts index f36bed6be..5f01a2a46 100644 --- a/packages/client/src/adapters/standard/rpc-json-serializer.test.ts +++ b/packages/client/src/adapters/standard/rpc-json-serializer.test.ts @@ -40,6 +40,16 @@ const customSupportedDataTypes: { name: string, value: unknown, expected: unknow value: new Person2('unnoq - 2', [{ nested: new Date('2023-01-02') }, /uic/gi]), expected: new Person2('unnoq - 2', [{ nested: new Date('2023-01-02') }, /uic/gi]), }, + { + name: 'should not resolve toJSON', + value: { value: { toJSON: () => 'hello' } }, + expected: { value: { } }, + }, + { + name: 'should resolve invalid toJSON', + value: { value: { toJSON: 'hello' } }, + expected: { value: { toJSON: 'hello' } }, + }, ] describe.each([ @@ -66,7 +76,14 @@ describe.each([ function assert(value: unknown, expected: unknown) { const [json, meta, maps, blobs] = serializer.serialize(value) - const deserialized = serializer.deserialize(json, meta, maps, (i: number) => blobs[i]!) + const result = JSON.parse(JSON.stringify({ json, meta, maps })) + + const deserialized = serializer.deserialize( + result.json, + result.meta, + result.maps, + (i: number) => blobs[i]!, + ) expect(deserialized).toEqual(expected) } diff --git a/packages/client/src/adapters/standard/rpc-json-serializer.ts b/packages/client/src/adapters/standard/rpc-json-serializer.ts index 9ec6c31e0..277afde95 100644 --- a/packages/client/src/adapters/standard/rpc-json-serializer.ts +++ b/packages/client/src/adapters/standard/rpc-json-serializer.ts @@ -112,6 +112,15 @@ export class StandardRPCJsonSerializer { const json: Record = {} for (const k in data) { + /** + * Skip custom toJSON methods to avoid JSON.stringify invoking them, + * which could cause meta and serialized data mismatches during deserialization. + * Instead, rely on custom serializers. + */ + if (k === 'toJSON' && typeof data[k] === 'function') { + continue + } + json[k] = this.serialize(data[k], [...segments, k], meta, maps, blobs)[0] } diff --git a/packages/openapi-client/src/adapters/standard/openapi-json-serializer.test.ts b/packages/openapi-client/src/adapters/standard/openapi-json-serializer.test.ts index 78c6ef671..9dd315fe3 100644 --- a/packages/openapi-client/src/adapters/standard/openapi-json-serializer.test.ts +++ b/packages/openapi-client/src/adapters/standard/openapi-json-serializer.test.ts @@ -145,6 +145,14 @@ const customSupportedDataTypes: TestCase[] = [ data: new Person2('unnoq - 2', [{ nested: new Date('2023-01-02') }, /uic/gi]), expected: { name: 'unnoq - 2', data: [{ nested: '2023-01-02T00:00:00.000Z' }, '/uic/gi'] }, }, + { + data: { value: { toJSON: () => 'hello' } }, + expected: { value: { } }, + }, + { + data: { value: { toJSON: 'hello' } }, + expected: { value: { toJSON: 'hello' } }, + }, ] describe.each([ diff --git a/packages/openapi-client/src/adapters/standard/openapi-json-serializer.ts b/packages/openapi-client/src/adapters/standard/openapi-json-serializer.ts index 497781305..ae8fefeab 100644 --- a/packages/openapi-client/src/adapters/standard/openapi-json-serializer.ts +++ b/packages/openapi-client/src/adapters/standard/openapi-json-serializer.ts @@ -49,6 +49,15 @@ export class StandardOpenAPIJsonSerializer { const json: Record = {} for (const k in data) { + /** + * Skip custom toJSON methods to avoid JSON.stringify invoking them, + * which could cause meta and serialized data mismatches during deserialization. + * Instead, rely on custom serializers. + */ + if (k === 'toJSON' && typeof data[k] === 'function') { + continue + } + json[k] = this.serialize(data[k], hasBlobRef)[0] }