humanbehavior-js 0.1.9 → 0.2.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.
@@ -186,18 +186,31 @@ declare class HumanBehaviorTracker {
186
186
  private trackConsoleEvent;
187
187
  private setupPageUnloadHandler;
188
188
  viewLogs(): void;
189
- addUserInfo(userProperties: Record<string, any>): Promise<void>;
189
+ addUserInfo({ userId, userProperties }: {
190
+ userId: string;
191
+ userProperties: Record<string, any>;
192
+ }): Promise<void>;
190
193
  /**
191
- * Authenticate user using existing userInfo data
194
+ * Add user identification information to the tracker
192
195
  * @param authFields Array of field names to check for existing users (e.g., ['email', 'phoneNumber'])
193
196
  */
194
- auth(authFields: string[]): Promise<void>;
197
+ private auth;
195
198
  start(): Promise<void>;
196
199
  stop(): Promise<void>;
197
200
  addEvent(event: any): Promise<void>;
198
201
  private flush;
199
202
  private setCookie;
200
203
  getCookie(name: string): string | null;
204
+ /**
205
+ * Delete a cookie by setting its expiration date to the past
206
+ * @param name The name of the cookie to delete
207
+ */
208
+ private deleteCookie;
209
+ /**
210
+ * Log out the current user by clearing all user-related data
211
+ * This will delete the user ID cookie, clear localStorage, and reset user properties
212
+ */
213
+ logout(): void;
201
214
  /**
202
215
  * Start redaction functionality for sensitive input fields
203
216
  * @param options Optional configuration for redaction behavior
@@ -314,5 +327,9 @@ declare const logWarn: (message: string, ...args: any[]) => void;
314
327
  declare const logInfo: (message: string, ...args: any[]) => void;
315
328
  declare const logDebug: (message: string, ...args: any[]) => void;
316
329
 
330
+ /**
331
+ * Main entry point for the HumanBehavior SDK
332
+ */
333
+
317
334
  export { HumanBehaviorAPI, HumanBehaviorTracker, LogLevel, MAX_CHUNK_SIZE_BYTES, RedactionManager, HumanBehaviorTracker as default, isChunkSizeExceeded, logDebug, logError, logInfo, logWarn, logger, redactionManager, splitLargeEvent, validateSingleEventSize };
318
335
  export type { LoggerConfig, RedactionOptions };
@@ -1,4 +1,5 @@
1
- import React, { ReactNode } from 'react';
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
  import { HumanBehaviorTracker } from '..';
3
4
  export { HumanBehaviorTracker } from '..';
4
5
 
@@ -12,7 +13,21 @@ interface HumanBehaviorProviderProps {
12
13
  redactFields?: string[];
13
14
  };
14
15
  }
15
- declare const HumanBehaviorProvider: ({ apiKey, client, children, options }: HumanBehaviorProviderProps) => React.JSX.Element;
16
+ declare const HumanBehaviorProvider: ({ apiKey, client, children, options }: HumanBehaviorProviderProps) => react_jsx_runtime.JSX.Element;
16
17
  declare const useHumanBehavior: () => HumanBehaviorTracker;
18
+ declare const useRedaction: () => {
19
+ setRedactedFields: (fields: string[]) => void;
20
+ isRedactionActive: () => boolean;
21
+ getRedactedFields: () => string[];
22
+ };
23
+ declare const useUserTracking: () => {
24
+ addUserInfo: (userId: string, userProperties: Record<string, any>) => Promise<{
25
+ success: boolean;
26
+ error?: undefined;
27
+ } | {
28
+ success: boolean;
29
+ error: unknown;
30
+ }>;
31
+ };
17
32
 
