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.
- package/CHANGELOG.md +8 -0
- package/lib/edge/index.cjs.js +3919 -0
- package/lib/edge/index.cjs.js.map +1 -0
- package/lib/edge/index.esm.js +3893 -0
- package/lib/edge/index.esm.js.map +1 -0
- package/lib/index.d.ts +921 -852
- package/lib/{index.cjs.js → node/index.cjs.js} +3572 -3539
- package/lib/node/index.cjs.js.map +1 -0
- package/lib/{index.esm.js → node/index.esm.js} +3573 -3537
- package/lib/node/index.esm.js.map +1 -0
- package/package.json +31 -4
- package/src/{posthog-node.ts → client.ts} +12 -30
- package/src/entrypoints/index.edge.ts +15 -0
- package/src/entrypoints/index.node.ts +17 -0
- package/src/exports.ts +3 -0
- package/src/extensions/error-tracking/autocapture.ts +1 -1
- package/src/extensions/error-tracking/{context-lines.ts → context-lines.node.ts} +64 -97
- package/src/extensions/error-tracking/error-conversion.ts +22 -5
- package/src/extensions/error-tracking/get-module.node.ts +57 -0
- package/src/{error-tracking.ts → extensions/error-tracking/index.ts} +12 -10
- package/src/extensions/error-tracking/{stack-trace.ts → stack-parser.ts} +7 -64
- package/src/extensions/error-tracking/types.ts +4 -0
- package/src/extensions/express.ts +3 -3
- package/src/{crypto-helpers.ts → extensions/feature-flags/crypto-helpers.ts} +1 -1
- package/src/{feature-flags.ts → extensions/feature-flags/feature-flags.ts} +7 -6
- package/src/extensions/sentry-integration.ts +13 -5
- package/src/fetch.ts +2 -2
- package/src/storage-memory.ts +13 -0
- package/src/types.ts +19 -1
- package/test/crypto.spec.ts +2 -2
- package/test/extensions/error-conversion.spec.ts +2 -2
- package/test/extensions/sentry-integration.spec.ts +1 -2
- package/test/feature-flags.decide.spec.ts +2 -1
- package/test/feature-flags.spec.ts +7 -4
- package/test/lazy.spec.ts +1 -1
- package/test/posthog-node.spec.ts +24 -26
- package/test/test-utils.ts +5 -0
- package/tsconfig.json +1 -0
- package/index.ts +0 -3
- package/lib/index.cjs.js.map +0 -1
- package/lib/index.esm.js.map +0 -1
- package/lib/posthog-core/src/eventemitter.d.ts +0 -8
- package/lib/posthog-core/src/featureFlagUtils.d.ts +0 -34
- package/lib/posthog-core/src/index.d.ts +0 -252
- package/lib/posthog-core/src/lz-string.d.ts +0 -8
- package/lib/posthog-core/src/storage-memory.d.ts +0 -6
- package/lib/posthog-core/src/types.d.ts +0 -422
- package/lib/posthog-core/src/utils.d.ts +0 -20
- package/lib/posthog-core/src/vendor/uuidv7.d.ts +0 -179
- package/lib/posthog-node/index.d.ts +0 -3
- package/lib/posthog-node/src/crypto-helpers.d.ts +0 -3
- package/lib/posthog-node/src/crypto.d.ts +0 -2
- package/lib/posthog-node/src/error-tracking.d.ts +0 -12
- package/lib/posthog-node/src/extensions/error-tracking/autocapture.d.ts +0 -3
- package/lib/posthog-node/src/extensions/error-tracking/context-lines.d.ts +0 -6
- package/lib/posthog-node/src/extensions/error-tracking/error-conversion.d.ts +0 -2
- package/lib/posthog-node/src/extensions/error-tracking/reduceable-cache.d.ts +0 -12
- package/lib/posthog-node/src/extensions/error-tracking/stack-trace.d.ts +0 -15
- package/lib/posthog-node/src/extensions/error-tracking/type-checking.d.ts +0 -7
- package/lib/posthog-node/src/extensions/error-tracking/types.d.ts +0 -57
- package/lib/posthog-node/src/extensions/express.d.ts +0 -17
- package/lib/posthog-node/src/extensions/sentry-integration.d.ts +0 -51
- package/lib/posthog-node/src/feature-flags.d.ts +0 -84
- package/lib/posthog-node/src/fetch.d.ts +0 -11
- package/lib/posthog-node/src/lazy.d.ts +0 -23
- package/lib/posthog-node/src/posthog-node.d.ts +0 -98
- package/lib/posthog-node/src/types.d.ts +0 -229
- package/lib/posthog-node/test/test-utils.d.ts +0 -17
- /package/src/{crypto.ts → extensions/feature-flags/crypto.ts} +0 -0
- /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 '
|
|
4
|
-
import {
|
|
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:
|
|
25
|
+
_posthog: PostHogBackendClient,
|
|
26
26
|
app: {
|
|
27
27
|
use: (middleware: ExpressMiddleware | ExpressErrorMiddleware) => unknown
|
|
28
28
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { FeatureFlagCondition, FlagProperty, PostHogFeatureFlag, PropertyGroup } from '
|
|
2
|
-
import { FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core
|
|
3
|
-
import { safeSetTimeout } from 'posthog-core
|
|
4
|
-
import fetch from '
|
|
5
|
-
import {
|
|
6
|
-
|
|
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 '
|
|
26
|
-
import { type
|
|
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:
|
|
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(
|
|
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(
|
|
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
|
|
11
|
-
import { getFetch } from 'posthog-core
|
|
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 {
|
|
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
|
package/test/crypto.spec.ts
CHANGED
|
@@ -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(
|
|
8
|
+
const exceptionProperties = await propertiesFromUnknownInput(createStackParser(), [], error, {
|
|
9
9
|
syntheticException,
|
|
10
10
|
})
|
|
11
11
|
return exceptionProperties.$exception_list
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
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
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
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,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 {
|
|
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
|
-
|
|
385
|
-
// which tells us when the flush is complete
|
|
384
|
+
ph.capture({ event: 'test-event-1', distinctId: '123' })
|
|
386
385
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
expect(
|
|
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
|
-
|
|
404
|
-
|
|
392
|
+
// start shutdown, but don't wait for promise to resolve before resuming events
|
|
393
|
+
const shutdownPromise = ph.shutdown()
|
|
405
394
|
|
|
406
|
-
|
|
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(
|
|
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(
|
|
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 () => {
|
package/test/test-utils.ts
CHANGED
|
@@ -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
package/index.ts
DELETED