@posthog/core 1.8.0 → 1.9.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/posthog-core-stateless.d.ts.map +1 -1
- package/dist/posthog-core-stateless.js +2 -1
- package/dist/posthog-core-stateless.mjs +2 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +22 -0
- package/dist/utils/index.mjs +1 -0
- package/dist/utils/user-agent-utils.d.ts +19 -0
- package/dist/utils/user-agent-utils.d.ts.map +1 -0
- package/dist/utils/user-agent-utils.js +384 -0
- package/dist/utils/user-agent-utils.mjs +338 -0
- package/package.json +1 -1
- package/src/posthog-core-stateless.ts +1 -0
- package/src/types.ts +5 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/user-agent-utils.ts +358 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { includes } from "./string-utils.mjs";
|
|
2
|
+
import { isFunction, isUndefined } from "./type-utils.mjs";
|
|
3
|
+
const FACEBOOK = 'Facebook';
|
|
4
|
+
const MOBILE = 'Mobile';
|
|
5
|
+
const IOS = 'iOS';
|
|
6
|
+
const ANDROID = 'Android';
|
|
7
|
+
const TABLET = 'Tablet';
|
|
8
|
+
const ANDROID_TABLET = ANDROID + ' ' + TABLET;
|
|
9
|
+
const IPAD = 'iPad';
|
|
10
|
+
const APPLE = 'Apple';
|
|
11
|
+
const APPLE_WATCH = APPLE + ' Watch';
|
|
12
|
+
const SAFARI = 'Safari';
|
|
13
|
+
const BLACKBERRY = 'BlackBerry';
|
|
14
|
+
const SAMSUNG = 'Samsung';
|
|
15
|
+
const SAMSUNG_BROWSER = SAMSUNG + 'Browser';
|
|
16
|
+
const SAMSUNG_INTERNET = SAMSUNG + ' Internet';
|
|
17
|
+
const CHROME = 'Chrome';
|
|
18
|
+
const CHROME_OS = CHROME + ' OS';
|
|
19
|
+
const CHROME_IOS = CHROME + ' ' + IOS;
|
|
20
|
+
const INTERNET_EXPLORER = 'Internet Explorer';
|
|
21
|
+
const INTERNET_EXPLORER_MOBILE = INTERNET_EXPLORER + ' ' + MOBILE;
|
|
22
|
+
const OPERA = 'Opera';
|
|
23
|
+
const OPERA_MINI = OPERA + ' Mini';
|
|
24
|
+
const EDGE = 'Edge';
|
|
25
|
+
const MICROSOFT_EDGE = 'Microsoft ' + EDGE;
|
|
26
|
+
const FIREFOX = 'Firefox';
|
|
27
|
+
const FIREFOX_IOS = FIREFOX + ' ' + IOS;
|
|
28
|
+
const NINTENDO = 'Nintendo';
|
|
29
|
+
const PLAYSTATION = 'PlayStation';
|
|
30
|
+
const XBOX = 'Xbox';
|
|
31
|
+
const ANDROID_MOBILE = ANDROID + ' ' + MOBILE;
|
|
32
|
+
const MOBILE_SAFARI = MOBILE + ' ' + SAFARI;
|
|
33
|
+
const WINDOWS = 'Windows';
|
|
34
|
+
const WINDOWS_PHONE = WINDOWS + ' Phone';
|
|
35
|
+
const NOKIA = 'Nokia';
|
|
36
|
+
const OUYA = 'Ouya';
|
|
37
|
+
const GENERIC = 'Generic';
|
|
38
|
+
const GENERIC_MOBILE = GENERIC + ' ' + MOBILE.toLowerCase();
|
|
39
|
+
const GENERIC_TABLET = GENERIC + ' ' + TABLET.toLowerCase();
|
|
40
|
+
const KONQUEROR = 'Konqueror';
|
|
41
|
+
const BROWSER_VERSION_REGEX_SUFFIX = '(\\d+(\\.\\d+)?)';
|
|
42
|
+
const DEFAULT_BROWSER_VERSION_REGEX = new RegExp('Version/' + BROWSER_VERSION_REGEX_SUFFIX);
|
|
43
|
+
const XBOX_REGEX = new RegExp(XBOX, 'i');
|
|
44
|
+
const PLAYSTATION_REGEX = new RegExp(PLAYSTATION + ' \\w+', 'i');
|
|
45
|
+
const NINTENDO_REGEX = new RegExp(NINTENDO + ' \\w+', 'i');
|
|
46
|
+
const BLACKBERRY_REGEX = new RegExp(BLACKBERRY + '|PlayBook|BB10', 'i');
|
|
47
|
+
const windowsVersionMap = {
|
|
48
|
+
'NT3.51': 'NT 3.11',
|
|
49
|
+
'NT4.0': 'NT 4.0',
|
|
50
|
+
'5.0': '2000',
|
|
51
|
+
'5.1': 'XP',
|
|
52
|
+
'5.2': 'XP',
|
|
53
|
+
'6.0': 'Vista',
|
|
54
|
+
'6.1': '7',
|
|
55
|
+
'6.2': '8',
|
|
56
|
+
'6.3': '8.1',
|
|
57
|
+
'6.4': '10',
|
|
58
|
+
'10.0': '10'
|
|
59
|
+
};
|
|
60
|
+
function isSafari(userAgent) {
|
|
61
|
+
return includes(userAgent, SAFARI) && !includes(userAgent, CHROME) && !includes(userAgent, ANDROID);
|
|
62
|
+
}
|
|
63
|
+
const safariCheck = (ua, vendor)=>vendor && includes(vendor, APPLE) || isSafari(ua);
|
|
64
|
+
const detectBrowser = function(user_agent, vendor) {
|
|
65
|
+
vendor = vendor || '';
|
|
66
|
+
if (includes(user_agent, ' OPR/') && includes(user_agent, 'Mini')) return OPERA_MINI;
|
|
67
|
+
if (includes(user_agent, ' OPR/')) return OPERA;
|
|
68
|
+
if (BLACKBERRY_REGEX.test(user_agent)) return BLACKBERRY;
|
|
69
|
+
if (includes(user_agent, 'IE' + MOBILE) || includes(user_agent, 'WPDesktop')) return INTERNET_EXPLORER_MOBILE;
|
|
70
|
+
if (includes(user_agent, SAMSUNG_BROWSER)) return SAMSUNG_INTERNET;
|
|
71
|
+
else if (includes(user_agent, EDGE) || includes(user_agent, 'Edg/')) return MICROSOFT_EDGE;
|
|
72
|
+
else if (includes(user_agent, 'FBIOS')) return FACEBOOK + ' ' + MOBILE;
|
|
73
|
+
else if (includes(user_agent, 'UCWEB') || includes(user_agent, 'UCBrowser')) return 'UC Browser';
|
|
74
|
+
else if (includes(user_agent, 'CriOS')) return CHROME_IOS;
|
|
75
|
+
else if (includes(user_agent, 'CrMo')) return CHROME;
|
|
76
|
+
else if (includes(user_agent, CHROME)) return CHROME;
|
|
77
|
+
else if (includes(user_agent, ANDROID) && includes(user_agent, SAFARI)) return ANDROID_MOBILE;
|
|
78
|
+
else if (includes(user_agent, 'FxiOS')) return FIREFOX_IOS;
|
|
79
|
+
else if (includes(user_agent.toLowerCase(), KONQUEROR.toLowerCase())) return KONQUEROR;
|
|
80
|
+
else if (safariCheck(user_agent, vendor)) return includes(user_agent, MOBILE) ? MOBILE_SAFARI : SAFARI;
|
|
81
|
+
else if (includes(user_agent, FIREFOX)) return FIREFOX;
|
|
82
|
+
else if (includes(user_agent, 'MSIE') || includes(user_agent, 'Trident/')) return INTERNET_EXPLORER;
|
|
83
|
+
else if (includes(user_agent, 'Gecko')) return FIREFOX;
|
|
84
|
+
return '';
|
|
85
|
+
};
|
|
86
|
+
const versionRegexes = {
|
|
87
|
+
[INTERNET_EXPLORER_MOBILE]: [
|
|
88
|
+
new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
89
|
+
],
|
|
90
|
+
[MICROSOFT_EDGE]: [
|
|
91
|
+
new RegExp(EDGE + '?\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
92
|
+
],
|
|
93
|
+
[CHROME]: [
|
|
94
|
+
new RegExp('(' + CHROME + '|CrMo)\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
95
|
+
],
|
|
96
|
+
[CHROME_IOS]: [
|
|
97
|
+
new RegExp('CriOS\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
98
|
+
],
|
|
99
|
+
'UC Browser': [
|
|
100
|
+
new RegExp('(UCBrowser|UCWEB)\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
101
|
+
],
|
|
102
|
+
[SAFARI]: [
|
|
103
|
+
DEFAULT_BROWSER_VERSION_REGEX
|
|
104
|
+
],
|
|
105
|
+
[MOBILE_SAFARI]: [
|
|
106
|
+
DEFAULT_BROWSER_VERSION_REGEX
|
|
107
|
+
],
|
|
108
|
+
[OPERA]: [
|
|
109
|
+
new RegExp('(' + OPERA + '|OPR)\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
110
|
+
],
|
|
111
|
+
[FIREFOX]: [
|
|
112
|
+
new RegExp(FIREFOX + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
113
|
+
],
|
|
114
|
+
[FIREFOX_IOS]: [
|
|
115
|
+
new RegExp('FxiOS\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
116
|
+
],
|
|
117
|
+
[KONQUEROR]: [
|
|
118
|
+
new RegExp('Konqueror[:/]?' + BROWSER_VERSION_REGEX_SUFFIX, 'i')
|
|
119
|
+
],
|
|
120
|
+
[BLACKBERRY]: [
|
|
121
|
+
new RegExp(BLACKBERRY + ' ' + BROWSER_VERSION_REGEX_SUFFIX),
|
|
122
|
+
DEFAULT_BROWSER_VERSION_REGEX
|
|
123
|
+
],
|
|
124
|
+
[ANDROID_MOBILE]: [
|
|
125
|
+
new RegExp('android\\s' + BROWSER_VERSION_REGEX_SUFFIX, 'i')
|
|
126
|
+
],
|
|
127
|
+
[SAMSUNG_INTERNET]: [
|
|
128
|
+
new RegExp(SAMSUNG_BROWSER + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
129
|
+
],
|
|
130
|
+
[INTERNET_EXPLORER]: [
|
|
131
|
+
new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
132
|
+
],
|
|
133
|
+
Mozilla: [
|
|
134
|
+
new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
const detectBrowserVersion = function(userAgent, vendor) {
|
|
138
|
+
const browser = detectBrowser(userAgent, vendor);
|
|
139
|
+
const regexes = versionRegexes[browser];
|
|
140
|
+
if (isUndefined(regexes)) return null;
|
|
141
|
+
for(let i = 0; i < regexes.length; i++){
|
|
142
|
+
const regex = regexes[i];
|
|
143
|
+
const matches = userAgent.match(regex);
|
|
144
|
+
if (matches) return parseFloat(matches[matches.length - 2]);
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
};
|
|
148
|
+
const osMatchers = [
|
|
149
|
+
[
|
|
150
|
+
new RegExp(XBOX + '; ' + XBOX + ' (.*?)[);]', 'i'),
|
|
151
|
+
(match)=>[
|
|
152
|
+
XBOX,
|
|
153
|
+
match && match[1] || ''
|
|
154
|
+
]
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
new RegExp(NINTENDO, 'i'),
|
|
158
|
+
[
|
|
159
|
+
NINTENDO,
|
|
160
|
+
''
|
|
161
|
+
]
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
new RegExp(PLAYSTATION, 'i'),
|
|
165
|
+
[
|
|
166
|
+
PLAYSTATION,
|
|
167
|
+
''
|
|
168
|
+
]
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
BLACKBERRY_REGEX,
|
|
172
|
+
[
|
|
173
|
+
BLACKBERRY,
|
|
174
|
+
''
|
|
175
|
+
]
|
|
176
|
+
],
|
|
177
|
+
[
|
|
178
|
+
new RegExp(WINDOWS, 'i'),
|
|
179
|
+
(_, user_agent)=>{
|
|
180
|
+
if (/Phone/.test(user_agent) || /WPDesktop/.test(user_agent)) return [
|
|
181
|
+
WINDOWS_PHONE,
|
|
182
|
+
''
|
|
183
|
+
];
|
|
184
|
+
if (new RegExp(MOBILE).test(user_agent) && !/IEMobile\b/.test(user_agent)) return [
|
|
185
|
+
WINDOWS + ' ' + MOBILE,
|
|
186
|
+
''
|
|
187
|
+
];
|
|
188
|
+
const match = /Windows NT ([0-9.]+)/i.exec(user_agent);
|
|
189
|
+
if (match && match[1]) {
|
|
190
|
+
const version = match[1];
|
|
191
|
+
let osVersion = windowsVersionMap[version] || '';
|
|
192
|
+
if (/arm/i.test(user_agent)) osVersion = 'RT';
|
|
193
|
+
return [
|
|
194
|
+
WINDOWS,
|
|
195
|
+
osVersion
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
return [
|
|
199
|
+
WINDOWS,
|
|
200
|
+
''
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
[
|
|
205
|
+
/((iPhone|iPad|iPod).*?OS (\d+)_(\d+)_?(\d+)?|iPhone)/,
|
|
206
|
+
(match)=>{
|
|
207
|
+
if (match && match[3]) {
|
|
208
|
+
const versionParts = [
|
|
209
|
+
match[3],
|
|
210
|
+
match[4],
|
|
211
|
+
match[5] || '0'
|
|
212
|
+
];
|
|
213
|
+
return [
|
|
214
|
+
IOS,
|
|
215
|
+
versionParts.join('.')
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
return [
|
|
219
|
+
IOS,
|
|
220
|
+
''
|
|
221
|
+
];
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
[
|
|
225
|
+
/(watch.*\/(\d+\.\d+\.\d+)|watch os,(\d+\.\d+),)/i,
|
|
226
|
+
(match)=>{
|
|
227
|
+
let version = '';
|
|
228
|
+
if (match && match.length >= 3) version = isUndefined(match[2]) ? match[3] : match[2];
|
|
229
|
+
return [
|
|
230
|
+
'watchOS',
|
|
231
|
+
version
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
[
|
|
236
|
+
new RegExp('(' + ANDROID + ' (\\d+)\\.(\\d+)\\.?(\\d+)?|' + ANDROID + ')', 'i'),
|
|
237
|
+
(match)=>{
|
|
238
|
+
if (match && match[2]) {
|
|
239
|
+
const versionParts = [
|
|
240
|
+
match[2],
|
|
241
|
+
match[3],
|
|
242
|
+
match[4] || '0'
|
|
243
|
+
];
|
|
244
|
+
return [
|
|
245
|
+
ANDROID,
|
|
246
|
+
versionParts.join('.')
|
|
247
|
+
];
|
|
248
|
+
}
|
|
249
|
+
return [
|
|
250
|
+
ANDROID,
|
|
251
|
+
''
|
|
252
|
+
];
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
[
|
|
256
|
+
/Mac OS X (\d+)[_.](\d+)[_.]?(\d+)?/i,
|
|
257
|
+
(match)=>{
|
|
258
|
+
const result = [
|
|
259
|
+
'Mac OS X',
|
|
260
|
+
''
|
|
261
|
+
];
|
|
262
|
+
if (match && match[1]) {
|
|
263
|
+
const versionParts = [
|
|
264
|
+
match[1],
|
|
265
|
+
match[2],
|
|
266
|
+
match[3] || '0'
|
|
267
|
+
];
|
|
268
|
+
result[1] = versionParts.join('.');
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
[
|
|
274
|
+
/Mac/i,
|
|
275
|
+
[
|
|
276
|
+
'Mac OS X',
|
|
277
|
+
''
|
|
278
|
+
]
|
|
279
|
+
],
|
|
280
|
+
[
|
|
281
|
+
/CrOS/,
|
|
282
|
+
[
|
|
283
|
+
CHROME_OS,
|
|
284
|
+
''
|
|
285
|
+
]
|
|
286
|
+
],
|
|
287
|
+
[
|
|
288
|
+
/Linux|debian/i,
|
|
289
|
+
[
|
|
290
|
+
'Linux',
|
|
291
|
+
''
|
|
292
|
+
]
|
|
293
|
+
]
|
|
294
|
+
];
|
|
295
|
+
const detectOS = function(user_agent) {
|
|
296
|
+
for(let i = 0; i < osMatchers.length; i++){
|
|
297
|
+
const [rgex, resultOrFn] = osMatchers[i];
|
|
298
|
+
const match = rgex.exec(user_agent);
|
|
299
|
+
const result = match && (isFunction(resultOrFn) ? resultOrFn(match, user_agent) : resultOrFn);
|
|
300
|
+
if (result) return result;
|
|
301
|
+
}
|
|
302
|
+
return [
|
|
303
|
+
'',
|
|
304
|
+
''
|
|
305
|
+
];
|
|
306
|
+
};
|
|
307
|
+
const detectDevice = function(user_agent) {
|
|
308
|
+
if (NINTENDO_REGEX.test(user_agent)) return NINTENDO;
|
|
309
|
+
if (PLAYSTATION_REGEX.test(user_agent)) return PLAYSTATION;
|
|
310
|
+
if (XBOX_REGEX.test(user_agent)) return XBOX;
|
|
311
|
+
if (new RegExp(OUYA, 'i').test(user_agent)) return OUYA;
|
|
312
|
+
if (new RegExp('(' + WINDOWS_PHONE + '|WPDesktop)', 'i').test(user_agent)) return WINDOWS_PHONE;
|
|
313
|
+
else if (/iPad/.test(user_agent)) return IPAD;
|
|
314
|
+
else if (/iPod/.test(user_agent)) return 'iPod Touch';
|
|
315
|
+
else if (/iPhone/.test(user_agent)) return 'iPhone';
|
|
316
|
+
else if (/(watch)(?: ?os[,/]|\d,\d\/)[\d.]+/i.test(user_agent)) return APPLE_WATCH;
|
|
317
|
+
else if (BLACKBERRY_REGEX.test(user_agent)) return BLACKBERRY;
|
|
318
|
+
else if (/(kobo)\s(ereader|touch)/i.test(user_agent)) return 'Kobo';
|
|
319
|
+
else if (new RegExp(NOKIA, 'i').test(user_agent)) return NOKIA;
|
|
320
|
+
else if (/(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i.test(user_agent) || /(kf[a-z]+)( bui|\)).+silk\//i.test(user_agent)) return 'Kindle Fire';
|
|
321
|
+
else if (/(Android|ZTE)/i.test(user_agent)) if (!(!new RegExp(MOBILE).test(user_agent) || /(9138B|TB782B|Nexus [97]|pixel c|HUAWEISHT|BTV|noble nook|smart ultra 6)/i.test(user_agent))) return ANDROID;
|
|
322
|
+
else {
|
|
323
|
+
if (/pixel[\daxl ]{1,6}/i.test(user_agent) && !/pixel c/i.test(user_agent) || /(huaweimed-al00|tah-|APA|SM-G92|i980|zte|U304AA)/i.test(user_agent) || /lmy47v/i.test(user_agent) && !/QTAQZ3/i.test(user_agent)) return ANDROID;
|
|
324
|
+
return ANDROID_TABLET;
|
|
325
|
+
}
|
|
326
|
+
else if (new RegExp('(pda|' + MOBILE + ')', 'i').test(user_agent)) return GENERIC_MOBILE;
|
|
327
|
+
else if (new RegExp(TABLET, 'i').test(user_agent) && !new RegExp(TABLET + ' pc', 'i').test(user_agent)) return GENERIC_TABLET;
|
|
328
|
+
else return '';
|
|
329
|
+
};
|
|
330
|
+
const detectDeviceType = function(user_agent) {
|
|
331
|
+
const device = detectDevice(user_agent);
|
|
332
|
+
if (device === IPAD || device === ANDROID_TABLET || 'Kobo' === device || 'Kindle Fire' === device || device === GENERIC_TABLET) return TABLET;
|
|
333
|
+
if (device === NINTENDO || device === XBOX || device === PLAYSTATION || device === OUYA) return 'Console';
|
|
334
|
+
if (device === APPLE_WATCH) return 'Wearable';
|
|
335
|
+
if (device) return MOBILE;
|
|
336
|
+
return 'Desktop';
|
|
337
|
+
};
|
|
338
|
+
export { detectBrowser, detectBrowserVersion, detectDevice, detectDeviceType, detectOS };
|
package/package.json
CHANGED
package/src/types.ts
CHANGED
|
@@ -294,13 +294,18 @@ export type EvaluationReason = {
|
|
|
294
294
|
export type SurveyAppearance = {
|
|
295
295
|
// keep in sync with frontend/src/types.ts -> SurveyAppearance
|
|
296
296
|
backgroundColor?: string
|
|
297
|
+
// Optional override for main survey text color. If not set, auto-calculated from backgroundColor.
|
|
298
|
+
textColor?: string
|
|
297
299
|
submitButtonColor?: string
|
|
298
300
|
// deprecate submit button text eventually
|
|
299
301
|
submitButtonText?: string
|
|
302
|
+
// Optional override for submit button text color. If not set, auto-calculated from submitButtonColor.
|
|
300
303
|
submitButtonTextColor?: string
|
|
301
304
|
ratingButtonColor?: string
|
|
302
305
|
ratingButtonActiveColor?: string
|
|
303
306
|
inputBackground?: string
|
|
307
|
+
// Optional override for input and rating button text color. If not set, auto-calculated from inputBackground.
|
|
308
|
+
inputTextColor?: string
|
|
304
309
|
autoDisappear?: boolean
|
|
305
310
|
displayThankYouMessage?: boolean
|
|
306
311
|
thankYouMessageHeader?: string
|