posthog-node 5.8.1 → 5.8.3

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.
@@ -780,7 +780,7 @@ function setupExpressErrorHandler(_posthog, app) {
780
780
  });
781
781
  }
782
782
 
783
- var version = "5.8.1";
783
+ var version = "5.8.3";
784
784
 
785
785
  /**
786
786
  * A lazy value that is only computed when needed. Inspired by C#'s Lazy<T> class.
@@ -967,12 +967,14 @@ class FeatureFlagsPoller {
967
967
  const payloads = {};
968
968
  let fallbackToFlags = this.featureFlags.length == 0;
969
969
  const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map(key => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
970
+ // Create a shared evaluation cache to prevent memory leaks when processing many flags
971
+ const sharedEvaluationCache = {};
970
972
  await Promise.all(flagsToEvaluate.map(async flag => {
971
973
  try {
972
974
  const {
973
975
  value: matchValue,
974
976
  payload: matchPayload
975
- } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties);
977
+ } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, undefined /* matchValue */, sharedEvaluationCache);
976
978
  response[flag.key] = matchValue;
977
979
  if (matchPayload) {
978
980
  payloads[flag.key] = matchPayload;
@@ -992,9 +994,11 @@ class FeatureFlagsPoller {
992
994
  fallbackToFlags
993
995
  };
994
996
  }
995
- async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue) {
996
- // Always ensure flags are loaded for payload computation
997
- await this.loadFeatureFlags();
997
+ async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue, evaluationCache, skipLoadCheck = false) {
998
+ // Only load flags if not already loaded and not skipping the check
999
+ if (!skipLoadCheck) {
1000
+ await this.loadFeatureFlags();
1001
+ }
998
1002
  if (!this.loadedSuccessfullyOnce) {
999
1003
  return {
1000
1004
  value: false,
@@ -1006,7 +1010,7 @@ class FeatureFlagsPoller {
1006
1010
  if (matchValue !== undefined) {
1007
1011
  flagValue = matchValue;
1008
1012
  } else {
1009
- flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties);
1013
+ flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties, evaluationCache);
1010
1014
  }
1011
1015
  // Always compute payload based on the final flagValue (whether provided or computed)
1012
1016
  const payload = this.getFeatureFlagPayload(flag.key, flagValue);
@@ -1015,7 +1019,7 @@ class FeatureFlagsPoller {
1015
1019
  payload
1016
1020
  };
1017
1021
  }
1018
- async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1022
+ async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
1019
1023
  if (flag.ensure_experience_continuity) {
1020
1024
  throw new InconclusiveMatchError('Flag has experience continuity enabled');
1021
1025
  }
@@ -1035,9 +1039,9 @@ class FeatureFlagsPoller {
1035
1039
  return false;
1036
1040
  }
1037
1041
  const focusedGroupProperties = groupProperties[groupName];
1038
- return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
1042
+ return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationCache);
1039
1043
  } else {
1040
- return await this.matchFeatureFlagProperties(flag, distinctId, personProperties);
1044
+ return await this.matchFeatureFlagProperties(flag, distinctId, personProperties, evaluationCache);
1041
1045
  }
1042
1046
  }
