@leanbase.com/js 0.1.2 → 0.2.0-alpha.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/autocapture-utils.d.ts +17 -0
- package/dist/autocapture.d.ts +35 -0
- package/dist/config.d.ts +5 -0
- package/dist/constants.d.ts +54 -0
- package/dist/entrypoints/main.cjs.d.ts +4 -0
- package/dist/entrypoints/module.es.d.ts +4 -0
- package/dist/extensions/rageclick.d.ts +9 -0
- package/dist/iife.d.ts +19 -0
- package/dist/index.d.ts +2 -779
- package/dist/leanbase-logger.d.ts +6 -0
- package/dist/leanbase-persistence.d.ts +64 -0
- package/dist/leanbase.d.ts +49 -0
- package/dist/leanbase.iife.js +1 -4745
- package/dist/leanbase.iife.js.map +1 -1
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -0
- package/dist/module.d.ts +780 -0
- package/dist/module.js +2 -0
- package/dist/module.js.map +1 -0
- package/dist/page-view.d.ts +29 -0
- package/dist/scroll-manager.d.ts +21 -0
- package/dist/session-props.d.ts +32 -0
- package/dist/sessionid.d.ts +50 -0
- package/dist/storage.d.ts +24 -0
- package/{src/types.ts → dist/types.d.ts} +145 -235
- package/dist/utils/blocked-uas.d.ts +17 -0
- package/dist/utils/element-utils.d.ts +5 -0
- package/dist/utils/event-utils.d.ts +22 -0
- package/dist/utils/index.d.ts +44 -0
- package/dist/utils/request-utils.d.ts +12 -0
- package/dist/utils/simple-event-emitter.d.ts +6 -0
- package/dist/utils/user-agent-utils.d.ts +18 -0
- package/dist/uuidv7.d.ts +43 -0
- package/dist/version.d.ts +1 -0
- package/lib/autocapture-utils.d.ts +17 -0
- package/{src/autocapture-utils.ts → lib/autocapture-utils.js} +196 -280
- package/lib/autocapture-utils.js.map +1 -0
- package/lib/autocapture.d.ts +35 -0
- package/lib/autocapture.js +311 -0
- package/lib/autocapture.js.map +1 -0
- package/lib/config.d.ts +5 -0
- package/lib/config.js +7 -0
- package/lib/config.js.map +1 -0
- package/lib/constants.d.ts +54 -0
- package/{src/constants.ts → lib/constants.js} +58 -55
- package/lib/constants.js.map +1 -0
- package/lib/entrypoints/main.cjs.d.ts +4 -0
- package/lib/entrypoints/main.cjs.js +3 -0
- package/lib/entrypoints/main.cjs.js.map +1 -0
- package/lib/entrypoints/module.es.d.ts +4 -0
- package/lib/entrypoints/module.es.js +3 -0
- package/lib/entrypoints/module.es.js.map +1 -0
- package/lib/extensions/rageclick.d.ts +9 -0
- package/lib/extensions/rageclick.js +27 -0
- package/lib/extensions/rageclick.js.map +1 -0
- package/lib/iife.d.ts +19 -0
- package/lib/iife.js +67 -0
- package/lib/iife.js.map +1 -0
- package/{src/index.ts → lib/index.d.ts} +2 -2
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/leanbase-logger.d.ts +6 -0
- package/lib/leanbase-logger.js +25 -0
- package/lib/leanbase-logger.js.map +1 -0
- package/lib/leanbase-persistence.d.ts +64 -0
- package/lib/leanbase-persistence.js +287 -0
- package/lib/leanbase-persistence.js.map +1 -0
- package/lib/leanbase.d.ts +49 -0
- package/lib/leanbase.js +294 -0
- package/lib/leanbase.js.map +1 -0
- package/lib/page-view.d.ts +29 -0
- package/lib/page-view.js +81 -0
- package/lib/page-view.js.map +1 -0
- package/lib/scroll-manager.d.ts +21 -0
- package/lib/scroll-manager.js +79 -0
- package/lib/scroll-manager.js.map +1 -0
- package/lib/session-props.d.ts +32 -0
- package/lib/session-props.js +73 -0
- package/lib/session-props.js.map +1 -0
- package/lib/sessionid.d.ts +50 -0
- package/{src/sessionid.ts → lib/sessionid.js} +128 -204
- package/lib/sessionid.js.map +1 -0
- package/lib/storage.d.ts +24 -0
- package/{src/storage.ts → lib/storage.js} +182 -225
- package/lib/storage.js.map +1 -0
- package/lib/types.d.ts +544 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/lib/utils/blocked-uas.d.ts +17 -0
- package/{src/utils/blocked-uas.ts → lib/utils/blocked-uas.js} +19 -48
- package/lib/utils/blocked-uas.js.map +1 -0
- package/lib/utils/element-utils.d.ts +5 -0
- package/{src/utils/element-utils.ts → lib/utils/element-utils.js} +13 -17
- package/lib/utils/element-utils.js.map +1 -0
- package/lib/utils/event-utils.d.ts +22 -0
- package/lib/utils/event-utils.js +258 -0
- package/lib/utils/event-utils.js.map +1 -0
- package/lib/utils/index.d.ts +44 -0
- package/lib/utils/index.js +183 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/request-utils.d.ts +12 -0
- package/lib/utils/request-utils.js +107 -0
- package/lib/utils/request-utils.js.map +1 -0
- package/lib/utils/simple-event-emitter.d.ts +6 -0
- package/lib/utils/simple-event-emitter.js +24 -0
- package/lib/utils/simple-event-emitter.js.map +1 -0
- package/lib/utils/user-agent-utils.d.ts +18 -0
- package/lib/utils/user-agent-utils.js +369 -0
- package/lib/utils/user-agent-utils.js.map +1 -0
- package/lib/uuidv7.d.ts +43 -0
- package/{src/uuidv7.ts → lib/uuidv7.js} +103 -131
- package/lib/uuidv7.js.map +1 -0
- package/lib/version.d.ts +1 -0
- package/lib/version.js +2 -0
- package/lib/version.js.map +1 -0
- package/package.json +23 -11
- package/dist/index.cjs +0 -3032
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs +0 -3030
- package/dist/index.mjs.map +0 -1
- package/src/autocapture.ts +0 -415
- package/src/config.ts +0 -8
- package/src/extensions/rageclick.ts +0 -34
- package/src/iife.ts +0 -87
- package/src/leanbase-logger.ts +0 -26
- package/src/leanbase-persistence.ts +0 -374
- package/src/leanbase.ts +0 -424
- package/src/page-view.ts +0 -124
- package/src/scroll-manager.ts +0 -103
- package/src/session-props.ts +0 -114
- package/src/utils/event-utils.ts +0 -304
- package/src/utils/index.ts +0 -222
- package/src/utils/request-utils.ts +0 -128
- package/src/utils/simple-event-emitter.ts +0 -27
- package/src/utils/user-agent-utils.ts +0 -357
- package/src/version.ts +0 -1
package/src/session-props.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/* Store some session-level attribution-related properties in the persistence layer
|
|
2
|
-
*
|
|
3
|
-
* These have the same lifespan as a session_id, meaning that if the session_id changes, these properties will be reset.
|
|
4
|
-
*
|
|
5
|
-
* We only store the entry URL and referrer, and derive many props (such as utm tags) from those.
|
|
6
|
-
*
|
|
7
|
-
* Given that the cookie is limited to 4K bytes, we don't want to store too much data, so we chose not to store device
|
|
8
|
-
* properties (such as browser, OS, etc) here, as usually getting the current value of those from event properties is
|
|
9
|
-
* sufficient.
|
|
10
|
-
*/
|
|
11
|
-
import { getPersonInfo, getPersonPropsFromInfo } from './utils/event-utils'
|
|
12
|
-
import type { SessionIdManager } from './sessionid'
|
|
13
|
-
import type { LeanbasePersistence } from './leanbase-persistence'
|
|
14
|
-
import { CLIENT_SESSION_PROPS } from './constants'
|
|
15
|
-
import type { Leanbase } from './leanbase'
|
|
16
|
-
import { each, stripEmptyProperties } from './utils'
|
|
17
|
-
import { stripLeadingDollar } from '@posthog/core'
|
|
18
|
-
|
|
19
|
-
interface LegacySessionSourceProps {
|
|
20
|
-
initialPathName: string
|
|
21
|
-
referringDomain: string // Is actually referring host, but named referring domain for internal consistency. Should contain a port if there is one.
|
|
22
|
-
utm_medium?: string
|
|
23
|
-
utm_source?: string
|
|
24
|
-
utm_campaign?: string
|
|
25
|
-
utm_content?: string
|
|
26
|
-
utm_term?: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface CurrentSessionSourceProps {
|
|
30
|
-
r: string // Referring host
|
|
31
|
-
u: string | undefined // full URL
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface StoredSessionSourceProps {
|
|
35
|
-
sessionId: string
|
|
36
|
-
props: LegacySessionSourceProps | CurrentSessionSourceProps
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const generateSessionSourceParams = (posthog?: Leanbase): LegacySessionSourceProps | CurrentSessionSourceProps => {
|
|
40
|
-
return getPersonInfo(posthog?.config.mask_personal_data_properties, posthog?.config.custom_personal_data_properties)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class SessionPropsManager {
|
|
44
|
-
private readonly _instance: Leanbase
|
|
45
|
-
private readonly _sessionIdManager: SessionIdManager
|
|
46
|
-
private readonly _persistence: LeanbasePersistence
|
|
47
|
-
private readonly _sessionSourceParamGenerator: (
|
|
48
|
-
instance?: Leanbase
|
|
49
|
-
) => LegacySessionSourceProps | CurrentSessionSourceProps
|
|
50
|
-
|
|
51
|
-
constructor(
|
|
52
|
-
instance: Leanbase,
|
|
53
|
-
sessionIdManager: SessionIdManager,
|
|
54
|
-
persistence: LeanbasePersistence,
|
|
55
|
-
sessionSourceParamGenerator?: (instance?: Leanbase) => LegacySessionSourceProps | CurrentSessionSourceProps
|
|
56
|
-
) {
|
|
57
|
-
this._instance = instance
|
|
58
|
-
this._sessionIdManager = sessionIdManager
|
|
59
|
-
this._persistence = persistence
|
|
60
|
-
this._sessionSourceParamGenerator = sessionSourceParamGenerator || generateSessionSourceParams
|
|
61
|
-
|
|
62
|
-
this._sessionIdManager.onSessionId(this._onSessionIdCallback)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
_getStored(): StoredSessionSourceProps | undefined {
|
|
66
|
-
return this._persistence.props[CLIENT_SESSION_PROPS]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
_onSessionIdCallback = (sessionId: string) => {
|
|
70
|
-
const stored = this._getStored()
|
|
71
|
-
if (stored && stored.sessionId === sessionId) {
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const newProps: StoredSessionSourceProps = {
|
|
76
|
-
sessionId,
|
|
77
|
-
props: this._sessionSourceParamGenerator(this._instance),
|
|
78
|
-
}
|
|
79
|
-
this._persistence.register({ [CLIENT_SESSION_PROPS]: newProps })
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
getSetOnceProps() {
|
|
83
|
-
const p = this._getStored()?.props
|
|
84
|
-
if (!p) {
|
|
85
|
-
return {}
|
|
86
|
-
}
|
|
87
|
-
if ('r' in p) {
|
|
88
|
-
return getPersonPropsFromInfo(p)
|
|
89
|
-
} else {
|
|
90
|
-
return {
|
|
91
|
-
$referring_domain: p.referringDomain,
|
|
92
|
-
$pathname: p.initialPathName,
|
|
93
|
-
utm_source: p.utm_source,
|
|
94
|
-
utm_campaign: p.utm_campaign,
|
|
95
|
-
utm_medium: p.utm_medium,
|
|
96
|
-
utm_content: p.utm_content,
|
|
97
|
-
utm_term: p.utm_term,
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
getSessionProps() {
|
|
103
|
-
// it's the same props, but don't include null for unset properties, and add a prefix
|
|
104
|
-
const p: Record<string, any> = {}
|
|
105
|
-
each(stripEmptyProperties(this.getSetOnceProps()), (v, k) => {
|
|
106
|
-
if (k === '$current_url') {
|
|
107
|
-
// $session_entry_current_url would be a weird name, call it $session_entry_url instead
|
|
108
|
-
k = 'url'
|
|
109
|
-
}
|
|
110
|
-
p[`$session_entry_${stripLeadingDollar(k)}`] = v
|
|
111
|
-
})
|
|
112
|
-
return p
|
|
113
|
-
}
|
|
114
|
-
}
|
package/src/utils/event-utils.ts
DELETED
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
import { convertToURL, getQueryParam, maskQueryParams } from './request-utils'
|
|
2
|
-
import { isNull, stripLeadingDollar } from '@posthog/core'
|
|
3
|
-
import { each, extend, extendArray, stripEmptyProperties } from './index'
|
|
4
|
-
import { document, location, userAgent, window } from './'
|
|
5
|
-
import { detectBrowser, detectBrowserVersion, detectDevice, detectDeviceType, detectOS } from './user-agent-utils'
|
|
6
|
-
import { cookieStore } from '../storage'
|
|
7
|
-
import Config from '../config'
|
|
8
|
-
import { Properties } from '../types'
|
|
9
|
-
|
|
10
|
-
const URL_REGEX_PREFIX = 'https?://(.*)'
|
|
11
|
-
|
|
12
|
-
// CAMPAIGN_PARAMS and EVENT_TO_PERSON_PROPERTIES should be kept in sync with
|
|
13
|
-
// https://github.com/PostHog/posthog/blob/master/plugin-server/src/utils/db/utils.ts#L60
|
|
14
|
-
|
|
15
|
-
// The list of campaign parameters that could be considered personal data under e.g. GDPR.
|
|
16
|
-
// These can be masked in URLs and properties before being sent to posthog.
|
|
17
|
-
export const PERSONAL_DATA_CAMPAIGN_PARAMS = [
|
|
18
|
-
'gclid', // google ads
|
|
19
|
-
'gclsrc', // google ads 360
|
|
20
|
-
'dclid', // google display ads
|
|
21
|
-
'gbraid', // google ads, web to app
|
|
22
|
-
'wbraid', // google ads, app to web
|
|
23
|
-
'fbclid', // facebook
|
|
24
|
-
'msclkid', // microsoft
|
|
25
|
-
'twclid', // twitter
|
|
26
|
-
'li_fat_id', // linkedin
|
|
27
|
-
'igshid', // instagram
|
|
28
|
-
'ttclid', // tiktok
|
|
29
|
-
'rdt_cid', // reddit
|
|
30
|
-
'epik', // pinterest
|
|
31
|
-
'qclid', // quora
|
|
32
|
-
'sccid', // snapchat
|
|
33
|
-
'irclid', // impact
|
|
34
|
-
'_kx', // klaviyo
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
export const CAMPAIGN_PARAMS = extendArray(
|
|
38
|
-
[
|
|
39
|
-
'utm_source',
|
|
40
|
-
'utm_medium',
|
|
41
|
-
'utm_campaign',
|
|
42
|
-
'utm_content',
|
|
43
|
-
'utm_term',
|
|
44
|
-
'gad_source', // google ads source
|
|
45
|
-
'mc_cid', // mailchimp campaign id
|
|
46
|
-
],
|
|
47
|
-
PERSONAL_DATA_CAMPAIGN_PARAMS
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
export const EVENT_TO_PERSON_PROPERTIES = [
|
|
51
|
-
// mobile params
|
|
52
|
-
'$app_build',
|
|
53
|
-
'$app_name',
|
|
54
|
-
'$app_namespace',
|
|
55
|
-
'$app_version',
|
|
56
|
-
// web params
|
|
57
|
-
'$browser',
|
|
58
|
-
'$browser_version',
|
|
59
|
-
'$device_type',
|
|
60
|
-
'$current_url',
|
|
61
|
-
'$pathname',
|
|
62
|
-
'$os',
|
|
63
|
-
'$os_name', // $os_name is a special case, it's treated as an alias of $os!
|
|
64
|
-
'$os_version',
|
|
65
|
-
'$referring_domain',
|
|
66
|
-
'$referrer',
|
|
67
|
-
'$screen_height',
|
|
68
|
-
'$screen_width',
|
|
69
|
-
'$viewport_height',
|
|
70
|
-
'$viewport_width',
|
|
71
|
-
'$raw_user_agent',
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
export const MASKED = '<masked>'
|
|
75
|
-
|
|
76
|
-
// Campaign params that can be read from the cookie store
|
|
77
|
-
export const COOKIE_CAMPAIGN_PARAMS = [
|
|
78
|
-
'li_fat_id', // linkedin
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
export function getCampaignParams(
|
|
82
|
-
customTrackedParams?: string[],
|
|
83
|
-
maskPersonalDataProperties?: boolean,
|
|
84
|
-
customPersonalDataProperties?: string[] | undefined
|
|
85
|
-
): Record<string, string> {
|
|
86
|
-
if (!document) {
|
|
87
|
-
return {}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const paramsToMask = maskPersonalDataProperties
|
|
91
|
-
? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])
|
|
92
|
-
: []
|
|
93
|
-
|
|
94
|
-
// Initially get campaign params from the URL
|
|
95
|
-
const urlCampaignParams = _getCampaignParamsFromUrl(
|
|
96
|
-
maskQueryParams(document.URL, paramsToMask, MASKED),
|
|
97
|
-
customTrackedParams
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
// But we can also get some of them from the cookie store
|
|
101
|
-
// For example: https://learn.microsoft.com/en-us/linkedin/marketing/conversions/enabling-first-party-cookies?view=li-lms-2025-05#reading-li_fat_id-from-cookies
|
|
102
|
-
const cookieCampaignParams = _getCampaignParamsFromCookie()
|
|
103
|
-
|
|
104
|
-
// Prefer the values found in the urlCampaignParams if possible
|
|
105
|
-
// `extend` will override the values if found in the second argument
|
|
106
|
-
return extend(cookieCampaignParams, urlCampaignParams)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function _getCampaignParamsFromUrl(url: string, customParams?: string[]): Record<string, string> {
|
|
110
|
-
const campaign_keywords = CAMPAIGN_PARAMS.concat(customParams || [])
|
|
111
|
-
|
|
112
|
-
const params: Record<string, any> = {}
|
|
113
|
-
each(campaign_keywords, function (kwkey) {
|
|
114
|
-
const kw = getQueryParam(url, kwkey)
|
|
115
|
-
params[kwkey] = kw ? kw : null
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
return params
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function _getCampaignParamsFromCookie(): Record<string, string> {
|
|
122
|
-
const params: Record<string, any> = {}
|
|
123
|
-
each(COOKIE_CAMPAIGN_PARAMS, function (kwkey) {
|
|
124
|
-
const kw = cookieStore._get(kwkey)
|
|
125
|
-
params[kwkey] = kw ? kw : null
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
return params
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function _getSearchEngine(referrer: string): string | null {
|
|
132
|
-
if (!referrer) {
|
|
133
|
-
return null
|
|
134
|
-
} else {
|
|
135
|
-
if (referrer.search(URL_REGEX_PREFIX + 'google.([^/?]*)') === 0) {
|
|
136
|
-
return 'google'
|
|
137
|
-
} else if (referrer.search(URL_REGEX_PREFIX + 'bing.com') === 0) {
|
|
138
|
-
return 'bing'
|
|
139
|
-
} else if (referrer.search(URL_REGEX_PREFIX + 'yahoo.com') === 0) {
|
|
140
|
-
return 'yahoo'
|
|
141
|
-
} else if (referrer.search(URL_REGEX_PREFIX + 'duckduckgo.com') === 0) {
|
|
142
|
-
return 'duckduckgo'
|
|
143
|
-
} else {
|
|
144
|
-
return null
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function _getSearchInfoFromReferrer(referrer: string): Record<string, any> {
|
|
150
|
-
const search = _getSearchEngine(referrer)
|
|
151
|
-
const param = search != 'yahoo' ? 'q' : 'p'
|
|
152
|
-
const ret: Record<string, any> = {}
|
|
153
|
-
|
|
154
|
-
if (!isNull(search)) {
|
|
155
|
-
ret['$search_engine'] = search
|
|
156
|
-
|
|
157
|
-
const keyword = document ? getQueryParam(document.referrer, param) : ''
|
|
158
|
-
if (keyword.length) {
|
|
159
|
-
ret['ph_keyword'] = keyword
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return ret
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function getSearchInfo(): Record<string, any> {
|
|
167
|
-
const referrer = document?.referrer
|
|
168
|
-
if (!referrer) {
|
|
169
|
-
return {}
|
|
170
|
-
}
|
|
171
|
-
return _getSearchInfoFromReferrer(referrer)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function getBrowserLanguage(): string | undefined {
|
|
175
|
-
return (
|
|
176
|
-
navigator.language || // Any modern browser
|
|
177
|
-
(navigator as Record<string, any>).userLanguage // IE11
|
|
178
|
-
)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function getBrowserLanguagePrefix(): string | undefined {
|
|
182
|
-
const lang = getBrowserLanguage()
|
|
183
|
-
return typeof lang === 'string' ? lang.split('-')[0] : undefined
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export function getReferrer(): string {
|
|
187
|
-
return document?.referrer || '$direct'
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export function getReferringDomain(): string {
|
|
191
|
-
if (!document?.referrer) {
|
|
192
|
-
return '$direct'
|
|
193
|
-
}
|
|
194
|
-
return convertToURL(document.referrer)?.host || '$direct'
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export function getReferrerInfo(): Record<string, any> {
|
|
198
|
-
return {
|
|
199
|
-
$referrer: getReferrer(),
|
|
200
|
-
$referring_domain: getReferringDomain(),
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function getPersonInfo(maskPersonalDataProperties?: boolean, customPersonalDataProperties?: string[]) {
|
|
205
|
-
const paramsToMask = maskPersonalDataProperties
|
|
206
|
-
? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])
|
|
207
|
-
: []
|
|
208
|
-
const url = location?.href.substring(0, 1000)
|
|
209
|
-
// we're being a bit more economical with bytes here because this is stored in the cookie
|
|
210
|
-
return {
|
|
211
|
-
r: getReferrer().substring(0, 1000),
|
|
212
|
-
u: url ? maskQueryParams(url, paramsToMask, MASKED) : undefined,
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export function getPersonPropsFromInfo(info: Record<string, any>): Record<string, any> {
|
|
217
|
-
const { r: referrer, u: url } = info
|
|
218
|
-
const referring_domain =
|
|
219
|
-
referrer == null ? undefined : referrer == '$direct' ? '$direct' : convertToURL(referrer)?.host
|
|
220
|
-
|
|
221
|
-
const props: Record<string, string | undefined> = {
|
|
222
|
-
$referrer: referrer,
|
|
223
|
-
$referring_domain: referring_domain,
|
|
224
|
-
}
|
|
225
|
-
if (url) {
|
|
226
|
-
props['$current_url'] = url
|
|
227
|
-
const location = convertToURL(url)
|
|
228
|
-
props['$host'] = location?.host
|
|
229
|
-
props['$pathname'] = location?.pathname
|
|
230
|
-
const campaignParams = _getCampaignParamsFromUrl(url)
|
|
231
|
-
extend(props, campaignParams)
|
|
232
|
-
}
|
|
233
|
-
if (referrer) {
|
|
234
|
-
const searchInfo = _getSearchInfoFromReferrer(referrer)
|
|
235
|
-
extend(props, searchInfo)
|
|
236
|
-
}
|
|
237
|
-
return props
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function getInitialPersonPropsFromInfo(info: Record<string, any>): Record<string, any> {
|
|
241
|
-
const personProps = getPersonPropsFromInfo(info)
|
|
242
|
-
const props: Record<string, any> = {}
|
|
243
|
-
each(personProps, function (val: any, key: string) {
|
|
244
|
-
props[`$initial_${stripLeadingDollar(key)}`] = val
|
|
245
|
-
})
|
|
246
|
-
return props
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export function getTimezone(): string | undefined {
|
|
250
|
-
try {
|
|
251
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
252
|
-
} catch {
|
|
253
|
-
return undefined
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export function getTimezoneOffset(): number | undefined {
|
|
258
|
-
try {
|
|
259
|
-
return new Date().getTimezoneOffset()
|
|
260
|
-
} catch {
|
|
261
|
-
return undefined
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export function getEventProperties(
|
|
266
|
-
maskPersonalDataProperties?: boolean,
|
|
267
|
-
customPersonalDataProperties?: string[]
|
|
268
|
-
): Properties {
|
|
269
|
-
if (!userAgent) {
|
|
270
|
-
return {}
|
|
271
|
-
}
|
|
272
|
-
const paramsToMask = maskPersonalDataProperties
|
|
273
|
-
? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])
|
|
274
|
-
: []
|
|
275
|
-
const [os_name, os_version] = detectOS(userAgent)
|
|
276
|
-
return extend(
|
|
277
|
-
stripEmptyProperties({
|
|
278
|
-
$os: os_name,
|
|
279
|
-
$os_version: os_version,
|
|
280
|
-
$browser: detectBrowser(userAgent, navigator.vendor),
|
|
281
|
-
$device: detectDevice(userAgent),
|
|
282
|
-
$device_type: detectDeviceType(userAgent),
|
|
283
|
-
$timezone: getTimezone(),
|
|
284
|
-
$timezone_offset: getTimezoneOffset(),
|
|
285
|
-
}),
|
|
286
|
-
{
|
|
287
|
-
$current_url: maskQueryParams(location?.href, paramsToMask, MASKED),
|
|
288
|
-
$host: location?.host,
|
|
289
|
-
$pathname: location?.pathname,
|
|
290
|
-
$raw_user_agent: userAgent.length > 1000 ? userAgent.substring(0, 997) + '...' : userAgent,
|
|
291
|
-
$browser_version: detectBrowserVersion(userAgent, navigator.vendor),
|
|
292
|
-
$browser_language: getBrowserLanguage(),
|
|
293
|
-
$browser_language_prefix: getBrowserLanguagePrefix(),
|
|
294
|
-
$screen_height: window?.screen.height,
|
|
295
|
-
$screen_width: window?.screen.width,
|
|
296
|
-
$viewport_height: window?.innerHeight,
|
|
297
|
-
$viewport_width: window?.innerWidth,
|
|
298
|
-
$lib: 'web',
|
|
299
|
-
$lib_version: Config.LIB_VERSION,
|
|
300
|
-
$insert_id: Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10),
|
|
301
|
-
$time: Date.now() / 1000, // epoch time in seconds
|
|
302
|
-
}
|
|
303
|
-
)
|
|
304
|
-
}
|
package/src/utils/index.ts
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import { isFormData, isNull, isNullish, hasOwnProperty, isArray, isString, isNumber } from '@posthog/core'
|
|
2
|
-
import { Properties } from '../types'
|
|
3
|
-
|
|
4
|
-
const breaker: Breaker = {}
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
7
|
-
export type Breaker = {}
|
|
8
|
-
|
|
9
|
-
export const ArrayProto = Array.prototype
|
|
10
|
-
export const nativeForEach = ArrayProto.forEach
|
|
11
|
-
export const nativeIndexOf = ArrayProto.indexOf
|
|
12
|
-
|
|
13
|
-
const win: (Window & typeof globalThis) | undefined = typeof window !== 'undefined' ? window : undefined
|
|
14
|
-
const global: typeof globalThis | undefined = typeof globalThis !== 'undefined' ? globalThis : win
|
|
15
|
-
export const navigator = global?.navigator
|
|
16
|
-
export const document = global?.document
|
|
17
|
-
export const location = global?.location
|
|
18
|
-
export const fetch = global?.fetch
|
|
19
|
-
export const XMLHttpRequest =
|
|
20
|
-
global?.XMLHttpRequest && 'withCredentials' in new global.XMLHttpRequest() ? global.XMLHttpRequest : undefined
|
|
21
|
-
export const AbortController = global?.AbortController
|
|
22
|
-
export const userAgent = navigator?.userAgent
|
|
23
|
-
export { win as window }
|
|
24
|
-
|
|
25
|
-
export function eachArray<E = any>(
|
|
26
|
-
obj: E[] | null | undefined,
|
|
27
|
-
iterator: (value: E, key: number) => void | Breaker,
|
|
28
|
-
thisArg?: any
|
|
29
|
-
): void {
|
|
30
|
-
if (isArray(obj)) {
|
|
31
|
-
if (nativeForEach && obj.forEach === nativeForEach) {
|
|
32
|
-
obj.forEach(iterator, thisArg)
|
|
33
|
-
} else if ('length' in obj && obj.length === +obj.length) {
|
|
34
|
-
for (let i = 0, l = obj.length; i < l; i++) {
|
|
35
|
-
if (i in obj && iterator.call(thisArg, obj[i], i) === breaker) {
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {*=} obj
|
|
45
|
-
* @param {function(...*)=} iterator
|
|
46
|
-
* @param {Object=} thisArg
|
|
47
|
-
*/
|
|
48
|
-
export function each(obj: any, iterator: (value: any, key: any) => void | Breaker, thisArg?: any): void {
|
|
49
|
-
if (isNullish(obj)) {
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
if (isArray(obj)) {
|
|
53
|
-
return eachArray(obj, iterator, thisArg)
|
|
54
|
-
}
|
|
55
|
-
if (isFormData(obj)) {
|
|
56
|
-
for (const pair of obj.entries()) {
|
|
57
|
-
if (iterator.call(thisArg, pair[1], pair[0]) === breaker) {
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
for (const key in obj) {
|
|
64
|
-
if (hasOwnProperty.call(obj, key)) {
|
|
65
|
-
if (iterator.call(thisArg, obj[key], key) === breaker) {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export const extend = function (obj: Record<string, any>, ...args: Record<string, any>[]): Record<string, any> {
|
|
73
|
-
eachArray(args, function (source) {
|
|
74
|
-
for (const prop in source) {
|
|
75
|
-
if (source[prop] !== void 0) {
|
|
76
|
-
obj[prop] = source[prop]
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
return obj
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export const extendArray = function <T>(obj: T[], ...args: T[][]): T[] {
|
|
84
|
-
eachArray(args, function (source) {
|
|
85
|
-
eachArray(source, function (item) {
|
|
86
|
-
obj.push(item)
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
return obj
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export const include = function (
|
|
93
|
-
obj: null | string | Array<any> | Record<string, any>,
|
|
94
|
-
target: any
|
|
95
|
-
): boolean | Breaker {
|
|
96
|
-
let found = false
|
|
97
|
-
if (isNull(obj)) {
|
|
98
|
-
return found
|
|
99
|
-
}
|
|
100
|
-
if (nativeIndexOf && obj.indexOf === nativeIndexOf) {
|
|
101
|
-
return obj.indexOf(target) != -1
|
|
102
|
-
}
|
|
103
|
-
each(obj, function (value) {
|
|
104
|
-
if (found || (found = value === target)) {
|
|
105
|
-
return breaker
|
|
106
|
-
}
|
|
107
|
-
return
|
|
108
|
-
})
|
|
109
|
-
return found
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Object.entries() polyfill
|
|
114
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
|
|
115
|
-
*/
|
|
116
|
-
export function entries<T = any>(obj: Record<string, T>): [string, T][] {
|
|
117
|
-
const ownProps = Object.keys(obj)
|
|
118
|
-
let i = ownProps.length
|
|
119
|
-
const resArray = new Array(i) // preallocate the Array
|
|
120
|
-
|
|
121
|
-
while (i--) {
|
|
122
|
-
resArray[i] = [ownProps[i], obj[ownProps[i]]]
|
|
123
|
-
}
|
|
124
|
-
return resArray
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export function addEventListener(
|
|
128
|
-
element: Window | Document | Element | undefined,
|
|
129
|
-
event: string,
|
|
130
|
-
callback: EventListener,
|
|
131
|
-
options?: AddEventListenerOptions
|
|
132
|
-
): void {
|
|
133
|
-
const { capture = false, passive = true } = options ?? {}
|
|
134
|
-
|
|
135
|
-
// This is the only place where we are allowed to call this function
|
|
136
|
-
// because the whole idea is that we should be calling this instead of the built-in one
|
|
137
|
-
// eslint-disable-next-line posthog-js/no-add-event-listener
|
|
138
|
-
element?.addEventListener(event, callback, { capture, passive })
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export const stripEmptyProperties = function (p: Properties): Properties {
|
|
142
|
-
const ret: Properties = {}
|
|
143
|
-
each(p, function (v, k) {
|
|
144
|
-
if ((isString(v) && v.length > 0) || isNumber(v)) {
|
|
145
|
-
ret[k] = v
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
return ret
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const EXCLUDED_FROM_CROSS_SUBDOMAIN_COOKIE = ['herokuapp.com', 'vercel.app', 'netlify.app']
|
|
152
|
-
export function isCrossDomainCookie(documentLocation: Location | undefined) {
|
|
153
|
-
const hostname = documentLocation?.hostname
|
|
154
|
-
|
|
155
|
-
if (!isString(hostname)) {
|
|
156
|
-
return false
|
|
157
|
-
}
|
|
158
|
-
// split and slice isn't a great way to match arbitrary domains,
|
|
159
|
-
// but it's good enough for ensuring we only match herokuapp.com when it is the TLD
|
|
160
|
-
// for the hostname
|
|
161
|
-
const lastTwoParts = hostname.split('.').slice(-2).join('.')
|
|
162
|
-
|
|
163
|
-
for (const excluded of EXCLUDED_FROM_CROSS_SUBDOMAIN_COOKIE) {
|
|
164
|
-
if (lastTwoParts === excluded) {
|
|
165
|
-
return false
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return true
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Deep copies an object.
|
|
174
|
-
* It handles cycles by replacing all references to them with `undefined`
|
|
175
|
-
* Also supports customizing native values
|
|
176
|
-
*
|
|
177
|
-
* @param value
|
|
178
|
-
* @param customizer
|
|
179
|
-
* @returns {{}|undefined|*}
|
|
180
|
-
*/
|
|
181
|
-
function deepCircularCopy<T extends Record<string, any> = Record<string, any>>(
|
|
182
|
-
value: T,
|
|
183
|
-
customizer?: <K extends keyof T = keyof T>(value: T[K], key?: K) => T[K]
|
|
184
|
-
): T | undefined {
|
|
185
|
-
const COPY_IN_PROGRESS_SET = new Set()
|
|
186
|
-
|
|
187
|
-
function internalDeepCircularCopy(value: T, key?: string): T | undefined {
|
|
188
|
-
if (value !== Object(value)) return customizer ? customizer(value as any, key) : value // primitive value
|
|
189
|
-
|
|
190
|
-
if (COPY_IN_PROGRESS_SET.has(value)) return undefined
|
|
191
|
-
COPY_IN_PROGRESS_SET.add(value)
|
|
192
|
-
let result: T
|
|
193
|
-
|
|
194
|
-
if (isArray(value)) {
|
|
195
|
-
result = [] as any as T
|
|
196
|
-
eachArray(value, (it) => {
|
|
197
|
-
result.push(internalDeepCircularCopy(it))
|
|
198
|
-
})
|
|
199
|
-
} else {
|
|
200
|
-
result = {} as T
|
|
201
|
-
each(value, (val, key) => {
|
|
202
|
-
if (!COPY_IN_PROGRESS_SET.has(val)) {
|
|
203
|
-
;(result as any)[key] = internalDeepCircularCopy(val, key)
|
|
204
|
-
}
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
return result
|
|
208
|
-
}
|
|
209
|
-
return internalDeepCircularCopy(value)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export function copyAndTruncateStrings<T extends Record<string, any> = Record<string, any>>(
|
|
213
|
-
object: T,
|
|
214
|
-
maxStringLength: number | null
|
|
215
|
-
): T {
|
|
216
|
-
return deepCircularCopy(object, (value: any) => {
|
|
217
|
-
if (isString(value) && !isNull(maxStringLength)) {
|
|
218
|
-
return (value as string).slice(0, maxStringLength)
|
|
219
|
-
}
|
|
220
|
-
return value
|
|
221
|
-
}) as T
|
|
222
|
-
}
|