Skip to content

Conversation

@talissoncosta
Copy link
Contributor

@talissoncosta talissoncosta commented Oct 24, 2025

Export FlagSource enum from all entry points to make it usable as both a type and runtime value in consumer code.

Previously, FlagSource was only exported as a type declaration, which prevented users from comparing against enum values like FlagSource.NONE in their code. Users had to use workarounds with string literals and type assertions.

Changes:

  • Export enum from flagsmith-core.ts
  • Re-export from types.d.ts referencing the real enum
  • Add FlagSource export to all entry points:
    • index.ts (web browser)
    • isomorphic.ts (SSR/universal)
    • index.react-native.ts (React Native)
    • next-middleware.ts (Next.js edge)

Users can now use:
import { FlagSource } from 'flagsmith';
if (loadingState.source === FlagSource.NONE) { ... }

Why Re-export from Each Entry Point?

Each entry point file (index.ts, isomorphic.ts, index.react-native.ts, next-middleware.ts) creates a separate JavaScript bundle via Rollup. Users import from different paths depending on their environment:

// These resolve to DIFFERENT bundles:
import { FlagSource } from 'flagsmith';            // → lib/flagsmith/index.js
import { FlagSource } from 'flagsmith/isomorphic'; // → lib/flagsmith/isomorphic.js
import { FlagSource } from 'flagsmith/react-native'; // → lib/react-native-flagsmith/index.js

The Problem Without Re-exports

When Rollup bundles each entry point, it only exports what that specific entry file explicitly exports:

// isomorphic.ts (without re-export)
import core from './flagsmith-core';
export default core({ ... });
// ❌ FlagSource is bundled but NOT exported

// Built file: lib/flagsmith/isomorphic.js
exports.default = flagsmith;
// FlagSource code exists in bundle but isn't exposed ❌

Result: SSR users would get an error:

import { FlagSource } from 'flagsmith/isomorphic';
//       ^^^^^^^^^^^ Error: Module has no exported member 'FlagSource'

The Solution: Explicit Re-exports

By adding export { FlagSource } from './flagsmith-core' to each entry point, the bundled files properly expose it:

// isomorphic.ts (with re-export)
import core from './flagsmith-core';
export default core({ ... });
export { FlagSource } from './flagsmith-core'; 

// Built file: lib/flagsmith/isomorphic.js
exports.default = flagsmith;
exports.FlagSource = { NONE: "NONE", ... }; 

Result: All users can access FlagSource regardless of which entry point they use.

Export FlagSource enum from all entry points to make it usable as both a type and runtime value in consumer code.

Previously, FlagSource was only exported as a type declaration, which prevented users from comparing against enum values like FlagSource.NONE in their code. Users had to use workarounds with string literals and type assertions.

Changes:
- Export enum from flagsmith-core.ts
- Re-export from types.d.ts referencing the real enum
- Add FlagSource export to all entry points:
  - index.ts (web browser)
  - isomorphic.ts (SSR/universal)
  - index.react-native.ts (React Native)
  - next-middleware.ts (Next.js edge)

Users can now use:
  import { FlagSource } from 'flagsmith';
  if (loadingState.source === FlagSource.NONE) { ... }
@talissoncosta talissoncosta requested a review from a team as a code owner October 24, 2025 21:09
@talissoncosta talissoncosta requested review from Zaimwa9 and removed request for a team October 24, 2025 21:09
@talissoncosta talissoncosta marked this pull request as draft October 24, 2025 21:09
@talissoncosta talissoncosta changed the title [WIP] fix: export FlagSource enum as runtime value fix: export FlagSource enum as runtime value Oct 24, 2025
@matthewelwell matthewelwell linked an issue Oct 27, 2025 that may be closed by this pull request
@talissoncosta talissoncosta marked this pull request as ready for review October 28, 2025 20:23
@talissoncosta
Copy link
Contributor Author

@Zaimwa9

I was considering adding those tests:

import { FlagSource } from '../index';
import { FlagSource as FlagSourceIso } from '../isomorphic';

describe('FlagSource Export', () => {

    test('should export FlagSource enum with all values', () => {
        expect(FlagSource).toBeDefined();
        expect(FlagSource.NONE).toBe('NONE');
        expect(FlagSource.DEFAULT_FLAGS).toBe('DEFAULT_FLAGS');
        expect(FlagSource.CACHE).toBe('CACHE');
        expect(FlagSource.SERVER).toBe('SERVER');
    });

    test('should be usable in runtime value comparisons', () => {
        const source = 'NONE' as string;

        expect(source === FlagSource.NONE).toBe(true);
        expect(source === FlagSource.CACHE).toBe(false);

        const mySource: FlagSource = FlagSource.NONE;
        expect(mySource).toBe('NONE');
    });

    test('should export FlagSource from all entry points', () => {
        expect(FlagSourceIso).toBeDefined();
        expect(FlagSourceIso.NONE).toBe('NONE');
        expect(FlagSource.NONE).toBe(FlagSourceIso.NONE);
    });
});

What do you think about it ?

Zaimwa9
Zaimwa9 previously approved these changes Oct 29, 2025
Copy link
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

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

Lgtm! Thanks

@matthewelwell matthewelwell merged commit d480bb9 into main Oct 29, 2025
1 check passed
@matthewelwell matthewelwell deleted the fix/flag-source-enum-export branch October 29, 2025 12:25
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.

Enum FlagSource not useable as value

4 participants