From 638897b1e064edb58237955bd410dba98fd80920 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Thu, 14 May 2026 15:44:07 +0200 Subject: [PATCH] feat: Support bundle analytics headers --- src/box-client.ts | 25 ++++++++ tests/manual-sdk/lib/box-client-test.js | 78 +++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/src/box-client.ts b/src/box-client.ts index 30eefecda..4f0ef1818 100644 --- a/src/box-client.ts +++ b/src/box-client.ts @@ -171,6 +171,25 @@ function getFullURL(defaultBasePath: string, url: string) { return defaultBasePath + url; } +/** + * Get the box bundle version from environment or global variable + * @returns {string|null} The bundle version or null if not found + */ +function getBoxBundleVersion(): string | null { + if (typeof process !== 'undefined' && process.env?.NPM_BOX_VERSION) { + return process.env.NPM_BOX_VERSION; + } + + if ( + typeof globalThis !== 'undefined' && + (globalThis as any).__BOX_PACKAGE_VERSION + ) { + return (globalThis as any).__BOX_PACKAGE_VERSION; + } + + return null; +} + /** * Construct the X-Box-UA header to send analytics identifiers * @param {Object} [client] Analytics client information @@ -186,6 +205,12 @@ function constructBoxUAHeader(client: any /* FIXME */) { analyticsIdentifiers.client = `${client.name}/${client.version}`; } + // Add bundle information if box-node-sdk is used through npm-box meta-package + const bundleVersion = getBoxBundleVersion(); + if (bundleVersion) { + analyticsIdentifiers['bundle'] = `box/${bundleVersion}`; + } + return Object.keys(analyticsIdentifiers) .map((k) => `${k}=${analyticsIdentifiers[k]}`) .join('; '); diff --git a/tests/manual-sdk/lib/box-client-test.js b/tests/manual-sdk/lib/box-client-test.js index 9ac92c183..e7d03f1b1 100644 --- a/tests/manual-sdk/lib/box-client-test.js +++ b/tests/manual-sdk/lib/box-client-test.js @@ -170,6 +170,84 @@ describe('box-client', function () { return client._makeRequest({}); }); + it('should attach bundle info in X-Box-UA header when NPM_BOX_VERSION env var is set', function () { + var originalEnvValue = process.env.NPM_BOX_VERSION; + process.env.NPM_BOX_VERSION = '1.2.3'; + + sandbox + .stub(apiSessionFake, 'getAccessToken') + .returns(Promise.resolve(FAKE_ACCESS_TOKEN)); + + var expectedHeader = `agent=box-node-sdk/${pkg.version}; env=Node/${process.version.slice(1)}; bundle=box/1.2.3`; + + sandbox + .mock(requestManagerFake) + .expects('makeRequest') + .withArgs({ + headers: sinon.match({ + 'X-Box-UA': expectedHeader, + }), + }) + .returns(Promise.resolve(fakeOKResponse)); + + var promise = basicClient._makeRequest({}); + + // Clean up after the promise completes + return promise.then(function() { + if (originalEnvValue !== undefined) { + process.env.NPM_BOX_VERSION = originalEnvValue; + } else { + delete process.env.NPM_BOX_VERSION; + } + }).catch(function(err) { + if (originalEnvValue !== undefined) { + process.env.NPM_BOX_VERSION = originalEnvValue; + } else { + delete process.env.NPM_BOX_VERSION; + } + throw err; + }); + }); + + it('should attach bundle info in X-Box-UA header when __BOX_PACKAGE_VERSION global is set', function () { + var originalGlobalValue = globalThis.__BOX_PACKAGE_VERSION; + globalThis.__BOX_PACKAGE_VERSION = '2.3.4'; + + sandbox + .stub(apiSessionFake, 'getAccessToken') + .returns(Promise.resolve(FAKE_ACCESS_TOKEN)); + + var expectedHeader = `agent=box-node-sdk/${pkg.version}; env=Node/${process.version.slice(1)}; bundle=box/2.3.4`; + + sandbox + .mock(requestManagerFake) + .expects('makeRequest') + .withArgs({ + headers: sinon.match({ + 'X-Box-UA': expectedHeader, + }), + }) + .returns(Promise.resolve(fakeOKResponse)); + + var promise = basicClient._makeRequest({}); + + // Clean up after the promise completes + return promise.then(function() { + if (originalGlobalValue !== undefined) { + globalThis.__BOX_PACKAGE_VERSION = originalGlobalValue; + } else { + delete globalThis.__BOX_PACKAGE_VERSION; + } + }).catch(function(err) { + if (originalGlobalValue !== undefined) { + globalThis.__BOX_PACKAGE_VERSION = originalGlobalValue; + } else { + delete globalThis.__BOX_PACKAGE_VERSION; + } + throw err; + }); + }); + it('should not overwrite the "BoxAPI" header when it already exists', function () { var explicitBoxApiHeader = 'shared_link=box.com/alreadyset&shared_link_password=456',