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.
@@ -1184,7 +1184,7 @@ function snipLine(line, colno) {
1184
1184
  return newLine;
1185
1185
  }
1186
1186
 
1187
- var version = "5.8.1";
1187
+ var version = "5.8.3";
1188
1188
 
1189
1189
  /**
1190
1190
  * A lazy value that is only computed when needed. Inspired by C#'s Lazy<T> class.
@@ -1371,12 +1371,14 @@ class FeatureFlagsPoller {
1371
1371
  const payloads = {};
1372
1372
  let fallbackToFlags = this.featureFlags.length == 0;
1373
1373
  const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map(key => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
1374
+ // Create a shared evaluation cache to prevent memory leaks when processing many flags
1375
+ const sharedEvaluationCache = {};
1374
1376
  await Promise.all(flagsToEvaluate.map(async flag => {
1375
1377
  try {
1376
1378
  const {
1377
1379
  value: matchValue,
1378
1380
  payload: matchPayload
1379
- } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties);
1381
+ } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, undefined /* matchValue */, sharedEvaluationCache);
1380
1382
  response[flag.key] = matchValue;
1381
1383
  if (matchPayload) {
1382
1384
  payloads[flag.key] = matchPayload;
@@ -1396,9 +1398,11 @@ class FeatureFlagsPoller {
1396
1398
  fallbackToFlags
1397
1399
  };
1398
1400
  }
1399
- async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue) {
1400
- // Always ensure flags are loaded for payload computation
1401
- await this.loadFeatureFlags();
1401
+ async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue, evaluationCache, skipLoadCheck = false) {
1402
+ // Only load flags if not already loaded and not skipping the check
1403
+ if (!skipLoadCheck) {
1404
+ await this.loadFeatureFlags();
1405
+ }
1402
1406
  if (!this.loadedSuccessfullyOnce) {
1403
1407
  return {
1404
1408
  value: false,
@@ -1410,7 +1414,7 @@ class FeatureFlagsPoller {
1410
1414
  if (matchValue !== undefined) {
1411
1415
  flagValue = matchValue;
1412
1416
  } else {
1413
- flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties);
1417
+ flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties, evaluationCache);
1414
1418
  }
1415
1419
  // Always compute payload based on the final flagValue (whether provided or computed)
1416
1420
  const payload = this.getFeatureFlagPayload(flag.key, flagValue);
@@ -1419,7 +1423,7 @@ class FeatureFlagsPoller {
1419
1423
  payload
1420
1424
  };
1421
1425
  }
1422
- async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1426
+ async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
1423
1427
  if (flag.ensure_experience_continuity) {
1424
1428
  throw new InconclusiveMatchError('Flag has experience continuity enabled');
1425
1429
  }
@@ -1439,9 +1443,9 @@ class FeatureFlagsPoller {
1439
1443
  return false;
1440
1444
  }
1441
1445
  const focusedGroupProperties = groupProperties[groupName];
1442
- return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
1446
+ return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationCache);
1443
1447
  } else {
1444
- return await this.matchFeatureFlagProperties(flag, distinctId, personProperties);
1448
+ return await this.matchFeatureFlagProperties(flag, distinctId, personProperties, evaluationCache);
1445
1449
  }
1446
1450
  }
