From ff649e1bedff4d24e5e60cb993759609dde87aa3 Mon Sep 17 00:00:00 2001 From: Tony133 Date: Thu, 5 Nov 2026 16:28:35 +0100 Subject: [PATCH 1/2] feat: document and test the objectMechanism option of fast-json-stringify 7.3.0 --- README.md | 13 ++++++++ package.json | 2 +- test/object-mechanism.test.js | 62 +++++++++++++++++++++++++++++++++++ types/index.tst.ts | 4 +++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/object-mechanism.test.js diff --git a/README.md b/README.md index 364845b..500e7b0 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,19 @@ The `fast-json-stringify` configuration is the default one. You can check the de You can also override the default configuration by passing the [`serializerOpts`](https://fastify.dev/docs/latest/Reference/Server/#serializeropts) configuration to the Fastify instance. +#### `objectMechanism: 'native'` + +`fast-json-stringify@7.3.0` added the [`objectMechanism`](https://github.com/fastify/fast-json-stringify/#object-mechanism) option. +With `'native'`, the serializer projects the payload into schema-shaped objects and delegates to `JSON.stringify`, so on Node.js 25+ V8 stays on its fast path while the response schema is still applied (undeclared properties stripped, coercions and formats as usual). The output is identical to the default mechanism, and the option is a no-op on Node.js < 25. + +```js +const app = fastify({ + serializerOpts: { + objectMechanism: 'native' + } +}) +``` + ## Usage This module is already used as default by Fastify. diff --git a/package.json b/package.json index 93dba38..9867154 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,6 @@ "tstyche": "^7.1.0" }, "dependencies": { - "fast-json-stringify": "^7.0.0" + "fast-json-stringify": "^7.3.0" } } diff --git a/test/object-mechanism.test.js b/test/object-mechanism.test.js new file mode 100644 index 0000000..981c3d9 --- /dev/null +++ b/test/object-mechanism.test.js @@ -0,0 +1,62 @@ +'use strict' + +const { test } = require('node:test') +const fastify = require('fastify') +const FjsCompiler = require('../index') + +const userSchema = Object.freeze({ + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + createdAt: { type: 'string', format: 'date-time' } + }, + required: ['id', 'name'] +}) + +test('objectMechanism is forwarded to fast-json-stringify', t => { + t.plan(1) + const factory = FjsCompiler() + t.assert.throws(() => { + factory({}, { objectMechanism: 'not-a-mechanism' })({ schema: userSchema }) + }, /Unsupported object mechanism not-a-mechanism/) +}) + +test('objectMechanism: native produces the same output as the default mechanism', t => { + t.plan(1) + const factory = FjsCompiler() + const serializeDefault = factory({}, {})({ schema: userSchema }) + const serializeNative = factory({}, { objectMechanism: 'native' })({ schema: userSchema }) + + const input = { id: 1, name: 'alice', passwordHash: 'secret', createdAt: new Date(0) } + t.assert.equal(serializeNative(input), serializeDefault(input)) +}) + +test('fastify integration with objectMechanism: native', async t => { + const factory = FjsCompiler() + + const app = fastify({ + serializerOpts: { + objectMechanism: 'native' + }, + schemaController: { + compilersFactory: { + buildSerializer: factory + } + } + }) + + app.get('/', { + handler: async () => ({ id: 1, name: 'alice', passwordHash: 'secret', createdAt: new Date(0) }), + schema: { + response: { + 200: userSchema + } + } + }) + + const res = await app.inject({ url: '/', method: 'GET' }) + + t.assert.equal(res.statusCode, 200) + t.assert.equal(res.body, '{"id":1,"name":"alice","createdAt":"1970-01-01T00:00:00.000Z"}') +}) diff --git a/types/index.tst.ts b/types/index.tst.ts index 4b0b6aa..2fa4026 100644 --- a/types/index.tst.ts +++ b/types/index.tst.ts @@ -41,6 +41,10 @@ import SerializerSelector, { expect(serializeFunc).type.toBe() expect(serializeFunc({ name: 'hello' })).type.toBe() + + expect(factory({}, { objectMechanism: 'native' })).type.toBe() + expect(factory({}, { objectMechanism: 'default' })).type.toBe() + expect(factory).type.not.toBeCallableWith({}, { objectMechanism: 'not-a-mechanism' }) } /** From c25d95c82b8eea1b0b9e13c8332572792d9e3c16 Mon Sep 17 00:00:00 2001 From: Tony133 Date: Thu, 5 Nov 2026 16:46:05 +0100 Subject: [PATCH 2/2] chore: temporarily exclude fast-json-stringify from min-release-age --- .npmrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.npmrc b/.npmrc index 288bb54..fdff003 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,5 @@ ignore-scripts=true min-release-age=7 +; temporary: fast-json-stringify@7.3.0 was published on 2026-11-05, remove after 2026-11-12 +min-release-age-exclude[]=fast-json-stringify package-lock=false