posthog-node 5.21.1 → 5.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { JsonType, PostHogCoreStateless, PostHogFetchOptions, PostHogFetchResponse, PostHogFlagsAndPayloadsResponse, PostHogPersistedProperty, PostHogCaptureOptions } from '@posthog/core';
2
- import { EventMessage, GroupIdentifyMessage, IdentifyMessage, IPostHog, OverrideFeatureFlagsOptions, PostHogOptions } from './types';
3
- import { FeatureFlagValue } from '@posthog/core';
1
+ import { FeatureFlagValue, JsonType, PostHogCaptureOptions, PostHogCoreStateless, PostHogFetchOptions, PostHogFetchResponse, PostHogFlagsAndPayloadsResponse, PostHogPersistedProperty } from '@posthog/core';
2
+ import { EventMessage, FeatureFlagResult, GroupIdentifyMessage, IdentifyMessage, IPostHog, OverrideFeatureFlagsOptions, PostHogOptions } from './types';
4
3
  import ErrorTracking from './extensions/error-tracking';
5
4
  import { PostHogEventProperties } from '@posthog/core';
6
5
  import { ContextData, ContextOptions, IPostHogContext } from './extensions/context/types';
@@ -395,6 +394,17 @@ export declare abstract class PostHogBackendClient extends PostHogCoreStateless
395
394
  * @returns Promise that resolves to true if ready, false if timed out
396
395
  */
397
396
  waitForLocalEvaluationReady(timeoutMs?: number): Promise<boolean>;
