posthog-js-lite 4.0.0 → 4.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Next
2
2
 
3
+ # 4.1.0 - 2025-06-12
4
+
5
+ 1. chore: use `/flags?v=2&config=true` instead of `/decide?v=4` for the flag evaluation backend
6
+
3
7
  # 4.0.0 - 2025-06-10
4
8
 
5
9
  ## Removed
package/lib/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "4.0.0";
5
+ var version = "4.1.0";
6
6
 
7
7
  var PostHogPersistedProperty;
8
8
  (function (PostHogPersistedProperty) {
@@ -26,11 +26,11 @@ var PostHogPersistedProperty;
26
26
  PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
27
27
  PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
28
28
  PostHogPersistedProperty["SessionReplay"] = "session_replay";
29
- PostHogPersistedProperty["DecideEndpointWasHit"] = "decide_endpoint_was_hit";
30
29
  PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
31
30
  PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
32
31
  PostHogPersistedProperty["Surveys"] = "surveys";
33
32
  PostHogPersistedProperty["RemoteConfig"] = "remote_config";
33
+ PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
34
34
  })(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
35
35
  // Any key prefixed with `attr__` can be added
36
36
  var Compression;
@@ -98,27 +98,27 @@ var ActionStepStringMatching;
98
98
  ActionStepStringMatching["Regex"] = "regex";
99
99
  })(ActionStepStringMatching || (ActionStepStringMatching = {}));
100
100
 