1447
1451
  getFeatureFlagPayload(key, flagValue) {
@@ -2085,6 +2089,35 @@ const THIRTY_SECONDS = 30 * 1000;
2085
2089
  const MAX_CACHE_SIZE = 50 * 1000;
2086
2090
  // The actual exported Nodejs API.
2087
2091
  class PostHogBackendClient extends PostHogCoreStateless {
2092
+ /**
2093
+ * Initialize a new PostHog client instance.
2094
+ *
2095
+ * @example
2096
+ * ```ts
2097
+ * // Basic initialization
2098
+ * const client = new PostHogBackendClient(
2099
+ * 'your-api-key',
2100
+ * { host: 'https://app.posthog.com' }
2101
+ * )
2102
+ * ```
2103
+ *
2104
+ * @example
2105
+ * ```ts
2106
+ * // With personal API key
2107
+ * const client = new PostHogBackendClient(
2108
+ * 'your-api-key',
2109
+ * {
2110
+ * host: 'https://app.posthog.com',
2111
+ * personalApiKey: 'your-personal-api-key'
2112
+ * }
2113
+ * )
2114
+ * ```
2115
+ *
2116
+ * {@label Initialization}
2117
+ *
2118
+ * @param apiKey - Your PostHog project API key
2119
+ * @param options - Configuration options for the client
2120
+ */
2088
2121
  constructor(apiKey, options = {}) {
2089
2122
  super(apiKey, options);
2090
2123
  this._memoryStorage = new PostHogMemoryStorage();
@@ -2120,31 +2153,185 @@ class PostHogBackendClient extends PostHogCoreStateless {
2120
2153
  this.distinctIdHasSentFlagCalls = {};
2121
2154
  this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
2122
2155
  }
2156
+ /**
2157
+ * Get a persisted property value from memory storage.
2158
+ *
2159
+ * @example
2160
+ * ```ts
2161
+ * // Get user ID
2162
+ * const userId = client.getPersistedProperty('userId')
2163
+ * ```
2164
+ *
2165
+ * @example
2166
+ * ```ts
2167
+ * // Get session ID
2168
+ * const sessionId = client.getPersistedProperty('sessionId')
2169
+ * ```
2170
+ *
2171
+ * {@label Initialization}
2172
+ *
2173
+ * @param key - The property key to retrieve
2174
+ * @returns The stored property value or undefined if not found
2175
+ */
2123
2176
  getPersistedProperty(key) {
2124
2177
  return this._memoryStorage.getProperty(key);
2125
2178
  }
2179
+ /**
2180
+ * Set a persisted property value in memory storage.
2181
+ *
2182
+ * @example
2183
+ * ```ts
2184
+ * // Set user ID
2185
+ * client.setPersistedProperty('userId', 'user_123')
2186
+ * ```
2187
+ *
2188
+ * @example
2189
+ * ```ts
2190
+ * // Set session ID
2191
+ * client.setPersistedProperty('sessionId', 'session_456')
2192
+ * ```
2193
+ *
2194
+ * {@label Initialization}
2195
+ *
2196
+ * @param key - The property key to set
2197
+ * @param value - The value to store (null to remove)
2198
+ */
2126
2199
  setPersistedProperty(key, value) {
2127
2200
  return this._memoryStorage.setProperty(key, value);
2128
2201
  }
2202
+ /**
2203
+ * Make an HTTP request using the configured fetch function or default fetch.
2204
+ *
2205
+ * @example
2206
+ * ```ts
2207
+ * // POST request
2208
+ * const response = await client.fetch('/api/endpoint', {
2209
+ * method: 'POST',
2210
+ * headers: { 'Content-Type': 'application/json' },
2211
+ * body: JSON.stringify(data)
2212
+ * })
2213
+ * ```
2214
+ *
2215
+ * @internal
2216
+ *
2217
+ * {@label Initialization}
2218
+ *
2219
+ * @param url - The URL to fetch
2220
+ * @param options - Fetch options
2221
+ * @returns Promise resolving to the fetch response
2222
+ */
2129
2223
  fetch(url, options) {
2130
2224
  return this.options.fetch ? this.options.fetch(url, options) : fetch(url, options);
2131
2225
  }
2226
+ /**
2227
+ * Get the library version from package.json.
2228
+ *
2229
+ * @example
2230
+ * ```ts
2231
+ * // Get version
2232
+ * const version = client.getLibraryVersion()
2233
+ * console.log(`Using PostHog SDK version: ${version}`)
2234
+ * ```
2235
+ *
2236
+ * {@label Initialization}
2237
+ *
2238
+ * @returns The current library version string
2239
+ */
2132
2240
  getLibraryVersion() {
2133
2241
  return version;
2134
2242
  }
2243
+ /**
2244
+ * Get the custom user agent string for this client.
2245
+ *
2246
+ * @example
2247
+ * ```ts
2248
+ * // Get user agent
2249
+ * const userAgent = client.getCustomUserAgent()
2250
+ * // Returns: "posthog-node/5.7.0"
2251
+ * ```
2252
+ *
2253
+ * {@label Identification}
2254
+ *
2255
+ * @returns The formatted user agent string
2256
+ */
2135
2257
  getCustomUserAgent() {
2136
2258
  return `${this.getLibraryId()}/${this.getLibraryVersion()}`;
2137
2259
  }
2260
+ /**
2261
+ * Enable the PostHog client (opt-in).
2262
+ *
2263
+ * @example
2264
+ * ```ts
2265
+ * // Enable client
2266
+ * await client.enable()
2267
+ * // Client is now enabled and will capture events
2268
+ * ```
2269
+ *
2270
+ * {@label Privacy}
2271
+ *
2272
+ * @returns Promise that resolves when the client is enabled
2273
+ */
2138
2274
  enable() {
2139
2275
  return super.optIn();
2140
2276
  }
2277
+ /**
2278
+ * Disable the PostHog client (opt-out).
2279
+ *
2280
+ * @example
2281
+ * ```ts
2282
+ * // Disable client
2283
+ * await client.disable()
2284
+ * // Client is now disabled and will not capture events
2285
+ * ```
2286
+ *
2287
+ * {@label Privacy}
2288
+ *
2289
+ * @returns Promise that resolves when the client is disabled
2290
+ */
2141
2291
  disable() {
2142
2292
  return super.optOut();
2143
2293
  }
2294
+ /**
2295
+ * Enable or disable debug logging.
2296
+ *
2297
+ * @example
2298
+ * ```ts
2299
+ * // Enable debug logging
2300
+ * client.debug(true)
2301
+ * ```
2302
+ *
2303
+ * @example
2304
+ * ```ts
2305
+ * // Disable debug logging
2306
+ * client.debug(false)
2307
+ * ```
2308
+ *
2309
+ * {@label Initialization}
2310
+ *
2311
+ * @param enabled - Whether to enable debug logging
2312
+ */
2144
2313
  debug(enabled = true) {
2145
2314
  super.debug(enabled);
2146
2315
  this.featureFlagsPoller?.debug(enabled);
2147
2316
  }
2317
+ /**
2318
+ * Capture an event manually.
2319
+ *
2320
+ * @example
2321
+ * ```ts
2322
+ * // Basic capture
2323
+ * client.capture({
2324
+ * distinctId: 'user_123',
2325
+ * event: 'button_clicked',
2326
+ * properties: { button_color: 'red' }
2327
+ * })
2328
+ * ```
2329
+ *
2330
+ * {@label Capture}
2331
+ *
2332
+ * @param props - The event properties
2333
+ * @returns void
2334
+ */
2148
2335
  capture(props) {
2149
2336
  if (typeof props === 'string') {
2150
2337
  this.logMsgIfDebug(() => console.warn('Called capture() with a string as the first argument when an object was expected.'));
@@ -2166,6 +2353,49 @@ class PostHogBackendClient extends PostHogCoreStateless {
2166
2353
  }
2167
2354
  }));
2168
2355
  }
2356
+ /**
2357
+ * Capture an event immediately (synchronously).
2358
+ *
2359
+ * @example
2360
+ * ```ts
2361
+ * // Basic immediate capture
2362
+ * await client.captureImmediate({
2363
+ * distinctId: 'user_123',
2364
+ * event: 'button_clicked',
2365
+ * properties: { button_color: 'red' }
2366
+ * })
2367
+ * ```
2368
+ *
2369
+ * @example
2370
+ * ```ts
2371
+ * // With feature flags
2372
+ * await client.captureImmediate({
2373
+ * distinctId: 'user_123',
2374
+ * event: 'user_action',
2375
+ * sendFeatureFlags: true
2376
+ * })
2377
+ * ```
2378
+ *
2379
+ * @example
2380
+ * ```ts
2381
+ * // With custom feature flags options
2382
+ * await client.captureImmediate({
2383
+ * distinctId: 'user_123',
2384
+ * event: 'user_action',
2385
+ * sendFeatureFlags: {
2386
+ * onlyEvaluateLocally: true,
2387
+ * personProperties: { plan: 'premium' },
2388
+ * groupProperties: { org: { tier: 'enterprise' } }
2389
+ * flagKeys: ['flag1', 'flag2']
2390
+ * }
2391
+ * })
2392
+ * ```
2393
+ *
2394
+ * {@label Capture}
2395
+ *
2396
+ * @param props - The event properties
2397
+ * @returns Promise that resolves when the event is captured
2398
+ */
2169
2399
  async captureImmediate(props) {
2170
2400
  if (typeof props === 'string') {
2171
2401
  this.logMsgIfDebug(() => console.warn('Called captureImmediate() with a string as the first argument when an object was expected.'));
@@ -2187,6 +2417,38 @@ class PostHogBackendClient extends PostHogCoreStateless {
2187
2417
  }
2188
2418
  }));
