@rpcbase/server 0.507.0 → 0.508.0

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/index.js CHANGED
@@ -539,6 +539,8 @@ var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedP
539
539
  PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
540
540
  PostHogPersistedProperty["DistinctId"] = "distinct_id";
541
541
  PostHogPersistedProperty["Props"] = "props";
542
+ PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
543
+ PostHogPersistedProperty["PersonMode"] = "person_mode";
542
544
  PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
543
545
  PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
544
546
  PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
@@ -573,7 +575,7 @@ const isObject = (x) => x === Object(x) && !isArray(x);
573
575
  const isUndefined = (x) => void 0 === x;
574
576
  const isString = (x) => "[object String]" == type_utils_toString.call(x);
575
577
  const isEmptyString = (x) => isString(x) && 0 === x.trim().length;
576
- const isNumber = (x) => "[object Number]" == type_utils_toString.call(x);
578
+ const isNumber = (x) => "[object Number]" == type_utils_toString.call(x) && x === x;
577
579
  const isPlainError = (x) => x instanceof Error;
578
580
  function isPrimitive(value) {
579
581
  return null === value || "object" != typeof value;
@@ -855,10 +857,11 @@ class PostHogCoreStateless {
855
857
  this.disableGeoip = options.disableGeoip ?? true;
856
858
  this.disabled = options.disabled ?? false;
857
859
  this.historicalMigration = options?.historicalMigration ?? false;
858
- this.evaluationEnvironments = options?.evaluationEnvironments;
859
860
  this._initPromise = Promise.resolve();
860
861
  this._isInitialized = true;
861
862
  this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
863
+ this.evaluationContexts = options?.evaluationContexts ?? options?.evaluationEnvironments;
864
+ if (options?.evaluationEnvironments && !options?.evaluationContexts) this._logger.warn("evaluationEnvironments is deprecated. Use evaluationContexts instead. This property will be removed in a future version.");
862
865
  this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
863
866
  }
864
867
  logMsgIfDebug(fn) {
@@ -1033,7 +1036,7 @@ class PostHogCoreStateless {
1033
1036
  group_properties: groupProperties,
1034
1037
  ...extraPayload
1035
1038
  };
1036
- if (this.evaluationEnvironments && this.evaluationEnvironments.length > 0) requestData.evaluation_environments = this.evaluationEnvironments;
1039
+ if (this.evaluationContexts && this.evaluationContexts.length > 0) requestData.evaluation_contexts = this.evaluationContexts;
1037
1040
  const fetchOptions = {
1038
1041
  method: "POST",
1039
1042
  headers: {
@@ -1045,10 +1048,35 @@ class PostHogCoreStateless {
1045
1048
  this._logger.info("Flags URL", url);
1046
1049
  return this.fetchWithRetry(url, fetchOptions, {
1047
1050
  retryCount: 0
1048
- }, this.featureFlagsRequestTimeoutMs).then((response) => response.json()).then((response) => normalizeFlagsResponse(response)).catch((error) => {
1051
+ }, this.featureFlagsRequestTimeoutMs).then((response) => response.json()).then((response) => ({
1052
+ success: true,
1053
+ response: normalizeFlagsResponse(response)
1054
+ })).catch((error) => {
1049
1055
  this._events.emit("error", error);
1056
+ return {
1057
+ success: false,
1058
+ error: this.categorizeRequestError(error)
1059
+ };
1050
1060
  });
1051
1061
  }
1062
+ categorizeRequestError(error) {
1063
+ if (error instanceof PostHogFetchHttpError) return {
1064
+ type: "api_error",
1065
+ statusCode: error.status
1066
+ };
1067
+ if (error instanceof PostHogFetchNetworkError) {
1068
+ const cause = error.error;
1069
+ if (cause instanceof Error && ("AbortError" === cause.name || "TimeoutError" === cause.name)) return {
1070
+ type: "timeout"
1071
+ };
1072
+ return {
1073
+ type: "connection_error"
1074
+ };
1075
+ }
1076
+ return {
1077
+ type: "unknown_error"
1078
+ };
1079
+ }
1052
1080
  async getFeatureFlagStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1053
1081
  await this._initPromise;
1054
1082
  const flagDetailResponse = await this.getFeatureFlagDetailStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
@@ -1115,8 +1143,9 @@ class PostHogCoreStateless {
1115
1143
  const extraPayload = {};
1116
1144
  if (disableGeoip ?? this.disableGeoip) extraPayload["geoip_disable"] = true;
1117
1145
  if (flagKeysToEvaluate) extraPayload["flag_keys_to_evaluate"] = flagKeysToEvaluate;
1118
- const flagsResponse = await this.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
1119
- if (void 0 === flagsResponse) return;
1146
+ const result = await this.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
1147
+ if (!result.success) return;
1148
+ const flagsResponse = result.response;
1120
1149
  if (flagsResponse.errorsWhileComputingFlags) console.error("[FEATURE FLAGS] Error while computing feature flags, some flags may be missing or incorrect. Learn more at https://posthog.com/docs/feature-flags/best-practices");
1121
1150
  if (flagsResponse.quotaLimited?.includes("feature_flags")) {
1122
1151
  console.warn("[FEATURE FLAGS] Feature flags quota limit exceeded - feature flags unavailable. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts");
@@ -1183,10 +1212,17 @@ class PostHogCoreStateless {
1183
1212
  this.setPersistedProperty(types_PostHogPersistedProperty.Props, this.props);
1184
1213
  });
1185
1214
  }
1215
+ processBeforeEnqueue(message) {
1216
+ return message;
1217
+ }
1218
+ async flushStorage() {
1219
+ }
1186
1220
  enqueue(type, _message, options) {
1187
1221
  this.wrap(() => {
1188
1222
  if (this.optedOut) return void this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
1189
- const message = this.prepareMessage(type, _message, options);
1223
+ let message = this.prepareMessage(type, _message, options);
1224
+ message = this.processBeforeEnqueue(message);
1225
+ if (null === message) return;
1190
1226
  const queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
1191
1227
  if (queue.length >= this.maxQueueSize) {
1192
1228
  queue.shift();
@@ -1205,10 +1241,13 @@ class PostHogCoreStateless {
1205
1241
  if (this.disabled) return void this._logger.warn("The client is disabled");
1206
1242
  if (!this._isInitialized) await this._initPromise;
1207
1243
  if (this.optedOut) return void this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
1244
+ let message = this.prepareMessage(type, _message, options);
1245
+ message = this.processBeforeEnqueue(message);
1246
+ if (null === message) return;
1208
1247
  const data = {
1209
1248
  api_key: this.apiKey,
1210
1249
  batch: [
1211
- this.prepareMessage(type, _message, options)
1250
+ message
1212
1251
  ],
1213
1252
  sent_at: currentISOTime()
1214
1253
  };
@@ -1293,11 +1332,12 @@ class PostHogCoreStateless {
1293
1332
  while (queue.length > 0 && sentMessages.length < originalQueueLength) {
1294
1333
  const batchItems = queue.slice(0, this.maxBatchSize);
1295
1334
  const batchMessages = batchItems.map((item) => item.message);
1296
- const persistQueueChange = () => {
1335
+ const persistQueueChange = async () => {
1297
1336
  const refreshedQueue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
1298
1337
  const newQueue = refreshedQueue.slice(batchItems.length);
1299
1338
  this.setPersistedProperty(types_PostHogPersistedProperty.Queue, newQueue);
1300
1339
  queue = newQueue;
1340
+ await this.flushStorage();
1301
1341
  };
1302
1342
  const data = {
1303
1343
  api_key: this.apiKey,
@@ -1333,11 +1373,11 @@ class PostHogCoreStateless {
1333
1373
  this._logger.warn(`Received 413 when sending batch of size ${batchMessages.length}, reducing batch size to ${this.maxBatchSize}`);
1334
1374
  continue;
1335
1375
  }
1336
- if (!(err instanceof PostHogFetchNetworkError)) persistQueueChange();
1376
+ if (!(err instanceof PostHogFetchNetworkError)) await persistQueueChange();
1337
1377
  this._events.emit("error", err);
1338
1378
  throw err;
1339
1379
  }
1340
- persistQueueChange();
1380
+ await persistQueueChange();
1341
1381
  sentMessages.push(...batchMessages);
1342
1382
  }
1343
1383
  this._events.emit("flush", sentMessages);
@@ -1462,7 +1502,7 @@ class ErrorPropertiesBuilder {
1462
1502
  };
1463
1503
  const coercingContext = this.buildCoercingContext(mechanism, hint, 0);
1464
1504
  const exceptionWithCause = coercingContext.apply(input);
1465
- const parsingContext = this.buildParsingContext();
1505
+ const parsingContext = this.buildParsingContext(hint);
1466
1506
  const exceptionWithStack = this.parseStacktrace(exceptionWithCause, parsingContext);
1467
1507
  const exceptionList = this.convertToExceptionList(exceptionWithStack, mechanism);
1468
1508
  return {
@@ -1486,7 +1526,7 @@ class ErrorPropertiesBuilder {
1486
1526
  let cause;
1487
1527
  if (null != err.cause) cause = this.parseStacktrace(err.cause, ctx);
1488
1528
  let stack;
1489
- if ("" != err.stack && null != err.stack) stack = this.applyChunkIds(this.stackParser(err.stack, err.synthetic ? 1 : 0), ctx.chunkIdMap);
1529
+ if ("" != err.stack && null != err.stack) stack = this.applyChunkIds(this.stackParser(err.stack, err.synthetic ? ctx.skipFirstLines : 0), ctx.chunkIdMap);
1490
1530
  return {
1491
1531
  ...err,
1492
1532
  cause,
@@ -1531,9 +1571,10 @@ class ErrorPropertiesBuilder {
1531
1571
  }));
1532
1572
  return exceptionList;
1533
1573
  }
1534
- buildParsingContext() {
1574
+ buildParsingContext(hint) {
1535
1575
  const context = {
1536
- chunkIdMap: getFilenameToChunkIdMap(this.stackParser)
1576
+ chunkIdMap: getFilenameToChunkIdMap(this.stackParser),
1577
+ skipFirstLines: hint.skipFirstLines ?? 1
1537
1578
  };
1538
1579
  return context;
1539
1580
  }
@@ -2105,7 +2146,7 @@ class ErrorTracking {
2105
2146
  this._rateLimiter.stop();
2106
2147
  }
2107
2148
  }
2108
- const version = "5.20.0";
2149
+ const version = "5.24.11";
2109
2150
  const FeatureFlagError = {
2110
2151
  ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
2111
2152
  FLAG_MISSING: "flag_missing",
@@ -2170,6 +2211,7 @@ class FeatureFlagsPoller {
2170
2211
  this.customHeaders = customHeaders;
2171
2212
  this.onLoad = options.onLoad;
2172
2213
  this.cacheProvider = options.cacheProvider;
2214
+ this.strictLocalEvaluation = options.strictLocalEvaluation ?? false;
2173
2215
  this.loadFeatureFlags();
2174
2216
  }
2175
2217
  debug(enabled = true) {
@@ -2365,6 +2407,11 @@ class FeatureFlagsPoller {
2365
2407
  this.cohorts = flagData.cohorts;
2366
2408
  this.loadedSuccessfullyOnce = true;
2367
2409
  }
2410
+ warnAboutExperienceContinuityFlags(flags) {
2411
+ if (this.strictLocalEvaluation) return;
2412
+ const experienceContinuityFlags = flags.filter((f) => f.ensure_experience_continuity);
2413
+ if (experienceContinuityFlags.length > 0) console.warn(`[PostHog] You are using local evaluation but ${experienceContinuityFlags.length} flag(s) have experience continuity enabled: ${experienceContinuityFlags.map((f) => f.key).join(", ")}. Experience continuity is incompatible with local evaluation and will cause a server request on every flag evaluation, negating local evaluation cost savings. To avoid server requests and unexpected costs, either disable experience continuity on these flags in PostHog, use strictLocalEvaluation: true in client init, or pass onlyEvaluateLocally: true per flag call (flags that cannot be evaluated locally will return undefined).`);
2414
+ }
2368
2415
  async loadFromCache(debugMessage) {
2369
2416
  if (!this.cacheProvider) return false;
2370
2417
  try {
@@ -2373,6 +2420,7 @@ class FeatureFlagsPoller {
2373
2420
  this.updateFlagState(cached);
2374
2421
  this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`));
2375
2422
  this.onLoad?.(this.featureFlags.length);
2423
+ this.warnAboutExperienceContinuityFlags(cached.flags);
2376
2424
  return true;
2377
2425
  }
2378
2426
  return false;
@@ -2466,6 +2514,7 @@ class FeatureFlagsPoller {
2466
2514
  this.onError?.(new Error(`Failed to store in cache: ${err}`));
2467
2515
  }
2468
2516
  this.onLoad?.(this.featureFlags.length);
2517
+ this.warnAboutExperienceContinuityFlags(flagData.flags);
2469
2518
  break;
2470
2519
  }
2471
2520
  default:
@@ -2720,7 +2769,8 @@ class PostHogBackendClient extends PostHogCoreStateless {
2720
2769
  this._events.emit("localEvaluationFlagsLoaded", count);
2721
2770
  },
2722
2771
  customHeaders: this.getCustomHeaders(),
2723
- cacheProvider: options.flagDefinitionCacheProvider
2772
+ cacheProvider: options.flagDefinitionCacheProvider,
2773
+ strictLocalEvaluation: options.strictLocalEvaluation
2724
2774
  });
2725
2775
  }
2726
2776
  this.errorTracking = new ErrorTracking(this, options, this._logger);
@@ -2826,21 +2876,56 @@ class PostHogBackendClient extends PostHogCoreStateless {
2826
2876
  });
2827
2877
  });
2828
2878
  }
2829
- async getFeatureFlag(key, distinctId, options) {
2830
- if (void 0 !== this._flagOverrides && key in this._flagOverrides) return this._flagOverrides[key];
2831
- const { groups, disableGeoip } = options || {};
2832
- let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {};
2879
+ async _getFeatureFlagResult(key, distinctId, options = {}, matchValue) {
2880
+ const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true;
2881
+ if (void 0 !== this._flagOverrides && key in this._flagOverrides) {
2882
+ const overrideValue = this._flagOverrides[key];
2883
+ if (void 0 === overrideValue) return;
2884
+ const overridePayload = this._payloadOverrides?.[key];
2885
+ return {
2886
+ key,
2887
+ enabled: false !== overrideValue,
2888
+ variant: "string" == typeof overrideValue ? overrideValue : void 0,
2889
+ payload: overridePayload
2890
+ };
2891
+ }
2892
+ const { groups, disableGeoip } = options;
2893
+ let { onlyEvaluateLocally, personProperties, groupProperties } = options;
2833
2894
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
2834
2895
  personProperties = adjustedProperties.allPersonProperties;
2835
2896
  groupProperties = adjustedProperties.allGroupProperties;
2836
- if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = false;
2837
- if (void 0 == sendFeatureFlagEvents) sendFeatureFlagEvents = this.options.sendFeatureFlagEvent ?? true;
2838
- let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
2839
- const flagWasLocallyEvaluated = void 0 !== response;
2897
+ if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
2898
+ let result;
2899
+ let flagWasLocallyEvaluated = false;
2840
2900
  let requestId;
2841
2901
  let evaluatedAt;
2842
- let flagDetail;
2843
2902
  let featureFlagError;
2903
+ let flagId;
2904
+ let flagVersion;
2905
+ let flagReason;
2906
+ const localEvaluationEnabled = void 0 !== this.featureFlagsPoller;
2907
+ if (localEvaluationEnabled) {
2908
+ await this.featureFlagsPoller?.loadFeatureFlags();
2909
+ const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
2910
+ if (flag) try {
2911
+ const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, matchValue);
2912
+ if (localResult) {
2913
+ flagWasLocallyEvaluated = true;
2914
+ const value = localResult.value;
2915
+ flagId = flag.id;
2916
+ flagReason = "Evaluated locally";
2917
+ result = {
2918
+ key,
2919
+ enabled: false !== value,
2920
+ variant: "string" == typeof value ? value : void 0,
2921
+ payload: localResult.payload ?? void 0
2922
+ };
2923
+ }
2924
+ } catch (e) {
2925
+ if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) this._logger?.info(`${e.name} when computing flag locally: ${key}: ${e.message}`);
2926
+ else throw e;
2927
+ }
2928
+ }
2844
2929
  if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
2845
2930
  const flagsResponse = await super.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
2846
2931
  key
@@ -2852,68 +2937,87 @@ class PostHogBackendClient extends PostHogCoreStateless {
2852
2937
  const errors = [];
2853
2938
  if (flagsResponse.errorsWhileComputingFlags) errors.push(FeatureFlagError.ERRORS_WHILE_COMPUTING);
2854
2939
  if (flagsResponse.quotaLimited?.includes("feature_flags")) errors.push(FeatureFlagError.QUOTA_LIMITED);
2855
- flagDetail = flagsResponse.flags[key];
2940
+ const flagDetail = flagsResponse.flags[key];
2856
2941
  if (void 0 === flagDetail) errors.push(FeatureFlagError.FLAG_MISSING);
2942
+ else {
2943
+ flagId = flagDetail.metadata?.id;
2944
+ flagVersion = flagDetail.metadata?.version;
2945
+ flagReason = flagDetail.reason?.description ?? flagDetail.reason?.code;
2946
+ let parsedPayload;
2947
+ if (flagDetail.metadata?.payload !== void 0) try {
2948
+ parsedPayload = JSON.parse(flagDetail.metadata.payload);
2949
+ } catch {
2950
+ parsedPayload = flagDetail.metadata.payload;
2951
+ }
2952
+ result = {
2953
+ key,
2954
+ enabled: flagDetail.enabled,
2955
+ variant: flagDetail.variant,
2956
+ payload: parsedPayload
2957
+ };
2958
+ }
2857
2959
  if (errors.length > 0) featureFlagError = errors.join(",");
2858
- response = getFeatureFlagValue(flagDetail);
2859
2960
  }
2860
2961
  }
2861
- const featureFlagReportedKey = `${key}_${response}`;
2862
- if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
2863
- if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
2864
- if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
2865
- else this.distinctIdHasSentFlagCalls[distinctId] = [
2866
- featureFlagReportedKey
2867
- ];
2868
- const properties = {
2869
- $feature_flag: key,
2870
- $feature_flag_response: response,
2871
- $feature_flag_id: flagDetail?.metadata?.id,
2872
- $feature_flag_version: flagDetail?.metadata?.version,
2873
- $feature_flag_reason: flagDetail?.reason?.description ?? flagDetail?.reason?.code,
2874
- locally_evaluated: flagWasLocallyEvaluated,
2875
- [`$feature/${key}`]: response,
2876
- $feature_flag_request_id: requestId,
2877
- $feature_flag_evaluated_at: evaluatedAt
2878
- };
2879
- if (featureFlagError) properties.$feature_flag_error = featureFlagError;
2880
- this.capture({
2881
- distinctId,
2882
- event: "$feature_flag_called",
2883
- properties,
2884
- groups,
2885
- disableGeoip
2886
- });
2962
+ if (sendFeatureFlagEvents) {
2963
+ const response = void 0 === result ? void 0 : false === result.enabled ? false : result.variant ?? true;
2964
+ const featureFlagReportedKey = `${key}_${response}`;
2965
+ if (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)) {
2966
+ if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
2967
+ if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
2968
+ else this.distinctIdHasSentFlagCalls[distinctId] = [
2969
+ featureFlagReportedKey
2970
+ ];
2971
+ const properties = {
2972
+ $feature_flag: key,
2973
+ $feature_flag_response: response,
2974
+ $feature_flag_id: flagId,
2975
+ $feature_flag_version: flagVersion,
2976
+ $feature_flag_reason: flagReason,
2977
+ locally_evaluated: flagWasLocallyEvaluated,
2978
+ [`$feature/${key}`]: response,
2979
+ $feature_flag_request_id: requestId,
2980
+ $feature_flag_evaluated_at: evaluatedAt
2981
+ };
2982
+ if (featureFlagError) properties.$feature_flag_error = featureFlagError;
2983
+ this.capture({
2984
+ distinctId,
2985
+ event: "$feature_flag_called",
2986
+ properties,
2987
+ groups,
2988
+ disableGeoip
2989
+ });
2990
+ }
2887
2991
  }
2888
- return response;
2992
+ if (void 0 !== result && void 0 !== this._payloadOverrides && key in this._payloadOverrides) result = {
2993
+ ...result,
2994
+ payload: this._payloadOverrides[key]
2995
+ };
2996
+ return result;
2997
+ }
2998
+ async getFeatureFlag(key, distinctId, options) {
2999
+ const result = await this._getFeatureFlagResult(key, distinctId, {
3000
+ ...options,
3001
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
3002
+ });
3003
+ if (void 0 === result) return;
3004
+ if (false === result.enabled) return false;
3005
+ return result.variant ?? true;
2889
3006
  }
2890
3007
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
2891
3008
  if (void 0 !== this._payloadOverrides && key in this._payloadOverrides) return this._payloadOverrides[key];
2892
- const { groups, disableGeoip } = options || {};
2893
- let { onlyEvaluateLocally, personProperties, groupProperties } = options || {};
2894
- const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
2895
- personProperties = adjustedProperties.allPersonProperties;
2896
- groupProperties = adjustedProperties.allGroupProperties;
2897
- let response;
2898
- const localEvaluationEnabled = void 0 !== this.featureFlagsPoller;
2899
- if (localEvaluationEnabled) {
2900
- await this.featureFlagsPoller?.loadFeatureFlags();
2901
- const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
2902
- if (flag) try {
2903
- const result = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, matchValue);
2904
- if (result) {
2905
- matchValue = result.value;
2906
- response = result.payload;
2907
- }
2908
- } catch (e) {
2909
- if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) this._logger?.info(`${e.name} when computing flag locally: ${flag.key}: ${e.message}`);
2910
- else throw e;
2911
- }
2912
- }
2913
- if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = false;
2914
- const payloadWasLocallyEvaluated = void 0 !== response;
2915
- if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
2916
- return response;
3009
+ const result = await this._getFeatureFlagResult(key, distinctId, {
3010
+ ...options,
3011
+ sendFeatureFlagEvents: false
3012
+ }, matchValue);
3013
+ if (void 0 === result) return;
3014
+ return result.payload ?? null;
3015
+ }
3016
+ async getFeatureFlagResult(key, distinctId, options) {
3017
+ return this._getFeatureFlagResult(key, distinctId, {
3018
+ ...options,
3019
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
3020
+ });
2917
3021
  }
2918
3022
  async getRemoteConfigPayload(flagKey) {
2919
3023
  if (!this.options.personalApiKey) throw new Error("Personal API key is required for remote config payload decryption");
@@ -2941,7 +3045,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
2941
3045
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
2942
3046
  personProperties = adjustedProperties.allPersonProperties;
2943
3047
  groupProperties = adjustedProperties.allGroupProperties;
2944
- if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = false;
3048
+ if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
2945
3049
  const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(distinctId, groups, personProperties, groupProperties, flagKeys);
2946
3050
  let featureFlags = {};
2947
3051
  let featureFlagPayloads = {};
@@ -3091,7 +3195,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
3091
3195
  const finalPersonProperties = sendFeatureFlagsOptions?.personProperties || {};
3092
3196
  const finalGroupProperties = sendFeatureFlagsOptions?.groupProperties || {};
3093
3197
  const flagKeys = sendFeatureFlagsOptions?.flagKeys;
3094
- const onlyEvaluateLocally = sendFeatureFlagsOptions?.onlyEvaluateLocally ?? false;
3198
+ const onlyEvaluateLocally = sendFeatureFlagsOptions?.onlyEvaluateLocally ?? this.options.strictLocalEvaluation ?? false;
3095
3199
  if (onlyEvaluateLocally) if (!((this.featureFlagsPoller?.featureFlags?.length || 0) > 0)) return {};
3096
3200
  else {
3097
3201
  const groupsWithStringValues = {};