posthog-node 4.15.0 → 4.17.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/edge/index.cjs.js +3919 -0
  3. package/lib/edge/index.cjs.js.map +1 -0
  4. package/lib/edge/index.esm.js +3893 -0
  5. package/lib/edge/index.esm.js.map +1 -0
  6. package/lib/index.d.ts +921 -852
  7. package/lib/{index.cjs.js → node/index.cjs.js} +3572 -3539
  8. package/lib/node/index.cjs.js.map +1 -0
  9. package/lib/{index.esm.js → node/index.esm.js} +3573 -3537
  10. package/lib/node/index.esm.js.map +1 -0
  11. package/package.json +31 -4
  12. package/src/{posthog-node.ts → client.ts} +12 -30
  13. package/src/entrypoints/index.edge.ts +15 -0
  14. package/src/entrypoints/index.node.ts +17 -0
  15. package/src/exports.ts +3 -0
  16. package/src/extensions/error-tracking/autocapture.ts +1 -1
  17. package/src/extensions/error-tracking/{context-lines.ts → context-lines.node.ts} +64 -97
  18. package/src/extensions/error-tracking/error-conversion.ts +22 -5
  19. package/src/extensions/error-tracking/get-module.node.ts +57 -0
  20. package/src/{error-tracking.ts → extensions/error-tracking/index.ts} +12 -10
  21. package/src/extensions/error-tracking/{stack-trace.ts → stack-parser.ts} +7 -64
  22. package/src/extensions/error-tracking/types.ts +4 -0
  23. package/src/extensions/express.ts +3 -3
  24. package/src/{crypto-helpers.ts → extensions/feature-flags/crypto-helpers.ts} +1 -1
  25. package/src/{feature-flags.ts → extensions/feature-flags/feature-flags.ts} +7 -6
  26. package/src/extensions/sentry-integration.ts +13 -5
  27. package/src/fetch.ts +2 -2
  28. package/src/storage-memory.ts +13 -0
  29. package/src/types.ts +19 -1
  30. package/test/crypto.spec.ts +2 -2
  31. package/test/extensions/error-conversion.spec.ts +2 -2
  32. package/test/extensions/sentry-integration.spec.ts +1 -2
  33. package/test/feature-flags.decide.spec.ts +2 -1
  34. package/test/feature-flags.spec.ts +7 -4
  35. package/test/lazy.spec.ts +1 -1
  36. package/test/posthog-node.spec.ts +24 -26
  37. package/test/test-utils.ts +5 -0
  38. package/tsconfig.json +1 -0
  39. package/index.ts +0 -3
  40. package/lib/index.cjs.js.map +0 -1
  41. package/lib/index.esm.js.map +0 -1
  42. package/lib/posthog-core/src/eventemitter.d.ts +0 -8
  43. package/lib/posthog-core/src/featureFlagUtils.d.ts +0 -34
  44. package/lib/posthog-core/src/index.d.ts +0 -252
  45. package/lib/posthog-core/src/lz-string.d.ts +0 -8
  46. package/lib/posthog-core/src/storage-memory.d.ts +0 -6
  47. package/lib/posthog-core/src/types.d.ts +0 -422
  48. package/lib/posthog-core/src/utils.d.ts +0 -20
  49. package/lib/posthog-core/src/vendor/uuidv7.d.ts +0 -179
  50. package/lib/posthog-node/index.d.ts +0 -3
  51. package/lib/posthog-node/src/crypto-helpers.d.ts +0 -3
  52. package/lib/posthog-node/src/crypto.d.ts +0 -2
  53. package/lib/posthog-node/src/error-tracking.d.ts +0 -12
  54. package/lib/posthog-node/src/extensions/error-tracking/autocapture.d.ts +0 -3
  55. package/lib/posthog-node/src/extensions/error-tracking/context-lines.d.ts +0 -6
  56. package/lib/posthog-node/src/extensions/error-tracking/error-conversion.d.ts +0 -2
  57. package/lib/posthog-node/src/extensions/error-tracking/reduceable-cache.d.ts +0 -12
  58. package/lib/posthog-node/src/extensions/error-tracking/stack-trace.d.ts +0 -15
  59. package/lib/posthog-node/src/extensions/error-tracking/type-checking.d.ts +0 -7
  60. package/lib/posthog-node/src/extensions/error-tracking/types.d.ts +0 -57
  61. package/lib/posthog-node/src/extensions/express.d.ts +0 -17
  62. package/lib/posthog-node/src/extensions/sentry-integration.d.ts +0 -51
  63. package/lib/posthog-node/src/feature-flags.d.ts +0 -84
  64. package/lib/posthog-node/src/fetch.d.ts +0 -11
  65. package/lib/posthog-node/src/lazy.d.ts +0 -23
  66. package/lib/posthog-node/src/posthog-node.d.ts +0 -98
  67. package/lib/posthog-node/src/types.d.ts +0 -229
  68. package/lib/posthog-node/test/test-utils.d.ts +0 -17
  69. /package/src/{crypto.ts → extensions/feature-flags/crypto.ts} +0 -0
  70. /package/src/{lazy.ts → extensions/feature-flags/lazy.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  import type * as http from 'node:http'
2
2
  import { uuidv7 } from 'posthog-core/src/vendor/uuidv7'
3
- import ErrorTracking from '../error-tracking'
4
- import { PostHog } from '../posthog-node'
3
+ import ErrorTracking from './error-tracking'
4
+ import { PostHogBackendClient } from '../client'
5
5
 
6
6
  type ExpressMiddleware = (req: http.IncomingMessage, res: http.ServerResponse, next: () => void) => void
7
7
 
@@ -22,7 +22,7 @@ interface MiddlewareError extends Error {
22
22
  }
23
23
 
24
24
  export function setupExpressErrorHandler(
25
- _posthog: PostHog,
25
+ _posthog: PostHogBackendClient,
26
26
  app: {
27
27
  use: (middleware: ExpressMiddleware | ExpressErrorMiddleware) => unknown
28
28
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="dom" />
2
- import { Lazy } from 'posthog-node/src/lazy'
2
+ import { Lazy } from './lazy'
3
3
 
4
4
  const nodeCrypto = new Lazy(async () => {
5
5
  try {
@@ -1,9 +1,10 @@
1
- import { FeatureFlagCondition, FlagProperty, PostHogFeatureFlag, PropertyGroup } from './types'
2
- import { FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src'
3
- import { safeSetTimeout } from 'posthog-core/src/utils'
4
- import fetch from './fetch'
5
- import { SIXTY_SECONDS } from './posthog-node'
6
- import { hashSHA1 } from 'posthog-node/src/crypto'
1
+ import { FeatureFlagCondition, FlagProperty, PostHogFeatureFlag, PropertyGroup } from '../../types'
2
+ import type { FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core'
3
+ import { safeSetTimeout } from 'posthog-core'
4
+ import fetch from '../../fetch'
5
+ import { hashSHA1 } from './crypto'
6
+
7
+ const SIXTY_SECONDS = 60 * 1000
7
8
 
8
9
  // eslint-disable-next-line
9
10
  const LONG_SCALE = 0xfffffffffffffff
@@ -22,8 +22,8 @@
22
22
  * @param {SeverityLevel[] | '*'} [severityAllowList] Optional: send events matching the provided levels. Use '*' to send all events (default: ['error'])
23
23
  */
24
24
 
25
- import { SeverityLevel } from 'posthog-node/src/extensions/error-tracking/types'
26
- import { type PostHog } from '../posthog-node'
25
+ import { SeverityLevel } from './error-tracking/types'
26
+ import { type PostHogBackendClient } from '../client'
27
27
 
28
28
  // NOTE - we can't import from @sentry/types because it changes frequently and causes clashes
29
29
  // We only use a small subset of the types, so we can just define the integration overall and use any for the rest
@@ -75,7 +75,7 @@ export type SentryIntegrationOptions = {
75
75
  const NAME = 'posthog-node'
76
76
 
77
77
  export function createEventProcessor(
78
- _posthog: PostHog,
78
+ _posthog: PostHogBackendClient,
79
79
  { organization, projectId, prefix, severityAllowList = ['error'] }: SentryIntegrationOptions = {}
80
80
  ): (event: _SentryEvent) => _SentryEvent {
81
81
  return (event) => {
@@ -154,7 +154,10 @@ export function createEventProcessor(
154
154
  }
155
155
 
156
156
  // V8 integration - function based
157
- export function sentryIntegration(_posthog: PostHog, options?: SentryIntegrationOptions): _SentryIntegration {
157
+ export function sentryIntegration(
158
+ _posthog: PostHogBackendClient,
159
+ options?: SentryIntegrationOptions
160
+ ): _SentryIntegration {
158
161
  const processor = createEventProcessor(_posthog, options)
159
162
  return {
160
163
  name: NAME,
@@ -175,7 +178,12 @@ export class PostHogSentryIntegration implements _SentryIntegrationClass {
175
178
  getCurrentHub: () => _SentryHub
176
179
  ) => void
177
180
 
178
- constructor(_posthog: PostHog, organization?: string, prefix?: string, severityAllowList?: SeverityLevel[] | '*') {
181
+ constructor(
182
+ _posthog: PostHogBackendClient,
183
+ organization?: string,
184
+ prefix?: string,
185
+ severityAllowList?: SeverityLevel[] | '*'
186
+ ) {
179
187
  // setupOnce gets called by Sentry when it intializes the plugin
180
188
  this.name = NAME
181
189
  this.setupOnce = function (
package/src/fetch.ts CHANGED
@@ -7,8 +7,8 @@
7
7
  * See https://github.com/PostHog/posthog-js-lite/issues/127 for more info
8
8
  */
9
9
 
10
- import { FetchLike, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src'
11
- import { getFetch } from 'posthog-core/src/utils'
10
+ import { FetchLike, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core'
11
+ import { getFetch } from 'posthog-core'
12
12
 
13
13
  let _fetch: FetchLike | undefined = getFetch()
14
14
 
@@ -0,0 +1,13 @@
1
+ import { PostHogPersistedProperty } from 'posthog-core'
2
+
3
+ export class PostHogMemoryStorage {
4
+ private _memoryStorage: { [key: string]: any | undefined } = {}
5
+
6
+ getProperty(key: PostHogPersistedProperty): any | undefined {
7
+ return this._memoryStorage[key]
8
+ }
9
+
10
+ setProperty(key: PostHogPersistedProperty, value: any | null): void {
11
+ this._memoryStorage[key] = value !== null ? value : undefined
12
+ }
13
+ }
package/src/types.ts CHANGED
@@ -1,4 +1,10 @@
1
- import { FeatureFlagValue, JsonType } from '../../posthog-core/src'
1
+ import type {
2
+ PostHogCoreOptions,
3
+ FeatureFlagValue,
4
+ JsonType,
5
+ PostHogFetchOptions,
6
+ PostHogFetchResponse,
7
+ } from 'posthog-core'
2
8
 
3
9
  export interface IdentifyMessage {
4
10
  distinctId: string
@@ -41,6 +47,18 @@ export type FeatureFlagCondition = {
41
47
  variant?: string
42
48
  }
43
49
 
50
+ export type PostHogOptions = PostHogCoreOptions & {
51
+ persistence?: 'memory'
52
+ personalApiKey?: string
53
+ privacyMode?: boolean
54
+ enableExceptionAutocapture?: boolean
55
+ // The interval in milliseconds between polls for refreshing feature flag definitions. Defaults to 30 seconds.
56
+ featureFlagsPollingInterval?: number
57
+ // Maximum size of cache that deduplicates $feature_flag_called calls per user.
58
+ maxCacheSize?: number
59
+ fetch?: (url: string, options: PostHogFetchOptions) => Promise<PostHogFetchResponse>
60
+ }
61
+
44
62
  export type PostHogFeatureFlag = {
45
63
  id: number
46
64
  name: string
@@ -1,5 +1,5 @@
1
- import * as crypto from '../src/crypto'
2
- import * as cryptoHelpers from '../src/crypto-helpers'
1
+ import * as crypto from '../src/extensions/feature-flags/crypto'
2
+ import * as cryptoHelpers from '../src/extensions/feature-flags/crypto-helpers'
3
3
 
4
4
  describe('crypto', () => {
5
5
  describe('hashSHA1', () => {
@@ -1,11 +1,11 @@
1
1
  import { propertiesFromUnknownInput } from '../../src/extensions/error-tracking/error-conversion'
2
- import { defaultStackParser } from '../../src/extensions/error-tracking/stack-trace'
3
2
  import { ErrorProperties } from '../../src/extensions/error-tracking/types'
3
+ import { createStackParser } from '../../src/extensions/error-tracking/stack-parser'
4
4
 
5
5
  describe('error conversion', () => {
6
6
  async function getExceptionList(error: unknown): Promise<ErrorProperties['$exception_list']> {
7
7
  const syntheticException = new Error('PostHog syntheticException')
8
- const exceptionProperties = await propertiesFromUnknownInput(defaultStackParser, error, {
8
+ const exceptionProperties = await propertiesFromUnknownInput(createStackParser(), [], error, {
9
9
  syntheticException,
10
10
  })
11
11
  return exceptionProperties.$exception_list
@@ -1,5 +1,4 @@
1
- // import { PostHog } from '../'
2
- import { PostHog as PostHog } from '../../src/posthog-node'
1
+ import { PostHog } from '../../src/entrypoints/index.node'
3
2
  import { PostHogSentryIntegration } from '../../src/extensions/sentry-integration'
4
3
  jest.mock('../../src/fetch')
5
4
  import fetch from '../../src/fetch'
@@ -1,4 +1,5 @@
1
- import { PostHog as PostHog, PostHogOptions } from '../src/posthog-node'
1
+ import { PostHog } from '../src/entrypoints/index.node'
2
+ import { PostHogOptions } from '../src/types'
2
3
  import fetch from '../src/fetch'
3
4
  import { apiImplementation, apiImplementationV4 } from './test-utils'
4
5
  import { waitForPromises } from 'posthog-core/test/test-utils/test-utils'
@@ -1,7 +1,10 @@
1
- // import { PostHog, PostHogOptions } from '../'
2
- // Uncomment below line while developing to not compile code everytime
3
- import { PostHog as PostHog, PostHogOptions } from '../src/posthog-node'
4
- import { matchProperty, InconclusiveMatchError, relativeDateParseForFeatureFlagMatching } from '../src/feature-flags'
1
+ import { PostHogOptions } from '../src/types'
2
+ import { PostHog } from '../src/entrypoints/index.node'
3
+ import {
4
+ matchProperty,
5
+ InconclusiveMatchError,
6
+ relativeDateParseForFeatureFlagMatching,
7
+ } from '../src/extensions/feature-flags/feature-flags'
5
8
  import fetch from '../src/fetch'
6
9
  import { anyDecideCall, anyLocalEvalCall, apiImplementation } from './test-utils'
7
10
  import { waitForPromises } from 'posthog-core/test/test-utils/test-utils'
package/test/lazy.spec.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Lazy } from '../src/lazy'
1
+ import { Lazy } from '../src/extensions/feature-flags/lazy'
2
2
 
3
3
  describe('Lazy', () => {
4
4
  it('should only call the factory once', async (): Promise<void> => {
@@ -1,6 +1,6 @@
1
- import { MINIMUM_POLLING_INTERVAL, PostHog as PostHog, THIRTY_SECONDS } from '../src/posthog-node'
2
1
  import fetch from '../src/fetch'
3
- import { anyDecideCall, anyLocalEvalCall, apiImplementation } from './test-utils'
2
+ import { PostHog } from '../src/entrypoints/index.node'
3
+ import { anyDecideCall, anyLocalEvalCall, apiImplementation, isPending } from './test-utils'
4
4
  import { waitForPromises, wait } from '../../posthog-core/test/test-utils/test-utils'
5
5
  import { randomUUID } from 'crypto'
6
6
  jest.mock('../src/fetch')
@@ -381,33 +381,31 @@ describe('PostHog Node.js', () => {
381
381
  })
382
382
  ph.debug(true)
383
383
 
384
- // using debug mode to check console.log output
385
- // which tells us when the flush is complete
384
+ ph.capture({ event: 'test-event-1', distinctId: '123' })
386
385
 
387
- ph.capture({ event: 'test-event', distinctId: '123' })
388
- await wait(100)
389
- expect(logSpy).toHaveBeenCalledTimes(1)
386
+ // start flushing, but don't wait for promise to resolve before resuming events
387
+ const flushPromise = ph.flush()
388
+ expect(isPending(flushPromise)).toEqual(true)
390
389
 
391
- ph.capture({ event: 'test-event', distinctId: '123' })
392
- ph.capture({ event: 'test-event', distinctId: '123' })
393
- await wait(100)
394
- expect(logSpy).toHaveBeenCalledTimes(3)
395
- await wait(400) // The flush will resolve in this time
396
- ph.capture({ event: 'test-event', distinctId: '123' })
397
- ph.capture({ event: 'test-event', distinctId: '123' })
398
- await wait(100)
399
- expect(logSpy).toHaveBeenCalledTimes(6) // 5 captures and 1 flush
400
- expect(5).toEqual(logSpy.mock.calls.filter((call) => call[1].includes('capture')).length)
401
- expect(1).toEqual(logSpy.mock.calls.filter((call) => call[1].includes('flush')).length)
390
+ ph.capture({ event: 'test-event-2', distinctId: '123' })
402
391
 
403
- logSpy.mockClear()
404
- expect(logSpy).toHaveBeenCalledTimes(0)
392
+ // start shutdown, but don't wait for promise to resolve before resuming events
393
+ const shutdownPromise = ph.shutdown()
405
394
 
406
- console.warn('YOO!!')
395
+ ph.capture({ event: 'test-event-3', distinctId: '123' })
396
+
397
+ // wait for shutdown to finish
398
+ await shutdownPromise
399
+ expect(isPending(flushPromise)).toEqual(false)
400
+
401
+ expect(3).toEqual(logSpy.mock.calls.filter((call) => call[1].includes('capture')).length)
402
+ const flushedEvents = logSpy.mock.calls.filter((call) => call[1].includes('flush')).flatMap((flush) => flush[2])
403
+ expect(flushedEvents).toMatchObject([
404
+ { event: 'test-event-1' },
405
+ { event: 'test-event-2' },
406
+ { event: 'test-event-3' },
407
+ ])
407
408
 
408
- await ph.shutdown()
409
- // 1 final flush for the events that were queued during shutdown
410
- expect(1).toEqual(logSpy.mock.calls.filter((call) => call[1].includes('flush')).length)
411
409
  logSpy.mockRestore()
412
410
  warnSpy.mockRestore()
413
411
  })
@@ -685,7 +683,7 @@ describe('PostHog Node.js', () => {
685
683
  featureFlagsPollingInterval: 98,
686
684
  })
687
685
 
688
- expect(posthog.options.featureFlagsPollingInterval).toEqual(MINIMUM_POLLING_INTERVAL)
686
+ expect(posthog.options.featureFlagsPollingInterval).toEqual(100)
689
687
  })
690
688
 
691
689
  it('should use default featureFlagsPollingInterval of 30000ms if none provided', async () => {
@@ -695,7 +693,7 @@ describe('PostHog Node.js', () => {
695
693
  personalApiKey: 'TEST_PERSONAL_API_KEY',
696
694
  })
697
695
 
698
- expect(posthog.options.featureFlagsPollingInterval).toEqual(THIRTY_SECONDS)
696
+ expect(posthog.options.featureFlagsPollingInterval).toEqual(30000)
699
697
  })
700
698
 
701
699
  it('should throw an error when creating SDK if a project key is passed in as personalApiKey', async () => {
@@ -1,4 +1,5 @@
1
1
  import { PostHogV4DecideResponse } from 'posthog-core/src/types'
2
+ import util from 'util'
2
3
 
3
4
  type ErrorResponse = {
4
5
  status: number
@@ -104,3 +105,7 @@ export const anyLocalEvalCall = [
104
105
  expect.any(Object),
105
106
  ]
106
107
  export const anyDecideCall = ['http://example.com/flags/?v=2', expect.any(Object)]
108
+
109
+ export const isPending = (promise: Promise<any>): boolean => {
110
+ return util.inspect(promise).includes('pending')
111
+ }
package/tsconfig.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "extends": "../tsconfig.json",
3
3
  "compilerOptions": {
4
+ "incremental": false,
4
5
  "types": ["node"],
5
6
  "typeRoots": ["./node_modules/@types", "../node_modules/@types"]
6
7
  }
package/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './src/posthog-node'
2
- export * from './src/extensions/sentry-integration'
3
- export * from './src/extensions/express'