Skip to content

Commit da3bcab

Browse files
committed
Merge branch 'main' into rlamb/prototype-multi-summary
2 parents 79ea083 + c486a3d commit da3bcab

File tree

14 files changed

+126
-76
lines changed

14 files changed

+126
-76
lines changed

.release-please-manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
"packages/shared/sdk-client": "1.12.5",
1515
"packages/sdk/react-native": "10.9.8",
1616
"packages/telemetry/node-server-sdk-otel": "1.1.8",
17-
"packages/sdk/browser": "0.5.1",
17+
"packages/sdk/browser": "0.5.2",
1818
"packages/sdk/server-ai": "0.9.5",
19-
"packages/telemetry/browser-telemetry": "1.0.4",
19+
"packages/telemetry/browser-telemetry": "1.0.5",
2020
"packages/tooling/jest": "0.1.3"
2121
}

packages/sdk/browser/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [0.5.2](https://github.com/launchdarkly/js-core/compare/js-client-sdk-v0.5.1...js-client-sdk-v0.5.2) (2025-04-15)
4+
5+
6+
### Bug Fixes
7+
8+
* Handle default flush interval for browser SDK. ([#822](https://github.com/launchdarkly/js-core/issues/822)) ([2c1cc7a](https://github.com/launchdarkly/js-core/commit/2c1cc7a117fd011a329dfcc5332fddf7fd11eff9))
9+
310
## [0.5.1](https://github.com/launchdarkly/js-core/compare/js-client-sdk-v0.5.0...js-client-sdk-v0.5.1) (2025-04-08)
411

512

packages/sdk/browser/__tests__/options.test.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { jest } from '@jest/globals';
22

33
import { LDLogger } from '@launchdarkly/js-client-sdk-common';
44

5-
import validateOptions, { filterToBaseOptions } from '../src/options';
5+
import validateBrowserOptions, { filterToBaseOptionsWithDefaults } from '../src/options';
66

77
let logger: LDLogger;
88

@@ -16,7 +16,7 @@ beforeEach(() => {
1616
});
1717

1818
it('logs no warnings when all configuration is valid', () => {
19-
validateOptions(
19+
validateBrowserOptions(
2020
{
2121
fetchGoals: true,
2222
eventUrlTransformer: (url: string) => url,
@@ -31,7 +31,7 @@ it('logs no warnings when all configuration is valid', () => {
3131
});
3232

3333
it('warns for invalid configuration', () => {
34-
validateOptions(
34+
validateBrowserOptions(
3535
{
3636
// @ts-ignore
3737
fetchGoals: 'yes',
@@ -50,8 +50,8 @@ it('warns for invalid configuration', () => {
5050
);
5151
});
5252

53-
it('applies default options', () => {
54-
const opts = validateOptions({}, logger);
53+
it('applies default browser-specific options', () => {
54+
const opts = validateBrowserOptions({}, logger);
5555

5656
expect(opts.fetchGoals).toBe(true);
5757
expect(opts.eventUrlTransformer).toBeDefined();
@@ -69,9 +69,24 @@ it('filters to base options', () => {
6969
eventUrlTransformer: (url: string) => url,
7070
};
7171

72-
const baseOpts = filterToBaseOptions(opts);
72+
const baseOpts = filterToBaseOptionsWithDefaults(opts);
7373
expect(baseOpts.debug).toBe(false);
74-
expect(Object.keys(baseOpts).length).toEqual(1);
74+
expect(Object.keys(baseOpts).length).toEqual(2);
7575
expect(baseOpts).not.toHaveProperty('fetchGoals');
7676
expect(baseOpts).not.toHaveProperty('eventUrlTransformer');
77+
expect(baseOpts.flushInterval).toEqual(2);
78+
});
79+
80+
it('applies default overrides to common config flushInterval', () => {
81+
const opts = {};
82+
const result = filterToBaseOptionsWithDefaults(opts);
83+
expect(result.flushInterval).toEqual(2);
84+
});
85+
86+
it('does not override common config flushInterval if it is set', () => {
87+
const opts = {
88+
flushInterval: 15,
89+
};
90+
const result = filterToBaseOptionsWithDefaults(opts);
91+
expect(result.flushInterval).toEqual(15);
7792
});

packages/sdk/browser/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@launchdarkly/js-client-sdk",
3-
"version": "0.5.1",
3+
"version": "0.5.2",
44
"description": "LaunchDarkly SDK for JavaScript in Browsers",
55
"homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/browser",
66
"repository": {

packages/sdk/browser/src/BrowserClient.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { BrowserIdentifyOptions as LDIdentifyOptions } from './BrowserIdentifyOp
2121
import { registerStateDetection } from './BrowserStateDetector';
2222
import GoalManager from './goals/GoalManager';
2323
import { Goal, isClick } from './goals/Goals';
24-
import validateOptions, { applyBrowserDefaults, BrowserOptions, filterToBaseOptions } from './options';
24+
import validateBrowserOptions, { BrowserOptions, filterToBaseOptionsWithDefaults } from './options';
2525
import BrowserPlatform from './platform/BrowserPlatform';
2626

2727
/**
@@ -116,14 +116,16 @@ export class BrowserClient extends LDClientImpl implements LDClient {
116116
const baseUrl = options.baseUri ?? 'https://clientsdk.launchdarkly.com';
117117

118118
const platform = overridePlatform ?? new BrowserPlatform(logger);
119-
const withDefaults = applyBrowserDefaults(options);
120-
const validatedBrowserOptions = validateOptions(withDefaults, logger);
119+
// Only the browser-specific options are in validatedBrowserOptions.
120+
const validatedBrowserOptions = validateBrowserOptions(options, logger);
121+
// The base options are in baseOptionsWithDefaults.
122+
const baseOptionsWithDefaults = filterToBaseOptionsWithDefaults({ ...options, logger });
121123
const { eventUrlTransformer } = validatedBrowserOptions;
122124
super(
123125
clientSideId,
124126
autoEnvAttributes,
125127
platform,
126-
filterToBaseOptions({ ...withDefaults, logger }),
128+
baseOptionsWithDefaults,
127129
(
128130
flagManager: FlagManager,
129131
configuration: Configuration,

packages/sdk/browser/src/options.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,14 @@ const validators: { [Property in keyof BrowserOptions]: TypeValidator | undefine
7373
streaming: TypeValidators.Boolean,
7474
};
7575

76-
export function filterToBaseOptions(opts: BrowserOptions): LDOptionsBase {
77-
const baseOptions: LDOptionsBase = { ...opts };
76+
function withBrowserDefaults(opts: BrowserOptions): BrowserOptions {
77+
const output = { ...opts };
78+
output.flushInterval ??= DEFAULT_FLUSH_INTERVAL_SECONDS;
79+
return output;
80+
}
81+
82+
export function filterToBaseOptionsWithDefaults(opts: BrowserOptions): LDOptionsBase {
83+
const baseOptions: LDOptionsBase = withBrowserDefaults(opts);
7884

7985
// Remove any browser specific configuration keys so we don't get warnings from
8086
// the base implementation for unknown configuration.
@@ -84,15 +90,11 @@ export function filterToBaseOptions(opts: BrowserOptions): LDOptionsBase {
8490
return baseOptions;
8591
}
8692

87-
export function applyBrowserDefaults(opts: BrowserOptions): BrowserOptions {
88-
const output = { ...opts };
89-
output.flushInterval ??= DEFAULT_FLUSH_INTERVAL_SECONDS;
90-
return output;
91-
}
92-
93-
export default function validateOptions(opts: BrowserOptions, logger: LDLogger): ValidatedOptions {
93+
export default function validateBrowserOptions(
94+
opts: BrowserOptions,
95+
logger: LDLogger,
96+
): ValidatedOptions {
9497
const output: ValidatedOptions = { ...optDefaults };
95-
applyBrowserDefaults(output);
9698

9799
Object.entries(validators).forEach((entry) => {
98100
const [key, validator] = entry as [keyof BrowserOptions, TypeValidator];

packages/shared/common/__tests__/internal/events/EventSummarizer.test.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ describe('given an event summarizer', () => {
77
const summarizer = new EventSummarizer();
88
const context = Context.fromLDContext({ key: 'key' });
99

10-
beforeEach(() => {
11-
summarizer.clearSummary();
12-
});
13-
1410
it('does nothing for an identify event.', () => {
1511
const beforeSummary = summarizer.getSummary();
1612
summarizer.summarizeEvent(new InputIdentifyEvent(context));
@@ -300,4 +296,25 @@ describe('given an event summarizer', () => {
300296
};
301297
expect(data.features).toEqual(expectedFeatures);
302298
});
299+
300+
it('automatically clears summaries after getSummary() is called', () => {
301+
const event = {
302+
kind: 'feature',
303+
creationDate: 1000,
304+
key: 'key1',
305+
version: 11,
306+
context,
307+
variation: 1,
308+
value: 100,
309+
default: 111,
310+
};
311+
312+
summarizer.summarizeEvent(event as any);
313+
summarizer.getSummary();
314+
315+
const secondSummary = summarizer.getSummary();
316+
expect(secondSummary.features).toEqual({});
317+
expect(secondSummary.startDate).toBe(0);
318+
expect(secondSummary.endDate).toBe(0);
319+
});
303320
});

packages/shared/common/__tests__/setupCrypto.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { Hasher } from '../src/api';
22

33
class MockHasher implements Hasher {
4-
private state: string[] = [];
4+
private _state: string[] = [];
55

66
update(value: string): Hasher {
7-
this.state.push(value);
7+
this._state.push(value);
88
return this;
99
}
1010

1111
digest(): string {
12-
const result = this.state.join('');
13-
this.state = []; // Reset state after digest
12+
const result = this._state.join('');
13+
this._state = []; // Reset state after digest
1414
return result;
1515
}
1616
}

packages/shared/common/src/Context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ export default class Context {
482482
const kinds = this.kinds.sort();
483483
kinds.forEach((kind) => hasher.update(kind));
484484

485-
for (const kind of kinds) {
485+
kinds.forEach((kind) => {
486486
hasher.update(kind);
487487
const context = this._contextForKind(kind)!;
488488
Object.getOwnPropertyNames(context)
@@ -502,7 +502,7 @@ export default class Context {
502502
.map((attr) => attr.components.join('/'))
503503
.sort();
504504
sortedAttributes.forEach((attr) => hasher.update(attr));
505-
}
505+
});
506506

507507
while (stack.length > 0) {
508508
const { target, visited } = stack.pop()!;

packages/shared/common/src/api/subsystem/LDEventSummarizer.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,21 @@ export interface SummarizedFlagsEvent {
3131
context?: any;
3232
}
3333

34+
/**
35+
* Interface for summarizing feature flag evaluations bucketed by the context.
36+
*/
3437
export interface LDMultiEventSummarizer {
38+
/**
39+
* Processes an event for summarization if it is a feature flag event and not excluded from summaries.
40+
* @param event The event to potentially summarize
41+
*/
3542
summarizeEvent(event: InputEvent): void;
36-
getSummaries(): Promise<SummarizedFlagsEvent[]>;
37-
clearSummary(): void;
43+
44+
/**
45+
* Gets the current summary of processed events.
46+
* @returns A summary of all processed feature flag events
47+
*/
48+
getSummaries(): SummarizedFlagsEvent[];
3849
}
3950

4051
/**
@@ -52,9 +63,4 @@ export default interface LDEventSummarizer {
5263
* @returns A summary of all processed feature flag events
5364
*/
5465
getSummary(): SummarizedFlagsEvent;
55-
56-
/**
57-
* Clears all summarized event data.
58-
*/
59-
clearSummary(): void;
6066
}

0 commit comments

Comments
 (0)