101
- const normalizeDecideResponse = (decideResponse) => {
102
- if ('flags' in decideResponse) {
103
- // Convert v4 format to v3 format
104
- const featureFlags = getFlagValuesFromFlags(decideResponse.flags);
105
- const featureFlagPayloads = getPayloadsFromFlags(decideResponse.flags);
101
+ const normalizeFlagsResponse = (flagsResponse) => {
102
+ if ('flags' in flagsResponse) {
103
+ // Convert v2 format to v1 format
104
+ const featureFlags = getFlagValuesFromFlags(flagsResponse.flags);
105
+ const featureFlagPayloads = getPayloadsFromFlags(flagsResponse.flags);
106
106
  return {
107
- ...decideResponse,
107
+ ...flagsResponse,
108
108
  featureFlags,
109
109
  featureFlagPayloads,
110
110
  };
111
111
  }
112
112
  else {
113
- // Convert v3 format to v4 format
114
- const featureFlags = decideResponse.featureFlags ?? {};
115
- const featureFlagPayloads = Object.fromEntries(Object.entries(decideResponse.featureFlagPayloads || {}).map(([k, v]) => [k, parsePayload(v)]));
113
+ // Convert v1 format to v2 format
114
+ const featureFlags = flagsResponse.featureFlags ?? {};
115
+ const featureFlagPayloads = Object.fromEntries(Object.entries(flagsResponse.featureFlagPayloads || {}).map(([k, v]) => [k, parsePayload(v)]));
116
116
  const flags = Object.fromEntries(Object.entries(featureFlags).map(([key, value]) => [
117
117
  key,
118
118
  getFlagDetailFromFlagAndPayload(key, value, featureFlagPayloads[key]),
119
119
  ]));
120
120
  return {
121
- ...decideResponse,
121
+ ...flagsResponse,
122
122
  featureFlags,
123
123
  featureFlagPayloads,
124
124
  flags,
@@ -190,7 +190,7 @@ const parsePayload = (response) => {
190
190
  * @param featureFlagPayloads - The feature flag payloads
191
191
  * @returns The normalized flag details
192
192
  */
193
- const createDecideResponseFromFlagsAndPayloads = (featureFlags, featureFlagPayloads) => {
193
+ const createFlagsResponseFromFlagsAndPayloads = (featureFlags, featureFlagPayloads) => {
194
194
  // If a feature flag payload key is not in the feature flags, we treat it as true feature flag.
195
195
  const allKeys = [...new Set([...Object.keys(featureFlags ?? {}), ...Object.keys(featureFlagPayloads ?? {})])];
196
196
  const enabledFlags = allKeys
@@ -200,7 +200,7 @@ const createDecideResponseFromFlagsAndPayloads = (featureFlags, featureFlagPaylo
200
200
  featureFlags: enabledFlags,
201
201
  featureFlagPayloads: featureFlagPayloads ?? {},
202
202
  };
203
- return normalizeDecideResponse(flagDetails);
203
+ return normalizeFlagsResponse(flagDetails);
204
204
  };
205
205
  const updateFlagValue = (flag, value) => {
206
206
  return {
@@ -216,90 +216,6 @@ function getVariantFromValue(value) {
216
216
  return typeof value === 'string' ? value : undefined;
217
217
  }
218
218
 
219
- // Rollout constants
220
- const NEW_FLAGS_ROLLOUT_PERCENTAGE = 1;
221
- // The fnv1a hashes of the tokens that are explicitly excluded from the rollout
222
- // see https://github.com/PostHog/posthog-js-lite/blob/main/posthog-core/src/utils.ts#L84
223
- // are hashed API tokens from our top 10 for each category supported by this SDK.
224
- const NEW_FLAGS_EXCLUDED_HASHES = new Set([
225
- // Node
226
- '61be3dd8',
227
- '96f6df5f',
228
- '8cfdba9b',
229
- 'bf027177',
230
- 'e59430a8',
231
- '7fa5500b',
232
- '569798e9',
233
- '04809ff7',
234
- '0ebc61a5',
235
- '32de7f98',
236
- '3beeb69a',
237
- '12d34ad9',
238
- '733853ec',
239
- '0645bb64',
240
- '5dcbee21',
241
- 'b1f95fa3',
242
- '2189e408',
243
- '82b460c2',
244
- '3a8cc979',
245
- '29ef8843',
246
- '2cdbf767',
247
- '38084b54',
248
- // React Native
249
- '50f9f8de',
250
- '41d0df91',
251
- '5c236689',
252
- 'c11aedd3',
253
- 'ada46672',
254
- 'f4331ee1',
255
- '42fed62a',
256
- 'c957462c',
257
- 'd62f705a',
258
- // Web (lots of teams per org, hence lots of API tokens)
259
- 'e0162666',
260
- '01b3e5cf',
261
- '441cef7f',
262
- 'bb9cafee',
263
- '8f348eb0',
264
- 'b2553f3a',
265
- '97469d7d',
266
- '39f21a76',
267
- '03706dcc',
268
- '27d50569',
269
- '307584a7',
270
- '6433e92e',
271
- '150c7fbb',
272
- '49f57f22',
273
- '3772f65b',
274
- '01eb8256',
275
- '3c9e9234',
276
- 'f853c7f7',
277
- 'c0ac4b67',
278
- 'cd609d40',
279
- '10ca9b1a',
280
- '8a87f11b',
281
- '8e8e5216',
282
- '1f6b63b3',
283
- 'db7943dd',
284
- '79b7164c',
285
- '07f78e33',
286
- '2d21b6fd',
287
- '952db5ee',
288
- 'a7d3b43f',
289
- '1924dd9c',
290
- '84e1b8f6',
291
- 'dff631b6',
292
- 'c5aa8a79',
293
- 'fa133a95',
294
- '498a4508',
295
- '24748755',
296
- '98f3d658',
297
- '21bbda67',
298
- '7dbfed69',
299
- 'be3ec24c',
300
- 'fc80b8e2',
301
- '75cc0998',
302
- ]);
303
219
  const STRING_FORMAT = 'utf8';
304
220
  function assert(truthyValue, message) {
305
221
  if (!truthyValue || typeof truthyValue !== 'string' || isEmpty(truthyValue)) {
@@ -355,30 +271,6 @@ const isError = (x) => {
355
271
  function getFetch() {
356
272
  return typeof fetch !== 'undefined' ? fetch : typeof globalThis.fetch !== 'undefined' ? globalThis.fetch : undefined;
357
273
  }
358
- // FNV-1a hash function
359
- // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
360
- // I know, I know, I'm rolling my own hash function, but I didn't want to take on
361
- // a crypto dependency and this is just temporary anyway
362
- function fnv1a(str) {
363
- let hash = 0x811c9dc5; // FNV offset basis
364
- for (let i = 0; i < str.length; i++) {
365
- hash ^= str.charCodeAt(i);
366
- hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
367
- }
368
- // Convert to hex string, padding to 8 chars
369
- return (hash >>> 0).toString(16).padStart(8, '0');
370
- }
371
- function isTokenInRollout(token, percentage = 0, excludedHashes) {
372
- const tokenHash = fnv1a(token);
373
- // Check excluded hashes (we're explicitly including these tokens from the rollout)
374
- if (excludedHashes?.has(tokenHash)) {
375
- return false;
376
- }
377
- // Convert hash to int and divide by max value to get number between 0-1
378
- const hashInt = parseInt(tokenHash, 16);
379
- const hashFloat = hashInt / 0xffffffff;
380
- return hashFloat < percentage;
381
- }
382
274
  function allSettled(promises) {
383
275
  return Promise.all(promises.map((p) => (p ?? Promise.resolve()).then((value) => ({ status: 'fulfilled', value }), (reason) => ({ status: 'rejected', reason }))));
384
276
  }
@@ -1110,13 +1002,9 @@ class PostHogCoreStateless {
1110
1002
  /***
1111
1003
  *** FEATURE FLAGS
1112
1004
  ***/
1113
- async getDecide(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
1005
+ async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
1114
1006
  await this._initPromise;
1115
- // Check if the API token is in the new flags rollout
1116
- // This is a temporary measure to ensure that we can still use the old flags API
1117
- // while we migrate to the new flags API
1118
- const useFlags = isTokenInRollout(this.apiKey, NEW_FLAGS_ROLLOUT_PERCENTAGE, NEW_FLAGS_EXCLUDED_HASHES);
1119
- const url = useFlags ? `${this.host}/flags/?v=2` : `${this.host}/decide/?v=4`;
1007
+ const url = `${this.host}/flags/?v=2&config=true`;
1120
1008
  const fetchOptions = {
1121
1009
  method: 'POST',
1122
1010
  headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
@@ -1129,11 +1017,11 @@ class PostHogCoreStateless {
1129
1017
  ...extraPayload,
1130
1018
  }),
1131
1019
  };
1132
- this.logMsgIfDebug(() => console.log('PostHog Debug', 'Decide URL', url));
1133
- // Don't retry /decide API calls
1020
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Flags URL', url));
1021
+ // Don't retry /flags API calls
1134
1022
  return this.fetchWithRetry(url, fetchOptions, { retryCount: 0 }, this.featureFlagsRequestTimeoutMs)
1135
1023
  .then((response) => response.json())
1136
- .then((response) => normalizeDecideResponse(response))
1024
+ .then((response) => normalizeFlagsResponse(response))
1137
1025
  .catch((error) => {
1138
1026
  this._events.emit('error', error);
1139
1027
  return undefined;
@@ -1162,15 +1050,15 @@ class PostHogCoreStateless {
1162
1050
  }
1163
1051
  async getFeatureFlagDetailStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1164
1052
  await this._initPromise;
1165
- const decideResponse = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [key]);
1166
- if (decideResponse === undefined) {
1053
+ const flagsResponse = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [key]);
1054
+ if (flagsResponse === undefined) {
1167
1055
  return undefined;
1168
1056
  }
1169
- const featureFlags = decideResponse.flags;
1057
+ const featureFlags = flagsResponse.flags;
1170
1058
  const flagDetail = featureFlags[key];
1171
1059
  return {
1172
1060
  response: flagDetail,
1173
- requestId: decideResponse.requestId,
1061
+ requestId: flagsResponse.requestId,
1174
1062
  };
1175
1063
  }
1176
1064
  async getFeatureFlagPayloadStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
@@ -1220,26 +1108,26 @@ class PostHogCoreStateless {
1220
1108
  if (flagKeysToEvaluate) {
1221
1109
  extraPayload['flag_keys_to_evaluate'] = flagKeysToEvaluate;
1222
1110
  }
1223
- const decideResponse = await this.getDecide(distinctId, groups, personProperties, groupProperties, extraPayload);
1224
- if (decideResponse === undefined) {
1111
+ const flagsResponse = await this.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
1112
+ if (flagsResponse === undefined) {
1225
1113
  // We probably errored out, so return undefined
1226
1114
  return undefined;
1227
1115
  }
1228
- // if there's an error on the decideResponse, log a console error, but don't throw an error
1229
- if (decideResponse.errorsWhileComputingFlags) {
1116
+ // if there's an error on the flagsResponse, log a console error, but don't throw an error
1117
+ if (flagsResponse.errorsWhileComputingFlags) {
1230
1118
  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');
1231
1119
  }
1232
1120
  // Add check for quota limitation on feature flags
1233
- if (decideResponse.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)) {
1121
+ if (flagsResponse.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)) {
1234
1122
  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');
1235
1123
  return {
1236
1124
  flags: {},
1237
1125
  featureFlags: {},
1238
1126
  featureFlagPayloads: {},
1239
- requestId: decideResponse?.requestId,
1127
+ requestId: flagsResponse?.requestId,
1240
1128
  };
1241
1129
  }
1242
- return decideResponse;
1130
+ return flagsResponse;
1243
1131
  }
1244
1132
  /***
1245
1133
  *** SURVEYS
@@ -1671,7 +1559,7 @@ class PostHogCore extends PostHogCoreStateless {
1671
1559
  const bootstrapFeatureFlags = bootstrap.featureFlags;
1672
1560
  const bootstrapFeatureFlagPayloads = bootstrap.featureFlagPayloads ?? {};
1673
1561
  if (bootstrapFeatureFlags && Object.keys(bootstrapFeatureFlags).length) {
1674
- const normalizedBootstrapFeatureFlagDetails = createDecideResponseFromFlagsAndPayloads(bootstrapFeatureFlags, bootstrapFeatureFlagPayloads);
1562
+ const normalizedBootstrapFeatureFlagDetails = createFlagsResponseFromFlagsAndPayloads(bootstrapFeatureFlags, bootstrapFeatureFlagPayloads);
1675
1563
  if (Object.keys(normalizedBootstrapFeatureFlagDetails.flags).length > 0) {
1676
1564
  this.setBootstrappedFeatureFlagDetails(normalizedBootstrapFeatureFlagDetails);
1677
1565
  const currentFeatureFlagDetails = this.getKnownFeatureFlagDetails() || { flags: {}, requestId: undefined };
@@ -1813,7 +1701,7 @@ class PostHogCore extends PostHogCoreStateless {
1813
1701
  ...maybeAdd('$set_once', userPropsOnce),
1814
1702
  });
1815
1703
  if (distinctId !== previousDistinctId) {
1816
- // We keep the AnonymousId to be used by decide calls and identify to link the previousId
1704
+ // We keep the AnonymousId to be used by flags calls and identify to link the previousId
1817
1705
  this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId);
1818
1706
  this.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
1819
1707
  this.reloadFeatureFlags();
@@ -1941,12 +1829,12 @@ class PostHogCore extends PostHogCoreStateless {
1941
1829
  /***
1942
1830
  *** FEATURE FLAGS
1943
1831
  ***/
1944
- async decideAsync(sendAnonDistinctId = true) {
1832
+ async flagsAsync(sendAnonDistinctId = true) {
1945
1833
  await this._initPromise;
1946
- if (this._decideResponsePromise) {
1947
- return this._decideResponsePromise;
1834
+ if (this._flagsResponsePromise) {
1835
+ return this._flagsResponsePromise;
1948
1836
  }
1949
- return this._decideAsync(sendAnonDistinctId);
1837
+ return this._flagsAsync(sendAnonDistinctId);
1950
1838
  }
1951
1839
  cacheSessionReplay(source, response) {
1952
1840
  const sessionReplay = response?.sessionRecording;
@@ -2017,8 +1905,8 @@ class PostHogCore extends PostHogCoreStateless {
2017
1905
  });
2018
1906
  return this._remoteConfigResponsePromise;
2019
1907
  }
2020
- async _decideAsync(sendAnonDistinctId = true) {
2021
- this._decideResponsePromise = this._initPromise
1908
+ async _flagsAsync(sendAnonDistinctId = true) {
1909
+ this._flagsResponsePromise = this._initPromise
2022
1910
  .then(async () => {
2023
1911
  const distinctId = this.getDistinctId();
2024
1912
  const groups = this.props.$groups || {};
@@ -2028,7 +1916,7 @@ class PostHogCore extends PostHogCoreStateless {
2028
1916
  const extraProperties = {
2029
1917
  $anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
2030
1918
  };
2031
- const res = await super.getDecide(distinctId, groups, personProperties, groupProperties, extraProperties);
1919
+ const res = await super.getFlags(distinctId, groups, personProperties, groupProperties, extraProperties);
2032
1920
  // Add check for quota limitation on feature flags
2033
1921
  if (res?.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)) {
2034
1922
  // Unset all feature flags by setting to null
@@ -2052,22 +1940,22 @@ class PostHogCore extends PostHogCoreStateless {
2052
1940
  };
2053
1941
  }
2054
1942
  this.setKnownFeatureFlagDetails(newFeatureFlagDetails);
2055
- // Mark that we hit the /decide endpoint so we can capture this in the $feature_flag_called event
2056
- this.setPersistedProperty(PostHogPersistedProperty.DecideEndpointWasHit, true);
2057
- this.cacheSessionReplay('decide/flags', res);
1943
+ // Mark that we hit the /flags endpoint so we can capture this in the $feature_flag_called event
1944
+ this.setPersistedProperty(PostHogPersistedProperty.FlagsEndpointWasHit, true);
1945
+ this.cacheSessionReplay('flags', res);
2058
1946
  }
2059
1947
  return res;
2060
1948
  })
2061
1949
  .finally(() => {
2062
- this._decideResponsePromise = undefined;
1950
+ this._flagsResponsePromise = undefined;
2063
1951
  });
2064
- return this._decideResponsePromise;
1952
+ return this._flagsResponsePromise;
2065
1953
  }
2066
1954
  // We only store the flags and request id in the feature flag details storage key
2067
- setKnownFeatureFlagDetails(decideResponse) {
1955
+ setKnownFeatureFlagDetails(flagsResponse) {
2068
1956
  this.wrap(() => {
2069
- this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagDetails, decideResponse);
2070
- this._events.emit('featureflags', getFlagValuesFromFlags(decideResponse?.flags ?? {}));
1957
+ this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagDetails, flagsResponse);
1958
+ this._events.emit('featureflags', getFlagValuesFromFlags(flagsResponse?.flags ?? {}));
2071
1959
  });
2072
1960
  }
2073
1961
  getKnownFeatureFlagDetails() {
@@ -2079,9 +1967,9 @@ class PostHogCore extends PostHogCoreStateless {
2079
1967
  if (featureFlags === undefined && featureFlagPayloads === undefined) {
2080
1968
  return undefined;
2081
1969
  }
2082
- return createDecideResponseFromFlagsAndPayloads(featureFlags ?? {}, featureFlagPayloads ?? {});
1970
+ return createFlagsResponseFromFlagsAndPayloads(featureFlags ?? {}, featureFlagPayloads ?? {});
2083
1971
  }
2084
- return normalizeDecideResponse(storedDetails);
1972
+ return normalizeFlagsResponse(storedDetails);
2085
1973
  }
2086
1974
  getKnownFeatureFlags() {
2087
1975
  const featureFlagDetails = this.getKnownFeatureFlagDetails();
@@ -2145,8 +2033,8 @@ class PostHogCore extends PostHogCoreStateless {
2145
2033
  ...maybeAdd('$feature_flag_reason', featureFlag?.reason?.description ?? featureFlag?.reason?.code),
2146
2034
  ...maybeAdd('$feature_flag_bootstrapped_response', bootstrappedResponse),
2147
2035
  ...maybeAdd('$feature_flag_bootstrapped_payload', bootstrappedPayload),
2148
- // If we haven't yet received a response from the /decide endpoint, we must have used the bootstrapped value
2149
- $used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.DecideEndpointWasHit),
2036
+ // If we haven't yet received a response from the /flags endpoint, we must have used the bootstrapped value
2037
+ $used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.FlagsEndpointWasHit),
2150
2038
  ...maybeAdd('$feature_flag_request_id', details.requestId),
2151
2039
  });
2152
2040
  }
@@ -2195,7 +2083,7 @@ class PostHogCore extends PostHogCoreStateless {
2195
2083
  ...details,
2196
2084
  flags,
2197
2085
  };
2198
- return normalizeDecideResponse(result);
2086
+ return normalizeFlagsResponse(result);
2199
2087
  }
2200
2088
  getFeatureFlagsAndPayloads() {
2201
2089
  const flags = this.getFeatureFlags();
@@ -2213,14 +2101,14 @@ class PostHogCore extends PostHogCoreStateless {
2213
2101
  return !!response;
2214
2102
  }
2215
2103
  // Used when we want to trigger the reload but we don't care about the result
2216
- reloadFeatureFlags(cb) {
2217
- this.decideAsync()
2104
+ reloadFeatureFlags(options) {
2105
+ this.flagsAsync(true)
2218
2106
  .then((res) => {
2219
- cb?.(undefined, res?.featureFlags);
2107
+ options?.cb?.(undefined, res?.featureFlags);
2220
2108
  })
2221
2109
  .catch((e) => {
2222
- cb?.(e, undefined);
2223
- if (!cb) {
2110
+ options?.cb?.(e, undefined);
2111
+ if (!options?.cb) {
2224
2112
  this.logMsgIfDebug(() => console.log('PostHog Debug', 'Error reloading feature flags', e));
2225
2113
  }
2226
2114
  });
@@ -2228,8 +2116,8 @@ class PostHogCore extends PostHogCoreStateless {
2228
2116
  async reloadRemoteConfigAsync() {
2229
2117
  return await this.remoteConfigAsync();
2230
2118
  }
2231
- async reloadFeatureFlagsAsync(sendAnonDistinctId = true) {
2232
- return (await this.decideAsync(sendAnonDistinctId))?.featureFlags;
2119
+ async reloadFeatureFlagsAsync(sendAnonDistinctId) {
2120
+ return (await this.flagsAsync(sendAnonDistinctId ?? true))?.featureFlags;
2233
2121
  }
2234
2122
  onFeatureFlags(cb) {
2235
2123
  return this.on('featureflags', async () => {