18
- export { HumanBehaviorProvider, useHumanBehavior };
33
+ export { HumanBehaviorProvider, useHumanBehavior, useRedaction, useUserTracking };
package/package.json CHANGED
@@ -1,37 +1,50 @@
1
1
  {
2
2
  "name": "humanbehavior-js",
3
- "version": "0.1.9",
3
+ "version": "0.2.1",
4
4
  "description": "SDK for HumanBehavior session and event recording",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
7
7
  "module": "./dist/esm/index.js",
8
8
  "types": "./dist/types/index.d.ts",
9
9
  "unpkg": "dist/index.min.js",
10
+ "jsdelivr": "dist/index.min.js",
10
11
  "homepage": "https://documentation.humanbehavior.co",
11
12
  "exports": {
12
13
  ".": {
13
14
  "import": "./dist/esm/index.js",
14
15
  "require": "./dist/cjs/index.js",
15
- "types": "./dist/types/index.d.ts"
16
+ "types": "./dist/types/index.d.ts",
17
+ "default": "./dist/esm/index.js"
16
18
  },
17
19
  "./react": {
18
20
  "import": "./dist/esm/react/index.js",
19
21
  "require": "./dist/cjs/react/index.js",
20
- "types": "./dist/types/react/index.d.ts"
21
- }
22
+ "types": "./dist/types/react/index.d.ts",
23
+ "default": "./dist/esm/react/index.js"
24
+ },
25
+ "./package.json": "./package.json"
22
26
  },
27
+ "files": [
28
+ "dist/**/*",
29
+ "src/**/*",
30
+ "*.d.ts"
31
+ ],
23
32
  "scripts": {
24
33
  "build": "rollup -c",
25
34
  "build:dev": "rollup -c --environment NODE_ENV:development",
26
35
  "prepare": "npm run build",
27
- "test": "echo \"Error: no test specified\" && exit 1"
36
+ "test": "node scripts/test-bundlers.js",
37
+ "test:bundlers": "node scripts/test-bundlers.js",
38
+ "test:framework": "node scripts/test-framework-compatibility.js",
39
+ "test:all": "npm run test:bundlers && npm run test:framework"
28
40
  },
29
41
  "author": "Chirag Kawediya, Skyler Ji, Amogh Chaturvedi",
30
42
  "license": "ISC",
43
+ "peerDependencies": {
44
+ "react": ">=16.8.0",
45
+ "react-dom": ">=16.8.0"
46
+ },
31
47
  "dependencies": {
32
- "@types/react": "^19.0.12",
33
- "humanbehavior-js": "^0.0.9",
34
- "react": "^19.0.0",
35
48
  "rrweb": "^2.0.0-alpha.4",
36
49
  "uuid": "^11.1.0"
37
50
  },
@@ -41,6 +54,8 @@
41
54
  "@rollup/plugin-terser": "^0.4.4",
42
55
  "@rollup/plugin-typescript": "^12.1.2",
43
56
  "@types/node": "^24.0.3",
57
+ "@types/react": "^19.0.12",
58
+ "@types/react-dom": "^19.0.0",
44
59
  "rollup": "^4.36.0",
45
60
  "rollup-plugin-dts": "^6.2.1",
46
61
  "tslib": "^2.8.1",
@@ -57,6 +72,13 @@
57
72
  "session-recording",
58
73
  "analytics",
59
74
  "rrweb",
60
- "koalaware"
61
- ]
75
+ "koalaware",
76
+ "webpack",
77
+ "esbuild",
78
+ "vite",
79
+ "rollup"
80
+ ],
81
+ "engines": {
82
+ "node": ">=14.0.0"
83
+ }
62
84
  }
package/src/api.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { logError, logInfo } from './utils/logger';
1
+ import { logError, logInfo, logDebug } from './utils/logger';
2
2
 
3
3
  export const MAX_CHUNK_SIZE_BYTES = 1024 * 1024; // 1MB chunk size - more conservative
4
4
 