1043
1047
  getFeatureFlagPayload(key, flagValue) {
@@ -1681,6 +1685,35 @@ const THIRTY_SECONDS = 30 * 1000;
1681
1685
  const MAX_CACHE_SIZE = 50 * 1000;
1682
1686
  // The actual exported Nodejs API.
1683
1687
  class PostHogBackendClient extends core.PostHogCoreStateless {
1688
+ /**
1689
+ * Initialize a new PostHog client instance.
1690
+ *
1691
+ * @example
1692
+ * ```ts
1693
+ * // Basic initialization
1694
+ * const client = new PostHogBackendClient(
1695
+ * 'your-api-key',
1696
+ * { host: 'https://app.posthog.com' }
1697
+ * )
1698
+ * ```
1699
+ *
1700
+ * @example
1701
+ * ```ts
1702
+ * // With personal API key
1703
+ * const client = new PostHogBackendClient(
1704
+ * 'your-api-key',
1705
+ * {
1706
+ * host: 'https://app.posthog.com',
1707
+ * personalApiKey: 'your-personal-api-key'
1708
+ * }
1709
+ * )
1710
+ * ```
1711
+ *
1712
+ * {@label Initialization}
1713
+ *
1714
+ * @param apiKey - Your PostHog project API key
1715
+ * @param options - Configuration options for the client
1716
+ */
1684
1717
  constructor(apiKey, options = {}) {
1685
1718
  super(apiKey, options);
1686
1719
  this._memoryStorage = new PostHogMemoryStorage();
@@ -1716,31 +1749,185 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1716
1749
  this.distinctIdHasSentFlagCalls = {};
1717
1750
  this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
1718
1751
  }
1752
+ /**
1753
+ * Get a persisted property value from memory storage.
1754
+ *
1755
+ * @example
1756
+ * ```ts
1757
+ * // Get user ID
1758
+ * const userId = client.getPersistedProperty('userId')
1759
+ * ```
1760
+ *
1761
+ * @example
1762
+ * ```ts
1763
+ * // Get session ID
1764
+ * const sessionId = client.getPersistedProperty('sessionId')
1765
+ * ```
1766
+ *
1767
+ * {@label Initialization}
1768
+ *
1769
+ * @param key - The property key to retrieve
1770
+ * @returns The stored property value or undefined if not found
1771
+ */
1719
1772
  getPersistedProperty(key) {
1720
1773
  return this._memoryStorage.getProperty(key);
1721
1774
  }
1775
+ /**
1776
+ * Set a persisted property value in memory storage.
1777
+ *
1778
+ * @example
1779
+ * ```ts
1780
+ * // Set user ID
1781
+ * client.setPersistedProperty('userId', 'user_123')
1782
+ * ```
1783
+ *
1784
+ * @example
1785
+ * ```ts
1786
+ * // Set session ID
1787
+ * client.setPersistedProperty('sessionId', 'session_456')
1788
+ * ```
1789
+ *
1790
+ * {@label Initialization}
1791
+ *
1792
+ * @param key - The property key to set
1793
+ * @param value - The value to store (null to remove)
1794
+ */
1722
1795
  setPersistedProperty(key, value) {
1723
1796
  return this._memoryStorage.setProperty(key, value);
1724
1797
  }
1798
+ /**
1799
+ * Make an HTTP request using the configured fetch function or default fetch.
1800
+ *
1801
+ * @example
1802
+ * ```ts
1803
+ * // POST request
1804
+ * const response = await client.fetch('/api/endpoint', {
1805
+ * method: 'POST',
1806
+ * headers: { 'Content-Type': 'application/json' },
1807
+ * body: JSON.stringify(data)
1808
+ * })
1809
+ * ```
1810
+ *
1811
+ * @internal
1812
+ *
1813
+ * {@label Initialization}
1814
+ *
1815
+ * @param url - The URL to fetch
1816
+ * @param options - Fetch options
1817
+ * @returns Promise resolving to the fetch response
1818
+ */
1725
1819
  fetch(url, options) {
1726
1820
  return this.options.fetch ? this.options.fetch(url, options) : fetch(url, options);
1727
1821
  }
1822
+ /**
1823
+ * Get the library version from package.json.
1824
+ *
1825
+ * @example
1826
+ * ```ts
1827
+ * // Get version
1828
+ * const version = client.getLibraryVersion()
1829
+ * console.log(`Using PostHog SDK version: ${version}`)
1830
+ * ```
1831
+ *
1832
+ * {@label Initialization}
1833
+ *
1834
+ * @returns The current library version string
1835
+ */
1728
1836
  getLibraryVersion() {
1729
1837
  return version;
1730
1838
  }
1839
+ /**
1840
+ * Get the custom user agent string for this client.
1841
+ *
1842
+ * @example
1843
+ * ```ts
1844
+ * // Get user agent
1845
+ * const userAgent = client.getCustomUserAgent()
1846
+ * // Returns: "posthog-node/5.7.0"
1847
+ * ```
1848
+ *
1849
+ * {@label Identification}
1850
+ *
1851
+ * @returns The formatted user agent string
1852
+ */
1731
1853
  getCustomUserAgent() {
1732
1854
  return `${this.getLibraryId()}/${this.getLibraryVersion()}`;
1733
1855
  }
1856
+ /**
1857
+ * Enable the PostHog client (opt-in).
1858
+ *
1859
+ * @example
1860
+ * ```ts
1861
+ * // Enable client
1862
+ * await client.enable()
1863
+ * // Client is now enabled and will capture events
1864
+ * ```
1865
+ *
1866
+ * {@label Privacy}
1867
+ *
1868
+ * @returns Promise that resolves when the client is enabled
1869
+ */
1734
1870
  enable() {
1735
1871
  return super.optIn();
1736
1872
  }
1873
+ /**
1874
+ * Disable the PostHog client (opt-out).
1875
+ *
1876
+ * @example
1877
+ * ```ts
1878
+ * // Disable client
1879
+ * await client.disable()
1880
+ * // Client is now disabled and will not capture events
1881
+ * ```
1882
+ *
1883
+ * {@label Privacy}
1884
+ *
1885
+ * @returns Promise that resolves when the client is disabled
1886
+ */
1737
1887
  disable() {
1738
1888
  return super.optOut();
1739
1889
  }
1890
+ /**
1891
+ * Enable or disable debug logging.
1892
+ *
1893
+ * @example
1894
+ * ```ts
1895
+ * // Enable debug logging
1896
+ * client.debug(true)
1897
+ * ```
1898
+ *
1899
+ * @example
1900
+ * ```ts
1901
+ * // Disable debug logging
1902
+ * client.debug(false)
1903
+ * ```
1904
+ *
1905
+ * {@label Initialization}
1906
+ *
1907
+ * @param enabled - Whether to enable debug logging
1908
+ */
1740
1909
  debug(enabled = true) {
1741
1910
  super.debug(enabled);
1742
1911
  this.featureFlagsPoller?.debug(enabled);
1743
1912
  }
1913
+ /**
1914
+ * Capture an event manually.
1915
+ *
1916
+ * @example
1917
+ * ```ts
1918
+ * // Basic capture
1919
+ * client.capture({
1920
+ * distinctId: 'user_123',
1921
+ * event: 'button_clicked',
1922
+ * properties: { button_color: 'red' }
1923
+ * })
1924
+ * ```
1925
+ *
1926
+ * {@label Capture}
1927
+ *
1928
+ * @param props - The event properties
1929
+ * @returns void
1930
+ */
1744
1931
  capture(props) {
1745
1932
  if (typeof props === 'string') {
1746
1933
  this.logMsgIfDebug(() => console.warn('Called capture() with a string as the first argument when an object was expected.'));
@@ -1762,6 +1949,49 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1762
1949
  }
1763
1950
  }));
