humanbehavior-js 0.4.28 → 0.5.1

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 (140) hide show
  1. package/README.md +151 -0
  2. package/package.json +116 -78
  3. package/packages/angular/dist/index.d.ts +46 -0
  4. package/packages/angular/dist/index.d.ts.map +1 -0
  5. package/packages/angular/dist/index.js +2 -0
  6. package/packages/angular/dist/index.js.map +1 -0
  7. package/packages/angular/dist/index.mjs +2 -0
  8. package/packages/angular/dist/index.mjs.map +1 -0
  9. package/packages/browser/dist/index.d.ts +5 -0
  10. package/packages/browser/dist/index.d.ts.map +1 -0
  11. package/packages/browser/dist/index.iife.js +12095 -0
  12. package/packages/browser/dist/index.iife.js.map +1 -0
  13. package/packages/browser/dist/index.js +2 -0
  14. package/packages/browser/dist/index.js.map +1 -0
  15. package/packages/browser/dist/index.min.js +2 -0
  16. package/packages/browser/dist/index.min.js.map +1 -0
  17. package/packages/browser/dist/index.mjs +2 -0
  18. package/packages/browser/dist/index.mjs.map +1 -0
  19. package/packages/react/dist/browser.d.ts +2 -0
  20. package/packages/react/dist/browser.d.ts.map +1 -0
  21. package/packages/react/dist/index.d.ts +48 -0
  22. package/packages/react/dist/index.d.ts.map +1 -0
  23. package/packages/react/dist/index.js +2 -0
  24. package/packages/react/dist/index.js.map +1 -0
  25. package/packages/react/dist/index.mjs +2 -0
  26. package/packages/react/dist/index.mjs.map +1 -0
  27. package/packages/remix/dist/index.d.ts +8 -0
  28. package/packages/remix/dist/index.d.ts.map +1 -0
  29. package/packages/remix/dist/index.js +2 -0
  30. package/packages/remix/dist/index.js.map +1 -0
  31. package/packages/remix/dist/index.mjs +2 -0
  32. package/packages/remix/dist/index.mjs.map +1 -0
  33. package/packages/svelte/dist/index.d.ts +11 -0
  34. package/packages/svelte/dist/index.d.ts.map +1 -0
  35. package/packages/svelte/dist/index.js +2 -0
  36. package/packages/svelte/dist/index.js.map +1 -0
  37. package/packages/svelte/dist/index.mjs +2 -0
  38. package/packages/svelte/dist/index.mjs.map +1 -0
  39. package/{dist/types/vue → packages/vue/dist}/index.d.ts +4 -5
  40. package/packages/vue/dist/index.d.ts.map +1 -0
  41. package/packages/vue/dist/index.js +2 -0
  42. package/packages/vue/dist/index.js.map +1 -0
  43. package/packages/vue/dist/index.mjs +2 -0
  44. package/packages/vue/dist/index.mjs.map +1 -0
  45. package/packages/wizard/dist/ai/ai-install-wizard.d.ts +145 -0
  46. package/packages/wizard/dist/ai/ai-install-wizard.d.ts.map +1 -0
  47. package/packages/wizard/dist/ai/manual-framework-wizard.d.ts +52 -0
  48. package/packages/wizard/dist/ai/manual-framework-wizard.d.ts.map +1 -0
  49. package/packages/wizard/dist/cli/ai-auto-install.d.ts +27 -0
  50. package/packages/wizard/dist/cli/ai-auto-install.d.ts.map +1 -0
  51. package/{dist → packages/wizard/dist}/cli/ai-auto-install.js +821 -905
  52. package/packages/wizard/dist/cli/ai-auto-install.js.map +1 -0
  53. package/packages/wizard/dist/cli/auto-install.d.ts +26 -0
  54. package/packages/wizard/dist/cli/auto-install.d.ts.map +1 -0
  55. package/{dist → packages/wizard/dist}/cli/auto-install.js +821 -905
  56. package/packages/wizard/dist/cli/auto-install.js.map +1 -0
  57. package/{dist/types → packages/wizard/dist/core}/install-wizard.d.ts +6 -8
  58. package/packages/wizard/dist/core/install-wizard.d.ts.map +1 -0
  59. package/packages/wizard/dist/index.d.ts +18 -0
  60. package/packages/wizard/dist/index.d.ts.map +1 -0
  61. package/packages/wizard/dist/index.js +2 -0
  62. package/packages/wizard/dist/index.js.map +1 -0
  63. package/packages/wizard/dist/index.mjs +2 -0
  64. package/packages/wizard/dist/index.mjs.map +1 -0
  65. package/packages/wizard/dist/services/centralized-ai-service.d.ts +159 -0
  66. package/packages/wizard/dist/services/centralized-ai-service.d.ts.map +1 -0
  67. package/packages/wizard/dist/services/remote-ai-service.d.ts +58 -0
  68. package/packages/wizard/dist/services/remote-ai-service.d.ts.map +1 -0
  69. package/WIZARD_USAGE_GUIDE.md +0 -381
  70. package/dist/cjs/angular/index.cjs +0 -14979
  71. package/dist/cjs/angular/index.cjs.map +0 -1
  72. package/dist/cjs/index.cjs +0 -14964
  73. package/dist/cjs/index.cjs.map +0 -1
  74. package/dist/cjs/install-wizard.cjs +0 -1576
  75. package/dist/cjs/install-wizard.cjs.map +0 -1
  76. package/dist/cjs/react/index.cjs +0 -15103
  77. package/dist/cjs/react/index.cjs.map +0 -1
  78. package/dist/cjs/remix/index.cjs +0 -15077
  79. package/dist/cjs/remix/index.cjs.map +0 -1
  80. package/dist/cjs/svelte/index.cjs +0 -14933
  81. package/dist/cjs/svelte/index.cjs.map +0 -1
  82. package/dist/cjs/vue/index.cjs +0 -14942
  83. package/dist/cjs/vue/index.cjs.map +0 -1
  84. package/dist/cjs/wizard/index.cjs +0 -3490
  85. package/dist/cjs/wizard/index.cjs.map +0 -1
  86. package/dist/cli/ai-auto-install.js.map +0 -1
  87. package/dist/cli/auto-install.js.map +0 -1
  88. package/dist/esm/angular/index.js +0 -14975
  89. package/dist/esm/angular/index.js.map +0 -1
  90. package/dist/esm/index.js +0 -14941
  91. package/dist/esm/index.js.map +0 -1
  92. package/dist/esm/install-wizard.js +0 -1553
  93. package/dist/esm/install-wizard.js.map +0 -1
  94. package/dist/esm/react/index.js +0 -15097
  95. package/dist/esm/react/index.js.map +0 -1
  96. package/dist/esm/remix/index.js +0 -15073
  97. package/dist/esm/remix/index.js.map +0 -1
  98. package/dist/esm/svelte/index.js +0 -14931
  99. package/dist/esm/svelte/index.js.map +0 -1
  100. package/dist/esm/vue/index.js +0 -14940
  101. package/dist/esm/vue/index.js.map +0 -1
  102. package/dist/esm/wizard/index.js +0 -3459
  103. package/dist/esm/wizard/index.js.map +0 -1
  104. package/dist/index.min.js +0 -2
  105. package/dist/index.min.js.map +0 -1
  106. package/dist/types/angular/index.d.ts +0 -357
  107. package/dist/types/index.d.ts +0 -644
  108. package/dist/types/react/index.d.ts +0 -345
  109. package/dist/types/remix/index.d.ts +0 -336
  110. package/dist/types/svelte/index.d.ts +0 -322
  111. package/dist/types/wizard/index.d.ts +0 -523
  112. package/readme.md +0 -335
  113. package/rollup.config.js +0 -422
  114. package/simple-spa.html +0 -1000
  115. package/src/angular/index.ts +0 -79
  116. package/src/api.ts +0 -416
  117. package/src/index.ts +0 -35
  118. package/src/react/AutoInstallWizard.tsx +0 -557
  119. package/src/react/browser.ts +0 -8
  120. package/src/react/index.tsx +0 -308
  121. package/src/redact.ts +0 -327
  122. package/src/remix/index.ts +0 -16
  123. package/src/svelte/index.ts +0 -14
  124. package/src/tracker.ts +0 -1587
  125. package/src/types/clack.d.ts +0 -31
  126. package/src/utils/ip-detector.ts +0 -158
  127. package/src/utils/logger.ts +0 -144
  128. package/src/utils/property-detector.ts +0 -345
  129. package/src/utils/property-manager.ts +0 -274
  130. package/src/vue/index.ts +0 -29
  131. package/src/wizard/README.md +0 -114
  132. package/src/wizard/ai/ai-install-wizard.ts +0 -897
  133. package/src/wizard/ai/manual-framework-wizard.ts +0 -238
  134. package/src/wizard/cli/ai-auto-install.ts +0 -241
  135. package/src/wizard/cli/auto-install.ts +0 -224
  136. package/src/wizard/core/install-wizard.ts +0 -1794
  137. package/src/wizard/index.ts +0 -23
  138. package/src/wizard/services/centralized-ai-service.ts +0 -668
  139. package/src/wizard/services/remote-ai-service.ts +0 -240
  140. package/tsconfig.json +0 -24
