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.
@@ -45,6 +45,28 @@ class AutoInstallationWizard {
45
45
  this.apiKey = apiKey;
46
46
  this.projectRoot = projectRoot;
47
47
  }
48
+ /**
49
+ * Simple version comparison utility
50
+ */
51
+ compareVersions(version1, version2) {
52
+ const v1Parts = version1.split('.').map(Number);
53
+ const v2Parts = version2.split('.').map(Number);
54
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
55
+ const v1 = v1Parts[i] || 0;
56
+ const v2 = v2Parts[i] || 0;
57
+ if (v1 > v2)
58
+ return 1;
59
+ if (v1 < v2)
60
+ return -1;
61
+ }
62
+ return 0;
63
+ }
64
+ isVersionGte(version, target) {
65
+ return this.compareVersions(version, target) >= 0;
66
+ }
67
+ getMajorVersion(version) {
68
+ return parseInt(version.split('.')[0]) || 0;
69
+ }
48
70
  /**
49
71
  * Main installation method - detects framework and auto-installs
50
72
  */
@@ -94,73 +116,146 @@ class AutoInstallationWizard {
94
116
  }
95
117
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
96
118
  const dependencies = Object.assign(Object.assign({}, packageJson.dependencies), packageJson.devDependencies);
97
- // Detect framework
119
+ // Detect framework with version information
98
120
  let framework = {
99
121
  name: 'vanilla',
100
122
  type: 'vanilla',
101
- projectRoot: this.projectRoot
123
+ projectRoot: this.projectRoot,
124
+ features: {}
102
125
  };
103
126
  if (dependencies.nuxt) {
127
+ const nuxtVersion = dependencies.nuxt;
128
+ const isNuxt3 = this.isVersionGte(nuxtVersion, '3.0.0');
104
129
  framework = {
105
130
  name: 'nuxt',
106
131
  type: 'nuxt',
132
+ version: nuxtVersion,
133
+ majorVersion: this.getMajorVersion(nuxtVersion),
107
134
  hasTypeScript: !!dependencies.typescript,
108
135
  hasRouter: true,
109
- projectRoot: this.projectRoot
136
+ projectRoot: this.projectRoot,
137
+ features: {
138
+ hasNuxt3: isNuxt3
139
+ }
110
140
  };
111
141
  }
112
142
  else if (dependencies.next) {
143
+ const nextVersion = dependencies.next;
144
+ const isNext13 = this.isVersionGte(nextVersion, '13.0.0');
113
145
  framework = {
114
146
  name: 'nextjs',
115
147
  type: 'nextjs',
148
+ version: nextVersion,
149
+ majorVersion: this.getMajorVersion(nextVersion),
116
150
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/node'],
117
151
  hasRouter: true,
118
- projectRoot: this.projectRoot
152
+ projectRoot: this.projectRoot,
153
+ features: {
154
+ hasNextAppRouter: isNext13
155
+ }
119
156
  };
120
157
  }
121
158
  else if (dependencies['@remix-run/react'] || dependencies['@remix-run/dev']) {
159
+ const remixVersion = dependencies['@remix-run/react'] || dependencies['@remix-run/dev'];
122
160
  framework = {
123
161
  name: 'remix',
124
162
  type: 'remix',
163
+ version: remixVersion,
164
+ majorVersion: this.getMajorVersion(remixVersion),
125
165
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
126
166
  hasRouter: true,
127
- projectRoot: this.projectRoot
167
+ projectRoot: this.projectRoot,
168
+ features: {}
128
169
  };
129
170
  }
130
171
  else if (dependencies.react) {
172
+ const reactVersion = dependencies.react;
173
+ const isReact18 = this.isVersionGte(reactVersion, '18.0.0');
131
174
  framework = {
132
175
  name: 'react',
133
176
  type: 'react',
177
+ version: reactVersion,
178
+ majorVersion: this.getMajorVersion(reactVersion),
134
179
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
135
180
  hasRouter: !!dependencies['react-router-dom'] || !!dependencies['react-router'],
136
- projectRoot: this.projectRoot
181
+ projectRoot: this.projectRoot,
182
+ features: {
183
+ hasReact18: isReact18
184
+ }
137
185
  };
138
186
  }
