@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.
Files changed (136) hide show
  1. package/dist/autocapture-utils.d.ts +17 -0
  2. package/dist/autocapture.d.ts +35 -0
  3. package/dist/config.d.ts +5 -0
  4. package/dist/constants.d.ts +54 -0
  5. package/dist/entrypoints/main.cjs.d.ts +4 -0
  6. package/dist/entrypoints/module.es.d.ts +4 -0
  7. package/dist/extensions/rageclick.d.ts +9 -0
  8. package/dist/iife.d.ts +19 -0
  9. package/dist/index.d.ts +2 -779
  10. package/dist/leanbase-logger.d.ts +6 -0
  11. package/dist/leanbase-persistence.d.ts +64 -0
  12. package/dist/leanbase.d.ts +49 -0
  13. package/dist/leanbase.iife.js +1 -4745
  14. package/dist/leanbase.iife.js.map +1 -1
  15. package/dist/main.js +2 -0
  16. package/dist/main.js.map +1 -0
  17. package/dist/module.d.ts +780 -0
  18. package/dist/module.js +2 -0
  19. package/dist/module.js.map +1 -0
  20. package/dist/page-view.d.ts +29 -0
  21. package/dist/scroll-manager.d.ts +21 -0
  22. package/dist/session-props.d.ts +32 -0
  23. package/dist/sessionid.d.ts +50 -0
  24. package/dist/storage.d.ts +24 -0
  25. package/{src/types.ts → dist/types.d.ts} +145 -235
  26. package/dist/utils/blocked-uas.d.ts +17 -0
  27. package/dist/utils/element-utils.d.ts +5 -0
  28. package/dist/utils/event-utils.d.ts +22 -0
  29. package/dist/utils/index.d.ts +44 -0
  30. package/dist/utils/request-utils.d.ts +12 -0
  31. package/dist/utils/simple-event-emitter.d.ts +6 -0
  32. package/dist/utils/user-agent-utils.d.ts +18 -0
  33. package/dist/uuidv7.d.ts +43 -0
  34. package/dist/version.d.ts +1 -0
  35. package/lib/autocapture-utils.d.ts +17 -0
  36. package/{src/autocapture-utils.ts → lib/autocapture-utils.js} +196 -280
  37. package/lib/autocapture-utils.js.map +1 -0
  38. package/lib/autocapture.d.ts +35 -0
  39. package/lib/autocapture.js +311 -0
  40. package/lib/autocapture.js.map +1 -0
  41. package/lib/config.d.ts +5 -0
  42. package/lib/config.js +7 -0
  43. package/lib/config.js.map +1 -0
  44. package/lib/constants.d.ts +54 -0
  45. package/{src/constants.ts → lib/constants.js} +58 -55
  46. package/lib/constants.js.map +1 -0
  47. package/lib/entrypoints/main.cjs.d.ts +4 -0
  48. package/lib/entrypoints/main.cjs.js +3 -0
  49. package/lib/entrypoints/main.cjs.js.map +1 -0
  50. package/lib/entrypoints/module.es.d.ts +4 -0
  51. package/lib/entrypoints/module.es.js +3 -0
  52. package/lib/entrypoints/module.es.js.map +1 -0
  53. package/lib/extensions/rageclick.d.ts +9 -0
  54. package/lib/extensions/rageclick.js +27 -0
  55. package/lib/extensions/rageclick.js.map +1 -0
  56. package/lib/iife.d.ts +19 -0
  57. package/lib/iife.js +67 -0
  58. package/lib/iife.js.map +1 -0
  59. package/{src/index.ts → lib/index.d.ts} +2 -2
  60. package/lib/index.js +2 -0
  61. package/lib/index.js.map +1 -0
  62. package/lib/leanbase-logger.d.ts +6 -0
  63. package/lib/leanbase-logger.js +25 -0
  64. package/lib/leanbase-logger.js.map +1 -0
  65. package/lib/leanbase-persistence.d.ts +64 -0
  66. package/lib/leanbase-persistence.js +287 -0
  67. package/lib/leanbase-persistence.js.map +1 -0
  68. package/lib/leanbase.d.ts +49 -0
  69. package/lib/leanbase.js +294 -0
  70. package/lib/leanbase.js.map +1 -0
  71. package/lib/page-view.d.ts +29 -0
  72. package/lib/page-view.js +81 -0
  73. package/lib/page-view.js.map +1 -0
  74. package/lib/scroll-manager.d.ts +21 -0
  75. package/lib/scroll-manager.js +79 -0
  76. package/lib/scroll-manager.js.map +1 -0
  77. package/lib/session-props.d.ts +32 -0
  78. package/lib/session-props.js +73 -0
  79. package/lib/session-props.js.map +1 -0
  80. package/lib/sessionid.d.ts +50 -0
  81. package/{src/sessionid.ts → lib/sessionid.js} +128 -204
  82. package/lib/sessionid.js.map +1 -0
  83. package/lib/storage.d.ts +24 -0
  84. package/{src/storage.ts → lib/storage.js} +182 -225
  85. package/lib/storage.js.map +1 -0
  86. package/lib/types.d.ts +544 -0
  87. package/lib/types.js +7 -0
  88. package/lib/types.js.map +1 -0
  89. package/lib/utils/blocked-uas.d.ts +17 -0
  90. package/{src/utils/blocked-uas.ts → lib/utils/blocked-uas.js} +19 -48
  91. package/lib/utils/blocked-uas.js.map +1 -0
  92. package/lib/utils/element-utils.d.ts +5 -0
  93. package/{src/utils/element-utils.ts → lib/utils/element-utils.js} +13 -17
  94. package/lib/utils/element-utils.js.map +1 -0
  95. package/lib/utils/event-utils.d.ts +22 -0
  96. package/lib/utils/event-utils.js +258 -0
  97. package/lib/utils/event-utils.js.map +1 -0
  98. package/lib/utils/index.d.ts +44 -0
  99. package/lib/utils/index.js +183 -0
  100. package/lib/utils/index.js.map +1 -0
  101. package/lib/utils/request-utils.d.ts +12 -0
  102. package/lib/utils/request-utils.js +107 -0
  103. package/lib/utils/request-utils.js.map +1 -0
  104. package/lib/utils/simple-event-emitter.d.ts +6 -0
  105. package/lib/utils/simple-event-emitter.js +24 -0
  106. package/lib/utils/simple-event-emitter.js.map +1 -0
  107. package/lib/utils/user-agent-utils.d.ts +18 -0
  108. package/lib/utils/user-agent-utils.js +369 -0
  109. package/lib/utils/user-agent-utils.js.map +1 -0
  110. package/lib/uuidv7.d.ts +43 -0
  111. package/{src/uuidv7.ts → lib/uuidv7.js} +103 -131
  112. package/lib/uuidv7.js.map +1 -0
  113. package/lib/version.d.ts +1 -0
  114. package/lib/version.js +2 -0
  115. package/lib/version.js.map +1 -0
  116. package/package.json +23 -11
  117. package/dist/index.cjs +0 -3032
  118. package/dist/index.cjs.map +0 -1
  119. package/dist/index.mjs +0 -3030
  120. package/dist/index.mjs.map +0 -1
  121. package/src/autocapture.ts +0 -415
  122. package/src/config.ts +0 -8
  123. package/src/extensions/rageclick.ts +0 -34
  124. package/src/iife.ts +0 -87
  125. package/src/leanbase-logger.ts +0 -26
  126. package/src/leanbase-persistence.ts +0 -374
  127. package/src/leanbase.ts +0 -424
  128. package/src/page-view.ts +0 -124
  129. package/src/scroll-manager.ts +0 -103
  130. package/src/session-props.ts +0 -114
  131. package/src/utils/event-utils.ts +0 -304
  132. package/src/utils/index.ts +0 -222
  133. package/src/utils/request-utils.ts +0 -128
  134. package/src/utils/simple-event-emitter.ts +0 -27
  135. package/src/utils/user-agent-utils.ts +0 -357
  136. package/src/version.ts +0 -1