397
+ /**
398
+ * Internal method that handles feature flag evaluation with full details.
399
+ * Used by getFeatureFlag, getFeatureFlagPayload, and getFeatureFlagResult.
400
+ *
401
+ * @param key - The feature flag key
402
+ * @param distinctId - The user's distinct ID
403
+ * @param options - Evaluation options (includes sendFeatureFlagEvents, defaults to true)
404
+ * @param matchValue - Optional match value for payload lookup (used by getFeatureFlagPayload)
405
+ * @returns Promise that resolves to the flag result or undefined
406
+ */
407
+ private _getFeatureFlagResult;
398
408
  /**
399
409
  * Get the value of a feature flag for a specific user.
400
410
  *
@@ -488,6 +498,45 @@ export declare abstract class PostHogBackendClient extends PostHogCoreStateless
488
498
  sendFeatureFlagEvents?: boolean;
489
499
  disableGeoip?: boolean;
490
500
  }): Promise<JsonType | undefined>;
501
+ /**
502
+ * Get the result of evaluating a feature flag, including its value and payload.
503
+ * This is more efficient than calling getFeatureFlag and getFeatureFlagPayload separately when you need both.
504
+ *
505
+ * @example
506
+ * ```ts
507
+ * // Get flag result
508
+ * const result = await client.getFeatureFlagResult('my-flag', 'user_123')
509
+ * if (result) {
510
+ * console.log('Flag enabled:', result.enabled)
511
+ * console.log('Variant:', result.variant)
512
+ * console.log('Payload:', result.payload)
513
+ * }
514
+ * ```
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * // With groups and properties
519
+ * const result = await client.getFeatureFlagResult('org-feature', 'user_123', {
520
+ * groups: { organization: 'acme-corp' },
521
+ * personProperties: { plan: 'enterprise' }
522
+ * })
523
+ * ```
524
+ *
525
+ * {@label Feature flags}
526
+ *
527
+ * @param key - The feature flag key
528
+ * @param distinctId - The user's distinct ID
529
+ * @param options - Optional configuration for flag evaluation
530
+ * @returns Promise that resolves to the flag result or undefined
531
+ */
532
+ getFeatureFlagResult(key: string, distinctId: string, options?: {
533
+ groups?: Record<string, string>;
534
+ personProperties?: Record<string, string>;
535
+ groupProperties?: Record<string, Record<string, string>>;
536
+ onlyEvaluateLocally?: boolean;
537
+ sendFeatureFlagEvents?: boolean;
538
+ disableGeoip?: boolean;
539
+ }): Promise<FeatureFlagResult | undefined>;
491
540
  /**
492
541
  * Get the remote config payload for a feature flag.
493
542
  *
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,QAAQ,EACR,oBAAoB,EAEpB,mBAAmB,EACnB,oBAAoB,EACpB,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EAGtB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,YAAY,EAIZ,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACR,2BAA2B,EAC3B,cAAc,EAEf,MAAM,SAAS,CAAA;AAChB,OAAO,EAAqB,gBAAgB,EAAuB,MAAM,eAAe,CAAA;AAMxF,OAAO,aAAa,MAAM,6BAA6B,CAAA;AACvD,OAAO,EAAkB,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAGtE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AASzF,8BAAsB,oBAAqB,SAAQ,oBAAqB,YAAW,QAAQ;IACzF,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,kBAAkB,CAAC,CAAoB;IAC/C,SAAS,CAAC,aAAa,EAAE,aAAa,CAAA;IACtC,OAAO,CAAC,YAAY,CAAQ;IAC5B,SAAgB,OAAO,EAAE,cAAc,CAAA;IACvC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAA;IAG5C,OAAO,CAAC,cAAc,CAAC,CAAkC;IACzD,OAAO,CAAC,iBAAiB,CAAC,CAA0B;IAEpD,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;gBACS,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;IA+CxD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,oBAAoB,CAAC,GAAG,EAAE,wBAAwB,GAAG,GAAG,GAAG,SAAS;IAIpE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,oBAAoB,CAAC,GAAG,EAAE,wBAAwB,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;IAI5E;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAI/E;;;;;;;;;;;;;OAaG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;;;;;;;;;;;;OAaG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;;;;;;;;;;;OAaG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;;;;;;;;;;;OAaG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CAAC,OAAO,GAAE,OAAc,GAAG,IAAI;IAKpC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAqBlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACG,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,QAAQ,CAAC,EAAE,UAAU,EAAE,UAAe,EAAE,YAAY,EAAE,EAAE,eAAe,GAAG,IAAI;IAc9E;;;;;;;;;;;;;;;;;;;OAmBG;IACG,iBAAiB,CAAC,EAAE,UAAU,EAAE,UAAe,EAAE,YAAY,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IActG;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAIhF;;;;;;;;;;;;;;;;OAgBG;IACG,cAAc,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxG;;;;;;;;;;;;;;;;;;OAkBG;IACH,sBAAsB,IAAI,OAAO;IAIjC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,2BAA2B,CAAC,SAAS,GAAE,MAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAuBvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACG,cAAc,CAClB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACxD,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;QAC/B,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,GACA,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IA+HxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACG,qBAAqB,CACzB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,gBAAgB,EAC7B,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACxD,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,4FAA4F;QAC5F,qBAAqB,CAAC,EAAE,OAAO,CAAA;QAC/B,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,GACA,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAwEhC;;;;;;;;;;;;;;;;;OAiBG;IACG,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IA0B5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACG,gBAAgB,CACpB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACxD,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;QAC/B,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,GACA,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAQ/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACG,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACxD,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KACpB,GACA,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAK5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACG,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACxD,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KACpB,GACA,OAAO,CAAC,+BAA+B,CAAC;IAwE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,aAAa,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,oBAAoB,GAAG,IAAI;IAIxG;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,oBAAoB,CAAC,SAAS,EAAE,2BAA2B,GAAG,IAAI;IAyClE;;;;;;OAMG;IACH,OAAO,CAAC,6BAA6B;IAoCrC,SAAS,CAAC,QAAQ,CAAC,iBAAiB,IAAI,eAAe,GAAG,SAAS;IAEnE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,CAAC;IASpF;;;;;;;;;;;;;;;OAeG;IACH,UAAU,IAAI,WAAW,GAAG,SAAS;IAIrC;;;;;;;;;;;;;;;;;;;OAmBG;IACG,SAAS,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAM5C,2BAA2B;IAqCzC,OAAO,CAAC,0BAA0B;YA+BpB,uBAAuB;IAkErC,OAAO,CAAC,gCAAgC;IAqBxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,gBAAgB,CACd,KAAK,EAAE,OAAO,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EACnD,IAAI,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,GAC1B,IAAI;IAWP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACG,yBAAyB,CAC7B,KAAK,EAAE,OAAO,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC;IAWH,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAC7D,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,sBAAsB,CAAA;QAClC,OAAO,EAAE,qBAAqB,CAAA;KAC/B,CAAC;IAiHF,OAAO,CAAC,cAAc;CAuBvB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -175,21 +175,56 @@ class PostHogBackendClient extends core_namespaceObject.PostHogCoreStateless {
175
175
  });
176
176
  });
177
177
  }
178
- async getFeatureFlag(key, distinctId, options) {
179
- if (void 0 !== this._flagOverrides && key in this._flagOverrides) return this._flagOverrides[key];
180
- const { groups, disableGeoip } = options || {};
181
- let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {};
178
+ async _getFeatureFlagResult(key, distinctId, options = {}, matchValue) {
179
+ const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true;
180
+ if (void 0 !== this._flagOverrides && key in this._flagOverrides) {
181
+ const overrideValue = this._flagOverrides[key];
182
+ if (void 0 === overrideValue) return;
183
+ const overridePayload = this._payloadOverrides?.[key];
184
+ return {
185
+ key,
186
+ enabled: false !== overrideValue,
187
+ variant: 'string' == typeof overrideValue ? overrideValue : void 0,
188
+ payload: overridePayload
189
+ };
190
+ }
191
+ const { groups, disableGeoip } = options;
192
+ let { onlyEvaluateLocally, personProperties, groupProperties } = options;
182
193
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
183
194
  personProperties = adjustedProperties.allPersonProperties;
184
195
  groupProperties = adjustedProperties.allGroupProperties;
185
196
  if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
186
- if (void 0 == sendFeatureFlagEvents) sendFeatureFlagEvents = this.options.sendFeatureFlagEvent ?? true;
187
- let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
188
- const flagWasLocallyEvaluated = void 0 !== response;
197
+ let result;
198
+ let flagWasLocallyEvaluated = false;
189
199
  let requestId;
190
200
  let evaluatedAt;
191
- let flagDetail;
192
201
  let featureFlagError;
202
+ let flagId;
203
+ let flagVersion;
204
+ let flagReason;
205
+ const localEvaluationEnabled = void 0 !== this.featureFlagsPoller;
206
+ if (localEvaluationEnabled) {
207
+ await this.featureFlagsPoller?.loadFeatureFlags();
208
+ const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
209
+ if (flag) try {
210
+ const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, matchValue);
211
+ if (localResult) {
212
+ flagWasLocallyEvaluated = true;
213
+ const value = localResult.value;
214
+ flagId = flag.id;
215
+ flagReason = 'Evaluated locally';
216
+ result = {
217
+ key,
218
+ enabled: false !== value,
219
+ variant: 'string' == typeof value ? value : void 0,
220
+ payload: localResult.payload ?? void 0
221
+ };
222
+ }
223
+ } catch (e) {
224
+ if (e instanceof feature_flags_js_namespaceObject.RequiresServerEvaluation || e instanceof feature_flags_js_namespaceObject.InconclusiveMatchError) this._logger?.info(`${e.name} when computing flag locally: ${key}: ${e.message}`);
225
+ else throw e;
226
+ }
227
+ }
193
228
  if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
194
229
  const flagsResponse = await super.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
195
230
  key
@@ -201,68 +236,87 @@ class PostHogBackendClient extends core_namespaceObject.PostHogCoreStateless {
201
236
  const errors = [];
202
237
  if (flagsResponse.errorsWhileComputingFlags) errors.push(external_types_js_namespaceObject.FeatureFlagError.ERRORS_WHILE_COMPUTING);
203
238
  if (flagsResponse.quotaLimited?.includes('feature_flags')) errors.push(external_types_js_namespaceObject.FeatureFlagError.QUOTA_LIMITED);
204
- flagDetail = flagsResponse.flags[key];
239
+ const flagDetail = flagsResponse.flags[key];
205
240
  if (void 0 === flagDetail) errors.push(external_types_js_namespaceObject.FeatureFlagError.FLAG_MISSING);
241
+ else {
242
+ flagId = flagDetail.metadata?.id;
243
+ flagVersion = flagDetail.metadata?.version;
244
+ flagReason = flagDetail.reason?.description ?? flagDetail.reason?.code;
245
+ let parsedPayload;
246
+ if (flagDetail.metadata?.payload !== void 0) try {
247
+ parsedPayload = JSON.parse(flagDetail.metadata.payload);
248
+ } catch {
249
+ parsedPayload = flagDetail.metadata.payload;
250
+ }
251
+ result = {
252
+ key,
253
+ enabled: flagDetail.enabled,
254
+ variant: flagDetail.variant,
255
+ payload: parsedPayload
256
+ };
257
+ }
206
258
  if (errors.length > 0) featureFlagError = errors.join(',');
207
- response = (0, core_namespaceObject.getFeatureFlagValue)(flagDetail);
208
259
  }
209
260
  }
210
- const featureFlagReportedKey = `${key}_${response}`;
211
- if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
212
- if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
213
- if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
214
- else this.distinctIdHasSentFlagCalls[distinctId] = [
215
- featureFlagReportedKey
216
- ];
217
- const properties = {
218
- $feature_flag: key,
219
- $feature_flag_response: response,
220
- $feature_flag_id: flagDetail?.metadata?.id,
221
- $feature_flag_version: flagDetail?.metadata?.version,
222
- $feature_flag_reason: flagDetail?.reason?.description ?? flagDetail?.reason?.code,
223
- locally_evaluated: flagWasLocallyEvaluated,
224
- [`$feature/${key}`]: response,
225
- $feature_flag_request_id: requestId,
226
- $feature_flag_evaluated_at: evaluatedAt
227
- };
228
- if (featureFlagError) properties.$feature_flag_error = featureFlagError;
229
- this.capture({
230
- distinctId,
231
- event: '$feature_flag_called',
232
- properties,
233
- groups,
234
- disableGeoip
235
- });
261
+ if (sendFeatureFlagEvents) {
262
+ const response = void 0 === result ? void 0 : false === result.enabled ? false : result.variant ?? true;
263
+ const featureFlagReportedKey = `${key}_${response}`;
264
+ if (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)) {
265
+ if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
266
+ if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
267
+ else this.distinctIdHasSentFlagCalls[distinctId] = [
268
+ featureFlagReportedKey
269
+ ];
270
+ const properties = {
271
+ $feature_flag: key,
272
+ $feature_flag_response: response,
273
+ $feature_flag_id: flagId,
274
+ $feature_flag_version: flagVersion,
275
+ $feature_flag_reason: flagReason,
276
+ locally_evaluated: flagWasLocallyEvaluated,
277
+ [`$feature/${key}`]: response,
278
+ $feature_flag_request_id: requestId,
279
+ $feature_flag_evaluated_at: evaluatedAt
280
+ };
281
+ if (featureFlagError) properties.$feature_flag_error = featureFlagError;
282
+ this.capture({
283
+ distinctId,
284
+ event: '$feature_flag_called',
285
+ properties,
286
+ groups,
287
+ disableGeoip
288
+ });
289
+ }
236
290
  }
237
- return response;
291
+ if (void 0 !== result && void 0 !== this._payloadOverrides && key in this._payloadOverrides) result = {
292
+ ...result,
293
+ payload: this._payloadOverrides[key]
294
+ };
295
+ return result;
296
+ }
297
+ async getFeatureFlag(key, distinctId, options) {
298
+ const result = await this._getFeatureFlagResult(key, distinctId, {
299
+ ...options,
300
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
301
+ });
302
+ if (void 0 === result) return;
303
+ if (false === result.enabled) return false;
304
+ return result.variant ?? true;
238
305
  }
239
306
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
240
307
  if (void 0 !== this._payloadOverrides && key in this._payloadOverrides) return this._payloadOverrides[key];
241
- const { groups, disableGeoip } = options || {};
242
- let { onlyEvaluateLocally, personProperties, groupProperties } = options || {};
243
- const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
244
- personProperties = adjustedProperties.allPersonProperties;
245
- groupProperties = adjustedProperties.allGroupProperties;
246
- let response;
247
- const localEvaluationEnabled = void 0 !== this.featureFlagsPoller;
248
- if (localEvaluationEnabled) {
249
- await this.featureFlagsPoller?.loadFeatureFlags();
250
- const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
251
- if (flag) try {
252
- const result = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, matchValue);
253
- if (result) {
254
- matchValue = result.value;
255
- response = result.payload;
256
- }
257
- } catch (e) {
258
- if (e instanceof feature_flags_js_namespaceObject.RequiresServerEvaluation || e instanceof feature_flags_js_namespaceObject.InconclusiveMatchError) this._logger?.info(`${e.name} when computing flag locally: ${flag.key}: ${e.message}`);
259
- else throw e;
260
- }
261
- }
262
- if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
263
- const payloadWasLocallyEvaluated = void 0 !== response;
264
- if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
265
- return response;
308
+ const result = await this._getFeatureFlagResult(key, distinctId, {
309
+ ...options,
310
+ sendFeatureFlagEvents: false
311
+ }, matchValue);
312
+ if (void 0 === result) return;
313
+ return result.payload ?? null;
314
+ }
315
+ async getFeatureFlagResult(key, distinctId, options) {
316
+ return this._getFeatureFlagResult(key, distinctId, {
317
+ ...options,
318
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
319
+ });
266
320
  }
267
321
  async getRemoteConfigPayload(flagKey) {
268
322
  if (!this.options.personalApiKey) throw new Error('Personal API key is required for remote config payload decryption');
package/dist/client.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { version } from "./version.mjs";
2
- import { PostHogCoreStateless, getFeatureFlagValue, isBlockedUA, isPlainObject, safeSetTimeout, uuidv7 } from "@posthog/core";
2
+ import { PostHogCoreStateless, isBlockedUA, isPlainObject, safeSetTimeout, uuidv7 } from "@posthog/core";
3
3
  import { FeatureFlagError } from "./types.mjs";
4
4
  import { FeatureFlagsPoller, InconclusiveMatchError, RequiresServerEvaluation } from "./extensions/feature-flags/feature-flags.mjs";
5
5
  import error_tracking from "./extensions/error-tracking/index.mjs";
@@ -137,21 +137,56 @@ class PostHogBackendClient extends PostHogCoreStateless {
137
137
  });
138
138
  });
139
139
  }
140
- async getFeatureFlag(key, distinctId, options) {
141
- if (void 0 !== this._flagOverrides && key in this._flagOverrides) return this._flagOverrides[key];
142
- const { groups, disableGeoip } = options || {};
143
- let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {};
140
+ async _getFeatureFlagResult(key, distinctId, options = {}, matchValue) {
141
+ const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true;
142
+ if (void 0 !== this._flagOverrides && key in this._flagOverrides) {
143
+ const overrideValue = this._flagOverrides[key];
144
+ if (void 0 === overrideValue) return;
145
+ const overridePayload = this._payloadOverrides?.[key];
146
+ return {
147
+ key,
148
+ enabled: false !== overrideValue,
149
+ variant: 'string' == typeof overrideValue ? overrideValue : void 0,
150
+ payload: overridePayload
151
+ };
152
+ }
153
+ const { groups, disableGeoip } = options;
154
+ let { onlyEvaluateLocally, personProperties, groupProperties } = options;
144
155
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
145
156
  personProperties = adjustedProperties.allPersonProperties;
146
157
  groupProperties = adjustedProperties.allGroupProperties;
147
158
  if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
148
- if (void 0 == sendFeatureFlagEvents) sendFeatureFlagEvents = this.options.sendFeatureFlagEvent ?? true;
149
- let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
150
- const flagWasLocallyEvaluated = void 0 !== response;
159
+ let result;
160
+ let flagWasLocallyEvaluated = false;
151
161
  let requestId;
152
162
  let evaluatedAt;
153
- let flagDetail;
154
163
  let featureFlagError;
164
+ let flagId;
165
+ let flagVersion;
166
+ let flagReason;
167
+ const localEvaluationEnabled = void 0 !== this.featureFlagsPoller;
168
+ if (localEvaluationEnabled) {
169
+ await this.featureFlagsPoller?.loadFeatureFlags();
170
+ const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
171
+ if (flag) try {
172
+ const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, matchValue);
173
+ if (localResult) {
174
+ flagWasLocallyEvaluated = true;
175
+ const value = localResult.value;
176
+ flagId = flag.id;
177
+ flagReason = 'Evaluated locally';
178
+ result = {
179
+ key,
180
+ enabled: false !== value,
181
+ variant: 'string' == typeof value ? value : void 0,
182
+ payload: localResult.payload ?? void 0
183
+ };
184
+ }
185
+ } catch (e) {
186
+ if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) this._logger?.info(`${e.name} when computing flag locally: ${key}: ${e.message}`);
187
+ else throw e;
188
+ }
189
+ }
155
190
  if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
156
191
  const flagsResponse = await super.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
157
192
  key
@@ -163,68 +198,87 @@ class PostHogBackendClient extends PostHogCoreStateless {
163
198
  const errors = [];
164
199
  if (flagsResponse.errorsWhileComputingFlags) errors.push(FeatureFlagError.ERRORS_WHILE_COMPUTING);
165
200
  if (flagsResponse.quotaLimited?.includes('feature_flags')) errors.push(FeatureFlagError.QUOTA_LIMITED);
166
- flagDetail = flagsResponse.flags[key];
201
+ const flagDetail = flagsResponse.flags[key];
167
202
  if (void 0 === flagDetail) errors.push(FeatureFlagError.FLAG_MISSING);
203
+ else {
204
+ flagId = flagDetail.metadata?.id;
205
+ flagVersion = flagDetail.metadata?.version;
206
+ flagReason = flagDetail.reason?.description ?? flagDetail.reason?.code;
207
+ let parsedPayload;
208
+ if (flagDetail.metadata?.payload !== void 0) try {
209
+ parsedPayload = JSON.parse(flagDetail.metadata.payload);
210
+ } catch {
211
+ parsedPayload = flagDetail.metadata.payload;
212
+ }
213
+ result = {
214
+ key,
215
+ enabled: flagDetail.enabled,
216
+ variant: flagDetail.variant,
217
+ payload: parsedPayload
218
+ };
219
+ }
168
220
  if (errors.length > 0) featureFlagError = errors.join(',');
169
- response = getFeatureFlagValue(flagDetail);
170
221
  }
171
222
  }
172
- const featureFlagReportedKey = `${key}_${response}`;
173
- if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
174
- if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
175
- if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
176
- else this.distinctIdHasSentFlagCalls[distinctId] = [
177
- featureFlagReportedKey
178
- ];
179
- const properties = {
180
- $feature_flag: key,
181
- $feature_flag_response: response,
182
- $feature_flag_id: flagDetail?.metadata?.id,
183
- $feature_flag_version: flagDetail?.metadata?.version,
184
- $feature_flag_reason: flagDetail?.reason?.description ?? flagDetail?.reason?.code,
185
- locally_evaluated: flagWasLocallyEvaluated,
186
- [`$feature/${key}`]: response,
187
- $feature_flag_request_id: requestId,
188
- $feature_flag_evaluated_at: evaluatedAt
189
- };
190
- if (featureFlagError) properties.$feature_flag_error = featureFlagError;
191
- this.capture({
192
- distinctId,
193
- event: '$feature_flag_called',
194
- properties,
195
- groups,
196
- disableGeoip
197
- });
223
+ if (sendFeatureFlagEvents) {
224
+ const response = void 0 === result ? void 0 : false === result.enabled ? false : result.variant ?? true;
225
+ const featureFlagReportedKey = `${key}_${response}`;
226
+ if (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)) {
227
+ if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
228
+ if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
229
+ else this.distinctIdHasSentFlagCalls[distinctId] = [
230
+ featureFlagReportedKey
231
+ ];
232
+ const properties = {
233
+ $feature_flag: key,
234
+ $feature_flag_response: response,
235
+ $feature_flag_id: flagId,
236
+ $feature_flag_version: flagVersion,
237
+ $feature_flag_reason: flagReason,
238
+ locally_evaluated: flagWasLocallyEvaluated,
239
+ [`$feature/${key}`]: response,
240
+ $feature_flag_request_id: requestId,
241
+ $feature_flag_evaluated_at: evaluatedAt
242
+ };
243
+ if (featureFlagError) properties.$feature_flag_error = featureFlagError;
244
+ this.capture({
245
+ distinctId,
246
+ event: '$feature_flag_called',
247
+ properties,
248
+ groups,
249
+ disableGeoip
250
+ });
251
+ }
198
252
  }
199
- return response;
253
+ if (void 0 !== result && void 0 !== this._payloadOverrides && key in this._payloadOverrides) result = {
254
+ ...result,
255
+ payload: this._payloadOverrides[key]
256
+ };
257
+ return result;
258
+ }
259
+ async getFeatureFlag(key, distinctId, options) {
260
+ const result = await this._getFeatureFlagResult(key, distinctId, {
261
+ ...options,
262
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
263
+ });
264
+ if (void 0 === result) return;
265
+ if (false === result.enabled) return false;
266
+ return result.variant ?? true;
200
267
  }
201
268
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
202
269
  if (void 0 !== this._payloadOverrides && key in this._payloadOverrides) return this._payloadOverrides[key];
203
- const { groups, disableGeoip } = options || {};
204
- let { onlyEvaluateLocally, personProperties, groupProperties } = options || {};
205
- const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
206
- personProperties = adjustedProperties.allPersonProperties;
207
- groupProperties = adjustedProperties.allGroupProperties;
208
- let response;
209
- const localEvaluationEnabled = void 0 !== this.featureFlagsPoller;
210
- if (localEvaluationEnabled) {
211
- await this.featureFlagsPoller?.loadFeatureFlags();
212
- const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
213
- if (flag) try {
214
- const result = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, matchValue);
215
- if (result) {
216
- matchValue = result.value;
217
- response = result.payload;
218
- }
219
- } catch (e) {
220
- if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) this._logger?.info(`${e.name} when computing flag locally: ${flag.key}: ${e.message}`);
221
- else throw e;
222
- }
223
- }
224
- if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
225
- const payloadWasLocallyEvaluated = void 0 !== response;
226
- if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
227
- return response;
270
+ const result = await this._getFeatureFlagResult(key, distinctId, {
271
+ ...options,
272
+ sendFeatureFlagEvents: false
273
+ }, matchValue);
274
+ if (void 0 === result) return;
275
+ return result.payload ?? null;
276
+ }
277
+ async getFeatureFlagResult(key, distinctId, options) {
278
+ return this._getFeatureFlagResult(key, distinctId, {
279
+ ...options,
280
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
281
+ });
228
282
  }
229
283
  async getRemoteConfigPayload(flagKey) {
230
284
  if (!this.options.personalApiKey) throw new Error('Personal API key is required for remote config payload decryption');
package/dist/types.d.ts CHANGED
@@ -201,6 +201,15 @@ export declare const FeatureFlagError: {
201
201
  readonly UNKNOWN_ERROR: "unknown_error";
202
202
  };
203
203
  export type FeatureFlagErrorType = (typeof FeatureFlagError)[keyof typeof FeatureFlagError] | string;
204
+ /**
205
+ * Result of evaluating a feature flag, including its value and payload.
206
+ */
207
+ export type FeatureFlagResult = {
208
+ key: string;
209
+ enabled: boolean;
210
+ variant: string | undefined;
211
+ payload: JsonType | undefined;
212
+ };
204
213
  export interface IPostHog {
205
214
  /**
206
215
  * @description Capture allows you to capture anything a user does within your system,
@@ -338,6 +347,33 @@ export interface IPostHog {
338
347
  getFeatureFlagPayload(key: string, distinctId: string, matchValue?: FeatureFlagValue, options?: {
339
348
  onlyEvaluateLocally?: boolean;
340
349
  }): Promise<JsonType | undefined>;
350
+ /**
351
+ * @description Get the result of evaluating a feature flag, including its value and payload.
352
+ * This is more efficient than calling getFeatureFlag and getFeatureFlagPayload separately when you need both.
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * const result = await client.getFeatureFlagResult('my-flag', 'user_123')
357
+ * if (result) {
358
+ * console.log('Flag enabled:', result.enabled)
359
+ * console.log('Variant:', result.variant)
360
+ * console.log('Payload:', result.payload)
361
+ * }
362
+ * ```
363
+ *
364
+ * @param key - The feature flag key
365
+ * @param distinctId - The user's distinct ID
366
+ * @param options - Optional configuration for flag evaluation
367
+ * @returns Promise that resolves to the flag result or undefined
368
+ */
369
+ getFeatureFlagResult(key: string, distinctId: string, options?: {
370
+ groups?: Record<string, string>;
371
+ personProperties?: Record<string, string>;
372
+ groupProperties?: Record<string, Record<string, string>>;
373
+ onlyEvaluateLocally?: boolean;
374
+ sendFeatureFlagEvents?: boolean;
375
+ disableGeoip?: boolean;
376
+ }): Promise<FeatureFlagResult | undefined>;
341
377
  /**
342
378
  * @description Sets a groups properties, which allows asking questions like "Who are the most active companies"
343
379
  * using my product in PostHog.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "5.21.1";
1
+ export declare const version = "5.21.2";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -26,7 +26,7 @@ __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
27
  version: ()=>version
28
28
  });
29
- const version = '5.21.1';
29
+ const version = '5.21.2';
30
30
  exports.version = __webpack_exports__.version;
31
31
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
32
32
  "version"
package/dist/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- const version = '5.21.1';
1
+ const version = '5.21.2';
2
2
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthog-node",
3
- "version": "5.21.1",
3
+ "version": "5.21.2",
4
4
  "description": "PostHog Node.js integration",
5
5
  "repository": {
6
6
  "type": "git",
package/src/client.ts CHANGED
@@ -1,22 +1,25 @@
1
1
  import { version } from './version'
2
2
 
3
3
  import {
4
+ FeatureFlagDetail,
5
+ FeatureFlagValue,
6
+ isBlockedUA,
7
+ isPlainObject,
4
8
  JsonType,
9
+ PostHogCaptureOptions,
5
10
  PostHogCoreStateless,
6
- PostHogFlagsResponse,
7
11
  PostHogFetchOptions,
8
12
  PostHogFetchResponse,
9
13
  PostHogFlagsAndPayloadsResponse,
14
+ PostHogFlagsResponse,
10
15
  PostHogPersistedProperty,
11
- PostHogCaptureOptions,
12
- isPlainObject,
13
- isBlockedUA,
14
16
  } from '@posthog/core'
15
17
  import {
16
18
  EventMessage,
17
19
  FeatureFlagError,
18
20
  FeatureFlagErrorType,
19
21
  FeatureFlagOverrideOptions,
22
+ FeatureFlagResult,
20
23
  GroupIdentifyMessage,
21
24
  IdentifyMessage,
22
25
  IPostHog,
@@ -24,7 +27,6 @@ import {
24
27
  PostHogOptions,
25
28
  SendFeatureFlagsOptions,
26
29
  } from './types'
27
- import { FeatureFlagDetail, FeatureFlagValue, getFeatureFlagValue } from '@posthog/core'
28
30
  import {
29
31
  FeatureFlagsPoller,
30
32
  RequiresServerEvaluation,
@@ -600,65 +602,47 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
600
602
  }
601
603
 
602
604
  /**
603
- * Get the value of a feature flag for a specific user.
604
- *
605
- * @example
606
- * ```ts
607
- * // Basic feature flag check
608
- * const flagValue = await client.getFeatureFlag('new-feature', 'user_123')
609
- * if (flagValue === 'variant-a') {
610
- * // Show variant A
611
- * } else if (flagValue === 'variant-b') {
612
- * // Show variant B
613
- * } else {
614
- * // Flag is disabled or not found
615
- * }
616
- * ```
617
- *
618
- * @example
619
- * ```ts
620
- * // With groups and properties
621
- * const flagValue = await client.getFeatureFlag('org-feature', 'user_123', {
622
- * groups: { organization: 'acme-corp' },
623
- * personProperties: { plan: 'enterprise' },
624
- * groupProperties: { organization: { tier: 'premium' } }
625
- * })
626
- * ```
627
- *
628
- * @example
629
- * ```ts
630
- * // Only evaluate locally
631
- * const flagValue = await client.getFeatureFlag('local-flag', 'user_123', {
632
- * onlyEvaluateLocally: true
633
- * })
634
- * ```
635
- *
636
- * {@label Feature flags}
605
+ * Internal method that handles feature flag evaluation with full details.
606
+ * Used by getFeatureFlag, getFeatureFlagPayload, and getFeatureFlagResult.
637
607
  *
638
608
  * @param key - The feature flag key
639
609
  * @param distinctId - The user's distinct ID
640
- * @param options - Optional configuration for flag evaluation
641
- * @returns Promise that resolves to the flag value or undefined
610
+ * @param options - Evaluation options (includes sendFeatureFlagEvents, defaults to true)
611
+ * @param matchValue - Optional match value for payload lookup (used by getFeatureFlagPayload)
612
+ * @returns Promise that resolves to the flag result or undefined
642
613
  */
643
- async getFeatureFlag(
614
+ private async _getFeatureFlagResult(
644
615
  key: string,
645
616
  distinctId: string,
646
- options?: {
617
+ options: {
647
618
  groups?: Record<string, string>
648
619
  personProperties?: Record<string, string>
649
620
  groupProperties?: Record<string, Record<string, string>>
650
621
  onlyEvaluateLocally?: boolean
651
622
  sendFeatureFlagEvents?: boolean
652
623
  disableGeoip?: boolean
653
- }
654
- ): Promise<FeatureFlagValue | undefined> {
624
+ } = {},
625
+ matchValue?: FeatureFlagValue
626
+ ): Promise<FeatureFlagResult | undefined> {
627
+ const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true
655
628
  // Check for overrides first - they take precedence over all evaluation
656
629
  if (this._flagOverrides !== undefined && key in this._flagOverrides) {
657
- return this._flagOverrides[key]
630
+ const overrideValue = this._flagOverrides[key]
631
+ // undefined override simulates "flag doesn't exist"
632
+ if (overrideValue === undefined) {
633
+ return undefined
634
+ }
635
+ const overridePayload = this._payloadOverrides?.[key]
636
+ return {
637
+ key,
638
+ enabled: overrideValue !== false,
639
+ variant: typeof overrideValue === 'string' ? overrideValue : undefined,
640
+ payload: overridePayload,
641
+ }
658
642
  }
659
643
 
660
- const { groups, disableGeoip } = options || {}
661
- let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {}
644
+ const { groups, disableGeoip } = options
645
+ let { onlyEvaluateLocally, personProperties, groupProperties } = options
662
646
 
663
647
  const adjustedProperties = this.addLocalPersonAndGroupProperties(
664
648
  distinctId,
@@ -674,26 +658,58 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
674
658
  if (onlyEvaluateLocally == undefined) {
675
659
  onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false
676
660
  }
677
- if (sendFeatureFlagEvents == undefined) {
678
- sendFeatureFlagEvents = this.options.sendFeatureFlagEvent ?? true
679
- }
680
661
 
681
- let response = await this.featureFlagsPoller?.getFeatureFlag(
682
- key,
683
- distinctId,
684
- groups,
685
- personProperties,
686
- groupProperties
687
- )
688
-
689
- const flagWasLocallyEvaluated = response !== undefined
662
+ let result: FeatureFlagResult | undefined = undefined
663
+ let flagWasLocallyEvaluated = false
690
664
  let requestId: string | undefined = undefined
691
665
  let evaluatedAt: number | undefined = undefined
692
- let flagDetail: FeatureFlagDetail | undefined = undefined
693
666
  let featureFlagError: FeatureFlagErrorType | undefined = undefined
667
+ // Track metadata for event tracking (not exposed in FeatureFlagResult)
668
+ let flagId: number | undefined = undefined
669
+ let flagVersion: number | undefined = undefined
670
+ let flagReason: string | undefined = undefined
671
+
672
+ // Try local evaluation first
673
+ const localEvaluationEnabled = this.featureFlagsPoller !== undefined
674
+ if (localEvaluationEnabled) {
675
+ await this.featureFlagsPoller?.loadFeatureFlags()
694
676
 
677
+ const flag = this.featureFlagsPoller?.featureFlagsByKey[key]
678
+ if (flag) {
679
+ try {
680
+ const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(
681
+ flag,
682
+ distinctId,
683
+ groups,
684
+ personProperties,
685
+ groupProperties,
686
+ matchValue
687
+ )
688
+ if (localResult) {
689
+ flagWasLocallyEvaluated = true
690
+ const value = localResult.value
691
+ flagId = flag.id
692
+ flagReason = 'Evaluated locally'
693
+ result = {
694
+ key,
695
+ enabled: value !== false,
696
+ variant: typeof value === 'string' ? value : undefined,
697
+ payload: localResult.payload ?? undefined,
698
+ }
699
+ }
700
+ } catch (e) {
701
+ if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) {
702
+ // Fall through to server evaluation
703
+ this._logger?.info(`${e.name} when computing flag locally: ${key}: ${e.message}`)
704
+ } else {
705
+ throw e
706
+ }
707
+ }
708
+ }
709
+ }
710
+
711
+ // Fall back to remote evaluation if needed
695
712
  if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
696
- // Call getFeatureFlagDetailsStateless directly to get access to error information
697
713
  const flagsResponse = await super.getFeatureFlagDetailsStateless(
698
714
  distinctId,
699
715
  groups,
@@ -704,13 +720,11 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
704
720
  )
705
721
 
706
722
  if (flagsResponse === undefined) {
707
- // Request failed (network error, timeout, etc.)
708
723
  featureFlagError = FeatureFlagError.UNKNOWN_ERROR
709
724
  } else {
710
725
  requestId = flagsResponse.requestId
711
726
  evaluatedAt = flagsResponse.evaluatedAt
712
727
 
713
- // Track errors from the response
714
728
  const errors: string[] = []
715
729
 
716
730
  if (flagsResponse.errorsWhileComputingFlags) {
@@ -721,61 +735,162 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
721
735
  errors.push(FeatureFlagError.QUOTA_LIMITED)
722
736
  }
723
737
 
724
- flagDetail = flagsResponse.flags[key]
738
+ const flagDetail = flagsResponse.flags[key]
725
739
 
726
740
  if (flagDetail === undefined) {
727
741
  errors.push(FeatureFlagError.FLAG_MISSING)
742
+ } else {
743
+ // Extract metadata for event tracking
744
+ flagId = flagDetail.metadata?.id
745
+ flagVersion = flagDetail.metadata?.version
746
+ flagReason = flagDetail.reason?.description ?? flagDetail.reason?.code
747
+
748
+ // Parse payload once from the API response
749
+ let parsedPayload: JsonType | undefined = undefined
750
+ if (flagDetail.metadata?.payload !== undefined) {
751
+ try {
752
+ parsedPayload = JSON.parse(flagDetail.metadata.payload)
753
+ } catch {
754
+ // If parsing fails, return the raw string (matches parsePayload behavior)
755
+ parsedPayload = flagDetail.metadata.payload
756
+ }
757
+ }
758
+
759
+ result = {
760
+ key,
761
+ enabled: flagDetail.enabled,
762
+ variant: flagDetail.variant,
763
+ payload: parsedPayload,
764
+ }
728
765
  }
729
766
 
730
767
  if (errors.length > 0) {
731
768
  featureFlagError = errors.join(',')
732
769
  }
733
-
734
- response = getFeatureFlagValue(flagDetail)
735
770
  }
736
771
  }
737
772
 
738
- const featureFlagReportedKey = `${key}_${response}`
773
+ // Send feature flag event if configured
774
+ if (sendFeatureFlagEvents) {
775
+ // Compute the response value for event tracking
776
+ const response = result === undefined ? undefined : result.enabled === false ? false : (result.variant ?? true)
777
+ const featureFlagReportedKey = `${key}_${response}`
739
778
 
740
- if (
741
- sendFeatureFlagEvents &&
742
- (!(distinctId in this.distinctIdHasSentFlagCalls) ||
743
- !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))
744
- ) {
745
- if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
746
- this.distinctIdHasSentFlagCalls = {}
747
- }
748
- if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
749
- this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey)
750
- } else {
751
- this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey]
752
- }
779
+ if (
780
+ !(distinctId in this.distinctIdHasSentFlagCalls) ||
781
+ !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)
782
+ ) {
783
+ if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
784
+ this.distinctIdHasSentFlagCalls = {}
785
+ }
786
+ if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
787
+ this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey)
788
+ } else {
789
+ this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey]
790
+ }
791
+
792
+ const properties: Record<string, any> = {
793
+ $feature_flag: key,
794
+ $feature_flag_response: response,
795
+ $feature_flag_id: flagId,
796
+ $feature_flag_version: flagVersion,
797
+ $feature_flag_reason: flagReason,
798
+ locally_evaluated: flagWasLocallyEvaluated,
799
+ [`$feature/${key}`]: response,
800
+ $feature_flag_request_id: requestId,
801
+ $feature_flag_evaluated_at: evaluatedAt,
802
+ }
803
+
804
+ if (featureFlagError) {
805
+ properties.$feature_flag_error = featureFlagError
806
+ }
753
807
 
