From 1617fcaa5318e0602cbb6bbac07d1901ed017582 Mon Sep 17 00:00:00 2001 From: Ty Potter Date: Fri, 28 Mar 2025 14:44:12 -0600 Subject: [PATCH 1/3] feat: use subdomain in precomputed client --- src/client/eppo-precomputed-client.spec.ts | 72 ++++++++++++++++++++++ src/client/eppo-precomputed-client.ts | 2 + 2 files changed, 74 insertions(+) diff --git a/src/client/eppo-precomputed-client.spec.ts b/src/client/eppo-precomputed-client.spec.ts index c512f0c..e5100a3 100644 --- a/src/client/eppo-precomputed-client.spec.ts +++ b/src/client/eppo-precomputed-client.spec.ts @@ -714,6 +714,78 @@ describe('EppoPrecomputedClient E2E test', () => { pollAfterFailedInitialization ? red : 'default', ); }); + + describe('Enhanced SDK Token with encoded subdomain', () => { + let urlsRequested: string[] = []; + + beforeEach(() => { + urlsRequested = []; + global.fetch = jest.fn((url) => { + urlsRequested.push(url.toString()); + return Promise.resolve({ + ok: true, + status: 200, + json: () => Promise.resolve(precomputedResponse), + } as Response); + }); + }); + + it('should request from the encoded subdomain', async () => { + const client = new EppoPrecomputedClient({ + precomputedFlagStore: new MemoryOnlyConfigurationStore(), + subject, + requestParameters: { + apiKey: 'zCsQuoHJxVPp895.Y3M9ZXhwZXJpbWVudA==', // subdomain=experiment + sdkName: 'js-client-sdk-common', + sdkVersion: '1.0.0', + }, + }); + + await client.fetchPrecomputedFlags(); + + expect(urlsRequested).toHaveLength(1); + expect(urlsRequested[0]).toContain( + 'https://experiment.fs-edge-assignment.eppo.cloud/assignments?apiKey=zCsQuoHJxVPp895.Y3M9ZXhwZXJpbWVudA%3D%3D&sdkName=js-client-sdk-common&sdkVersion=1.0.0', + ); + }); + + it('should request from the default domain if the encoded subdomain is not present', async () => { + const client = new EppoPrecomputedClient({ + precomputedFlagStore: new MemoryOnlyConfigurationStore(), + subject, + requestParameters: { + apiKey: 'old style key', + sdkName: 'js-client-sdk-common', + sdkVersion: '1.0.0', + }, + }); + + await client.fetchPrecomputedFlags(); + + expect(urlsRequested).toHaveLength(1); + expect(urlsRequested[0]).toEqual( + 'https://fs-edge-assignment.eppo.cloud/assignments?apiKey=old+style+key&sdkName=js-client-sdk-common&sdkVersion=1.0.0', + ); + }); + + it('should request from the provided baseUrl if present', async () => { + const client = new EppoPrecomputedClient({ + precomputedFlagStore: new MemoryOnlyConfigurationStore(), + subject, + requestParameters: { + apiKey: 'zCsQuoHJxVPp895.Y3M9ZXhwZXJpbWVudA==', // subdomain=experiment + sdkName: 'js-client-sdk-common', + sdkVersion: '1.0.0', + baseUrl: 'https://custom-base-url.com', + }, + }); + + await client.fetchPrecomputedFlags(); + + expect(urlsRequested).toHaveLength(1); + expect(urlsRequested[0]).toContain('https://custom-base-url.com'); + }); + }); }); describe('Obfuscated precomputed flags', () => { diff --git a/src/client/eppo-precomputed-client.ts b/src/client/eppo-precomputed-client.ts index 2c9192e..590ed87 100644 --- a/src/client/eppo-precomputed-client.ts +++ b/src/client/eppo-precomputed-client.ts @@ -32,6 +32,7 @@ import { import { getMD5Hash } from '../obfuscation'; import initPoller, { IPoller } from '../poller'; import PrecomputedRequestor from '../precomputed-requestor'; +import SdkTokenDecoder from '../sdk-token-decoder'; import { Attributes, ContextAttributes, FlagKey } from '../types'; import { validateNotBlank } from '../validation'; import { LIB_VERSION } from '../version'; @@ -164,6 +165,7 @@ export default class EppoPrecomputedClient { defaultUrl: PRECOMPUTED_BASE_URL, baseUrl, queryParams: { apiKey, sdkName, sdkVersion }, + sdkTokenDecoder: new SdkTokenDecoder(apiKey), }); const httpClient = new FetchHttpClient(apiEndpoints, requestTimeoutMs); const precomputedRequestor = new PrecomputedRequestor( From a3f7434e17deecae9dfb8779675cd7650accf6e2 Mon Sep 17 00:00:00 2001 From: Ty Potter Date: Fri, 28 Mar 2025 14:45:33 -0600 Subject: [PATCH 2/3] v4.15.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 579dc7e..313b1c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eppo/js-client-sdk-common", - "version": "4.15.0", + "version": "4.15.1", "description": "Common library for Eppo JavaScript SDKs (web, react native, and node)", "main": "dist/index.js", "files": [ From 1b865b90ffe3736f58eb930db4304100b4eca1bf Mon Sep 17 00:00:00 2001 From: Ty Potter Date: Mon, 31 Mar 2025 08:36:39 -0600 Subject: [PATCH 3/3] toEqual tests --- src/client/eppo-precomputed-client.spec.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/client/eppo-precomputed-client.spec.ts b/src/client/eppo-precomputed-client.spec.ts index e5100a3..4316eb6 100644 --- a/src/client/eppo-precomputed-client.spec.ts +++ b/src/client/eppo-precomputed-client.spec.ts @@ -717,6 +717,7 @@ describe('EppoPrecomputedClient E2E test', () => { describe('Enhanced SDK Token with encoded subdomain', () => { let urlsRequested: string[] = []; + const SDK_PARAM_SUFFIX = 'sdkName=js-client-sdk-common&sdkVersion=1.0.0'; beforeEach(() => { urlsRequested = []; @@ -744,8 +745,9 @@ describe('EppoPrecomputedClient E2E test', () => { await client.fetchPrecomputedFlags(); expect(urlsRequested).toHaveLength(1); - expect(urlsRequested[0]).toContain( - 'https://experiment.fs-edge-assignment.eppo.cloud/assignments?apiKey=zCsQuoHJxVPp895.Y3M9ZXhwZXJpbWVudA%3D%3D&sdkName=js-client-sdk-common&sdkVersion=1.0.0', + expect(urlsRequested[0]).toEqual( + 'https://experiment.fs-edge-assignment.eppo.cloud/assignments?apiKey=zCsQuoHJxVPp895.Y3M9ZXhwZXJpbWVudA%3D%3D&' + + SDK_PARAM_SUFFIX, ); }); @@ -764,7 +766,8 @@ describe('EppoPrecomputedClient E2E test', () => { expect(urlsRequested).toHaveLength(1); expect(urlsRequested[0]).toEqual( - 'https://fs-edge-assignment.eppo.cloud/assignments?apiKey=old+style+key&sdkName=js-client-sdk-common&sdkVersion=1.0.0', + 'https://fs-edge-assignment.eppo.cloud/assignments?apiKey=old+style+key&' + + SDK_PARAM_SUFFIX, ); }); @@ -783,7 +786,10 @@ describe('EppoPrecomputedClient E2E test', () => { await client.fetchPrecomputedFlags(); expect(urlsRequested).toHaveLength(1); - expect(urlsRequested[0]).toContain('https://custom-base-url.com'); + expect(urlsRequested[0]).toEqual( + 'https://custom-base-url.com/assignments?apiKey=zCsQuoHJxVPp895.Y3M9ZXhwZXJpbWVudA%3D%3D&' + + SDK_PARAM_SUFFIX, + ); }); }); });