@posthog/next 0.1.0 → 0.4.43
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/dist/app/PostHogProvider.js +7 -7
- package/dist/app/PostHogProvider.js.map +1 -1
- package/dist/client/ClientPostHogProvider.js +2 -2
- package/dist/client/ClientPostHogProvider.js.map +1 -1
- package/dist/client/PostHogPageView.js +2 -2
- package/dist/client/PostHogPageView.js.map +1 -1
- package/dist/client/hooks.d.ts +1 -1
- package/dist/client/hooks.d.ts.map +1 -1
- package/dist/client/hooks.js +1 -1
- package/dist/client/hooks.js.map +1 -1
- package/dist/index.client.d.ts +5 -5
- package/dist/index.client.d.ts.map +1 -1
- package/dist/index.client.js +3 -3
- package/dist/index.client.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.edge.d.ts +6 -6
- package/dist/index.edge.d.ts.map +1 -1
- package/dist/index.edge.js +4 -4
- package/dist/index.edge.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/index.react-server.d.ts +4 -4
- package/dist/index.react-server.d.ts.map +1 -1
- package/dist/index.react-server.js +3 -3
- package/dist/index.react-server.js.map +1 -1
- package/dist/middleware/postHogMiddleware.d.ts +12 -5
- package/dist/middleware/postHogMiddleware.d.ts.map +1 -1
- package/dist/middleware/postHogMiddleware.js +8 -7
- package/dist/middleware/postHogMiddleware.js.map +1 -1
- package/dist/pages/PostHogPageView.js +2 -2
- package/dist/pages/PostHogPageView.js.map +1 -1
- package/dist/pages/PostHogProvider.js +3 -3
- package/dist/pages/PostHogProvider.js.map +1 -1
- package/dist/pages/getServerSidePostHog.d.ts.map +1 -1
- package/dist/pages/getServerSidePostHog.js +8 -7
- package/dist/pages/getServerSidePostHog.js.map +1 -1
- package/dist/pages.client.d.ts +6 -0
- package/dist/pages.client.d.ts.map +1 -0
- package/dist/pages.client.js +8 -0
- package/dist/pages.client.js.map +1 -0
- package/dist/pages.d.ts +8 -8
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.edge.d.ts +7 -0
- package/dist/pages.edge.d.ts.map +1 -0
- package/dist/pages.edge.js +9 -0
- package/dist/pages.edge.js.map +1 -0
- package/dist/pages.js +6 -6
- package/dist/pages.js.map +1 -1
- package/dist/server/getPostHog.d.ts +1 -1
- package/dist/server/getPostHog.d.ts.map +1 -1
- package/dist/server/getPostHog.js +11 -9
- package/dist/server/getPostHog.js.map +1 -1
- package/dist/shared/config.d.ts +3 -0
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +12 -1
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/cookie.js +1 -1
- package/dist/shared/cookie.js.map +1 -1
- package/dist/shared/tracing-headers.d.ts +38 -0
- package/dist/shared/tracing-headers.d.ts.map +1 -0
- package/dist/shared/tracing-headers.js +52 -0
- package/dist/shared/tracing-headers.js.map +1 -0
- package/package.json +13 -6
- package/src/app/PostHogProvider.tsx +8 -8
- package/src/client/ClientPostHogProvider.tsx +2 -2
- package/src/client/PostHogPageView.tsx +2 -2
- package/src/client/hooks.ts +1 -1
- package/src/index.client.ts +5 -5
- package/src/index.edge.ts +6 -6
- package/src/index.react-server.ts +4 -4
- package/src/index.ts +8 -8
- package/src/middleware/postHogMiddleware.ts +19 -11
- package/src/pages/PostHogPageView.tsx +2 -2
- package/src/pages/PostHogProvider.tsx +3 -3
- package/src/pages/getServerSidePostHog.ts +8 -7
- package/src/pages.client.ts +9 -0
- package/src/pages.edge.ts +10 -0
- package/src/pages.ts +8 -8
- package/src/server/getPostHog.ts +11 -9
- package/src/shared/config.ts +15 -1
- package/src/shared/cookie.ts +1 -1
- package/src/shared/tracing-headers.ts +67 -0
package/src/server/getPostHog.ts
CHANGED
|
@@ -2,10 +2,11 @@ import 'server-only'
|
|
|
2
2
|
|
|
3
3
|
import { isFunction } from '@posthog/core'
|
|
4
4
|
import type { PostHogOptions, IPostHog } from 'posthog-node'
|
|
5
|
-
import { cookies } from 'next/headers'
|
|
6
|
-
import { getOrCreateNodeClient } from './nodeClientCache'
|
|
7
|
-
import { readPostHogCookie,
|
|
8
|
-
import { resolveApiKey } from '../shared/config'
|
|
5
|
+
import { cookies, headers } from 'next/headers.js'
|
|
6
|
+
import { getOrCreateNodeClient } from './nodeClientCache.js'
|
|
7
|
+
import { readPostHogCookie, isOptedOut } from '../shared/cookie.js'
|
|
8
|
+
import { resolveApiKey, resolveHostOrDefault } from '../shared/config.js'
|
|
9
|
+
import { readTracingHeaders, buildContextData } from '../shared/tracing-headers.js'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Returns a PostHog server client scoped to the current request.
|
|
@@ -14,7 +15,7 @@ import { resolveApiKey } from '../shared/config'
|
|
|
14
15
|
* request-scoped client. Methods like `getAllFlags()`, `getFeatureFlagResult()`,
|
|
15
16
|
* and `capture()` automatically use the current user's identity.
|
|
16
17
|
*
|
|
17
|
-
* Calls `cookies()` internally, which opts the route into dynamic rendering.
|
|
18
|
+
* Calls `cookies()` and `headers()` internally, which opts the route into dynamic rendering.
|
|
18
19
|
*
|
|
19
20
|
* @param apiKey - PostHog project API key. If omitted, reads from `NEXT_PUBLIC_POSTHOG_KEY`.
|
|
20
21
|
* @param options - Optional `posthog-node` configuration (e.g., `{ host: '...' }`).
|
|
@@ -34,8 +35,8 @@ import { resolveApiKey } from '../shared/config'
|
|
|
34
35
|
*/
|
|
35
36
|
export async function getPostHog(apiKey?: string, options?: Partial<PostHogOptions>): Promise<IPostHog> {
|
|
36
37
|
const resolvedApiKey = resolveApiKey(apiKey)
|
|
37
|
-
const host = options?.host
|
|
38
|
-
const resolvedOptions =
|
|
38
|
+
const host = resolveHostOrDefault(options?.host)
|
|
39
|
+
const resolvedOptions = { ...options, host }
|
|
39
40
|
const client = await getOrCreateNodeClient(resolvedApiKey, resolvedOptions)
|
|
40
41
|
const cookieStore = await cookies()
|
|
41
42
|
|
|
@@ -44,8 +45,9 @@ export async function getPostHog(apiKey?: string, options?: Partial<PostHogOptio
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
const state = readPostHogCookie(cookieStore, resolvedApiKey)
|
|
47
|
-
const
|
|
48
|
-
const
|
|
48
|
+
const headerStore = await headers()
|
|
49
|
+
const tracing = readTracingHeaders(headerStore)
|
|
50
|
+
const contextData = buildContextData(tracing, state)
|
|
49
51
|
|
|
50
52
|
// Wrap the shared client in a Proxy that applies request-scoped context
|
|
51
53
|
// to every method call. We can't use enterContext() here because
|
package/src/shared/config.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PostHogConfig } from 'posthog-js'
|
|
2
2
|
import type { PostHogOptions } from 'posthog-node'
|
|
3
|
+
import { DEFAULT_API_HOST } from './constants.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Configuration for the client-side PostHog provider.
|
|
@@ -19,8 +20,13 @@ export type PostHogServerConfig = PostHogOptions
|
|
|
19
20
|
*
|
|
20
21
|
* Throws if neither is available.
|
|
21
22
|
*/
|
|
23
|
+
export function normalizeConfigValue(value?: unknown): string | undefined {
|
|
24
|
+
const normalizedValue = typeof value === 'string' ? value.trim() : ''
|
|
25
|
+
return normalizedValue || undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
export function resolveApiKey(apiKey?: string): string {
|
|
23
|
-
const resolved = apiKey
|
|
29
|
+
const resolved = normalizeConfigValue(apiKey) ?? normalizeConfigValue(process.env.NEXT_PUBLIC_POSTHOG_KEY)
|
|
24
30
|
if (!resolved) {
|
|
25
31
|
throw new Error(
|
|
26
32
|
'[PostHog Next.js] apiKey is required. Either pass it explicitly or set the NEXT_PUBLIC_POSTHOG_KEY environment variable.'
|
|
@@ -29,6 +35,14 @@ export function resolveApiKey(apiKey?: string): string {
|
|
|
29
35
|
return resolved
|
|
30
36
|
}
|
|
31
37
|
|
|
38
|
+
export function resolveHost(host?: string): string | undefined {
|
|
39
|
+
return normalizeConfigValue(host) ?? normalizeConfigValue(process.env.NEXT_PUBLIC_POSTHOG_HOST)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function resolveHostOrDefault(host?: string): string {
|
|
43
|
+
return resolveHost(host) ?? DEFAULT_API_HOST
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
/**
|
|
33
47
|
* Next.js-specific defaults for the posthog-js client.
|
|
34
48
|
*
|
package/src/shared/cookie.ts
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { isFunction, isArray } from '@posthog/core'
|
|
2
|
+
import type { PostHogCookieState } from './cookie.js'
|
|
3
|
+
import { cookieStateToProperties } from './cookie.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Header names used by the PostHog browser SDK's tracing headers feature.
|
|
7
|
+
*
|
|
8
|
+
* When `__add_tracing_headers` is enabled in the browser SDK, these headers
|
|
9
|
+
* are added to outgoing fetch/XHR requests so that server-side code can
|
|
10
|
+
* correlate events back to the browser session.
|
|
11
|
+
*/
|
|
12
|
+
export const POSTHOG_SESSION_ID_HEADER = 'x-posthog-session-id'
|
|
13
|
+
export const POSTHOG_DISTINCT_ID_HEADER = 'x-posthog-distinct-id'
|
|
14
|
+
export const POSTHOG_WINDOW_ID_HEADER = 'x-posthog-window-id'
|
|
15
|
+
|
|
16
|
+
export interface TracingHeaderValues {
|
|
17
|
+
distinctId?: string
|
|
18
|
+
sessionId?: string
|
|
19
|
+
windowId?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extracts PostHog tracing header values from request headers.
|
|
24
|
+
*
|
|
25
|
+
* Accepts either a Headers-like object with a `.get()` method (e.g. from
|
|
26
|
+
* `next/headers`) or a plain record (e.g. `ctx.req.headers` in Pages Router).
|
|
27
|
+
*/
|
|
28
|
+
export function readTracingHeaders(
|
|
29
|
+
headers: { get(name: string): string | null } | Record<string, string | string[] | undefined>
|
|
30
|
+
): TracingHeaderValues {
|
|
31
|
+
const getValue = (name: string): string | undefined => {
|
|
32
|
+
if (isFunction((headers as { get: unknown }).get)) {
|
|
33
|
+
return (headers as { get(name: string): string | null }).get(name) ?? undefined
|
|
34
|
+
}
|
|
35
|
+
const value = (headers as Record<string, string | string[] | undefined>)[name]
|
|
36
|
+
return typeof value === 'string' ? value : isArray(value) ? value[0] : undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
distinctId: getValue(POSTHOG_DISTINCT_ID_HEADER) || undefined,
|
|
41
|
+
sessionId: getValue(POSTHOG_SESSION_ID_HEADER) || undefined,
|
|
42
|
+
windowId: getValue(POSTHOG_WINDOW_ID_HEADER) || undefined,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Builds context data by merging cookie state with tracing headers.
|
|
48
|
+
*
|
|
49
|
+
* Tracing headers take precedence over cookie values for `distinctId` and
|
|
50
|
+
* `sessionId` because they represent the browser's current state and are
|
|
51
|
+
* set per-request by the browser SDK.
|
|
52
|
+
*/
|
|
53
|
+
export function buildContextData(
|
|
54
|
+
tracing: TracingHeaderValues,
|
|
55
|
+
state: PostHogCookieState | null
|
|
56
|
+
): { distinctId: string | undefined; sessionId: string | undefined; properties: Record<string, string> | undefined } {
|
|
57
|
+
const mergedProperties: Record<string, string> = {
|
|
58
|
+
...cookieStateToProperties(state),
|
|
59
|
+
...(tracing.sessionId ? { $session_id: tracing.sessionId } : {}),
|
|
60
|
+
...(tracing.windowId ? { $window_id: tracing.windowId } : {}),
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
distinctId: tracing.distinctId || state?.distinctId,
|
|
64
|
+
sessionId: tracing.sessionId || state?.sessionId,
|
|
65
|
+
properties: Object.keys(mergedProperties).length > 0 ? mergedProperties : undefined,
|
|
66
|
+
}
|
|
67
|
+
}
|