754
- const properties: Record<string, any> = {
755
- $feature_flag: key,
756
- $feature_flag_response: response,
757
- $feature_flag_id: flagDetail?.metadata?.id,
758
- $feature_flag_version: flagDetail?.metadata?.version,
759
- $feature_flag_reason: flagDetail?.reason?.description ?? flagDetail?.reason?.code,
760
- locally_evaluated: flagWasLocallyEvaluated,
761
- [`$feature/${key}`]: response,
762
- $feature_flag_request_id: requestId,
763
- $feature_flag_evaluated_at: evaluatedAt,
808
+ this.capture({
809
+ distinctId,
810
+ event: '$feature_flag_called',
811
+ properties,
812
+ groups,
813
+ disableGeoip,
814
+ })
764
815
  }
816
+ }
765
817
 
766
- if (featureFlagError) {
767
- properties.$feature_flag_error = featureFlagError
818
+ // Apply payload override if present (even when there's no flag override)
819
+ // This ensures consistency with getFeatureFlagPayload behavior
820
+ if (result !== undefined && this._payloadOverrides !== undefined && key in this._payloadOverrides) {
821
+ result = {
822
+ ...result,
823
+ payload: this._payloadOverrides[key],
768
824
  }
825
+ }
769
826
 
770
- this.capture({
771
- distinctId,
772
- event: '$feature_flag_called',
773
- properties,
774
- groups,
775
- disableGeoip,
776
- })
827
+ return result
828
+ }
829
+
830
+ /**
831
+ * Get the value of a feature flag for a specific user.
832
+ *
833
+ * @example
834
+ * ```ts
835
+ * // Basic feature flag check
836
+ * const flagValue = await client.getFeatureFlag('new-feature', 'user_123')
837
+ * if (flagValue === 'variant-a') {
838
+ * // Show variant A
839
+ * } else if (flagValue === 'variant-b') {
840
+ * // Show variant B
841
+ * } else {
842
+ * // Flag is disabled or not found
843
+ * }
844
+ * ```
845
+ *
846
+ * @example
847
+ * ```ts
848
+ * // With groups and properties
849
+ * const flagValue = await client.getFeatureFlag('org-feature', 'user_123', {
850
+ * groups: { organization: 'acme-corp' },
851
+ * personProperties: { plan: 'enterprise' },
852
+ * groupProperties: { organization: { tier: 'premium' } }
853
+ * })
854
+ * ```
855
+ *
856
+ * @example
857
+ * ```ts
858
+ * // Only evaluate locally
859
+ * const flagValue = await client.getFeatureFlag('local-flag', 'user_123', {
860
+ * onlyEvaluateLocally: true
861
+ * })
862
+ * ```
863
+ *
864
+ * {@label Feature flags}
865
+ *
866
+ * @param key - The feature flag key
867
+ * @param distinctId - The user's distinct ID
868
+ * @param options - Optional configuration for flag evaluation
869
+ * @returns Promise that resolves to the flag value or undefined
870
+ */
871
+ async getFeatureFlag(
872
+ key: string,
873
+ distinctId: string,
874
+ options?: {
875
+ groups?: Record<string, string>
876
+ personProperties?: Record<string, string>
877
+ groupProperties?: Record<string, Record<string, string>>
878
+ onlyEvaluateLocally?: boolean
879
+ sendFeatureFlagEvents?: boolean
880
+ disableGeoip?: boolean
777
881
  }
778
- return response
882
+ ): Promise<FeatureFlagValue | undefined> {
883
+ const result = await this._getFeatureFlagResult(key, distinctId, {
884
+ ...options,
885
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true,
886
+ })
887
+ if (result === undefined) {
888
+ return undefined
889
+ }
890
+ if (result.enabled === false) {
891
+ return false
892
+ }
893
+ return result.variant ?? true
779
894
  }
