posthog-node 5.11.2 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -219,7 +219,7 @@ limitations under the License.
219
219
 
220
220
  ---
221
221
 
222
- Some files in this codebase contain code from getsentry/sentry-javascript by Software, Inc. dba Sentry.
222
+ Some files in this codebase contain code from getsentry/sentry-javascript or getsentry/sentry-react-native by Software, Inc. dba Sentry.
223
223
  In such cases it is explicitly stated in the file header. This license only applies to the relevant code in such cases.
224
224
 
225
225
  MIT License
@@ -242,4 +242,58 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
242
242
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
243
243
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
244
244
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
245
- SOFTWARE.
245
+ SOFTWARE.
246
+
247
+ ---
248
+
249
+ Some files in this codebase contain code from facebook/metro by Meta Platforms, Inc. and affiliates.
250
+ In such cases it is explicitly stated in the file header. This license only applies to the relevant code in such cases.
251
+
252
+ MIT License
253
+
254
+ Copyright (c) Meta Platforms, Inc. and affiliates.
255
+
256
+ Permission is hereby granted, free of charge, to any person obtaining a copy
257
+ of this software and associated documentation files (the "Software"), to deal
258
+ in the Software without restriction, including without limitation the rights
259
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
260
+ copies of the Software, and to permit persons to whom the Software is
261
+ furnished to do so, subject to the following conditions:
262
+
263
+ The above copyright notice and this permission notice shall be included in all
264
+ copies or substantial portions of the Software.
265
+
266
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
267
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
268
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
269
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
270
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
271
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
272
+ SOFTWARE.
273
+
274
+ ---
275
+
276
+ Some files in this codebase contain code from expo/expo by 650 Industries, Inc. (aka Expo).
277
+ In such cases it is explicitly stated in the file header. This license only applies to the relevant code in such cases.
278
+
279
+ The MIT License (MIT)
280
+
281
+ Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
282
+
283
+ Permission is hereby granted, free of charge, to any person obtaining a copy
284
+ of this software and associated documentation files (the "Software"), to deal
285
+ in the Software without restriction, including without limitation the rights
286
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
287
+ copies of the Software, and to permit persons to whom the Software is
288
+ furnished to do so, subject to the following conditions:
289
+
290
+ The above copyright notice and this permission notice shall be included in all
291
+ copies or substantial portions of the Software.
292
+
293
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
294
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
295
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
296
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
297
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
298
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
299
+ SOFTWARE.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -65,7 +65,8 @@ class PostHogBackendClient extends core_namespaceObject.PostHogCoreStateless {
65
65
  onLoad: (count)=>{
66
66
  this._events.emit('localEvaluationFlagsLoaded', count);
67
67
  },
68
- customHeaders: this.getCustomHeaders()
68
+ customHeaders: this.getCustomHeaders(),
69
+ cacheProvider: options.flagDefinitionCacheProvider
69
70
  });
70
71
  }
71
72
  this.errorTracking = new (index_js_default())(this, options, this._logger);
@@ -299,7 +300,7 @@ class PostHogBackendClient extends core_namespaceObject.PostHogCoreStateless {
299
300
  await this.featureFlagsPoller?.loadFeatureFlags(true);
300
301
  }
301
302
  async _shutdown(shutdownTimeoutMs) {
302
- this.featureFlagsPoller?.stopPoller();
303
+ this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
303
304
  this.errorTracking.shutdown();
304
305
  return super._shutdown(shutdownTimeoutMs);
305
306
  }
package/dist/client.mjs CHANGED
@@ -27,7 +27,8 @@ class PostHogBackendClient extends PostHogCoreStateless {
27
27
  onLoad: (count)=>{
28
28
  this._events.emit('localEvaluationFlagsLoaded', count);
29
29
  },
30
- customHeaders: this.getCustomHeaders()
30
+ customHeaders: this.getCustomHeaders(),
31
+ cacheProvider: options.flagDefinitionCacheProvider
31
32
  });
32
33
  }
33
34
  this.errorTracking = new error_tracking(this, options, this._logger);
@@ -261,7 +262,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
261
262
  await this.featureFlagsPoller?.loadFeatureFlags(true);
262
263
  }
