Skip to content

feat(flags): add flag dependencies support for local evaluation#2190

Closed
haacked wants to merge 8 commits intomainfrom
haacked/flag-dependencies-local-eval
Closed

feat(flags): add flag dependencies support for local evaluation#2190
haacked wants to merge 8 commits intomainfrom
haacked/flag-dependencies-local-eval

Conversation

@haacked
Copy link
Contributor

@haacked haacked commented Aug 6, 2025

Implement comprehensive flag dependency support allowing flags to depend on other flag evaluations with proper dependency resolution.

This is based on the posthog-python implementation.

Problem

We recently added support for flag dependencies (hidden behind a feature flag). We now need to add support for local evaluation.

Changes

Key features:

  • Dependency graph with cycle detection and topological sorting
  • Support for simple flag dependencies (true/false)
  • Support for variant-specific dependencies
  • Dependency chains and complex hierarchies
  • Graceful error handling and fallback mechanisms
  • Performance optimization through result caching
  • Full backward compatibility with existing flag evaluation

Components:

  • New DependencyGraph class with comprehensive graph operations
  • Updated FeatureFlagsPoller to integrate dependency-aware evaluation
  • Enhanced flag evaluation methods to handle dependencies
  • Comprehensive test suite with 95%+ code coverage

This enables complex feature flag configurations while maintaining performance and reliability for local evaluation scenarios.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react
  • @posthog/ai
  • @posthog/nextjs-config

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file
  • Added the "release" label to the PR to indicate we're publishing new versions for the affected packages

@vercel
Copy link

vercel bot commented Aug 6, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
posthog-js ✅ Ready (Inspect) Visit Preview Aug 8, 2025 0:41am

@github-actions
Copy link
Contributor

github-actions bot commented Aug 6, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Aug 6, 2025

Size Change: +51.4 kB (+1.08%)

Total Size: 4.82 MB