780
895
 
781
896
  /**
@@ -828,74 +943,77 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
828
943
  }
829
944
  ): Promise<JsonType | undefined> {
830
945
  // Check for payload overrides first - they take precedence over all evaluation
946
+ // This is checked independently from flag overrides
831
947
  if (this._payloadOverrides !== undefined && key in this._payloadOverrides) {
832
948
  return this._payloadOverrides[key]
833
949
  }
834
950
 
835
- const { groups, disableGeoip } = options || {}
836
- let { onlyEvaluateLocally, personProperties, groupProperties } = options || {}
837
-
838
- const adjustedProperties = this.addLocalPersonAndGroupProperties(
951
+ // sendFeatureFlagEvents is intentionally ignored for payload-only calls.
952
+ // getFeatureFlagPayload never sends $feature_flag_called events, matching pre-refactoring behavior.
953
+ // The option is kept in the signature for backwards compatibility (marked @deprecated above).
954
+ const result = await this._getFeatureFlagResult(
955
+ key,
839
956
  distinctId,
840
- groups,
841
- personProperties,
842
- groupProperties
957
+ { ...options, sendFeatureFlagEvents: false },
958
+ matchValue
843
959
  )
844
960
 
845
- personProperties = adjustedProperties.allPersonProperties
846
- groupProperties = adjustedProperties.allGroupProperties
847
-
848
- let response = undefined
849
-
850
- const localEvaluationEnabled = this.featureFlagsPoller !== undefined
851
- if (localEvaluationEnabled) {
852
- // Ensure flags are loaded before checking for the specific flag
853
- await this.featureFlagsPoller?.loadFeatureFlags()
854
-
855
- const flag = this.featureFlagsPoller?.featureFlagsByKey[key]
856
- if (flag) {
857
- try {
858
- const result = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(
859
- flag,
860
- distinctId,
861
- groups,
862
- personProperties,
863
- groupProperties,
864
- matchValue
865
- )
866
- if (result) {
867
- matchValue = result.value
868
- response = result.payload
869
- }
870
- } catch (e) {
871
- if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) {
872
- // Fall through to server evaluation
873
- this._logger?.info(`${e.name} when computing flag locally: ${flag.key}: ${e.message}`)
874
- } else {
875
- throw e
876
- }
877
- }
878
- }
879
- }
880
-
881
- // set defaults
882
- if (onlyEvaluateLocally == undefined) {
883
- onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false
961
+ // Return undefined when API fails or flag not found
962
+ if (result === undefined) {
963
+ return undefined
884
964
  }
885
965
 
886
- const payloadWasLocallyEvaluated = response !== undefined
966
+ // Return payload if available, null if flag exists but no payload
967
+ return result.payload ?? null
968
+ }
887
969
 
888
- if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
889
- response = await super.getFeatureFlagPayloadStateless(
890
- key,
891
- distinctId,
892
- groups,
893
- personProperties,
894
- groupProperties,
895
- disableGeoip
896
- )
970
+ /**
971
+ * Get the result of evaluating a feature flag, including its value and payload.
972
+ * This is more efficient than calling getFeatureFlag and getFeatureFlagPayload separately when you need both.
973
+ *
974
+ * @example
975
+ * ```ts
976
+ * // Get flag result
977
+ * const result = await client.getFeatureFlagResult('my-flag', 'user_123')
978
+ * if (result) {
979
+ * console.log('Flag enabled:', result.enabled)
980
+ * console.log('Variant:', result.variant)
981
+ * console.log('Payload:', result.payload)
982
+ * }
983
+ * ```
984
+ *
985
+ * @example
986
+ * ```ts
987
+ * // With groups and properties
988
+ * const result = await client.getFeatureFlagResult('org-feature', 'user_123', {
989
+ * groups: { organization: 'acme-corp' },
990
+ * personProperties: { plan: 'enterprise' }
991
+ * })
992
+ * ```
993
+ *
994
+ * {@label Feature flags}
995
+ *
996
+ * @param key - The feature flag key
997
+ * @param distinctId - The user's distinct ID
998
+ * @param options - Optional configuration for flag evaluation
999
+ * @returns Promise that resolves to the flag result or undefined
1000
+ */
1001
+ async getFeatureFlagResult(
1002
+ key: string,
1003
+ distinctId: string,
1004
+ options?: {
1005
+ groups?: Record<string, string>
1006
+ personProperties?: Record<string, string>
1007
+ groupProperties?: Record<string, Record<string, string>>
1008
+ onlyEvaluateLocally?: boolean
1009
+ sendFeatureFlagEvents?: boolean
1010
+ disableGeoip?: boolean
897
1011
  }
898
- return response
1012
+ ): Promise<FeatureFlagResult | undefined> {
1013
+ return this._getFeatureFlagResult(key, distinctId, {
1014
+ ...options,
1015
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true,
1016
+ })
899
1017
  }