2189
2419
  }
2420
+ /**
2421
+ * Identify a user and set their properties.
2422
+ *
2423
+ * @example
2424
+ * ```ts
2425
+ * // Basic identify with properties
2426
+ * client.identify({
2427
+ * distinctId: 'user_123',
2428
+ * properties: {
2429
+ * name: 'John Doe',
2430
+ * email: 'john@example.com',
2431
+ * plan: 'premium'
2432
+ * }
2433
+ * })
2434
+ * ```
2435
+ *
2436
+ * @example
2437
+ * ```ts
2438
+ * // Using $set and $set_once
2439
+ * client.identify({
2440
+ * distinctId: 'user_123',
2441
+ * properties: {
2442
+ * $set: { name: 'John Doe', email: 'john@example.com' },
2443
+ * $set_once: { first_login: new Date().toISOString() }
2444
+ * }
2445
+ * })
2446
+ * ```
2447
+ *
2448
+ * {@label Identification}
2449
+ *
2450
+ * @param data - The identify data containing distinctId and properties
2451
+ */
2190
2452
  identify({
2191
2453
  distinctId,
2192
2454
  properties,
@@ -2205,6 +2467,26 @@ class PostHogBackendClient extends PostHogCoreStateless {
2205
2467
  disableGeoip
2206
2468
  });
2207
2469
  }
