diff --git a/packages/shared/sdk-client/__tests__/datasource/fdv2/StreamingFDv2Base.test.ts b/packages/shared/sdk-client/__tests__/datasource/fdv2/StreamingFDv2Base.test.ts index 8b6aa4f691..ee28828e47 100644 --- a/packages/shared/sdk-client/__tests__/datasource/fdv2/StreamingFDv2Base.test.ts +++ b/packages/shared/sdk-client/__tests__/datasource/fdv2/StreamingFDv2Base.test.ts @@ -430,6 +430,58 @@ it('produces results in order', async () => { base.close(); }); +it('includes basis parameter in stream URI when selectorGetter returns a value', () => { + const mockEventSource = createMockEventSource(); + const mockRequests = createMockRequests(mockEventSource); + + const base = createBase(mockRequests, logger, { + streamUriPath: '/sdk/stream/eval/ctx', + parameters: [{ key: 'auth', value: 'my-key' }], + selectorGetter: () => '(p:test:1)', + }); + base.start(); + + const uri = mockRequests.createEventSource.mock.calls[0][0]; + expect(uri).toContain(`basis=${encodeURIComponent('(p:test:1)')}`); + expect(uri).toContain('auth=my-key'); + + base.close(); +}); + +it('does not include basis parameter when selectorGetter returns undefined', () => { + const mockEventSource = createMockEventSource(); + const mockRequests = createMockRequests(mockEventSource); + + const base = createBase(mockRequests, logger, { + streamUriPath: '/sdk/stream/eval/ctx', + parameters: [{ key: 'auth', value: 'my-key' }], + selectorGetter: () => undefined, + }); + base.start(); + + const uri = mockRequests.createEventSource.mock.calls[0][0]; + expect(uri).not.toContain('basis'); + expect(uri).toContain('auth=my-key'); + + base.close(); +}); + +it('does not include basis parameter when no selectorGetter is provided', () => { + const mockEventSource = createMockEventSource(); + const mockRequests = createMockRequests(mockEventSource); + + const base = createBase(mockRequests, logger, { + streamUriPath: '/sdk/stream/eval/ctx', + parameters: [{ key: 'auth', value: 'my-key' }], + }); + base.start(); + + const uri = mockRequests.createEventSource.mock.calls[0][0]; + expect(uri).not.toContain('basis'); + + base.close(); +}); + it('close is idempotent', () => { const mockEventSource = createMockEventSource(); const mockRequests = createMockRequests(mockEventSource); diff --git a/packages/shared/sdk-client/__tests__/datasource/fdv2/streamingTestHelpers.ts b/packages/shared/sdk-client/__tests__/datasource/fdv2/streamingTestHelpers.ts index c554d54b6b..28162299dc 100644 --- a/packages/shared/sdk-client/__tests__/datasource/fdv2/streamingTestHelpers.ts +++ b/packages/shared/sdk-client/__tests__/datasource/fdv2/streamingTestHelpers.ts @@ -114,6 +114,7 @@ export function createBase( pingHandler?: PingHandler; streamUriPath?: string; parameters?: { key: string; value: string }[]; + selectorGetter?: () => string | undefined; } = {}, ) { return createStreamingBase({ @@ -121,6 +122,7 @@ export function createBase( serviceEndpoints, streamUriPath: options.streamUriPath ?? '/sdk/stream/eval/test-context', parameters: options.parameters ?? [], + selectorGetter: options.selectorGetter, headers: baseHeaders, initialRetryDelayMillis: 1000, logger, diff --git a/packages/shared/sdk-client/src/datasource/fdv2/StreamingFDv2Base.ts b/packages/shared/sdk-client/src/datasource/fdv2/StreamingFDv2Base.ts index a1624edca0..89bdd50ba4 100644 --- a/packages/shared/sdk-client/src/datasource/fdv2/StreamingFDv2Base.ts +++ b/packages/shared/sdk-client/src/datasource/fdv2/StreamingFDv2Base.ts @@ -82,6 +82,7 @@ export function createStreamingBase(config: { serviceEndpoints: ServiceEndpoints; streamUriPath: string; parameters: { key: string; value: string }[]; + selectorGetter?: () => string | undefined; headers: LDHeaders; initialRetryDelayMillis: number; logger?: LDLogger; @@ -94,13 +95,17 @@ export function createStreamingBase(config: { config.logger, ); - const streamUri = getStreamingUri( - config.serviceEndpoints, - config.streamUriPath, - config.parameters, - ); const headers: { [key: string]: string | string[] } = { ...config.headers }; + function buildStreamUri(): string { + const params = [...config.parameters]; + const basis = config.selectorGetter?.(); + if (basis) { + params.push({ key: 'basis', value: encodeURIComponent(basis) }); + } + return getStreamingUri(config.serviceEndpoints, config.streamUriPath, params); + } + let eventSource: EventSource | undefined; let connectionAttemptStartTime: number | undefined; let fdv1Fallback = false; @@ -256,7 +261,7 @@ export function createStreamingBase(config: { logConnectionAttempt(); - const es = config.requests.createEventSource(streamUri, { + const es = config.requests.createEventSource(buildStreamUri(), { headers, errorFilter: (error: HttpErrorResponse) => handleError(error), initialRetryDelayMillis: config.initialRetryDelayMillis,