@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/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 data attributes on the script tag.
5
+ * It auto-initializes from script tag attributes or URL parameters.
6
6
  *
7
- * Usage:
8
- * <script src="https://unpkg.com/@loamly/tracker" data-api-key="your-key"></script>
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
- // Auto-initialize from script tag data attributes
17
- function autoInit(): void {
18
- // Find the script tag that loaded us
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
- if (script.src.includes('loamly') || script.dataset.loamly !== undefined) {
24
- scriptTag = script
25
- break
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
- if (!scriptTag) {
30
- // No matching script tag found, don't auto-init
31
- return
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
- // Extract configuration from data attributes
35
- const config: LoamlyConfig = {}
75
+ /**
76
+ * Extract config from script tag data attributes
77
+ */
78
+ function extractConfigFromDataAttributes(): LoamlyConfig | null {
79
+ const scripts = document.getElementsByTagName('script')
36
80
 
37
- if (scriptTag.dataset.apiKey) {
38
- config.apiKey = scriptTag.dataset.apiKey
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
- if (scriptTag.dataset.apiHost) {
42
- config.apiHost = scriptTag.dataset.apiHost
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 (scriptTag.dataset.debug === 'true') {
46
- config.debug = true
121
+ if (domain) {
122
+ const resolvedConfig = await resolveWorkspaceConfig(domain)
123
+ if (resolvedConfig) {
124
+ loamly.init(resolvedConfig)
125
+ return
126
+ }
47
127
  }
48
128
 
49
- if (scriptTag.dataset.disableAutoPageview === 'true') {
50
- config.disableAutoPageview = true
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
- if (scriptTag.dataset.disableBehavioral === 'true') {
54
- config.disableBehavioral = true
55
- }
56
-
57
- // Initialize if we have configuration
58
- if (config.apiKey || scriptTag.dataset.loamly !== undefined) {
59
- loamly.init(config)
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', autoInit)
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
-
package/src/config.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * @see https://github.com/loamly/loamly
7
7
  */
8
8
 
9
- export const VERSION = '1.8.0'
9
+ export const VERSION = '2.0.0'
10
10
 
11
11
  export const DEFAULT_CONFIG = {
12
12
  apiHost: 'https://app.loamly.ai',