Skip to content

Conversation

@aarsilv
Copy link
Contributor

@aarsilv aarsilv commented Jan 20, 2026

Summary

  • Adds getFlagsConfiguration() function to export the current flags configuration as JSON
  • This enables bootstrapping other SDK instances via offline initialization

Stacked PRs

Test plan

  • Verify getFlagsConfiguration() returns null before initialization
  • Verify it returns valid JSON with flags and format after init
  • Verify the exported configuration matches the expected structure from flags-v1.json

🤖 Generated with Claude Code

This function returns the current flags configuration as a JSON string that can
be used to bootstrap another SDK instance. It includes flags, format, createdAt,
environment, and banditReferences when available.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
aarsilv and others added 2 commits January 19, 2026 22:03
- Remove jest.resetModules() from read-only file system tests (not needed)
- Add td.reset() afterEach in initialization errors tests to clean up mocks
- Move getFlagsConfiguration tests inside main EppoClient E2E test block
- Consolidate getFlagsConfiguration tests into single test for better isolation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use afterAll with null check for more robust client cleanup.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@aarsilv aarsilv changed the title Add getFlagsConfiguration() to export flag configuration as JSON Offline Init Part 1 of 4: Add getFlagsConfiguration() to export flag configuration as JSON Jan 20, 2026
aarsilv and others added 2 commits January 19, 2026 22:20
- Verify exact metadata (format, createdAt, environment)
- Check exact number of flags (22) from flags-v1.json
- Thoroughly test new-user-onboarding flag structure including:
  - All 6 variations
  - All 4 allocations with their rules and conditions
  - Various operators (MATCHES, NOT_ONE_OF, ONE_OF)
  - Extra logging configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Explain why configuration stores are kept at module level (EppoClient
  doesn't expose getters for store metadata or bandit configurations)
- Change "Returns" to "Reconstructs" in getFlagsConfiguration JSDoc

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment on lines +44 to +50
// We keep references to the configuration stores at module level because EppoClient
// does not expose public getters for store metadata (format, createdAt, environment)
// or bandit configurations. These references are needed by getFlagsConfiguration()
// and getBanditsConfiguration() to reconstruct exportable configuration JSON.
let flagConfigurationStore: MemoryOnlyConfigurationStore<Flag>;
let banditVariationConfigurationStore: MemoryOnlyConfigurationStore<BanditVariation[]>;
let banditModelConfigurationStore: MemoryOnlyConfigurationStore<BanditParameters>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying not to mess with the core SDK for now, but future us can expose these which would tidy this up a bit.

@aarsilv aarsilv marked this pull request as ready for review January 20, 2026 03:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a getFlagsConfiguration() function to export the current flags configuration as JSON, enabling offline initialization of SDK instances in future PRs.

Changes:

  • Adds getFlagsConfiguration() public API that returns JSON representation of current flag configuration
  • Stores configuration stores at module level to enable access to metadata and bandit configurations
  • Includes comprehensive tests validating the exported JSON structure matches the expected format

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/index.ts Adds module-level configuration store references, implements getFlagsConfiguration() and helper function to reconstruct bandit references
src/index.spec.ts Adds test suite validating getFlagsConfiguration() returns correct JSON structure with flags metadata

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +511 to +513
afterEach(() => {
td.reset();
});
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The afterEach block calls td.reset() but the corresponding test 'retries initial configuration request before resolving' uses td.replace() on HttpClient.prototype. This cleanup should be in the existing test's cleanup (or a dedicated beforeEach/afterEach within that specific test), not added at the describe block level where it affects all tests in the 'Configuration Request' suite.

Copilot uses AI. Check for mistakes.
// Save original implementation
let isReadOnlyFsSpy: SpyInstance;

beforeEach(() => {
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removed comment 'Reset the module before each test' and the removed jest.resetModules() call may have been important for test isolation. If module-level state (like the new flagConfigurationStore variables) persists between tests, this could cause test interdependencies. Verify that removing this reset doesn't cause tests to fail when run in different orders.

Suggested change
beforeEach(() => {
beforeEach(() => {
// Reset the module before each test to avoid shared module-level state between tests
jest.resetModules();

Copilot uses AI. Check for mistakes.
Comment on lines +188 to +196
if (createdAt) {
configuration.createdAt = createdAt;
}
if (format) {
configuration.format = format;
}
if (environment) {
configuration.environment = environment;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If some of these values were null or undefined, it would be an invalid configuration. It might be better to return defaults instead. This would also allow you to reuse the IUniversalFlagConfigResponse type from common.

So you could do something like this:

  const config: IUniversalFlagConfigResponse = {
    createdAt: createdAt ?? new Date().toISOString(),
    format: format ?? FormatEnum.SERVER,
    environment: environment ?? { name: 'UNKNOWN' },
    flags,
    banditReferences: reconstructBanditReferences() ?? {},
  };

  return JSON.stringify(config);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also related to this comment

Copy link
Contributor

@greghuels greghuels left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking, but I'd fall back to default values to prevent an invalid configuration object, and I'd also reuse the existing configuration type. See comment for more info.

@greghuels greghuels assigned aarsilv and unassigned sameerank Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants