From f4a18a0dc8545d47c71eb141feef22677c94a038 Mon Sep 17 00:00:00 2001 From: Robert DeLuca Date: Mon, 16 Feb 2026 13:36:16 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20double-nested=20properties?= =?UTF-8?q?=20in=20client=20screenshot=20payload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client was sending the entire options object as `properties`, so when SDKs passed `{ properties: { url } }`, the server received `properties: { properties: { url } }` — making `url` unreachable. Now the client destructures SDK options (`fullPage`, `threshold`) out and flattens `options.properties` into the top-level properties object, so metadata like `url` is always directly accessible. --- src/client/index.js | 11 +++++++++-- tests/sdk/client.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/client/index.js b/src/client/index.js index 4ba708e2..b63dc7e3 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -199,6 +199,13 @@ function createSimpleClient(serverUrl) { let image = isFilePath ? imageBuffer : imageBuffer.toString('base64'); let type = isFilePath ? 'file-path' : 'base64'; + let { + fullPage, + threshold, + properties: userProperties, + ...rest + } = options; + let httpStart = Date.now(); const { status, json } = await httpPost( `${serverUrl}/screenshot`, @@ -207,8 +214,8 @@ function createSimpleClient(serverUrl) { name, image, type, - properties: options, - fullPage: options.fullPage || false, + properties: { ...rest, ...userProperties }, + fullPage: fullPage || false, }, DEFAULT_TIMEOUT_MS ); diff --git a/tests/sdk/client.test.js b/tests/sdk/client.test.js index 6b53cbde..d7a8b1ba 100644 --- a/tests/sdk/client.test.js +++ b/tests/sdk/client.test.js @@ -377,6 +377,36 @@ describe('client/index httpPost integration tests', () => { assert.deepStrictEqual(req.body.properties, { browser: 'chrome' }); }); + it('flattens nested properties into top-level properties', async () => { + await vizzlyScreenshot('test', Buffer.from('data'), { + properties: { url: 'http://localhost:3000/page' }, + }); + + assert.strictEqual(requests.length, 1); + assert.deepStrictEqual(requests[0].body.properties, { + url: 'http://localhost:3000/page', + }); + }); + + it('excludes SDK options from properties', async () => { + await vizzlyScreenshot('test', Buffer.from('data'), { + fullPage: true, + threshold: 0.1, + properties: { url: 'http://localhost:3000' }, + browser: 'firefox', + }); + + assert.strictEqual(requests.length, 1); + let { properties, fullPage } = requests[0].body; + assert.strictEqual(fullPage, true); + assert.deepStrictEqual(properties, { + browser: 'firefox', + url: 'http://localhost:3000', + }); + assert.strictEqual(properties.fullPage, undefined); + assert.strictEqual(properties.threshold, undefined); + }); + it('sends Connection: close header to disable keep-alive', async () => { await vizzlyScreenshot('test', Buffer.from('data'));