@posthog/core 1.28.7 → 1.29.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.
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Minimal cookie-reading interface compatible with Next.js `cookies()`,
3
+ * `request.cookies`, and plain objects.
4
+ */
5
+ export interface CookieStore {
6
+ get(name: string): {
7
+ value: string;
8
+ } | undefined;
9
+ }
10
+ /**
11
+ * Adapts a raw `Cookie` header string into a {@link CookieStore}.
12
+ */
13
+ export declare function cookieStoreFromHeader(cookieHeader: string): CookieStore;
14
+ export interface PostHogCookieState {
15
+ distinctId: string;
16
+ isIdentified: boolean;
17
+ sessionId?: string;
18
+ deviceId?: string;
19
+ }
20
+ /**
21
+ * Returns the PostHog cookie name for the given API key.
22
+ *
23
+ * PostHog-js stores state in a cookie named `ph_<sanitized_token>_posthog`.
24
+ * The token is sanitized by replacing `+` with `PL`, `/` with `SL`, `=` with `EQ`.
25
+ *
26
+ * @param apiKey - The PostHog project API key
27
+ * @returns The cookie name string
28
+ */
29
+ export declare function getPostHogCookieName(apiKey: string): string;
30
+ /**
31
+ * Serializes an anonymous ID into the JSON format posthog-js expects.
32
+ *
33
+ * When `distinct_id === $device_id`, posthog-js treats the user as anonymous.
34
+ *
35
+ * @param anonymousId - The anonymous distinct ID to serialize
36
+ * @returns JSON string suitable for the PostHog cookie value
37
+ */
38
+ export declare function serializePostHogCookie(anonymousId: string): string;
39
+ /**
40
+ * Reads and parses the PostHog cookie from a cookie store.
41
+ *
42
+ * Compatible with Next.js `cookies()`, `request.cookies`, and any object
43
+ * with a `get(name)` method that returns `{ value: string } | undefined`.
44
+ */
45
+ export declare function readPostHogCookie(cookies: CookieStore, apiKey: string): PostHogCookieState | null;
46
+ /**
47
+ * Converts cookie state into PostHog properties (e.g. `$session_id`, `$device_id`).
48
+ */
49
+ export declare function cookieStateToProperties(state: PostHogCookieState | null): Record<string, string> | undefined;
50
+ /**
51
+ * Parses a PostHog cookie value and extracts identity information.
52
+ *
53
+ * The cookie value is a JSON object containing `distinct_id` and `$user_state`.
54
+ * A user is considered identified if `$user_state` is `'identified'`.
55
+ *
56
+ * @param cookieValue - The raw cookie string value
57
+ * @returns Parsed identity state, or null if the cookie is missing/invalid
58
+ */
59
+ export declare function parsePostHogCookie(cookieValue: string): PostHogCookieState | null;
60
+ export interface ConsentCookieConfig {
61
+ consent_persistence_name?: string | null;
62
+ opt_out_capturing_cookie_prefix?: string | null;
63
+ }
64
+ export declare function getConsentCookieName(apiKey: string, config?: ConsentCookieConfig): string;
65
+ export interface ConsentConfig extends ConsentCookieConfig {
66
+ opt_out_capturing_by_default?: boolean;
67
+ }
68
+ export declare function isOptedOut(cookies: CookieStore, apiKey: string, config?: ConsentConfig): boolean;
69
+ //# sourceMappingURL=cookie.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../src/cookie.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CACjD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,CAmBvE;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CASlE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAIjG;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAY5G;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAuBjF;AAED,MAAM,WAAW,mBAAmB;IAClC,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxC,+BAA+B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAChD;AAID,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAQzF;AAED,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IACxD,4BAA4B,CAAC,EAAE,OAAO,CAAA;CACvC;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAUhG"}
package/dist/cookie.js ADDED
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ getConsentCookieName: ()=>getConsentCookieName,
28
+ parsePostHogCookie: ()=>parsePostHogCookie,
29
+ isOptedOut: ()=>isOptedOut,
30
+ readPostHogCookie: ()=>readPostHogCookie,
31
+ serializePostHogCookie: ()=>serializePostHogCookie,
32
+ cookieStateToProperties: ()=>cookieStateToProperties,
33
+ getPostHogCookieName: ()=>getPostHogCookieName,
34
+ cookieStoreFromHeader: ()=>cookieStoreFromHeader
35
+ });
36
+ const index_js_namespaceObject = require("./utils/index.js");
37
+ const uuidv7_js_namespaceObject = require("./vendor/uuidv7.js");
38
+ const COOKIE_PREFIX = 'ph_';
39
+ const COOKIE_SUFFIX = '_posthog';
40
+ function cookieStoreFromHeader(cookieHeader) {
41
+ const cookies = {};
42
+ if (cookieHeader) for (const pair of cookieHeader.split(';')){
43
+ const [key, ...valueParts] = pair.trim().split('=');
44
+ if (key) {
45
+ const raw = valueParts.join('=').trim();
46
+ try {
47
+ cookies[key.trim()] = decodeURIComponent(raw);
48
+ } catch {
49
+ cookies[key.trim()] = raw;
50
+ }
51
+ }
52
+ }
53
+ return {
54
+ get: (name)=>name in cookies ? {
55
+ value: cookies[name]
56
+ } : void 0
57
+ };
58
+ }
59
+ function getPostHogCookieName(apiKey) {
60
+ const sanitized = apiKey.replace(/\+/g, 'PL').replace(/\//g, 'SL').replace(/=/g, 'EQ');
61
+ return `${COOKIE_PREFIX}${sanitized}${COOKIE_SUFFIX}`;
62
+ }
63
+ function serializePostHogCookie(anonymousId) {
64
+ const now = Date.now();
65
+ const sessionId = (0, uuidv7_js_namespaceObject.uuidv7)();
66
+ return JSON.stringify({
67
+ distinct_id: anonymousId,
68
+ $device_id: anonymousId,
69
+ $user_state: 'anonymous',
70
+ $sesid: [
71
+ now,
72
+ sessionId,
73
+ now
74
+ ]
75
+ });
76
+ }
77
+ function readPostHogCookie(cookies, apiKey) {
78
+ const cookieName = getPostHogCookieName(apiKey);
79
+ const cookie = cookies.get(cookieName);
80
+ return cookie ? parsePostHogCookie(cookie.value) : null;
81
+ }
82
+ function cookieStateToProperties(state) {
83
+ if (!state) return;
84
+ const props = {};
85
+ if (state.sessionId) props.$session_id = state.sessionId;
86
+ if (state.deviceId) props.$device_id = state.deviceId;
87
+ return Object.keys(props).length > 0 ? props : void 0;
88
+ }
89
+ function parsePostHogCookie(cookieValue) {
90
+ if (!cookieValue) return null;
91
+ try {
92
+ const parsed = JSON.parse(cookieValue);
93
+ if (!parsed || 'object' != typeof parsed || !parsed.distinct_id) return null;
94
+ const sesid = (0, index_js_namespaceObject.isArray)(parsed.$sesid) ? parsed.$sesid[1] : void 0;
95
+ return {
96
+ distinctId: String(parsed.distinct_id),
97
+ isIdentified: 'identified' === parsed.$user_state,
98
+ sessionId: 'string' == typeof sesid ? sesid : void 0,
99
+ deviceId: 'string' == typeof parsed.$device_id ? parsed.$device_id : void 0
100
+ };
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+ const CONSENT_PREFIX = '__ph_opt_in_out_';
106
+ function getConsentCookieName(apiKey, config) {
107
+ if (config?.consent_persistence_name) return config.consent_persistence_name;
108
+ if (config?.opt_out_capturing_cookie_prefix) return config.opt_out_capturing_cookie_prefix + apiKey;
109
+ return CONSENT_PREFIX + apiKey;
110
+ }
111
+ function isOptedOut(cookies, apiKey, config) {
112
+ const cookieName = getConsentCookieName(apiKey, config);
113
+ const cookie = cookies.get(cookieName);
114
+ if (cookie) return (0, index_js_namespaceObject.isNoLike)(cookie.value);
115
+ return config?.opt_out_capturing_by_default ?? false;
116
+ }
117
+ exports.cookieStateToProperties = __webpack_exports__.cookieStateToProperties;
118
+ exports.cookieStoreFromHeader = __webpack_exports__.cookieStoreFromHeader;
119
+ exports.getConsentCookieName = __webpack_exports__.getConsentCookieName;
120
+ exports.getPostHogCookieName = __webpack_exports__.getPostHogCookieName;
121
+ exports.isOptedOut = __webpack_exports__.isOptedOut;
122
+ exports.parsePostHogCookie = __webpack_exports__.parsePostHogCookie;
123
+ exports.readPostHogCookie = __webpack_exports__.readPostHogCookie;
124
+ exports.serializePostHogCookie = __webpack_exports__.serializePostHogCookie;
125
+ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
126
+ "cookieStateToProperties",
127
+ "cookieStoreFromHeader",
128
+ "getConsentCookieName",
129
+ "getPostHogCookieName",
130
+ "isOptedOut",
131
+ "parsePostHogCookie",
132
+ "readPostHogCookie",
133
+ "serializePostHogCookie"
134
+ ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
135
+ Object.defineProperty(exports, '__esModule', {
136
+ value: true
137
+ });
@@ -0,0 +1,82 @@
1
+ import { isArray, isNoLike } from "./utils/index.mjs";
2
+ import { uuidv7 } from "./vendor/uuidv7.mjs";
3
+ const COOKIE_PREFIX = 'ph_';
4
+ const COOKIE_SUFFIX = '_posthog';
5
+ function cookieStoreFromHeader(cookieHeader) {
6
+ const cookies = {};
7
+ if (cookieHeader) for (const pair of cookieHeader.split(';')){
8
+ const [key, ...valueParts] = pair.trim().split('=');
9
+ if (key) {
10
+ const raw = valueParts.join('=').trim();
11
+ try {
12
+ cookies[key.trim()] = decodeURIComponent(raw);
13
+ } catch {
14
+ cookies[key.trim()] = raw;
15
+ }
16
+ }
17
+ }
18
+ return {
19
+ get: (name)=>name in cookies ? {
20
+ value: cookies[name]
21
+ } : void 0
22
+ };
23
+ }
24
+ function getPostHogCookieName(apiKey) {
25
+ const sanitized = apiKey.replace(/\+/g, 'PL').replace(/\//g, 'SL').replace(/=/g, 'EQ');
26
+ return `${COOKIE_PREFIX}${sanitized}${COOKIE_SUFFIX}`;
27
+ }
28
+ function serializePostHogCookie(anonymousId) {
29
+ const now = Date.now();
30
+ const sessionId = uuidv7();
31
+ return JSON.stringify({
32
+ distinct_id: anonymousId,
33
+ $device_id: anonymousId,
34
+ $user_state: 'anonymous',
35
+ $sesid: [
36
+ now,
37
+ sessionId,
38
+ now
39
+ ]
40
+ });
41
+ }
42
+ function readPostHogCookie(cookies, apiKey) {
43
+ const cookieName = getPostHogCookieName(apiKey);
44
+ const cookie = cookies.get(cookieName);
45
+ return cookie ? parsePostHogCookie(cookie.value) : null;
46
+ }
47
+ function cookieStateToProperties(state) {
48
+ if (!state) return;
49
+ const props = {};
50
+ if (state.sessionId) props.$session_id = state.sessionId;
51
+ if (state.deviceId) props.$device_id = state.deviceId;
52
+ return Object.keys(props).length > 0 ? props : void 0;
53
+ }
54
+ function parsePostHogCookie(cookieValue) {
55
+ if (!cookieValue) return null;
56
+ try {
57
+ const parsed = JSON.parse(cookieValue);
58
+ if (!parsed || 'object' != typeof parsed || !parsed.distinct_id) return null;
59
+ const sesid = isArray(parsed.$sesid) ? parsed.$sesid[1] : void 0;
60
+ return {
61
+ distinctId: String(parsed.distinct_id),
62
+ isIdentified: 'identified' === parsed.$user_state,
63
+ sessionId: 'string' == typeof sesid ? sesid : void 0,
64
+ deviceId: 'string' == typeof parsed.$device_id ? parsed.$device_id : void 0
65
+ };
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ const CONSENT_PREFIX = '__ph_opt_in_out_';
71
+ function getConsentCookieName(apiKey, config) {
72
+ if (config?.consent_persistence_name) return config.consent_persistence_name;
73
+ if (config?.opt_out_capturing_cookie_prefix) return config.opt_out_capturing_cookie_prefix + apiKey;
74
+ return CONSENT_PREFIX + apiKey;
75
+ }
76
+ function isOptedOut(cookies, apiKey, config) {
77
+ const cookieName = getConsentCookieName(apiKey, config);
78
+ const cookie = cookies.get(cookieName);
79
+ if (cookie) return isNoLike(cookie.value);
80
+ return config?.opt_out_capturing_by_default ?? false;
81
+ }
82
+ export { cookieStateToProperties, cookieStoreFromHeader, getConsentCookieName, getPostHogCookieName, isOptedOut, parsePostHogCookie, readPostHogCookie, serializePostHogCookie };
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export { PostHogLogs } from './logs';
7
7
  export type { BeforeSendLogFn, BufferedLogEntry, CaptureLogger, LogSdkContext, PostHogLogsConfig, ResolvedPostHogLogsConfig, } from './logs/types';
8
8
  export type { CaptureLogOptions, LogAttributeValue, LogAttributes, LogSeverityLevel } from './logs/types';
9
9
  export { uuidv7 } from './vendor/uuidv7';
10
+ export * from './cookie';
10
11
  export * from './posthog-core';
11
12
  export * from './posthog-core-stateless';
12
13
  export * from './tracing-headers';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,QAAQ,CAAA;AACzF,cAAc,SAAS,CAAA;AACvB,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AACjD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACpC,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,cAAc,CAAA;AAIrB,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACzG,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,0BAA0B,CAAA;AACxC,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,QAAQ,CAAA;AACzF,cAAc,SAAS,CAAA;AACvB,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AACjD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACpC,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,cAAc,CAAA;AAIrB,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACzG,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,0BAA0B,CAAA;AACxC,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  "use strict";
2
2
  var __webpack_modules__ = {
3
+ "./cookie": function(module) {
4
+ module.exports = require("./cookie.js");
5
+ },
3
6
  "./error-tracking": function(module) {
4
7
  module.exports = require("./error-tracking/index.js");
5
8
  },
@@ -86,11 +89,11 @@ var __webpack_exports__ = {};
86
89
  buildOtlpLogRecord: ()=>_logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__.buildOtlpLogRecord,
87
90
  buildOtlpLogsPayload: ()=>_logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__.buildOtlpLogsPayload,
88
91
  getFeatureFlagValue: ()=>_featureFlagUtils__WEBPACK_IMPORTED_MODULE_0__.getFeatureFlagValue,
89
- getLengthFromRules: ()=>_surveys_validation__WEBPACK_IMPORTED_MODULE_11__.getLengthFromRules,
92
+ getLengthFromRules: ()=>_surveys_validation__WEBPACK_IMPORTED_MODULE_12__.getLengthFromRules,
90
93
  getOtlpSeverityNumber: ()=>_logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__.getOtlpSeverityNumber,
91
94
  getOtlpSeverityText: ()=>_logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__.getOtlpSeverityText,
92
- getRequirementsHint: ()=>_surveys_validation__WEBPACK_IMPORTED_MODULE_11__.getRequirementsHint,
93
- getValidationError: ()=>_surveys_validation__WEBPACK_IMPORTED_MODULE_11__.getValidationError,
95
+ getRequirementsHint: ()=>_surveys_validation__WEBPACK_IMPORTED_MODULE_12__.getRequirementsHint,
96
+ getValidationError: ()=>_surveys_validation__WEBPACK_IMPORTED_MODULE_12__.getValidationError,
94
97
  gzipCompress: ()=>_gzip__WEBPACK_IMPORTED_MODULE_1__.gzipCompress,
95
98
  isNativeAsyncGzipError: ()=>_gzip__WEBPACK_IMPORTED_MODULE_1__.isNativeAsyncGzipError,
96
99
  isNativeAsyncGzipReadError: ()=>_gzip__WEBPACK_IMPORTED_MODULE_1__.isNativeAsyncGzipReadError,
@@ -128,9 +131,33 @@ var __webpack_exports__ = {};
128
131
  var _logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__("./logs/logs-utils");
129
132
  var _logs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__("./logs");
130
133
  var _vendor_uuidv7__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__("./vendor/uuidv7");
131
- var _posthog_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__("./posthog-core");
134
+ var _cookie__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__("./cookie");
135
+ var __WEBPACK_REEXPORT_OBJECT__ = {};
136
+ for(var __WEBPACK_IMPORT_KEY__ in _cookie__WEBPACK_IMPORTED_MODULE_7__)if ([
137
+ "toOtlpKeyValueList",
138
+ "PostHogLogs",
139
+ "isNativeAsyncGzipError",
140
+ "getOtlpSeverityText",
141
+ "isNativeAsyncGzipReadError",
142
+ "getFeatureFlagValue",
143
+ "uuidv7",
144
+ "getValidationError",
145
+ "ErrorTracking",
146
+ "gzipCompress",
147
+ "default",
148
+ "getRequirementsHint",
149
+ "getOtlpSeverityNumber",
150
+ "getLengthFromRules",
151
+ "buildOtlpLogsPayload",
152
+ "buildOtlpLogRecord",
153
+ "toOtlpAnyValue"
154
+ ].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
155
+ return _cookie__WEBPACK_IMPORTED_MODULE_7__[key];
156
+ }).bind(0, __WEBPACK_IMPORT_KEY__);
157
+ __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
158
+ var _posthog_core__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__("./posthog-core");
132
159
  var __WEBPACK_REEXPORT_OBJECT__ = {};
133
- for(var __WEBPACK_IMPORT_KEY__ in _posthog_core__WEBPACK_IMPORTED_MODULE_7__)if ([
160
+ for(var __WEBPACK_IMPORT_KEY__ in _posthog_core__WEBPACK_IMPORTED_MODULE_8__)if ([
134
161
  "toOtlpKeyValueList",
135
162
  "PostHogLogs",
136
163
  "isNativeAsyncGzipError",
@@ -149,12 +176,12 @@ var __webpack_exports__ = {};
149
176
  "buildOtlpLogRecord",
150
177
  "toOtlpAnyValue"
151
178
  ].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
152
- return _posthog_core__WEBPACK_IMPORTED_MODULE_7__[key];
179
+ return _posthog_core__WEBPACK_IMPORTED_MODULE_8__[key];
153
180
  }).bind(0, __WEBPACK_IMPORT_KEY__);
154
181
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
155
- var _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__("./posthog-core-stateless");
182
+ var _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__("./posthog-core-stateless");
156
183
  var __WEBPACK_REEXPORT_OBJECT__ = {};
157
- for(var __WEBPACK_IMPORT_KEY__ in _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_8__)if ([
184
+ for(var __WEBPACK_IMPORT_KEY__ in _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_9__)if ([
158
185
  "toOtlpKeyValueList",
159
186
  "PostHogLogs",
160
187
  "isNativeAsyncGzipError",
@@ -173,12 +200,12 @@ var __webpack_exports__ = {};
173
200
  "buildOtlpLogRecord",
174
201
  "toOtlpAnyValue"
175
202
  ].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
176
- return _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_8__[key];
203
+ return _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_9__[key];
177
204
  }).bind(0, __WEBPACK_IMPORT_KEY__);
178
205
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
179
- var _tracing_headers__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__("./tracing-headers");
206
+ var _tracing_headers__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__("./tracing-headers");
180
207
  var __WEBPACK_REEXPORT_OBJECT__ = {};
181
- for(var __WEBPACK_IMPORT_KEY__ in _tracing_headers__WEBPACK_IMPORTED_MODULE_9__)if ([
208
+ for(var __WEBPACK_IMPORT_KEY__ in _tracing_headers__WEBPACK_IMPORTED_MODULE_10__)if ([
182
209
  "toOtlpKeyValueList",
183
210
  "PostHogLogs",
184
211
  "isNativeAsyncGzipError",
@@ -197,12 +224,12 @@ var __webpack_exports__ = {};
197
224
  "buildOtlpLogRecord",
198
225
  "toOtlpAnyValue"
199
226
  ].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
200
- return _tracing_headers__WEBPACK_IMPORTED_MODULE_9__[key];
227
+ return _tracing_headers__WEBPACK_IMPORTED_MODULE_10__[key];
201
228
  }).bind(0, __WEBPACK_IMPORT_KEY__);
202
229
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
203
- var _types__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__("./types");
230
+ var _types__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__("./types");
204
231
  var __WEBPACK_REEXPORT_OBJECT__ = {};
205
- for(var __WEBPACK_IMPORT_KEY__ in _types__WEBPACK_IMPORTED_MODULE_10__)if ([
232
+ for(var __WEBPACK_IMPORT_KEY__ in _types__WEBPACK_IMPORTED_MODULE_11__)if ([
206
233
  "toOtlpKeyValueList",
207
234
  "PostHogLogs",
208
235
  "isNativeAsyncGzipError",
@@ -221,10 +248,10 @@ var __webpack_exports__ = {};
221
248
  "buildOtlpLogRecord",
222
249
  "toOtlpAnyValue"
223
250
  ].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
224
- return _types__WEBPACK_IMPORTED_MODULE_10__[key];
251
+ return _types__WEBPACK_IMPORTED_MODULE_11__[key];
225
252
  }).bind(0, __WEBPACK_IMPORT_KEY__);
226
253
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
227
- var _surveys_validation__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__("./surveys/validation");
254
+ var _surveys_validation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__("./surveys/validation");
228
255
  })();
229
256
  exports.ErrorTracking = __webpack_exports__.ErrorTracking;
230
257
  exports.PostHogLogs = __webpack_exports__.PostHogLogs;
package/dist/index.mjs CHANGED
@@ -5,6 +5,7 @@ import { PostHogLogs } from "./logs/index.mjs";
5
5
  import { uuidv7 } from "./vendor/uuidv7.mjs";
6
6
  import { getLengthFromRules, getRequirementsHint, getValidationError } from "./surveys/validation.mjs";
7
7
  export * from "./utils/index.mjs";
8
+ export * from "./cookie.mjs";
8
9
  export * from "./posthog-core.mjs";
9
10
  export * from "./posthog-core-stateless.mjs";
10
11
  export * from "./tracing-headers.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/core",
3
- "version": "1.28.7",
3
+ "version": "1.29.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -67,7 +67,7 @@
67
67
  }
68
68
  },
69
69
  "dependencies": {
70
- "@posthog/types": "1.373.2"
70
+ "@posthog/types": "1.373.3"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@rslib/core": "0.10.6",
package/src/cookie.ts ADDED
@@ -0,0 +1,173 @@
1
+ import { isArray, isNoLike } from './utils'
2
+ import { uuidv7 } from './vendor/uuidv7'
3
+
4
+ const COOKIE_PREFIX = 'ph_'
5
+ const COOKIE_SUFFIX = '_posthog'
6
+
7
+ /**
8
+ * Minimal cookie-reading interface compatible with Next.js `cookies()`,
9
+ * `request.cookies`, and plain objects.
10
+ */
11
+ export interface CookieStore {
12
+ get(name: string): { value: string } | undefined
13
+ }
14
+
15
+ /**
16
+ * Adapts a raw `Cookie` header string into a {@link CookieStore}.
17
+ */
18
+ export function cookieStoreFromHeader(cookieHeader: string): CookieStore {
19
+ const cookies: Record<string, string> = {}
20
+ if (cookieHeader) {
21
+ for (const pair of cookieHeader.split(';')) {
22
+ const [key, ...valueParts] = pair.trim().split('=')
23
+ if (key) {
24
+ const raw = valueParts.join('=').trim()
25
+ // `decodeURIComponent` throws `URIError` on malformed sequences (e.g. `%gg`).
26
+ // The Cookie header is externally controlled, so fall back to the raw value
27
+ // rather than crashing the request handler.
28
+ try {
29
+ cookies[key.trim()] = decodeURIComponent(raw)
30
+ } catch {
31
+ cookies[key.trim()] = raw
32
+ }
33
+ }
34
+ }
35
+ }
36
+ return { get: (name: string) => (name in cookies ? { value: cookies[name] } : undefined) }
37
+ }
38
+
39
+ export interface PostHogCookieState {
40
+ distinctId: string
41
+ isIdentified: boolean
42
+ sessionId?: string
43
+ deviceId?: string
44
+ }
45
+
46
+ /**
47
+ * Returns the PostHog cookie name for the given API key.
48
+ *
49
+ * PostHog-js stores state in a cookie named `ph_<sanitized_token>_posthog`.
50
+ * The token is sanitized by replacing `+` with `PL`, `/` with `SL`, `=` with `EQ`.
51
+ *
52
+ * @param apiKey - The PostHog project API key
53
+ * @returns The cookie name string
54
+ */
55
+ export function getPostHogCookieName(apiKey: string): string {
56
+ const sanitized = apiKey.replace(/\+/g, 'PL').replace(/\//g, 'SL').replace(/=/g, 'EQ')
57
+ return `${COOKIE_PREFIX}${sanitized}${COOKIE_SUFFIX}`
58
+ }
59
+
60
+ /**
61
+ * Serializes an anonymous ID into the JSON format posthog-js expects.
62
+ *
63
+ * When `distinct_id === $device_id`, posthog-js treats the user as anonymous.
64
+ *
65
+ * @param anonymousId - The anonymous distinct ID to serialize
66
+ * @returns JSON string suitable for the PostHog cookie value
67
+ */
68
+ export function serializePostHogCookie(anonymousId: string): string {
69
+ const now = Date.now()
70
+ const sessionId = uuidv7()
71
+ return JSON.stringify({
72
+ distinct_id: anonymousId,
73
+ $device_id: anonymousId,
74
+ $user_state: 'anonymous',
75
+ $sesid: [now, sessionId, now],
76
+ })
77
+ }
78
+
79
+ /**
80
+ * Reads and parses the PostHog cookie from a cookie store.
81
+ *
82
+ * Compatible with Next.js `cookies()`, `request.cookies`, and any object
83
+ * with a `get(name)` method that returns `{ value: string } | undefined`.
84
+ */
85
+ export function readPostHogCookie(cookies: CookieStore, apiKey: string): PostHogCookieState | null {
86
+ const cookieName = getPostHogCookieName(apiKey)
87
+ const cookie = cookies.get(cookieName)
88
+ return cookie ? parsePostHogCookie(cookie.value) : null
89
+ }
90
+
91
+ /**
92
+ * Converts cookie state into PostHog properties (e.g. `$session_id`, `$device_id`).
93
+ */
94
+ export function cookieStateToProperties(state: PostHogCookieState | null): Record<string, string> | undefined {
95
+ if (!state) {
96
+ return undefined
97
+ }
98
+ const props: Record<string, string> = {}
99
+ if (state.sessionId) {
100
+ props.$session_id = state.sessionId
101
+ }
102
+ if (state.deviceId) {
103
+ props.$device_id = state.deviceId
104
+ }
105
+ return Object.keys(props).length > 0 ? props : undefined
106
+ }
107
+
108
+ /**
109
+ * Parses a PostHog cookie value and extracts identity information.
110
+ *
111
+ * The cookie value is a JSON object containing `distinct_id` and `$user_state`.
112
+ * A user is considered identified if `$user_state` is `'identified'`.
113
+ *
114
+ * @param cookieValue - The raw cookie string value
115
+ * @returns Parsed identity state, or null if the cookie is missing/invalid
116
+ */
117
+ export function parsePostHogCookie(cookieValue: string): PostHogCookieState | null {
118
+ if (!cookieValue) {
119
+ return null
120
+ }
121
+
122
+ try {
123
+ const parsed = JSON.parse(cookieValue)
124
+ if (!parsed || typeof parsed !== 'object' || !parsed.distinct_id) {
125
+ return null
126
+ }
127
+
128
+ // $sesid is stored as [lastActivityTimestamp, sessionId, sessionStartTimestamp]
129
+ const sesid = isArray(parsed.$sesid) ? parsed.$sesid[1] : undefined
130
+
131
+ return {
132
+ distinctId: String(parsed.distinct_id),
133
+ isIdentified: parsed.$user_state === 'identified',
134
+ sessionId: typeof sesid === 'string' ? sesid : undefined,
135
+ deviceId: typeof parsed.$device_id === 'string' ? parsed.$device_id : undefined,
136
+ }
137
+ } catch {
138
+ return null
139
+ }
140
+ }
141
+
142
+ export interface ConsentCookieConfig {
143
+ consent_persistence_name?: string | null
144
+ opt_out_capturing_cookie_prefix?: string | null
145
+ }
146
+
147
+ const CONSENT_PREFIX = '__ph_opt_in_out_'
148
+
149
+ export function getConsentCookieName(apiKey: string, config?: ConsentCookieConfig): string {
150
+ if (config?.consent_persistence_name) {
151
+ return config.consent_persistence_name
152
+ }
153
+ if (config?.opt_out_capturing_cookie_prefix) {
154
+ return config.opt_out_capturing_cookie_prefix + apiKey
155
+ }
156
+ return CONSENT_PREFIX + apiKey
157
+ }
158
+
159
+ export interface ConsentConfig extends ConsentCookieConfig {
160
+ opt_out_capturing_by_default?: boolean
161
+ }
162
+
163
+ export function isOptedOut(cookies: CookieStore, apiKey: string, config?: ConsentConfig): boolean {
164
+ const cookieName = getConsentCookieName(apiKey, config)
165
+ const cookie = cookies.get(cookieName)
166
+
167
+ if (cookie) {
168
+ return isNoLike(cookie.value)
169
+ }
170
+
171
+ // No consent cookie means pending — defer to config
172
+ return config?.opt_out_capturing_by_default ?? false
173
+ }
package/src/index.ts CHANGED
@@ -24,6 +24,7 @@ export type {
24
24
  // packages to type their `captureLog` calls.
25
25
  export type { CaptureLogOptions, LogAttributeValue, LogAttributes, LogSeverityLevel } from './logs/types'
26
26
  export { uuidv7 } from './vendor/uuidv7'
27
+ export * from './cookie'
27
28
  export * from './posthog-core'
28
29
  export * from './posthog-core-stateless'
29
30
  export * from './tracing-headers'