2470
+ /**
2471
+ * Identify a user and set their properties immediately (synchronously).
2472
+ *
2473
+ * @example
2474
+ * ```ts
2475
+ * // Basic immediate identify
2476
+ * await client.identifyImmediate({
2477
+ * distinctId: 'user_123',
2478
+ * properties: {
2479
+ * name: 'John Doe',
2480
+ * email: 'john@example.com'
2481
+ * }
2482
+ * })
2483
+ * ```
2484
+ *
2485
+ * {@label Identification}
2486
+ *
2487
+ * @param data - The identify data containing distinctId and properties
2488
+ * @returns Promise that resolves when the identify is processed
2489
+ */
2208
2490
  async identifyImmediate({
2209
2491
  distinctId,
2210
2492
  properties,
@@ -2222,19 +2504,96 @@ class PostHogBackendClient extends PostHogCoreStateless {
2222
2504
  disableGeoip
2223
2505
  });
2224
2506
  }
2507
+ /**
2508
+ * Create an alias to link two distinct IDs together.
2509
+ *
2510
+ * @example
2511
+ * ```ts
2512
+ * // Link an anonymous user to an identified user
2513
+ * client.alias({
2514
+ * distinctId: 'anonymous_123',
2515
+ * alias: 'user_456'
2516
+ * })
2517
+ * ```
2518
+ *
2519
+ * {@label Identification}
2520
+ *
2521
+ * @param data - The alias data containing distinctId and alias
2522
+ */
2225
2523
  alias(data) {
2226
2524
  super.aliasStateless(data.alias, data.distinctId, undefined, {
2227
2525
  disableGeoip: data.disableGeoip
2228
2526
  });
2229
2527
  }
2528
+ /**
2529
+ * Create an alias to link two distinct IDs together immediately (synchronously).
2530
+ *
2531
+ * @example
2532
+ * ```ts
2533
+ * // Link an anonymous user to an identified user immediately
2534
+ * await client.aliasImmediate({
2535
+ * distinctId: 'anonymous_123',
2536
+ * alias: 'user_456'
2537
+ * })
2538
+ * ```
2539
+ *
2540
+ * {@label Identification}
2541
+ *
2542
+ * @param data - The alias data containing distinctId and alias
2543
+ * @returns Promise that resolves when the alias is processed
2544
+ */
2230
2545
  async aliasImmediate(data) {
2231
2546
  await super.aliasStatelessImmediate(data.alias, data.distinctId, undefined, {
2232
2547
  disableGeoip: data.disableGeoip
2233
2548
  });
2234
2549
  }
2550
+ /**
2551
+ * Check if local evaluation of feature flags is ready.
2552
+ *
2553
+ * @example
2554
+ * ```ts
2555
+ * // Check if ready
2556
+ * if (client.isLocalEvaluationReady()) {
2557
+ * // Local evaluation is ready, can evaluate flags locally
2558
+ * const flag = await client.getFeatureFlag('flag-key', 'user_123')
2559
+ * } else {
2560
+ * // Local evaluation not ready, will use remote evaluation
2561
+ * const flag = await client.getFeatureFlag('flag-key', 'user_123')
2562
+ * }
2563
+ * ```
2564
+ *
2565
+ * {@label Feature flags}
2566
+ *
2567
+ * @returns true if local evaluation is ready, false otherwise
2568
+ */
2235
2569
  isLocalEvaluationReady() {
2236
2570
  return this.featureFlagsPoller?.isLocalEvaluationReady() ?? false;
2237
2571
  }
