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.
- package/dist/cjs/install-wizard.cjs +396 -25
- package/dist/cjs/install-wizard.cjs.map +1 -1
- package/dist/cjs/wizard/index.cjs +633 -395
- package/dist/cjs/wizard/index.cjs.map +1 -1
- package/dist/cli/ai-auto-install.cjs +57161 -0
- package/dist/cli/ai-auto-install.cjs.map +1 -0
- package/dist/cli/ai-auto-install.js +520 -575
- package/dist/cli/ai-auto-install.js.map +1 -1
- package/dist/cli/auto-install.cjs +56352 -0
- package/dist/cli/auto-install.cjs.map +1 -0
- package/dist/cli/auto-install.js +925 -140
- package/dist/cli/auto-install.js.map +1 -1
- package/dist/esm/install-wizard.js +396 -25
- package/dist/esm/install-wizard.js.map +1 -1
- package/dist/esm/wizard/index.js +631 -394
- package/dist/esm/wizard/index.js.map +1 -1
- package/dist/types/install-wizard.d.ts +31 -1
- package/dist/types/wizard/index.d.ts +44 -10
- package/package.json +3 -1
- package/rollup.config.js +5 -1
- package/src/types/clack.d.ts +31 -0
- package/src/wizard/ai/ai-install-wizard.ts +4 -1
- package/src/wizard/ai/manual-framework-wizard.ts +2 -0
- package/src/wizard/cli/ai-auto-install.ts +122 -248
- package/src/wizard/cli/auto-install.ts +116 -117
- package/src/wizard/core/install-wizard.ts +498 -60
- package/src/wizard/services/centralized-ai-service.ts +1 -1
- package/src/wizard/services/remote-ai-service.ts +18 -2
- package/tsconfig.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
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
|
-
|
|
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
|
-
|
|
871
|
-
|
|
872
|
-
//
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
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
|
-
//
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
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
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
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}=${
|
|
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}=${
|
|
1570
|
+
content: `${envVarName}=${cleanApiKey}`,
|
|
1133
1571
|
description: `Created ${path.basename(filePath)} with API key`
|
|
1134
1572
|
};
|
|
1135
1573
|
}
|