@@ -278,7 +278,8 @@ export class HumanBehaviorAPI {
278
278
  const payload = {
279
279
  sessionId: sessionId,
280
280
  events: events,
281
- endUserId: null // Beacon doesn't have user context
281
+ endUserId: null, // Beacon doesn't have user context
282
+ apiKey: this.apiKey // Include API key in body since beacon can't use headers
282
283
  };
283
284
 
284
285
  // Convert to Blob for sendBeacon
@@ -295,6 +296,7 @@ export class HumanBehaviorAPI {
295
296
  }
296
297
 
297
298
  async sendCustomEvent(sessionId: string, eventName: string, eventProperties?: Record<string, any>) {
299
+ logInfo('[SDK] Sending custom event', { sessionId, eventName, eventProperties });
298
300
  try {
299
301
  const response = await fetch(`${this.baseUrl}/api/ingestion/customEvent`, {
300
302
  method: 'POST',
@@ -308,14 +310,17 @@ export class HumanBehaviorAPI {
308
310
  eventProperties: eventProperties || {}
309
311
  })
310
312
  });
311
-
313
+ logInfo('[SDK] Custom event response', { status: response.status, statusText: response.statusText });
312
314
  if (!response.ok) {
313
- throw new Error(`Failed to send custom event: ${response.status} ${response.statusText}`);
315
+ const errorText = await response.text();
316
+ logError('[SDK] Failed to send custom event', { status: response.status, statusText: response.statusText, errorText });
317
+ throw new Error(`Failed to send custom event: ${response.status} ${response.statusText} - ${errorText}`);
314
318
  }
315
-
316
- return await response.json();
319
+ const json = await response.json();
320
+ logDebug('[SDK] Custom event success', json);
321
+ return json;
317
322
  } catch (error) {
318
- logError('Error sending custom event:', error);
323
+ logError('[SDK] Error sending custom event', error, { sessionId, eventName, eventProperties });
319
324
  throw error;
320
325
  }
321
326
  }
package/src/index.ts CHANGED
@@ -16,8 +16,8 @@ export * from './redact';
16
16
  // Export logger functionality
17
17
  export * from './utils/logger';
18
18
 
19
- // Also export the tracker as the default export
20
- export { HumanBehaviorTracker as default } from './tracker';
19
+ // Export the tracker as the default export
20
+ export default HumanBehaviorTracker;
21
21
 
22
22
  // For UMD builds, expose the main class globally
