@posthog/core 1.28.6 → 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.
- package/dist/cookie.d.ts +69 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/cookie.js +137 -0
- package/dist/cookie.mjs +82 -0
- package/dist/gzip.d.ts +1 -0
- package/dist/gzip.d.ts.map +1 -1
- package/dist/gzip.js +43 -1
- package/dist/gzip.mjs +41 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -16
- package/dist/index.mjs +3 -2
- package/package.json +2 -2
- package/src/cookie.ts +173 -0
- package/src/gzip.ts +71 -1
- package/src/index.ts +2 -1
package/dist/cookie.d.ts
ADDED
|
@@ -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
|
+
});
|
package/dist/cookie.mjs
ADDED
|
@@ -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/gzip.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare function isGzipSupported(): boolean;
|
|
6
6
|
export declare const isNativeAsyncGzipReadError: (error: unknown) => boolean;
|
|
7
|
+
export declare const isNativeAsyncGzipError: (error: unknown) => boolean;
|
|
7
8
|
export type GzipCompressOptions = {
|
|
8
9
|
/**
|
|
9
10
|
* By default this helper swallows compression errors and returns null.
|
package/dist/gzip.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gzip.d.ts","sourceRoot":"","sources":["../src/gzip.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAOzC;
|
|
1
|
+
{"version":3,"file":"gzip.d.ts","sourceRoot":"","sources":["../src/gzip.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAOzC;AAID,eAAO,MAAM,0BAA0B,GAAI,OAAO,OAAO,KAAG,OAQ3D,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,OAQvD,CAAA;AA0DD,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,UAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAgCrH"}
|
package/dist/gzip.js
CHANGED
|
@@ -26,21 +26,60 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
gzipCompress: ()=>gzipCompress,
|
|
28
28
|
isGzipSupported: ()=>isGzipSupported,
|
|
29
|
+
isNativeAsyncGzipError: ()=>isNativeAsyncGzipError,
|
|
29
30
|
isNativeAsyncGzipReadError: ()=>isNativeAsyncGzipReadError
|
|
30
31
|
});
|
|
31
32
|
function isGzipSupported() {
|
|
32
33
|
return 'CompressionStream' in globalThis && 'TextEncoder' in globalThis && 'Response' in globalThis && 'function' == typeof Response.prototype.blob;
|
|
33
34
|
}
|
|
35
|
+
const NATIVE_GZIP_VALIDATION_ERROR = 'NativeGzipValidationError';
|
|
34
36
|
const isNativeAsyncGzipReadError = (error)=>{
|
|
35
37
|
if (!error || 'object' != typeof error) return false;
|
|
36
38
|
const name = 'name' in error ? String(error.name) : '';
|
|
37
39
|
return 'NotReadableError' === name;
|
|
38
40
|
};
|
|
41
|
+
const isNativeAsyncGzipError = (error)=>{
|
|
42
|
+
if (!error || 'object' != typeof error) return false;
|
|
43
|
+
const name = 'name' in error ? String(error.name) : '';
|
|
44
|
+
return isNativeAsyncGzipReadError(error) || name === NATIVE_GZIP_VALIDATION_ERROR;
|
|
45
|
+
};
|
|
46
|
+
let crc32Table;
|
|
47
|
+
const getCrc32Table = ()=>{
|
|
48
|
+
if (crc32Table) return crc32Table;
|
|
49
|
+
crc32Table = [];
|
|
50
|
+
for(let i = 0; i < 256; i++){
|
|
51
|
+
let crc = i;
|
|
52
|
+
for(let j = 0; j < 8; j++)crc = 1 & crc ? 0xedb88320 ^ crc >>> 1 : crc >>> 1;
|
|
53
|
+
crc32Table[i] = crc >>> 0;
|
|
54
|
+
}
|
|
55
|
+
return crc32Table;
|
|
56
|
+
};
|
|
57
|
+
const crc32 = (bytes)=>{
|
|
58
|
+
const table = getCrc32Table();
|
|
59
|
+
let crc = 0xffffffff;
|
|
60
|
+
for(let i = 0; i < bytes.length; i++)crc = table[(crc ^ bytes[i]) & 0xff] ^ crc >>> 8;
|
|
61
|
+
return (0xffffffff ^ crc) >>> 0;
|
|
62
|
+
};
|
|
63
|
+
const throwNativeGzipValidationError = (reason)=>{
|
|
64
|
+
const error = new Error(`Native gzip produced invalid output: ${reason}`);
|
|
65
|
+
error.name = NATIVE_GZIP_VALIDATION_ERROR;
|
|
66
|
+
throw error;
|
|
67
|
+
};
|
|
68
|
+
const validateNativeGzip = async (compressed, inputBytes)=>{
|
|
69
|
+
if (compressed.size < 18) throwNativeGzipValidationError('too-short');
|
|
70
|
+
const header = new Uint8Array(await compressed.slice(0, 10).arrayBuffer());
|
|
71
|
+
if (0x1f !== header[0] || 0x8b !== header[1] || 0x08 !== header[2]) throwNativeGzipValidationError('invalid-header');
|
|
72
|
+
const trailer = new DataView(await compressed.slice(compressed.size - 8).arrayBuffer());
|
|
73
|
+
if (trailer.getUint32(0, true) !== crc32(inputBytes)) throwNativeGzipValidationError('invalid-crc');
|
|
74
|
+
const inputSize = inputBytes.length >>> 0;
|
|
75
|
+
if (trailer.getUint32(4, true) !== inputSize) throwNativeGzipValidationError('invalid-size');
|
|
76
|
+
};
|
|
39
77
|
async function gzipCompress(input, isDebug = true, options) {
|
|
40
78
|
try {
|
|
79
|
+
const inputBytes = new TextEncoder().encode(input);
|
|
41
80
|
const compressedStream = new CompressionStream('gzip');
|
|
42
81
|
const writer = compressedStream.writable.getWriter();
|
|
43
|
-
const writePromise = writer.write(
|
|
82
|
+
const writePromise = writer.write(inputBytes).then(()=>writer.close()).catch(async (err)=>{
|
|
44
83
|
try {
|
|
45
84
|
await writer.abort(err);
|
|
46
85
|
} catch {}
|
|
@@ -51,6 +90,7 @@ async function gzipCompress(input, isDebug = true, options) {
|
|
|
51
90
|
responsePromise,
|
|
52
91
|
writePromise
|
|
53
92
|
]);
|
|
93
|
+
await validateNativeGzip(compressed, inputBytes);
|
|
54
94
|
return compressed;
|
|
55
95
|
} catch (error) {
|
|
56
96
|
if (options?.rethrow) throw error;
|
|
@@ -60,10 +100,12 @@ async function gzipCompress(input, isDebug = true, options) {
|
|
|
60
100
|
}
|
|
61
101
|
exports.gzipCompress = __webpack_exports__.gzipCompress;
|
|
62
102
|
exports.isGzipSupported = __webpack_exports__.isGzipSupported;
|
|
103
|
+
exports.isNativeAsyncGzipError = __webpack_exports__.isNativeAsyncGzipError;
|
|
63
104
|
exports.isNativeAsyncGzipReadError = __webpack_exports__.isNativeAsyncGzipReadError;
|
|
64
105
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
65
106
|
"gzipCompress",
|
|
66
107
|
"isGzipSupported",
|
|
108
|
+
"isNativeAsyncGzipError",
|
|
67
109
|
"isNativeAsyncGzipReadError"
|
|
68
110
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
69
111
|
Object.defineProperty(exports, '__esModule', {
|
package/dist/gzip.mjs
CHANGED
|
@@ -1,16 +1,54 @@
|
|
|
1
1
|
function isGzipSupported() {
|
|
2
2
|
return 'CompressionStream' in globalThis && 'TextEncoder' in globalThis && 'Response' in globalThis && 'function' == typeof Response.prototype.blob;
|
|
3
3
|
}
|
|
4
|
+
const NATIVE_GZIP_VALIDATION_ERROR = 'NativeGzipValidationError';
|
|
4
5
|
const isNativeAsyncGzipReadError = (error)=>{
|
|
5
6
|
if (!error || 'object' != typeof error) return false;
|
|
6
7
|
const name = 'name' in error ? String(error.name) : '';
|
|
7
8
|
return 'NotReadableError' === name;
|
|
8
9
|
};
|
|
10
|
+
const isNativeAsyncGzipError = (error)=>{
|
|
11
|
+
if (!error || 'object' != typeof error) return false;
|
|
12
|
+
const name = 'name' in error ? String(error.name) : '';
|
|
13
|
+
return isNativeAsyncGzipReadError(error) || name === NATIVE_GZIP_VALIDATION_ERROR;
|
|
14
|
+
};
|
|
15
|
+
let crc32Table;
|
|
16
|
+
const getCrc32Table = ()=>{
|
|
17
|
+
if (crc32Table) return crc32Table;
|
|
18
|
+
crc32Table = [];
|
|
19
|
+
for(let i = 0; i < 256; i++){
|
|
20
|
+
let crc = i;
|
|
21
|
+
for(let j = 0; j < 8; j++)crc = 1 & crc ? 0xedb88320 ^ crc >>> 1 : crc >>> 1;
|
|
22
|
+
crc32Table[i] = crc >>> 0;
|
|
23
|
+
}
|
|
24
|
+
return crc32Table;
|
|
25
|
+
};
|
|
26
|
+
const crc32 = (bytes)=>{
|
|
27
|
+
const table = getCrc32Table();
|
|
28
|
+
let crc = 0xffffffff;
|
|
29
|
+
for(let i = 0; i < bytes.length; i++)crc = table[(crc ^ bytes[i]) & 0xff] ^ crc >>> 8;
|
|
30
|
+
return (0xffffffff ^ crc) >>> 0;
|
|
31
|
+
};
|
|
32
|
+
const throwNativeGzipValidationError = (reason)=>{
|
|
33
|
+
const error = new Error(`Native gzip produced invalid output: ${reason}`);
|
|
34
|
+
error.name = NATIVE_GZIP_VALIDATION_ERROR;
|
|
35
|
+
throw error;
|
|
36
|
+
};
|
|
37
|
+
const validateNativeGzip = async (compressed, inputBytes)=>{
|
|
38
|
+
if (compressed.size < 18) throwNativeGzipValidationError('too-short');
|
|
39
|
+
const header = new Uint8Array(await compressed.slice(0, 10).arrayBuffer());
|
|
40
|
+
if (0x1f !== header[0] || 0x8b !== header[1] || 0x08 !== header[2]) throwNativeGzipValidationError('invalid-header');
|
|
41
|
+
const trailer = new DataView(await compressed.slice(compressed.size - 8).arrayBuffer());
|
|
42
|
+
if (trailer.getUint32(0, true) !== crc32(inputBytes)) throwNativeGzipValidationError('invalid-crc');
|
|
43
|
+
const inputSize = inputBytes.length >>> 0;
|
|
44
|
+
if (trailer.getUint32(4, true) !== inputSize) throwNativeGzipValidationError('invalid-size');
|
|
45
|
+
};
|
|
9
46
|
async function gzipCompress(input, isDebug = true, options) {
|
|
10
47
|
try {
|
|
48
|
+
const inputBytes = new TextEncoder().encode(input);
|
|
11
49
|
const compressedStream = new CompressionStream('gzip');
|
|
12
50
|
const writer = compressedStream.writable.getWriter();
|
|
13
|
-
const writePromise = writer.write(
|
|
51
|
+
const writePromise = writer.write(inputBytes).then(()=>writer.close()).catch(async (err)=>{
|
|
14
52
|
try {
|
|
15
53
|
await writer.abort(err);
|
|
16
54
|
} catch {}
|
|
@@ -21,6 +59,7 @@ async function gzipCompress(input, isDebug = true, options) {
|
|
|
21
59
|
responsePromise,
|
|
22
60
|
writePromise
|
|
23
61
|
]);
|
|
62
|
+
await validateNativeGzip(compressed, inputBytes);
|
|
24
63
|
return compressed;
|
|
25
64
|
} catch (error) {
|
|
26
65
|
if (options?.rethrow) throw error;
|
|
@@ -28,4 +67,4 @@ async function gzipCompress(input, isDebug = true, options) {
|
|
|
28
67
|
return null;
|
|
29
68
|
}
|
|
30
69
|
}
|
|
31
|
-
export { gzipCompress, isGzipSupported, isNativeAsyncGzipReadError };
|
|
70
|
+
export { gzipCompress, isGzipSupported, isNativeAsyncGzipError, isNativeAsyncGzipReadError };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { getFeatureFlagValue } from './featureFlagUtils';
|
|
2
|
-
export { gzipCompress, isNativeAsyncGzipReadError } from './gzip';
|
|
2
|
+
export { gzipCompress, isNativeAsyncGzipError, isNativeAsyncGzipReadError } from './gzip';
|
|
3
3
|
export * from './utils';
|
|
4
4
|
export * as ErrorTracking from './error-tracking';
|
|
5
5
|
export { buildOtlpLogRecord, buildOtlpLogsPayload, getOtlpSeverityNumber, getOtlpSeverityText, toOtlpAnyValue, toOtlpKeyValueList, } from './logs/logs-utils';
|
|
@@ -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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,0BAA0B,EAAE,MAAM,QAAQ,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,12 +89,13 @@ 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: ()=>
|
|
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: ()=>
|
|
93
|
-
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,
|
|
98
|
+
isNativeAsyncGzipError: ()=>_gzip__WEBPACK_IMPORTED_MODULE_1__.isNativeAsyncGzipError,
|
|
95
99
|
isNativeAsyncGzipReadError: ()=>_gzip__WEBPACK_IMPORTED_MODULE_1__.isNativeAsyncGzipReadError,
|
|
96
100
|
toOtlpAnyValue: ()=>_logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__.toOtlpAnyValue,
|
|
97
101
|
toOtlpKeyValueList: ()=>_logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__.toOtlpKeyValueList,
|
|
@@ -104,6 +108,7 @@ var __webpack_exports__ = {};
|
|
|
104
108
|
for(var __WEBPACK_IMPORT_KEY__ in _utils__WEBPACK_IMPORTED_MODULE_2__)if ([
|
|
105
109
|
"toOtlpKeyValueList",
|
|
106
110
|
"PostHogLogs",
|
|
111
|
+
"isNativeAsyncGzipError",
|
|
107
112
|
"getOtlpSeverityText",
|
|
108
113
|
"isNativeAsyncGzipReadError",
|
|
109
114
|
"getFeatureFlagValue",
|
|
@@ -126,11 +131,36 @@ var __webpack_exports__ = {};
|
|
|
126
131
|
var _logs_logs_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__("./logs/logs-utils");
|
|
127
132
|
var _logs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__("./logs");
|
|
128
133
|
var _vendor_uuidv7__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__("./vendor/uuidv7");
|
|
129
|
-
var
|
|
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");
|
|
130
159
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
131
|
-
for(var __WEBPACK_IMPORT_KEY__ in
|
|
160
|
+
for(var __WEBPACK_IMPORT_KEY__ in _posthog_core__WEBPACK_IMPORTED_MODULE_8__)if ([
|
|
132
161
|
"toOtlpKeyValueList",
|
|
133
162
|
"PostHogLogs",
|
|
163
|
+
"isNativeAsyncGzipError",
|
|
134
164
|
"getOtlpSeverityText",
|
|
135
165
|
"isNativeAsyncGzipReadError",
|
|
136
166
|
"getFeatureFlagValue",
|
|
@@ -146,14 +176,15 @@ var __webpack_exports__ = {};
|
|
|
146
176
|
"buildOtlpLogRecord",
|
|
147
177
|
"toOtlpAnyValue"
|
|
148
178
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
149
|
-
return
|
|
179
|
+
return _posthog_core__WEBPACK_IMPORTED_MODULE_8__[key];
|
|
150
180
|
}).bind(0, __WEBPACK_IMPORT_KEY__);
|
|
151
181
|
__webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
|
|
152
|
-
var
|
|
182
|
+
var _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__("./posthog-core-stateless");
|
|
153
183
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
154
|
-
for(var __WEBPACK_IMPORT_KEY__ in
|
|
184
|
+
for(var __WEBPACK_IMPORT_KEY__ in _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_9__)if ([
|
|
155
185
|
"toOtlpKeyValueList",
|
|
156
186
|
"PostHogLogs",
|
|
187
|
+
"isNativeAsyncGzipError",
|
|
157
188
|
"getOtlpSeverityText",
|
|
158
189
|
"isNativeAsyncGzipReadError",
|
|
159
190
|
"getFeatureFlagValue",
|
|
@@ -169,14 +200,15 @@ var __webpack_exports__ = {};
|
|
|
169
200
|
"buildOtlpLogRecord",
|
|
170
201
|
"toOtlpAnyValue"
|
|
171
202
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
172
|
-
return
|
|
203
|
+
return _posthog_core_stateless__WEBPACK_IMPORTED_MODULE_9__[key];
|
|
173
204
|
}).bind(0, __WEBPACK_IMPORT_KEY__);
|
|
174
205
|
__webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
|
|
175
|
-
var
|
|
206
|
+
var _tracing_headers__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__("./tracing-headers");
|
|
176
207
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
177
|
-
for(var __WEBPACK_IMPORT_KEY__ in
|
|
208
|
+
for(var __WEBPACK_IMPORT_KEY__ in _tracing_headers__WEBPACK_IMPORTED_MODULE_10__)if ([
|
|
178
209
|
"toOtlpKeyValueList",
|
|
179
210
|
"PostHogLogs",
|
|
211
|
+
"isNativeAsyncGzipError",
|
|
180
212
|
"getOtlpSeverityText",
|
|
181
213
|
"isNativeAsyncGzipReadError",
|
|
182
214
|
"getFeatureFlagValue",
|
|
@@ -192,14 +224,15 @@ var __webpack_exports__ = {};
|
|
|
192
224
|
"buildOtlpLogRecord",
|
|
193
225
|
"toOtlpAnyValue"
|
|
194
226
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
195
|
-
return
|
|
227
|
+
return _tracing_headers__WEBPACK_IMPORTED_MODULE_10__[key];
|
|
196
228
|
}).bind(0, __WEBPACK_IMPORT_KEY__);
|
|
197
229
|
__webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
|
|
198
|
-
var
|
|
230
|
+
var _types__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__("./types");
|
|
199
231
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
200
|
-
for(var __WEBPACK_IMPORT_KEY__ in
|
|
232
|
+
for(var __WEBPACK_IMPORT_KEY__ in _types__WEBPACK_IMPORTED_MODULE_11__)if ([
|
|
201
233
|
"toOtlpKeyValueList",
|
|
202
234
|
"PostHogLogs",
|
|
235
|
+
"isNativeAsyncGzipError",
|
|
203
236
|
"getOtlpSeverityText",
|
|
204
237
|
"isNativeAsyncGzipReadError",
|
|
205
238
|
"getFeatureFlagValue",
|
|
@@ -215,10 +248,10 @@ var __webpack_exports__ = {};
|
|
|
215
248
|
"buildOtlpLogRecord",
|
|
216
249
|
"toOtlpAnyValue"
|
|
217
250
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
218
|
-
return
|
|
251
|
+
return _types__WEBPACK_IMPORTED_MODULE_11__[key];
|
|
219
252
|
}).bind(0, __WEBPACK_IMPORT_KEY__);
|
|
220
253
|
__webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
|
|
221
|
-
var
|
|
254
|
+
var _surveys_validation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__("./surveys/validation");
|
|
222
255
|
})();
|
|
223
256
|
exports.ErrorTracking = __webpack_exports__.ErrorTracking;
|
|
224
257
|
exports.PostHogLogs = __webpack_exports__.PostHogLogs;
|
|
@@ -231,6 +264,7 @@ exports.getOtlpSeverityText = __webpack_exports__.getOtlpSeverityText;
|
|
|
231
264
|
exports.getRequirementsHint = __webpack_exports__.getRequirementsHint;
|
|
232
265
|
exports.getValidationError = __webpack_exports__.getValidationError;
|
|
233
266
|
exports.gzipCompress = __webpack_exports__.gzipCompress;
|
|
267
|
+
exports.isNativeAsyncGzipError = __webpack_exports__.isNativeAsyncGzipError;
|
|
234
268
|
exports.isNativeAsyncGzipReadError = __webpack_exports__.isNativeAsyncGzipReadError;
|
|
235
269
|
exports.toOtlpAnyValue = __webpack_exports__.toOtlpAnyValue;
|
|
236
270
|
exports.toOtlpKeyValueList = __webpack_exports__.toOtlpKeyValueList;
|
|
@@ -247,6 +281,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
|
247
281
|
"getRequirementsHint",
|
|
248
282
|
"getValidationError",
|
|
249
283
|
"gzipCompress",
|
|
284
|
+
"isNativeAsyncGzipError",
|
|
250
285
|
"isNativeAsyncGzipReadError",
|
|
251
286
|
"toOtlpAnyValue",
|
|
252
287
|
"toOtlpKeyValueList",
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { getFeatureFlagValue } from "./featureFlagUtils.mjs";
|
|
2
|
-
import { gzipCompress, isNativeAsyncGzipReadError } from "./gzip.mjs";
|
|
2
|
+
import { gzipCompress, isNativeAsyncGzipError, isNativeAsyncGzipReadError } from "./gzip.mjs";
|
|
3
3
|
import { buildOtlpLogRecord, buildOtlpLogsPayload, getOtlpSeverityNumber, getOtlpSeverityText, toOtlpAnyValue, toOtlpKeyValueList } from "./logs/logs-utils.mjs";
|
|
4
4
|
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";
|
|
11
12
|
export * from "./types.mjs";
|
|
12
13
|
import * as __WEBPACK_EXTERNAL_MODULE__error_tracking_index_mjs_b3406d6f__ from "./error-tracking/index.mjs";
|
|
13
|
-
export { __WEBPACK_EXTERNAL_MODULE__error_tracking_index_mjs_b3406d6f__ as ErrorTracking, PostHogLogs, buildOtlpLogRecord, buildOtlpLogsPayload, getFeatureFlagValue, getLengthFromRules, getOtlpSeverityNumber, getOtlpSeverityText, getRequirementsHint, getValidationError, gzipCompress, isNativeAsyncGzipReadError, toOtlpAnyValue, toOtlpKeyValueList, uuidv7 };
|
|
14
|
+
export { __WEBPACK_EXTERNAL_MODULE__error_tracking_index_mjs_b3406d6f__ as ErrorTracking, PostHogLogs, buildOtlpLogRecord, buildOtlpLogsPayload, getFeatureFlagValue, getLengthFromRules, getOtlpSeverityNumber, getOtlpSeverityText, getRequirementsHint, getValidationError, gzipCompress, isNativeAsyncGzipError, isNativeAsyncGzipReadError, toOtlpAnyValue, toOtlpKeyValueList, uuidv7 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/core",
|
|
3
|
-
"version": "1.
|
|
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.
|
|
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/gzip.ts
CHANGED
|
@@ -11,6 +11,8 @@ export function isGzipSupported(): boolean {
|
|
|
11
11
|
)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const NATIVE_GZIP_VALIDATION_ERROR = 'NativeGzipValidationError'
|
|
15
|
+
|
|
14
16
|
export const isNativeAsyncGzipReadError = (error: unknown): boolean => {
|
|
15
17
|
if (!error || typeof error !== 'object') {
|
|
16
18
|
return false
|
|
@@ -21,6 +23,72 @@ export const isNativeAsyncGzipReadError = (error: unknown): boolean => {
|
|
|
21
23
|
return name === 'NotReadableError'
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
export const isNativeAsyncGzipError = (error: unknown): boolean => {
|
|
27
|
+
if (!error || typeof error !== 'object') {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const name = 'name' in error ? String(error.name) : ''
|
|
32
|
+
|
|
33
|
+
return isNativeAsyncGzipReadError(error) || name === NATIVE_GZIP_VALIDATION_ERROR
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type NativeGzipValidationReason = 'too-short' | 'invalid-header' | 'invalid-crc' | 'invalid-size'
|
|
37
|
+
|
|
38
|
+
let crc32Table: number[] | undefined
|
|
39
|
+
|
|
40
|
+
const getCrc32Table = (): number[] => {
|
|
41
|
+
if (crc32Table) {
|
|
42
|
+
return crc32Table
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
crc32Table = []
|
|
46
|
+
for (let i = 0; i < 256; i++) {
|
|
47
|
+
let crc = i
|
|
48
|
+
for (let j = 0; j < 8; j++) {
|
|
49
|
+
crc = crc & 1 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1
|
|
50
|
+
}
|
|
51
|
+
crc32Table[i] = crc >>> 0
|
|
52
|
+
}
|
|
53
|
+
return crc32Table
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const crc32 = (bytes: Uint8Array): number => {
|
|
57
|
+
const table = getCrc32Table()
|
|
58
|
+
let crc = 0xffffffff
|
|
59
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
60
|
+
crc = table[(crc ^ bytes[i]) & 0xff] ^ (crc >>> 8)
|
|
61
|
+
}
|
|
62
|
+
return (crc ^ 0xffffffff) >>> 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const throwNativeGzipValidationError = (reason: NativeGzipValidationReason): never => {
|
|
66
|
+
const error = new Error(`Native gzip produced invalid output: ${reason}`)
|
|
67
|
+
error.name = NATIVE_GZIP_VALIDATION_ERROR
|
|
68
|
+
throw error
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const validateNativeGzip = async (compressed: Blob, inputBytes: Uint8Array): Promise<void> => {
|
|
72
|
+
if (compressed.size < 18) {
|
|
73
|
+
throwNativeGzipValidationError('too-short')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const header = new Uint8Array(await compressed.slice(0, 10).arrayBuffer())
|
|
77
|
+
if (header[0] !== 0x1f || header[1] !== 0x8b || header[2] !== 0x08) {
|
|
78
|
+
throwNativeGzipValidationError('invalid-header')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const trailer = new DataView(await compressed.slice(compressed.size - 8).arrayBuffer())
|
|
82
|
+
if (trailer.getUint32(0, true) !== crc32(inputBytes)) {
|
|
83
|
+
throwNativeGzipValidationError('invalid-crc')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const inputSize = inputBytes.length >>> 0
|
|
87
|
+
if (trailer.getUint32(4, true) !== inputSize) {
|
|
88
|
+
throwNativeGzipValidationError('invalid-size')
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
24
92
|
export type GzipCompressOptions = {
|
|
25
93
|
/**
|
|
26
94
|
* By default this helper swallows compression errors and returns null.
|
|
@@ -36,11 +104,12 @@ export type GzipCompressOptions = {
|
|
|
36
104
|
*/
|
|
37
105
|
export async function gzipCompress(input: string, isDebug = true, options?: GzipCompressOptions): Promise<Blob | null> {
|
|
38
106
|
try {
|
|
107
|
+
const inputBytes = new TextEncoder().encode(input)
|
|
39
108
|
const compressedStream = new CompressionStream('gzip')
|
|
40
109
|
const writer = compressedStream.writable.getWriter()
|
|
41
110
|
|
|
42
111
|
const writePromise = writer
|
|
43
|
-
.write(
|
|
112
|
+
.write(inputBytes)
|
|
44
113
|
.then(() => writer.close())
|
|
45
114
|
.catch(async (err) => {
|
|
46
115
|
try {
|
|
@@ -53,6 +122,7 @@ export async function gzipCompress(input: string, isDebug = true, options?: Gzip
|
|
|
53
122
|
const responsePromise = new Response(compressedStream.readable).blob()
|
|
54
123
|
|
|
55
124
|
const [compressed] = await Promise.all([responsePromise, writePromise])
|
|
125
|
+
await validateNativeGzip(compressed, inputBytes)
|
|
56
126
|
return compressed
|
|
57
127
|
} catch (error) {
|
|
58
128
|
if (options?.rethrow) {
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { getFeatureFlagValue } from './featureFlagUtils'
|
|
2
|
-
export { gzipCompress, isNativeAsyncGzipReadError } from './gzip'
|
|
2
|
+
export { gzipCompress, isNativeAsyncGzipError, isNativeAsyncGzipReadError } from './gzip'
|
|
3
3
|
export * from './utils'
|
|
4
4
|
export * as ErrorTracking from './error-tracking'
|
|
5
5
|
export {
|
|
@@ -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'
|