2572
+ /**
2573
+ * Wait for local evaluation of feature flags to be ready.
2574
+ *
2575
+ * @example
2576
+ * ```ts
2577
+ * // Wait for local evaluation
2578
+ * const isReady = await client.waitForLocalEvaluationReady()
2579
+ * if (isReady) {
2580
+ * console.log('Local evaluation is ready')
2581
+ * } else {
2582
+ * console.log('Local evaluation timed out')
2583
+ * }
2584
+ * ```
2585
+ *
2586
+ * @example
2587
+ * ```ts
2588
+ * // Wait with custom timeout
2589
+ * const isReady = await client.waitForLocalEvaluationReady(10000) // 10 seconds
2590
+ * ```
2591
+ *
2592
+ * {@label Feature flags}
2593
+ *
2594
+ * @param timeoutMs - Timeout in milliseconds (default: 30000)
2595
+ * @returns Promise that resolves to true if ready, false if timed out
2596
+ */
2238
2597
  async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
2239
2598
  if (this.isLocalEvaluationReady()) {
2240
2599
  return true;
@@ -2254,6 +2613,47 @@ class PostHogBackendClient extends PostHogCoreStateless {
2254
2613
  });
2255
2614
  });
2256
2615
  }
2616
+ /**
2617
+ * Get the value of a feature flag for a specific user.
2618
+ *
2619
+ * @example
2620
+ * ```ts
2621
+ * // Basic feature flag check
2622
+ * const flagValue = await client.getFeatureFlag('new-feature', 'user_123')
2623
+ * if (flagValue === 'variant-a') {
2624
+ * // Show variant A
2625
+ * } else if (flagValue === 'variant-b') {
2626
+ * // Show variant B
2627
+ * } else {
2628
+ * // Flag is disabled or not found
2629
+ * }
2630
+ * ```
2631
+ *
2632
+ * @example
2633
+ * ```ts
2634
+ * // With groups and properties
2635
+ * const flagValue = await client.getFeatureFlag('org-feature', 'user_123', {
2636
+ * groups: { organization: 'acme-corp' },
2637
+ * personProperties: { plan: 'enterprise' },
2638
+ * groupProperties: { organization: { tier: 'premium' } }
2639
+ * })
2640
+ * ```
2641
+ *
2642
+ * @example
2643
+ * ```ts
2644
+ * // Only evaluate locally
2645
+ * const flagValue = await client.getFeatureFlag('local-flag', 'user_123', {
2646
+ * onlyEvaluateLocally: true
2647
+ * })
2648
+ * ```
2649
+ *
2650
+ * {@label Feature flags}
2651
+ *
2652
+ * @param key - The feature flag key
2653
+ * @param distinctId - The user's distinct ID
2654
+ * @param options - Optional configuration for flag evaluation
2655
+ * @returns Promise that resolves to the flag value or undefined
2656
+ */
2257
2657
  async getFeatureFlag(key, distinctId, options) {
2258
2658
  const {
2259
2659
  groups,
@@ -2273,7 +2673,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
2273
2673
  onlyEvaluateLocally = false;
2274
2674
  }
2275
2675
  if (sendFeatureFlagEvents == undefined) {
2276
- sendFeatureFlagEvents = true;
2676
+ sendFeatureFlagEvents = this.options.sendFeatureFlagEvent ?? true;
2277
2677
  }
2278
2678
  let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
2279
2679
  const flagWasLocallyEvaluated = response !== undefined;
@@ -2317,6 +2717,41 @@ class PostHogBackendClient extends PostHogCoreStateless {
2317
2717
  }
2318
2718
  return response;
2319
2719
  }
