posthog-node 2.4.0 → 2.5.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.
@@ -3,42 +3,84 @@ import { RetriableOptions } from './utils';
3
3
  export * as utils from './utils';
4
4
  import { LZString } from './lz-string';
5
5
  import { SimpleEventEmitter } from './eventemitter';
6
- export declare abstract class PostHogCore {
6
+ export declare abstract class PostHogCoreStateless {
7
7
  private apiKey;
8
8
  host: string;
9
9
  private flushAt;
10
10
  private flushInterval;
11
11
  private requestTimeout;
12
12
  private captureMode;
13
- private sendFeatureFlagEvent;
14
- private flagCallReported;
15
13
  private removeDebugCallback?;
14
+ private _optoutOverride;
16
15
  protected _events: SimpleEventEmitter;
17
16
  protected _flushTimer?: any;
18
- protected _decideResponsePromise?: Promise<PostHogDecideResponse>;
19
17
  protected _retryOptions: RetriableOptions;
20
- protected _sessionExpirationTimeSeconds: number;
21
18
  abstract fetch(url: string, options: PostHogFetchOptions): Promise<PostHogFetchResponse>;
22
19
  abstract getLibraryId(): string;
23
20
  abstract getLibraryVersion(): string;
24
21
  abstract getCustomUserAgent(): string | void;
25
22
  abstract getPersistedProperty<T>(key: PostHogPersistedProperty): T | undefined;
26
23
  abstract setPersistedProperty<T>(key: PostHogPersistedProperty, value: T | null): void;
27
- private _optoutOverride;
28
24
  constructor(apiKey: string, options?: PosthogCoreOptions);
29
25
  protected getCommonEventProperties(): any;
26
+ get optedOut(): boolean;
27
+ optIn(): void;
28
+ optOut(): void;
29
+ on(event: string, cb: (...args: any[]) => void): () => void;
30
+ debug(enabled?: boolean): void;
31
+ private buildPayload;
32
+ /***
33
+ *** TRACKING
34
+ ***/
35
+ protected identifyStateless(distinctId: string, properties?: PostHogEventProperties, options?: PosthogCaptureOptions): this;
36
+ protected captureStateless(distinctId: string, event: string, properties?: {
37
+ [key: string]: any;
38
+ }, options?: PosthogCaptureOptions): this;
39
+ protected aliasStateless(alias: string, distinctId: string, properties?: {
40
+ [key: string]: any;
41
+ }): this;
42
+ /***
43
+ *** GROUPS
44
+ ***/
45
+ protected groupIdentifyStateless(groupType: string, groupKey: string | number, groupProperties?: PostHogEventProperties, options?: PosthogCaptureOptions, distinctId?: string, eventProperties?: PostHogEventProperties): this;
46
+ /***
47
+ *** FEATURE FLAGS
48
+ ***/
49
+ protected getDecide(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, extraPayload?: Record<string, any>): Promise<PostHogDecideResponse | undefined>;
50
+ protected getFeatureFlagStateless(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<boolean | string | undefined>;
51
+ protected getFeatureFlagPayloadStateless(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<JsonType | undefined>;
52
+ protected getFeatureFlagPayloadsStateless(distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<PostHogDecideResponse['featureFlagPayloads'] | undefined>;
53
+ protected _parsePayload(response: any): any;
54
+ protected getFeatureFlagsStateless(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<PostHogDecideResponse['featureFlags'] | undefined>;
55
+ protected getFeatureFlagsAndPayloadsStateless(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<{
56
+ flags: PostHogDecideResponse['featureFlags'] | undefined;
57
+ payloads: PostHogDecideResponse['featureFlagPayloads'] | undefined;
58
+ }>;
59
+ /***
60
+ *** QUEUEING AND FLUSHING
61
+ ***/
62
+ protected enqueue(type: string, _message: any, options?: PosthogCaptureOptions): void;
63
+ flushAsync(): Promise<any>;
64
+ flush(callback?: (err?: any, data?: any) => void): void;
65
+ private fetchWithRetry;
66
+ shutdownAsync(): Promise<void>;
67
+ shutdown(): void;
68
+ }
69
+ export declare abstract class PostHogCore extends PostHogCoreStateless {
70
+ private sendFeatureFlagEvent;
71
+ private flagCallReported;
72
+ protected _decideResponsePromise?: Promise<PostHogDecideResponse | undefined>;
73
+ protected _sessionExpirationTimeSeconds: number;
74
+ constructor(apiKey: string, options?: PosthogCoreOptions);
30
75
  protected setupBootstrap(options?: Partial<PosthogCoreOptions>): void;
31
76
  private get props();
32
77
  private set props(value);
33
78
  private clearProps;
34
79
  private _props;
35
- get optedOut(): boolean;
36
- optIn(): void;
37
- optOut(): void;
38
80
  on(event: string, cb: (...args: any[]) => void): () => void;
39
81
  reset(propertiesToKeep?: PostHogPersistedProperty[]): void;
40
- debug(enabled?: boolean): void;
41
- private buildPayload;
82
+ protected getCommonEventProperties(): any;
83
+ private enrichProperties;
42
84
  getSessionId(): string | undefined;
43
85
  resetSessionId(): void;
44
86
  getAnonymousId(): string;
@@ -83,26 +125,17 @@ export declare abstract class PostHogCore {
83
125
  getFeatureFlag(key: string): boolean | string | undefined;
84
126
  getFeatureFlagPayload(key: string): JsonType | undefined;
85
127
  getFeatureFlagPayloads(): PostHogDecideResponse['featureFlagPayloads'] | undefined;
86
- _parsePayload(response: any): any;
87
128
  getFeatureFlags(): PostHogDecideResponse['featureFlags'] | undefined;
88
129
  getFeatureFlagsAndPayloads(): {
89
130
  flags: PostHogDecideResponse['featureFlags'] | undefined;
90
131
  payloads: PostHogDecideResponse['featureFlagPayloads'] | undefined;
91
132
  };
92
133
  isFeatureEnabled(key: string): boolean | undefined;
93
- reloadFeatureFlagsAsync(sendAnonDistinctId?: boolean): Promise<PostHogDecideResponse['featureFlags']>;
134
+ reloadFeatureFlags(cb?: (err?: Error, flags?: PostHogDecideResponse['featureFlags']) => void): void;
135
+ reloadFeatureFlagsAsync(sendAnonDistinctId?: boolean): Promise<PostHogDecideResponse['featureFlags'] | undefined>;
94
136
  onFeatureFlags(cb: (flags: PostHogDecideResponse['featureFlags']) => void): () => void;
95
137
  onFeatureFlag(key: string, cb: (value: string | boolean) => void): () => void;
96
138
  overrideFeatureFlag(flags: PostHogDecideResponse['featureFlags'] | null): void;
97
- /***
98
- *** QUEUEING AND FLUSHING
99
- ***/
100
- private enqueue;
101
- flushAsync(): Promise<any>;
102
- flush(callback?: (err?: any, data?: any) => void): void;
103
- private fetchWithRetry;
104
- shutdownAsync(): Promise<void>;
105
- shutdown(): void;
106
139
  }
107
140
  export * from './types';
108
141
  export { LZString };
@@ -1,4 +1,4 @@
1
- import { JsonType, PosthogCoreOptions, PostHogFetchOptions, PostHogFetchResponse, PosthogFlagsAndPayloadsResponse } from '../../posthog-core/src';
1
+ import { JsonType, PosthogCoreOptions, PostHogCoreStateless, PostHogFetchOptions, PostHogFetchResponse, PosthogFlagsAndPayloadsResponse, PostHogPersistedProperty } from '../../posthog-core/src';
2
2
  import { EventMessageV1, GroupIdentifyMessage, IdentifyMessageV1, PostHogNodeV1 } from './types';
3
3
  export declare type PostHogOptions = PosthogCoreOptions & {
4
4
  persistence?: 'memory';
@@ -8,13 +8,19 @@ export declare type PostHogOptions = PosthogCoreOptions & {
8
8
  maxCacheSize?: number;
9
9
  fetch?: (url: string, options: PostHogFetchOptions) => Promise<PostHogFetchResponse>;
10
10
  };
11
- export declare class PostHog implements PostHogNodeV1 {
12
- private _sharedClient;
11
+ export declare class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
12
+ private _memoryStorage;
13
13
  private featureFlagsPoller?;
14
14
  private maxCacheSize;
15
+ private options;
15
16
  distinctIdHasSentFlagCalls: Record<string, string[]>;
16
17
  constructor(apiKey: string, options?: PostHogOptions);
17
- private reInit;
18
+ getPersistedProperty(key: PostHogPersistedProperty): any | undefined;
19
+ setPersistedProperty(key: PostHogPersistedProperty, value: any | null): void;
20
+ fetch(url: string, options: PostHogFetchOptions): Promise<PostHogFetchResponse>;
21
+ getLibraryId(): string;
22
+ getLibraryVersion(): string;
23
+ getCustomUserAgent(): string;
18
24
  enable(): void;
19
25
  disable(): void;
20
26
  capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp }: EventMessageV1): void;
@@ -58,8 +64,6 @@ export declare class PostHog implements PostHogNodeV1 {
58
64
  }): Promise<PosthogFlagsAndPayloadsResponse>;
59
65
  groupIdentify({ groupType, groupKey, properties }: GroupIdentifyMessage): void;
60
66
  reloadFeatureFlags(): Promise<void>;
61
- flush(): void;
62
67
  shutdown(): void;
63
68
  shutdownAsync(): Promise<void>;
64
- debug(enabled?: boolean): void;
65
69
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "posthog-node",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "PostHog Node.js integration",
5
5
  "repository": "PostHog/posthog-node",
6
6
  "scripts": {
7
7
  "prepublishOnly": "cd .. && yarn build"
8
8
  },
9
9
  "engines": {
10
- "node": ">=14.17.0"
10
+ "node": ">=15.0.0"
11
11
  },
12
12
  "license": "MIT",
13
13
  "author": {
@@ -2,8 +2,8 @@ import { version } from '../package.json'
2
2
 
3
3
  import {
4
4
  JsonType,
5
- PostHogCore,
6
5
  PosthogCoreOptions,
6
+ PostHogCoreStateless,
7
7
  PostHogFetchOptions,
8
8
  PostHogFetchResponse,
9
9
  PosthogFlagsAndPayloadsResponse,
@@ -29,15 +29,37 @@ export type PostHogOptions = PosthogCoreOptions & {
29
29
  const THIRTY_SECONDS = 30 * 1000
30
30
  const MAX_CACHE_SIZE = 50 * 1000
31
31
 
32
- class PostHogClient extends PostHogCore {
32
+ // The actual exported Nodejs API.
33
+ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
33
34
  private _memoryStorage = new PostHogMemoryStorage()
34
35
 
35
- constructor(apiKey: string, private options: PostHogOptions = {}) {
36
- options.captureMode = options?.captureMode || 'json'
37
- options.preloadFeatureFlags = false // Don't preload as this makes no sense without a distinctId
38
- options.sendFeatureFlagEvent = false // Let `posthog-node` handle this on its own, since we're dealing with multiple distinctIDs
36
+ private featureFlagsPoller?: FeatureFlagsPoller
37
+ private maxCacheSize: number
38
+ private options: PostHogOptions
39
+
40
+ distinctIdHasSentFlagCalls: Record<string, string[]>
39
41
 
42
+ constructor(apiKey: string, options: PostHogOptions = {}) {
43
+ options.captureMode = options?.captureMode || 'json'
40
44
  super(apiKey, options)
45
+
46
+ this.options = options
47
+
48
+ if (options.personalApiKey) {
49
+ this.featureFlagsPoller = new FeatureFlagsPoller({
50
+ pollingInterval:
51
+ typeof options.featureFlagsPollingInterval === 'number'
52
+ ? options.featureFlagsPollingInterval
53
+ : THIRTY_SECONDS,
54
+ personalApiKey: options.personalApiKey,
55
+ projectApiKey: apiKey,
56
+ timeout: options.requestTimeout ?? 10000, // 10 seconds
57
+ host: this.host,
58
+ fetch: options.fetch,
59
+ })
60
+ }
61
+ this.distinctIdHasSentFlagCalls = {}
62
+ this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE
41
63
  }
42
64
 
43
65
  getPersistedProperty(key: PostHogPersistedProperty): any | undefined {
@@ -48,11 +70,6 @@ class PostHogClient extends PostHogCore {
48
70
  return this._memoryStorage.setProperty(key, value)
49
71
  }
50
72
 
51
- getSessionId(): string | undefined {
52
- // Sessions don't make sense for Node
53
- return undefined
54
- }
55
-
56
73
  fetch(url: string, options: PostHogFetchOptions): Promise<PostHogFetchResponse> {
57
74
  return this.options.fetch ? this.options.fetch(url, options) : fetch(url, options)
58
75
  }
@@ -66,76 +83,45 @@ class PostHogClient extends PostHogCore {
66
83
  getCustomUserAgent(): string {
67
84
  return `posthog-node/${version}`
68
85
  }
69
- }
70
-
71
- // The actual exported Nodejs API.
72
- export class PostHog implements PostHogNodeV1 {
73
- private _sharedClient: PostHogClient
74
- private featureFlagsPoller?: FeatureFlagsPoller
75
- private maxCacheSize: number
76
-
77
- distinctIdHasSentFlagCalls: Record<string, string[]>
78
-
79
- constructor(apiKey: string, options: PostHogOptions = {}) {
80
- this._sharedClient = new PostHogClient(apiKey, options)
81
- if (options.personalApiKey) {
82
- this.featureFlagsPoller = new FeatureFlagsPoller({
83
- pollingInterval:
84
- typeof options.featureFlagsPollingInterval === 'number'
85
- ? options.featureFlagsPollingInterval
86
- : THIRTY_SECONDS,
87
- personalApiKey: options.personalApiKey,
88
- projectApiKey: apiKey,
89
- timeout: options.requestTimeout ?? 10000, // 10 seconds
90
- host: this._sharedClient.host,
91
- fetch: options.fetch,
92
- })
93
- }
94
- this.distinctIdHasSentFlagCalls = {}
95
- this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE
96
- }
97
-
98
- private reInit(distinctId: string): void {
99
- // Certain properties we want to persist. Queue is persisted always by default.
100
- this._sharedClient.reset([PostHogPersistedProperty.OptedOut])
101
- this._sharedClient.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId)
102
- }
103
86
 
104
87
  enable(): void {
105
- return this._sharedClient.optIn()
88
+ return super.optIn()
106
89
  }
107
90
 
108
91
  disable(): void {
109
- return this._sharedClient.optOut()
92
+ return super.optOut()
110
93
  }
111
94
 
112
95
  capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp }: EventMessageV1): void {
113
- this.reInit(distinctId)
114
- if (groups) {
115
- this._sharedClient.groups(groups)
116
- }
117
-
118
- const _capture = (): void => {
119
- this._sharedClient.capture(event, properties, { timestamp })
96
+ const _capture = (props: EventMessageV1['properties']): void => {
97
+ super.captureStateless(distinctId, event, props, { timestamp })
120
98
  }
121
99
 
122
100
  if (sendFeatureFlags) {
123
- this._sharedClient.reloadFeatureFlagsAsync(false).finally(() => {
124
- _capture()
101
+ super.getFeatureFlagsStateless(distinctId, groups).then((flags) => {
102
+ const featureVariantProperties: Record<string, string | boolean> = {}
103
+ if (flags) {
104
+ for (const [feature, variant] of Object.entries(flags)) {
105
+ featureVariantProperties[`$feature/${feature}`] = variant
106
+ }
107
+ }
108
+ const flagProperties = {
109
+ $active_feature_flags: flags ? Object.keys(flags) : undefined,
110
+ ...featureVariantProperties,
111
+ }
112
+ _capture({ ...properties, $groups: groups, ...flagProperties })
125
113
  })
126
114
  } else {
127
- _capture()
115
+ _capture({ ...properties, $groups: groups })
128
116
  }
129
117
  }
130
118
 
131
119
  identify({ distinctId, properties }: IdentifyMessageV1): void {
132
- this.reInit(distinctId)
133
- this._sharedClient.identify(distinctId, properties)
120
+ super.identifyStateless(distinctId, properties)
134
121
  }
135
122
 
136
123
  alias(data: { distinctId: string; alias: string }): void {
137
- this.reInit(data.distinctId)
138
- this._sharedClient.alias(data.alias)
124
+ super.aliasStateless(data.alias, data.distinctId)
139
125
  }
140
126
 
141
127
  async getFeatureFlag(
@@ -171,20 +157,7 @@ export class PostHog implements PostHogNodeV1 {
171
157
  const flagWasLocallyEvaluated = response !== undefined
172
158
 
173
159
  if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
174
- this.reInit(distinctId)
175
- if (groups != undefined) {
176
- this._sharedClient.groups(groups)
177
- }
178
-
179
- if (personProperties) {
180
- this._sharedClient.personProperties(personProperties)
181
- }
182
-
183
- if (groupProperties) {
184
- this._sharedClient.groupProperties(groupProperties)
185
- }
186
- await this._sharedClient.reloadFeatureFlagsAsync(false)
187
- response = this._sharedClient.getFeatureFlag(key)
160
+ response = await super.getFeatureFlagStateless(key, distinctId, groups, personProperties, groupProperties)
188
161
  }
189
162
 
190
163
  const featureFlagReportedKey = `${key}_${response}`
@@ -260,20 +233,7 @@ export class PostHog implements PostHogNodeV1 {
260
233
  const payloadWasLocallyEvaluated = response !== undefined
261
234
 
262
235
  if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
263
- this.reInit(distinctId)
264
- if (groups != undefined) {
265
- this._sharedClient.groups(groups)
266
- }
267
-
268
- if (personProperties) {
269
- this._sharedClient.personProperties(personProperties)
270
- }
271
-
272
- if (groupProperties) {
273
- this._sharedClient.groupProperties(groupProperties)
274
- }
275
- await this._sharedClient.reloadFeatureFlagsAsync(false)
276
- response = this._sharedClient.getFeatureFlagPayload(key)
236
+ response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties)
277
237
  }
278
238
 
279
239
  try {
@@ -348,20 +308,12 @@ export class PostHog implements PostHogNodeV1 {
348
308
  }
349
309
 
350
310
  if (fallbackToDecide && !onlyEvaluateLocally) {
351
- this.reInit(distinctId)
352
- if (groups) {
353
- this._sharedClient.groups(groups)
354
- }
355
-
356
- if (personProperties) {
357
- this._sharedClient.personProperties(personProperties)
358
- }
359
-
360
- if (groupProperties) {
361
- this._sharedClient.groupProperties(groupProperties)
362
- }
363
- await this._sharedClient.reloadFeatureFlagsAsync(false)
364
- const remoteEvaluationResult = this._sharedClient.getFeatureFlagsAndPayloads()
311
+ const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(
312
+ distinctId,
313
+ groups,
314
+ personProperties,
315
+ groupProperties
316
+ )
365
317
  featureFlags = {
366
318
  ...featureFlags,
367
319
  ...(remoteEvaluationResult.flags || {}),
@@ -376,28 +328,19 @@ export class PostHog implements PostHogNodeV1 {
376
328
  }
377
329
 
378
330
  groupIdentify({ groupType, groupKey, properties }: GroupIdentifyMessage): void {
379
- this.reInit(`$${groupType}_${groupKey}`)
380
- this._sharedClient.groupIdentify(groupType, groupKey, properties)
331
+ super.groupIdentifyStateless(groupType, groupKey, properties)
381
332
  }
382
333
 
383
334
  async reloadFeatureFlags(): Promise<void> {
384
335
  await this.featureFlagsPoller?.loadFeatureFlags(true)
385
336
  }
386
337
 
387
- flush(): void {
388
- this._sharedClient.flush()
389
- }
390
-
391
338
  shutdown(): void {
392
339
  void this.shutdownAsync()
393
340
  }
394
341
 
395
342
  async shutdownAsync(): Promise<void> {
396
343
  this.featureFlagsPoller?.stopPoller()
397
- return this._sharedClient.shutdownAsync()
398
- }
399
-
400
- debug(enabled?: boolean): void {
401
- return this._sharedClient.debug(enabled)
344
+ return super.shutdownAsync()
402
345
  }
403
346
  }
@@ -1,35 +0,0 @@
1
- export function __extends(d: any, b: any): void;
2
- export function __rest(s: any, e: any): {};
3
- export function __decorate(decorators: any, target: any, key: any, desc: any, ...args: any[]): any;
4
- export function __param(paramIndex: any, decorator: any): (target: any, key: any) => void;
5
- export function __metadata(metadataKey: any, metadataValue: any): any;
6
- export function __awaiter(thisArg: any, _arguments: any, P: any, generator: any): any;
7
- export function __generator(thisArg: any, body: any): {
8
- next: (v: any) => any;
9
- throw: (v: any) => any;
10
- return: (v: any) => any;
11
- };
12
- export function __exportStar(m: any, o: any): void;
13
- export function __values(o: any): any;
14
- export function __read(o: any, n: any): any;
15
- /** @deprecated */
16
- export function __spread(...args: any[]): any[];
17
- /** @deprecated */
18
- export function __spreadArrays(...args: any[]): any[];
19
- export function __spreadArray(to: any, from: any, pack: any, ...args: any[]): any;
20
- export function __await(v: any): __await;
21
- export class __await {
22
- constructor(v: any);
23
- v: any;
24
- }
25
- export function __asyncGenerator(thisArg: any, _arguments: any, generator: any): {};
26
- export function __asyncDelegator(o: any): {};
27
- export function __asyncValues(o: any): any;
28
- export function __makeTemplateObject(cooked: any, raw: any): any;
29
- export function __importStar(mod: any): any;
30
- export function __importDefault(mod: any): any;
31
- export function __classPrivateFieldGet(receiver: any, state: any, kind: any, f: any): any;
32
- export function __classPrivateFieldSet(receiver: any, state: any, value: any, kind: any, f: any): any;
33
- export function __classPrivateFieldIn(state: any, receiver: any): any;
34
- export function __assign(...args: any[]): any;
35
- export function __createBinding(o: any, m: any, k: any, k2: any): void;