Filename Size Change
packages/node/dist/edge/index.cjs 95.4 kB +12.8 kB (+15.57%) ⚠️
packages/node/dist/edge/index.mjs 95.3 kB +12.8 kB (+15.59%) ⚠️
packages/node/dist/node/index.cjs 110 kB +12.8 kB (+13.2%) ⚠️
packages/node/dist/node/index.mjs 110 kB +12.8 kB (+13.21%) ⚠️
ℹ️ View Unchanged
Filename Size
packages/ai/dist/anthropic/index.cjs 11.1 kB
packages/ai/dist/anthropic/index.mjs 10.9 kB
packages/ai/dist/gemini/index.cjs 11.4 kB
packages/ai/dist/gemini/index.mjs 11.3 kB
packages/ai/dist/index.cjs 96.8 kB
packages/ai/dist/index.mjs 96.1 kB
packages/ai/dist/langchain/index.cjs 36.3 kB
packages/ai/dist/langchain/index.mjs 35.8 kB
packages/ai/dist/openai/index.cjs 20.7 kB
packages/ai/dist/openai/index.mjs 20.5 kB
packages/ai/dist/vercel/index.cjs 18 kB
packages/ai/dist/vercel/index.mjs 18 kB
packages/browser/dist/all-external-dependencies.js 221 kB
packages/browser/dist/array.full.es5.js 309 kB
packages/browser/dist/array.full.js 373 kB
packages/browser/dist/array.full.no-external.js 390 kB
packages/browser/dist/array.js 172 kB
packages/browser/dist/array.no-external.js 187 kB
packages/browser/dist/crisp-chat-integration.js 1.97 kB
packages/browser/dist/customizations.full.js 15.9 kB
packages/browser/dist/dead-clicks-autocapture.js 12.6 kB
packages/browser/dist/exception-autocapture.js 9.55 kB
packages/browser/dist/external-scripts-loader.js 2.57 kB
packages/browser/dist/intercom-integration.js 2.02 kB
packages/browser/dist/main.js 173 kB
packages/browser/dist/module.full.js 373 kB
packages/browser/dist/module.full.no-external.js 390 kB
packages/browser/dist/module.js 173 kB
packages/browser/dist/module.no-external.js 188 kB
packages/browser/dist/posthog-recorder.js 207 kB
packages/browser/dist/recorder-v2.js 113 kB
packages/browser/dist/recorder.js 113 kB
packages/browser/dist/surveys-preview.js 70.8 kB
packages/browser/dist/surveys.js 79.2 kB
packages/browser/dist/tracing-headers.js 1.81 kB
packages/browser/dist/web-vitals.js 10.4 kB
packages/browser/react/dist/esm/index.js 14.7 kB
packages/browser/react/dist/umd/index.js 17.3 kB
packages/core/dist/eventemitter.js 1.78 kB
packages/core/dist/eventemitter.mjs 571 B
packages/core/dist/featureFlagUtils.js 7.56 kB
packages/core/dist/featureFlagUtils.mjs 5.34 kB
packages/core/dist/gzip.js 1.95 kB
packages/core/dist/gzip.mjs 650 B
packages/core/dist/index.js 71.7 kB
packages/core/dist/index.mjs 60.3 kB
packages/core/dist/testing/index.js 2.93 kB
packages/core/dist/testing/index.mjs 79 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.5 kB
packages/core/dist/testing/PostHogCoreTestClient.mjs 2.11 kB
packages/core/dist/testing/test-utils.js 2.35 kB
packages/core/dist/testing/test-utils.mjs 783 B
packages/core/dist/types.js 7.67 kB
packages/core/dist/types.mjs 5.56 kB
packages/core/dist/utils.js 3.91 kB
packages/core/dist/utils.mjs 1.76 kB
packages/core/dist/vendor/uuidv7.js 8.57 kB
packages/core/dist/vendor/uuidv7.mjs 7 kB
packages/nextjs-config/dist/config.js 3.8 kB
packages/nextjs-config/dist/config.mjs 2.53 kB
packages/nextjs-config/dist/index.js 2.24 kB
packages/nextjs-config/dist/index.mjs 30 B
packages/nextjs-config/dist/utils.js 4.21 kB
packages/nextjs-config/dist/utils.mjs 2.29 kB
packages/nextjs-config/dist/utils.spec.js 723 B
packages/nextjs-config/dist/utils.spec.mjs 455 B
packages/nextjs-config/dist/webpack-plugin.js 4.41 kB
packages/nextjs-config/dist/webpack-plugin.mjs 2.66 kB
packages/react-native/dist/autocapture.js 4.68 kB
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB
packages/react-native/dist/hooks/useFeatureFlag.js 1.49 kB
packages/react-native/dist/hooks/useFeatureFlags.js 821 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.46 kB
packages/react-native/dist/hooks/usePostHog.js 467 B
packages/react-native/dist/index.js 3.12 kB
packages/react-native/dist/native-deps.js 12.2 kB
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B
packages/react-native/dist/optional/OptionalSessionReplay.js 455 B
packages/react-native/dist/posthog-rn.js 28.7 kB
packages/react-native/dist/PostHogContext.js 329 B
packages/react-native/dist/PostHogProvider.js 4.77 kB
packages/react-native/dist/storage.js 3.39 kB
packages/react-native/dist/surveys/components/BottomSection.js 1.34 kB
packages/react-native/dist/surveys/components/Cancel.js 909 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.63 kB
packages/react-native/dist/surveys/components/QuestionHeader.js 1.11 kB
packages/react-native/dist/surveys/components/QuestionTypes.js 10.1 kB
packages/react-native/dist/surveys/components/SurveyModal.js 3.95 kB
packages/react-native/dist/surveys/components/Surveys.js 6.17 kB
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 3.06 kB
packages/react-native/dist/surveys/icons.js 7.76 kB
packages/react-native/dist/surveys/index.js 600 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 5.61 kB
packages/react-native/dist/surveys/surveys-utils.js 5.59 kB
packages/react-native/dist/surveys/useActivatedSurveys.js 3.38 kB
packages/react-native/dist/surveys/useSurveyStorage.js 2.16 kB
packages/react-native/dist/types.js 70 B
packages/react-native/dist/version.js 129 B
packages/react/dist/esm/index.js 14.7 kB
packages/react/dist/umd/index.js 17.3 kB
packages/web/dist/index.cjs 13.8 kB
packages/web/dist/index.mjs 13.7 kB
tooling/rollup-utils/dist/index.js 1.17 kB