package/simple-spa.html DELETED
@@ -1,1000 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>HumanBehavior SDK - Simple SPA Demo</title>
7
- <style>
8
- body {
9
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
10
- margin: 0;
11
- padding: 20px;
12
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
13
- min-height: 100vh;
14
- color: white;
15
- }
16
-
17
- .container {
18
- max-width: 800px;
19
- margin: 0 auto;
20
- background: rgba(255, 255, 255, 0.1);
21
- backdrop-filter: blur(10px);
22
- border-radius: 20px;
23
- padding: 40px;
24
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
25
- }
26
-
27
- h1 {
28
- text-align: center;
29
- margin-bottom: 30px;
30
- font-size: 2.5em;
31
- text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
32
- }
33
-
34
- .nav {
35
- display: flex;
36
- justify-content: center;
37
- gap: 20px;
38
- margin-bottom: 40px;
39
- }
40
-
41
- .nav button {
42
- background: rgba(255, 255, 255, 0.2);
43
- border: 2px solid rgba(255, 255, 255, 0.3);
44
- color: white;
45
- padding: 12px 24px;
46
- border-radius: 25px;
47
- cursor: pointer;
48
- font-size: 16px;
49
- transition: all 0.3s ease;
50
- backdrop-filter: blur(5px);
51
- }
52
-
53
- .nav button:hover {
54
- background: rgba(255, 255, 255, 0.3);
55
- transform: translateY(-2px);
56
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
57
- }
58
-
59
- .nav button.active {
60
- background: rgba(255, 255, 255, 0.4);
61
- border-color: rgba(255, 255, 255, 0.6);
62
- }
63
-
64
- .content {
65
- background: rgba(255, 255, 255, 0.1);
66
- border-radius: 15px;
67
- padding: 30px;
68
- min-height: 400px;
69
- backdrop-filter: blur(5px);
70
- }
71
-
72
- .button {
73
- background: linear-gradient(45deg, #ff6b6b, #ee5a24);
74
- color: white;
75
- border: none;
76
- padding: 12px 24px;
77
- border-radius: 25px;
78
- cursor: pointer;
79
- font-size: 16px;
80
- margin: 10px;
81
- transition: all 0.3s ease;
82
- }
83
-
84
- .button:hover {
85
- transform: translateY(-2px);
86
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
87
- }
88
-
89
- .button.secondary {
90
- background: linear-gradient(45deg, #4834d4, #686de0);
91
- }
92
-
93
- .button.success {
94
- background: linear-gradient(45deg, #00b894, #00cec9);
95
- }
96
-
97
- .status {
98
- background: rgba(0, 0, 0, 0.2);
99
- border-radius: 10px;
100
- padding: 15px;
101
- margin: 20px 0;
102
- font-family: monospace;
103
- font-size: 14px;
104
- }
105
-
106
- .logs {
107
- background: rgba(0, 0, 0, 0.3);
108
- border-radius: 10px;
109
- padding: 15px;
110
- margin: 20px 0;
111
- max-height: 200px;
112
- overflow-y: auto;
113
- font-family: monospace;
114
- font-size: 12px;
115
- }
116
-
117
- .fade-in {
118
- animation: fadeIn 0.5s ease-in;
119
- }
120
-
121
- @keyframes fadeIn {
122
- from { opacity: 0; transform: translateY(20px); }
123
- to { opacity: 1; transform: translateY(0); }
124
- }
125
- </style>
126
- </head>
127
- <body>
128
- <div class="container">
129
- <h1>HumanBehavior SDK - Simple SPA Demo</h1>
130
-
131
- <div class="nav">
132
- <button class="nav-btn active" data-page="home">🏠 Home</button>
133
- <button class="nav-btn" data-page="about">ℹ️ About</button>
134
- <button class="nav-btn" data-page="demo">🎯 Demo</button>
135
- <button class="nav-btn" data-page="status">📊 Status</button>
136
- </div>
137
-
138
- <div id="content" class="content fade-in">
139
- <!-- Content will be loaded here -->
140
- </div>
141
- </div>
142
-
143
- <!-- Load the HumanBehavior SDK -->
144
- <script src="dist/index.min.js"></script>
145
-
146
- <script>
147
- // Global tracker instance
148
- let tracker = null;
149
- let currentPage = 'home';
150
-
151
- // Page content definitions
152
- const pages = {
153
- home: {
154
- title: '🏠 Home',
155
- content: `
156
- <h2>Welcome to HumanBehavior SDK Demo</h2>
157
- <p>This is a single-page application that demonstrates session continuity across page navigations.</p>
158
-
159
- <div class="status">
160
- <strong>Session Info:</strong><br>
161
- Session ID: <span id="sessionId">Loading...</span><br>
162
- End User ID: <span id="endUserId">Loading...</span><br>
163
- User Type: <span id="userType">Loading...</span><br>
164
- Current URL: <span id="currentUrl">Loading...</span>
165
- </div>
166
-
167
- <h3>Test Actions</h3>
168
- <button class="button" onclick="trackCustomEvent('home_button_click', {page: 'home'})">
169
- Track Custom Event
170
- </button>
171
- <button class="button secondary" onclick="testConsoleLog()">
172
- Test Console Log
173
- </button>
174
- <button class="button success" onclick="testConsoleError()">
175
- Test Console Error
176
- </button>
177
-
178
- <div class="logs" id="logs">
179
- <div>Logs will appear here...</div>
180
- </div>
181
- `
182
- },
183
-
184
- about: {
185
- title: 'ℹ️ About',
186
- content: `
187
- <h2>About This Demo</h2>
188
- <p>This single-page application demonstrates how the HumanBehavior SDK maintains session continuity across page navigations.</p>
189
-
190
- <h3>Key Features</h3>
191
- <ul>
192
- <li><strong>Session Continuity:</strong> The tracker never reinitializes when navigating between pages</li>
193
- <li><strong>URL Tracking:</strong> All navigation events are captured and sent to the server</li>
194
- <li><strong>Event Recording:</strong> User interactions, console logs, and custom events are all tracked</li>
195
- <li><strong>Real-time Updates:</strong> Session information updates in real-time</li>
196
- </ul>
197
-
198
- <div class="status">
199
- <strong>Current Session:</strong><br>
200
- Session ID: <span id="sessionId-about">Loading...</span><br>
201
- User Type: <span id="userType-about">Loading...</span><br>
202
- Page Load Time: <span id="pageLoadTime">Loading...</span>
203
- </div>
204
-
205
- <button class="button" onclick="trackCustomEvent('about_page_viewed', {section: 'about'})">
206
- Track About Page View
207
- </button>
208
- <button class="button secondary" onclick="showUserInfo()">
209
- Show Detailed User Info
210
- </button>
211
- `
212
- },
213
-
214
- demo: {
215
- title: '🎯 Interactive Demo',
216
- content: `
217
- <h2>Interactive Demo</h2>
218
- <p>Test various tracking features and see them in action.</p>
219
-
220
- <h3>Form Interaction</h3>
221
- <form onsubmit="handleFormSubmit(event)">
222
- <input type="text" id="demoInput" placeholder="Type something..." style="padding: 10px; border-radius: 5px; border: none; margin: 10px; width: 200px;">
223
- <button type="submit" class="button">Submit Form</button>
224
- </form>
225
-
226
- <h3>Custom Events</h3>
227
- <button class="button" onclick="trackCustomEvent('demo_button_1', {button: 'demo1'})">Demo Button 1</button>
228
- <button class="button secondary" onclick="trackCustomEvent('demo_button_2', {button: 'demo2'})">Demo Button 2</button>
229
- <button class="button success" onclick="trackCustomEvent('demo_button_3', {button: 'demo3'})">Demo Button 3</button>
230
-
231
- <h3>User Authentication Test</h3>
232
- <button class="button" onclick="testUserAuthentication()">
233
- Test User Authentication
234
- </button>
235
- <p style="font-size: 12px; color: #666; margin-top: 5px;">
236
- Tests the new behavior where endUserId stays the same but posthogName gets updated with email
237
- </p>
238
-
239
- <h3>Real User Authentication</h3>
240
- <form onsubmit="handleAuthSubmit(event)" style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px; margin: 15px 0;">
241
- <div style="margin-bottom: 15px;">
242
- <label for="authEmail" style="display: block; margin-bottom: 5px; font-weight: 600;">Email:</label>
243
- <input type="email" id="authEmail" placeholder="your.email@example.com" required
244
- style="width: 100%; padding: 10px; border-radius: 5px; border: none; background: rgba(255,255,255,0.9);">
245
- </div>
246
-
247
- <div style="margin-bottom: 15px;">
248
- <label for="authName" style="display: block; margin-bottom: 5px; font-weight: 600;">Name:</label>
249
- <input type="text" id="authName" placeholder="Your Name" required
250
- style="width: 100%; padding: 10px; border-radius: 5px; border: none; background: rgba(255,255,255,0.9);">
251
- </div>
252
-
253
- <div style="margin-bottom: 15px;">
254
- <label for="authPlan" style="display: block; margin-bottom: 5px; font-weight: 600;">Plan:</label>
255
- <select id="authPlan" style="width: 100%; padding: 10px; border-radius: 5px; border: none; background: rgba(255,255,255,0.9);">
256
- <option value="free">Free</option>
257
- <option value="basic">Basic</option>
258
- <option value="premium">Premium</option>
259
- <option value="enterprise">Enterprise</option>
260
- </select>
261
- </div>
262
-
263
- <div style="margin-bottom: 15px;">
264
- <label for="authCompany" style="display: block; margin-bottom: 5px; font-weight: 600;">Company (Optional):</label>
265
- <input type="text" id="authCompany" placeholder="Your Company"
266
- style="width: 100%; padding: 10px; border-radius: 5px; border: none; background: rgba(255,255,255,0.9);">
267
- </div>
268
-
269
- <button type="submit" class="button success" style="width: 100%;">
270
- 🔐 Authenticate User
271
- </button>
272
- </form>
273
-
274
- <div style="margin-top: 15px; display: flex; gap: 10px;">
275
- <button class="button secondary" onclick="showAuthStatus()" style="flex: 1;">
276
- 📊 Show Auth Status
277
- </button>
278
- </div>
279
-
280
- <div id="authResult" style="margin-top: 15px; padding: 10px; border-radius: 5px; display: none;"></div>
281
-
282
- <div class="logs" id="demoLogs">
283
- <div>Demo events will appear here...</div>
284
- </div>
285
- `
286
- },
287
-
288
- status: {
289
- title: '📊 Session Status',
290
- content: `
291
- <h2>Session Status & Debug Info</h2>
292
-
293
- <div class="status">
294
- <strong>Tracker Status:</strong><br>
295
- Initialized: <span id="trackerInitialized">Loading...</span><br>
296
- Session ID: <span id="sessionId-status">Loading...</span><br>
297
- End User ID: <span id="endUserId-status">Loading...</span><br>
298
- User Type: <span id="userType-status">Loading...</span><br>
299
- Current URL: <span id="currentUrl-status">Loading...</span><br>
300
- Connection Status: <span id="connectionStatus">Loading...</span>
301
- </div>
302
-
303
- <h3>Actions</h3>
304
- <button class="button" onclick="viewLogs()">View Logs</button>
305
- <button class="button secondary" onclick="testConnection()">Test Connection</button>
306
- <button class="button success" onclick="clearLogs()">Clear Logs</button>
307
-
308
- <div class="logs" id="statusLogs">
309
- <div>Status logs will appear here...</div>
310
- </div>
311
- `
312
- }
313
- };
314
-
315
- // Initialize the application
316
- async function initApp() {
317
- try {
318
- console.log('Starting SPA initialization...');
319
-
320
- // Check if SDK is loaded
321
- if (typeof HumanBehaviorTracker === 'undefined') {
322
- throw new Error('HumanBehaviorTracker SDK not loaded. Check if dist/index.js exists.');
323
- }
324
-
325
- // Initialize HumanBehavior tracker
326
- console.log('Initializing tracker...');
327
- tracker = HumanBehaviorTracker.init('13c3e029-ca45-4a3c-a33b-f5dcb297e31c', {
328
- logLevel: 'debug',
329
- redactFields: ['password', 'credit_card'],
330
- enableAutomaticProperties: true
331
- });
332
-
333
- console.log('Tracker created, waiting for initialization...');
334
-
335
- // Wait for tracker to initialize with timeout
336
- if (tracker.initializationPromise) {
337
- try {
338
- await Promise.race([
339
- tracker.initializationPromise,
340
- new Promise((_, reject) =>
341
- setTimeout(() => reject(new Error('Initialization timeout')), 10000)
342
- )
343
- ]);
344
- console.log('Tracker initialized successfully');
345
- } catch (initError) {
346
- console.warn('Tracker initialization failed or timed out:', initError);
347
- addLog('Tracker initialization warning: ' + initError.message);
348
- // Continue anyway - tracker might still work
349
- }
350
- } else {
351
- console.log('No initialization promise, continuing...');
352
- }
353
-
354
- // Set up navigation
355
- setupNavigation();
356
-
357
- // Load initial page
358
- loadPage('home');
359
-
360
- // Update status periodically
361
- setInterval(updateStatus, 2000);
362
-
363
- // Display automatic properties
364
- displayAutomaticProperties();
365
-
366
- // Display IP information
367
- displayIPInfo();
368
-
369
- console.log('SPA App initialized successfully');
370
- addLog('SPA App initialized successfully');
371
-
372
- } catch (error) {
373
- console.error('Failed to initialize SPA app:', error);
374
- addLog('Error initializing app: ' + error.message);
375
-
376
- // Show error in content
377
- document.getElementById('content').innerHTML = `
378
- <h2>Initialization Error</h2>
379
- <p>Failed to initialize the HumanBehavior SDK:</p>
380
- <div class="status">
381
- <strong>Error:</strong> ${error.message}<br>
382
- <strong>Stack:</strong> ${error.stack}
383
- </div>
384
- <button class="button" onclick="location.reload()">Reload Page</button>
385
- `;
386
- }
387
- }
388
-
389
- // Set up client-side navigation
390
- function setupNavigation() {
391
- const navButtons = document.querySelectorAll('.nav-btn');
392
-
393
- navButtons.forEach(button => {
394
- button.addEventListener('click', () => {
395
- const page = button.dataset.page;
396
- navigateToPage(page);
397
- });
398
- });
399
-
400
- // Handle browser back/forward buttons
401
- window.addEventListener('popstate', (event) => {
402
- const page = event.state?.page || 'home';
403
- loadPage(page);
404
- updateActiveNavButton(page);
405
- });
406
- }
407
-
408
- // Navigate to a page
409
- function navigateToPage(page) {
410
- if (page === currentPage) return;
411
-
412
- console.log(`Navigating from ${currentPage} to ${page}`);
413
-
414
- // Update URL without page reload
415
- history.pushState({ page }, pages[page].title, `#${page}`);
416
-
417
- // Load the page content
418
- loadPage(page);
419
-
420
- // Update active nav button
421
- updateActiveNavButton(page);
422
-
423
- // Track navigation event
424
- if (tracker && tracker.trackNavigationEvent) {
425
- try {
426
- tracker.trackNavigationEvent('spa_navigation', currentPage, page);
427
- } catch (error) {
428
- console.error('Failed to track navigation:', error);
429
- }
430
- }
431
-
432
- currentPage = page;
433
- }
434
-
435
- // Load page content
436
- function loadPage(page) {
437
- const contentDiv = document.getElementById('content');
438
- const pageData = pages[page];
439
-
440
- if (!pageData) {
441
- contentDiv.innerHTML = '<h2>Page not found</h2>';
442
- return;
443
- }
444
-
445
- // Add fade-in animation
446
- contentDiv.classList.remove('fade-in');
447
- void contentDiv.offsetWidth; // Trigger reflow
448
- contentDiv.classList.add('fade-in');
449
-
450
- contentDiv.innerHTML = pageData.content;
451
-
452
- // Update page title
453
- document.title = `HumanBehavior SDK - ${pageData.title}`;
454
-
455
- // Track page view
456
- if (tracker && tracker.trackPageView) {
457
- try {
458
- tracker.trackPageView();
459
- } catch (error) {
460
- console.error('Failed to track pageview:', error);
461
- }
462
- }
463
-
464
- addLog(`Navigated to ${page} page`);
465
- }
466
-
467
- // Update active navigation button
468
- function updateActiveNavButton(page) {
469
- document.querySelectorAll('.nav-btn').forEach(btn => {
470
- btn.classList.remove('active');
471
- });
472
- const activeButton = document.querySelector(`[data-page="${page}"]`);
473
- if (activeButton) {
474
- activeButton.classList.add('active');
475
- }
476
- }
477
-
478
- // Update status information
479
- function updateStatus() {
480
- if (!tracker) return;
481
-
482
- try {
483
- // Update session info
484
- const sessionIdElements = document.querySelectorAll('#sessionId, #sessionId-about, #sessionId-status');
485
- const sessionId = tracker.getSessionId ? tracker.getSessionId() : 'Not available';
486
- sessionIdElements.forEach(el => {
487
- if (el) el.textContent = sessionId;
488
- });
489
-
490
- const endUserIdElements = document.querySelectorAll('#endUserId, #endUserId-status');
491
- const endUserId = tracker.endUserId || 'Not set';
492
- endUserIdElements.forEach(el => {
493
- if (el) el.textContent = endUserId;
494
- });
495
-
496
- // Update user type (preexisting vs new)
497
- const userTypeElements = document.querySelectorAll('#userType, #userType-about, #userType-status');
498
- let userType = 'Unknown';
499
- if (tracker.isPreexistingUser) {
500
- try {
501
- const isPreexisting = tracker.isPreexistingUser();
502
- userType = isPreexisting ? '🔄 Preexisting User' : '🆕 New User';
503
- } catch (error) {
504
- console.warn('Error checking preexisting user:', error);
505
- userType = 'Error';
506
- }
507
- }
508
- userTypeElements.forEach(el => {
509
- if (el) el.textContent = userType;
510
- });
511
-
512
- const currentUrlElements = document.querySelectorAll('#currentUrl, #currentUrl-status');
513
- const currentUrl = window.location.href;
514
- currentUrlElements.forEach(el => {
515
- if (el) el.textContent = currentUrl;
516
- });
517
-
518
- const trackerInitialized = document.getElementById('trackerInitialized');
519
- if (trackerInitialized) {
520
- trackerInitialized.textContent = tracker.initialized ? 'Yes' : 'No';
521
- }
522
-
523
- const connectionStatus = document.getElementById('connectionStatus');
524
- if (connectionStatus && tracker.getConnectionStatus) {
525
- try {
526
- const status = tracker.getConnectionStatus();
527
- connectionStatus.textContent = status.blocked ? 'Blocked' : 'Connected';
528
- } catch (error) {
529
- console.warn('Error getting connection status:', error);
530
- connectionStatus.textContent = 'Error';
531
- }
532
- }
533
-
534
- const pageLoadTime = document.getElementById('pageLoadTime');
535
- if (pageLoadTime) {
536
- pageLoadTime.textContent = new Date().toLocaleTimeString();
537
- }
538
- } catch (error) {
539
- console.error('Error updating status:', error);
540
- // Don't let status update errors crash the app
541
- }
542
- }
543
-
544
- // Track custom events
545
- async function trackCustomEvent(eventName, properties = {}) {
546
- if (!tracker) {
547
- addLog('Tracker not available');
548
- return;
549
- }
550
-
551
- try {
552
- if (tracker.customEvent) {
553
- await tracker.customEvent(eventName, properties);
554
- addLog(`Custom event tracked: ${eventName}`, properties);
555
- } else {
556
- addLog('customEvent method not available');
557
- }
558
- } catch (error) {
559
- console.error('Error tracking custom event:', error);
560
- addLog('Error tracking custom event: ' + error.message);
561
- }
562
- }
563
-
564
- // Test user authentication (new behavior)
565
- async function testUserAuthentication() {
566
- if (!tracker) {
567
- addLog('Tracker not available');
568
- return;
569
- }
570
-
571
- try {
572
- const originalEndUserId = tracker.getSessionId();
573
- addLog(`Original endUserId: ${originalEndUserId}`);
574
-
575
- // Simulate user sign-in
576
- const userId = await tracker.addUserInfo({
577
- userId: 'user123@example.com',
578
- userProperties: {
579
- email: 'user123@example.com',
580
- name: 'John Doe',
581
- plan: 'premium',
582
- signupDate: new Date().toISOString()
583
- }
584
- });
585
-
586
- const newEndUserId = tracker.getSessionId();
587
- addLog(`New endUserId: ${newEndUserId}`);
588
- addLog(`endUserId changed: ${originalEndUserId !== newEndUserId ? 'YES (BAD)' : 'NO (GOOD)'}`);
589
- addLog(`User authenticated: ${userId}`);
590
-
591
- // The endUserId should stay the same, but user name will be updated
592
- addLog('✅ endUserId maintained for session continuity');
593
- addLog('✅ posthogName will be updated with email for UI display');
594
-
595
- } catch (error) {
596
- console.error('Error testing user authentication:', error);
597
- addLog('Error testing user authentication: ' + error.message);
598
- }
599
- }
600
-
601
- // Test console logging
602
- function testConsoleLog() {
603
- console.log('This is a test console log message');
604
- addLog('Console log test executed');
605
- }
606
-
607
- function testConsoleError() {
608
- console.error('This is a test console error message');
609
- addLog('Console error test executed');
610
- }
611
-
612
- // Handle form submission
613
- function handleFormSubmit(event) {
614
- event.preventDefault();
615
- const input = document.getElementById('demoInput');
616
- const value = input.value;
617
-
618
- trackCustomEvent('form_submitted', { value: value });
619
- addLog(`Form submitted with value: ${value}`);
620
-
621
- input.value = '';
622
- }
623
-
624
- // Handle authentication form submission
625
- async function handleAuthSubmit(event) {
626
- event.preventDefault();
627
- const email = document.getElementById('authEmail').value;
628
- const name = document.getElementById('authName').value;
629
- const plan = document.getElementById('authPlan').value;
630
- const company = document.getElementById('authCompany').value;
631
-
632
- if (!email || !name) {
633
- alert('Email and Name are required for authentication.');
634
- return;
635
- }
636
-
637
- try {
638
- const userId = await tracker.addUserInfo({
639
- userId: email, // Use email as userId
640
- userProperties: {
641
- email: email,
642
- name: name,
643
- plan: plan,
644
- company: company,
645
- signupDate: new Date().toISOString()
646
- }
647
- });
648
-
649
- const newEndUserId = tracker.getSessionId();
650
- addLog(`New endUserId after authentication: ${newEndUserId}`);
651
- addLog(`endUserId changed: ${tracker.getSessionId() !== newEndUserId ? 'YES (BAD)' : 'NO (GOOD)'}`);
652
- addLog(`User authenticated: ${userId}`);
653
-
654
- const authResultDiv = document.getElementById('authResult');
655
- authResultDiv.style.display = 'block';
656
- authResultDiv.innerHTML = `
657
- <strong>Authentication Successful!</strong><br>
658
- New End User ID: ${newEndUserId}<br>
659
- Original End User ID: ${tracker.getSessionId()}<br>
660
- endUserId changed: ${tracker.getSessionId() !== newEndUserId ? 'YES (BAD)' : 'NO (GOOD)'}
661
- `;
662
- authResultDiv.style.color = 'green';
663
-
664
- } catch (error) {
665
- console.error('Error authenticating user:', error);
666
- addLog('Error authenticating user: ' + error.message);
667
-
668
- const authResultDiv = document.getElementById('authResult');
669
- authResultDiv.style.display = 'block';
670
- authResultDiv.innerHTML = `
671
- <strong>Authentication Failed!</strong><br>
672
- Error: ${error.message}
673
- `;
674
- authResultDiv.style.color = 'red';
675
- }
676
- }
677
-
678
- // View logs
679
- function viewLogs() {
680
- if (tracker && tracker.viewLogs) {
681
- tracker.viewLogs();
682
- } else {
683
- addLog('viewLogs method not available');
684
- }
685
- }
686
-
687
- // Test connection
688
- async function testConnection() {
689
- if (!tracker) {
690
- addLog('Tracker not available');
691
- return;
692
- }
693
-
694
- try {
695
- if (tracker.testConnection) {
696
- const result = await tracker.testConnection();
697
- addLog(`Connection test: ${result.success ? 'Success' : 'Failed'}`, result);
698
- } else {
699
- addLog('testConnection method not available');
700
- }
701
- } catch (error) {
702
- addLog(`Connection test error: ${error.message}`);
703
- }
704
- }
705
-
706
- // Clear logs
707
- function clearLogs() {
708
- const logElements = document.querySelectorAll('.logs');
709
- logElements.forEach(el => {
710
- el.innerHTML = '<div>Logs cleared...</div>';
711
- });
712
- }
713
-
714
- // Show detailed user information
715
- function showUserInfo() {
716
- if (!tracker) {
717
- addLog('Tracker not available');
718
- return;
719
- }
720
-
721
- try {
722
- const userInfo = tracker.getUserInfo ? tracker.getUserInfo() : null;
723
- if (userInfo) {
724
- const infoText = ` <strong>Detailed User Information:</strong><br>
725
- End User ID: ${userInfo.endUserId || 'Not set'}<br>
726
- Session ID: ${userInfo.sessionId}<br>
727
- Is Preexisting User: ${userInfo.isPreexistingUser ? 'Yes' : 'No'}<br>
728
- Initialized: ${userInfo.initialized ? 'Yes' : 'No'}<br>
729
- <br>
730
- <strong>Cookie Check:</strong><br>
731
- End User Cookie: ${tracker.getCookie ? tracker.getCookie(`human_behavior_end_user_id_13c3e029-ca45-4a3c-a33b-f5dcb297e31c`) : 'Method not available'}<br>
732
- Session Cookie: ${tracker.getCookie ? tracker.getCookie('human_behavior_session_id') : 'Method not available'}
733
- `;
734
-
735
- // Show in an alert or add to logs
736
- addLog('Detailed user info displayed', userInfo);
737
- alert(infoText);
738
- } else {
739
- addLog('getUserInfo method not available');
740
- }
741
- } catch (error) {
742
- addLog(`Error getting user info: ${error.message}`);
743
- }
744
- }
745
-
746
- // Show current authentication status
747
- function showAuthStatus() {
748
- if (!tracker) {
749
- addLog('Tracker not available');
750
- return;
751
- }
752
- try {
753
- const userInfo = tracker.getUserInfo ? tracker.getUserInfo() : null;
754
- const userAttributes = tracker.getUserAttributes ? tracker.getUserAttributes() : {};
755
-
756
- if (userInfo) {
757
- const statusText = `
758
- <strong>Current Authentication Status:</strong><br>
759
- End User ID: ${userInfo.endUserId || 'Not set'}<br>
760
- Session ID: ${userInfo.sessionId}<br>
761
- Is Preexisting User: ${userInfo.isPreexistingUser ? 'Yes' : 'No'}<br>
762
- Initialized: ${userInfo.initialized ? 'Yes' : 'No'}<br>
763
- <br>
764
- <strong>User Attributes:</strong><br>
765
- ${Object.keys(userAttributes).length > 0 ?
766
- Object.entries(userAttributes).map(([key, value]) => `${key}: ${value}`).join('<br>') :
767
- 'No user attributes set'
768
- }
769
- <br><br>
770
- <strong>Cookie Check:</strong><br>
771
- End User Cookie: ${tracker.getCookie ? tracker.getCookie(`human_behavior_end_user_id_13c3e029-ca45-4a3c-a33b-f5dcb297e31c`) : 'Method not available'}<br>
772
- Session Cookie: ${tracker.getCookie ? tracker.getCookie('human_behavior_session_id') : 'Method not available'}
773
- `;
774
- addLog('Authentication status displayed', { userInfo, userAttributes });
775
- alert(statusText);
776
- } else {
777
- addLog('getUserInfo method not available for status');
778
- }
779
- } catch (error) {
780
- addLog(`Error getting authentication status: ${error.message}`);
781
- }
782
- }
783
-
784
- // Display automatic properties
785
- function displayAutomaticProperties() {
786
- if (!tracker) {
787
- addLog('Tracker not available for automatic properties');
788
- return;
789
- }
790
-
791
- try {
792
- const allProperties = tracker.getAllProperties();
793
-
794
- // Create a properties display section
795
- const propertiesSection = document.createElement('div');
796
- propertiesSection.className = 'demo-section';
797
- propertiesSection.style.cssText = `
798
- background: rgba(255, 255, 255, 0.1);
799
- border-radius: 15px;
800
- padding: 30px;
801
- margin: 20px 0;
802
- backdrop-filter: blur(5px);
803
- `;
804
-
805
- propertiesSection.innerHTML = `
806
- <h2>🔍 Automatic Properties</h2>
807
- <p>These properties are automatically captured by the HumanBehavior SDK:</p>
808
-
809
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
810
- <div>
811
- <h3>🖥️ Device Information</h3>
812
- <div class="status" style="font-size: 12px; max-height: 200px; overflow-y: auto;">
813
- ${Object.entries(allProperties.automatic)
814
- .filter(([key]) => ['device_type', 'browser', 'browser_version', 'os', 'os_version', 'screen_resolution', 'viewport_size', 'color_depth', 'timezone', 'language', 'languages'].includes(key))
815
- .map(([key, value]) => `<strong>${key}:</strong> ${JSON.stringify(value)}<br>`)
816
- .join('')}
817
- </div>
818
- </div>
819
-
820
- <div>
821
- <h3>📍 Location Information</h3>
822
- <div class="status" style="font-size: 12px; max-height: 200px; overflow-y: auto;">
823
- ${Object.entries(allProperties.automatic)
824
- .filter(([key]) => ['current_url', 'pathname', 'search', 'hash', 'title', 'referrer', 'referrer_domain', 'initial_referrer', 'initial_referrer_domain', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].includes(key))
825
- .map(([key, value]) => `<strong>${key}:</strong> ${JSON.stringify(value)}<br>`)
826
- .join('')}
827
- </div>
828
- </div>
829
- </div>
830
-
831
- <div style="margin-top: 20px;">
832
- <h3>📌 Session Properties</h3>
833
- <div class="status" style="font-size: 12px; max-height: 150px; overflow-y: auto;">
834
- ${Object.keys(allProperties.session).length > 0 ?
835
- Object.entries(allProperties.session).map(([key, value]) => `<strong>${key}:</strong> ${JSON.stringify(value)}<br>`).join('') :
836
- '<em>No session properties set</em>'
837
- }
838
- </div>
839
- </div>
840
-
841
- <div style="margin-top: 20px;">
842
- <h3>👤 User Properties</h3>
843
- <div class="status" style="font-size: 12px; max-height: 150px; overflow-y: auto;">
844
- ${Object.keys(allProperties.user).length > 0 ?
845
- Object.entries(allProperties.user).map(([key, value]) => `<strong>${key}:</strong> ${JSON.stringify(value)}<br>`).join('') :
846
- '<em>No user properties set</em>'
847
- }
848
- </div>
849
- </div>
850
-
851
- <div style="margin-top: 20px;">
852
- <h3>🎯 Initial Properties</h3>
853
- <div class="status" style="font-size: 12px; max-height: 150px; overflow-y: auto;">
854
- ${Object.entries(allProperties.initial).map(([key, value]) => `<strong>${key}:</strong> ${JSON.stringify(value)}<br>`).join('')}
855
- </div>
856
- </div>
857
- `;
858
-
859
- // Insert the properties section at the top of the content
860
- const contentDiv = document.getElementById('content');
861
- if (contentDiv) {
862
- contentDiv.insertBefore(propertiesSection, contentDiv.firstChild);
863
- }
864
-
865
- addLog('Automatic properties displayed');
866
-
867
- } catch (error) {
868
- console.error('Error displaying automatic properties:', error);
869
- addLog('Error displaying automatic properties: ' + error.message);
870
- }
871
- }
872
-
873
- // Display IP information
874
- async function displayIPInfo() {
875
- try {
876
- // Create IP display section
877
- const ipSection = document.createElement('div');
878
- ipSection.className = 'demo-section';
879
- ipSection.style.cssText = `
880
- background: rgba(255, 255, 255, 0.1);
881
- border-radius: 15px;
882
- padding: 30px;
883
- margin: 20px 0;
884
- backdrop-filter: blur(5px);
885
- `;
886
-
887
- ipSection.innerHTML = `
888
- <h2>🌐 IP Information</h2>
889
- <p>Client IP address detection (for server-side geolocation):</p>
890
- <div id="ip-info" style="font-size: 12px; max-height: 200px; overflow-y: auto;">
891
- <em>Detecting IP address...</em>
892
- </div>
893
- `;
894
-
895
- // Insert after properties section
896
- const contentDiv = document.getElementById('content');
897
- if (contentDiv) {
898
- const propertiesSection = contentDiv.querySelector('.demo-section');
899
- if (propertiesSection) {
900
- propertiesSection.insertAdjacentElement('afterend', ipSection);
901
- } else {
902
- contentDiv.insertBefore(ipSection, contentDiv.firstChild);
903
- }
904
- }
905
-
906
- // Try to get IP info using the SDK
907
- try {
908
- if (typeof HumanBehaviorTracker !== 'undefined') {
909
- // Wait a bit for IP detection to complete
910
- setTimeout(async () => {
911
- const ipInfoDiv = document.getElementById('ip-info');
912
- if (ipInfoDiv) {
913
- ipInfoDiv.innerHTML = `
914
- <strong>IP Detection Status:</strong> IP address is being sent to server for geolocation<br>
915
- <strong>Method:</strong> STUN servers + public IP services<br>
916
- <strong>Privacy:</strong> No precise GPS coordinates, only IP-based location<br>
917
- <strong>Server Processing:</strong> City, country, and region determined server-side<br>
918
- <br>
919
- <em>Note: Actual IP address and geo data are processed on the server for privacy and accuracy.</em>
920
- `;
921
- }
922
- }, 2000);
923
- }
924
- } catch (error) {
925
- const ipInfoDiv = document.getElementById('ip-info');
926
- if (ipInfoDiv) {
927
- ipInfoDiv.innerHTML = `<em>IP detection not available: ${error.message}</em>`;
928
- }
929
- }
930
-
931
- addLog('IP information display initialized');
932
-
933
- } catch (error) {
934
- console.error('Error displaying IP info:', error);
935
- addLog('Error displaying IP info: ' + error.message);
936
- }
937
- }
938
-
939
- // Add log message
940
- function addLog(message, data = null) {
941
- const logElements = document.querySelectorAll('.logs');
942
- const timestamp = new Date().toLocaleTimeString();
943
- const logEntry = `<div>[${timestamp}] ${message}${data ? ' - ' + JSON.stringify(data) : ''}</div>`;
944
-
945
- logElements.forEach(el => {
946
- el.innerHTML += logEntry;
947
- el.scrollTop = el.scrollHeight;
948
- });
949
-
950
- // Also log to console
951
- console.log(`[${timestamp}] ${message}`, data);
952
- }
953
-
954
- // Initialize the app when the page loads
955
- document.addEventListener('DOMContentLoaded', initApp);
956
-
957
- // Add global error handler to prevent page from going blank
958
- window.addEventListener('error', function(event) {
959
- console.error('Global error caught:', event.error);
960
- addLog('Global error: ' + event.error.message);
961
-
962
- // Prevent the page from going blank by showing error content
963
- const contentDiv = document.getElementById('content');
964
- if (contentDiv && contentDiv.innerHTML.trim() === '') {
965
- contentDiv.innerHTML = `
966
- <h2>Application Error</h2>
967
- <p>An error occurred but the application is still running:</p>
968
- <div class="status">
969
- <strong>Error:</strong> ${event.error.message}<br>
970
- <strong>File:</strong> ${event.filename}<br>
971
- <strong>Line:</strong> ${event.lineno}
972
- </div>
973
- <button class="button" onclick="loadPage('home')">Go to Home</button>
974
- <button class="button secondary" onclick="location.reload()">Reload Page</button>
975
- `;
976
- }
977
- });
978
-
979
- // Add unhandled promise rejection handler
980
- window.addEventListener('unhandledrejection', function(event) {
981
- console.error('Unhandled promise rejection:', event.reason);
982
- addLog('Unhandled promise rejection: ' + event.reason);
983
- event.preventDefault(); // Prevent the default browser behavior
984
- });
985
-
986
- // Add periodic health check
987
- setInterval(() => {
988
- try {
989
- const contentDiv = document.getElementById('content');
990
- if (contentDiv && contentDiv.innerHTML.trim() === '') {
991
- console.warn('Content div is empty, attempting to restore...');
992
- loadPage('home');
993
- }
994
- } catch (error) {
995
- console.error('Health check error:', error);
996
- }
997
- }, 5000); // Check every 5 seconds
998
- </script>
999
- </body>
1000
- </html>