900
1018
 
901
1019
  /**
package/src/types.ts CHANGED
@@ -232,6 +232,16 @@ export const FeatureFlagError = {
232
232
 
233
233
  export type FeatureFlagErrorType = (typeof FeatureFlagError)[keyof typeof FeatureFlagError] | string
234
234
 
235
+ /**
236
+ * Result of evaluating a feature flag, including its value and payload.
237
+ */
238
+ export type FeatureFlagResult = {
239
+ key: string
240
+ enabled: boolean
241
+ variant: string | undefined
242
+ payload: JsonType | undefined
243
+ }
244
+
235
245
  export interface IPostHog {
236
246
  /**
237
247
  * @description Capture allows you to capture anything a user does within your system,
@@ -385,6 +395,38 @@ export interface IPostHog {
385
395
  }
386
396
  ): Promise<JsonType | undefined>
387
397
 
398
+ /**
399
+ * @description Get the result of evaluating a feature flag, including its value and payload.
400
+ * This is more efficient than calling getFeatureFlag and getFeatureFlagPayload separately when you need both.
401
+ *
402
+ * @example
403
+ * ```ts
404
+ * const result = await client.getFeatureFlagResult('my-flag', 'user_123')
405
+ * if (result) {
406
+ * console.log('Flag enabled:', result.enabled)
407
+ * console.log('Variant:', result.variant)
408
+ * console.log('Payload:', result.payload)
409
+ * }
410
+ * ```
411
+ *
412
+ * @param key - The feature flag key
413
+ * @param distinctId - The user's distinct ID
414
+ * @param options - Optional configuration for flag evaluation
415
+ * @returns Promise that resolves to the flag result or undefined
416
+ */
417
+ getFeatureFlagResult(
418
+ key: string,
419
+ distinctId: string,
420
+ options?: {
421
+ groups?: Record<string, string>
422
+ personProperties?: Record<string, string>
423
+ groupProperties?: Record<string, Record<string, string>>
424
+ onlyEvaluateLocally?: boolean
425
+ sendFeatureFlagEvents?: boolean
426
+ disableGeoip?: boolean
427
+ }
428
+ ): Promise<FeatureFlagResult | undefined>
429
+
388
430
  /**
389
431
  * @description Sets a groups properties, which allows asking questions like "Who are the most active companies"
390
432
  * using my product in PostHog.
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '5.21.1'
1
+ export const version = '5.21.2'