2720
+ /**
2721
+ * Get the payload for a feature flag.
2722
+ *
2723
+ * @example
2724
+ * ```ts
2725
+ * // Get payload for a feature flag
2726
+ * const payload = await client.getFeatureFlagPayload('flag-key', 'user_123')
2727
+ * if (payload) {
2728
+ * console.log('Flag payload:', payload)
2729
+ * }
2730
+ * ```
2731
+ *
2732
+ * @example
2733
+ * ```ts
2734
+ * // Get payload with specific match value
2735
+ * const payload = await client.getFeatureFlagPayload('flag-key', 'user_123', 'variant-a')
2736
+ * ```
2737
+ *
2738
+ * @example
2739
+ * ```ts
2740
+ * // With groups and properties
2741
+ * const payload = await client.getFeatureFlagPayload('org-flag', 'user_123', undefined, {
2742
+ * groups: { organization: 'acme-corp' },
2743
+ * personProperties: { plan: 'enterprise' }
2744
+ * })
2745
+ * ```
2746
+ *
2747
+ * {@label Feature flags}
2748
+ *
2749
+ * @param key - The feature flag key
2750
+ * @param distinctId - The user's distinct ID
2751
+ * @param matchValue - Optional match value to get payload for
2752
+ * @param options - Optional configuration for flag evaluation
2753
+ * @returns Promise that resolves to the flag payload or undefined
2754
+ */
2320
2755
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
2321
2756
  const {
2322
2757
  groups,
@@ -2324,7 +2759,6 @@ class PostHogBackendClient extends PostHogCoreStateless {
2324
2759
  } = options || {};
2325
2760
  let {
2326
2761
  onlyEvaluateLocally,
2327
- sendFeatureFlagEvents,
2328
2762
  personProperties,
2329
2763
  groupProperties
2330
2764
  } = options || {};
@@ -2349,15 +2783,30 @@ class PostHogBackendClient extends PostHogCoreStateless {
2349
2783
  if (onlyEvaluateLocally == undefined) {
2350
2784
  onlyEvaluateLocally = false;
2351
2785
  }
2352
- if (sendFeatureFlagEvents == undefined) {
2353
- sendFeatureFlagEvents = true;
2354
- }
2355
2786
  const payloadWasLocallyEvaluated = response !== undefined;
2356
2787
  if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
2357
2788
  response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
2358
2789
  }
2359
2790
  return response;
2360
2791
  }
