humanbehavior-js 0.4.13 → 0.4.15

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,12 +10,22 @@ 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;
17
17
  hasRouter?: boolean;
18
18
  projectRoot?: string;
19
+ version?: string;
20
+ majorVersion?: number;
21
+ features?: {
22
+ hasReact18?: boolean;
23
+ hasVue3?: boolean;
24
+ hasNuxt3?: boolean;
25
+ hasAngularStandalone?: boolean;
26
+ hasNextAppRouter?: boolean;
27
+ hasSvelteKit?: boolean;
28
+ };
19
29
  }
20
30
 
21
31
  export interface CodeModification {
@@ -43,6 +53,30 @@ export class AutoInstallationWizard {
43
53
  this.projectRoot = projectRoot;
44
54
  }
45
55
 
56
+ /**
57
+ * Simple version comparison utility
58
+ */
59
+ private compareVersions(version1: string, version2: string): number {
60
+ const v1Parts = version1.split('.').map(Number);
61
+ const v2Parts = version2.split('.').map(Number);
62
+
63
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
64
+ const v1 = v1Parts[i] || 0;
65
+ const v2 = v2Parts[i] || 0;
66
+ if (v1 > v2) return 1;
67
+ if (v1 < v2) return -1;
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ private isVersionGte(version: string, target: string): boolean {
73
+ return this.compareVersions(version, target) >= 0;
74
+ }
75
+
76
+ private getMajorVersion(version: string): number {
77
+ return parseInt(version.split('.')[0]) || 0;
78
+ }
79
+
46
80
  /**
47
81
  * Main installation method - detects framework and auto-installs
48
82
  */
@@ -99,68 +133,145 @@ export class AutoInstallationWizard {
99
133
  ...packageJson.devDependencies
100
134
  };
101
135
 
102
- // Detect framework
136
+ // Detect framework with version information
103
137
  let framework: FrameworkInfo = {
104
138
  name: 'vanilla',
105
139
  type: 'vanilla',
106
- projectRoot: this.projectRoot
140
+ projectRoot: this.projectRoot,
141
+ features: {}
107
142
  };
108
143
 
109
144
  if (dependencies.nuxt) {
145
+ const nuxtVersion = dependencies.nuxt;
146
+ const isNuxt3 = this.isVersionGte(nuxtVersion, '3.0.0');
147
+
110
148
  framework = {
111
149
  name: 'nuxt',
112
150
  type: 'nuxt',
151
+ version: nuxtVersion,
152
+ majorVersion: this.getMajorVersion(nuxtVersion),
113
153
  hasTypeScript: !!dependencies.typescript,
114
154
  hasRouter: true,
115
- projectRoot: this.projectRoot
155
+ projectRoot: this.projectRoot,
156
+ features: {
157
+ hasNuxt3: isNuxt3
158
+ }
116
159
  };
117
160
  } else if (dependencies.next) {
161
+ const nextVersion = dependencies.next;
162
+ const isNext13 = this.isVersionGte(nextVersion, '13.0.0');
163
+
118
164
  framework = {
119
165
  name: 'nextjs',
120
166
  type: 'nextjs',
167
+ version: nextVersion,
168
+ majorVersion: this.getMajorVersion(nextVersion),
121
169
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/node'],
122
170
  hasRouter: true,
123
- projectRoot: this.projectRoot
171
+ projectRoot: this.projectRoot,
172
+ features: {
173
+ hasNextAppRouter: isNext13
174
+ }
124
175
  };
125
176
  } else if (dependencies['@remix-run/react'] || dependencies['@remix-run/dev']) {
177
+ const remixVersion = dependencies['@remix-run/react'] || dependencies['@remix-run/dev'];
126
178
  framework = {
127
179
  name: 'remix',
128
180
  type: 'remix',
181
+ version: remixVersion,
182
+ majorVersion: this.getMajorVersion(remixVersion),
129
183
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
130
184
  hasRouter: true,
131
- projectRoot: this.projectRoot
185
+ projectRoot: this.projectRoot,
186
+ features: {}
132
187
  };
133
188
  } else if (dependencies.react) {
189
+ const reactVersion = dependencies.react;
190
+ const isReact18 = this.isVersionGte(reactVersion, '18.0.0');
191
+
134
192
  framework = {
135
193
  name: 'react',
136
194
  type: 'react',
195
+ version: reactVersion,
196
+ majorVersion: this.getMajorVersion(reactVersion),
137
197
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
138
198
  hasRouter: !!dependencies['react-router-dom'] || !!dependencies['react-router'],
139
- projectRoot: this.projectRoot
199
+ projectRoot: this.projectRoot,
200
+ features: {
201
+ hasReact18: isReact18
202
+ }
140
203
  };
141
204
  } else if (dependencies.vue) {
205
+ const vueVersion = dependencies.vue;
206
+ const isVue3 = this.isVersionGte(vueVersion, '3.0.0');
207
+
142
208
  framework = {
143
209
  name: 'vue',
144
210
  type: 'vue',
211
+ version: vueVersion,
212
+ majorVersion: this.getMajorVersion(vueVersion),
145
213
  hasTypeScript: !!dependencies.typescript || !!dependencies['@vue/cli-service'],
146
214
  hasRouter: !!dependencies['vue-router'],
147
- projectRoot: this.projectRoot
215
+ projectRoot: this.projectRoot,
216
+ features: {
217
+ hasVue3: isVue3
218
+ }
148
219
  };
149
220
  } else if (dependencies['@angular/core']) {
221
+ const angularVersion = dependencies['@angular/core'];
222
+ const isAngular17 = this.isVersionGte(angularVersion, '17.0.0');
223
+
150
224
  framework = {
151
225
  name: 'angular',
152
226
  type: 'angular',
227
+ version: angularVersion,
228
+ majorVersion: this.getMajorVersion(angularVersion),
153
229
  hasTypeScript: true,
154
230
  hasRouter: true,
155
- projectRoot: this.projectRoot
231
+ projectRoot: this.projectRoot,
232
+ features: {
233
+ hasAngularStandalone: isAngular17
234
+ }
156
235
  };
157
236
  } else if (dependencies.svelte) {
237
+ const svelteVersion = dependencies.svelte;
238
+ const isSvelteKit = !!dependencies['@sveltejs/kit'];
239
+
158
240
  framework = {
159
241
  name: 'svelte',
160
242
  type: 'svelte',
243
+ version: svelteVersion,
244
+ majorVersion: this.getMajorVersion(svelteVersion),
161
245
  hasTypeScript: !!dependencies.typescript || !!dependencies['svelte-check'],
162
246
  hasRouter: !!dependencies['svelte-routing'] || !!dependencies['@sveltejs/kit'],
163
- projectRoot: this.projectRoot
247
+ projectRoot: this.projectRoot,
248
+ features: {
249
+ hasSvelteKit: isSvelteKit
250
+ }
251
+ };
252
+ } else if (dependencies.astro) {
253
+ const astroVersion = dependencies.astro;
254
+ framework = {
255
+ name: 'astro',
256
+ type: 'astro',
257
+ version: astroVersion,
258
+ majorVersion: this.getMajorVersion(astroVersion),
259
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@astrojs/ts-plugin'],
260
+ hasRouter: true,
261
+ projectRoot: this.projectRoot,
262
+ features: {}
263
+ };
264
+ } else if (dependencies.gatsby) {
265
+ const gatsbyVersion = dependencies.gatsby;
266
+ framework = {
267
+ name: 'gatsby',
268
+ type: 'gatsby',
269
+ version: gatsbyVersion,
270
+ majorVersion: this.getMajorVersion(gatsbyVersion),
271
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
272
+ hasRouter: true,
273
+ projectRoot: this.projectRoot,
274
+ features: {}
164
275
  };
165
276
  }
166
277
 
@@ -192,11 +303,18 @@ export class AutoInstallationWizard {
192
303
  */
193
304
  protected async installPackage(): Promise<void> {
194
305
  const { execSync } = await import('child_process');
195
- const command = this.framework?.packageManager === 'yarn'
306
+
307
+ // Build base command
308
+ let command = this.framework?.packageManager === 'yarn'
196
309
  ? 'yarn add humanbehavior-js'
197
310
  : this.framework?.packageManager === 'pnpm'
198
311
  ? 'pnpm add humanbehavior-js'
199
312
  : 'npm install humanbehavior-js';
313
+
314
+ // Add legacy peer deps flag for npm to handle dependency conflicts
315
+ if (this.framework?.packageManager !== 'yarn' && this.framework?.packageManager !== 'pnpm') {
316
+ command += ' --legacy-peer-deps';
317
+ }
200
318
 
201
319
  try {
202
320
  execSync(command, { cwd: this.projectRoot, stdio: 'inherit' });
@@ -221,6 +339,12 @@ export class AutoInstallationWizard {
221
339
  case 'nuxt':
222
340
  modifications.push(...await this.generateNuxtModifications());
223
341
  break;
342
+ case 'astro':
343
+ modifications.push(...await this.generateAstroModifications());
344
+ break;
345
+ case 'gatsby':
346
+ modifications.push(...await this.generateGatsbyModifications());
347
+ break;
224
348
  case 'remix':
225
349
  modifications.push(...await this.generateRemixModifications());
226
350
  break;
@@ -342,6 +466,91 @@ export function Providers({ children }: { children: React.ReactNode }) {
342
466
  return modifications;
343
467
  }
344
468
 
469
+ /**
470
+ * Generate Astro-specific modifications
471
+ */
472
+ private async generateAstroModifications(): Promise<CodeModification[]> {
473
+ const modifications: CodeModification[] = [];
474
+
475
+ // Create Astro component for HumanBehavior
476
+ const astroComponentPath = path.join(this.projectRoot, 'src', 'components', 'HumanBehavior.astro');
477
+ const astroComponentContent = `---
478
+ // This component will only run on the client side
479
+ ---
480
+
481
+ <script>
482
+ import { HumanBehaviorTracker } from 'humanbehavior-js';
483
+
484
+ // Get API key from environment variable
485
+ const apiKey = import.meta.env.PUBLIC_HUMANBEHAVIOR_API_KEY;
486
+
487
+ console.log('HumanBehavior: API key found:', apiKey ? 'Yes' : 'No');
488
+
489
+ if (apiKey) {
490
+ try {
491
+ const tracker = HumanBehaviorTracker.init(apiKey);
492
+ console.log('HumanBehavior: Tracker initialized successfully');
493
+
494
+ // Test event to verify tracking is working
495
+ setTimeout(() => {
496
+ tracker.customEvent('astro_page_view', {
497
+ page: window.location.pathname,
498
+ framework: 'astro'
499
+ }).then(() => {
500
+ console.log('HumanBehavior: Test event sent successfully');
501
+ }).catch((error) => {
502
+ console.error('HumanBehavior: Failed to send test event:', error);
503
+ });
504
+ }, 1000);
505
+
506
+ } catch (error) {
507
+ console.error('HumanBehavior: Failed to initialize tracker:', error);
508
+ }
509
+ } else {
510
+ console.error('HumanBehavior: No API key found');
511
+ }
512
+ </script>`;
513
+
514
+ modifications.push({
515
+ filePath: astroComponentPath,
516
+ action: 'create',
517
+ content: astroComponentContent,
518
+ description: 'Created Astro component for HumanBehavior SDK'
519
+ });
520
+
521
+ // Find and update layout file
522
+ const layoutFiles = [
523
+ path.join(this.projectRoot, 'src', 'layouts', 'Layout.astro'),
524
+ path.join(this.projectRoot, 'src', 'layouts', 'layout.astro'),
525
+ path.join(this.projectRoot, 'src', 'layouts', 'BaseLayout.astro')
526
+ ];
527
+
528
+ let layoutFile = null;
529
+ for (const file of layoutFiles) {
530
+ if (fs.existsSync(file)) {
531
+ layoutFile = file;
532
+ break;
533
+ }
534
+ }
535
+
536
+ if (layoutFile) {
537
+ const content = fs.readFileSync(layoutFile, 'utf8');
538
+ const modifiedContent = this.injectAstroLayout(content);
539
+
540
+ modifications.push({
541
+ filePath: layoutFile,
542
+ action: 'modify',
543
+ content: modifiedContent,
544
+ description: 'Added HumanBehavior component to Astro layout'
545
+ });
546
+ }
547
+
548
+ // Add environment variable
549
+ modifications.push(this.createEnvironmentModification(this.framework!));
550
+
551
+ return modifications;
552
+ }
553
+
345
554
  /**
346
555
  * Generate Nuxt-specific modifications
347
556
  */
@@ -588,6 +797,55 @@ export default defineNuxtPlugin(() => {
588
797
  return modifications;
589
798
  }
590
799
 
800
+ /**
801
+ * Generate Gatsby-specific modifications
802
+ */
803
+ private async generateGatsbyModifications(): Promise<CodeModification[]> {
804
+ const modifications: CodeModification[] = [];
805
+
806
+ // Modify or create gatsby-browser.js for Gatsby
807
+ const gatsbyBrowserFile = path.join(this.projectRoot, 'gatsby-browser.js');
808
+
809
+ if (fs.existsSync(gatsbyBrowserFile)) {
810
+ const content = fs.readFileSync(gatsbyBrowserFile, 'utf8');
811
+ const modifiedContent = this.injectGatsbyBrowser(content);
812
+
813
+ modifications.push({
814
+ filePath: gatsbyBrowserFile,
815
+ action: 'modify',
816
+ content: modifiedContent,
817
+ description: 'Added HumanBehavior initialization to Gatsby browser'
818
+ });
819
+ } else {
820
+ // Create gatsby-browser.js if it doesn't exist
821
+ modifications.push({
822
+ filePath: gatsbyBrowserFile,
823
+ action: 'create',
824
+ content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
825
+
826
+ export const onClientEntry = () => {
827
+ console.log('Gatsby browser entry point loaded');
828
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
829
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
830
+ if (apiKey) {
831
+ const tracker = HumanBehaviorTracker.init(apiKey);
832
+ console.log('HumanBehavior SDK initialized for Gatsby');
833
+ } else {
834
+ console.log('No API key found in environment variables');
835
+ }
836
+ };`,
837
+ description: 'Created gatsby-browser.js with HumanBehavior initialization'
838
+ });
839
+ }
840
+
841
+ // Create or append to environment file
842
+ modifications.push(this.createEnvironmentModification(this.framework!));
843
+
844
+ return modifications;
845
+ }
846
+
847
+
848
+
591
849
  /**
592
850
  * Apply modifications to the codebase
593
851
  */
@@ -705,30 +963,61 @@ export default defineNuxtPlugin(() => {
705
963
  : 'process.env.HUMANBEHAVIOR_API_KEY!';
706
964
 
707
965
  const importStatement = `import { HumanBehaviorProvider } from 'humanbehavior-js/react';`;
708
- const providerWrapper = `
709
- function App() {
710
- return (
711
- <HumanBehaviorProvider apiKey={${envVar}}>
712
- {/* Your existing app content */}
713
- </HumanBehaviorProvider>
714
- );
715
- }`;
716
966
 
717
- // Simple injection - in production, you'd want more sophisticated parsing
967
+ // Enhanced parsing for React 18+ features
968
+ const hasReact18 = this.framework?.features?.hasReact18;
969
+
970
+ // Handle different React patterns
718
971
  if (content.includes('function App()') || content.includes('const App =')) {
719
- return content.replace(
720
- /(function App\(\)|const App =)/,
721
- `${importStatement}\n\n$1`
722
- ).replace(
723
- /return \(([\s\S]*?)\);/,
972
+ // Add import statement
973
+ let modifiedContent = content.replace(
974
+ /(import.*?from.*?['"]react['"];?)/,
975
+ `$1\n${importStatement}`
976
+ );
977
+
978
+ // If no React import found, add it at the top
979
+ if (!modifiedContent.includes(importStatement)) {
980
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
981
+ }
982
+
983
+ // Wrap the App component return with HumanBehaviorProvider
984
+ modifiedContent = modifiedContent.replace(
985
+ /(return\s*\([\s\S]*?\)\s*;)/,
724
986
  `return (
725
987
  <HumanBehaviorProvider apiKey={${envVar}}>
726
988
  $1
727
989
  </HumanBehaviorProvider>
728
990
  );`
729
991
  );
992
+
993
+ return modifiedContent;
994
+ }
995
+
996
+ // Handle React 18+ createRoot pattern
997
+ if (hasReact18 && content.includes('createRoot')) {
998
+ let modifiedContent = content.replace(
999
+ /(import.*?from.*?['"]react['"];?)/,
1000
+ `$1\n${importStatement}`
1001
+ );
1002
+
1003
+ if (!modifiedContent.includes(importStatement)) {
1004
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1005
+ }
1006
+
1007
+ // Wrap the root render with HumanBehaviorProvider
1008
+ modifiedContent = modifiedContent.replace(
1009
+ /(root\.render\s*\([\s\S]*?\)\s*;)/,
1010
+ `root.render(
1011
+ <HumanBehaviorProvider apiKey={${envVar}}>
1012
+ $1
1013
+ </HumanBehaviorProvider>
1014
+ );`
1015
+ );
1016
+
1017
+ return modifiedContent;
730
1018
  }
731
1019
 
1020
+ // Fallback: simple injection
732
1021
  return `${importStatement}\n\n${content}`;
733
1022
  }
734
1023
 
@@ -863,29 +1152,69 @@ export default function App()`
863
1152
  }
864
1153
 
865
1154
  const importStatement = `import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';`;
866
- const pluginUsage = `app.use(HumanBehaviorPlugin, {
1155
+
1156
+ // Enhanced Vue 3 support with version detection
1157
+ const hasVue3 = this.framework?.features?.hasVue3;
1158
+
1159
+ if (hasVue3) {
1160
+ // Vue 3 with Composition API
1161
+ const pluginUsage = `app.use(HumanBehaviorPlugin, {
867
1162
  apiKey: import.meta.env.VITE_HUMANBEHAVIOR_API_KEY
868
1163
  });`;
869
1164
 
870
- // Handle both Vue 2 and Vue 3 patterns
871
- if (content.includes('createApp')) {
872
- // Vue 3
873
- return content.replace(
874
- /import.*from.*['"]vue['"]/,
875
- `$&\n${importStatement}`
876
- ).replace(
877
- /app\.mount\(/,
878
- `${pluginUsage}\n\napp.mount(`
879
- );
1165
+ let modifiedContent = content;
1166
+
1167
+ // Add import statement
1168
+ if (!content.includes(importStatement)) {
1169
+ modifiedContent = content.replace(
1170
+ /(import.*?from.*?['"]vue['"];?)/,
1171
+ `$1\n${importStatement}`
1172
+ );
1173
+
1174
+ // If no Vue import found, add it at the top
1175
+ if (!modifiedContent.includes(importStatement)) {
1176
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1177
+ }
1178
+ }
1179
+
1180
+ // Handle createApp pattern
1181
+ if (content.includes('createApp')) {
1182
+ modifiedContent = modifiedContent.replace(
1183
+ /(app\.mount\(.*?\))/,
1184
+ `${pluginUsage}\n\n$1`
1185
+ );
1186
+ }
1187
+
1188
+ return modifiedContent;
880
1189
  } else {
881
- // Vue 2
882
- return content.replace(
883
- /import.*from.*['"]vue['"]/,
884
- `$&\n${importStatement}`
885
- ).replace(
886
- /new Vue\(/,
887
- `${pluginUsage}\n\nnew Vue(`
888
- );
1190
+ // Vue 2 with Options API
1191
+ const pluginUsage = `Vue.use(HumanBehaviorPlugin, {
1192
+ apiKey: process.env.VUE_APP_HUMANBEHAVIOR_API_KEY
1193
+ });`;
1194
+
1195
+ let modifiedContent = content;
1196
+
1197
+ // Add import statement
1198
+ if (!content.includes(importStatement)) {
1199
+ modifiedContent = content.replace(
1200
+ /(import.*?from.*?['"]vue['"];?)/,
1201
+ `$1\n${importStatement}`
1202
+ );
1203
+
1204
+ if (!modifiedContent.includes(importStatement)) {
1205
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1206
+ }
1207
+ }
1208
+
1209
+ // Handle new Vue pattern
1210
+ if (content.includes('new Vue')) {
1211
+ modifiedContent = modifiedContent.replace(
1212
+ /(new Vue\(.*?\))/,
1213
+ `${pluginUsage}\n\n$1`
1214
+ );
1215
+ }
1216
+
1217
+ return modifiedContent;
889
1218
  }
890
1219
  }
891
1220
 
@@ -1012,23 +1341,125 @@ if (typeof window !== 'undefined') {
1012
1341
  );
1013
1342
  }
1014
1343
 
1344
+ /**
1345
+ * Inject Astro layout with HumanBehavior component
1346
+ */
1347
+ private injectAstroLayout(content: string): string {
1348
+ // Check if HumanBehavior component is already imported
1349
+ if (content.includes('HumanBehavior') || content.includes('humanbehavior-js')) {
1350
+ return content; // Already has HumanBehavior
1351
+ }
1352
+
1353
+ // Add import inside frontmatter if not present
1354
+ let modifiedContent = content;
1355
+ if (!content.includes('import HumanBehavior')) {
1356
+ const importStatement = 'import HumanBehavior from \'../components/HumanBehavior.astro\';';
1357
+ const frontmatterEndIndex = content.indexOf('---', 3);
1358
+ if (frontmatterEndIndex !== -1) {
1359
+ // Insert import inside frontmatter, before the closing ---
1360
+ modifiedContent = content.slice(0, frontmatterEndIndex) + '\n' + importStatement + '\n' + content.slice(frontmatterEndIndex);
1361
+ } else {
1362
+ // No frontmatter, add at the very beginning
1363
+ modifiedContent = '---\n' + importStatement + '\n---\n\n' + content;
1364
+ }
1365
+ }
1366
+
1367
+ // Find the closing </body> tag and add HumanBehavior component before it
1368
+ const bodyCloseIndex = modifiedContent.lastIndexOf('</body>');
1369
+ if (bodyCloseIndex === -1) {
1370
+ // No body tag found, append to end
1371
+ return modifiedContent + '\n\n<HumanBehavior />';
1372
+ }
1373
+
1374
+ // Add component before closing body tag
1375
+ return modifiedContent.slice(0, bodyCloseIndex) + ' <HumanBehavior />\n' + modifiedContent.slice(bodyCloseIndex);
1376
+ }
1377
+
1015
1378
  private injectNuxtConfig(content: string): string {
1016
1379
  if (content.includes('humanBehaviorApiKey')) {
1017
1380
  return content;
1018
1381
  }
1019
1382
 
1020
- // Add runtime config by inserting it after the opening brace
1021
- return content.replace(
1022
- /export default defineNuxtConfig\(\{/,
1023
- `export default defineNuxtConfig({
1383
+ // Enhanced Nuxt 3 support with version detection
1384
+ const hasNuxt3 = this.framework?.features?.hasNuxt3;
1385
+
1386
+ if (hasNuxt3) {
1387
+ // Nuxt 3 with runtime config
1388
+ return content.replace(
1389
+ /export default defineNuxtConfig\(\{/,
1390
+ `export default defineNuxtConfig({
1024
1391
  runtimeConfig: {
1025
1392
  public: {
1026
1393
  humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY
1027
1394
  }
1028
1395
  },`
1396
+ );
1397
+ } else {
1398
+ // Nuxt 2 with env config
1399
+ return content.replace(
1400
+ /export default \{/,
1401
+ `export default {
1402
+ env: {
1403
+ humanBehaviorApiKey: process.env.HUMANBEHAVIOR_API_KEY
1404
+ },`
1405
+ );
1406
+ }
1407
+ }
1408
+
1409
+ private injectGatsbyLayout(content: string): string {
1410
+ if (content.includes('HumanBehavior')) {
1411
+ return content;
1412
+ }
1413
+
1414
+ const importStatement = `import HumanBehavior from './HumanBehavior';`;
1415
+ const componentUsage = `<HumanBehavior apiKey={process.env.GATSBY_HUMANBEHAVIOR_API_KEY || ''} />`;
1416
+
1417
+ // Add import at the top
1418
+ let modifiedContent = content.replace(
1419
+ /import.*from.*['"]\./,
1420
+ `${importStatement}\n$&`
1421
+ );
1422
+
1423
+ // Add component before closing body tag
1424
+ modifiedContent = modifiedContent.replace(
1425
+ /(\s*<\/body>)/,
1426
+ `\n ${componentUsage}\n$1`
1029
1427
  );
1428
+
1429
+ return modifiedContent;
1030
1430
  }
1031
1431
 
1432
+ private injectGatsbyBrowser(content: string): string {
1433
+ if (content.includes('HumanBehaviorTracker')) {
1434
+ return content;
1435
+ }
1436
+
1437
+ const importStatement = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
1438
+ const initCode = `
1439
+ // Initialize HumanBehavior SDK
1440
+ export const onClientEntry = () => {
1441
+ console.log('Gatsby browser entry point loaded');
1442
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
1443
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
1444
+ if (apiKey) {
1445
+ const tracker = HumanBehaviorTracker.init(apiKey);
1446
+ console.log('HumanBehavior SDK initialized for Gatsby');
1447
+ } else {
1448
+ console.log('No API key found in environment variables');
1449
+ }
1450
+ };`;
1451
+
1452
+ // If the file already has content, add the import and init code
1453
+ if (content.trim()) {
1454
+ return `${importStatement}${initCode}\n\n${content}`;
1455
+ } else {
1456
+ // If file is empty, just return the new content
1457
+ return `${importStatement}${initCode}`;
1458
+ }
1459
+ }
1460
+
1461
+
1462
+
1032
1463
  /**
1033
1464
  * Helper method to find the best environment file for a framework
1034
1465
  */
@@ -1052,16 +1483,18 @@ if (typeof window !== 'undefined') {
1052
1483
 
1053
1484
  // Framework-specific mappings
1054
1485
  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'
1486
+ react: 'HUMANBEHAVIOR_API_KEY',
1487
+ nextjs: 'NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1488
+ vue: 'VITE_HUMANBEHAVIOR_API_KEY',
1489
+ svelte: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1490
+ angular: 'HUMANBEHAVIOR_API_KEY',
1491
+ nuxt: 'NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1492
+ remix: 'HUMANBEHAVIOR_API_KEY',
1493
+ vanilla: 'HUMANBEHAVIOR_API_KEY',
1494
+ astro: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1495
+ gatsby: 'GATSBY_HUMANBEHAVIOR_API_KEY',
1496
+ node: 'HUMANBEHAVIOR_API_KEY',
1497
+ auto: 'HUMANBEHAVIOR_API_KEY'
1065
1498
  };
1066
1499
 
1067
1500
  return envVarNames[framework.type] || 'HUMANBEHAVIOR_API_KEY';
@@ -1087,6 +1520,8 @@ if (typeof window !== 'undefined') {
1087
1520
  nuxt: '.env',
1088
1521
  remix: '.env.local',
1089
1522
  vanilla: '.env',
1523
+ astro: '.env',
1524
+ gatsby: '.env.development',
1090
1525
  node: '.env',
1091
1526
  auto: '.env'
1092
1527
  };
@@ -1104,6 +1539,9 @@ if (typeof window !== 'undefined') {
1104
1539
  private createEnvironmentModification(framework: FrameworkInfo): CodeModification {
1105
1540
  const { filePath, envVarName } = this.findBestEnvFile(framework);
1106
1541
 
1542
+ // Clean the API key to prevent formatting issues
1543
+ const cleanApiKey = this.apiKey.trim();
1544
+
1107
1545
  if (fs.existsSync(filePath)) {
1108
1546
  // Check if the variable already exists
1109
1547
  const content = fs.readFileSync(filePath, 'utf8');
@@ -1120,7 +1558,7 @@ if (typeof window !== 'undefined') {
1120
1558
  return {
1121
1559
  filePath,
1122
1560
  action: 'append',
1123
- content: `\n${envVarName}=${this.apiKey}`,
1561
+ content: `\n${envVarName}=${cleanApiKey}`,
1124
1562
  description: `Added API key to existing ${path.basename(filePath)}`
1125
1563
  };
1126
1564
  }
@@ -1129,7 +1567,7 @@ if (typeof window !== 'undefined') {
1129
1567
  return {
1130
1568
  filePath,
1131
1569
  action: 'create',
1132
- content: `${envVarName}=${this.apiKey}`,
1570
+ content: `${envVarName}=${cleanApiKey}`,
1133
1571
  description: `Created ${path.basename(filePath)} with API key`
1134
1572
  };
1135
1573
  }