Skip to content

feat: add official PostHog OpenFeature server provider (Node)#3994

Open
gustavohstrassburger wants to merge 1 commit into
mainfrom
posthog-code/openfeature-provider
Open

feat: add official PostHog OpenFeature server provider (Node)#3994
gustavohstrassburger wants to merge 1 commit into
mainfrom
posthog-code/openfeature-provider

Conversation

@gustavohstrassburger

@gustavohstrassburger gustavohstrassburger commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Based on PostHog/posthog-python#695, adds @posthog/openfeature-node-provider — the official PostHog provider for the OpenFeature server SDK (@openfeature/server-sdk), backed by posthog-node.

Split into two PRs per review (@marandaneto: "could be 2 PRs tbh"). This PR is the server/Node provider; the web/browser provider (@posthog/openfeature-web-provider, backed by posthog-js) is in #4069.

OpenFeature ships two SDKs with incompatible Provider contracts — the server SDK is async with a per-call evaluation context (distinct id from targetingKey), versus the web SDK's synchronous, static-context model. So the two providers are separate packages, each pulling in only its own paradigm's SDK. The Python parent PR is server-only (no browser runtime); this pair covers both.

Behaviour

The server model is stateless and multi-user: the distinct id arrives per evaluation from the context's targetingKey, and resolution is async. Context mapping: targetingKeydistinctId, reserved groups/groupProperties → PostHog equivalents, every other attribute → personProperties.

Flag-type mapping (via getFeatureFlagResult): boolean → enabled, string → multivariate variant, number → parsed variant, object → JSON payload. A missing flag resolves to FLAG_NOT_FOUND; asking for a type the flag can't provide resolves to TYPE_MISMATCH (caller gets its default, per spec).

One deliberate divergence from Python: posthog-node's FeatureFlagResult has no reason field, so reason mapping simplifies to enabled ? TARGETING_MATCH : DEFAULT and there's no posthog_reason metadata.

Options

  • sendFeatureFlagEvents (default true) — control $feature_flag_called capture.
  • defaultDistinctId — when set, evaluations without a targetingKey use it instead of raising TARGETING_KEY_MISSING.

Publishing

Marked for release (changeset + entry in the release.yml publish matrix); created on npm under the @posthog scope on first publish, gated on the standard merge + NPM Release approval flow.

Docs

