humanbehavior-js 0.4.13 → 0.4.14

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.
@@ -10,7 +10,7 @@ import * as path from 'path';
10
10
 
11
11
  export interface FrameworkInfo {
12
12
  name: string;
13
- type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'node' | 'auto';
13
+ type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'astro' | 'gatsby' | 'node' | 'auto';
14
14
  bundler?: 'vite' | 'webpack' | 'esbuild' | 'rollup';
15
15
  packageManager?: 'npm' | 'yarn' | 'pnpm';
16
16
  hasTypeScript?: boolean;
@@ -162,6 +162,22 @@ export class AutoInstallationWizard {
162
162
  hasRouter: !!dependencies['svelte-routing'] || !!dependencies['@sveltejs/kit'],
163
163
  projectRoot: this.projectRoot
164
164
  };
165
+ } else if (dependencies.astro) {
166
+ framework = {
167
+ name: 'astro',
168
+ type: 'astro',
169
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@astrojs/ts-plugin'],
170
+ hasRouter: true,
171
+ projectRoot: this.projectRoot
172
+ };
173
+ } else if (dependencies.gatsby) {
174
+ framework = {
175
+ name: 'gatsby',
176
+ type: 'gatsby',
177
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
178
+ hasRouter: true,
179
+ projectRoot: this.projectRoot
180
+ };
165
181
  }
166
182
 
167
183
  // Detect bundler