1764
1951
  }
1952
+ /**
1953
+ * Capture an event immediately (synchronously).
1954
+ *
1955
+ * @example
1956
+ * ```ts
1957
+ * // Basic immediate capture
1958
+ * await client.captureImmediate({
1959
+ * distinctId: 'user_123',
1960
+ * event: 'button_clicked',
1961
+ * properties: { button_color: 'red' }
1962
+ * })
1963
+ * ```
1964
+ *
1965
+ * @example
1966
+ * ```ts
1967
+ * // With feature flags
1968
+ * await client.captureImmediate({
1969
+ * distinctId: 'user_123',
1970
+ * event: 'user_action',
1971
+ * sendFeatureFlags: true
1972
+ * })
1973
+ * ```
1974
+ *
1975
+ * @example
1976
+ * ```ts
1977
+ * // With custom feature flags options
1978
+ * await client.captureImmediate({
1979
+ * distinctId: 'user_123',
1980
+ * event: 'user_action',
1981
+ * sendFeatureFlags: {
1982
+ * onlyEvaluateLocally: true,
1983
+ * personProperties: { plan: 'premium' },
1984
+ * groupProperties: { org: { tier: 'enterprise' } }
1985
+ * flagKeys: ['flag1', 'flag2']
1986
+ * }
1987
+ * })
1988
+ * ```
1989
+ *
1990
+ * {@label Capture}
1991
+ *
1992
+ * @param props - The event properties
1993
+ * @returns Promise that resolves when the event is captured
1994
+ */
1765
1995
  async captureImmediate(props) {
1766
1996
  if (typeof props === 'string') {
1767
1997
  this.logMsgIfDebug(() => console.warn('Called captureImmediate() with a string as the first argument when an object was expected.'));
@@ -1783,6 +2013,38 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1783
2013
  }
1784
2014
  }));
1785
2015
  }