139
187
  else if (dependencies.vue) {
188
+ const vueVersion = dependencies.vue;
189
+ const isVue3 = this.isVersionGte(vueVersion, '3.0.0');
140
190
  framework = {
141
191
  name: 'vue',
142
192
  type: 'vue',
193
+ version: vueVersion,
194
+ majorVersion: this.getMajorVersion(vueVersion),
143
195
  hasTypeScript: !!dependencies.typescript || !!dependencies['@vue/cli-service'],
144
196
  hasRouter: !!dependencies['vue-router'],
145
- projectRoot: this.projectRoot
197
+ projectRoot: this.projectRoot,
198
+ features: {
199
+ hasVue3: isVue3
200
+ }
146
201
  };
147
202
  }
148
203
  else if (dependencies['@angular/core']) {
204
+ const angularVersion = dependencies['@angular/core'];
205
+ const isAngular17 = this.isVersionGte(angularVersion, '17.0.0');
149
206
  framework = {
150
207
  name: 'angular',
151
208
  type: 'angular',
209
+ version: angularVersion,
210
+ majorVersion: this.getMajorVersion(angularVersion),
152
211
  hasTypeScript: true,
153
212
  hasRouter: true,
154
- projectRoot: this.projectRoot
213
+ projectRoot: this.projectRoot,
214
+ features: {
215
+ hasAngularStandalone: isAngular17
216
+ }
155
217
  };
156
218
  }
157
219
  else if (dependencies.svelte) {
220
+ const svelteVersion = dependencies.svelte;
221
+ const isSvelteKit = !!dependencies['@sveltejs/kit'];
158
222
  framework = {
159
223
  name: 'svelte',
160
224
  type: 'svelte',
225
+ version: svelteVersion,
226
+ majorVersion: this.getMajorVersion(svelteVersion),
161
227
  hasTypeScript: !!dependencies.typescript || !!dependencies['svelte-check'],
162
228
  hasRouter: !!dependencies['svelte-routing'] || !!dependencies['@sveltejs/kit'],
163
- projectRoot: this.projectRoot
229
+ projectRoot: this.projectRoot,
230
+ features: {
231
+ hasSvelteKit: isSvelteKit
232
+ }
233
+ };
234
+ }
235
+ else if (dependencies.astro) {
236
+ const astroVersion = dependencies.astro;
237
+ framework = {
238
+ name: 'astro',
239
+ type: 'astro',
240
+ version: astroVersion,
241
+ majorVersion: this.getMajorVersion(astroVersion),
242
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@astrojs/ts-plugin'],
243
+ hasRouter: true,
244
+ projectRoot: this.projectRoot,
245
+ features: {}
246
+ };
247
+ }
248
+ else if (dependencies.gatsby) {
249
+ const gatsbyVersion = dependencies.gatsby;
250
+ framework = {
251
+ name: 'gatsby',
252
+ type: 'gatsby',
253
+ version: gatsbyVersion,
254
+ majorVersion: this.getMajorVersion(gatsbyVersion),
255
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
256
+ hasRouter: true,
257
+ projectRoot: this.projectRoot,
258
+ features: {}
164
259
  };
165
260
  }
166
261
  // Detect bundler