263
264
  async _shutdown(shutdownTimeoutMs) {
264
- this.featureFlagsPoller?.stopPoller();
265
+ this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
265
266
  this.errorTracking.shutdown();
266
267
  return super._shutdown(shutdownTimeoutMs);
267
268
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Experimental APIs
3
+ *
4
+ * This module exports experimental features that may change or be removed in minor versions.
5
+ * Use these APIs with caution and be prepared for breaking changes.
6
+ *
7
+ * @packageDocumentation
8
+ * @experimental
9
+ */
10
+ export type { FlagDefinitionCacheProvider, FlagDefinitionCacheData } from './extensions/feature-flags/cache';
11
+ //# sourceMappingURL=experimental.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"experimental.d.ts","sourceRoot":"","sources":["../src/experimental.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAA"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.r = (exports1)=>{
5
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
6
+ value: 'Module'
7
+ });
8
+ Object.defineProperty(exports1, '__esModule', {
9
+ value: true
10
+ });
11
+ };
12
+ })();
13
+ var __webpack_exports__ = {};
14
+ __webpack_require__.r(__webpack_exports__);
15
+ for(var __webpack_i__ in __webpack_exports__)exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
16
+ Object.defineProperty(exports, '__esModule', {
17
+ value: true
18
+ });
File without changes
@@ -0,0 +1,110 @@
1
+ import type { PostHogFeatureFlag, PropertyGroup } from '../../types';
2
+ /**
3
+ * Represents the complete set of feature flag data needed for local evaluation.
4
+ *
5
+ * This includes flag definitions, group type mappings, and cohort property groups.
6
+ */
7
+ export interface FlagDefinitionCacheData {
8
+ /** Array of feature flag definitions */
9
+ flags: PostHogFeatureFlag[];
10
+ /** Mapping of group type index to group name */
11
+ groupTypeMapping: Record<string, string>;
12
+ /** Cohort property groups for local evaluation */
13
+ cohorts: Record<string, PropertyGroup>;
14
+ }
15
+ /**
16
+ * @experimental This API is experimental and may change in minor versions.
17
+ *
18
+ * Provider interface for caching feature flag definitions.
19
+ *
20
+ * Implementations can use this to control when flag definitions are fetched
21
+ * and how they're cached (Redis, database, filesystem, etc.).
22
+ *
23
+ * This interface is designed for server-side environments where multiple workers
24
+ * need to share flag definitions and coordinate fetching to reduce API calls.
25
+ *
26
+ * All methods may throw errors - the poller will catch and log them gracefully,
27
+ * ensuring cache provider errors never break flag evaluation.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * import { FlagDefinitionCacheProvider } from 'posthog-node/experimental'
32
+ *
33
+ * class RedisFlagCache implements FlagDefinitionCacheProvider {
34
+ * constructor(private redis: Redis, private teamKey: string) { }
35
+ *
36
+ * async getFlagDefinitions(): Promise<FlagDefinitionCacheData | undefined> {
37
+ * const cached = await this.redis.get(`posthog:flags:${this.teamKey}`)
38
+ * return cached ? JSON.parse(cached) : undefined
39
+ * }
40
+ *
41
+ * async shouldFetchFlagDefinitions(): Promise<boolean> {
42
+ * // Acquire distributed lock - only one worker fetches
43
+ * const acquired = await this.redis.set(`posthog:flags:${this.teamKey}:lock`, '1', 'EX', 60, 'NX')
44
+ * return acquired === 'OK'
45
+ * }
46
+ *
47
+ * async onFlagDefinitionsReceived(data: FlagDefinitionCacheData): Promise<void> {
48
+ * await this.redis.set(`posthog:flags:${this.teamKey}`, JSON.stringify(data), 'EX', 300)
49
+ * await this.redis.del(`posthog:flags:${this.teamKey}:lock`)
50
+ * }
51
+ *
52
+ * async shutdown(): Promise<void> {
53
+ * await this.redis.del(`posthog:flags:${this.teamKey}:lock`)
54
+ * }
55
+ * }
56
+ * ```
57
+ */
58
+ export interface FlagDefinitionCacheProvider {
59
+ /**
60
+ * Retrieve cached flag definitions.
61
+ *
62
+ * Called when the poller is refreshing in-memory flag definitions. If this returns undefined
63
+ * (or throws an error), the poller will fetch fresh data from the PostHog API if no flag
64
+ * definitions are in memory. Otherwise, stale cache data is used until the next poll cycle.
65
+ *
66
+ * @returns cached definitions if available, undefined if cache is empty
67
+ * @throws if an error occurs while accessing the cache (error will be logged)
68
+ */
69
+ getFlagDefinitions(): Promise<FlagDefinitionCacheData | undefined> | FlagDefinitionCacheData | undefined;
70
+ /**
71
+ * Determines whether this instance should fetch new flag definitions.
72
+ *
73
+ * Use this to implement distributed coordination (e.g., via distributed locks)
74
+ * to ensure only one instance fetches at a time in a multi-worker setup.
75
+ *
76
+ * When multiple workers share a cache, typically only one should fetch while
77
+ * others use cached data. Implementations can use Redis locks, database locks,
78
+ * or other coordination mechanisms.
79
+ *
80
+ * @returns true if this instance should fetch, false to skip and read cache
81
+ * @throws if coordination backend is unavailable (error will be logged, fetch continues)
82
+ */
83
+ shouldFetchFlagDefinitions(): Promise<boolean> | boolean;
84
+ /**
85
+ * Called after successfully receiving new flag definitions from PostHog.
86
+ *
87
+ * Store the definitions in your cache backend here. This is called only
88
+ * after a successful API response with valid flag data.
89
+ *
90
+ * If this method throws, the error is logged but flag definitions are still
91
+ * stored in memory, ensuring local evaluation can still be performed.
92
+ *
93
+ * @param data - The complete flag definition data from PostHog
94
+ * @throws if storage backend is unavailable (error will be logged)
95
+ */
96
+ onFlagDefinitionsReceived(data: FlagDefinitionCacheData): Promise<void> | void;
97
+ /**
98
+ * Called when the PostHog client shuts down.
99
+ *
100
+ * Release any held locks, close connections, or clean up resources here.
101
+ *
102
+ * Both sync and async cleanup are supported. Async cleanup has a timeout
103
+ * (default 30s, configurable via client shutdown options) to prevent the
104
+ * process shutdown from hanging indefinitely.
105
+ *
106
+ * @returns Promise that resolves when cleanup is complete, or void for sync cleanup
107
+ */
108
+ shutdown(): Promise<void> | void;
109
+ }
110
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/extensions/feature-flags/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEpE;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,KAAK,EAAE,kBAAkB,EAAE,CAAA;IAC3B,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;;OASG;IACH,kBAAkB,IAAI,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC,GAAG,uBAAuB,GAAG,SAAS,CAAA;IAExG;;;;;;;;;;;;OAYG;IACH,0BAA0B,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IAExD;;;;;;;;;;;OAWG;IACH,yBAAyB,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAE9E;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACjC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.r = (exports1)=>{
5
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
6
+ value: 'Module'
7
+ });
8
+ Object.defineProperty(exports1, '__esModule', {
9
+ value: true
10
+ });
11
+ };
12
+ })();
13
+ var __webpack_exports__ = {};
14
+ __webpack_require__.r(__webpack_exports__);
15
+ for(var __webpack_i__ in __webpack_exports__)exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
16
+ Object.defineProperty(exports, '__esModule', {
17
+ value: true
18
+ });
File without changes
@@ -1,5 +1,6 @@
1
1
  import { FeatureFlagCondition, PostHogFeatureFlag, PropertyGroup } from '../../types';