2016
+ /**
2017
+ * Identify a user and set their properties.
2018
+ *
2019
+ * @example
2020
+ * ```ts
2021
+ * // Basic identify with properties
2022
+ * client.identify({
2023
+ * distinctId: 'user_123',
2024
+ * properties: {
2025
+ * name: 'John Doe',
2026
+ * email: 'john@example.com',
2027
+ * plan: 'premium'
2028
+ * }
2029
+ * })
2030
+ * ```
2031
+ *
2032
+ * @example
2033
+ * ```ts
2034
+ * // Using $set and $set_once
2035
+ * client.identify({
2036
+ * distinctId: 'user_123',
2037
+ * properties: {
2038
+ * $set: { name: 'John Doe', email: 'john@example.com' },
2039
+ * $set_once: { first_login: new Date().toISOString() }
2040
+ * }
2041
+ * })
2042
+ * ```
2043
+ *
2044
+ * {@label Identification}
2045
+ *
2046
+ * @param data - The identify data containing distinctId and properties
2047
+ */
1786
2048
  identify({
1787
2049
  distinctId,
1788
2050
  properties,
@@ -1801,6 +2063,26 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1801
2063
  disableGeoip
1802
2064
  });
1803
2065
  }
2066
+ /**
2067
+ * Identify a user and set their properties immediately (synchronously).
2068
+ *
2069
+ * @example
2070
+ * ```ts
2071
+ * // Basic immediate identify
2072
+ * await client.identifyImmediate({
2073
+ * distinctId: 'user_123',
2074
+ * properties: {
2075
+ * name: 'John Doe',
2076
+ * email: 'john@example.com'
2077
+ * }
2078
+ * })
2079
+ * ```
2080
+ *
2081
+ * {@label Identification}
2082
+ *
2083
+ * @param data - The identify data containing distinctId and properties
2084
+ * @returns Promise that resolves when the identify is processed
2085
+ */
1804
2086
  async identifyImmediate({
1805
2087
  distinctId,
1806
2088
  properties,
@@ -1818,19 +2100,96 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1818
2100
  disableGeoip
1819
2101
  });
1820
2102
  }
2103
+ /**
2104
+ * Create an alias to link two distinct IDs together.
2105
+ *
2106
+ * @example
2107
+ * ```ts
2108
+ * // Link an anonymous user to an identified user
2109
+ * client.alias({
2110
+ * distinctId: 'anonymous_123',
2111
+ * alias: 'user_456'
2112
+ * })
2113
+ * ```
2114
+ *
2115
+ * {@label Identification}
2116
+ *
2117
+ * @param data - The alias data containing distinctId and alias
2118
+ */
1821
2119
  alias(data) {
1822
2120
  super.aliasStateless(data.alias, data.distinctId, undefined, {
1823
2121
  disableGeoip: data.disableGeoip
1824
2122
  });
1825
2123
  }
2124
+ /**
2125
+ * Create an alias to link two distinct IDs together immediately (synchronously).
2126
+ *
2127
+ * @example
2128
+ * ```ts
2129
+ * // Link an anonymous user to an identified user immediately
2130
+ * await client.aliasImmediate({
2131
+ * distinctId: 'anonymous_123',
2132
+ * alias: 'user_456'
2133
+ * })
2134
+ * ```
2135
+ *
2136
+ * {@label Identification}
2137
+ *
2138
+ * @param data - The alias data containing distinctId and alias
2139
+ * @returns Promise that resolves when the alias is processed
2140
+ */
1826
2141
  async aliasImmediate(data) {
1827
2142
  await super.aliasStatelessImmediate(data.alias, data.distinctId, undefined, {
1828
2143
  disableGeoip: data.disableGeoip
1829
2144
  });
1830
2145
  }
2146
+ /**
2147
+ * Check if local evaluation of feature flags is ready.
2148
+ *
2149
+ * @example
2150
+ * ```ts
2151
+ * // Check if ready
2152
+ * if (client.isLocalEvaluationReady()) {
2153
+ * // Local evaluation is ready, can evaluate flags locally
2154
+ * const flag = await client.getFeatureFlag('flag-key', 'user_123')
2155
+ * } else {
2156
+ * // Local evaluation not ready, will use remote evaluation
2157
+ * const flag = await client.getFeatureFlag('flag-key', 'user_123')
2158
+ * }
2159
+ * ```
2160
+ *
2161
+ * {@label Feature flags}
2162
+ *
2163
+ * @returns true if local evaluation is ready, false otherwise
2164
+ */
1831
2165
  isLocalEvaluationReady() {
1832
2166
  return this.featureFlagsPoller?.isLocalEvaluationReady() ?? false;
1833
2167
  }