23
23
  if (typeof window !== 'undefined') {
@@ -120,14 +120,18 @@ export const HumanBehaviorProvider = ({ apiKey, client, children, options }: Hum
120
120
  // Process any queued events
121
121
  const currentQueue = eventQueueRef.current;
122
122
  if (currentQueue.length > 0) {
123
- currentQueue.forEach(event => {
123
+ for (const event of currentQueue) {
124
124
  if (event.type === 'identify') {
125
125
  logDebug('Processing queued identify event', event.userProperties);
126
- tracker.addUserInfo(event.userProperties);
126
+ try {
127
+ await tracker.addUserInfo(event.userProperties);
128
+ } catch (error) {
129
+ logError('Failed to process queued user info:', error);
130
+ }
127
131
  } else {
128
132
  tracker.addEvent(event);
129
133
  }
130
- });
134
+ }
131
135
  setEventQueue([]); // Clear the queue
132
136
  }
133
137
  }).catch(error => {
@@ -200,6 +204,48 @@ export const useHumanBehavior = () => {
200
204
  return tracker;
201
205
  };
202
206
 
207
+ // Custom hook for managing redaction fields dynamically
208
+ export const useRedaction = () => {
209
+ const tracker = useHumanBehavior();
210
+
211
+ const setRedactedFields = useCallback((fields: string[]) => {
212
+ tracker.setRedactedFields(fields);
213
+ }, [tracker]);
214
+
215
+ const isRedactionActive = useCallback(() => {
216
+ return tracker.isRedactionActive();
217
+ }, [tracker]);
218
+
219
+ const getRedactedFields = useCallback(() => {
220
+ return tracker.getRedactedFields();
221
+ }, [tracker]);
222
+
223
+ return {
224
+ setRedactedFields,
225
+ isRedactionActive,
226
+ getRedactedFields
227
+ };
228
+ };
229
+
230
+ // Custom hook for managing user info
231
+ export const useUserTracking = () => {
232
+ const tracker = useHumanBehavior();
233
+
234
+ const addUserInfo = useCallback(async (userId: string, userProperties: Record<string, any>) => {
235
+ try {
236
+ await tracker.addUserInfo({ userId, userProperties });
237
+ return { success: true };
238
+ } catch (error) {
239
+ logError('Failed to add user info:', error);
240
+ return { success: false, error };
241
+ }
242
+ }, [tracker]);
243
+
244
+ return {
245
+ addUserInfo
246
+ };
247
+ };
248
+
203
249
  // Automatic page tracking component (similar to PostHog's PostHogPageView)
204
250
  function HumanBehaviorPageView() {
205
251
  const tracker = useContext(HumanBehaviorContext);
package/src/tracker.ts CHANGED
@@ -717,30 +717,31 @@ export class HumanBehaviorTracker {
717
717
  }
718
718
  }
719
719
 
720
- public async addUserInfo(userProperties: Record<string, any>) {
720
+ public async addUserInfo(
721
+ { userId, userProperties }: { userId: string, userProperties: Record<string, any> }
722
+ ) {
721
723
  await this.ensureInitialized();
722
724
  if (!this.endUserId) {
723
725
  throw new Error('Cannot add user info before tracker initialization');
724
726
  }
725
727
  this.userProperties = userProperties;
726
728
  await this.api.sendUserData(this.endUserId, userProperties, this.sessionId);
729
+ if (userId) {
730
+ this.endUserId = userId;
731
+ }
727
732
  }
728
733
 
729
734
  /**
730
- * Authenticate user using existing userInfo data
735
+ * Add user identification information to the tracker
731
736
  * @param authFields Array of field names to check for existing users (e.g., ['email', 'phoneNumber'])
732
737
  */
733
- public async auth(authFields: string[]) {
738
+ private async auth(id: string) {
734
739
  await this.ensureInitialized();
735
740
  if (!this.endUserId) {
736
741
  throw new Error('Cannot authenticate before tracker initialization');
737
742
  }
738
- if (!this.userProperties || Object.keys(this.userProperties).length === 0) {
739
- throw new Error('No user info available. Call addUserInfo() first.');
740
- }
741
- const response = await this.api.sendUserAuth(this.endUserId, this.userProperties, this.sessionId, authFields);
743
+ const response = await this.api.sendUserAuth(this.endUserId, { id }, this.sessionId, ["id"]);
742
744
  if (response && response.userId && response.userId !== this.endUserId) {
743
- // Update endUserId and cookie if backend returns a new userId
744
745
  this.endUserId = response.userId;
745
746
  this.setCookie(`human_behavior_end_user_id_${this.apiKey}`, response.userId, 365);
746
747
  }
@@ -903,6 +904,56 @@ export class HumanBehaviorTracker {
903
904
  }
904
905
  }
905
906
 
907
+ /**
908
+ * Delete a cookie by setting its expiration date to the past
909
+ * @param name The name of the cookie to delete
910
+ */
911
+ private deleteCookie(name: string) {
912
+ if (!isBrowser) return;
913
+
914
+ try {
915
+ // Delete cookie by setting expiration to past
916
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Lax`;
917
+ logDebug(`Deleted cookie: ${name}`);
918
+ } catch (error) {
919
+ logError(`Failed to delete cookie: ${name}`, error);
920
+ }
921
+
922
+ // Also remove from localStorage
923
+ try {
924
+ localStorage.removeItem(name);
925
+ logDebug(`Removed from localStorage: ${name}`);
926
+ } catch (error) {
927
+ logError(`Failed to remove from localStorage: ${name}`, error);
928
+ }
929
+ }
930
+
931
+ /**
932
+ * Log out the current user by clearing all user-related data
933
+ * This will delete the user ID cookie, clear localStorage, and reset user properties
934
+ */
935
+ public logout(): void {
936
+ if (!isBrowser) return;
937
+
938
+ try {
939
+ // Clear user ID cookie and localStorage
940
+ const userIdCookieName = `human_behavior_end_user_id_${this.apiKey}`;
941
+ this.deleteCookie(userIdCookieName);
942
+
943
+ // Clear session data from localStorage
944
+ localStorage.removeItem('human_behavior_session_id');
945
+ localStorage.removeItem('human_behavior_last_activity');
946
+
947
+ // Reset user-related properties
948
+ this.endUserId = null;
949
+ this.userProperties = {};
950
+
951
+ logInfo('User logged out - cleared all user data and cookies');
952
+ } catch (error) {
953
+ logError('Error during logout:', error);
954
+ }
955
+ }
956
+
906
957
  /**
907
958
  * Start redaction functionality for sensitive input fields
908
959
  * @param options Optional configuration for redaction behavior
package/rollup.config.js DELETED
@@ -1,106 +0,0 @@
1
- import typescript from '@rollup/plugin-typescript';
2
- import resolve from '@rollup/plugin-node-resolve';
3
- import commonjs from '@rollup/plugin-commonjs';
4
- import terser from '@rollup/plugin-terser';
5
- import dts from 'rollup-plugin-dts';
6
-
7
- // Only React should be external since it's typically provided by the host application
8
- const external = ['react', 'react-dom'];
9
-
10
- // Global variables for UMD build
11
- const globals = {
12
- react: 'React',
13
- 'react-dom': 'ReactDOM'
14
- };
15
-
16
- export default [
17
- // Main SDK bundle
18
- {
19
- input: 'src/index.ts',
20
- output: [
21
- {
22
- file: 'dist/cjs/index.js',
23
- format: 'cjs',
24
- name: 'HumanBehaviorTracker',
25
- globals,
26
- exports: 'named',
27
- sourcemap: true
28
- },
29
- {
30
- file: 'dist/esm/index.js',
31
- format: 'es',
32
- sourcemap: true
33
- },
34
- {
35
- file: 'dist/index.min.js',
36
- format: 'umd',
37
- name: 'HumanBehaviorTracker',
38
- globals,
39
- exports: 'auto',
40
- sourcemap: true,
41
- plugins: [terser()]
42
- }
43
- ],
44
- plugins: [
45
- resolve(),
46
- commonjs(),
47
- typescript({
48
- tsconfig: './tsconfig.json',
49
- declaration: false
50
- })
51
- ],
52
- external
53
- },
54
-
55
- // React component bundle
56
- {
57
- input: './src/react/index.tsx',
58
- output: [
59
- {
60
- file: 'dist/cjs/react/index.js',
61
- format: 'cjs',
62
- name: 'HumanBehaviorReact',
63
- globals: {
64
- ...globals,
65
- '..': 'HumanBehaviorTracker'
66
- },
67
- exports: 'named',
68
- sourcemap: true
69
- },
70
- {
71
- file: 'dist/esm/react/index.js',
72
- format: 'es',
73
- sourcemap: true
74
- }
75
- ],
76
- plugins: [
77
- resolve(),
78
- commonjs(),
79
- typescript({
80
- tsconfig: './tsconfig.json',
81
- declaration: false
82
- })
83
- ],
84
- external: [...external, '..']
85
- },
86
-
87
- // Type definition bundles - generate these separately
88
- {
89
- input: 'src/index.ts',
90
- output: {
91
- file: 'dist/types/index.d.ts',
92
- format: 'es'
93
- },
94
- plugins: [dts()],
95
- external
96
- },
97
- {
98
- input: 'src/react/index.tsx',
99
- output: {
100
- file: 'dist/types/react/index.d.ts',
101
- format: 'es'
102
- },
103
- plugins: [dts()],
104
- external: [...external, '..']
105
- }
106
- ];
package/simple-demo.html DELETED
@@ -1,26 +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 Simple Demo</title>
7
- </head>
8
- <body>
9
- <h1>HumanBehavior Tracker Demo</h1>
10
- <p>This page initializes the HumanBehavior tracker. Check the console for status.</p>
11
-
12
- <button>Click me to test recording</button>
13
- <input type="text" placeholder="Type something">
14
- <input type="password" placeholder="Password (will be redacted)">
15
-
16
- <script src="./dist/index.min.js"></script>
17
- <script>
18
- // Initialize the tracker
19
- const tracker = HumanBehaviorTracker.init('13c3e029-ca45-4a3c-a33b-f5dcb297e31c', {
20
- redactFields: ['input[type="password"]']
21
- });
22
-
23
- console.log('HumanBehavior tracker initialized:', tracker);
24
- </script>
25
- </body>
26
- </html>