@@ -1,415 +0,0 @@
1
- import { addEventListener, each, extend } from './utils'
2
- import {
3
- autocaptureCompatibleElements,
4
- getClassNames,
5
- getDirectAndNestedSpanText,
6
- getElementsChainString,
7
- getEventTarget,
8
- getSafeText,
9
- isAngularStyleAttr,
10
- isSensitiveElement,
11
- makeSafeText,
12
- shouldCaptureDomEvent,
13
- shouldCaptureElement,
14
- shouldCaptureRageclick,
15
- shouldCaptureValue,
16
- splitClassString,
17
- } from './autocapture-utils'
18
-
19
- import RageClick from './extensions/rageclick'
20
- import { AutocaptureConfig, COPY_AUTOCAPTURE_EVENT, EventName, Properties, RemoteConfig } from './types'
21
- import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from './constants'
22
-
23
- import { isBoolean, isFunction, isNull, isObject } from '@posthog/core'
24
- import { document, window } from './utils'
25
- import { convertToURL } from './utils/request-utils'
26
- import { isDocumentFragment, isElementNode, isTag, isTextNode } from './utils/element-utils'
27
- import { includes } from '@posthog/core'
28
- import { logger } from './leanbase-logger'
29
- import { Leanbase } from './leanbase'
30
-
31
- function limitText(length: number, text: string): string {
32
- if (text.length > length) {
33
- return text.slice(0, length) + '...'
34
- }
35
- return text
36
- }
37
-
38
- export function getAugmentPropertiesFromElement(elem: Element): Properties {
39
- const shouldCaptureEl = shouldCaptureElement(elem)
40
- if (!shouldCaptureEl) {
41
- return {}
42
- }
43
-
44
- const props: Properties = {}
45
-
46
- each(elem.attributes, function (attr: Attr) {
47
- if (attr.name && attr.name.indexOf('data-ph-capture-attribute') === 0) {
48
- const propertyKey = attr.name.replace('data-ph-capture-attribute-', '')
49
- const propertyValue = attr.value
50
- if (propertyKey && propertyValue && shouldCaptureValue(propertyValue)) {
51
- props[propertyKey] = propertyValue
52
- }
53
- }
54
- })
55
-
56
- return props
57
- }
58
-
59
- export function previousElementSibling(el: Element): Element | null {
60
- if (el.previousElementSibling) {
61
- return el.previousElementSibling
62
- }
63
- let _el: Element | null = el
64
- do {
65
- _el = _el.previousSibling as Element | null // resolves to ChildNode->Node, which is Element's parent class
66
- } while (_el && !isElementNode(_el))
67
- return _el
68
- }
69
-
70
- export function getDefaultProperties(eventType: string): Properties {
71
- return {
72
- $event_type: eventType,
73
- $ce_version: 1,
74
- }
75
- }
76
-
77
- export function getPropertiesFromElement(
78
- elem: Element,
79
- maskAllAttributes: boolean,
80
- maskText: boolean,
81
- elementAttributeIgnorelist: string[] | undefined
82
- ): Properties {
83
- const tag_name = elem.tagName.toLowerCase()
84
- const props: Properties = {
85
- tag_name: tag_name,
86
- }
87
- if (autocaptureCompatibleElements.indexOf(tag_name) > -1 && !maskText) {
88
- if (tag_name.toLowerCase() === 'a' || tag_name.toLowerCase() === 'button') {
89
- props['$el_text'] = limitText(1024, getDirectAndNestedSpanText(elem))
90
- } else {
91
- props['$el_text'] = limitText(1024, getSafeText(elem))
92
- }
93
- }
94
-
95
- const classes = getClassNames(elem)
96
- if (classes.length > 0)
97
- props['classes'] = classes.filter(function (c) {
98
- return c !== ''
99
- })
100
-
101
- // capture the deny list here because this not-a-class class makes it tricky to use this.config in the function below
102
- each(elem.attributes, function (attr: Attr) {
103
- // Only capture attributes we know are safe
104
- if (isSensitiveElement(elem) && ['name', 'id', 'class', 'aria-label'].indexOf(attr.name) === -1) return
105
-
106
- if (elementAttributeIgnorelist?.includes(attr.name)) return
107
-
108
- if (!maskAllAttributes && shouldCaptureValue(attr.value) && !isAngularStyleAttr(attr.name)) {
109
- let value = attr.value
110
- if (attr.name === 'class') {
111
- // html attributes can _technically_ contain linebreaks,
112
- // but we're very intolerant of them in the class string,
113
- // so we strip them.
114
- value = splitClassString(value).join(' ')
115
- }
116
- props['attr__' + attr.name] = limitText(1024, value)
117
- }
118
- })
119
-
120
- let nthChild = 1
121
- let nthOfType = 1
122
- let currentElem: Element | null = elem
123
- while ((currentElem = previousElementSibling(currentElem))) {
124
- // eslint-disable-line no-cond-assign
125
- nthChild++
126
- if (currentElem.tagName === elem.tagName) {
127
- nthOfType++
128
- }
129
- }
130
- props['nth_child'] = nthChild
131
- props['nth_of_type'] = nthOfType
132
-
133
- return props
134
- }
135
-
136
- export function autocapturePropertiesForElement(
137
- target: Element,
138
- {
139
- e,
140
- maskAllElementAttributes,
141
- maskAllText,
142
- elementAttributeIgnoreList,
143
- elementsChainAsString,
144
- }: {
145
- e: Event
146
- maskAllElementAttributes: boolean
147
- maskAllText: boolean
148
- elementAttributeIgnoreList?: string[] | undefined
149
- elementsChainAsString: boolean
150
- }
151
- ): { props: Properties; explicitNoCapture?: boolean } {
152
- const targetElementList = [target]
153
- let curEl = target
154
- while (curEl.parentNode && !isTag(curEl, 'body')) {
155
- if (isDocumentFragment(curEl.parentNode)) {
156
- targetElementList.push((curEl.parentNode as any).host)
157
- curEl = (curEl.parentNode as any).host
158
- continue
159
- }
160
- targetElementList.push(curEl.parentNode as Element)
161
- curEl = curEl.parentNode as Element
162
- }
163
-
164
- const elementsJson: Properties[] = []
165
- const autocaptureAugmentProperties: Properties = {}
166
- let href: string | false = false
167
- let explicitNoCapture = false
168
-
169
- each(targetElementList, (el) => {
170
- const shouldCaptureEl = shouldCaptureElement(el)
171
-
172
- // if the element or a parent element is an anchor tag
173
- // include the href as a property
174
- if (el.tagName.toLowerCase() === 'a') {
175
- href = el.getAttribute('href')
176
- href = shouldCaptureEl && href && shouldCaptureValue(href) && href
177
- }
178
-
179
- // allow users to programmatically prevent capturing of elements by adding class 'ph-no-capture'
180
- const classes = getClassNames(el)
181
- if (includes(classes, 'ph-no-capture')) {
182
- explicitNoCapture = true
183
- }
184
-
185
- elementsJson.push(
186
- getPropertiesFromElement(el, maskAllElementAttributes, maskAllText, elementAttributeIgnoreList)
187
- )
188
-
189
- const augmentProperties = getAugmentPropertiesFromElement(el)
190
- extend(autocaptureAugmentProperties, augmentProperties)
191
- })
192
-
193
- if (explicitNoCapture) {
194
- return { props: {}, explicitNoCapture }
195
- }
196
-
197
- if (!maskAllText) {
198
- // if the element is a button or anchor tag get the span text from any
199
- // children and include it as/with the text property on the parent element
200
- if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'button') {
201
- elementsJson[0]['$el_text'] = getDirectAndNestedSpanText(target)
202
- } else {
203
- elementsJson[0]['$el_text'] = getSafeText(target)
204
- }
205
- }
206
-
207
- let externalHref: string | undefined
208
- if (href) {
209
- elementsJson[0]['attr__href'] = href
210
- const hrefHost = convertToURL(href)?.host
211
- const locationHost = window?.location?.host
212
- if (hrefHost && locationHost && hrefHost !== locationHost) {
213
- externalHref = href
214
- }
215
- }
216
-
217
- const props = extend(
218
- getDefaultProperties(e.type),
219
- // Sending "$elements" is deprecated. Only one client on US cloud uses this.
220
- !elementsChainAsString ? { $elements: elementsJson } : {},
221
- // Always send $elements_chain, as it's needed downstream in site app filtering
222
- { $elements_chain: getElementsChainString(elementsJson) },
223
- elementsJson[0]?.['$el_text'] ? { $el_text: elementsJson[0]?.['$el_text'] } : {},
224
- externalHref && e.type === 'click' ? { $external_click_url: externalHref } : {},
225
- autocaptureAugmentProperties
226
- )
227
-
228
- return { props }
229
- }
230
-
231
- export class Autocapture {
232
- instance: Leanbase
233
- _initialized: boolean = false
234
- _isDisabledServerSide: boolean | null = null
235
- _elementSelectors: Set<string> | null
236
- rageclicks = new RageClick()
237
- _elementsChainAsString = false
238
-
239
- constructor(instance: Leanbase) {
240
- this.instance = instance
241
- this._elementSelectors = null
242
- }
243
-
244
- private get _config(): AutocaptureConfig {
245
- const config = isObject(this.instance.config.autocapture) ? this.instance.config.autocapture : {}
246
- // precompile the regex
247
- config.url_allowlist = config.url_allowlist?.map((url) => new RegExp(url))
248
- config.url_ignorelist = config.url_ignorelist?.map((url) => new RegExp(url))
249
- return config
250
- }
251
-
252
- _addDomEventHandlers(): void {
253
- if (!this.isBrowserSupported()) {
254
- logger.info('Disabling Automatic Event Collection because this browser is not supported')
255
- return
256
- }
257
-
258
- if (!window || !document) {
259
- return
260
- }
261
-
262
- const handler = (e: Event) => {
263
- e = e || window?.event
264
- try {
265
- this._captureEvent(e)
266
- } catch (error) {
267
- logger.error('Failed to capture event', error)
268
- }
269
- }
270
-
271
- addEventListener(document, 'submit', handler, { capture: true })
272
- addEventListener(document, 'change', handler, { capture: true })
273
- addEventListener(document, 'click', handler, { capture: true })
274
-
275
- if (this._config.capture_copied_text) {
276
- const copiedTextHandler = (e: Event) => {
277
- e = e || window?.event
278
- this._captureEvent(e, COPY_AUTOCAPTURE_EVENT)
279
- }
280
-
281
- addEventListener(document, 'copy', copiedTextHandler, { capture: true })
282
- addEventListener(document, 'cut', copiedTextHandler, { capture: true })
283
- }
284
- }
285
-
286
- public startIfEnabled() {
287
- if (this.isEnabled && !this._initialized) {
288
- this._addDomEventHandlers()
289
- this._initialized = true
290
- }
291
- }
292
-
293
- public onRemoteConfig(response: RemoteConfig) {
294
- if (response.elementsChainAsString) {
295
- this._elementsChainAsString = response.elementsChainAsString
296
- }
297
-
298
- if (this.instance.persistence) {
299
- this.instance.persistence.register({
300
- [AUTOCAPTURE_DISABLED_SERVER_SIDE]: !!response['autocapture_opt_out'],
301
- })
302
- }
303
-
304
- this._isDisabledServerSide = !!response['autocapture_opt_out']
305
- this.startIfEnabled()
306
- }
307
-
308
- public setElementSelectors(selectors: Set<string>): void {
309
- this._elementSelectors = selectors
310
- }
311
-
312
- public getElementSelectors(element: Element | null): string[] | null {
313
- const elementSelectors: string[] = []
314
-
315
- this._elementSelectors?.forEach((selector) => {
316
- const matchedElements = document?.querySelectorAll(selector)
317
- matchedElements?.forEach((matchedElement: Element) => {
318
- if (element === matchedElement) {
319
- elementSelectors.push(selector)
320
- }
321
- })
322
- })
323
-
324
- return elementSelectors
325
- }
326
-
327
- public get isEnabled(): boolean {
328
- const persistedServerDisabled = this.instance.persistence?.props[AUTOCAPTURE_DISABLED_SERVER_SIDE]
329
- const memoryDisabled = this._isDisabledServerSide
330
-
331
- if (isNull(memoryDisabled) && !isBoolean(persistedServerDisabled)) {
332
- return false
333
- }
334
-
335
- const disabledServer = this._isDisabledServerSide ?? !!persistedServerDisabled
336
- const disabledClient = !this.instance.config.autocapture
337
- return !disabledClient && !disabledServer
338
- }
339
-
340
- private _captureEvent(e: Event, eventName: EventName = '$autocapture'): boolean | void {
341
- if (!this.isEnabled) {
342
- return
343
- }
344
-
345
- /*** Don't mess with this code without running IE8 tests on it ***/
346
- let target = getEventTarget(e)
347
- if (isTextNode(target)) {
348
- // defeat Safari bug (see: http://www.quirksmode.org/js/events_properties.html)
349
- target = (target.parentNode || null) as Element | null
350
- }
351
-
352
- if (eventName === '$autocapture' && e.type === 'click' && e instanceof MouseEvent) {
353
- if (
354
- !!this.instance.config.rageclick &&
355
- this.rageclicks?.isRageClick(e.clientX, e.clientY, new Date().getTime())
356
- ) {
357
- if (shouldCaptureRageclick(target, this.instance.config.rageclick)) {
358
- this._captureEvent(e, '$rageclick')
359
- }
360
- }
361
- }
362
-
363
- const isCopyAutocapture = eventName === COPY_AUTOCAPTURE_EVENT
364
- if (
365
- target &&
366
- shouldCaptureDomEvent(
367
- target,
368
- e,
369
- this._config,
370
- // mostly this method cares about the target element, but in the case of copy events,
371
- // we want some of the work this check does without insisting on the target element's type
372
- isCopyAutocapture,
373
- // we also don't want to restrict copy checks to clicks,
374
- // so we pass that knowledge in here, rather than add the logic inside the check
375
- isCopyAutocapture ? ['copy', 'cut'] : undefined
376
- )
377
- ) {
378
- const { props, explicitNoCapture } = autocapturePropertiesForElement(target, {
379
- e,
380
- maskAllElementAttributes: this.instance.config.mask_all_element_attributes,
381
- maskAllText: this.instance.config.mask_all_text,
382
- elementAttributeIgnoreList: this._config.element_attribute_ignorelist,
383
- elementsChainAsString: this._elementsChainAsString,
384
- })
385
-
386
- if (explicitNoCapture) {
387
- return false
388
- }
389
-
390
- const elementSelectors = this.getElementSelectors(target)
391
- if (elementSelectors && elementSelectors.length > 0) {
392
- props['$element_selectors'] = elementSelectors
393
- }
394
-
395
- if (eventName === COPY_AUTOCAPTURE_EVENT) {
396
- // you can't read the data from the clipboard event,
397
- // but you can guess that you can read it from the window's current selection
398
- const selectedContent = makeSafeText(window?.getSelection()?.toString())
399
- const clipType = (e as ClipboardEvent).type || 'clipboard'
400
- if (!selectedContent) {
401
- return false
402
- }
403
- props['$selected_content'] = selectedContent
404
- props['$copy_type'] = clipType
405
- }
406
-
407
- this.instance.capture(eventName, props)
408
- return true
409
- }
410
- }
411
-
412
- isBrowserSupported(): boolean {
413
- return isFunction(document?.querySelectorAll)
414
- }
415
- }
package/src/config.ts DELETED
@@ -1,8 +0,0 @@
1
- import packageInfo from '../package.json'
2
-
3
- const Config = {
4
- DEBUG: false,
5
- LIB_VERSION: packageInfo.version,
6
- }
7
-
8
- export default Config
@@ -1,34 +0,0 @@
1
- // Naive rage click implementation: If mouse has not moved further than RAGE_CLICK_THRESHOLD_PX
2
- // over RAGE_CLICK_CLICK_COUNT clicks with max RAGE_CLICK_TIMEOUT_MS between clicks, it's
3
- // counted as a rage click
4
-
5
- const RAGE_CLICK_THRESHOLD_PX = 30
6
- const RAGE_CLICK_TIMEOUT_MS = 1000
7
- const RAGE_CLICK_CLICK_COUNT = 3
8
-
9
- export default class RageClick {
10
- clicks: { x: number; y: number; timestamp: number }[]
11
-
12
- constructor() {
13
- this.clicks = []
14
- }
15
-
16
- isRageClick(x: number, y: number, timestamp: number): boolean {
17
- const lastClick = this.clicks[this.clicks.length - 1]
18
- if (
19
- lastClick &&
20
- Math.abs(x - lastClick.x) + Math.abs(y - lastClick.y) < RAGE_CLICK_THRESHOLD_PX &&
21
- timestamp - lastClick.timestamp < RAGE_CLICK_TIMEOUT_MS
22
- ) {
23
- this.clicks.push({ x, y, timestamp })
24
-
25
- if (this.clicks.length === RAGE_CLICK_CLICK_COUNT) {
26
- return true
27
- }
28
- } else {
29
- this.clicks = [{ x, y, timestamp }]
30
- }
31
-
32
- return false
33
- }
34
- }
package/src/iife.ts DELETED
@@ -1,87 +0,0 @@
1
- import { Leanbase } from './leanbase'
2
- import type { LeanbaseConfig } from './types'
3
- import { isArray } from '@posthog/core'
4
-
5
- type QueuedCall = { fn: keyof typeof api; args: any[] }
6
-
7
- const api = {
8
- _instance: null as Leanbase | null,
9
- _queue: [] as QueuedCall[],
10
-
11
- init(apiKey: string, options?: LeanbaseConfig) {
12
- this._instance = new Leanbase(apiKey, options)
13
- const q = this._queue
14
- this._queue = []
15
- for (const { fn, args } of q) {
16
- // @ts-expect-error dynamic dispatch to API methods
17
- this[fn](...args)
18
- }
19
- },
20
-
21
- capture(...args: Parameters<NonNullable<typeof this._instance>['capture']>) {
22
- if (this._instance) {
23
- return this._instance.capture(...args)
24
- }
25
-
26
- this._queue.push({ fn: 'capture', args })
27
- },
28
-
29
- captureException(...args: Parameters<NonNullable<typeof this._instance>['captureException']>) {
30
- if (this._instance) {
31
- return this._instance.captureException(...args)
32
- }
33
-
34
- this._queue.push({ fn: 'captureException', args })
35
- },
36
-
37
- identify(...args: Parameters<NonNullable<typeof this._instance>['identify']>) {
38
- if (this._instance) {
39
- return this._instance.identify(...args)
40
- }
41
-
42
- this._queue.push({ fn: 'identify', args })
43
- },
44
-
45
- group(...args: Parameters<NonNullable<typeof this._instance>['group']>) {
46
- if (this._instance) {
47
- return this._instance.group(...args)
48
- }
49
-
50
- this._queue.push({ fn: 'group', args })
51
- },
52
-
53
- alias(...args: Parameters<NonNullable<typeof this._instance>['alias']>) {
54
- if (this._instance) {
55
- return this._instance.alias(...args)
56
- }
57
-
58
- this._queue.push({ fn: 'alias', args })
59
- },
60
-
61
- reset() {
62
- this._instance?.reset()
63
- this._instance = null
64
- },
65
-
66
- getInstance(): Leanbase | null {
67
- return this._instance
68
- },
69
- }
70
-
71
- // Attach to globalThis for browsers (SSR-safe guards inside Leanbase)
72
- ;(function attachToGlobal(g: Window & typeof globalThis & { leanbase?: typeof api; Leanbase?: typeof api }) {
73
- // Prefer not to overwrite if a stub already exists (e.g., user queued calls before script loaded)
74
- const existing = g.leanbase
75
- if (existing && typeof existing === 'object') {
76
- // If there is a pre-existing queue-compatible stub, try to drain it into our API
77
- if (isArray(existing._queue)) {
78
- api._queue = existing._queue as any
79
- }
80
- }
81
-
82
- g.leanbase = api
83
- // Also expose PascalCase alias for familiarity
84
- g.Leanbase = g.leanbase
85
- })(globalThis as Window & typeof globalThis)
86
-
87
- export default api
@@ -1,26 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- const PREFIX = '[Leanbase]'
4
-
5
- export const logger = {
6
- info: (...args: any[]) => {
7
- if (typeof console !== 'undefined') {
8
- console.log(PREFIX, ...args)
9
- }
10
- },
11
- warn: (...args: any[]) => {
12
- if (typeof console !== 'undefined') {
13
- console.warn(PREFIX, ...args)
14
- }
15
- },
16
- error: (...args: any[]) => {
17
- if (typeof console !== 'undefined') {
18
- console.error(PREFIX, ...args)
19
- }
20
- },
21
- critical: (...args: any[]) => {
22
- if (typeof console !== 'undefined') {
23
- console.error(PREFIX, 'CRITICAL:', ...args)
24
- }
25
- },
26
- }