2168
+ /**
2169
+ * Wait for local evaluation of feature flags to be ready.
2170
+ *
2171
+ * @example
2172
+ * ```ts
2173
+ * // Wait for local evaluation
2174
+ * const isReady = await client.waitForLocalEvaluationReady()
2175
+ * if (isReady) {
2176
+ * console.log('Local evaluation is ready')
2177
+ * } else {
2178
+ * console.log('Local evaluation timed out')
2179
+ * }
2180
+ * ```
2181
+ *
2182
+ * @example
2183
+ * ```ts
2184
+ * // Wait with custom timeout
2185
+ * const isReady = await client.waitForLocalEvaluationReady(10000) // 10 seconds
2186
+ * ```
2187
+ *
2188
+ * {@label Feature flags}
2189
+ *
2190
+ * @param timeoutMs - Timeout in milliseconds (default: 30000)
2191
+ * @returns Promise that resolves to true if ready, false if timed out
2192
+ */
1834
2193
  async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
1835
2194
  if (this.isLocalEvaluationReady()) {
1836
2195
  return true;
@@ -1850,6 +2209,47 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1850
2209
  });
1851
2210
  });
1852
2211
  }
2212
+ /**
2213
+ * Get the value of a feature flag for a specific user.
2214
+ *
2215
+ * @example
2216
+ * ```ts
2217
+ * // Basic feature flag check
2218
+ * const flagValue = await client.getFeatureFlag('new-feature', 'user_123')
2219
+ * if (flagValue === 'variant-a') {
2220
+ * // Show variant A
2221
+ * } else if (flagValue === 'variant-b') {
2222
+ * // Show variant B
2223
+ * } else {
2224
+ * // Flag is disabled or not found
2225
+ * }
2226
+ * ```
2227
+ *
2228
+ * @example
2229
+ * ```ts
2230
+ * // With groups and properties
2231
+ * const flagValue = await client.getFeatureFlag('org-feature', 'user_123', {
2232
+ * groups: { organization: 'acme-corp' },
2233
+ * personProperties: { plan: 'enterprise' },
2234
+ * groupProperties: { organization: { tier: 'premium' } }
2235
+ * })
2236
+ * ```
2237
+ *
2238
+ * @example
2239
+ * ```ts
2240
+ * // Only evaluate locally
2241
+ * const flagValue = await client.getFeatureFlag('local-flag', 'user_123', {
2242
+ * onlyEvaluateLocally: true
2243
+ * })
2244
+ * ```
2245
+ *
2246
+ * {@label Feature flags}
2247
+ *
2248
+ * @param key - The feature flag key
2249
+ * @param distinctId - The user's distinct ID
2250
+ * @param options - Optional configuration for flag evaluation
2251
+ * @returns Promise that resolves to the flag value or undefined
2252
+ */
1853
2253
  async getFeatureFlag(key, distinctId, options) {
1854
2254
  const {
1855
2255
  groups,
@@ -1869,7 +2269,7 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1869
2269
  onlyEvaluateLocally = false;
1870
2270
  }
1871
2271
  if (sendFeatureFlagEvents == undefined) {
1872
- sendFeatureFlagEvents = true;
2272
+ sendFeatureFlagEvents = this.options.sendFeatureFlagEvent ?? true;
1873
2273
  }
1874
2274
  let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
1875
2275
  const flagWasLocallyEvaluated = response !== undefined;
@@ -1913,6 +2313,41 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1913
2313
  }
1914
2314
  return response;
1915
2315
  }
2316
+ /**
2317
+ * Get the payload for a feature flag.
2318
+ *
2319
+ * @example
2320
+ * ```ts
2321
+ * // Get payload for a feature flag
2322
+ * const payload = await client.getFeatureFlagPayload('flag-key', 'user_123')
2323
+ * if (payload) {
2324
+ * console.log('Flag payload:', payload)
2325
+ * }
2326
+ * ```
2327
+ *
2328
+ * @example
2329
+ * ```ts
2330
+ * // Get payload with specific match value
2331
+ * const payload = await client.getFeatureFlagPayload('flag-key', 'user_123', 'variant-a')
2332
+ * ```
2333
+ *
2334
+ * @example
2335
+ * ```ts
2336
+ * // With groups and properties
2337
+ * const payload = await client.getFeatureFlagPayload('org-flag', 'user_123', undefined, {
2338
+ * groups: { organization: 'acme-corp' },
2339
+ * personProperties: { plan: 'enterprise' }
2340
+ * })
2341
+ * ```
2342
+ *
2343
+ * {@label Feature flags}
2344
+ *
2345
+ * @param key - The feature flag key
2346
+ * @param distinctId - The user's distinct ID
2347
+ * @param matchValue - Optional match value to get payload for
2348
+ * @param options - Optional configuration for flag evaluation
2349
+ * @returns Promise that resolves to the flag payload or undefined
2350
+ */
1916
2351
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
1917
2352
  const {
1918
2353
  groups,
@@ -1920,7 +2355,6 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1920
2355
  } = options || {};
