@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/leanbase.ts
DELETED
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PostHogCore,
|
|
3
|
-
getFetch,
|
|
4
|
-
isEmptyObject,
|
|
5
|
-
isEmptyString,
|
|
6
|
-
isNumber,
|
|
7
|
-
isObject,
|
|
8
|
-
isString,
|
|
9
|
-
isUndefined,
|
|
10
|
-
} from '@posthog/core'
|
|
11
|
-
import type {
|
|
12
|
-
PostHogEventProperties,
|
|
13
|
-
PostHogFetchOptions,
|
|
14
|
-
PostHogFetchResponse,
|
|
15
|
-
PostHogPersistedProperty,
|
|
16
|
-
} from '@posthog/core'
|
|
17
|
-
import {
|
|
18
|
-
LeanbaseConfig,
|
|
19
|
-
LeanbasegCaptureOptions as LeanbaseCaptureOptions,
|
|
20
|
-
RemoteConfig,
|
|
21
|
-
CaptureResult,
|
|
22
|
-
Properties,
|
|
23
|
-
} from './types'
|
|
24
|
-
import { LeanbasePersistence } from './leanbase-persistence'
|
|
25
|
-
import {
|
|
26
|
-
addEventListener,
|
|
27
|
-
copyAndTruncateStrings,
|
|
28
|
-
document,
|
|
29
|
-
extend,
|
|
30
|
-
isCrossDomainCookie,
|
|
31
|
-
navigator,
|
|
32
|
-
userAgent,
|
|
33
|
-
} from './utils'
|
|
34
|
-
import Config from './config'
|
|
35
|
-
import { Autocapture } from './autocapture'
|
|
36
|
-
import { logger } from './leanbase-logger'
|
|
37
|
-
import { COOKIELESS_MODE_FLAG_PROPERTY, USER_STATE } from './constants'
|
|
38
|
-
import { getEventProperties } from './utils/event-utils'
|
|
39
|
-
import { SessionIdManager } from './sessionid'
|
|
40
|
-
import { SessionPropsManager } from './session-props'
|
|
41
|
-
import { uuidv7 } from './uuidv7'
|
|
42
|
-
import { PageViewManager } from './page-view'
|
|
43
|
-
import { ScrollManager } from './scroll-manager'
|
|
44
|
-
import { isLikelyBot } from './utils/blocked-uas'
|
|
45
|
-
|
|
46
|
-
const defaultConfig = (): LeanbaseConfig => ({
|
|
47
|
-
host: 'https://i.leanbase.co',
|
|
48
|
-
token: '',
|
|
49
|
-
autocapture: true,
|
|
50
|
-
rageclick: true,
|
|
51
|
-
persistence: 'localStorage+cookie',
|
|
52
|
-
capture_pageview: 'history_change',
|
|
53
|
-
capture_pageleave: 'if_capture_pageview',
|
|
54
|
-
persistence_name: '',
|
|
55
|
-
mask_all_element_attributes: false,
|
|
56
|
-
cookie_expiration: 365,
|
|
57
|
-
cross_subdomain_cookie: isCrossDomainCookie(document?.location),
|
|
58
|
-
custom_campaign_params: [],
|
|
59
|
-
custom_personal_data_properties: [],
|
|
60
|
-
disable_persistence: false,
|
|
61
|
-
mask_personal_data_properties: false,
|
|
62
|
-
secure_cookie: window?.location?.protocol === 'https:',
|
|
63
|
-
mask_all_text: false,
|
|
64
|
-
bootstrap: {},
|
|
65
|
-
session_idle_timeout_seconds: 30 * 60,
|
|
66
|
-
save_campaign_params: true,
|
|
67
|
-
save_referrer: true,
|
|
68
|
-
opt_out_useragent_filter: false,
|
|
69
|
-
properties_string_max_length: 65535,
|
|
70
|
-
loaded: () => {},
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
export class Leanbase extends PostHogCore {
|
|
74
|
-
config: LeanbaseConfig
|
|
75
|
-
scrollManager: ScrollManager
|
|
76
|
-
pageViewManager: PageViewManager
|
|
77
|
-
|
|
78
|
-
replayAutocapture?: Autocapture
|
|
79
|
-
persistence?: LeanbasePersistence
|
|
80
|
-
sessionPersistence?: LeanbasePersistence
|
|
81
|
-
sessionManager?: SessionIdManager
|
|
82
|
-
sessionPropsManager?: SessionPropsManager
|
|
83
|
-
isRemoteConfigLoaded?: boolean
|
|
84
|
-
personProcessingSetOncePropertiesSent = false
|
|
85
|
-
isLoaded: boolean = false
|
|
86
|
-
initialPageviewCaptured: boolean
|
|
87
|
-
visibilityStateListener: (() => void) | null
|
|
88
|
-
|
|
89
|
-
constructor(token: string, config?: Partial<LeanbaseConfig>) {
|
|
90
|
-
const mergedConfig = extend(defaultConfig(), config || {}, {
|
|
91
|
-
token,
|
|
92
|
-
})
|
|
93
|
-
super(token, mergedConfig)
|
|
94
|
-
this.config = mergedConfig as LeanbaseConfig
|
|
95
|
-
this.visibilityStateListener = null
|
|
96
|
-
this.initialPageviewCaptured = false
|
|
97
|
-
this.scrollManager = new ScrollManager(this)
|
|
98
|
-
this.pageViewManager = new PageViewManager(this)
|
|
99
|
-
this.init(token, mergedConfig)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
init(token: string, config: Partial<LeanbaseConfig>) {
|
|
103
|
-
this.setConfig(
|
|
104
|
-
extend(defaultConfig(), config, {
|
|
105
|
-
token,
|
|
106
|
-
})
|
|
107
|
-
)
|
|
108
|
-
this.isLoaded = true
|
|
109
|
-
this.persistence = new LeanbasePersistence(this.config)
|
|
110
|
-
this.replayAutocapture = new Autocapture(this)
|
|
111
|
-
this.replayAutocapture.startIfEnabled()
|
|
112
|
-
|
|
113
|
-
if (this.config.preloadFeatureFlags !== false) {
|
|
114
|
-
this.reloadFeatureFlags()
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
this.config.loaded?.(this)
|
|
118
|
-
if (this.config.capture_pageview) {
|
|
119
|
-
setTimeout(() => {
|
|
120
|
-
if (this.config.cookieless_mode === 'always') {
|
|
121
|
-
this.captureInitialPageview()
|
|
122
|
-
}
|
|
123
|
-
}, 1)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
addEventListener(document, 'DOMContentLoaded', () => {
|
|
127
|
-
this.loadRemoteConfig()
|
|
128
|
-
})
|
|
129
|
-
addEventListener(window, 'onpagehide' in self ? 'pagehide' : 'unload', this.capturePageLeave.bind(this), {
|
|
130
|
-
passive: false,
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
captureInitialPageview(): void {
|
|
135
|
-
if (!document) {
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (document.visibilityState !== 'visible') {
|
|
140
|
-
if (!this.visibilityStateListener) {
|
|
141
|
-
this.visibilityStateListener = this.captureInitialPageview.bind(this)
|
|
142
|
-
addEventListener(document, 'visibilitychange', this.visibilityStateListener)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (!this.initialPageviewCaptured) {
|
|
149
|
-
this.initialPageviewCaptured = true
|
|
150
|
-
this.capture('$pageview', { title: document.title })
|
|
151
|
-
|
|
152
|
-
if (this.visibilityStateListener) {
|
|
153
|
-
document.removeEventListener('visibilitychange', this.visibilityStateListener)
|
|
154
|
-
this.visibilityStateListener = null
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
capturePageLeave() {
|
|
160
|
-
const { capture_pageleave, capture_pageview } = this.config
|
|
161
|
-
if (
|
|
162
|
-
capture_pageleave === true ||
|
|
163
|
-
(capture_pageleave === 'if_capture_pageview' &&
|
|
164
|
-
(capture_pageview === true || capture_pageview === 'history_change'))
|
|
165
|
-
) {
|
|
166
|
-
this.capture('$pageleave')
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async loadRemoteConfig() {
|
|
171
|
-
if (!this.isRemoteConfigLoaded) {
|
|
172
|
-
const remoteConfig = await this.reloadRemoteConfigAsync()
|
|
173
|
-
if (remoteConfig) {
|
|
174
|
-
this.onRemoteConfig(remoteConfig as RemoteConfig)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
onRemoteConfig(config: RemoteConfig): void {
|
|
180
|
-
if (!(document && document.body)) {
|
|
181
|
-
setTimeout(() => {
|
|
182
|
-
this.onRemoteConfig(config)
|
|
183
|
-
}, 500)
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
this.isRemoteConfigLoaded = true
|
|
188
|
-
this.replayAutocapture?.onRemoteConfig(config)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
fetch(url: string, options: PostHogFetchOptions): Promise<PostHogFetchResponse> {
|
|
192
|
-
const fetchFn = getFetch()
|
|
193
|
-
if (!fetchFn) {
|
|
194
|
-
return Promise.reject(new Error('Fetch API is not available in this environment.'))
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return fetchFn(url, options)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
setConfig(config: Partial<LeanbaseConfig>): void {
|
|
201
|
-
const oldConfig = { ...this.config }
|
|
202
|
-
if (isObject(config)) {
|
|
203
|
-
extend(this.config, config)
|
|
204
|
-
this.persistence?.update_config(this.config, oldConfig)
|
|
205
|
-
this.replayAutocapture?.startIfEnabled()
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const isTempStorage = this.config.persistence === 'sessionStorage' || this.config.persistence === 'memory'
|
|
209
|
-
this.sessionPersistence = isTempStorage
|
|
210
|
-
? this.persistence
|
|
211
|
-
: new LeanbasePersistence({ ...this.config, persistence: 'sessionStorage' })
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
getLibraryId(): string {
|
|
215
|
-
return 'leanbase'
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
getLibraryVersion(): string {
|
|
219
|
-
return Config.LIB_VERSION
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
getCustomUserAgent(): void {
|
|
223
|
-
return
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
getPersistedProperty<T>(key: PostHogPersistedProperty): T | undefined {
|
|
227
|
-
return this.persistence?.get_property(key)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
setPersistedProperty<T>(key: PostHogPersistedProperty, value: T | null): void {
|
|
231
|
-
this.persistence?.set_property(key, value)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
calculateEventProperties(
|
|
235
|
-
eventName: string,
|
|
236
|
-
eventProperties: PostHogEventProperties,
|
|
237
|
-
timestamp: Date,
|
|
238
|
-
uuid: string,
|
|
239
|
-
readOnly?: boolean
|
|
240
|
-
): Properties {
|
|
241
|
-
if (!this.persistence || !this.sessionPersistence) {
|
|
242
|
-
return eventProperties
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
timestamp = timestamp || new Date()
|
|
246
|
-
const startTimestamp = readOnly ? undefined : this.persistence?.remove_event_timer(eventName)
|
|
247
|
-
let properties = { ...eventProperties }
|
|
248
|
-
properties['token'] = this.config.token
|
|
249
|
-
if (this.config.cookieless_mode == 'always' || this.config.cookieless_mode == 'on_reject') {
|
|
250
|
-
properties[COOKIELESS_MODE_FLAG_PROPERTY] = true
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (eventName === '$snapshot') {
|
|
254
|
-
const persistenceProps = { ...this.persistence.properties() }
|
|
255
|
-
properties['distinct_id'] = persistenceProps.distinct_id
|
|
256
|
-
if (
|
|
257
|
-
!(isString(properties['distinct_id']) || isNumber(properties['distinct_id'])) ||
|
|
258
|
-
isEmptyString(properties['distinct_id'])
|
|
259
|
-
) {
|
|
260
|
-
logger.error('Invalid distinct_id for replay event. This indicates a bug in your implementation')
|
|
261
|
-
}
|
|
262
|
-
return properties
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const infoProperties = getEventProperties(
|
|
266
|
-
this.config.mask_personal_data_properties,
|
|
267
|
-
this.config.custom_personal_data_properties
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
if (this.sessionManager) {
|
|
271
|
-
const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId(
|
|
272
|
-
readOnly,
|
|
273
|
-
timestamp.getTime()
|
|
274
|
-
)
|
|
275
|
-
properties['$session_id'] = sessionId
|
|
276
|
-
properties['$window_id'] = windowId
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (this.sessionPropsManager) {
|
|
280
|
-
extend(properties, this.sessionPropsManager.getSessionProps())
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
let pageviewProperties: Record<string, any> = this.pageViewManager.doEvent()
|
|
284
|
-
if (eventName === '$pageview' && !readOnly) {
|
|
285
|
-
pageviewProperties = this.pageViewManager.doPageView(timestamp, uuid)
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (eventName === '$pageleave' && !readOnly) {
|
|
289
|
-
pageviewProperties = this.pageViewManager.doPageLeave(timestamp)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
properties = extend(properties, pageviewProperties)
|
|
293
|
-
|
|
294
|
-
if (eventName === '$pageview' && document) {
|
|
295
|
-
properties['title'] = document.title
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (!isUndefined(startTimestamp)) {
|
|
299
|
-
const duration_in_ms = timestamp.getTime() - startTimestamp
|
|
300
|
-
properties['$duration'] = parseFloat((duration_in_ms / 1000).toFixed(3))
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (userAgent && this.config.opt_out_useragent_filter) {
|
|
304
|
-
properties['$browser_type'] = isLikelyBot(navigator, []) ? 'bot' : 'browser'
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
properties = extend(
|
|
308
|
-
{},
|
|
309
|
-
infoProperties,
|
|
310
|
-
this.persistence.properties(),
|
|
311
|
-
this.sessionPersistence.properties(),
|
|
312
|
-
properties
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
properties['$is_identified'] = this.isIdentified()
|
|
316
|
-
return properties
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
isIdentified(): boolean {
|
|
320
|
-
return (
|
|
321
|
-
this.persistence?.get_property(USER_STATE) === 'identified' ||
|
|
322
|
-
this.sessionPersistence?.get_property(USER_STATE) === 'identified'
|
|
323
|
-
)
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Add additional set_once properties to the event when creating a person profile. This allows us to create the
|
|
328
|
-
* profile with mostly-accurate properties, despite earlier events not setting them. We do this by storing them in
|
|
329
|
-
* persistence.
|
|
330
|
-
* @param dataSetOnce
|
|
331
|
-
*/
|
|
332
|
-
calculateSetOnceProperties(dataSetOnce?: Properties): Properties | undefined {
|
|
333
|
-
if (!this.persistence) {
|
|
334
|
-
return dataSetOnce
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (this.personProcessingSetOncePropertiesSent) {
|
|
338
|
-
return dataSetOnce
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const initialProps = this.persistence.get_initial_props()
|
|
342
|
-
const sessionProps = this.sessionPropsManager?.getSetOnceProps()
|
|
343
|
-
const setOnceProperties = extend({}, initialProps, sessionProps || {}, dataSetOnce || {})
|
|
344
|
-
this.personProcessingSetOncePropertiesSent = true
|
|
345
|
-
if (isEmptyObject(setOnceProperties)) {
|
|
346
|
-
return undefined
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return setOnceProperties
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
capture(event: string, properties?: PostHogEventProperties, options?: LeanbaseCaptureOptions): void {
|
|
353
|
-
if (!this.isLoaded || !this.sessionPersistence || !this.persistence) {
|
|
354
|
-
return
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (isUndefined(event) || !isString(event)) {
|
|
358
|
-
logger.error('No event name provided to posthog.capture')
|
|
359
|
-
return
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (properties?.$current_url && !isString(properties?.$current_url)) {
|
|
363
|
-
logger.error(
|
|
364
|
-
'Invalid `$current_url` property provided to `posthog.capture`. Input must be a string. Ignoring provided value.'
|
|
365
|
-
)
|
|
366
|
-
delete properties?.$current_url
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
this.sessionPersistence.update_search_keyword()
|
|
370
|
-
|
|
371
|
-
if (this.config.save_campaign_params) {
|
|
372
|
-
this.sessionPersistence.update_campaign_params()
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (this.config.save_referrer) {
|
|
376
|
-
this.sessionPersistence.update_referrer_info()
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (this.config.save_campaign_params || this.config.save_referrer) {
|
|
380
|
-
this.persistence.set_initial_person_info()
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
const systemTime = new Date()
|
|
384
|
-
const timestamp = options?.timestamp || systemTime
|
|
385
|
-
const uuid = uuidv7()
|
|
386
|
-
let data: CaptureResult = {
|
|
387
|
-
uuid,
|
|
388
|
-
event,
|
|
389
|
-
properties: this.calculateEventProperties(event, properties || {}, timestamp, uuid),
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const setProperties = options?.$set
|
|
393
|
-
if (setProperties) {
|
|
394
|
-
data.$set = options?.$set
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const setOnceProperties = this.calculateSetOnceProperties(options?.$set_once)
|
|
398
|
-
if (setOnceProperties) {
|
|
399
|
-
data.$set_once = setOnceProperties
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
data = copyAndTruncateStrings(data, options?._noTruncate ? null : this.config.properties_string_max_length)
|
|
403
|
-
data.timestamp = timestamp
|
|
404
|
-
if (!isUndefined(options?.timestamp)) {
|
|
405
|
-
data.properties['$event_time_override_provided'] = true
|
|
406
|
-
data.properties['$event_time_override_system_time'] = systemTime
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const finalSet = { ...data.properties['$set'], ...data['$set'] }
|
|
410
|
-
if (!isEmptyObject(finalSet)) {
|
|
411
|
-
this.setPersonPropertiesForFlags(finalSet)
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
super.capture(data.event, data.properties, options)
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
identify(distinctId?: string, properties?: PostHogEventProperties, options?: LeanbaseCaptureOptions): void {
|
|
418
|
-
super.identify(distinctId, properties, options)
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
destroy(): void {
|
|
422
|
-
this.persistence?.clear()
|
|
423
|
-
}
|
|
424
|
-
}
|
package/src/page-view.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { window } from './utils'
|
|
2
|
-
import { Leanbase } from './leanbase'
|
|
3
|
-
import { clampToRange, isUndefined, Logger } from '@posthog/core'
|
|
4
|
-
import { extend } from './utils'
|
|
5
|
-
import { logger } from './leanbase-logger'
|
|
6
|
-
|
|
7
|
-
interface PageViewEventProperties {
|
|
8
|
-
$pageview_id?: string
|
|
9
|
-
$prev_pageview_id?: string
|
|
10
|
-
$prev_pageview_pathname?: string
|
|
11
|
-
$prev_pageview_duration?: number // seconds
|
|
12
|
-
$prev_pageview_last_scroll?: number
|
|
13
|
-
$prev_pageview_last_scroll_percentage?: number
|
|
14
|
-
$prev_pageview_max_scroll?: number
|
|
15
|
-
$prev_pageview_max_scroll_percentage?: number
|
|
16
|
-
$prev_pageview_last_content?: number
|
|
17
|
-
$prev_pageview_last_content_percentage?: number
|
|
18
|
-
$prev_pageview_max_content?: number
|
|
19
|
-
$prev_pageview_max_content_percentage?: number
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// This keeps track of the PageView state (such as the previous PageView's path, timestamp, id, and scroll properties).
|
|
23
|
-
// We store the state in memory, which means that for non-SPA sites, the state will be lost on page reload. This means
|
|
24
|
-
// that non-SPA sites should always send a $pageleave event on any navigation, before the page unloads. For SPA sites,
|
|
25
|
-
// they only need to send a $pageleave event when the user navigates away from the site, as the information is not lost
|
|
26
|
-
// on an internal navigation, and is included as the $prev_pageview_ properties in the next $pageview event.
|
|
27
|
-
|
|
28
|
-
// Practically, this means that to find the scroll properties for a given pageview, you need to find the event where
|
|
29
|
-
// event name is $pageview or $pageleave and where $prev_pageview_id matches the original pageview event's id.
|
|
30
|
-
|
|
31
|
-
export class PageViewManager {
|
|
32
|
-
_currentPageview?: { timestamp: Date; pageViewId: string | undefined; pathname: string | undefined }
|
|
33
|
-
_instance: Leanbase
|
|
34
|
-
|
|
35
|
-
constructor(instance: Leanbase) {
|
|
36
|
-
this._instance = instance
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
doPageView(timestamp: Date, pageViewId?: string): PageViewEventProperties {
|
|
40
|
-
const response = this._previousPageViewProperties(timestamp, pageViewId)
|
|
41
|
-
|
|
42
|
-
// On a pageview we reset the contexts
|
|
43
|
-
this._currentPageview = { pathname: window?.location.pathname ?? '', pageViewId, timestamp }
|
|
44
|
-
this._instance.scrollManager.resetContext()
|
|
45
|
-
|
|
46
|
-
return response
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
doPageLeave(timestamp: Date): PageViewEventProperties {
|
|
50
|
-
return this._previousPageViewProperties(timestamp, this._currentPageview?.pageViewId)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
doEvent(): PageViewEventProperties {
|
|
54
|
-
return { $pageview_id: this._currentPageview?.pageViewId }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private _previousPageViewProperties(timestamp: Date, pageviewId: string | undefined): PageViewEventProperties {
|
|
58
|
-
const previousPageView = this._currentPageview
|
|
59
|
-
|
|
60
|
-
if (!previousPageView) {
|
|
61
|
-
return { $pageview_id: pageviewId }
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let properties: PageViewEventProperties = {
|
|
65
|
-
$pageview_id: pageviewId,
|
|
66
|
-
$prev_pageview_id: previousPageView.pageViewId,
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const scrollContext = this._instance.scrollManager.getContext()
|
|
70
|
-
|
|
71
|
-
if (scrollContext && !this._instance.config.disable_scroll_properties) {
|
|
72
|
-
let { maxScrollHeight, lastScrollY, maxScrollY, maxContentHeight, lastContentY, maxContentY } =
|
|
73
|
-
scrollContext
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
!isUndefined(maxScrollHeight) &&
|
|
77
|
-
!isUndefined(lastScrollY) &&
|
|
78
|
-
!isUndefined(maxScrollY) &&
|
|
79
|
-
!isUndefined(maxContentHeight) &&
|
|
80
|
-
!isUndefined(lastContentY) &&
|
|
81
|
-
!isUndefined(maxContentY)
|
|
82
|
-
) {
|
|
83
|
-
// Use ceil, so that e.g. scrolling 999.5px of a 1000px page is considered 100% scrolled
|
|
84
|
-
maxScrollHeight = Math.ceil(maxScrollHeight)
|
|
85
|
-
lastScrollY = Math.ceil(lastScrollY)
|
|
86
|
-
maxScrollY = Math.ceil(maxScrollY)
|
|
87
|
-
maxContentHeight = Math.ceil(maxContentHeight)
|
|
88
|
-
lastContentY = Math.ceil(lastContentY)
|
|
89
|
-
maxContentY = Math.ceil(maxContentY)
|
|
90
|
-
|
|
91
|
-
// if the maximum scroll height is near 0, then the percentage is 1
|
|
92
|
-
const lastScrollPercentage =
|
|
93
|
-
maxScrollHeight <= 1 ? 1 : clampToRange(lastScrollY / maxScrollHeight, 0, 1, logger as Logger)
|
|
94
|
-
const maxScrollPercentage =
|
|
95
|
-
maxScrollHeight <= 1 ? 1 : clampToRange(maxScrollY / maxScrollHeight, 0, 1, logger as Logger)
|
|
96
|
-
const lastContentPercentage =
|
|
97
|
-
maxContentHeight <= 1 ? 1 : clampToRange(lastContentY / maxContentHeight, 0, 1, logger as Logger)
|
|
98
|
-
const maxContentPercentage =
|
|
99
|
-
maxContentHeight <= 1 ? 1 : clampToRange(maxContentY / maxContentHeight, 0, 1, logger as Logger)
|
|
100
|
-
|
|
101
|
-
properties = extend(properties, {
|
|
102
|
-
$prev_pageview_last_scroll: lastScrollY,
|
|
103
|
-
$prev_pageview_last_scroll_percentage: lastScrollPercentage,
|
|
104
|
-
$prev_pageview_max_scroll: maxScrollY,
|
|
105
|
-
$prev_pageview_max_scroll_percentage: maxScrollPercentage,
|
|
106
|
-
$prev_pageview_last_content: lastContentY,
|
|
107
|
-
$prev_pageview_last_content_percentage: lastContentPercentage,
|
|
108
|
-
$prev_pageview_max_content: maxContentY,
|
|
109
|
-
$prev_pageview_max_content_percentage: maxContentPercentage,
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (previousPageView.pathname) {
|
|
115
|
-
properties.$prev_pageview_pathname = previousPageView.pathname
|
|
116
|
-
}
|
|
117
|
-
if (previousPageView.timestamp) {
|
|
118
|
-
// Use seconds, for consistency with our other duration-related properties like $duration
|
|
119
|
-
properties.$prev_pageview_duration = (timestamp.getTime() - previousPageView.timestamp.getTime()) / 1000
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return properties
|
|
123
|
-
}
|
|
124
|
-
}
|
package/src/scroll-manager.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { window } from './utils'
|
|
2
|
-
import { Leanbase } from './leanbase'
|
|
3
|
-
import { addEventListener } from './utils'
|
|
4
|
-
import { isArray } from '@posthog/core'
|
|
5
|
-
|
|
6
|
-
export interface ScrollContext {
|
|
7
|
-
// scroll is how far down the page the user has scrolled,
|
|
8
|
-
// content is how far down the page the user can view content
|
|
9
|
-
// (e.g. if the page is 1000 tall, but the user's screen is only 500 tall,
|
|
10
|
-
// and they don't scroll at all, then scroll is 0 and content is 500)
|
|
11
|
-
maxScrollHeight?: number
|
|
12
|
-
maxScrollY?: number
|
|
13
|
-
lastScrollY?: number
|
|
14
|
-
maxContentHeight?: number
|
|
15
|
-
maxContentY?: number
|
|
16
|
-
lastContentY?: number
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// This class is responsible for tracking scroll events and maintaining the scroll context
|
|
20
|
-
export class ScrollManager {
|
|
21
|
-
private _context: ScrollContext | undefined
|
|
22
|
-
|
|
23
|
-
constructor(private _instance: Leanbase) {}
|
|
24
|
-
|
|
25
|
-
getContext(): ScrollContext | undefined {
|
|
26
|
-
return this._context
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
resetContext(): ScrollContext | undefined {
|
|
30
|
-
const ctx = this._context
|
|
31
|
-
|
|
32
|
-
// update the scroll properties for the new page, but wait until the next tick
|
|
33
|
-
// of the event loop
|
|
34
|
-
setTimeout(this._updateScrollData, 0)
|
|
35
|
-
|
|
36
|
-
return ctx
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private _updateScrollData = () => {
|
|
40
|
-
if (!this._context) {
|
|
41
|
-
this._context = {}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const el = this.scrollElement()
|
|
45
|
-
|
|
46
|
-
const scrollY = this.scrollY()
|
|
47
|
-
const scrollHeight = el ? Math.max(0, el.scrollHeight - el.clientHeight) : 0
|
|
48
|
-
const contentY = scrollY + (el?.clientHeight || 0)
|
|
49
|
-
const contentHeight = el?.scrollHeight || 0
|
|
50
|
-
|
|
51
|
-
this._context.lastScrollY = Math.ceil(scrollY)
|
|
52
|
-
this._context.maxScrollY = Math.max(scrollY, this._context.maxScrollY ?? 0)
|
|
53
|
-
this._context.maxScrollHeight = Math.max(scrollHeight, this._context.maxScrollHeight ?? 0)
|
|
54
|
-
|
|
55
|
-
this._context.lastContentY = contentY
|
|
56
|
-
this._context.maxContentY = Math.max(contentY, this._context.maxContentY ?? 0)
|
|
57
|
-
this._context.maxContentHeight = Math.max(contentHeight, this._context.maxContentHeight ?? 0)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// `capture: true` is required to get scroll events for other scrollable elements
|
|
61
|
-
// on the page, not just the window
|
|
62
|
-
// see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#usecapture
|
|
63
|
-
startMeasuringScrollPosition() {
|
|
64
|
-
addEventListener(window, 'scroll', this._updateScrollData, { capture: true })
|
|
65
|
-
addEventListener(window, 'scrollend', this._updateScrollData, { capture: true })
|
|
66
|
-
addEventListener(window, 'resize', this._updateScrollData)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public scrollElement(): Element | undefined {
|
|
70
|
-
if (this._instance.config.scroll_root_selector) {
|
|
71
|
-
const selectors = isArray(this._instance.config.scroll_root_selector)
|
|
72
|
-
? this._instance.config.scroll_root_selector
|
|
73
|
-
: [this._instance.config.scroll_root_selector]
|
|
74
|
-
for (const selector of selectors) {
|
|
75
|
-
const element = window?.document.querySelector(selector)
|
|
76
|
-
if (element) {
|
|
77
|
-
return element
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return undefined
|
|
81
|
-
} else {
|
|
82
|
-
return window?.document.documentElement
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
public scrollY(): number {
|
|
87
|
-
if (this._instance.config.scroll_root_selector) {
|
|
88
|
-
const element = this.scrollElement()
|
|
89
|
-
return (element && element.scrollTop) || 0
|
|
90
|
-
} else {
|
|
91
|
-
return window ? window.scrollY || window.pageYOffset || window.document.documentElement.scrollTop || 0 : 0
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
public scrollX(): number {
|
|
96
|
-
if (this._instance.config.scroll_root_selector) {
|
|
97
|
-
const element = this.scrollElement()
|
|
98
|
-
return (element && element.scrollLeft) || 0
|
|
99
|
-
} else {
|
|
100
|
-
return window ? window.scrollX || window.pageXOffset || window.document.documentElement.scrollLeft || 0 : 0
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|