2792
+ /**
2793
+ * Get the remote config payload for a feature flag.
2794
+ *
2795
+ * @example
2796
+ * ```ts
2797
+ * // Get remote config payload
2798
+ * const payload = await client.getRemoteConfigPayload('flag-key')
2799
+ * if (payload) {
2800
+ * console.log('Remote config payload:', payload)
2801
+ * }
2802
+ * ```
2803
+ *
2804
+ * {@label Feature flags}
2805
+ *
2806
+ * @param flagKey - The feature flag key
2807
+ * @returns Promise that resolves to the remote config payload or undefined
2808
+ * @throws Error if personal API key is not provided
2809
+ */
2361
2810
  async getRemoteConfigPayload(flagKey) {
2362
2811
  if (!this.options.personalApiKey) {
2363
2812
  throw new Error('Personal API key is required for remote config payload decryption');
@@ -2381,6 +2830,38 @@ class PostHogBackendClient extends PostHogCoreStateless {
2381
2830
  }
2382
2831
  return parsed;
2383
2832
  }
2833
+ /**
2834
+ * Check if a feature flag is enabled for a specific user.
2835
+ *
2836
+ * @example
2837
+ * ```ts
2838
+ * // Basic feature flag check
2839
+ * const isEnabled = await client.isFeatureEnabled('new-feature', 'user_123')
2840
+ * if (isEnabled) {
2841
+ * // Feature is enabled
2842
+ * console.log('New feature is active')
2843
+ * } else {
2844
+ * // Feature is disabled
2845
+ * console.log('New feature is not active')
2846
+ * }
2847
+ * ```
2848
+ *
2849
+ * @example
2850
+ * ```ts
2851
+ * // With groups and properties
2852
+ * const isEnabled = await client.isFeatureEnabled('org-feature', 'user_123', {
2853
+ * groups: { organization: 'acme-corp' },
2854
+ * personProperties: { plan: 'enterprise' }
2855
+ * })
2856
+ * ```
2857
+ *
2858
+ * {@label Feature flags}
2859
+ *
2860
+ * @param key - The feature flag key
2861
+ * @param distinctId - The user's distinct ID
2862
+ * @param options - Optional configuration for flag evaluation
2863
+ * @returns Promise that resolves to true if enabled, false if disabled, undefined if not found
2864
+ */
2384
2865
  async isFeatureEnabled(key, distinctId, options) {
2385
2866
  const feat = await this.getFeatureFlag(key, distinctId, options);
2386
2867
  if (feat === undefined) {
@@ -2388,10 +2869,77 @@ class PostHogBackendClient extends PostHogCoreStateless {
2388
2869
  }
2389
2870
  return !!feat || false;
2390
2871
  }
2872
+ /**
2873
+ * Get all feature flag values for a specific user.
2874
+ *
2875
+ * @example
2876
+ * ```ts
2877
+ * // Get all flags for a user
2878
+ * const allFlags = await client.getAllFlags('user_123')
2879
+ * console.log('User flags:', allFlags)
2880
+ * // Output: { 'flag-1': 'variant-a', 'flag-2': false, 'flag-3': 'variant-b' }
2881
+ * ```
2882
+ *
2883
+ * @example
2884
+ * ```ts
2885
+ * // With specific flag keys
2886
+ * const specificFlags = await client.getAllFlags('user_123', {
2887
+ * flagKeys: ['flag-1', 'flag-2']
2888
+ * })
2889
+ * ```
2890
+ *
2891
+ * @example
2892
+ * ```ts
2893
+ * // With groups and properties
2894
+ * const orgFlags = await client.getAllFlags('user_123', {
2895
+ * groups: { organization: 'acme-corp' },
2896
+ * personProperties: { plan: 'enterprise' }
2897
+ * })
2898
+ * ```
2899
+ *
2900
+ * {@label Feature flags}
2901
+ *
2902
+ * @param distinctId - The user's distinct ID
2903
+ * @param options - Optional configuration for flag evaluation
2904
+ * @returns Promise that resolves to a record of flag keys and their values
2905
+ */
2391
2906
  async getAllFlags(distinctId, options) {
2392
2907
  const response = await this.getAllFlagsAndPayloads(distinctId, options);
2393
2908
  return response.featureFlags || {};
2394
2909
  }
2910
+ /**
2911
+ * Get all feature flag values and payloads for a specific user.
2912
+ *
2913
+ * @example
2914
+ * ```ts
2915
+ * // Get all flags and payloads for a user
2916
+ * const result = await client.getAllFlagsAndPayloads('user_123')
2917
+ * console.log('Flags:', result.featureFlags)
2918
+ * console.log('Payloads:', result.featureFlagPayloads)
2919
+ * ```
2920
+ *
2921
+ * @example
2922
+ * ```ts
2923
+ * // With specific flag keys
2924
+ * const result = await client.getAllFlagsAndPayloads('user_123', {
2925
+ * flagKeys: ['flag-1', 'flag-2']
2926
+ * })
2927
+ * ```
2928
+ *
2929
+ * @example
2930
+ * ```ts
2931
+ * // Only evaluate locally
2932
+ * const result = await client.getAllFlagsAndPayloads('user_123', {
2933
+ * onlyEvaluateLocally: true
2934
+ * })
2935
+ * ```
2936
+ *
2937
+ * {@label Feature flags}
2938
+ *
2939
+ * @param distinctId - The user's distinct ID
2940
+ * @param options - Optional configuration for flag evaluation
2941
+ * @returns Promise that resolves to flags and payloads
2942
+ */
2395
2943
  async getAllFlagsAndPayloads(distinctId, options) {
2396
2944
  const {
2397
2945
  groups,
@@ -2435,6 +2983,41 @@ class PostHogBackendClient extends PostHogCoreStateless {
2435
2983
  featureFlagPayloads
2436
2984
  };
2437
2985
  }
2986
+ /**
2987
+ * Create or update a group and its properties.
2988
+ *
2989
+ * @example
2990
+ * ```ts
2991
+ * // Create a company group
2992
+ * client.groupIdentify({
2993
+ * groupType: 'company',
2994
+ * groupKey: 'acme-corp',
2995
+ * properties: {
2996
+ * name: 'Acme Corporation',
2997
+ * industry: 'Technology',
2998
+ * employee_count: 500
2999
+ * },
3000
+ * distinctId: 'user_123'
3001
+ * })
3002
+ * ```
3003
+ *
3004
+ * @example
3005
+ * ```ts
3006
+ * // Update organization properties
3007
+ * client.groupIdentify({
3008
+ * groupType: 'organization',
3009
+ * groupKey: 'org-456',
3010
+ * properties: {
3011
+ * plan: 'enterprise',
3012
+ * region: 'US-West'
3013
+ * }
3014
+ * })
3015
+ * ```
3016
+ *
3017
+ * {@label Identification}
3018
+ *
3019
+ * @param data - The group identify data
3020
+ */
2438
3021
  groupIdentify({
2439
3022
  groupType,
2440
3023
  groupKey,
@@ -2447,12 +3030,49 @@ class PostHogBackendClient extends PostHogCoreStateless {
2447
3030
  }, distinctId);
2448
3031
  }
2449
3032
  /**
2450
- * Reloads the feature flag definitions from the server for local evaluation.
2451
- * This is useful to call if you want to ensure that the feature flags are up to date before calling getFeatureFlag.
3033
+ * Reload feature flag definitions from the server for local evaluation.
3034
+ *
3035
+ * @example
3036
+ * ```ts
3037
+ * // Force reload of feature flags
3038
+ * await client.reloadFeatureFlags()
3039
+ * console.log('Feature flags reloaded')
3040
+ * ```
3041
+ *
3042
+ * @example
3043
+ * ```ts
3044
+ * // Reload before checking a specific flag
3045
+ * await client.reloadFeatureFlags()
3046
+ * const flag = await client.getFeatureFlag('flag-key', 'user_123')
3047
+ * ```
3048
+ *
3049
+ * {@label Feature flags}
3050
+ *
3051
+ * @returns Promise that resolves when flags are reloaded
2452
3052
  */
2453
3053
  async reloadFeatureFlags() {
2454
3054
  await this.featureFlagsPoller?.loadFeatureFlags(true);
2455
3055
  }
3056
+ /**
3057
+ * Shutdown the PostHog client gracefully.
3058
+ *
3059
+ * @example
3060
+ * ```ts
3061
+ * // Shutdown with default timeout
3062
+ * await client._shutdown()
3063
+ * ```
3064
+ *
3065
+ * @example
3066
+ * ```ts
3067
+ * // Shutdown with custom timeout
3068
+ * await client._shutdown(5000) // 5 seconds
3069
+ * ```
3070
+ *
3071
+ * {@label Shutdown}
3072
+ *
3073
+ * @param shutdownTimeoutMs - Timeout in milliseconds for shutdown
3074
+ * @returns Promise that resolves when shutdown is complete
3075
+ */
2456
3076
  async _shutdown(shutdownTimeoutMs) {
2457
3077
  this.featureFlagsPoller?.stopPoller();
2458
3078
  this.errorTracking.shutdown();
@@ -2581,12 +3201,81 @@ class PostHogBackendClient extends PostHogCoreStateless {
2581
3201
  allGroupProperties
2582
3202
  };
2583
3203
  }
3204
+ /**
3205
+ * Capture an error exception as an event.
3206
+ *
3207
+ * @example
3208
+ * ```ts
3209
+ * // Capture an error with user ID
3210
+ * try {
3211
+ * // Some risky operation
3212
+ * riskyOperation()
3213
+ * } catch (error) {
3214
+ * client.captureException(error, 'user_123')
3215
+ * }
3216
+ * ```
3217
+ *
3218
+ * @example
3219
+ * ```ts
3220
+ * // Capture with additional properties
3221
+ * try {
3222
+ * apiCall()
3223
+ * } catch (error) {
3224
+ * client.captureException(error, 'user_123', {
3225
+ * endpoint: '/api/users',
3226
+ * method: 'POST',
3227
+ * status_code: 500
3228
+ * })
3229
+ * }
3230
+ * ```
3231
+ *
3232
+ * {@label Error tracking}
3233
+ *
3234
+ * @param error - The error to capture
3235
+ * @param distinctId - Optional user distinct ID
3236
+ * @param additionalProperties - Optional additional properties to include
3237
+ */
2584
3238
  captureException(error, distinctId, additionalProperties) {
2585
3239
  const syntheticException = new Error('PostHog syntheticException');
2586
3240
  this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
2587
3241
  syntheticException
2588
3242
  }, distinctId, additionalProperties).then(msg => this.capture(msg)));
2589
3243
  }