1921
2356
  let {
1922
2357
  onlyEvaluateLocally,
1923
- sendFeatureFlagEvents,
1924
2358
  personProperties,
1925
2359
  groupProperties
1926
2360
  } = options || {};
@@ -1945,15 +2379,30 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1945
2379
  if (onlyEvaluateLocally == undefined) {
1946
2380
  onlyEvaluateLocally = false;
1947
2381
  }
1948
- if (sendFeatureFlagEvents == undefined) {
1949
- sendFeatureFlagEvents = true;
1950
- }
1951
2382
  const payloadWasLocallyEvaluated = response !== undefined;
1952
2383
  if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
1953
2384
  response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
1954
2385
  }
1955
2386
  return response;
1956
2387
  }
2388
+ /**
2389
+ * Get the remote config payload for a feature flag.
2390
+ *
2391
+ * @example
2392
+ * ```ts
2393
+ * // Get remote config payload
2394
+ * const payload = await client.getRemoteConfigPayload('flag-key')
2395
+ * if (payload) {
2396
+ * console.log('Remote config payload:', payload)
2397
+ * }
2398
+ * ```
2399
+ *
2400
+ * {@label Feature flags}
2401
+ *
2402
+ * @param flagKey - The feature flag key
2403
+ * @returns Promise that resolves to the remote config payload or undefined
2404
+ * @throws Error if personal API key is not provided
2405
+ */
1957
2406
  async getRemoteConfigPayload(flagKey) {
1958
2407
  if (!this.options.personalApiKey) {
1959
2408
  throw new Error('Personal API key is required for remote config payload decryption');
@@ -1977,6 +2426,38 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1977
2426
  }
1978
2427
  return parsed;
1979
2428
  }
2429
+ /**
2430
+ * Check if a feature flag is enabled for a specific user.
2431
+ *
2432
+ * @example
2433
+ * ```ts
2434
+ * // Basic feature flag check
2435
+ * const isEnabled = await client.isFeatureEnabled('new-feature', 'user_123')
2436
+ * if (isEnabled) {
2437
+ * // Feature is enabled
2438
+ * console.log('New feature is active')
2439
+ * } else {
2440
+ * // Feature is disabled
2441
+ * console.log('New feature is not active')
2442
+ * }
2443
+ * ```
2444
+ *
2445
+ * @example
2446
+ * ```ts
2447
+ * // With groups and properties
2448
+ * const isEnabled = await client.isFeatureEnabled('org-feature', 'user_123', {
2449
+ * groups: { organization: 'acme-corp' },
2450
+ * personProperties: { plan: 'enterprise' }
2451
+ * })
2452
+ * ```
2453
+ *
2454
+ * {@label Feature flags}
2455
+ *
2456
+ * @param key - The feature flag key
2457
+ * @param distinctId - The user's distinct ID
2458
+ * @param options - Optional configuration for flag evaluation
2459
+ * @returns Promise that resolves to true if enabled, false if disabled, undefined if not found
2460
+ */
1980
2461
  async isFeatureEnabled(key, distinctId, options) {
1981
2462
  const feat = await this.getFeatureFlag(key, distinctId, options);
1982
2463
  if (feat === undefined) {
@@ -1984,10 +2465,77 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
1984
2465
  }
1985
2466
  return !!feat || false;
1986
2467
  }