@@ -194,13 +289,18 @@ class AutoInstallationWizard {
194
289
  */
195
290
  installPackage() {
196
291
  return __awaiter(this, void 0, void 0, function* () {
197
- var _a, _b;
292
+ var _a, _b, _c, _d;
198
293
  const { execSync } = yield import('child_process');
199
- const command = ((_a = this.framework) === null || _a === void 0 ? void 0 : _a.packageManager) === 'yarn'
294
+ // Build base command
295
+ let command = ((_a = this.framework) === null || _a === void 0 ? void 0 : _a.packageManager) === 'yarn'
200
296
  ? 'yarn add humanbehavior-js'
201
297
  : ((_b = this.framework) === null || _b === void 0 ? void 0 : _b.packageManager) === 'pnpm'
202
298
  ? 'pnpm add humanbehavior-js'
203
299
  : 'npm install humanbehavior-js';
300
+ // Add legacy peer deps flag for npm to handle dependency conflicts
301
+ if (((_c = this.framework) === null || _c === void 0 ? void 0 : _c.packageManager) !== 'yarn' && ((_d = this.framework) === null || _d === void 0 ? void 0 : _d.packageManager) !== 'pnpm') {
302
+ command += ' --legacy-peer-deps';
303
+ }
204
304
  try {
205
305
  execSync(command, { cwd: this.projectRoot, stdio: 'inherit' });
206
306
  }
@@ -226,6 +326,12 @@ class AutoInstallationWizard {
226
326
  case 'nuxt':
227
327
  modifications.push(...yield this.generateNuxtModifications());
228
328
  break;
329
+ case 'astro':
330
+ modifications.push(...yield this.generateAstroModifications());
331
+ break;
332
+ case 'gatsby':
333
+ modifications.push(...yield this.generateGatsbyModifications());
334
+ break;
229
335
  case 'remix':
230
336
  modifications.push(...yield this.generateRemixModifications());
231
337
  break;
@@ -337,6 +443,84 @@ export function Providers({ children }: { children: React.ReactNode }) {
337
443
  return modifications;
338
444
  });
339
445
  }
446
+ /**
447
+ * Generate Astro-specific modifications
448
+ */
449
+ generateAstroModifications() {
450
+ return __awaiter(this, void 0, void 0, function* () {
451
+ const modifications = [];
452
+ // Create Astro component for HumanBehavior
453
+ const astroComponentPath = path.join(this.projectRoot, 'src', 'components', 'HumanBehavior.astro');
454
+ const astroComponentContent = `---
455
+ // This component will only run on the client side
456
+ ---
457
+
458
+ <script>
459
+ import { HumanBehaviorTracker } from 'humanbehavior-js';
460
+
461
+ // Get API key from environment variable
462
+ const apiKey = import.meta.env.PUBLIC_HUMANBEHAVIOR_API_KEY;
463
+
464
+ console.log('HumanBehavior: API key found:', apiKey ? 'Yes' : 'No');
465
+
466
+ if (apiKey) {
467
+ try {
468
+ const tracker = HumanBehaviorTracker.init(apiKey);
469
+ console.log('HumanBehavior: Tracker initialized successfully');
470
+
471
+ // Test event to verify tracking is working
472
+ setTimeout(() => {
473
+ tracker.customEvent('astro_page_view', {
474
+ page: window.location.pathname,
475
+ framework: 'astro'
476
+ }).then(() => {
477
+ console.log('HumanBehavior: Test event sent successfully');
478
+ }).catch((error) => {
479
+ console.error('HumanBehavior: Failed to send test event:', error);
480
+ });
481
+ }, 1000);
482
+
483
+ } catch (error) {
484
+ console.error('HumanBehavior: Failed to initialize tracker:', error);
485
+ }
486
+ } else {
487
+ console.error('HumanBehavior: No API key found');
488
+ }
489
+ </script>`;
490
+ modifications.push({
491
+ filePath: astroComponentPath,
492
+ action: 'create',
493
+ content: astroComponentContent,
494
+ description: 'Created Astro component for HumanBehavior SDK'
495
+ });
496
+ // Find and update layout file
497
+ const layoutFiles = [
498
+ path.join(this.projectRoot, 'src', 'layouts', 'Layout.astro'),
499
+ path.join(this.projectRoot, 'src', 'layouts', 'layout.astro'),
500
+ path.join(this.projectRoot, 'src', 'layouts', 'BaseLayout.astro')
501
+ ];
502
+ let layoutFile = null;
503
+ for (const file of layoutFiles) {
504
+ if (fs.existsSync(file)) {
505
+ layoutFile = file;
506
+ break;
507
+ }
508
+ }
509
+ if (layoutFile) {
510
+ const content = fs.readFileSync(layoutFile, 'utf8');
511
+ const modifiedContent = this.injectAstroLayout(content);
512
+ modifications.push({
513
+ filePath: layoutFile,
514
+ action: 'modify',
515
+ content: modifiedContent,
516
+ description: 'Added HumanBehavior component to Astro layout'
517
+ });
518
+ }
519
+ // Add environment variable
520
+ modifications.push(this.createEnvironmentModification(this.framework));
521
+ return modifications;
522
+ });
523
+ }
340
524
  /**
341
525
  * Generate Nuxt-specific modifications
342
526
  */
@@ -557,6 +741,50 @@ export default defineNuxtPlugin(() => {
557
741
  return modifications;
558
742
  });
559
743
  }
744
+ /**
745
+ * Generate Gatsby-specific modifications
746
+ */
747
+ generateGatsbyModifications() {
748
+ return __awaiter(this, void 0, void 0, function* () {
749
+ const modifications = [];
750
+ // Modify or create gatsby-browser.js for Gatsby
751
+ const gatsbyBrowserFile = path.join(this.projectRoot, 'gatsby-browser.js');
752
+ if (fs.existsSync(gatsbyBrowserFile)) {
753
+ const content = fs.readFileSync(gatsbyBrowserFile, 'utf8');
754
+ const modifiedContent = this.injectGatsbyBrowser(content);
755
+ modifications.push({
756
+ filePath: gatsbyBrowserFile,
757
+ action: 'modify',
758
+ content: modifiedContent,
759
+ description: 'Added HumanBehavior initialization to Gatsby browser'
760
+ });
761
+ }
762
+ else {
763
+ // Create gatsby-browser.js if it doesn't exist
764
+ modifications.push({
765
+ filePath: gatsbyBrowserFile,
766
+ action: 'create',
767
+ content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
768
+
769
+ export const onClientEntry = () => {
770
+ console.log('Gatsby browser entry point loaded');
771
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
772
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
773
+ if (apiKey) {
774
+ const tracker = HumanBehaviorTracker.init(apiKey);
775
+ console.log('HumanBehavior SDK initialized for Gatsby');
776
+ } else {
777
+ console.log('No API key found in environment variables');
778
+ }
779
+ };`,
780
+ description: 'Created gatsby-browser.js with HumanBehavior initialization'
781
+ });
782
+ }
783
+ // Create or append to environment file
784
+ modifications.push(this.createEnvironmentModification(this.framework));
785
+ return modifications;
786
+ });
787
+ }
560
788
  /**
561
789
  * Apply modifications to the codebase
562
790
  */
@@ -651,7 +879,7 @@ export default defineNuxtPlugin(() => {
651
879
  return null;
652
880
  }
653
881
  injectReactProvider(content, filePath) {
654
- var _a;
882
+ var _a, _b, _c;
655
883
  filePath.endsWith('.tsx') || filePath.endsWith('.ts');
656
884
  // Check if already has HumanBehaviorProvider
657
885
  if (content.includes('HumanBehaviorProvider')) {
@@ -663,14 +891,39 @@ export default defineNuxtPlugin(() => {
663
891
  ? 'import.meta.env.VITE_HUMANBEHAVIOR_API_KEY!'
664
892
  : 'process.env.HUMANBEHAVIOR_API_KEY!';
665
893
  const importStatement = `import { HumanBehaviorProvider } from 'humanbehavior-js/react';`;
666
- // Simple injection - in production, you'd want more sophisticated parsing
894
+ // Enhanced parsing for React 18+ features
895
+ const hasReact18 = (_c = (_b = this.framework) === null || _b === void 0 ? void 0 : _b.features) === null || _c === void 0 ? void 0 : _c.hasReact18;
896
+ // Handle different React patterns
667
897
  if (content.includes('function App()') || content.includes('const App =')) {
668
- return content.replace(/(function App\(\)|const App =)/, `${importStatement}\n\n$1`).replace(/return \(([\s\S]*?)\);/, `return (
898
+ // Add import statement
899
+ let modifiedContent = content.replace(/(import.*?from.*?['"]react['"];?)/, `$1\n${importStatement}`);
900
+ // If no React import found, add it at the top
901
+ if (!modifiedContent.includes(importStatement)) {
902
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
903
+ }
904
+ // Wrap the App component return with HumanBehaviorProvider
905
+ modifiedContent = modifiedContent.replace(/(return\s*\([\s\S]*?\)\s*;)/, `return (
669
906
  <HumanBehaviorProvider apiKey={${envVar}}>
670
907
  $1
671
908
  </HumanBehaviorProvider>
672
909
  );`);
910
+ return modifiedContent;
673
911
  }
912
+ // Handle React 18+ createRoot pattern
913
+ if (hasReact18 && content.includes('createRoot')) {
914
+ let modifiedContent = content.replace(/(import.*?from.*?['"]react['"];?)/, `$1\n${importStatement}`);
915
+ if (!modifiedContent.includes(importStatement)) {
916
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
917
+ }
918
+ // Wrap the root render with HumanBehaviorProvider
919
+ modifiedContent = modifiedContent.replace(/(root\.render\s*\([\s\S]*?\)\s*;)/, `root.render(
920
+ <HumanBehaviorProvider apiKey={${envVar}}>
921
+ $1
922
+ </HumanBehaviorProvider>
923
+ );`);
924
+ return modifiedContent;
925
+ }
926
+ // Fallback: simple injection
674
927
  return `${importStatement}\n\n${content}`;
675
928
  }
676
929
  injectNextJSAppRouter(content) {
@@ -767,21 +1020,51 @@ export default function App()`);
767
1020
  return modifiedContent;
768
1021
  }
769
1022
  injectVuePlugin(content) {
1023
+ var _a, _b;
770
1024
  if (content.includes('HumanBehaviorPlugin')) {
771
1025
  return content;
772
1026
  }
773
1027
  const importStatement = `import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';`;
774
- const pluginUsage = `app.use(HumanBehaviorPlugin, {
1028
+ // Enhanced Vue 3 support with version detection
1029
+ const hasVue3 = (_b = (_a = this.framework) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.hasVue3;
1030
+ if (hasVue3) {
1031
+ // Vue 3 with Composition API
1032
+ const pluginUsage = `app.use(HumanBehaviorPlugin, {
775
1033
  apiKey: import.meta.env.VITE_HUMANBEHAVIOR_API_KEY
776
1034
  });`;
777
- // Handle both Vue 2 and Vue 3 patterns
778
- if (content.includes('createApp')) {
779
- // Vue 3
780
- return content.replace(/import.*from.*['"]vue['"]/, `$&\n${importStatement}`).replace(/app\.mount\(/, `${pluginUsage}\n\napp.mount(`);
1035
+ let modifiedContent = content;
1036
+ // Add import statement
1037
+ if (!content.includes(importStatement)) {
1038
+ modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
1039
+ // If no Vue import found, add it at the top
1040
+ if (!modifiedContent.includes(importStatement)) {
1041
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1042
+ }
1043
+ }
1044
+ // Handle createApp pattern
1045
+ if (content.includes('createApp')) {
1046
+ modifiedContent = modifiedContent.replace(/(app\.mount\(.*?\))/, `${pluginUsage}\n\n$1`);
1047
+ }
1048
+ return modifiedContent;
781
1049
  }
782
1050
  else {
783
- // Vue 2
784
- return content.replace(/import.*from.*['"]vue['"]/, `$&\n${importStatement}`).replace(/new Vue\(/, `${pluginUsage}\n\nnew Vue(`);
1051
+ // Vue 2 with Options API
1052
+ const pluginUsage = `Vue.use(HumanBehaviorPlugin, {
1053
+ apiKey: process.env.VUE_APP_HUMANBEHAVIOR_API_KEY
1054
+ });`;
1055
+ let modifiedContent = content;
1056
+ // Add import statement
1057
+ if (!content.includes(importStatement)) {
1058
+ modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
1059
+ if (!modifiedContent.includes(importStatement)) {
1060
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1061
+ }
1062
+ }
1063
+ // Handle new Vue pattern
1064
+ if (content.includes('new Vue')) {
1065
+ modifiedContent = modifiedContent.replace(/(new Vue\(.*?\))/, `${pluginUsage}\n\n$1`);
1066
+ }
1067
+ return modifiedContent;
785
1068
  }
786
1069
  }
787
1070
  injectAngularModule(content) {
@@ -862,17 +1145,99 @@ if (typeof window !== 'undefined') {
862
1145
  </script>`;
863
1146
  return content.replace(/<\/head>/, ` ${cdnScript}\n ${initScript}\n</head>`);
864
1147
  }
1148
+ /**
1149
+ * Inject Astro layout with HumanBehavior component
1150
+ */
1151
+ injectAstroLayout(content) {
1152
+ // Check if HumanBehavior component is already imported
1153
+ if (content.includes('HumanBehavior') || content.includes('humanbehavior-js')) {
1154
+ return content; // Already has HumanBehavior
1155
+ }
1156
+ // Add import inside frontmatter if not present
1157
+ let modifiedContent = content;
1158
+ if (!content.includes('import HumanBehavior')) {
1159
+ const importStatement = 'import HumanBehavior from \'../components/HumanBehavior.astro\';';
1160
+ const frontmatterEndIndex = content.indexOf('---', 3);
1161
+ if (frontmatterEndIndex !== -1) {
1162
+ // Insert import inside frontmatter, before the closing ---
1163
+ modifiedContent = content.slice(0, frontmatterEndIndex) + '\n' + importStatement + '\n' + content.slice(frontmatterEndIndex);
1164
+ }
1165
+ else {
1166
+ // No frontmatter, add at the very beginning
1167
+ modifiedContent = '---\n' + importStatement + '\n---\n\n' + content;
1168
+ }
1169
+ }
1170
+ // Find the closing </body> tag and add HumanBehavior component before it
1171
+ const bodyCloseIndex = modifiedContent.lastIndexOf('</body>');
1172
+ if (bodyCloseIndex === -1) {
1173
+ // No body tag found, append to end
1174
+ return modifiedContent + '\n\n<HumanBehavior />';
1175
+ }
1176
+ // Add component before closing body tag
1177
+ return modifiedContent.slice(0, bodyCloseIndex) + ' <HumanBehavior />\n' + modifiedContent.slice(bodyCloseIndex);
1178
+ }
865
1179
  injectNuxtConfig(content) {
1180
+ var _a, _b;
866
1181
  if (content.includes('humanBehaviorApiKey')) {
867
1182
  return content;
868
1183
  }
869
- // Add runtime config by inserting it after the opening brace
870
- return content.replace(/export default defineNuxtConfig\(\{/, `export default defineNuxtConfig({
1184
+ // Enhanced Nuxt 3 support with version detection
1185
+ const hasNuxt3 = (_b = (_a = this.framework) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.hasNuxt3;
1186
+ if (hasNuxt3) {
1187
+ // Nuxt 3 with runtime config
1188
+ return content.replace(/export default defineNuxtConfig\(\{/, `export default defineNuxtConfig({
871
1189
  runtimeConfig: {
872
1190
  public: {
873
1191
  humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY
874
1192
  }
875
1193
  },`);
1194
+ }
1195
+ else {
1196
+ // Nuxt 2 with env config
1197
+ return content.replace(/export default \{/, `export default {
1198
+ env: {
1199
+ humanBehaviorApiKey: process.env.HUMANBEHAVIOR_API_KEY
1200
+ },`);
1201
+ }
1202
+ }
1203
+ injectGatsbyLayout(content) {
1204
+ if (content.includes('HumanBehavior')) {
1205
+ return content;
1206
+ }
1207
+ const importStatement = `import HumanBehavior from './HumanBehavior';`;
1208
+ const componentUsage = `<HumanBehavior apiKey={process.env.GATSBY_HUMANBEHAVIOR_API_KEY || ''} />`;
1209
+ // Add import at the top
1210
+ let modifiedContent = content.replace(/import.*from.*['"]\./, `${importStatement}\n$&`);
1211
+ // Add component before closing body tag
1212
+ modifiedContent = modifiedContent.replace(/(\s*<\/body>)/, `\n ${componentUsage}\n$1`);
1213
+ return modifiedContent;
1214
+ }
1215
+ injectGatsbyBrowser(content) {
1216
+ if (content.includes('HumanBehaviorTracker')) {
1217
+ return content;
1218
+ }
1219
+ const importStatement = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
1220
+ const initCode = `
1221
+ // Initialize HumanBehavior SDK
1222
+ export const onClientEntry = () => {
1223
+ console.log('Gatsby browser entry point loaded');
1224
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
1225
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
1226
+ if (apiKey) {
1227
+ const tracker = HumanBehaviorTracker.init(apiKey);
1228
+ console.log('HumanBehavior SDK initialized for Gatsby');
1229
+ } else {
1230
+ console.log('No API key found in environment variables');
1231
+ }
1232
+ };`;
1233
+ // If the file already has content, add the import and init code
1234
+ if (content.trim()) {
1235
+ return `${importStatement}${initCode}\n\n${content}`;
1236
+ }
1237
+ else {
1238
+ // If file is empty, just return the new content
1239
+ return `${importStatement}${initCode}`;
1240
+ }
876
1241
  }
877
1242
  /**
878
1243
  * Helper method to find the best environment file for a framework
@@ -903,6 +1268,8 @@ if (typeof window !== 'undefined') {
903
1268
  nuxt: 'NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
904
1269
  remix: 'HUMANBEHAVIOR_API_KEY',
905
1270
  vanilla: 'HUMANBEHAVIOR_API_KEY',
1271
+ astro: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1272
+ gatsby: 'GATSBY_HUMANBEHAVIOR_API_KEY',
906
1273
  node: 'HUMANBEHAVIOR_API_KEY',
907
1274
  auto: 'HUMANBEHAVIOR_API_KEY'
908
1275
  };
@@ -926,6 +1293,8 @@ if (typeof window !== 'undefined') {
926
1293
  nuxt: '.env',
927
1294
  remix: '.env.local',
928
1295
  vanilla: '.env',
1296
+ astro: '.env',
1297
+ gatsby: '.env.development',
929
1298
  node: '.env',
930
1299
  auto: '.env'
931
1300
  };
@@ -940,6 +1309,8 @@ if (typeof window !== 'undefined') {
940
1309
  */
941
1310
  createEnvironmentModification(framework) {
942
1311
  const { filePath, envVarName } = this.findBestEnvFile(framework);
1312
+ // Clean the API key to prevent formatting issues
1313
+ const cleanApiKey = this.apiKey.trim();
943
1314
  if (fs.existsSync(filePath)) {
944
1315
  // Check if the variable already exists
945
1316
  const content = fs.readFileSync(filePath, 'utf8');
@@ -957,7 +1328,7 @@ if (typeof window !== 'undefined') {
957
1328
  return {
958
1329
  filePath,
959
1330
  action: 'append',
960
- content: `\n${envVarName}=${this.apiKey}`,
1331
+ content: `\n${envVarName}=${cleanApiKey}`,
961
1332
  description: `Added API key to existing ${path.basename(filePath)}`
962
1333
  };
963
1334
  }
@@ -967,7 +1338,7 @@ if (typeof window !== 'undefined') {
967
1338
  return {
968
1339
  filePath,
969
1340
  action: 'create',
970
- content: `${envVarName}=${this.apiKey}`,
1341
+ content: `${envVarName}=${cleanApiKey}`,
971
1342
  description: `Created ${path.basename(filePath)} with API key`
972
1343
  };
973
1344
  }