3244
+ /**
3245
+ * Capture an error exception as an event immediately (synchronously).
3246
+ *
3247
+ * @example
3248
+ * ```ts
3249
+ * // Capture an error immediately with user ID
3250
+ * try {
3251
+ * // Some risky operation
3252
+ * riskyOperation()
3253
+ * } catch (error) {
3254
+ * await client.captureExceptionImmediate(error, 'user_123')
3255
+ * }
3256
+ * ```
3257
+ *
3258
+ * @example
3259
+ * ```ts
3260
+ * // Capture with additional properties
3261
+ * try {
3262
+ * apiCall()
3263
+ * } catch (error) {
3264
+ * await client.captureExceptionImmediate(error, 'user_123', {
3265
+ * endpoint: '/api/users',
3266
+ * method: 'POST',
3267
+ * status_code: 500
3268
+ * })
3269
+ * }
3270
+ * ```
3271
+ *
3272
+ * {@label Error tracking}
3273
+ *
3274
+ * @param error - The error to capture
3275
+ * @param distinctId - Optional user distinct ID
3276
+ * @param additionalProperties - Optional additional properties to include
3277
+ * @returns Promise that resolves when the error is captured
3278
+ */
2590
3279
  async captureExceptionImmediate(error, distinctId, additionalProperties) {
2591
3280
  const syntheticException = new Error('PostHog syntheticException');
2592
3281
  this.addPendingPromise(ErrorTracking.buildEventMessage(error, {