2468
+ /**
2469
+ * Get all feature flag values for a specific user.
2470
+ *
2471
+ * @example
2472
+ * ```ts
2473
+ * // Get all flags for a user
2474
+ * const allFlags = await client.getAllFlags('user_123')
2475
+ * console.log('User flags:', allFlags)
2476
+ * // Output: { 'flag-1': 'variant-a', 'flag-2': false, 'flag-3': 'variant-b' }
2477
+ * ```
2478
+ *
2479
+ * @example
2480
+ * ```ts
2481
+ * // With specific flag keys
2482
+ * const specificFlags = await client.getAllFlags('user_123', {
2483
+ * flagKeys: ['flag-1', 'flag-2']
2484
+ * })
2485
+ * ```
2486
+ *
2487
+ * @example
2488
+ * ```ts
2489
+ * // With groups and properties
2490
+ * const orgFlags = await client.getAllFlags('user_123', {
2491
+ * groups: { organization: 'acme-corp' },
2492
+ * personProperties: { plan: 'enterprise' }
2493
+ * })
2494
+ * ```
2495
+ *
2496
+ * {@label Feature flags}
2497
+ *
2498
+ * @param distinctId - The user's distinct ID
2499
+ * @param options - Optional configuration for flag evaluation
2500
+ * @returns Promise that resolves to a record of flag keys and their values
2501
+ */
1987
2502
  async getAllFlags(distinctId, options) {
1988
2503
  const response = await this.getAllFlagsAndPayloads(distinctId, options);
1989
2504
  return response.featureFlags || {};
1990
2505
  }
2506
+ /**
2507
+ * Get all feature flag values and payloads for a specific user.
2508
+ *
2509
+ * @example
2510
+ * ```ts
2511
+ * // Get all flags and payloads for a user
2512
+ * const result = await client.getAllFlagsAndPayloads('user_123')
2513
+ * console.log('Flags:', result.featureFlags)
2514
+ * console.log('Payloads:', result.featureFlagPayloads)
2515
+ * ```
2516
+ *
2517
+ * @example
2518
+ * ```ts
2519
+ * // With specific flag keys
2520
+ * const result = await client.getAllFlagsAndPayloads('user_123', {
2521
+ * flagKeys: ['flag-1', 'flag-2']
2522
+ * })
2523
+ * ```
2524
+ *
2525
+ * @example
2526
+ * ```ts
2527
+ * // Only evaluate locally
2528
+ * const result = await client.getAllFlagsAndPayloads('user_123', {
2529
+ * onlyEvaluateLocally: true
2530
+ * })
2531
+ * ```
2532
+ *
2533
+ * {@label Feature flags}
2534
+ *
2535
+ * @param distinctId - The user's distinct ID
2536
+ * @param options - Optional configuration for flag evaluation
2537
+ * @returns Promise that resolves to flags and payloads
2538
+ */
1991
2539
  async getAllFlagsAndPayloads(distinctId, options) {
1992
2540
  const {
1993
2541
  groups,
@@ -2031,6 +2579,41 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
2031
2579
  featureFlagPayloads
2032
2580
  };
2033
2581
  }
2582
+ /**
2583
+ * Create or update a group and its properties.
2584
+ *
2585
+ * @example
2586
+ * ```ts
2587
+ * // Create a company group
2588
+ * client.groupIdentify({
2589
+ * groupType: 'company',
2590
+ * groupKey: 'acme-corp',
2591
+ * properties: {
2592
+ * name: 'Acme Corporation',
2593
+ * industry: 'Technology',
2594
+ * employee_count: 500
2595
+ * },
2596
+ * distinctId: 'user_123'
2597
+ * })
2598
+ * ```
2599
+ *
2600
+ * @example
2601
+ * ```ts
2602
+ * // Update organization properties
2603
+ * client.groupIdentify({
2604
+ * groupType: 'organization',
2605
+ * groupKey: 'org-456',
2606
+ * properties: {
2607
+ * plan: 'enterprise',
2608
+ * region: 'US-West'
2609
+ * }
2610
+ * })
2611
+ * ```
2612
+ *
2613
+ * {@label Identification}
2614
+ *
2615
+ * @param data - The group identify data
2616
+ */
2034
2617
  groupIdentify({
2035
2618
  groupType,
2036
2619
  groupKey,
@@ -2043,12 +2626,49 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
2043
2626
  }, distinctId);
2044
2627
  }
2045
2628
  /**
2046
- * Reloads the feature flag definitions from the server for local evaluation.
2047
- * This is useful to call if you want to ensure that the feature flags are up to date before calling getFeatureFlag.
2629
+ * Reload feature flag definitions from the server for local evaluation.
2630
+ *
2631
+ * @example
2632
+ * ```ts
2633
+ * // Force reload of feature flags
2634
+ * await client.reloadFeatureFlags()
2635
+ * console.log('Feature flags reloaded')
2636
+ * ```
2637
+ *
2638
+ * @example
2639
+ * ```ts
2640
+ * // Reload before checking a specific flag
2641
+ * await client.reloadFeatureFlags()
2642
+ * const flag = await client.getFeatureFlag('flag-key', 'user_123')
2643
+ * ```
2644
+ *
2645
+ * {@label Feature flags}
2646
+ *
2647
+ * @returns Promise that resolves when flags are reloaded
2048
2648
  */