Usage lives in the PostHog docs (kept out of the package README so it doesn't drift): PostHog/posthog.com#18105/docs/feature-flags/installation/openfeature-js (covers both the node and web providers).

Testing

  • 20 unit tests (type mappings, error cases, context split, distinct-id resolution, initialize preload) + end-to-end tests through the real @openfeature/server-sdk client.
  • ✅ Build (rslib esm + cjs + declarations) · ✅ Lint · ✅ Tests · ✅ pnpm install --frozen-lockfile consistent

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat: add official PostHog OpenFeature p..." | Re-trigger Greptile

Comment thread packages/openfeature-web-provider/src/provider.ts
Comment thread packages/openfeature-provider/src/mapping.ts Outdated
Comment thread packages/openfeature-provider/src/__tests__/server-provider.spec.ts Outdated
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 17.1 MB

ℹ️ View Unchanged
Filename Size Change
packages/ai/dist/anthropic/index.cjs 28.2 kB 0 B
packages/ai/dist/anthropic/index.mjs 27.9 kB 0 B
packages/ai/dist/gemini/index.cjs 36.5 kB 0 B
packages/ai/dist/gemini/index.mjs 36.3 kB 0 B
packages/ai/dist/index.cjs 55.2 kB 0 B
packages/ai/dist/index.mjs 55.1 kB 0 B
packages/ai/dist/langchain/index.cjs 34.7 kB 0 B
packages/ai/dist/langchain/index.mjs 34.7 kB 0 B
packages/ai/dist/openai-agents/index.cjs 29.5 kB 0 B
packages/ai/dist/openai-agents/index.mjs 29.4 kB 0 B
packages/ai/dist/openai/index.cjs 78.9 kB 0 B
packages/ai/dist/openai/index.mjs 78.6 kB 0 B
packages/ai/dist/otel/index.cjs 17.2 kB 0 B
packages/ai/dist/otel/index.mjs 17.1 kB 0 B
packages/ai/dist/vercel/index.cjs 47.3 kB 0 B
packages/ai/dist/vercel/index.mjs 47.3 kB 0 B
packages/browser/dist/all-external-dependencies.js 237 kB 0 B
packages/browser/dist/array.full.es5.js 403 kB 0 B
packages/browser/dist/array.full.js 430 kB 0 B
packages/browser/dist/array.full.no-********.js 508 kB 0 B
packages/browser/dist/array.js 217 kB 0 B
packages/browser/dist/array.no-********.js 241 kB 0 B
packages/browser/dist/conversations.js 68.4 kB 0 B
packages/browser/dist/crisp-chat-integration.js 1.97 kB 0 B
packages/browser/dist/customizations.full.js 19.1 kB 0 B
packages/browser/dist/customizations.js 19.1 kB 0 B
packages/browser/dist/dead-clicks-autocapture.js 14.7 kB 0 B
packages/browser/dist/default-extensions.js 215 kB 0 B
packages/browser/dist/element-inference.js 5.69 kB 0 B
packages/browser/dist/exception-autocapture.js 11.8 kB 0 B
packages/browser/dist/extension-bundles.js 122 kB 0 B
packages/browser/dist/external-scripts-loader.js 3.11 kB 0 B
packages/browser/dist/intercom-integration.js 2.03 kB 0 B
packages/browser/dist/lazy-********.js 161 kB 0 B
packages/browser/dist/logs.js 4.35 kB 0 B
packages/browser/dist/main.js 222 kB 0 B
packages/browser/dist/module.full.js 433 kB 0 B
packages/browser/dist/module.full.no-********.js 511 kB 0 B
packages/browser/dist/module.js 221 kB 0 B
packages/browser/dist/module.no-********.js 244 kB 0 B
packages/browser/dist/module.slim.js 112 kB 0 B
packages/browser/dist/module.slim.no-********.js 119 kB 0 B
packages/browser/dist/posthog-********.js 161 kB 0 B
packages/browser/dist/product-tours-preview.js 76.6 kB 0 B
packages/browser/dist/product-tours.js 116 kB 0 B
packages/browser/dist/recorder-v2.js 106 kB 0 B
packages/browser/dist/recorder.js 106 kB 0 B
packages/browser/dist/rrweb-plugin-console-record.js 6.67 kB 0 B
packages/browser/dist/rrweb-types.js 2.33 kB 0 B
packages/browser/dist/rrweb.js 286 kB 0 B
packages/browser/dist/surveys-preview.js 78.3 kB 0 B
packages/browser/dist/surveys.js 97.2 kB 0 B
packages/browser/dist/tracing-headers.js 3.36 kB 0 B
packages/browser/dist/web-vitals-with-attribution.js 12.2 kB 0 B
packages/browser/dist/web-vitals.js 6.66 kB 0 B
packages/browser/react/dist/esm/index.js 21.1 kB 0 B
packages/browser/react/dist/esm/slim/index.js 17.5 kB 0 B
packages/browser/react/dist/esm/surveys/index.js 4.68 kB 0 B
packages/browser/react/dist/umd/index.js 24.4 kB 0 B
packages/browser/react/dist/umd/slim/index.js 20.3 kB 0 B
packages/browser/react/dist/umd/surveys/index.js 5.45 kB 0 B
packages/convex/dist/client/feature-flags/crypto.js 461 B 0 B
packages/convex/dist/client/feature-flags/evaluator.js 16.5 kB 0 B
packages/convex/dist/client/feature-flags/index.js 196 B 0 B
packages/convex/dist/client/feature-flags/match-********.js 14.8 kB 0 B
packages/convex/dist/client/feature-flags/types.js 44 B 0 B
packages/convex/dist/client/index.js 14.6 kB 0 B
packages/convex/dist/component/_generated/api.js 712 B 0 B
packages/convex/dist/component/_generated/component.js 212 B 0 B
packages/convex/dist/component/_generated/dataModel.js 230 B 0 B
packages/convex/dist/component/_generated/server.js 3.74 kB 0 B
packages/convex/dist/component/convex.config.js 1.66 kB 0 B
packages/convex/dist/component/crons.js 969 B 0 B
packages/convex/dist/component/lib.js 24.7 kB 0 B
packages/convex/dist/component/schema.js 1.17 kB 0 B
packages/convex/dist/component/version.js 68 B 0 B
packages/core/dist/cookie.js 5.34 kB 0 B
packages/core/dist/cookie.mjs 3.12 kB 0 B
packages/core/dist/error-tracking/chunk-ids.js 2.54 kB 0 B
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.3 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B 0 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.02 kB 0 B
packages/core/dist/error-tracking/coercers/error-coercer.mjs 794 B 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.js 1.76 kB 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 513 B 0 B
packages/core/dist/error-tracking/coercers/event-coercer.js 1.82 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B 0 B
packages/core/dist/error-tracking/coercers/index.js 6.79 kB 0 B
packages/core/dist/error-tracking/coercers/index.mjs 326 B 0 B
packages/core/dist/error-tracking/coercers/object-coercer.js 3.46 kB 0 B
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.07 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.67 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.59 kB 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 1.25 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.js 2.01 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B 0 B
packages/core/dist/error-tracking/coercers/utils.js 2.06 kB 0 B
packages/core/dist/error-tracking/coercers/utils.mjs 716 B 0 B
packages/core/dist/error-tracking/error-properties-builder.js 5.56 kB 0 B
packages/core/dist/error-tracking/error-properties-builder.mjs 4.23 kB 0 B
packages/core/dist/error-tracking/exception-steps.js 6.01 kB 0 B
packages/core/dist/error-tracking/exception-steps.mjs 3.84 kB 0 B
packages/core/dist/error-tracking/index.js 4.74 kB 0 B
packages/core/dist/error-tracking/index.mjs 191 B 0 B
packages/core/dist/error-tracking/parsers/base.js 1.83 kB 0 B
packages/core/dist/error-tracking/parsers/base.mjs 464 B 0 B
packages/core/dist/error-tracking/parsers/chrome.js 2.73 kB 0 B
packages/core/dist/error-tracking/parsers/chrome.mjs 1.32 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.js 2.47 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.mjs 1.13 kB 0 B
packages/core/dist/error-tracking/parsers/index.js 4.75 kB 0 B
packages/core/dist/error-tracking/parsers/index.mjs 2.1 kB 0 B
packages/core/dist/error-tracking/parsers/node.js 3.94 kB 0 B
packages/core/dist/error-tracking/parsers/node.mjs 2.68 kB 0 B
packages/core/dist/error-tracking/parsers/opera.js 2.26 kB 0 B
packages/core/dist/error-tracking/parsers/opera.mjs 746 B 0 B
packages/core/dist/error-tracking/parsers/safari.js 1.88 kB 0 B
packages/core/dist/error-tracking/parsers/safari.mjs 574 B 0 B
packages/core/dist/error-tracking/parsers/winjs.js 1.72 kB 0 B
packages/core/dist/error-tracking/parsers/winjs.mjs 426 B 0 B
packages/core/dist/error-tracking/types.js 1.33 kB 0 B
packages/core/dist/error-tracking/types.mjs 131 B 0 B
packages/core/dist/error-tracking/utils.js 1.8 kB 0 B
packages/core/dist/error-tracking/utils.mjs 604 B 0 B
packages/core/dist/eventemitter.js 1.78 kB 0 B
packages/core/dist/eventemitter.mjs 571 B 0 B
packages/core/dist/featureFlagUtils.js 6.42 kB 0 B
packages/core/dist/featureFlagUtils.mjs 3.99 kB 0 B
packages/core/dist/gzip.js 5.72 kB 0 B
packages/core/dist/gzip.mjs 3.84 kB 0 B
packages/core/dist/index.js 15.5 kB 0 B
packages/core/dist/index.mjs 1.52 kB 0 B
packages/core/dist/logs/index.js 10.9 kB 0 B
packages/core/dist/logs/index.mjs 9.22 kB 0 B
packages/core/dist/logs/logs-utils.js 7.01 kB 0 B
packages/core/dist/logs/logs-utils.mjs 4.85 kB 0 B
packages/core/dist/logs/types.js 603 B 0 B
packages/core/dist/logs/types.mjs 0 B 0 B 🆕
packages/core/dist/posthog-core-stateless.js 38.9 kB 0 B
packages/core/dist/posthog-core-stateless.mjs 35.7 kB 0 B
packages/core/dist/posthog-core.js 47.1 kB 0 B
packages/core/dist/posthog-core.mjs 41.7 kB 0 B
packages/core/dist/surveys/events.js 4.21 kB 0 B
packages/core/dist/surveys/events.mjs 1.99 kB 0 B
packages/core/dist/surveys/index.js 4.57 kB 0 B
packages/core/dist/surveys/index.mjs 894 B 0 B
packages/core/dist/surveys/translations.js 10 kB 0 B
packages/core/dist/surveys/translations.mjs 7.55 kB 0 B
packages/core/dist/surveys/validation.js 3.06 kB 0 B
packages/core/dist/surveys/validation.mjs 1.51 kB 0 B
packages/core/dist/testing/index.js 2.93 kB 0 B
packages/core/dist/testing/index.mjs 79 B 0 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.24 kB 0 B
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.83 kB 0 B
packages/core/dist/testing/test-utils.js 2.83 kB 0 B
packages/core/dist/testing/test-utils.mjs 1.15 kB 0 B
packages/core/dist/tracing-headers.js 3.38 kB 0 B
packages/core/dist/tracing-headers.mjs 2.08 kB 0 B
packages/core/dist/types.js 10 kB 0 B
packages/core/dist/types.mjs 7.28 kB 0 B
packages/core/dist/utils/bot-detection.js 3.28 kB 0 B
packages/core/dist/utils/bot-detection.mjs 1.95 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.js 3 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.mjs 1.62 kB 0 B
packages/core/dist/utils/index.js 13.5 kB 0 B
packages/core/dist/utils/index.mjs 2.4 kB 0 B
packages/core/dist/utils/logger.js 2.58 kB 0 B
packages/core/dist/utils/logger.mjs 1.29 kB 0 B
packages/core/dist/utils/number-utils.js 3.32 kB 0 B
packages/core/dist/utils/number-utils.mjs 1.68 kB 0 B
packages/core/dist/utils/promise-queue.js 2.48 kB 0 B
packages/core/dist/utils/promise-queue.mjs 1.25 kB 0 B
packages/core/dist/utils/string-utils.js 3.73 kB 0 B
packages/core/dist/utils/string-utils.mjs 1.97 kB 0 B
packages/core/dist/utils/type-utils.js 7.43 kB 0 B
packages/core/dist/utils/type-utils.mjs 3.28 kB 0 B
packages/core/dist/utils/user-agent-utils.js 17.7 kB 0 B
packages/core/dist/utils/user-agent-utils.mjs 14.2 kB 0 B
packages/core/dist/vendor/uuidv7.js 8.29 kB 0 B
packages/core/dist/vendor/uuidv7.mjs 6.72 kB 0 B
packages/mcp/dist/extensions/capture.js 3.67 kB 0 B
packages/mcp/dist/extensions/capture.mjs 2.23 kB 0 B
packages/mcp/dist/extensions/compatibility.js 5.63 kB 0 B
packages/mcp/dist/extensions/compatibility.mjs 3.79 kB 0 B
packages/mcp/dist/extensions/constants.js 4.64 kB 0 B
packages/mcp/dist/extensions/constants.mjs 2.39 kB 0 B
packages/mcp/dist/extensions/context-parameters.js 3.9 kB 0 B
packages/mcp/dist/extensions/context-parameters.mjs 2.11 kB 0 B
packages/mcp/dist/extensions/conversation-id.js 7.12 kB 0 B
packages/mcp/dist/extensions/conversation-id.mjs 4.21 kB 0 B
packages/mcp/dist/extensions/event-types.js 1.68 kB 0 B
packages/mcp/dist/extensions/event-types.mjs 459 B 0 B
packages/mcp/dist/extensions/exceptions.js 2.57 kB 0 B
packages/mcp/dist/extensions/exceptions.mjs 1.19 kB 0 B
packages/mcp/dist/extensions/ids.js 2.01 kB 0 B
packages/mcp/dist/extensions/ids.mjs 637 B 0 B
packages/mcp/dist/extensions/instrument-highlevel.js 11.3 kB 0 B
packages/mcp/dist/extensions/instrument-highlevel.mjs 8.71 kB 0 B
packages/mcp/dist/extensions/instrument-********.js 4.25 kB 0 B
packages/mcp/dist/extensions/instrument-********.mjs 2.43 kB 0 B
packages/mcp/dist/extensions/instrumentation.js 14.8 kB 0 B
packages/mcp/dist/extensions/instrumentation.mjs 10.6 kB 0 B
packages/mcp/dist/extensions/intent.js 3.31 kB 0 B
packages/mcp/dist/extensions/intent.mjs 1.68 kB 0 B
packages/mcp/dist/extensions/internal.js 6.39 kB 0 B
packages/mcp/dist/extensions/internal.mjs 4.14 kB 0 B
packages/mcp/dist/extensions/lib-********.js 1.6 kB 0 B
packages/mcp/dist/extensions/lib-********.mjs 267 B 0 B
packages/mcp/dist/extensions/logger.js 1.44 kB 0 B
packages/mcp/dist/extensions/logger.mjs 204 B 0 B
packages/mcp/dist/extensions/mcp-********.js 3.93 kB 0 B
packages/mcp/dist/extensions/mcp-********.mjs 2.56 kB 0 B
packages/mcp/dist/extensions/mcp-sdk-compat.js 4.08 kB 0 B
packages/mcp/dist/extensions/mcp-sdk-compat.mjs 2.22 kB 0 B
packages/mcp/dist/extensions/posthog-events.js 10.5 kB 0 B
packages/mcp/dist/extensions/posthog-events.mjs 7.13 kB 0 B
packages/mcp/dist/extensions/posthog-mcp.js 6.6 kB 0 B
packages/mcp/dist/extensions/posthog-mcp.mjs 4.69 kB 0 B
packages/mcp/dist/extensions/sanitization.js 4.04 kB 0 B
packages/mcp/dist/extensions/sanitization.mjs 2.46 kB 0 B
packages/mcp/dist/extensions/session.js 4.78 kB 0 B
packages/mcp/dist/extensions/session.mjs 2.67 kB 0 B
packages/mcp/dist/extensions/sink.js 4.38 kB 0 B
packages/mcp/dist/extensions/sink.mjs 2.54 kB 0 B
packages/mcp/dist/extensions/tools.js 3.5 kB 0 B
packages/mcp/dist/extensions/tools.mjs 1.61 kB 0 B
packages/mcp/dist/extensions/tracing-helpers.js 2.41 kB 0 B
packages/mcp/dist/extensions/tracing-helpers.mjs 772 B 0 B
packages/mcp/dist/extensions/truncation.js 11.2 kB 0 B
packages/mcp/dist/extensions/truncation.mjs 9.54 kB 0 B
packages/mcp/dist/index.js 7.72 kB 0 B
packages/mcp/dist/index.mjs 4.46 kB 0 B
packages/mcp/dist/types.js 603 B 0 B
packages/mcp/dist/types.mjs 0 B 0 B 🆕
packages/mcp/dist/version.js 1.21 kB 0 B
packages/mcp/dist/version.mjs 45 B 0 B
packages/next/dist/app/PostHogProvider.js 3.34 kB 0 B
packages/next/dist/client/ClientPostHogProvider.js 2.37 kB 0 B
packages/next/dist/client/hooks.js 172 B 0 B
packages/next/dist/client/PostHogPageView.js 1.76 kB 0 B
packages/next/dist/index.client.js 401 B 0 B
packages/next/dist/index.edge.js 570 B 0 B
packages/next/dist/index.js 548 B 0 B
packages/next/dist/index.react-server.js 420 B 0 B
packages/next/dist/middleware/postHogMiddleware.js 3.7 kB 0 B
packages/next/dist/pages.client.js 502 B 0 B
packages/next/dist/pages.edge.js 570 B 0 B
packages/next/dist/pages.js 414 B 0 B
packages/next/dist/pages/getServerSidePostHog.js 1.99 kB 0 B
packages/next/dist/pages/PostHogPageView.js 1.55 kB 0 B
packages/next/dist/pages/PostHogProvider.js 1.61 kB 0 B
packages/next/dist/server.edge.js 795 B 0 B
packages/next/dist/server/captureRequestError.js 5.26 kB 0 B
packages/next/dist/server/clientCache.edge.js 305 B 0 B
packages/next/dist/server/clientCache.js 1.27 kB 0 B
packages/next/dist/server/clientCache.node.js 305 B 0 B
packages/next/dist/server/getPostHog.js 2.79 kB 0 B
packages/next/dist/server/onRequestError.js 1.39 kB 0 B
packages/next/dist/server/onRequestError.types.js 59 B 0 B
packages/next/dist/shared/browser.js 195 B 0 B
packages/next/dist/shared/config.js 2.23 kB 0 B
packages/next/dist/shared/constants.js 201 B 0 B
packages/next/dist/shared/cookie.js 540 B 0 B
packages/next/dist/shared/identity.js 264 B 0 B
packages/next/dist/shared/tracing-headers.js 2.18 kB 0 B
packages/nextjs-config/dist/config.js 6.1 kB 0 B
packages/nextjs-config/dist/config.mjs 4.53 kB 0 B
packages/nextjs-config/dist/index.js 2.24 kB 0 B
packages/nextjs-config/dist/index.mjs 30 B 0 B
packages/nextjs-config/dist/strip-sourcemap-********.js 3.63 kB 0 B
packages/nextjs-config/dist/strip-sourcemap-********.mjs 1.77 kB 0 B
packages/nextjs-config/dist/utils.js 2.94 kB 0 B
packages/nextjs-config/dist/utils.mjs 826 B 0 B
packages/node/dist/client.js 50.4 kB 0 B
packages/node/dist/client.mjs 48 kB 0 B
packages/node/dist/entrypoints/index.edge.js 3.85 kB 0 B
packages/node/dist/entrypoints/index.edge.mjs 720 B 0 B
packages/node/dist/entrypoints/index.node.js 5.67 kB 0 B
packages/node/dist/entrypoints/index.node.mjs 1.25 kB 0 B
packages/node/dist/entrypoints/nestjs.js 2.31 kB 0 B
packages/node/dist/entrypoints/nestjs.mjs 42 B 0 B
packages/node/dist/experimental.js 870 B 0 B
packages/node/dist/experimental.mjs 267 B 0 B
packages/node/dist/exports.js 6.75 kB 0 B
packages/node/dist/exports.mjs 582 B 0 B
packages/node/dist/extensions/context/context.js 2.13 kB 0 B
packages/node/dist/extensions/context/context.mjs 863 B 0 B
packages/node/dist/extensions/context/types.js 603 B 0 B
packages/node/dist/extensions/context/types.mjs 0 B 0 B 🆕
packages/node/dist/extensions/error-tracking/autocapture.js 2.66 kB 0 B
packages/node/dist/extensions/error-tracking/autocapture.mjs 1.24 kB 0 B
packages/node/dist/extensions/error-tracking/index.js 4.17 kB 0 B
packages/node/dist/extensions/error-tracking/index.mjs 2.9 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 8.81 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 7.15 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.78 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.js 1.97 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs 624 B 0 B
packages/node/dist/extensions/express.js 4.97 kB 0 B
packages/node/dist/extensions/express.mjs 2.78 kB 0 B
packages/node/dist/extensions/feature-flags/cache.js 603 B 0 B
packages/node/dist/extensions/feature-flags/cache.mjs 0 B 0 B 🆕
packages/node/dist/extensions/feature-flags/crypto.js 1.57 kB 0 B
packages/node/dist/extensions/feature-flags/crypto.mjs 395 B 0 B
packages/node/dist/extensions/feature-flags/feature-flags.js 41 kB 0 B
packages/node/dist/extensions/feature-flags/feature-flags.mjs 38.9 kB 0 B
packages/node/dist/extensions/nestjs.js 5.36 kB 0 B
packages/node/dist/extensions/nestjs.mjs 3.18 kB 0 B
packages/node/dist/extensions/sentry-integration.js 4.66 kB 0 B
packages/node/dist/extensions/sentry-integration.mjs 3.17 kB 0 B
packages/node/dist/extensions/tracing-headers.js 3.31 kB 0 B
packages/node/dist/extensions/tracing-headers.mjs 1.53 kB 0 B
packages/node/dist/extensions/url-utils.js 2.22 kB 0 B
packages/node/dist/extensions/url-utils.mjs 785 B 0 B
packages/node/dist/feature-flag-evaluations.js 5.97 kB 0 B
packages/node/dist/feature-flag-evaluations.mjs 4.63 kB 0 B
packages/node/dist/storage-memory.js 1.52 kB 0 B
packages/node/dist/storage-memory.mjs 297 B 0 B
packages/node/dist/types.js 1.43 kB 0 B
packages/node/dist/types.mjs 224 B 0 B
packages/node/dist/version.js 1.21 kB 0 B
packages/node/dist/version.mjs 46 B 0 B
packages/nuxt/dist/module.mjs 5.35 kB 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 690 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagVariantKey.js 591 B 0 B
packages/nuxt/dist/runtime/composables/usePostHog.js 128 B 0 B
packages/nuxt/dist/runtime/nitro-plugin.js 1.08 kB 0 B
packages/nuxt/dist/runtime/vue-plugin.js 1.14 kB 0 B
packages/openfeature-node-provider/dist/index.js 1.76 kB 0 B
packages/openfeature-node-provider/dist/index.mjs 190 B 0 B
packages/openfeature-node-provider/dist/mapping.js 5.29 kB 0 B
packages/openfeature-node-provider/dist/mapping.mjs 3.18 kB 0 B
packages/openfeature-node-provider/dist/provider.js 3.84 kB 0 B
packages/openfeature-node-provider/dist/provider.mjs 2.45 kB 0 B
packages/openfeature-web-provider/dist/index.js 1.75 kB 0 B
packages/openfeature-web-provider/dist/index.mjs 184 B 0 B
packages/openfeature-web-provider/dist/mapping.js 5.29 kB 0 B
packages/openfeature-web-provider/dist/mapping.mjs 3.18 kB 0 B
packages/openfeature-web-provider/dist/provider.js 4.41 kB 0 B
packages/openfeature-web-provider/dist/provider.mjs 3.06 kB 0 B
packages/plugin-utils/dist/cli.js 3.14 kB 0 B
packages/plugin-utils/dist/cli.mjs 1.64 kB 0 B
packages/plugin-utils/dist/config.js 3.07 kB 0 B
packages/plugin-utils/dist/config.mjs 1.83 kB 0 B
packages/plugin-utils/dist/index.js 4.3 kB 0 B
packages/plugin-utils/dist/index.mjs 217 B 0 B
packages/plugin-utils/dist/spawn-local.js 2.17 kB 0 B
packages/plugin-utils/dist/spawn-local.mjs 918 B 0 B
packages/plugin-utils/dist/utils.js 3.27 kB 0 B
packages/plugin-utils/dist/utils.mjs 1.3 kB 0 B
packages/react-native/dist/autocapture.js 6.27 kB 0 B
packages/react-native/dist/error-tracking/index.js 9.97 kB 0 B
packages/react-native/dist/error-tracking/utils.js 2.58 kB 0 B
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB 0 B
packages/react-native/dist/hooks/useFeatureFlag.js 1.84 kB 0 B
packages/react-native/dist/hooks/useFeatureFlagResult.js 963 B 0 B
packages/react-native/dist/hooks/useFeatureFlags.js 921 B 0 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.45 kB 0 B
packages/react-native/dist/hooks/usePostHog.js 544 B 0 B
packages/react-native/dist/hooks/utils.js 988 B 0 B
packages/react-native/dist/index.js 4.33 kB 0 B
packages/react-native/dist/logs-********.js 3.66 kB 0 B
packages/react-native/dist/native-deps.js 8.73 kB 0 B
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B 0 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B 0 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B 0 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B 0 B
packages/react-native/dist/optional/OptionalPlugin.js 569 B 0 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSvg.js 872 B 0 B
packages/react-native/dist/posthog-rn.js 55 kB 0 B
packages/react-native/dist/PostHogContext.js 329 B 0 B
packages/react-native/dist/PostHogErrorBoundary.js 3.19 kB 0 B
packages/react-native/dist/PostHogMaskView.js 1.68 kB 0 B
packages/react-native/dist/PostHogProvider.js 4.55 kB 0 B
packages/react-native/dist/storage.js 5.76 kB 0 B
packages/react-native/dist/surveys/components/BottomSection.js 1.51 kB 0 B
packages/react-native/dist/surveys/components/Cancel.js 968 B 0 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.71 kB 0 B
packages/react-native/dist/surveys/components/QuestionHeader.js 1.43 kB 0 B
packages/react-native/dist/surveys/components/QuestionTypes.js 14 kB 0 B
packages/react-native/dist/surveys/components/SurveyModal.js 6.59 kB 0 B
packages/react-native/dist/surveys/components/Surveys.js 6.58 kB 0 B
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 2.64 kB 0 B
packages/react-native/dist/surveys/icons.js 10 kB 0 B
packages/react-native/dist/surveys/index.js 600 B 0 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 6.28 kB 0 B
packages/react-native/dist/surveys/safeStyleSheet.js 448 B 0 B
packages/react-native/dist/surveys/survey-translations.js 1.11 kB 0 B
packages/react-native/dist/surveys/surveys-utils.js 14.2 kB 0 B
packages/react-native/dist/surveys/useActivatedSurveys.js 3.67 kB 0 B
packages/react-native/dist/surveys/useSurveyStorage.js 2.16 kB 0 B
packages/react-native/dist/tooling/expoconfig.js 11.9 kB 0 B
packages/react-native/dist/tooling/metroconfig.js 2.32 kB 0 B
packages/react-native/dist/tooling/posthogMetroSerializer.js 4.86 kB 0 B
packages/react-native/dist/tooling/utils.js 4.05 kB 0 B
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 70 B 0 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 237 B 0 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.35 kB 0 B
packages/react-native/dist/types.js 70 B 0 B
packages/react-native/dist/utils.js 1.3 kB 0 B
packages/react-native/dist/version.js 130 B 0 B
packages/react/dist/esm/index.js 21.1 kB 0 B
packages/react/dist/esm/slim/index.js 17.5 kB 0 B
packages/react/dist/esm/surveys/index.js 4.68 kB 0 B
packages/react/dist/umd/index.js 24.4 kB 0 B
packages/react/dist/umd/slim/index.js 20.3 kB 0 B
packages/react/dist/umd/surveys/index.js 5.45 kB 0 B
packages/rollup-plugin/dist/index.js 2.44 kB 0 B
packages/rrweb/all/dist/rrweb-all.cjs 627 kB 0 B
packages/rrweb/all/dist/rrweb-all.js 626 kB 0 B
packages/rrweb/all/dist/rrweb-all.umd.cjs 629 kB 0 B
packages/rrweb/all/dist/rrweb-all.umd.min.cjs 297 kB 0 B
packages/rrweb/packer/dist/base-********.js 18.2 kB 0 B
packages/rrweb/packer/dist/base-********.cjs 18.3 kB 0 B
packages/rrweb/packer/dist/base-********.umd.cjs 18.7 kB 0 B
packages/rrweb/packer/dist/base-********.umd.min.cjs 9.5 kB 0 B
packages/rrweb/packer/dist/pack.cjs 347 B 0 B
packages/rrweb/packer/dist/pack.js 285 B 0 B
packages/rrweb/packer/dist/pack.umd.cjs 1.63 kB 0 B
packages/rrweb/packer/dist/pack.umd.min.cjs 1.11 kB 0 B
packages/rrweb/packer/dist/packer.cjs 257 B 0 B
packages/rrweb/packer/dist/packer.js 136 B 0 B
packages/rrweb/packer/dist/packer.umd.cjs 662 B 0 B
packages/rrweb/packer/dist/packer.umd.min.cjs 626 B 0 B
packages/rrweb/packer/dist/unpack.cjs 769 B 0 B
packages/rrweb/packer/dist/unpack.js 702 B 0 B
packages/rrweb/packer/dist/unpack.umd.cjs 1.17 kB 0 B
packages/rrweb/packer/dist/unpack.umd.min.cjs 955 B 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.cjs 37.6 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.js 37.5 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.cjs 38 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.min.cjs 22.2 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.cjs 34.3 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.js 34.2 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.cjs 34.7 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.min.cjs 20.5 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.cjs 14.9 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.js 14.8 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.cjs 15.4 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.min.cjs 7.33 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.cjs 5.01 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.js 4.9 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.cjs 5.44 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.min.cjs 2.64 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.cjs 681 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.js 548 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.cjs 1.12 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.min.cjs 829 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.cjs 933 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.js 820 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.cjs 1.37 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.min.cjs 968 B 0 B
packages/rrweb/record/dist/rrweb-record.cjs 186 kB 0 B
packages/rrweb/record/dist/rrweb-record.js 186 kB 0 B
packages/rrweb/record/dist/rrweb-record.umd.cjs 186 kB 0 B
packages/rrweb/record/dist/rrweb-record.umd.min.cjs 88.8 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.cjs 443 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.js 443 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.umd.cjs 445 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.umd.min.cjs 211 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.cjs 150 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.js 149 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.cjs 152 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.min.cjs 70.8 kB 0 B
packages/rrweb/rrdom/dist/rrdom.cjs 174 kB 0 B
packages/rrweb/rrdom/dist/rrdom.js 173 kB 0 B
packages/rrweb/rrdom/dist/rrdom.umd.cjs 175 kB 0 B
packages/rrweb/rrdom/dist/rrdom.umd.min.cjs 80.8 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.cjs 34.2 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.js 33.2 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.umd.cjs 55.5 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.umd.min.cjs 26.4 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.cjs 138 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.js 137 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.umd.cjs 161 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.umd.min.cjs 74 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.cjs 2.27 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.js 1.42 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.cjs 220 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.min.cjs 92.6 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.cjs 18.3 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.umd.cjs 18.8 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.umd.min.cjs 9.31 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.js 17.8 kB 0 B
packages/rrweb/rrweb/dist/rrweb.cjs 610 kB 0 B
packages/rrweb/rrweb/dist/rrweb.js 610 kB 0 B
packages/rrweb/rrweb/dist/rrweb.umd.cjs 610 kB 0 B
packages/rrweb/rrweb/dist/rrweb.umd.min.cjs 287 kB 0 B
packages/rrweb/types/dist/rrweb-types.cjs 5.75 kB 0 B
packages/rrweb/types/dist/rrweb-types.js 5.46 kB 0 B
packages/rrweb/types/dist/rrweb-types.umd.cjs 6.16 kB 0 B
packages/rrweb/types/dist/rrweb-types.umd.min.cjs 2.86 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.cjs 6.41 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.js 5.95 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.umd.cjs 6.82 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.umd.min.cjs 3.51 kB 0 B
packages/types/dist/capture-log.js 603 B 0 B
packages/types/dist/capture-log.mjs 0 B 0 B 🆕
packages/types/dist/capture.js 603 B 0 B
packages/types/dist/capture.mjs 0 B 0 B 🆕
packages/types/dist/common.js 603 B 0 B
packages/types/dist/common.mjs 0 B 0 B 🆕
packages/types/dist/feature-flags.js 603 B 0 B
packages/types/dist/feature-flags.mjs 0 B 0 B 🆕
packages/types/dist/index.js 603 B 0 B
packages/types/dist/index.mjs 0 B 0 B 🆕
packages/types/dist/posthog-config.js 603 B 0 B
packages/types/dist/posthog-config.mjs 0 B 0 B 🆕
packages/types/dist/posthog.js 603 B 0 B
packages/types/dist/posthog.mjs 0 B 0 B 🆕
packages/types/dist/request.js 603 B 0 B
packages/types/dist/request.mjs 0 B 0 B 🆕
packages/types/dist/segment.js 603 B 0 B
packages/types/dist/segment.mjs 0 B 0 B 🆕
packages/types/dist/session-recording.js 603 B 0 B
packages/types/dist/session-recording.mjs 0 B 0 B 🆕
packages/types/dist/survey.js 603 B 0 B
packages/types/dist/survey.mjs 0 B 0 B 🆕
packages/types/dist/toolbar.js 603 B 0 B
packages/types/dist/toolbar.mjs 0 B 0 B 🆕
packages/types/dist/tree-shakeable.js 603 B 0 B
packages/types/dist/tree-shakeable.mjs 0 B 0 B 🆕
packages/web/dist/index.cjs 14.1 kB 0 B
packages/web/dist/index.mjs 14 kB 0 B
packages/webpack-plugin/dist/config.js 1.47 kB 0 B
packages/webpack-plugin/dist/config.mjs 480 B 0 B
packages/webpack-plugin/dist/index.js 6.7 kB 0 B
packages/webpack-plugin/dist/index.mjs 2.94 kB 0 B
tooling/changelog/dist/index.js 3.31 kB 0 B
tooling/rollup-utils/dist/index.js 1.17 kB 0 B

compressed-size-action

@gustavohstrassburger gustavohstrassburger marked this pull request as draft June 26, 2026 15:55
@gustavohstrassburger gustavohstrassburger moved this to In Progress in Feature Flags Jul 1, 2026
gustavohstrassburger added a commit to PostHog/posthog.com that referenced this pull request Jul 1, 2026
Documents the two official PostHog OpenFeature providers for JavaScript
(@posthog/openfeature-node and @posthog/openfeature-web): installation,
usage, evaluation-context mapping, supported flag types, and options.

Companion to the posthog-js implementation PR (PostHog/posthog-js#3994),
mirroring the existing OpenFeature (Python) page.

Generated-By: PostHog Code
Task-Id: 46a3f8c9-fbcd-460e-9457-fca583955e5a
@gustavohstrassburger gustavohstrassburger marked this pull request as ready for review July 1, 2026 19:33
@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviews (2): Last reviewed commit: "refactor(openfeature): rename packages t..." | Re-trigger Greptile

@haacked haacked left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice addition! Two blocking issues inline: disabled flags throw instead of resolving to the default, and the node package's server-sdk peer range can't actually be satisfied. A few non-blocking suggestions too.

flagKey: string
): ResolutionDetails<string> {
const resolved = ensureResolved(result, flagKey)
if (resolved.variant === undefined) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: A disabled or unmatched flag ({ enabled: false, variant: undefined }) throws TypeMismatchError instead of resolving to the caller's default. OpenFeature's SDK catches the throw, sets errorCode: TYPE_MISMATCH and reason: ERROR, and fires every registered error hook. So a consumer with error hooks wired to their error tracker gets paged on every ordinary disabled-flag read.

The Python provider that this PR mirrors returns the caller's default with Reason.DEFAULT and no error in exactly this case, only raising TypeMismatchError when enabled is true. The identical bug exists in packages/openfeature-web-provider/src/mapping.ts. Neither provider.spec.ts has a test for disabled flags through these resolvers.

Add the !resolved.enabled guard before the throw in all three resolvers in both packages, and thread the caller's default value through:

 export function resolveStringDetails(
   result: PostHogFlagResult | undefined,
-  flagKey: string
+  flagKey: string,
+  defaultValue: string
 ): ResolutionDetails<string> {
   const resolved = ensureResolved(result, flagKey)
   if (resolved.variant === undefined) {
-    // A boolean flag has no string variant. Surface a type mismatch so the
-    // caller gets its default value (per the OpenFeature spec) rather than a
-    // surprising "true"/"false" string.
+    if (!resolved.enabled) {
+      return { value: defaultValue, reason: StandardResolutionReasons.DEFAULT }
+    }
+    // An enabled boolean flag has no string variant: this is a genuine mismatch.
     throw new TypeMismatchError(`Flag '${flagKey}' has no string variant (boolean flag).`)
   }
   return { value: resolved.variant, variant: resolved.variant, reason: reasonFor(resolved) }
 }

Apply the same guard in resolveNumberDetails (before the variant === undefined throw) and resolveObjectDetails (before the payload-type throw). Pass _defaultValue through at the call sites in both provider.ts files. Add disabled-flag cases to each it.each table asserting reason: DEFAULT and no errorCode.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7fffb7c (node) and 85f34db (web) — added the !resolved.enabled guard to all three resolvers, so a disabled/unmatched flag resolves to the caller's default with reason: DEFAULT instead of throwing. Threaded the default value through resolveString/Number/Object and their provider.ts call sites. Added disabled-flag test cases asserting reason: DEFAULT and no errorCode.

"@openfeature/core": "^1.11.0",
"@openfeature/server-sdk": "^1.7.0",
"posthog-node": ">=5.21.2"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: The @openfeature/server-sdk@^1.7.0 lower bound conflicts with the @openfeature/core@^1.11.0 peer declared above. Every server-sdk version from 1.7.0 through 1.16.x requires @openfeature/core below 1.11.0, so no single installed version satisfies both constraints. A consumer on any server-sdk in that range hits an ERESOLVE failure on npm or yarn install; pnpm only warns unless strict-peer-dependencies is set.

server-sdk@1.17.0 is the first version whose own core peer (^1.6.0) overlaps with 1.11.0:

   "peerDependencies": {
     "@openfeature/core": "^1.11.0",
-    "@openfeature/server-sdk": "^1.7.0",
+    "@openfeature/server-sdk": "^1.17.0",
     "posthog-node": ">=5.21.2"
   },

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7fffb7c — bumped the @openfeature/server-sdk peer floor to ^1.17.0, the first version whose own @openfeature/core peer overlaps ^1.11.0.

}

async onContextChange(_oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> {
await this._reconcile(newContext)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: onContextChange reconciles on every call even when the context is unchanged. @openfeature/web-sdk's setContext runs the provider's handler on every call with no equality check, and _reconcile doesn't diff against the previous context either. So a host that re-sets an equivalent context (a React integration passing a freshly-constructed object on every render, say) triggers a $groupidentify event and a reloadFeatureFlags() request on every call, since consecutive calls are typically more than 5ms apart and don't fold into the SDK's debounce.

Diff newContext against the previous context and skip reconciliation when nothing changed:

async onContextChange(oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> {
  if (contextsEqual(oldContext, newContext)) {
    return
  }
  await this._reconcile(newContext)
}

groupProperties is nested, so this needs a deep compare, not a shallow one. initialize() should keep calling _reconcile unconditionally since first load always needs it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed on the web PR #4069 in 85f34dbonContextChange now deep-compares old vs new context (handling nested groupProperties) and skips reconciliation when nothing changed. initialize() still reconciles unconditionally.

try {
await this._client.reloadFeatureFlags()
} catch {
// Intentionally ignored: remote evaluation remains available.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This swallows every preload error with no log, not just the documented no-personalApiKey no-op case. A genuine misconfiguration during reloadFeatureFlags() (bad host, network failure) disappears silently, so a user whose local evaluation never warms up has no visibility. The Python reference that this PR mirrors logs a warning with the exception in the equivalent spot.

     try {
       await this._client.reloadFeatureFlags()
-    } catch {
-      // Intentionally ignored: remote evaluation remains available.
+    } catch (err) {
+      // Remote evaluation still works, so don't block readiness, but surface
+      // the failure so a real misconfiguration isn't invisible.
+      console.warn('[PostHogServerProvider] initialize() flag preload failed; remote evaluation still available.', err)
     }

no-console is already disabled for this package in .eslintrc.cjs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7fffb7cinitialize() now console.warns on a preload failure (with the error) instead of swallowing it, so a genuine misconfiguration on a client set up for local evaluation is visible. Remote evaluation still works, so readiness isn't blocked.

})

it.each<[string, FlagResult | undefined, Resolve, ErrorCode]>([
[

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This table only covers a string read on a boolean flag and a missing flag. The node package's equivalent table also has a "number from a non-numeric variant" case and an "object from a non-object payload" case, exercising resolveNumberDetails's !Number.isFinite throw and resolveObjectDetails's non-object-payload throw. Neither branch is exercised here, so a regression in either check on the web side ships silently.

Add the two missing rows, mirroring the node spec:

[
  'number from a non-numeric variant',
  { key: 'flag', enabled: true, variant: 'not-a-number' },
  (p) => p.resolveNumberEvaluation('flag', 0),
  ErrorCode.TYPE_MISMATCH,
],
[
  'object from a non-object payload',
  { key: 'flag', enabled: true, variant: 'x', payload: 'not-an-object' },
  (p) => p.resolveObjectEvaluation('flag', {}),
  ErrorCode.TYPE_MISMATCH,
],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed on the web PR #4069 in 85f34db — added the missing number from a non-numeric variant and object from a non-object payload cases (plus disabled-flag cases) to the parameterised tables.

@@ -0,0 +1,150 @@
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question: This file is identical to openfeature-node-provider/src/mapping.ts apart from two words in the header comment, and imports only from @openfeature/core, not from posthog-js, posthog-node, or any runtime SDK. So the dependency-isolation argument that justifies splitting the providers into two packages doesn't apply to the mapping layer: a shared internal module would peer on @openfeature/core, which both already require, adding no extra peer constraints. The concrete cost of duplication is drift: the disabled-flag type-mismatch bug exists identically in both files, and any fix lands twice and stays in sync.

Was a shared internal module considered and set aside deliberately? The likely counter-argument is that with bundle: false in both rslib.config.ts, extracting means either publishing a third @posthog/openfeature-* package or setting bundle: true here, which would deviate from the @posthog/mcp convention these packages otherwise follow. For 150 lines with two consumers that's a defensible tradeoff, just want to confirm it was weighed rather than copy-paste.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Considered and set aside deliberately. With bundle: false (the @posthog/mcp convention both packages follow), sharing the mapping means either publishing a third @posthog/openfeature-* package or switching to bundle: true — both deviate from convention for ~150 lines. We accept the duplication; the drift risk you flagged (the disabled-flag bug) is now fixed in both packages in lockstep (7fffb7c / 85f34db). Happy to revisit if a third consumer appears.

"package": "pnpm pack --out $PACKAGE_DEST/%s.tgz"
},
"files": [
"dist/"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: No engines block here, while the node provider and every other sibling package (@posthog/mcp, @posthog/nextjs-config, @posthog/nuxt) declare one despite targeting the web. Without it, consumers on unsupported Node versions get no install-time warning when building or testing this package.

     "package": "pnpm pack --out $PACKAGE_DEST/%s.tgz"
   },
+  "engines": {
+    "node": "^20.20.0 || >=22.22.0"
+  },
   "files": [
     "dist/"
   ],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed on the web PR #4069 in 85f34db — added an engines block (^20.20.0 || >=22.22.0) matching the node package.

let subscribed = false

const finish = (): void => {
if (settled) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: finish references timer and unsubscribe before either const below it is declared. It works today only because finish never actually runs until after both are assigned, so a future edit that lets it run earlier would hit a temporal-dead-zone throw instead of a type error. Declaring unsubscribe and timer above finish would let the closure read top-to-bottom.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed on the web PR #4069 in 85f34db — restructured _reloadFlags to collect cleanups in an array declared above finish, so the closure no longer forward-references timer/unsubscribe.

Comment thread .changeset/openfeature-providers.md Outdated
Comment on lines +2 to +3
'@posthog/openfeature-node-provider': minor
'@posthog/openfeature-web-provider': minor

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

could be 2 PRs tbh

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — split into two PRs. This one (#3994) now ships only the server provider (@posthog/openfeature-node-provider); the web provider (@posthog/openfeature-web-provider) moved to #4069. Each has its own changeset and release-matrix entry.

@marandaneto

Copy link
Copy Markdown
Member

@marandaneto

Copy link
Copy Markdown
Member

also append to https://github.com/PostHog/posthog-js#packages

@marandaneto

Copy link
Copy Markdown
Member

@marandaneto

Copy link
Copy Markdown
Member

can we add examples to https://github.com/PostHog/posthog-js/tree/main/examples so we know/can test this outside unit tests? or extend one of our examples for node/web

@gustavohstrassburger gustavohstrassburger moved this from In Review to In Progress in Feature Flags Jul 3, 2026
gustavohstrassburger added a commit that referenced this pull request Jul 3, 2026
Official PostHog provider for the OpenFeature web SDK (@openfeature/web-sdk),
backed by posthog-js. Split out from the combined providers PR per review
(marandaneto) — the server provider (@posthog/openfeature-node-provider)
ships in #3994.

The browser model is single-user and synchronous: posthog-js owns the user
identity and holds flags in memory, so evaluation is synchronous and the
static evaluation context is reconciled into the SDK on
initialize()/onContextChange(). Resolves booleans from `enabled`, strings
from the multivariate variant, numbers from the parsed variant, and objects
from the JSON payload; missing flag -> FLAG_NOT_FOUND, wrong type ->
TYPE_MISMATCH.

Not published yet at the workflow level beyond being wired into the release
matrix and carrying a changeset; publishing still requires the standard
merge + NPM Release approval flow.

Generated-By: PostHog Code
Task-Id: 46a3f8c9-fbcd-460e-9457-fca583955e5a
@gustavohstrassburger gustavohstrassburger changed the title feat: add official PostHog OpenFeature providers (server + web) feat: add official PostHog OpenFeature server provider (Node) Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@marandaneto addressed your follow-ups:

@gustavohstrassburger gustavohstrassburger moved this from In Progress to In Review in Feature Flags Jul 3, 2026
gustavohstrassburger added a commit that referenced this pull request Jul 6, 2026
* feat(openfeature): add web provider (@posthog/openfeature-web-provider)

Official PostHog provider for the OpenFeature web SDK (@openfeature/web-sdk),
backed by posthog-js. Split out from the combined providers PR per review
(marandaneto) — the server provider (@posthog/openfeature-node-provider)
ships in #3994.

The browser model is single-user and synchronous: posthog-js owns the user
identity and holds flags in memory, so evaluation is synchronous and the
static evaluation context is reconciled into the SDK on
initialize()/onContextChange(). Resolves booleans from `enabled`, strings
from the multivariate variant, numbers from the parsed variant, and objects
from the JSON payload; missing flag -> FLAG_NOT_FOUND, wrong type ->
TYPE_MISMATCH.

Not published yet at the workflow level beyond being wired into the release
matrix and carrying a changeset; publishing still requires the standard
merge + NPM Release approval flow.

Generated-By: PostHog Code
Task-Id: 46a3f8c9-fbcd-460e-9457-fca583955e5a

* fix(openfeature-web): address review feedback (haacked, Greptile, manoel)

Provider/mapping fixes (haacked):
- Disabled or unmatched flags now resolve to the caller's default with
  reason=DEFAULT instead of throwing TypeMismatchError (which set reason=ERROR
  and fired error hooks on every ordinary disabled-flag read). Threaded the
  default value through resolveString/Number/Object.
- onContextChange now deep-compares old vs new context and skips reconciliation
  (group()/reloadFeatureFlags()) when nothing changed.
- Added an engines block.
- Restructured _reloadFlags so the cleanup closure no longer references
  timer/unsubscribe before their declarations (temporal-dead-zone fragility).

Tests:
- Added disabled-flag resolution cases (reason=DEFAULT, no errorCode) and the
  missing number/object TypeMismatchError branches to the parameterised tables.
- Converted the reload-timeout test to fake timers (Greptile) so it's
  deterministic and instant instead of waiting on real wall-clock time.

Repo wiring (manoel):
- Listed the package in the root README and CHANGELOG package lists and the PR
  template's "Libraries affected" checklist.
- Added examples/example-openfeature-web (Vite) demonstrating the provider.

Generated-By: PostHog Code
Task-Id: 46a3f8c9-fbcd-460e-9457-fca583955e5a
Rebuilt on top of current main after the web provider (#4069) merged, resolving conflicts in the shared registration files by adding the node entries alongside the now-merged web entries.

Adds @posthog/openfeature-node-provider (OpenFeature server SDK, backed by posthog-node), an example (examples/example-openfeature-node), a changeset, and registration entries. Includes review fixes: disabled/unmatched flags resolve to the caller's default with reason=DEFAULT instead of throwing; @openfeature/server-sdk peer floor raised to ^1.17.0; initialize() logs a warning on preload failure.
@gustavohstrassburger gustavohstrassburger force-pushed the posthog-code/openfeature-provider branch from 7fffb7c to 92704a5 Compare July 7, 2026 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

3 participants