2
2
  import type { FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from '@posthog/core';
3
+ import { FlagDefinitionCacheProvider } from './cache';
3
4
  declare class ClientError extends Error {
4
5
  constructor(message: string);
5
6
  }
@@ -21,6 +22,7 @@ type FeatureFlagsPollerOptions = {
21
22
  customHeaders?: {
22
23
  [key: string]: string;
23
24
  };
25
+ cacheProvider?: FlagDefinitionCacheProvider;
24
26
  };
25
27
  declare class FeatureFlagsPoller {
26
28
  pollingInterval: number;
@@ -43,6 +45,9 @@ declare class FeatureFlagsPoller {
43
45
  shouldBeginExponentialBackoff: boolean;
44
46
  backOffCount: number;
45
47
  onLoad?: (count: number) => void;
48
+ private cacheProvider?;
49
+ private hasAttemptedCacheLoad;
50
+ private loadingPromise?;
46
51
  constructor({ pollingInterval, personalApiKey, projectApiKey, timeout, host, customHeaders, ...options }: FeatureFlagsPollerOptions);
47
52
  debug(enabled?: boolean): void;
48
53
  private logMsgIfDebug;
@@ -68,6 +73,15 @@ declare class FeatureFlagsPoller {
68
73
  valueMax: number;
69
74
  key: string;
70
75
  }[];
76
+ /**
77
+ * Updates the internal flag state with the provided flag data.
78
+ */
79
+ private updateFlagState;
80
+ /**
81
+ * Attempts to load flags from cache and update internal state.
82
+ * Returns true if flags were successfully loaded from cache, false otherwise.
83
+ */
84
+ private loadFromCache;
71
85
  loadFeatureFlags(forceReload?: boolean): Promise<void>;
72
86
  /**
73
87
  * Returns true if the feature flags poller has loaded successfully at least once and has more than 0 feature flags.
@@ -84,7 +98,7 @@ declare class FeatureFlagsPoller {
84
98
  _loadFeatureFlags(): Promise<void>;
85
99
  private getPersonalApiKeyRequestOptions;
86
100
  _requestFeatureFlagDefinitions(): Promise<PostHogFetchResponse>;
87
- stopPoller(): void;
101
+ stopPoller(timeoutMs?: number): Promise<void>;
88
102
  }
89
103
  declare function matchProperty(property: FeatureFlagCondition['properties'][number], propertyValues: Record<string, any>, warnFunction?: (msg: string) => void): boolean;
90
104
  declare function relativeDateParseForFeatureFlagMatching(value: string): Date | null;
@@ -1 +1 @@
1
- {"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../../src/extensions/feature-flags/feature-flags.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../../src/extensions/feature-flags/feature-flags.ts"],"names":[],"mappings":"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"}
@@ -68,6 +68,7 @@ class FeatureFlagsPoller {
68
68
  this.debugMode = false;
69
69
  this.shouldBeginExponentialBackoff = false;
70
70
  this.backOffCount = 0;
71
+ this.hasAttemptedCacheLoad = false;
71
72
  this.pollingInterval = pollingInterval;
72
73
  this.personalApiKey = personalApiKey;
73
74
  this.featureFlags = [];
@@ -83,6 +84,7 @@ class FeatureFlagsPoller {
83
84
  this.onError = options.onError;
84
85
  this.customHeaders = customHeaders;
85
86
  this.onLoad = options.onLoad;
87
+ this.cacheProvider = options.cacheProvider;
86
88
  this.loadFeatureFlags();
87
89
  }
88
90
  debug(enabled = true) {
@@ -270,8 +272,39 @@ class FeatureFlagsPoller {
270
272
  });
271
273
  return lookupTable;
272
274
  }
275
+ updateFlagState(flagData) {
276
+ this.featureFlags = flagData.flags;
277
+ this.featureFlagsByKey = flagData.flags.reduce((acc, curr)=>(acc[curr.key] = curr, acc), {});
278
+ this.groupTypeMapping = flagData.groupTypeMapping;
279
+ this.cohorts = flagData.cohorts;
280
+ this.loadedSuccessfullyOnce = true;
281
+ }
282
+ async loadFromCache(debugMessage) {
283
+ if (!this.cacheProvider) return false;
284
+ try {
285
+ const cached = await this.cacheProvider.getFlagDefinitions();
286
+ if (cached) {
287
+ this.updateFlagState(cached);
288
+ this.logMsgIfDebug(()=>console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`));
289
+ this.onLoad?.(this.featureFlags.length);
290
+ return true;
291
+ }
292
+ return false;
293
+ } catch (err) {
294
+ this.onError?.(new Error(`Failed to load from cache: ${err}`));
295
+ return false;
296
+ }
297
+ }
273
298
  async loadFeatureFlags(forceReload = false) {
274
- if (!this.loadedSuccessfullyOnce || forceReload) await this._loadFeatureFlags();
299
+ if (this.cacheProvider && !this.hasAttemptedCacheLoad) {
300
+ this.hasAttemptedCacheLoad = true;
301
+ await this.loadFromCache('Loaded flags from cache');
302
+ }
303
+ if (this.loadingPromise) return this.loadingPromise;
304
+ if (!this.loadedSuccessfullyOnce || forceReload) {
305
+ this.loadingPromise = this._loadFeatureFlags();
306
+ await this.loadingPromise;
307
+ }
275
308
  }
276
309
  isLocalEvaluationReady() {
277
310
  return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
@@ -287,6 +320,17 @@ class FeatureFlagsPoller {
287
320
  }
288
321
  this.poller = setTimeout(()=>this._loadFeatureFlags(), this.getPollingInterval());
289
322
  try {
323
+ let shouldFetch = true;
324
+ if (this.cacheProvider) try {
325
+ shouldFetch = await this.cacheProvider.shouldFetchFlagDefinitions();
326
+ } catch (err) {
327
+ this.onError?.(new Error(`Error in shouldFetchFlagDefinitions: ${err}`));
328
+ }
329
+ if (!shouldFetch) {
330
+ const loaded = await this.loadFromCache('Loaded flags from cache (skipped fetch)');
331
+ if (loaded) return;
332
+ if (this.loadedSuccessfullyOnce) return;
333
+ }
290
334
  const res = await this._requestFeatureFlagDefinitions();
291
335
  if (!res) return;
292
336
  switch(res.status){
@@ -313,13 +357,19 @@ class FeatureFlagsPoller {
313
357
  {
314
358
  const responseJson = await res.json() ?? {};
315
359
  if (!('flags' in responseJson)) return void this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`));
316
- this.featureFlags = responseJson.flags ?? [];
317
- this.featureFlagsByKey = this.featureFlags.reduce((acc, curr)=>(acc[curr.key] = curr, acc), {});
318
- this.groupTypeMapping = responseJson.group_type_mapping || {};
319
- this.cohorts = responseJson.cohorts || {};
320
- this.loadedSuccessfullyOnce = true;
360
+ const flagData = {
361
+ flags: responseJson.flags ?? [],
362
+ groupTypeMapping: responseJson.group_type_mapping || {},
363
+ cohorts: responseJson.cohorts || {}
364
+ };
365
+ this.updateFlagState(flagData);
321
366
  this.shouldBeginExponentialBackoff = false;
322
367
  this.backOffCount = 0;
368
+ if (this.cacheProvider && shouldFetch) try {
369
+ await this.cacheProvider.onFlagDefinitionsReceived(flagData);
370
+ } catch (err) {
371
+ this.onError?.(new Error(`Failed to store in cache: ${err}`));
372
+ }
323
373
  this.onLoad?.(this.featureFlags.length);
324
374
  break;
325
375
  }
@@ -328,6 +378,8 @@ class FeatureFlagsPoller {
328
378
  }
329
379
  } catch (err) {
330
380
  if (err instanceof ClientError) this.onError?.(err);
381
+ } finally{
382
+ this.loadingPromise = void 0;
331
383
  }
332
384
  }
333
385
  getPersonalApiKeyRequestOptions(method = 'GET') {
@@ -340,7 +392,7 @@ class FeatureFlagsPoller {
340
392
  }
341
393
  };
342
394
  }
343
- async _requestFeatureFlagDefinitions() {
395
+ _requestFeatureFlagDefinitions() {
344
396
  const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`;
345
397
  const options = this.getPersonalApiKeyRequestOptions();
346
398
  let abortTimeout = null;
@@ -352,13 +404,22 @@ class FeatureFlagsPoller {
352
404
  options.signal = controller.signal;
353
405
  }
354
406
  try {
355
- return await this.fetch(url, options);
407
+ return this.fetch(url, options);
356
408
  } finally{
357
409
  clearTimeout(abortTimeout);
358
410
  }
359
411
  }
360
- stopPoller() {
412
+ async stopPoller(timeoutMs = 30000) {
361
413
  clearTimeout(this.poller);
414
+ if (this.cacheProvider) try {
415
+ const shutdownResult = this.cacheProvider.shutdown();
416
+ if (shutdownResult instanceof Promise) await Promise.race([
417
+ shutdownResult,
418
+ new Promise((_, reject)=>setTimeout(()=>reject(new Error(`Cache shutdown timeout after ${timeoutMs}ms`)), timeoutMs))
419
+ ]);
420
+ } catch (err) {
421
+ this.onError?.(new Error(`Error during cache shutdown: ${err}`));
422
+ }
362
423
  }
363
424
  }
364
425
  async function _hash(key, distinctId, salt = '') {
@@ -35,6 +35,7 @@ class FeatureFlagsPoller {
35
35
  this.debugMode = false;
36
36
  this.shouldBeginExponentialBackoff = false;
37
37
  this.backOffCount = 0;
38
+ this.hasAttemptedCacheLoad = false;
38
39
  this.pollingInterval = pollingInterval;
39
40
  this.personalApiKey = personalApiKey;
40
41
  this.featureFlags = [];
@@ -50,6 +51,7 @@ class FeatureFlagsPoller {
50
51
  this.onError = options.onError;
51
52
  this.customHeaders = customHeaders;
52
53
  this.onLoad = options.onLoad;
54
+ this.cacheProvider = options.cacheProvider;
53
55
  this.loadFeatureFlags();
54
56
  }
55
57
  debug(enabled = true) {
@@ -237,8 +239,39 @@ class FeatureFlagsPoller {
237
239
  });
238
240
  return lookupTable;
239
241
  }
242
+ updateFlagState(flagData) {
243
+ this.featureFlags = flagData.flags;
244
+ this.featureFlagsByKey = flagData.flags.reduce((acc, curr)=>(acc[curr.key] = curr, acc), {});
245
+ this.groupTypeMapping = flagData.groupTypeMapping;
246
+ this.cohorts = flagData.cohorts;
247
+ this.loadedSuccessfullyOnce = true;
248
+ }
249
+ async loadFromCache(debugMessage) {
250
+ if (!this.cacheProvider) return false;
251
+ try {
252
+ const cached = await this.cacheProvider.getFlagDefinitions();
253
+ if (cached) {
254
+ this.updateFlagState(cached);
255
+ this.logMsgIfDebug(()=>console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`));
256
+ this.onLoad?.(this.featureFlags.length);
257
+ return true;
258
+ }
259
+ return false;
260
+ } catch (err) {
261
+ this.onError?.(new Error(`Failed to load from cache: ${err}`));
262
+ return false;
263
+ }
264
+ }
240
265
  async loadFeatureFlags(forceReload = false) {
241
- if (!this.loadedSuccessfullyOnce || forceReload) await this._loadFeatureFlags();
266
+ if (this.cacheProvider && !this.hasAttemptedCacheLoad) {
267
+ this.hasAttemptedCacheLoad = true;
268
+ await this.loadFromCache('Loaded flags from cache');
269
+ }
270
+ if (this.loadingPromise) return this.loadingPromise;
271
+ if (!this.loadedSuccessfullyOnce || forceReload) {
272
+ this.loadingPromise = this._loadFeatureFlags();
273
+ await this.loadingPromise;
274
+ }
242
275
  }
243
276
  isLocalEvaluationReady() {
244
277
  return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
@@ -254,6 +287,17 @@ class FeatureFlagsPoller {
254
287
  }
255
288
  this.poller = setTimeout(()=>this._loadFeatureFlags(), this.getPollingInterval());
256
289
  try {
290
+ let shouldFetch = true;
291
+ if (this.cacheProvider) try {
292
+ shouldFetch = await this.cacheProvider.shouldFetchFlagDefinitions();
293
+ } catch (err) {
294
+ this.onError?.(new Error(`Error in shouldFetchFlagDefinitions: ${err}`));
295
+ }
296
+ if (!shouldFetch) {
297
+ const loaded = await this.loadFromCache('Loaded flags from cache (skipped fetch)');
298
+ if (loaded) return;
299
+ if (this.loadedSuccessfullyOnce) return;
300
+ }
257
301
  const res = await this._requestFeatureFlagDefinitions();
258
302
  if (!res) return;
259
303
  switch(res.status){
@@ -280,13 +324,19 @@ class FeatureFlagsPoller {
280
324
  {
281
325
  const responseJson = await res.json() ?? {};
282
326
  if (!('flags' in responseJson)) return void this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`));
283
- this.featureFlags = responseJson.flags ?? [];
284
- this.featureFlagsByKey = this.featureFlags.reduce((acc, curr)=>(acc[curr.key] = curr, acc), {});
285
- this.groupTypeMapping = responseJson.group_type_mapping || {};
286
- this.cohorts = responseJson.cohorts || {};
287
- this.loadedSuccessfullyOnce = true;
327
+ const flagData = {
328
+ flags: responseJson.flags ?? [],
329
+ groupTypeMapping: responseJson.group_type_mapping || {},
330
+ cohorts: responseJson.cohorts || {}
331
+ };
332
+ this.updateFlagState(flagData);
288
333
  this.shouldBeginExponentialBackoff = false;
289
334
  this.backOffCount = 0;
335
+ if (this.cacheProvider && shouldFetch) try {
336
+ await this.cacheProvider.onFlagDefinitionsReceived(flagData);
337
+ } catch (err) {
338
+ this.onError?.(new Error(`Failed to store in cache: ${err}`));
339
+ }
290
340
  this.onLoad?.(this.featureFlags.length);
291
341
  break;
292
342
  }
@@ -295,6 +345,8 @@ class FeatureFlagsPoller {
295
345
  }
296
346
  } catch (err) {
297
347
  if (err instanceof ClientError) this.onError?.(err);
348
+ } finally{
349
+ this.loadingPromise = void 0;
298
350
  }
299
351
  }
300
352
  getPersonalApiKeyRequestOptions(method = 'GET') {
@@ -307,7 +359,7 @@ class FeatureFlagsPoller {
307
359
  }
308
360
  };
309
361
  }
310
- async _requestFeatureFlagDefinitions() {
362
+ _requestFeatureFlagDefinitions() {
311
363
  const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`;
312
364
  const options = this.getPersonalApiKeyRequestOptions();
313
365
  let abortTimeout = null;
@@ -319,13 +371,22 @@ class FeatureFlagsPoller {
319
371
  options.signal = controller.signal;
320
372
  }
321
373
  try {
322
- return await this.fetch(url, options);
374
+ return this.fetch(url, options);
323
375
  } finally{
324
376
  clearTimeout(abortTimeout);
325
377
  }
326
378
  }
327
- stopPoller() {
379
+ async stopPoller(timeoutMs = 30000) {
328
380
  clearTimeout(this.poller);
381
+ if (this.cacheProvider) try {
382
+ const shutdownResult = this.cacheProvider.shutdown();
383
+ if (shutdownResult instanceof Promise) await Promise.race([
384
+ shutdownResult,
385
+ new Promise((_, reject)=>setTimeout(()=>reject(new Error(`Cache shutdown timeout after ${timeoutMs}ms`)), timeoutMs))
386
+ ]);
387
+ } catch (err) {
388
+ this.onError?.(new Error(`Error during cache shutdown: ${err}`));
389
+ }
329
390
  }
330
391
  }
331
392
  async function _hash(key, distinctId, salt = '') {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { PostHogCoreOptions, FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from '@posthog/core';
2
+ import type { FlagDefinitionCacheProvider } from './extensions/feature-flags/cache';
2
3
  export interface IdentifyMessage {
3
4
  distinctId: string;
4
5
  properties?: Record<string | number, any>;
@@ -52,6 +53,32 @@ export type PostHogOptions = PostHogCoreOptions & {
52
53
  maxCacheSize?: number;
53
54
  fetch?: (url: string, options: PostHogFetchOptions) => Promise<PostHogFetchResponse>;
54
55
  enableLocalEvaluation?: boolean;
56
+ /**
57
+ * @experimental This API is experimental and may change in minor versions.
58
+ *
59
+ * Optional cache provider for feature flag definitions.
60
+ *
61
+ * Allows custom caching strategies (Redis, database, etc.) for flag definitions
62
+ * in multi-worker environments. If not provided, defaults to in-memory cache.
63
+ *
64
+ * This enables distributed coordination where only one worker fetches flags while
65
+ * others use cached data, reducing API calls and improving performance.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * import { FlagDefinitionCacheProvider } from 'posthog-node/experimental'
70
+ *
71
+ * class RedisCacheProvider implements FlagDefinitionCacheProvider {
72
+ * // ... implementation
73
+ * }
74
+ *
75
+ * const client = new PostHog('api-key', {
76
+ * personalApiKey: 'personal-key',
77
+ * flagDefinitionCacheProvider: new RedisCacheProvider(redis)
78
+ * })
79
+ * ```
80
+ */
81
+ flagDefinitionCacheProvider?: FlagDefinitionCacheProvider;
55
82
  /**
56
83
  * Allows modification or dropping of events before they're sent to PostHog.
57
84
  * If an array is provided, the functions are run in order.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "5.11.2";
1
+ export declare const version = "5.12.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -26,7 +26,7 @@ __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
27
  version: ()=>version
28
28
  });
29
- const version = '5.11.2';
29
+ const version = '5.12.0';
30
30
  exports.version = __webpack_exports__.version;
31
31
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
32
32
  "version"
package/dist/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- const version = '5.11.2';
1
+ const version = '5.12.0';
2
2
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthog-node",
3
- "version": "5.11.2",
3
+ "version": "5.12.0",
4
4
  "description": "PostHog Node.js integration",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,6 +30,7 @@
30
30
  "devDependencies": {
31
31
  "@types/node": "^20.0.0",
32
32
  "jest": "^29.7.0",
33
+ "@types/jest": "^29.5.0",
33
34
  "@rslib/core": "^0.10.5",
34
35
  "@posthog-tooling/tsconfig-base": "1.0.0"
35
36
  },
@@ -64,6 +65,9 @@
64
65
  },
65
66
  "import": "./dist/entrypoints/index.node.mjs",
66
67
  "require": "./dist/entrypoints/index.node.js"
68
+ },
69
+ "./experimental": {
70
+ "types": "./dist/experimental.d.ts"
67
71
  }
68
72
  },
69
73
  "scripts": {
package/src/client.ts CHANGED
@@ -112,6 +112,7 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
112
112
  this._events.emit('localEvaluationFlagsLoaded', count)
113
113
  },
114
114
  customHeaders: this.getCustomHeaders(),
115
+ cacheProvider: options.flagDefinitionCacheProvider,
115
116
  })
116
117
  }
117
118
  }
@@ -1179,7 +1180,7 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen
1179
1180
  * @returns Promise that resolves when shutdown is complete
1180
1181
  */
1181
1182
  async _shutdown(shutdownTimeoutMs?: number): Promise<void> {
1182
- this.featureFlagsPoller?.stopPoller()
1183
+ this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs)
1183
1184
  this.errorTracking.shutdown()
1184
1185
  return super._shutdown(shutdownTimeoutMs)
1185
1186
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Experimental APIs
3
+ *
4
+ * This module exports experimental features that may change or be removed in minor versions.
5
+ * Use these APIs with caution and be prepared for breaking changes.
6
+ *
7
+ * @packageDocumentation
8
+ * @experimental
9
+ */
10
+
11
+ export type { FlagDefinitionCacheProvider, FlagDefinitionCacheData } from './extensions/feature-flags/cache'
@@ -0,0 +1,114 @@
1
+ import type { PostHogFeatureFlag, PropertyGroup } from '../../types'
2
+
3
+ /**
4
+ * Represents the complete set of feature flag data needed for local evaluation.
5
+ *
6
+ * This includes flag definitions, group type mappings, and cohort property groups.
7
+ */
8
+ export interface FlagDefinitionCacheData {
9
+ /** Array of feature flag definitions */
10
+ flags: PostHogFeatureFlag[]
11
+ /** Mapping of group type index to group name */
12
+ groupTypeMapping: Record<string, string>
13
+ /** Cohort property groups for local evaluation */
14
+ cohorts: Record<string, PropertyGroup>
15
+ }
16
+
17
+ /**
18
+ * @experimental This API is experimental and may change in minor versions.
19
+ *
20
+ * Provider interface for caching feature flag definitions.
21
+ *
22
+ * Implementations can use this to control when flag definitions are fetched
23
+ * and how they're cached (Redis, database, filesystem, etc.).
24
+ *
25
+ * This interface is designed for server-side environments where multiple workers
26
+ * need to share flag definitions and coordinate fetching to reduce API calls.
27
+ *
28
+ * All methods may throw errors - the poller will catch and log them gracefully,
29
+ * ensuring cache provider errors never break flag evaluation.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * import { FlagDefinitionCacheProvider } from 'posthog-node/experimental'
34
+ *
35
+ * class RedisFlagCache implements FlagDefinitionCacheProvider {
36
+ * constructor(private redis: Redis, private teamKey: string) { }
37
+ *
38
+ * async getFlagDefinitions(): Promise<FlagDefinitionCacheData | undefined> {
39
+ * const cached = await this.redis.get(`posthog:flags:${this.teamKey}`)
40
+ * return cached ? JSON.parse(cached) : undefined
41
+ * }
42
+ *
43
+ * async shouldFetchFlagDefinitions(): Promise<boolean> {
44
+ * // Acquire distributed lock - only one worker fetches
45
+ * const acquired = await this.redis.set(`posthog:flags:${this.teamKey}:lock`, '1', 'EX', 60, 'NX')
46
+ * return acquired === 'OK'
47
+ * }
48
+ *
49
+ * async onFlagDefinitionsReceived(data: FlagDefinitionCacheData): Promise<void> {
50
+ * await this.redis.set(`posthog:flags:${this.teamKey}`, JSON.stringify(data), 'EX', 300)
51
+ * await this.redis.del(`posthog:flags:${this.teamKey}:lock`)
52
+ * }
53
+ *
54
+ * async shutdown(): Promise<void> {
55
+ * await this.redis.del(`posthog:flags:${this.teamKey}:lock`)
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ export interface FlagDefinitionCacheProvider {
61
+ /**
62
+ * Retrieve cached flag definitions.
63
+ *
64
+ * Called when the poller is refreshing in-memory flag definitions. If this returns undefined
65
+ * (or throws an error), the poller will fetch fresh data from the PostHog API if no flag
66
+ * definitions are in memory. Otherwise, stale cache data is used until the next poll cycle.
67
+ *
68
+ * @returns cached definitions if available, undefined if cache is empty
69
+ * @throws if an error occurs while accessing the cache (error will be logged)
70
+ */
71
+ getFlagDefinitions(): Promise<FlagDefinitionCacheData | undefined> | FlagDefinitionCacheData | undefined
72
+
73
+ /**
74
+ * Determines whether this instance should fetch new flag definitions.
75
+ *
76
+ * Use this to implement distributed coordination (e.g., via distributed locks)
77
+ * to ensure only one instance fetches at a time in a multi-worker setup.
78
+ *
79
+ * When multiple workers share a cache, typically only one should fetch while
80
+ * others use cached data. Implementations can use Redis locks, database locks,
81
+ * or other coordination mechanisms.
82
+ *
83
+ * @returns true if this instance should fetch, false to skip and read cache
84
+ * @throws if coordination backend is unavailable (error will be logged, fetch continues)
85
+ */
86
+ shouldFetchFlagDefinitions(): Promise<boolean> | boolean
87
+
88
+ /**
89
+ * Called after successfully receiving new flag definitions from PostHog.
90
+ *
91
+ * Store the definitions in your cache backend here. This is called only
92
+ * after a successful API response with valid flag data.
93
+ *
94
+ * If this method throws, the error is logged but flag definitions are still
95
+ * stored in memory, ensuring local evaluation can still be performed.
96
+ *
97
+ * @param data - The complete flag definition data from PostHog
98
+ * @throws if storage backend is unavailable (error will be logged)
99
+ */
100
+ onFlagDefinitionsReceived(data: FlagDefinitionCacheData): Promise<void> | void
101
+
102
+ /**
103
+ * Called when the PostHog client shuts down.
104
+ *
105
+ * Release any held locks, close connections, or clean up resources here.
106
+ *
107
+ * Both sync and async cleanup are supported. Async cleanup has a timeout
108
+ * (default 30s, configurable via client shutdown options) to prevent the
109
+ * process shutdown from hanging indefinitely.
110
+ *
111
+ * @returns Promise that resolves when cleanup is complete, or void for sync cleanup
112
+ */
113
+ shutdown(): Promise<void> | void
114
+ }
@@ -2,6 +2,7 @@ import { FeatureFlagCondition, FlagProperty, FlagPropertyValue, PostHogFeatureFl
2
2
  import type { FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from '@posthog/core'
3
3
  import { safeSetTimeout } from '@posthog/core'
4
4
  import { hashSHA1 } from './crypto'
5
+ import { FlagDefinitionCacheProvider, FlagDefinitionCacheData } from './cache'
5
6
 
6
7
  const SIXTY_SECONDS = 60 * 1000
7
8
 
@@ -53,6 +54,7 @@ type FeatureFlagsPollerOptions = {
53
54
  onError?: (error: Error) => void
54
55
  onLoad?: (count: number) => void
55
56
  customHeaders?: { [key: string]: string }
57
+ cacheProvider?: FlagDefinitionCacheProvider
56
58
  }
57
59
 
58
60
  class FeatureFlagsPoller {
@@ -74,6 +76,9 @@ class FeatureFlagsPoller {
74
76
  shouldBeginExponentialBackoff: boolean = false
75
77
  backOffCount: number = 0
76
78
  onLoad?: (count: number) => void
79
+ private cacheProvider?: FlagDefinitionCacheProvider
80
+ private hasAttemptedCacheLoad: boolean = false
81
+ private loadingPromise?: Promise<void>
77
82
 
78
83
  constructor({
79
84
  pollingInterval,
@@ -99,6 +104,7 @@ class FeatureFlagsPoller {
99
104
  this.onError = options.onError
100
105
  this.customHeaders = customHeaders
101
106
  this.onLoad = options.onLoad
107
+ this.cacheProvider = options.cacheProvider
102
108
  void this.loadFeatureFlags()
103
109
  }
104
110
 
@@ -537,9 +543,59 @@ class FeatureFlagsPoller {
537
543
  return lookupTable
538
544
  }
539
545
 
546
+ /**
547
+ * Updates the internal flag state with the provided flag data.
548
+ */
549
+ private updateFlagState(flagData: FlagDefinitionCacheData): void {
550
+ this.featureFlags = flagData.flags
551
+ this.featureFlagsByKey = flagData.flags.reduce(
552
+ (acc, curr) => ((acc[curr.key] = curr), acc),
553
+ <Record<string, PostHogFeatureFlag>>{}
554
+ )
555
+ this.groupTypeMapping = flagData.groupTypeMapping
556
+ this.cohorts = flagData.cohorts
557
+ this.loadedSuccessfullyOnce = true
558
+ }
559
+
560
+ /**
561
+ * Attempts to load flags from cache and update internal state.
562
+ * Returns true if flags were successfully loaded from cache, false otherwise.
563
+ */
564
+ private async loadFromCache(debugMessage: string): Promise<boolean> {
565
+ if (!this.cacheProvider) {
566
+ return false
567
+ }
568
+
569
+ try {
570
+ const cached = await this.cacheProvider.getFlagDefinitions()
571
+ if (cached) {
572
+ this.updateFlagState(cached)
573
+ this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`))
574
+ this.onLoad?.(this.featureFlags.length)
575
+ return true
576
+ }
577
+ return false
578
+ } catch (err) {
579
+ this.onError?.(new Error(`Failed to load from cache: ${err}`))
580
+ return false
581
+ }
582
+ }
583
+
540
584
  async loadFeatureFlags(forceReload = false): Promise<void> {
585
+ // On first load, try to initialize from cache (if a cache provider is configured)
586
+ if (this.cacheProvider && !this.hasAttemptedCacheLoad) {
587
+ this.hasAttemptedCacheLoad = true
588
+ await this.loadFromCache('Loaded flags from cache')
589
+ }
590
+
591
+ // If a fetch is already in progress, wait for it
592
+ if (this.loadingPromise) {
593
+ return this.loadingPromise
594
+ }
595
+
541
596
  if (!this.loadedSuccessfullyOnce || forceReload) {
542
- await this._loadFeatureFlags()
597
+ this.loadingPromise = this._loadFeatureFlags()
598
+ await this.loadingPromise
543
599
  }
544
600
  }
545
601
 
@@ -574,6 +630,42 @@ class FeatureFlagsPoller {
574
630
  this.poller = setTimeout(() => this._loadFeatureFlags(), this.getPollingInterval())
575
631
 
576
632
  try {
633
+ let shouldFetch = true
634
+ if (this.cacheProvider) {
635
+ try {
636
+ shouldFetch = await this.cacheProvider.shouldFetchFlagDefinitions()
637
+ } catch (err) {
638
+ this.onError?.(new Error(`Error in shouldFetchFlagDefinitions: ${err}`))
639
+ // Important: if `shouldFetchFlagDefinitions` throws, we
640
+ // default to fetching.
641
+ }
642
+ }
643
+
644
+ if (!shouldFetch) {
645
+ // If we're not supposed to fetch, we assume another instance
646
+ // is handling it. In this case, we'll just reload from cache.
647
+ const loaded = await this.loadFromCache('Loaded flags from cache (skipped fetch)')
648
+ if (loaded) {
649
+ return
650
+ }
651
+
652
+ if (this.loadedSuccessfullyOnce) {
653
+ // Respect the decision to not fetch, even if it means
654
+ // keeping stale feature flags.
655
+ return
656
+ }
657
+
658
+ // If we've gotten here:
659
+ // - A cache provider is configured
660
+ // - We've been asked not to fetch
661
+ // - We failed to load from cache
662
+ // - We have no feature flag definitions to work with.
663
+ //
664
+ // This is the only case where we'll ignore the shouldFetch
665
+ // decision and proceed to fetch, because the alternative is
666
+ // worse: local evaluation is impossible.
667
+ }
668
+
577
669
  const res = await this._requestFeatureFlagDefinitions()
578
670
 
579
671
  // Handle undefined res case, this shouldn't happen, but it doesn't hurt to handle it anyway
@@ -637,16 +729,28 @@ class FeatureFlagsPoller {
637
729
  return
638
730
  }
639
731
 
640
- this.featureFlags = (responseJson.flags as PostHogFeatureFlag[]) ?? []
641
- this.featureFlagsByKey = this.featureFlags.reduce(
642
- (acc, curr) => ((acc[curr.key] = curr), acc),
643
- <Record<string, PostHogFeatureFlag>>{}
644
- )
645
- this.groupTypeMapping = (responseJson.group_type_mapping as Record<string, string>) || {}
646
- this.cohorts = (responseJson.cohorts as Record<string, PropertyGroup>) || {}
647
- this.loadedSuccessfullyOnce = true
732
+ const flagData: FlagDefinitionCacheData = {
733
+ flags: (responseJson.flags as PostHogFeatureFlag[]) ?? [],
734
+ groupTypeMapping: (responseJson.group_type_mapping as Record<string, string>) || {},
735
+ cohorts: (responseJson.cohorts as Record<string, PropertyGroup>) || {},
736
+ }
737
+
738
+ this.updateFlagState(flagData)
648
739
  this.shouldBeginExponentialBackoff = false
649
740
  this.backOffCount = 0
741
+
742
+ if (this.cacheProvider && shouldFetch) {
743
+ // Only notify the cache if it's actually expecting new data
744
+ // E.g., if we weren't supposed to fetch but we missed the
745
+ // cache, we may not have a lock, so we skip this step
746
+ try {
747
+ await this.cacheProvider.onFlagDefinitionsReceived(flagData)
748
+ } catch (err) {
749
+ this.onError?.(new Error(`Failed to store in cache: ${err}`))
750
+ // Continue anyway, the data at least made it to memory
751
+ }
752
+ }
753
+
650
754
  this.onLoad?.(this.featureFlags.length)
651
755
  break
652
756
  }
@@ -660,6 +764,8 @@ class FeatureFlagsPoller {
660
764
  if (err instanceof ClientError) {
661
765
  this.onError?.(err)
662
766
  }
767
+ } finally {
768
+ this.loadingPromise = undefined
663
769
  }
664
770
  }
665
771
 
@@ -674,7 +780,7 @@ class FeatureFlagsPoller {
674
780
  }
675
781
  }
676
782
 
677
- async _requestFeatureFlagDefinitions(): Promise<PostHogFetchResponse> {
783
+ _requestFeatureFlagDefinitions(): Promise<PostHogFetchResponse> {
678
784
  const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`
679
785
 
680
786
  const options = this.getPersonalApiKeyRequestOptions()
@@ -690,14 +796,34 @@ class FeatureFlagsPoller {
690
796
  }
691
797
 
692
798
  try {
693
- return await this.fetch(url, options)
799
+ return this.fetch(url, options)
694
800
  } finally {
695
801
  clearTimeout(abortTimeout)
696
802
  }
697
803
  }
698
804
 
699
- stopPoller(): void {
805
+ async stopPoller(timeoutMs: number = 30000): Promise<void> {
700
806
  clearTimeout(this.poller)
807
+
808
+ if (this.cacheProvider) {
809
+ try {
810
+ const shutdownResult = this.cacheProvider.shutdown()
811
+
812
+ if (shutdownResult instanceof Promise) {
813
+ // This follows the same timeout logic defined in _shutdown.
814
+ // We time out after some period of time to avoid hanging the entire
815
+ // shutdown process if the cache provider misbehaves.
816
+ await Promise.race([
817
+ shutdownResult,
818
+ new Promise((_, reject) =>
819
+ setTimeout(() => reject(new Error(`Cache shutdown timeout after ${timeoutMs}ms`)), timeoutMs)
820
+ ),
821
+ ])
822
+ }
823
+ } catch (err) {
824
+ this.onError?.(new Error(`Error during cache shutdown: ${err}`))
825
+ }
826
+ }
701
827
  }
702
828
  }
703
829
 
package/src/types.ts CHANGED
@@ -6,6 +6,8 @@ import type {
6
6
  PostHogFetchResponse,
7
7
  } from '@posthog/core'
8
8
 
9
+ import type { FlagDefinitionCacheProvider } from './extensions/feature-flags/cache'
10
+
9
11
  export interface IdentifyMessage {
10
12
  distinctId: string
11
13
  properties?: Record<string | number, any>
@@ -72,6 +74,32 @@ export type PostHogOptions = PostHogCoreOptions & {
72
74
  // Whether to enable feature flag polling for local evaluation by default. Defaults to true when personalApiKey is provided.
73
75
  // We recommend setting this to false if you are only using the personalApiKey for evaluating remote config payloads via `getRemoteConfigPayload` and not using local evaluation.
74
76
  enableLocalEvaluation?: boolean
77
+ /**
78
+ * @experimental This API is experimental and may change in minor versions.
79
+ *
80
+ * Optional cache provider for feature flag definitions.
81
+ *
82
+ * Allows custom caching strategies (Redis, database, etc.) for flag definitions
83
+ * in multi-worker environments. If not provided, defaults to in-memory cache.
84
+ *
85
+ * This enables distributed coordination where only one worker fetches flags while
86
+ * others use cached data, reducing API calls and improving performance.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * import { FlagDefinitionCacheProvider } from 'posthog-node/experimental'
91
+ *
92
+ * class RedisCacheProvider implements FlagDefinitionCacheProvider {
93
+ * // ... implementation
94
+ * }
95
+ *
96
+ * const client = new PostHog('api-key', {
97
+ * personalApiKey: 'personal-key',
98
+ * flagDefinitionCacheProvider: new RedisCacheProvider(redis)
99
+ * })
100
+ * ```
101
+ */
102
+ flagDefinitionCacheProvider?: FlagDefinitionCacheProvider
75
103
  /**
76
104
  * Allows modification or dropping of events before they're sent to PostHog.
77
105
  * If an array is provided, the functions are run in order.
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '5.11.2'
1
+ export const version = '5.12.0'