2049
2649
  async reloadFeatureFlags() {
2050
2650
  await this.featureFlagsPoller?.loadFeatureFlags(true);
2051
2651
  }
2652
+ /**
2653
+ * Shutdown the PostHog client gracefully.
2654
+ *
2655
+ * @example
2656
+ * ```ts
2657
+ * // Shutdown with default timeout
2658
+ * await client._shutdown()
2659
+ * ```
2660
+ *
2661
+ * @example
2662
+ * ```ts
2663
+ * // Shutdown with custom timeout
2664
+ * await client._shutdown(5000) // 5 seconds
2665
+ * ```
2666
+ *
2667
+ * {@label Shutdown}
2668
+ *
2669
+ * @param shutdownTimeoutMs - Timeout in milliseconds for shutdown
2670
+ * @returns Promise that resolves when shutdown is complete
2671
+ */
2052
2672
  async _shutdown(shutdownTimeoutMs) {
2053
2673
  this.featureFlagsPoller?.stopPoller();
2054
2674
  this.errorTracking.shutdown();
@@ -2177,12 +2797,81 @@ class PostHogBackendClient extends core.PostHogCoreStateless {
2177
2797
  allGroupProperties
2178
2798
  };
2179
2799
  }
2800
+ /**
2801
+ * Capture an error exception as an event.
2802
+ *
2803
+ * @example
2804
+ * ```ts
2805
+ * // Capture an error with user ID
2806
+ * try {
2807
+ * // Some risky operation
2808
+ * riskyOperation()
2809
+ * } catch (error) {
2810
+ * client.captureException(error, 'user_123')
2811
+ * }
2812
+ * ```
2813
+ *
2814
+ * @example
2815
+ * ```ts
2816
+ * // Capture with additional properties
2817
+ * try {
2818
+ * apiCall()
2819
+ * } catch (error) {
2820
+ * client.captureException(error, 'user_123', {
2821
+ * endpoint: '/api/users',
2822
+ * method: 'POST',
2823
+ * status_code: 500
2824
+ * })
2825
+ * }
2826
+ * ```
2827
+ *
2828
+ * {@label Error tracking}
2829
+ *
2830
+ * @param error - The error to capture
2831
+ * @param distinctId - Optional user distinct ID
2832
+ * @param additionalProperties - Optional additional properties to include
2833
+ */
2180
2834
  captureException(error, distinctId, additionalProperties) {
2181
2835
  const syntheticException = new Error('PostHog syntheticException');
2182
2836
  this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
2183
2837
  syntheticException
2184
2838
  }, distinctId, additionalProperties).then(msg => this.capture(msg)));
2185
2839
  }
2840
+ /**
2841
+ * Capture an error exception as an event immediately (synchronously).
2842
+ *
2843
+ * @example
2844
+ * ```ts
2845
+ * // Capture an error immediately with user ID
2846
+ * try {
2847
+ * // Some risky operation
2848
+ * riskyOperation()
2849
+ * } catch (error) {
2850
+ * await client.captureExceptionImmediate(error, 'user_123')
2851
+ * }
2852
+ * ```
2853
+ *
2854
+ * @example
2855
+ * ```ts
2856
+ * // Capture with additional properties
2857
+ * try {
2858
+ * apiCall()
2859
+ * } catch (error) {
2860
+ * await client.captureExceptionImmediate(error, 'user_123', {
2861
+ * endpoint: '/api/users',
2862
+ * method: 'POST',
2863
+ * status_code: 500
2864
+ * })
2865
+ * }
2866
+ * ```
2867
+ *
2868
+ * {@label Error tracking}
2869
+ *
2870
+ * @param error - The error to capture
2871
+ * @param distinctId - Optional user distinct ID
2872
+ * @param additionalProperties - Optional additional properties to include
2873
+ * @returns Promise that resolves when the error is captured
2874
+ */
2186
2875
  async captureExceptionImmediate(error, distinctId, additionalProperties) {
2187
2876
  const syntheticException = new Error('PostHog syntheticException');
2188
2877
  this.addPendingPromise(ErrorTracking.buildEventMessage(error, {