posthog-node 3.0.0 → 3.1.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,7 +3,7 @@ export declare function removeTrailingSlash(url: string): string;
3
3
  export interface RetriableOptions {
4
4
  retryCount?: number;
5
5
  retryDelay?: number;
6
- retryCheck?: (err: any) => true;
6
+ retryCheck?: (err: any) => boolean;
7
7
  }
8
8
  export declare function retriable<T>(fn: () => Promise<T>, props?: RetriableOptions): Promise<T>;
9
9
  export declare function generateUUID(globalThis?: any): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthog-node",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "PostHog Node.js integration",
5
5
  "repository": "PostHog/posthog-node",
6
6
  "scripts": {
@@ -425,7 +425,7 @@ class FeatureFlagsPoller {
425
425
  try {
426
426
  return await this.fetch(url, options)
427
427
  } catch (err) {
428
- throw new Error(`Request failed with error: ${err}`)
428
+ throw err
429
429
  } finally {
430
430
  clearTimeout(abortTimeout)
431
431
  }
package/src/fetch.ts CHANGED
@@ -10,11 +10,13 @@ export const fetch = async (url: string, options: PostHogFetchOptions): Promise<
10
10
  method: options.method.toLowerCase(),
11
11
  data: options.body,
12
12
  signal: options.signal,
13
+ // fetch only throws on network errors, not on HTTP errors
14
+ validateStatus: () => true,
13
15
  })
14
16
 
15
17
  return {
16
18
  status: res.status,
17
- text: () => res.data,
18
- json: () => res.data,
19
+ text: async () => res.data,
20
+ json: async () => res.data,
19
21
  }
20
22
  }
@@ -1,6 +1,6 @@
1
- // import { PostHog } from '../'
1
+ // import { PostHog, PostHogOptions } from '../'
2
2
  // Uncomment below line while developing to not compile code everytime
3
- import { PostHog as PostHog } from '../src/posthog-node'
3
+ import { PostHog as PostHog, PostHogOptions } from '../src/posthog-node'
4
4
  import { matchProperty, InconclusiveMatchError } from '../src/feature-flags'
5
5
  jest.mock('../src/fetch')
6
6
  import { fetch } from '../src/fetch'
@@ -9,6 +9,10 @@ jest.spyOn(global.console, 'debug').mockImplementation()
9
9
 
10
10
  const mockedFetch = jest.mocked(fetch, true)
11
11
 
12
+ const posthogImmediateResolveOptions: PostHogOptions = {
13
+ fetchRetryCount: 0,
14
+ }
15
+
12
16
  export const apiImplementation = ({
13
17
  localFlags,
14
18
  decideFlags,
@@ -105,6 +109,7 @@ describe('local evaluation', () => {
105
109
  posthog = new PostHog('TEST_API_KEY', {
106
110
  host: 'http://example.com',
107
111
  personalApiKey: 'TEST_PERSONAL_API_KEY',
112
+ ...posthogImmediateResolveOptions,
108
113
  })
109
114
 
110
115
  expect(
@@ -151,6 +156,7 @@ describe('local evaluation', () => {
151
156
  posthog = new PostHog('TEST_API_KEY', {
152
157
  host: 'http://example.com',
153
158
  personalApiKey: 'TEST_PERSONAL_API_KEY',
159
+ ...posthogImmediateResolveOptions,
154
160
  })
155
161
 
156
162
  // # groups not passed in, hence false
@@ -231,6 +237,7 @@ describe('local evaluation', () => {
231
237
  posthog = new PostHog('TEST_API_KEY', {
232
238
  host: 'http://example.com',
233
239
  personalApiKey: 'TEST_PERSONAL_API_KEY',
240
+ ...posthogImmediateResolveOptions,
234
241
  })
235
242
  // # group_type_mappings not present, so fallback to `/decide`
236
243
  expect(
@@ -304,6 +311,7 @@ describe('local evaluation', () => {
304
311
  posthog = new PostHog('TEST_API_KEY', {
305
312
  host: 'http://example.com',
306
313
  personalApiKey: 'TEST_PERSONAL_API_KEY',
314
+ ...posthogImmediateResolveOptions,
307
315
  })
308
316
 
309
317
  expect(
@@ -426,6 +434,7 @@ describe('local evaluation', () => {
426
434
  posthog = new PostHog('TEST_API_KEY', {
427
435
  host: 'http://example.com',
428
436
  personalApiKey: 'TEST_PERSONAL_API_KEY',
437
+ ...posthogImmediateResolveOptions,
429
438
  })
430
439
 
431
440
  // # beta-feature fallbacks to decide because property type is unknown
@@ -488,6 +497,7 @@ describe('local evaluation', () => {
488
497
  posthog = new PostHog('TEST_API_KEY', {
489
498
  host: 'http://example.com',
490
499
  personalApiKey: 'TEST_PERSONAL_API_KEY',
500
+ ...posthogImmediateResolveOptions,
491
501
  })
492
502
 
493
503
  // # beta-feature should fallback to decide because property type is unknown
@@ -536,6 +546,7 @@ describe('local evaluation', () => {
536
546
  posthog = new PostHog('TEST_API_KEY', {
537
547
  host: 'http://example.com',
538
548
  personalApiKey: 'TEST_PERSONAL_API_KEY',
549
+ ...posthogImmediateResolveOptions,
539
550
  })
540
551
 
541
552
  // # beta-feature resolves to False
@@ -576,12 +587,20 @@ describe('local evaluation', () => {
576
587
  posthog = new PostHog('TEST_API_KEY', {
577
588
  host: 'http://example.com',
578
589
  personalApiKey: 'TEST_PERSONAL_API_KEY',
590
+ ...posthogImmediateResolveOptions,
591
+ })
592
+
593
+ let err: any = null
594
+ posthog.on('error', (e) => {
595
+ err = e
579
596
  })
580
597
 
581
598
  // # beta-feature2 falls back to decide, which on error returns undefined
582
599
  expect(await posthog.getFeatureFlag('beta-feature2', 'some-distinct-id')).toEqual(undefined)
583
600
  expect(await posthog.isFeatureEnabled('beta-feature2', 'some-distinct-id')).toEqual(undefined)
584
601
  expect(mockedFetch).toHaveBeenCalledWith(...anyDecideCall)
602
+ await posthog.shutdownAsync()
603
+ expect(err).toHaveProperty('name', 'PostHogFetchHttpError')
585
604
  })
586
605
 
587
606
  it('experience continuity flags are not evaluated locally', async () => {
@@ -612,6 +631,7 @@ describe('local evaluation', () => {
612
631
  posthog = new PostHog('TEST_API_KEY', {
613
632
  host: 'http://example.com',
614
633
  personalApiKey: 'TEST_PERSONAL_API_KEY',
634
+ ...posthogImmediateResolveOptions,
615
635
  })
616
636
 
617
637
  // # beta-feature2 falls back to decide, which on error returns default
@@ -680,6 +700,7 @@ describe('local evaluation', () => {
680
700
  posthog = new PostHog('TEST_API_KEY', {
681
701
  host: 'http://example.com',
682
702
  personalApiKey: 'TEST_PERSONAL_API_KEY',
703
+ ...posthogImmediateResolveOptions,
683
704
  })
684
705
 
685
706
  // # beta-feature value overridden by /decide
@@ -763,6 +784,7 @@ describe('local evaluation', () => {
763
784
  posthog = new PostHog('TEST_API_KEY', {
764
785
  host: 'http://example.com',
765
786
  personalApiKey: 'TEST_PERSONAL_API_KEY',
787
+ ...posthogImmediateResolveOptions,
766
788
  })
767
789
 
768
790
  // # beta-feature value overridden by /decide
@@ -835,6 +857,7 @@ describe('local evaluation', () => {
835
857
  posthog = new PostHog('TEST_API_KEY', {
836
858
  host: 'http://example.com',
837
859
  personalApiKey: 'TEST_PERSONAL_API_KEY',
860
+ ...posthogImmediateResolveOptions,
838
861
  })
839
862
 
840
863
  // # beta-feature2 has no value
@@ -916,6 +939,7 @@ describe('local evaluation', () => {
916
939
  posthog = new PostHog('TEST_API_KEY', {
917
940
  host: 'http://example.com',
918
941
  personalApiKey: 'TEST_PERSONAL_API_KEY',
942
+ ...posthogImmediateResolveOptions,
919
943
  })
920
944
 
921
945
  expect(
@@ -940,6 +964,7 @@ describe('local evaluation', () => {
940
964
  posthog = new PostHog('TEST_API_KEY', {
941
965
  host: 'http://example.com',
942
966
  personalApiKey: 'TEST_PERSONAL_API_KEY',
967
+ ...posthogImmediateResolveOptions,
943
968
  })
944
969
 
945
970
  expect(await posthog.getAllFlags('distinct-id')).toEqual({
@@ -965,6 +990,7 @@ describe('local evaluation', () => {
965
990
  posthog = new PostHog('TEST_API_KEY', {
966
991
  host: 'http://example.com',
967
992
  personalApiKey: 'TEST_PERSONAL_API_KEY',
993
+ ...posthogImmediateResolveOptions,
968
994
  })
969
995
 
970
996
  expect((await posthog.getAllFlagsAndPayloads('distinct-id')).featureFlagPayloads).toEqual({
@@ -1021,6 +1047,7 @@ describe('local evaluation', () => {
1021
1047
  posthog = new PostHog('TEST_API_KEY', {
1022
1048
  host: 'http://example.com',
1023
1049
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1050
+ ...posthogImmediateResolveOptions,
1024
1051
  })
1025
1052
 
1026
1053
  expect(await posthog.getAllFlags('distinct-id')).toEqual({ 'beta-feature': true, 'disabled-feature': false })
@@ -1079,6 +1106,7 @@ describe('local evaluation', () => {
1079
1106
  posthog = new PostHog('TEST_API_KEY', {
1080
1107
  host: 'http://example.com',
1081
1108
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1109
+ ...posthogImmediateResolveOptions,
1082
1110
  })
1083
1111
 
1084
1112
  expect((await posthog.getAllFlagsAndPayloads('distinct-id')).featureFlagPayloads).toEqual({ 'beta-feature': 'new' })
@@ -1131,6 +1159,7 @@ describe('local evaluation', () => {
1131
1159
  posthog = new PostHog('TEST_API_KEY', {
1132
1160
  host: 'http://example.com',
1133
1161
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1162
+ ...posthogImmediateResolveOptions,
1134
1163
  })
1135
1164
 
1136
1165
  expect(await posthog.getAllFlags('distinct-id')).toEqual({ 'beta-feature': true, 'disabled-feature': false })
@@ -1238,6 +1267,7 @@ describe('local evaluation', () => {
1238
1267
  posthog = new PostHog('TEST_API_KEY', {
1239
1268
  host: 'http://example.com',
1240
1269
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1270
+ ...posthogImmediateResolveOptions,
1241
1271
  })
1242
1272
 
1243
1273
  expect(
@@ -1319,6 +1349,7 @@ describe('local evaluation', () => {
1319
1349
  posthog = new PostHog('TEST_API_KEY', {
1320
1350
  host: 'http://example.com',
1321
1351
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1352
+ ...posthogImmediateResolveOptions,
1322
1353
  })
1323
1354
 
1324
1355
  expect(
@@ -1408,6 +1439,7 @@ describe('local evaluation', () => {
1408
1439
  posthog = new PostHog('TEST_API_KEY', {
1409
1440
  host: 'http://example.com',
1410
1441
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1442
+ ...posthogImmediateResolveOptions,
1411
1443
  })
1412
1444
 
1413
1445
  expect(
@@ -1489,6 +1521,7 @@ describe('local evaluation', () => {
1489
1521
  posthog = new PostHog('TEST_API_KEY', {
1490
1522
  host: 'http://example.com',
1491
1523
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1524
+ ...posthogImmediateResolveOptions,
1492
1525
  })
1493
1526
 
1494
1527
  expect(
@@ -1560,6 +1593,7 @@ describe('local evaluation', () => {
1560
1593
  posthog = new PostHog('TEST_API_KEY', {
1561
1594
  host: 'http://example.com',
1562
1595
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1596
+ ...posthogImmediateResolveOptions,
1563
1597
  })
1564
1598
 
1565
1599
  expect(
@@ -1632,6 +1666,7 @@ describe('local evaluation', () => {
1632
1666
  posthog = new PostHog('TEST_API_KEY', {
1633
1667
  host: 'http://example.com',
1634
1668
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1669
+ ...posthogImmediateResolveOptions,
1635
1670
  })
1636
1671
 
1637
1672
  expect(
@@ -1682,6 +1717,7 @@ describe('local evaluation', () => {
1682
1717
  posthog = new PostHog('TEST_API_KEY', {
1683
1718
  host: 'http://example.com',
1684
1719
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1720
+ ...posthogImmediateResolveOptions,
1685
1721
  })
1686
1722
 
1687
1723
  expect(
@@ -1762,6 +1798,7 @@ describe('local evaluation', () => {
1762
1798
  posthog = new PostHog('TEST_API_KEY', {
1763
1799
  host: 'http://example.com',
1764
1800
  personalApiKey: 'TEST_PERSONAL_API_KEY',
1801
+ ...posthogImmediateResolveOptions,
1765
1802
  })
1766
1803
 
1767
1804
  expect(
@@ -1990,10 +2027,6 @@ describe('consistency tests', () => {
1990
2027
  let posthog: PostHog
1991
2028
  jest.useFakeTimers()
1992
2029
 
1993
- afterEach(async () => {
1994
- await posthog.shutdownAsync()
1995
- })
1996
-
1997
2030
  it('is consistent for simple flags', () => {
1998
2031
  const flags = {
1999
2032
  flags: [
@@ -2015,6 +2048,7 @@ describe('consistency tests', () => {
2015
2048
  posthog = new PostHog('TEST_API_KEY', {
2016
2049
  host: 'http://example.com',
2017
2050
  personalApiKey: 'TEST_PERSONAL_API_KEY',
2051
+ ...posthogImmediateResolveOptions,
2018
2052
  })
2019
2053
 
2020
2054
  const results = [
@@ -3057,6 +3091,7 @@ describe('consistency tests', () => {
3057
3091
  posthog = new PostHog('TEST_API_KEY', {
3058
3092
  host: 'http://example.com',
3059
3093
  personalApiKey: 'TEST_PERSONAL_API_KEY',
3094
+ ...posthogImmediateResolveOptions,
3060
3095
  })
3061
3096
 
3062
3097
  const results = [
@@ -28,6 +28,7 @@ describe('PostHog Node.js', () => {
28
28
  beforeEach(() => {
29
29
  posthog = new PostHog('TEST_API_KEY', {
30
30
  host: 'http://example.com',
31
+ fetchRetryCount: 0,
31
32
  })
32
33
 
33
34
  mockedFetch.mockResolvedValue({
@@ -266,8 +267,7 @@ describe('PostHog Node.js', () => {
266
267
  // a serverless posthog configuration
267
268
  posthog = new PostHog('TEST_API_KEY', {
268
269
  host: 'http://example.com',
269
- flushAt: 1,
270
- flushInterval: 0,
270
+ fetchRetryCount: 0,
271
271
  })
272
272
 
273
273
  mockedFetch.mockImplementation(async () => {
@@ -290,6 +290,12 @@ describe('PostHog Node.js', () => {
290
290
  })
291
291
 
292
292
  it('should shutdown cleanly', async () => {
293
+ posthog = new PostHog('TEST_API_KEY', {
294
+ host: 'http://example.com',
295
+ fetchRetryCount: 0,
296
+ flushAt: 1,
297
+ })
298
+
293
299
  const logSpy = jest.spyOn(global.console, 'log')
294
300
  jest.useRealTimers()
295
301
  // using debug mode to check console.log output
@@ -319,9 +325,10 @@ describe('PostHog Node.js', () => {
319
325
  })
320
326
 
321
327
  describe('groupIdentify', () => {
322
- it('should identify group with unique id', () => {
328
+ it('should identify group with unique id', async () => {
323
329
  posthog.groupIdentify({ groupType: 'posthog', groupKey: 'team-1', properties: { analytics: true } })
324
330
  jest.runOnlyPendingTimers()
331
+ await posthog.flushAsync()
325
332
  const batchEvents = getLastBatchEvents()
326
333
  expect(batchEvents).toMatchObject([
327
334
  {
@@ -338,7 +345,7 @@ describe('PostHog Node.js', () => {
338
345
  ])
339
346
  })
340
347
 
341
- it('should allow passing optional distinctID to identify group', () => {
348
+ it('should allow passing optional distinctID to identify group', async () => {
342
349
  posthog.groupIdentify({
343
350
  groupType: 'posthog',
344
351
  groupKey: 'team-1',
@@ -346,6 +353,7 @@ describe('PostHog Node.js', () => {
346
353
  distinctId: '123',
347
354
  })
348
355
  jest.runOnlyPendingTimers()
356
+ await posthog.flushAsync()
349
357
  const batchEvents = getLastBatchEvents()
350
358
  expect(batchEvents).toMatchObject([
351
359
  {
@@ -383,6 +391,7 @@ describe('PostHog Node.js', () => {
383
391
 
384
392
  posthog = new PostHog('TEST_API_KEY', {
385
393
  host: 'http://example.com',
394
+ fetchRetryCount: 0,
386
395
  })
387
396
  })
388
397
 
@@ -413,6 +422,7 @@ describe('PostHog Node.js', () => {
413
422
  posthog = new PostHog('TEST_API_KEY', {
414
423
  host: 'http://example.com',
415
424
  flushAt: 1,
425
+ fetchRetryCount: 0,
416
426
  })
417
427
 
418
428
  posthog.capture({
@@ -463,6 +473,7 @@ describe('PostHog Node.js', () => {
463
473
  posthog = new PostHog('TEST_API_KEY', {
464
474
  host: 'http://example.com',
465
475
  flushAt: 1,
476
+ fetchRetryCount: 0,
466
477
  })
467
478
 
468
479
  posthog.capture({
@@ -523,6 +534,7 @@ describe('PostHog Node.js', () => {
523
534
  host: 'http://example.com',
524
535
  personalApiKey: 'TEST_PERSONAL_API_KEY',
525
536
  maxCacheSize: 10,
537
+ fetchRetryCount: 0,
526
538
  })
527
539
 
528
540
  expect(Object.keys(posthog.distinctIdHasSentFlagCalls).length).toEqual(0)
@@ -581,6 +593,7 @@ describe('PostHog Node.js', () => {
581
593
  host: 'http://example.com',
582
594
  personalApiKey: 'TEST_PERSONAL_API_KEY',
583
595
  maxCacheSize: 10,
596
+ fetchRetryCount: 0,
584
597
  })
585
598
 
586
599
  expect(