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