@@ -192,11 +208,18 @@ export class AutoInstallationWizard {
192
208
  */
193
209
  protected async installPackage(): Promise<void> {
194
210
  const { execSync } = await import('child_process');
195
- const command = this.framework?.packageManager === 'yarn'
211
+
212
+ // Build base command
213
+ let command = this.framework?.packageManager === 'yarn'
196
214
  ? 'yarn add humanbehavior-js'
197
215
  : this.framework?.packageManager === 'pnpm'
198
216
  ? 'pnpm add humanbehavior-js'
199
217
  : 'npm install humanbehavior-js';
218
+
219
+ // Add legacy peer deps flag for npm to handle dependency conflicts
220
+ if (this.framework?.packageManager !== 'yarn' && this.framework?.packageManager !== 'pnpm') {
221
+ command += ' --legacy-peer-deps';
222
+ }
200
223
 
201
224
  try {
202
225
  execSync(command, { cwd: this.projectRoot, stdio: 'inherit' });
@@ -221,6 +244,12 @@ export class AutoInstallationWizard {
221
244
  case 'nuxt':
222
245
  modifications.push(...await this.generateNuxtModifications());
223
246
  break;
247
+ case 'astro':
248
+ modifications.push(...await this.generateAstroModifications());
249
+ break;
250
+ case 'gatsby':
251
+ modifications.push(...await this.generateGatsbyModifications());
252
+ break;
224
253
  case 'remix':
225
254
  modifications.push(...await this.generateRemixModifications());
226
255
  break;
@@ -342,6 +371,91 @@ export function Providers({ children }: { children: React.ReactNode }) {
342
371
  return modifications;
343
372
  }
344
373
 
374
+ /**
375
+ * Generate Astro-specific modifications
376
+ */
377
+ private async generateAstroModifications(): Promise<CodeModification[]> {
378
+ const modifications: CodeModification[] = [];
379
+
380
+ // Create Astro component for HumanBehavior
381
+ const astroComponentPath = path.join(this.projectRoot, 'src', 'components', 'HumanBehavior.astro');
382
+ const astroComponentContent = `---
383
+ // This component will only run on the client side
384
+ ---
385
+
386
+ <script>
387
+ import { HumanBehaviorTracker } from 'humanbehavior-js';
388
+
389
+ // Get API key from environment variable
390
+ const apiKey = import.meta.env.PUBLIC_HUMANBEHAVIOR_API_KEY;
391
+
392
+ console.log('HumanBehavior: API key found:', apiKey ? 'Yes' : 'No');
393
+
394
+ if (apiKey) {
395
+ try {
396
+ const tracker = HumanBehaviorTracker.init(apiKey);
397
+ console.log('HumanBehavior: Tracker initialized successfully');
398
+
399
+ // Test event to verify tracking is working
400
+ setTimeout(() => {
401
+ tracker.customEvent('astro_page_view', {
402
+ page: window.location.pathname,
403
+ framework: 'astro'
404
+ }).then(() => {
405
+ console.log('HumanBehavior: Test event sent successfully');
406
+ }).catch((error) => {
407
+ console.error('HumanBehavior: Failed to send test event:', error);
408
+ });
409
+ }, 1000);
410
+
411
+ } catch (error) {
412
+ console.error('HumanBehavior: Failed to initialize tracker:', error);
413
+ }
414
+ } else {
415
+ console.error('HumanBehavior: No API key found');
416
+ }
417
+ </script>`;
418
+
419
+ modifications.push({
420
+ filePath: astroComponentPath,
421
+ action: 'create',
422
+ content: astroComponentContent,
423
+ description: 'Created Astro component for HumanBehavior SDK'
424
+ });
425
+
426
+ // Find and update layout file
427
+ const layoutFiles = [
428
+ path.join(this.projectRoot, 'src', 'layouts', 'Layout.astro'),
429
+ path.join(this.projectRoot, 'src', 'layouts', 'layout.astro'),
430
+ path.join(this.projectRoot, 'src', 'layouts', 'BaseLayout.astro')
431
+ ];
432
+
433
+ let layoutFile = null;
434
+ for (const file of layoutFiles) {
435
+ if (fs.existsSync(file)) {
436
+ layoutFile = file;
437
+ break;
438
+ }
439
+ }
440
+
441
+ if (layoutFile) {
442
+ const content = fs.readFileSync(layoutFile, 'utf8');
443
+ const modifiedContent = this.injectAstroLayout(content);
444
+
445
+ modifications.push({
446
+ filePath: layoutFile,
447
+ action: 'modify',
448
+ content: modifiedContent,
449
+ description: 'Added HumanBehavior component to Astro layout'
450
+ });
451
+ }
452
+
453
+ // Add environment variable
454
+ modifications.push(this.createEnvironmentModification(this.framework!));
455
+
456
+ return modifications;
457
+ }
458
+
345
459
  /**
346
460
  * Generate Nuxt-specific modifications
347
461
  */
@@ -588,6 +702,55 @@ export default defineNuxtPlugin(() => {
588
702
  return modifications;
589
703
  }
590
704
 
705
+ /**
706
+ * Generate Gatsby-specific modifications
707
+ */
708
+ private async generateGatsbyModifications(): Promise<CodeModification[]> {
709
+ const modifications: CodeModification[] = [];
710
+
711
+ // Modify or create gatsby-browser.js for Gatsby
712
+ const gatsbyBrowserFile = path.join(this.projectRoot, 'gatsby-browser.js');
713
+
714
+ if (fs.existsSync(gatsbyBrowserFile)) {
715
+ const content = fs.readFileSync(gatsbyBrowserFile, 'utf8');
716
+ const modifiedContent = this.injectGatsbyBrowser(content);
717
+
718
+ modifications.push({
719
+ filePath: gatsbyBrowserFile,
720
+ action: 'modify',
721
+ content: modifiedContent,
722
+ description: 'Added HumanBehavior initialization to Gatsby browser'
723
+ });
724
+ } else {
725
+ // Create gatsby-browser.js if it doesn't exist
726
+ modifications.push({
727
+ filePath: gatsbyBrowserFile,
728
+ action: 'create',
729
+ content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
730
+
731
+ export const onClientEntry = () => {
732
+ console.log('Gatsby browser entry point loaded');
733
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
734
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
735
+ if (apiKey) {
736
+ const tracker = HumanBehaviorTracker.init(apiKey);
737
+ console.log('HumanBehavior SDK initialized for Gatsby');
738
+ } else {
739
+ console.log('No API key found in environment variables');
740
+ }
741
+ };`,
742
+ description: 'Created gatsby-browser.js with HumanBehavior initialization'
743
+ });
744
+ }
745
+
746
+ // Create or append to environment file
747
+ modifications.push(this.createEnvironmentModification(this.framework!));
748
+
749
+ return modifications;
750
+ }
751
+
752
+
753
+
591
754
  /**
592
755
  * Apply modifications to the codebase
593
756
  */
@@ -1012,6 +1175,40 @@ if (typeof window !== 'undefined') {
1012
1175
  );
1013
1176
  }
1014
1177
 
1178
+ /**
1179
+ * Inject Astro layout with HumanBehavior component
1180
+ */
1181
+ private injectAstroLayout(content: string): string {
1182
+ // Check if HumanBehavior component is already imported
1183
+ if (content.includes('HumanBehavior') || content.includes('humanbehavior-js')) {
1184
+ return content; // Already has HumanBehavior
1185
+ }
1186
+
1187
+ // Add import inside frontmatter if not present
1188
+ let modifiedContent = content;
1189
+ if (!content.includes('import HumanBehavior')) {
1190
+ const importStatement = 'import HumanBehavior from \'../components/HumanBehavior.astro\';';
1191
+ const frontmatterEndIndex = content.indexOf('---', 3);
1192
+ if (frontmatterEndIndex !== -1) {
1193
+ // Insert import inside frontmatter, before the closing ---
1194
+ modifiedContent = content.slice(0, frontmatterEndIndex) + '\n' + importStatement + '\n' + content.slice(frontmatterEndIndex);
1195
+ } else {
1196
+ // No frontmatter, add at the very beginning
1197
+ modifiedContent = '---\n' + importStatement + '\n---\n\n' + content;
1198
+ }
1199
+ }
1200
+
1201
+ // Find the closing </body> tag and add HumanBehavior component before it
1202
+ const bodyCloseIndex = modifiedContent.lastIndexOf('</body>');
1203
+ if (bodyCloseIndex === -1) {
1204
+ // No body tag found, append to end
1205
+ return modifiedContent + '\n\n<HumanBehavior />';
1206
+ }
1207
+
1208
+ // Add component before closing body tag
1209
+ return modifiedContent.slice(0, bodyCloseIndex) + ' <HumanBehavior />\n' + modifiedContent.slice(bodyCloseIndex);
1210
+ }
1211
+
1015
1212
  private injectNuxtConfig(content: string): string {
1016
1213
  if (content.includes('humanBehaviorApiKey')) {
1017
1214
  return content;
@@ -1029,6 +1226,60 @@ if (typeof window !== 'undefined') {
1029
1226
  );
1030
1227
  }
1031
1228
 
1229
+ private injectGatsbyLayout(content: string): string {
1230
+ if (content.includes('HumanBehavior')) {
1231
+ return content;
1232
+ }
1233
+
1234
+ const importStatement = `import HumanBehavior from './HumanBehavior';`;
1235
+ const componentUsage = `<HumanBehavior apiKey={process.env.GATSBY_HUMANBEHAVIOR_API_KEY || ''} />`;
1236
+
1237
+ // Add import at the top
1238
+ let modifiedContent = content.replace(
1239
+ /import.*from.*['"]\./,
1240
+ `${importStatement}\n$&`
1241
+ );
1242
+
1243
+ // Add component before closing body tag
1244
+ modifiedContent = modifiedContent.replace(
1245
+ /(\s*<\/body>)/,
1246
+ `\n ${componentUsage}\n$1`
1247
+ );
1248
+
1249
+ return modifiedContent;
1250
+ }
1251
+
1252
+ private injectGatsbyBrowser(content: string): string {
1253
+ if (content.includes('HumanBehaviorTracker')) {
1254
+ return content;
1255
+ }
1256
+
1257
+ const importStatement = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
1258
+ const initCode = `
1259
+ // Initialize HumanBehavior SDK
1260
+ export const onClientEntry = () => {
1261
+ console.log('Gatsby browser entry point loaded');
1262
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
1263
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
1264
+ if (apiKey) {
1265
+ const tracker = HumanBehaviorTracker.init(apiKey);
1266
+ console.log('HumanBehavior SDK initialized for Gatsby');
1267
+ } else {
1268
+ console.log('No API key found in environment variables');
1269
+ }
1270
+ };`;
1271
+
1272
+ // If the file already has content, add the import and init code
1273
+ if (content.trim()) {
1274
+ return `${importStatement}${initCode}\n\n${content}`;
1275
+ } else {
1276
+ // If file is empty, just return the new content
1277
+ return `${importStatement}${initCode}`;
1278
+ }
1279
+ }
1280
+
1281
+
1282
+
1032
1283
  /**
1033
1284
  * Helper method to find the best environment file for a framework
1034
1285
  */
@@ -1052,16 +1303,18 @@ if (typeof window !== 'undefined') {
1052
1303
 
1053
1304
  // Framework-specific mappings
1054
1305
  const envVarNames = {
1055
- react: 'HUMANBEHAVIOR_API_KEY',
1056
- nextjs: 'NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1057
- vue: 'VITE_HUMANBEHAVIOR_API_KEY',
1058
- svelte: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1059
- angular: 'HUMANBEHAVIOR_API_KEY',
1060
- nuxt: 'NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1061
- remix: 'HUMANBEHAVIOR_API_KEY',
1062
- vanilla: 'HUMANBEHAVIOR_API_KEY',
1063
- node: 'HUMANBEHAVIOR_API_KEY',
1064
- auto: 'HUMANBEHAVIOR_API_KEY'
1306
+ react: 'HUMANBEHAVIOR_API_KEY',
1307
+ nextjs: 'NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1308
+ vue: 'VITE_HUMANBEHAVIOR_API_KEY',
1309
+ svelte: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1310
+ angular: 'HUMANBEHAVIOR_API_KEY',
1311
+ nuxt: 'NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1312
+ remix: 'HUMANBEHAVIOR_API_KEY',
1313
+ vanilla: 'HUMANBEHAVIOR_API_KEY',
1314
+ astro: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1315
+ gatsby: 'GATSBY_HUMANBEHAVIOR_API_KEY',
1316
+ node: 'HUMANBEHAVIOR_API_KEY',
1317
+ auto: 'HUMANBEHAVIOR_API_KEY'
1065
1318
  };
1066
1319
 
1067
1320
  return envVarNames[framework.type] || 'HUMANBEHAVIOR_API_KEY';
@@ -1087,6 +1340,8 @@ if (typeof window !== 'undefined') {
1087
1340
  nuxt: '.env',
1088
1341
  remix: '.env.local',
1089
1342
  vanilla: '.env',
1343
+ astro: '.env',
1344
+ gatsby: '.env.development',
1090
1345
  node: '.env',
1091
1346
  auto: '.env'
1092
1347
  };
@@ -1104,6 +1359,9 @@ if (typeof window !== 'undefined') {
1104
1359
  private createEnvironmentModification(framework: FrameworkInfo): CodeModification {
1105
1360
  const { filePath, envVarName } = this.findBestEnvFile(framework);
1106
1361
 
1362
+ // Clean the API key to prevent formatting issues
1363
+ const cleanApiKey = this.apiKey.trim();
1364
+
1107
1365
  if (fs.existsSync(filePath)) {
1108
1366
  // Check if the variable already exists
1109
1367
  const content = fs.readFileSync(filePath, 'utf8');
@@ -1120,7 +1378,7 @@ if (typeof window !== 'undefined') {
1120
1378
  return {
1121
1379
  filePath,
1122
1380
  action: 'append',
1123
- content: `\n${envVarName}=${this.apiKey}`,
1381
+ content: `\n${envVarName}=${cleanApiKey}`,
1124
1382
  description: `Added API key to existing ${path.basename(filePath)}`
1125
1383
  };
1126
1384
  }
@@ -1129,7 +1387,7 @@ if (typeof window !== 'undefined') {
1129
1387
  return {
1130
1388
  filePath,
1131
1389
  action: 'create',
1132
- content: `${envVarName}=${this.apiKey}`,
1390
+ content: `${envVarName}=${cleanApiKey}`,
1133
1391
  description: `Created ${path.basename(filePath)} with API key`
1134
1392
  };
1135
1393
  }
@@ -15,7 +15,7 @@ import { AICodeAnalysis } from '../ai/ai-install-wizard';
15
15
 
16
16
  export interface FrameworkInfo {
17
17
  name: string;
18
- type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'node';
18
+ type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'astro' | 'node';
19
19
  bundler?: 'vite' | 'webpack' | 'esbuild' | 'rollup';
20
20
  packageManager?: 'npm' | 'yarn' | 'pnpm';
21
21
  hasTypeScript?: boolean;
@@ -8,7 +8,7 @@ import { AICodeAnalysis } from '../ai/ai-install-wizard';
8
8
 
9
9
  export interface FrameworkInfo {
10
10
  name: string;
11
- type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'node';
11
+ type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'astro' | 'gatsby' | 'node';
12
12
  bundler?: 'vite' | 'webpack' | 'esbuild' | 'rollup';
13
13
  packageManager?: 'npm' | 'yarn' | 'pnpm';
14
14
  hasTypeScript?: boolean;
@@ -125,6 +125,9 @@ export class RemoteAIService {
125
125
  } else if (patterns.includes('next') || patterns.includes('nextjs') || patterns.includes('next/link') || patterns.includes('next/image') || patterns.includes('next/navigation') || patterns.includes('next/router') || patterns.includes('getserverSideProps') || patterns.includes('getstaticProps') || patterns.includes('getstaticPaths') || patterns.includes('app/layout') || patterns.includes('app/page') || patterns.includes('pages/')) {
126
126
  framework = { name: 'nextjs', type: 'nextjs' };
127
127
  confidence = 0.95;
128
+ } else if (patterns.includes('gatsby') || patterns.includes('gatsby-browser') || patterns.includes('gatsby-ssr') || patterns.includes('gatsby-node') || patterns.includes('gatsby-config') || patterns.includes('useStaticQuery') || patterns.includes('graphql')) {
129
+ framework = { name: 'gatsby', type: 'gatsby' };
130
+ confidence = 0.95;
128
131
  } else if (patterns.includes('react')) {
129
132
  framework = { name: 'react', type: 'react' };
130
133
  confidence = 0.9;
@@ -137,11 +140,14 @@ export class RemoteAIService {
137
140
  } else if (patterns.includes('svelte')) {
138
141
  framework = { name: 'svelte', type: 'svelte' };
139
142
  confidence = 0.9;
143
+ } else if (patterns.includes('astro')) {
144
+ framework = { name: 'astro', type: 'astro' };
145
+ confidence = 0.9;
140
146
  }
141
147
 
142
148
  // Integration strategy
143
149
  let integrationStrategy: 'provider' | 'plugin' | 'module' | 'script' | 'standalone' = 'script';
144
- if (framework.type === 'react' || framework.type === 'nextjs') {
150
+ if (framework.type === 'react' || framework.type === 'nextjs' || framework.type === 'gatsby') {
145
151
  integrationStrategy = 'provider';
146
152
  } else if (framework.type === 'vue') {
147
153
  integrationStrategy = 'plugin';
package/tsconfig.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "forceConsistentCasingInFileNames": true,
19
19
  "lib": ["dom", "dom.iterable", "esnext"]
20
20
  },
21
- "include": ["src/**/*.ts", "src/**/*.tsx"],
21
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/types/**/*.d.ts"],
22
22
 
23
23
  "exclude": ["node_modules", "dist", "test-website"]
24
24
  }