@loamly/tracker 1.8.0 → 2.0.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/README.md +146 -47
- package/dist/index.cjs +1244 -357
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +78 -65
- package/dist/index.d.ts +78 -65
- package/dist/index.mjs +1244 -357
- package/dist/index.mjs.map +1 -1
- package/dist/loamly.iife.global.js +1291 -140
- package/dist/loamly.iife.global.js.map +1 -1
- package/dist/loamly.iife.min.global.js +16 -1
- package/dist/loamly.iife.min.global.js.map +1 -1
- package/package.json +2 -2
- package/src/behavioral/form-tracker.ts +325 -0
- package/src/behavioral/index.ts +9 -0
- package/src/behavioral/scroll-tracker.ts +163 -0
- package/src/behavioral/time-tracker.ts +174 -0
- package/src/browser.ts +127 -36
- package/src/config.ts +1 -1
- package/src/core.ts +278 -156
- package/src/infrastructure/event-queue.ts +225 -0
- package/src/infrastructure/index.ts +8 -0
- package/src/infrastructure/ping.ts +149 -0
- package/src/spa/index.ts +7 -0
- package/src/spa/router.ts +147 -0
package/src/browser.ts
CHANGED
|
@@ -2,72 +2,165 @@
|
|
|
2
2
|
* Loamly Tracker - Browser Bundle (IIFE)
|
|
3
3
|
*
|
|
4
4
|
* This file is the entry point for the browser script tag version.
|
|
5
|
-
* It auto-initializes from
|
|
5
|
+
* It auto-initializes from script tag attributes or URL parameters.
|
|
6
6
|
*
|
|
7
|
-
* Usage:
|
|
8
|
-
*
|
|
7
|
+
* Usage Options:
|
|
8
|
+
* 1. CDN with domain parameter:
|
|
9
|
+
* <script src="https://app.loamly.ai/t.js?d=your-domain.com"></script>
|
|
10
|
+
*
|
|
11
|
+
* 2. npm with data attributes:
|
|
12
|
+
* <script src="https://cdn.jsdelivr.net/npm/@loamly/tracker" data-api-key="your-key"></script>
|
|
13
|
+
*
|
|
14
|
+
* 3. Self-hosted with manual init:
|
|
15
|
+
* <script src="/tracker.js"></script>
|
|
16
|
+
* <script>loamly.init({ apiKey: 'your-key' })</script>
|
|
9
17
|
*
|
|
10
18
|
* @module @loamly/tracker/browser
|
|
11
19
|
*/
|
|
12
20
|
|
|
13
21
|
import { loamly } from './core'
|
|
14
22
|
import type { LoamlyConfig } from './types'
|
|
23
|
+
import { DEFAULT_CONFIG } from './config'
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Extract domain from script URL ?d= parameter
|
|
27
|
+
*/
|
|
28
|
+
function extractDomainFromScriptUrl(): string | null {
|
|
19
29
|
const scripts = document.getElementsByTagName('script')
|
|
20
|
-
let scriptTag: HTMLScriptElement | null = null
|
|
21
30
|
|
|
22
31
|
for (const script of scripts) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
const src = script.src
|
|
33
|
+
if (src.includes('t.js') || src.includes('loamly')) {
|
|
34
|
+
try {
|
|
35
|
+
const url = new URL(src)
|
|
36
|
+
const domain = url.searchParams.get('d')
|
|
37
|
+
if (domain) return domain
|
|
38
|
+
} catch {
|
|
39
|
+
// Invalid URL, continue
|
|
40
|
+
}
|
|
26
41
|
}
|
|
27
42
|
}
|
|
43
|
+
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Resolve workspace configuration from domain
|
|
49
|
+
*/
|
|
50
|
+
async function resolveWorkspaceConfig(domain: string): Promise<LoamlyConfig | null> {
|
|
51
|
+
try {
|
|
52
|
+
const response = await fetch(`${DEFAULT_CONFIG.apiHost}${DEFAULT_CONFIG.endpoints.resolve}?domain=${encodeURIComponent(domain)}`)
|
|
53
|
+
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
console.warn('[Loamly] Failed to resolve workspace for domain:', domain)
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const data = await response.json()
|
|
60
|
+
|
|
61
|
+
if (data.workspace_id) {
|
|
62
|
+
return {
|
|
63
|
+
apiKey: data.workspace_api_key,
|
|
64
|
+
apiHost: DEFAULT_CONFIG.apiHost,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.warn('[Loamly] Error resolving workspace:', error)
|
|
71
|
+
return null
|
|
32
72
|
}
|
|
73
|
+
}
|
|
33
74
|
|
|
34
|
-
|
|
35
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Extract config from script tag data attributes
|
|
77
|
+
*/
|
|
78
|
+
function extractConfigFromDataAttributes(): LoamlyConfig | null {
|
|
79
|
+
const scripts = document.getElementsByTagName('script')
|
|
36
80
|
|
|
37
|
-
|
|
38
|
-
|
|
81
|
+
for (const script of scripts) {
|
|
82
|
+
if (script.src.includes('loamly') || script.dataset.loamly !== undefined) {
|
|
83
|
+
const config: LoamlyConfig = {}
|
|
84
|
+
|
|
85
|
+
if (script.dataset.apiKey) {
|
|
86
|
+
config.apiKey = script.dataset.apiKey
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (script.dataset.apiHost) {
|
|
90
|
+
config.apiHost = script.dataset.apiHost
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (script.dataset.debug === 'true') {
|
|
94
|
+
config.debug = true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (script.dataset.disableAutoPageview === 'true') {
|
|
98
|
+
config.disableAutoPageview = true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (script.dataset.disableBehavioral === 'true') {
|
|
102
|
+
config.disableBehavioral = true
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (config.apiKey) {
|
|
106
|
+
return config
|
|
107
|
+
}
|
|
108
|
+
}
|
|
39
109
|
}
|
|
40
110
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Auto-initialize the tracker
|
|
116
|
+
*/
|
|
117
|
+
async function autoInit(): Promise<void> {
|
|
118
|
+
// Priority 1: Domain parameter in script URL (?d=domain.com)
|
|
119
|
+
const domain = extractDomainFromScriptUrl()
|
|
44
120
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
121
|
+
if (domain) {
|
|
122
|
+
const resolvedConfig = await resolveWorkspaceConfig(domain)
|
|
123
|
+
if (resolvedConfig) {
|
|
124
|
+
loamly.init(resolvedConfig)
|
|
125
|
+
return
|
|
126
|
+
}
|
|
47
127
|
}
|
|
48
128
|
|
|
49
|
-
|
|
50
|
-
|
|
129
|
+
// Priority 2: Data attributes on script tag
|
|
130
|
+
const dataConfig = extractConfigFromDataAttributes()
|
|
131
|
+
if (dataConfig) {
|
|
132
|
+
loamly.init(dataConfig)
|
|
133
|
+
return
|
|
51
134
|
}
|
|
52
135
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
136
|
+
// Priority 3: Current domain auto-detection (for app.loamly.ai hosted script)
|
|
137
|
+
const currentDomain = window.location.hostname
|
|
138
|
+
if (currentDomain && currentDomain !== 'localhost') {
|
|
139
|
+
const resolvedConfig = await resolveWorkspaceConfig(currentDomain)
|
|
140
|
+
if (resolvedConfig) {
|
|
141
|
+
loamly.init(resolvedConfig)
|
|
142
|
+
return
|
|
143
|
+
}
|
|
60
144
|
}
|
|
145
|
+
|
|
146
|
+
// No configuration found, tracker not initialized
|
|
147
|
+
// User can manually call loamly.init() later
|
|
61
148
|
}
|
|
62
149
|
|
|
63
150
|
// Run auto-init when DOM is ready
|
|
64
151
|
if (typeof document !== 'undefined') {
|
|
65
152
|
if (document.readyState === 'loading') {
|
|
66
|
-
document.addEventListener('DOMContentLoaded',
|
|
153
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
154
|
+
// Use requestIdleCallback if available for non-blocking init
|
|
155
|
+
if (typeof requestIdleCallback !== 'undefined') {
|
|
156
|
+
requestIdleCallback(() => autoInit())
|
|
157
|
+
} else {
|
|
158
|
+
setTimeout(autoInit, 0)
|
|
159
|
+
}
|
|
160
|
+
})
|
|
67
161
|
} else {
|
|
68
|
-
// Use requestIdleCallback if available for non-blocking init
|
|
69
162
|
if (typeof requestIdleCallback !== 'undefined') {
|
|
70
|
-
requestIdleCallback(autoInit)
|
|
163
|
+
requestIdleCallback(() => autoInit())
|
|
71
164
|
} else {
|
|
72
165
|
setTimeout(autoInit, 0)
|
|
73
166
|
}
|
|
@@ -77,5 +170,3 @@ if (typeof document !== 'undefined') {
|
|
|
77
170
|
// Export for manual usage
|
|
78
171
|
export { loamly }
|
|
79
172
|
export default loamly
|
|
80
|
-
|
|
81
|
-
|