compressed-size-action

This comment was marked as outdated.

@haacked haacked force-pushed the haacked/flag-dependencies-local-eval branch from c65ec63 to ccded7b Compare August 6, 2025 19:46
@haacked haacked changed the base branch from main to haacked/compute-locally-refactoring August 6, 2025 19:47
@haacked haacked force-pushed the haacked/compute-locally-refactoring branch from 3e50a15 to 6ff7082 Compare August 6, 2025 19:50
Base automatically changed from haacked/compute-locally-refactoring to main August 6, 2025 20:47
@haacked haacked force-pushed the haacked/flag-dependencies-local-eval branch from ccded7b to b184867 Compare August 6, 2025 20:48
@haacked haacked force-pushed the haacked/flag-dependencies-local-eval branch from b184867 to 9ce849d Compare August 6, 2025 21:30
haacked added 3 commits August 7, 2025 15:37
Implement comprehensive flag dependency support allowing flags to depend on other flag evaluations with proper dependency resolution.

Key features:
- Dependency graph with cycle detection and topological sorting
- Support for simple flag dependencies (true/false)
- Support for variant-specific dependencies
- Dependency chains and complex hierarchies
- Graceful error handling and fallback mechanisms
- Performance optimization through result caching
- Full backward compatibility with existing flag evaluation

Components:
- New DependencyGraph class with comprehensive graph operations
- Updated FeatureFlagsPoller to integrate dependency-aware evaluation
- Enhanced flag evaluation methods to handle dependencies
- Comprehensive test suite with 95%+ code coverage

This enables complex feature flag configurations while maintaining performance and reliability for local evaluation scenarios.
The CI was failing because unit tests were running without building packages first. The posthog-js-lite and posthog-react-native packages generate their version.ts files during the prebuild step (which runs
before build), but the test:unit task had no dependencies in turbo.json.

This change makes test:unit depend on build, ensuring that:
- All packages are built before tests run
- The prebuild scripts generate required version.ts files
- Tests can successfully import the version modules

The issue was that version.ts files are generated by prebuild scripts but tests were running before build, causing "Cannot find module './version'" errors in CI.
- Rename remote-config-example.js to remote-config-demo.js for consistency
- Update both demos to use .env configuration instead of hardcoded values
- Add interactive index.js menu to select and run available demos
- Update README with streamlined setup instructions
- Add REMOTE_CONFIG_FLAG_KEY to .env.example for remote config demo
Copy link
Contributor

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 implements comprehensive flag dependency support for local evaluation in the PostHog Node.js SDK, allowing flags to depend on other flag evaluations with proper dependency resolution, cycle detection, and topological sorting.

Key changes:

  • Added dependency graph infrastructure with cycle detection and topological sorting
  • Updated feature flag evaluation to handle dependencies in correct order
  • Enhanced playground with interactive demos for testing flag dependencies

Reviewed Changes

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

Show a summary per file
File Description
turbo.json Adds build dependency for unit tests
playground/flags/* Complete overhaul of playground with dependency demos and improved structure
packages/node/src/extensions/feature-flags/dependency-graph.ts New dependency graph implementation with cycle detection
packages/node/src/extensions/feature-flags/feature-flags.ts Updated feature flag evaluation to support dependencies
packages/node/test/* Comprehensive test coverage for dependency functionality

…nts in integration tests

The integration tests were failing because custom events weren't being captured.
This was due to a race condition where the custom event button was clicked
before PostHog was fully initialized and ready to capture events.

Added await posthog.waitForLoaded() after posthog.init() to ensure PostHog
is completely loaded before attempting to capture custom events.
- Add FlagDependencyProperty type for better type constraints
- Add type guard in matchFlagProperty to ensure flag dependencies only
- Handle unexpected value types gracefully with clear warnings
- Convert non-FeatureFlagValue types to string with fallback logic
- Maintain backward compatibility while improving type safety
@posthog-bot
Copy link
Contributor

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the stale label – otherwise this will be closed in another week.

@haacked haacked closed this Aug 21, 2025
@haacked haacked deleted the haacked/flag-dependencies-local-eval branch August 21, 2025 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants