posthog-node 2.6.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.
- package/CHANGELOG.md +28 -0
- package/lib/index.cjs.js +173 -66
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +21 -10
- package/lib/index.esm.js +173 -66
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/index.d.ts +7 -6
- package/lib/posthog-core/src/types.d.ts +2 -0
- package/lib/posthog-core/src/utils.d.ts +1 -1
- package/lib/posthog-node/src/posthog-node.d.ts +9 -3
- package/lib/posthog-node/src/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/feature-flags.ts +1 -1
- package/src/fetch.ts +4 -2
- package/src/posthog-node.ts +42 -17
- package/src/types.ts +2 -0
- package/test/feature-flags.spec.ts +43 -6
- package/test/posthog-node.spec.ts +194 -15
|
@@ -12,7 +12,8 @@ const mockedFetch = jest.mocked(fetch, true)
|
|
|
12
12
|
const getLastBatchEvents = (): any[] | undefined => {
|
|
13
13
|
expect(mockedFetch).toHaveBeenCalledWith('http://example.com/batch/', expect.objectContaining({ method: 'POST' }))
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// reverse mock calls array to get the last call
|
|
16
|
+
const call = mockedFetch.mock.calls.reverse().find((x) => (x[0] as string).includes('/batch/'))
|
|
16
17
|
if (!call) {
|
|
17
18
|
return undefined
|
|
18
19
|
}
|
|
@@ -27,6 +28,7 @@ describe('PostHog Node.js', () => {
|
|
|
27
28
|
beforeEach(() => {
|
|
28
29
|
posthog = new PostHog('TEST_API_KEY', {
|
|
29
30
|
host: 'http://example.com',
|
|
31
|
+
fetchRetryCount: 0,
|
|
30
32
|
})
|
|
31
33
|
|
|
32
34
|
mockedFetch.mockResolvedValue({
|
|
@@ -51,14 +53,21 @@ describe('PostHog Node.js', () => {
|
|
|
51
53
|
|
|
52
54
|
jest.runOnlyPendingTimers()
|
|
53
55
|
const batchEvents = getLastBatchEvents()
|
|
54
|
-
expect(batchEvents).
|
|
56
|
+
expect(batchEvents).toEqual([
|
|
55
57
|
{
|
|
56
58
|
distinct_id: '123',
|
|
57
59
|
event: 'test-event',
|
|
58
60
|
properties: {
|
|
59
61
|
$groups: { org: 123 },
|
|
60
62
|
foo: 'bar',
|
|
63
|
+
$geoip_disable: true,
|
|
64
|
+
$lib: 'posthog-node',
|
|
65
|
+
$lib_version: '1.2.3',
|
|
61
66
|
},
|
|
67
|
+
timestamp: expect.any(String),
|
|
68
|
+
type: 'capture',
|
|
69
|
+
library: 'posthog-node',
|
|
70
|
+
library_version: '1.2.3',
|
|
62
71
|
},
|
|
63
72
|
])
|
|
64
73
|
})
|
|
@@ -97,6 +106,7 @@ describe('PostHog Node.js', () => {
|
|
|
97
106
|
properties: expect.objectContaining({
|
|
98
107
|
$groups: { other_group: 'x' },
|
|
99
108
|
foo: 'bar',
|
|
109
|
+
$geoip_disable: true,
|
|
100
110
|
}),
|
|
101
111
|
library: 'posthog-node',
|
|
102
112
|
library_version: '1.2.3',
|
|
@@ -117,6 +127,7 @@ describe('PostHog Node.js', () => {
|
|
|
117
127
|
$set: {
|
|
118
128
|
foo: 'bar',
|
|
119
129
|
},
|
|
130
|
+
$geoip_disable: true,
|
|
120
131
|
},
|
|
121
132
|
},
|
|
122
133
|
])
|
|
@@ -135,6 +146,7 @@ describe('PostHog Node.js', () => {
|
|
|
135
146
|
$set: {
|
|
136
147
|
foo: 'other',
|
|
137
148
|
},
|
|
149
|
+
$geoip_disable: true,
|
|
138
150
|
},
|
|
139
151
|
},
|
|
140
152
|
])
|
|
@@ -152,6 +164,7 @@ describe('PostHog Node.js', () => {
|
|
|
152
164
|
properties: {
|
|
153
165
|
distinct_id: '123',
|
|
154
166
|
alias: '1234',
|
|
167
|
+
$geoip_disable: true,
|
|
155
168
|
},
|
|
156
169
|
},
|
|
157
170
|
])
|
|
@@ -170,6 +183,83 @@ describe('PostHog Node.js', () => {
|
|
|
170
183
|
},
|
|
171
184
|
])
|
|
172
185
|
})
|
|
186
|
+
|
|
187
|
+
it('should respect disableGeoip setting if passed in', async () => {
|
|
188
|
+
expect(mockedFetch).toHaveBeenCalledTimes(0)
|
|
189
|
+
posthog.capture({
|
|
190
|
+
distinctId: '123',
|
|
191
|
+
event: 'test-event',
|
|
192
|
+
properties: { foo: 'bar' },
|
|
193
|
+
groups: { org: 123 },
|
|
194
|
+
disableGeoip: false,
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
jest.runOnlyPendingTimers()
|
|
198
|
+
const batchEvents = getLastBatchEvents()
|
|
199
|
+
expect(batchEvents?.[0].properties).toEqual({
|
|
200
|
+
$groups: { org: 123 },
|
|
201
|
+
foo: 'bar',
|
|
202
|
+
$lib: 'posthog-node',
|
|
203
|
+
$lib_version: '1.2.3',
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('should use default is set, and override on specific disableGeoip calls', async () => {
|
|
208
|
+
expect(mockedFetch).toHaveBeenCalledTimes(0)
|
|
209
|
+
const client = new PostHog('TEST_API_KEY', {
|
|
210
|
+
host: 'http://example.com',
|
|
211
|
+
disableGeoip: false,
|
|
212
|
+
})
|
|
213
|
+
client.debug()
|
|
214
|
+
client.capture({ distinctId: '123', event: 'test-event', properties: { foo: 'bar' }, groups: { org: 123 } })
|
|
215
|
+
|
|
216
|
+
jest.runOnlyPendingTimers()
|
|
217
|
+
let batchEvents = getLastBatchEvents()
|
|
218
|
+
expect(batchEvents?.[0].properties).toEqual({
|
|
219
|
+
$groups: { org: 123 },
|
|
220
|
+
foo: 'bar',
|
|
221
|
+
$lib: 'posthog-node',
|
|
222
|
+
$lib_version: '1.2.3',
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
client.capture({
|
|
226
|
+
distinctId: '123',
|
|
227
|
+
event: 'test-event',
|
|
228
|
+
properties: { foo: 'bar' },
|
|
229
|
+
groups: { org: 123 },
|
|
230
|
+
disableGeoip: true,
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
jest.runOnlyPendingTimers()
|
|
234
|
+
batchEvents = getLastBatchEvents()
|
|
235
|
+
console.warn(batchEvents)
|
|
236
|
+
expect(batchEvents?.[0].properties).toEqual({
|
|
237
|
+
$groups: { org: 123 },
|
|
238
|
+
foo: 'bar',
|
|
239
|
+
$lib: 'posthog-node',
|
|
240
|
+
$lib_version: '1.2.3',
|
|
241
|
+
$geoip_disable: true,
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
client.capture({
|
|
245
|
+
distinctId: '123',
|
|
246
|
+
event: 'test-event',
|
|
247
|
+
properties: { foo: 'bar' },
|
|
248
|
+
groups: { org: 123 },
|
|
249
|
+
disableGeoip: false,
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
jest.runOnlyPendingTimers()
|
|
253
|
+
batchEvents = getLastBatchEvents()
|
|
254
|
+
expect(batchEvents?.[0].properties).toEqual({
|
|
255
|
+
$groups: { org: 123 },
|
|
256
|
+
foo: 'bar',
|
|
257
|
+
$lib: 'posthog-node',
|
|
258
|
+
$lib_version: '1.2.3',
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
await client.shutdownAsync()
|
|
262
|
+
})
|
|
173
263
|
})
|
|
174
264
|
|
|
175
265
|
describe('shutdown', () => {
|
|
@@ -177,8 +267,7 @@ describe('PostHog Node.js', () => {
|
|
|
177
267
|
// a serverless posthog configuration
|
|
178
268
|
posthog = new PostHog('TEST_API_KEY', {
|
|
179
269
|
host: 'http://example.com',
|
|
180
|
-
|
|
181
|
-
flushInterval: 0,
|
|
270
|
+
fetchRetryCount: 0,
|
|
182
271
|
})
|
|
183
272
|
|
|
184
273
|
mockedFetch.mockImplementation(async () => {
|
|
@@ -201,6 +290,12 @@ describe('PostHog Node.js', () => {
|
|
|
201
290
|
})
|
|
202
291
|
|
|
203
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
|
+
|
|
204
299
|
const logSpy = jest.spyOn(global.console, 'log')
|
|
205
300
|
jest.useRealTimers()
|
|
206
301
|
// using debug mode to check console.log output
|
|
@@ -230,9 +325,10 @@ describe('PostHog Node.js', () => {
|
|
|
230
325
|
})
|
|
231
326
|
|
|
232
327
|
describe('groupIdentify', () => {
|
|
233
|
-
it('should identify group with unique id', () => {
|
|
328
|
+
it('should identify group with unique id', async () => {
|
|
234
329
|
posthog.groupIdentify({ groupType: 'posthog', groupKey: 'team-1', properties: { analytics: true } })
|
|
235
330
|
jest.runOnlyPendingTimers()
|
|
331
|
+
await posthog.flushAsync()
|
|
236
332
|
const batchEvents = getLastBatchEvents()
|
|
237
333
|
expect(batchEvents).toMatchObject([
|
|
238
334
|
{
|
|
@@ -243,12 +339,13 @@ describe('PostHog Node.js', () => {
|
|
|
243
339
|
$group_key: 'team-1',
|
|
244
340
|
$group_set: { analytics: true },
|
|
245
341
|
$lib: 'posthog-node',
|
|
342
|
+
$geoip_disable: true,
|
|
246
343
|
},
|
|
247
344
|
},
|
|
248
345
|
])
|
|
249
346
|
})
|
|
250
347
|
|
|
251
|
-
it('should allow passing optional distinctID to identify group', () => {
|
|
348
|
+
it('should allow passing optional distinctID to identify group', async () => {
|
|
252
349
|
posthog.groupIdentify({
|
|
253
350
|
groupType: 'posthog',
|
|
254
351
|
groupKey: 'team-1',
|
|
@@ -256,6 +353,7 @@ describe('PostHog Node.js', () => {
|
|
|
256
353
|
distinctId: '123',
|
|
257
354
|
})
|
|
258
355
|
jest.runOnlyPendingTimers()
|
|
356
|
+
await posthog.flushAsync()
|
|
259
357
|
const batchEvents = getLastBatchEvents()
|
|
260
358
|
expect(batchEvents).toMatchObject([
|
|
261
359
|
{
|
|
@@ -266,6 +364,7 @@ describe('PostHog Node.js', () => {
|
|
|
266
364
|
$group_key: 'team-1',
|
|
267
365
|
$group_set: { analytics: true },
|
|
268
366
|
$lib: 'posthog-node',
|
|
367
|
+
$geoip_disable: true,
|
|
269
368
|
},
|
|
270
369
|
},
|
|
271
370
|
])
|
|
@@ -292,7 +391,7 @@ describe('PostHog Node.js', () => {
|
|
|
292
391
|
|
|
293
392
|
posthog = new PostHog('TEST_API_KEY', {
|
|
294
393
|
host: 'http://example.com',
|
|
295
|
-
|
|
394
|
+
fetchRetryCount: 0,
|
|
296
395
|
})
|
|
297
396
|
})
|
|
298
397
|
|
|
@@ -302,6 +401,10 @@ describe('PostHog Node.js', () => {
|
|
|
302
401
|
'variant'
|
|
303
402
|
)
|
|
304
403
|
expect(mockedFetch).toHaveBeenCalledTimes(1)
|
|
404
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
405
|
+
'http://example.com/decide/?v=3',
|
|
406
|
+
expect.objectContaining({ method: 'POST', body: expect.stringContaining('"geoip_disable":true') })
|
|
407
|
+
)
|
|
305
408
|
})
|
|
306
409
|
|
|
307
410
|
it('should do isFeatureEnabled', async () => {
|
|
@@ -319,6 +422,7 @@ describe('PostHog Node.js', () => {
|
|
|
319
422
|
posthog = new PostHog('TEST_API_KEY', {
|
|
320
423
|
host: 'http://example.com',
|
|
321
424
|
flushAt: 1,
|
|
425
|
+
fetchRetryCount: 0,
|
|
322
426
|
})
|
|
323
427
|
|
|
324
428
|
posthog.capture({
|
|
@@ -347,12 +451,58 @@ describe('PostHog Node.js', () => {
|
|
|
347
451
|
'$feature/feature-variant': 'variant',
|
|
348
452
|
$lib: 'posthog-node',
|
|
349
453
|
$lib_version: '1.2.3',
|
|
454
|
+
$geoip_disable: true,
|
|
350
455
|
}),
|
|
351
456
|
})
|
|
352
457
|
)
|
|
353
458
|
|
|
354
459
|
// no calls to `/local_evaluation`
|
|
355
460
|
|
|
461
|
+
expect(mockedFetch).not.toHaveBeenCalledWith(...anyLocalEvalCall)
|
|
462
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
463
|
+
'http://example.com/decide/?v=3',
|
|
464
|
+
expect.objectContaining({ method: 'POST', body: expect.stringContaining('"geoip_disable":true') })
|
|
465
|
+
)
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
it('captures feature flags with same geoip setting as capture', async () => {
|
|
469
|
+
mockedFetch.mockClear()
|
|
470
|
+
mockedFetch.mockClear()
|
|
471
|
+
expect(mockedFetch).toHaveBeenCalledTimes(0)
|
|
472
|
+
|
|
473
|
+
posthog = new PostHog('TEST_API_KEY', {
|
|
474
|
+
host: 'http://example.com',
|
|
475
|
+
flushAt: 1,
|
|
476
|
+
fetchRetryCount: 0,
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
posthog.capture({
|
|
480
|
+
distinctId: 'distinct_id',
|
|
481
|
+
event: 'node test event',
|
|
482
|
+
sendFeatureFlags: true,
|
|
483
|
+
disableGeoip: false,
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
487
|
+
'http://example.com/decide/?v=3',
|
|
488
|
+
expect.objectContaining({ method: 'POST', body: expect.not.stringContaining('geoip_disable') })
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
jest.runOnlyPendingTimers()
|
|
492
|
+
|
|
493
|
+
await waitForPromises()
|
|
494
|
+
|
|
495
|
+
expect(getLastBatchEvents()?.[0].properties).toEqual({
|
|
496
|
+
$active_feature_flags: ['feature-1', 'feature-2', 'feature-variant'],
|
|
497
|
+
'$feature/feature-1': true,
|
|
498
|
+
'$feature/feature-2': true,
|
|
499
|
+
'$feature/feature-variant': 'variant',
|
|
500
|
+
$lib: 'posthog-node',
|
|
501
|
+
$lib_version: '1.2.3',
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
// no calls to `/local_evaluation`
|
|
505
|
+
|
|
356
506
|
expect(mockedFetch).not.toHaveBeenCalledWith(...anyLocalEvalCall)
|
|
357
507
|
})
|
|
358
508
|
|
|
@@ -384,6 +534,7 @@ describe('PostHog Node.js', () => {
|
|
|
384
534
|
host: 'http://example.com',
|
|
385
535
|
personalApiKey: 'TEST_PERSONAL_API_KEY',
|
|
386
536
|
maxCacheSize: 10,
|
|
537
|
+
fetchRetryCount: 0,
|
|
387
538
|
})
|
|
388
539
|
|
|
389
540
|
expect(Object.keys(posthog.distinctIdHasSentFlagCalls).length).toEqual(0)
|
|
@@ -442,6 +593,7 @@ describe('PostHog Node.js', () => {
|
|
|
442
593
|
host: 'http://example.com',
|
|
443
594
|
personalApiKey: 'TEST_PERSONAL_API_KEY',
|
|
444
595
|
maxCacheSize: 10,
|
|
596
|
+
fetchRetryCount: 0,
|
|
445
597
|
})
|
|
446
598
|
|
|
447
599
|
expect(
|
|
@@ -462,6 +614,7 @@ describe('PostHog Node.js', () => {
|
|
|
462
614
|
$lib: 'posthog-node',
|
|
463
615
|
$lib_version: '1.2.3',
|
|
464
616
|
locally_evaluated: true,
|
|
617
|
+
$geoip_disable: true,
|
|
465
618
|
}),
|
|
466
619
|
})
|
|
467
620
|
)
|
|
@@ -482,6 +635,7 @@ describe('PostHog Node.js', () => {
|
|
|
482
635
|
await posthog.getFeatureFlag('beta-feature', 'some-distinct-id2', {
|
|
483
636
|
groups: { x: 'y' },
|
|
484
637
|
personProperties: { region: 'USA', name: 'Aloha' },
|
|
638
|
+
disableGeoip: false,
|
|
485
639
|
})
|
|
486
640
|
).toEqual(true)
|
|
487
641
|
jest.runOnlyPendingTimers()
|
|
@@ -491,16 +645,16 @@ describe('PostHog Node.js', () => {
|
|
|
491
645
|
expect.objectContaining({
|
|
492
646
|
distinct_id: 'some-distinct-id2',
|
|
493
647
|
event: '$feature_flag_called',
|
|
494
|
-
properties: expect.objectContaining({
|
|
495
|
-
$feature_flag: 'beta-feature',
|
|
496
|
-
$feature_flag_response: true,
|
|
497
|
-
$lib: 'posthog-node',
|
|
498
|
-
$lib_version: '1.2.3',
|
|
499
|
-
locally_evaluated: true,
|
|
500
|
-
$groups: { x: 'y' },
|
|
501
|
-
}),
|
|
502
648
|
})
|
|
503
649
|
)
|
|
650
|
+
expect(getLastBatchEvents()?.[0].properties).toEqual({
|
|
651
|
+
$feature_flag: 'beta-feature',
|
|
652
|
+
$feature_flag_response: true,
|
|
653
|
+
$lib: 'posthog-node',
|
|
654
|
+
$lib_version: '1.2.3',
|
|
655
|
+
locally_evaluated: true,
|
|
656
|
+
$groups: { x: 'y' },
|
|
657
|
+
})
|
|
504
658
|
mockedFetch.mockClear()
|
|
505
659
|
|
|
506
660
|
// # called for different user, but send configuration is false, so should NOT call capture again
|
|
@@ -559,6 +713,10 @@ describe('PostHog Node.js', () => {
|
|
|
559
713
|
posthog.getFeatureFlagPayload('feature-variant', '123', 'variant', { groups: { org: '123' } })
|
|
560
714
|
).resolves.toEqual(2)
|
|
561
715
|
expect(mockedFetch).toHaveBeenCalledTimes(1)
|
|
716
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
717
|
+
'http://example.com/decide/?v=3',
|
|
718
|
+
expect.objectContaining({ method: 'POST', body: expect.stringContaining('"geoip_disable":true') })
|
|
719
|
+
)
|
|
562
720
|
})
|
|
563
721
|
|
|
564
722
|
it('should do getFeatureFlagPayloads without matchValue', async () => {
|
|
@@ -568,5 +726,26 @@ describe('PostHog Node.js', () => {
|
|
|
568
726
|
).resolves.toEqual(2)
|
|
569
727
|
expect(mockedFetch).toHaveBeenCalledTimes(1)
|
|
570
728
|
})
|
|
729
|
+
|
|
730
|
+
it('should do getFeatureFlags with geoip disabled and enabled', async () => {
|
|
731
|
+
expect(mockedFetch).toHaveBeenCalledTimes(0)
|
|
732
|
+
await expect(
|
|
733
|
+
posthog.getFeatureFlagPayload('feature-variant', '123', 'variant', { groups: { org: '123' } })
|
|
734
|
+
).resolves.toEqual(2)
|
|
735
|
+
expect(mockedFetch).toHaveBeenCalledTimes(1)
|
|
736
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
737
|
+
'http://example.com/decide/?v=3',
|
|
738
|
+
expect.objectContaining({ method: 'POST', body: expect.stringContaining('"geoip_disable":true') })
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
mockedFetch.mockClear()
|
|
742
|
+
|
|
743
|
+
await expect(posthog.isFeatureEnabled('feature-variant', '123', { disableGeoip: false })).resolves.toEqual(true)
|
|
744
|
+
expect(mockedFetch).toHaveBeenCalledTimes(1)
|
|
745
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
746
|
+
'http://example.com/decide/?v=3',
|
|
747
|
+
expect.objectContaining({ method: 'POST', body: expect.not.stringContaining('geoip_disable') })
|
|
748
|
+
)
|
|
749
|
+
})
|
|
571
750
|
})
|
|
572
751
|
})
|