humanbehavior-js 0.5.25 → 0.5.27
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/package.json +2 -2
- package/packages/browser/dist/cjs/index.js +1 -1
- package/packages/browser/dist/cjs/index.js.map +1 -1
- package/packages/browser/dist/esm/index.js +1 -1
- package/packages/browser/dist/esm/index.js.map +1 -1
- package/packages/browser/dist/index.min.js +1 -1
- package/packages/browser/dist/index.min.js.map +1 -1
- package/packages/core/dist/index.js +1 -1
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/index.mjs +1 -1
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/tracker.d.ts.map +1 -1
- package/packages/react/dist/index.js +1 -1
- package/packages/react/dist/index.js.map +1 -1
- package/packages/react/dist/index.mjs +1 -1
- package/packages/react/dist/index.mjs.map +1 -1
- package/packages/wizard/dist/cli/ai-auto-install.js +236 -203
- package/packages/wizard/dist/cli/ai-auto-install.js.map +1 -1
- package/packages/wizard/dist/cli/auto-install.d.ts +0 -1
- package/packages/wizard/dist/cli/auto-install.d.ts.map +1 -1
- package/packages/wizard/dist/cli/auto-install.js +247 -646
- package/packages/wizard/dist/cli/auto-install.js.map +1 -1
- package/packages/wizard/dist/core/install-wizard.d.ts +5 -0
- package/packages/wizard/dist/core/install-wizard.d.ts.map +1 -1
- package/packages/wizard/dist/index.js +1 -1
- package/packages/wizard/dist/index.js.map +1 -1
- package/packages/wizard/dist/index.mjs +1 -1
- package/packages/wizard/dist/index.mjs.map +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
4
5
|
import * as clack from '@clack/prompts';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -12,6 +13,7 @@ import * as clack from '@clack/prompts';
|
|
|
12
13
|
class AutoInstallationWizard {
|
|
13
14
|
constructor(apiKey, projectRoot = process.cwd()) {
|
|
14
15
|
this.framework = null;
|
|
16
|
+
this.manualNotes = [];
|
|
15
17
|
this.apiKey = apiKey;
|
|
16
18
|
this.projectRoot = projectRoot;
|
|
17
19
|
}
|
|
@@ -257,7 +259,6 @@ class AutoInstallationWizard {
|
|
|
257
259
|
* Install the SDK package with latest version range
|
|
258
260
|
*/
|
|
259
261
|
async installPackage() {
|
|
260
|
-
const { execSync } = await import('child_process');
|
|
261
262
|
// Build base command with latest version range
|
|
262
263
|
let command = this.framework?.packageManager === 'yarn'
|
|
263
264
|
? 'yarn add humanbehavior-js@latest'
|
|
@@ -415,34 +416,9 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
415
416
|
|
|
416
417
|
<script>
|
|
417
418
|
import { HumanBehaviorTracker } from 'humanbehavior-js';
|
|
418
|
-
|
|
419
|
-
// Get API key from environment variable
|
|
420
419
|
const apiKey = import.meta.env.PUBLIC_HUMANBEHAVIOR_API_KEY;
|
|
421
|
-
|
|
422
|
-
console.log('HumanBehavior: API key found:', apiKey ? 'Yes' : 'No');
|
|
423
|
-
|
|
424
420
|
if (apiKey) {
|
|
425
|
-
|
|
426
|
-
const tracker = HumanBehaviorTracker.init(apiKey);
|
|
427
|
-
console.log('HumanBehavior: Tracker initialized successfully');
|
|
428
|
-
|
|
429
|
-
// Test event to verify tracking is working
|
|
430
|
-
setTimeout(() => {
|
|
431
|
-
tracker.customEvent('astro_page_view', {
|
|
432
|
-
page: window.location.pathname,
|
|
433
|
-
framework: 'astro'
|
|
434
|
-
}).then(() => {
|
|
435
|
-
console.log('HumanBehavior: Test event sent successfully');
|
|
436
|
-
}).catch((error) => {
|
|
437
|
-
console.error('HumanBehavior: Failed to send test event:', error);
|
|
438
|
-
});
|
|
439
|
-
}, 1000);
|
|
440
|
-
|
|
441
|
-
} catch (error) {
|
|
442
|
-
console.error('HumanBehavior: Failed to initialize tracker:', error);
|
|
443
|
-
}
|
|
444
|
-
} else {
|
|
445
|
-
console.error('HumanBehavior: No API key found');
|
|
421
|
+
HumanBehaviorTracker.init(apiKey);
|
|
446
422
|
}
|
|
447
423
|
</script>`;
|
|
448
424
|
modifications.push({
|
|
@@ -492,21 +468,10 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
492
468
|
|
|
493
469
|
export default defineNuxtPlugin(() => {
|
|
494
470
|
const config = useRuntimeConfig();
|
|
495
|
-
|
|
496
|
-
// Initialize HumanBehavior SDK (client-side only)
|
|
497
471
|
if (typeof window !== 'undefined') {
|
|
498
472
|
const apiKey = config.public.humanBehaviorApiKey;
|
|
499
|
-
console.log('HumanBehavior: API key:', apiKey ? 'present' : 'missing');
|
|
500
|
-
|
|
501
473
|
if (apiKey) {
|
|
502
|
-
|
|
503
|
-
const tracker = HumanBehaviorTracker.init(apiKey);
|
|
504
|
-
console.log('HumanBehavior: Tracker initialized successfully');
|
|
505
|
-
} catch (error) {
|
|
506
|
-
console.error('HumanBehavior: Failed to initialize tracker:', error);
|
|
507
|
-
}
|
|
508
|
-
} else {
|
|
509
|
-
console.error('HumanBehavior: No API key found in runtime config');
|
|
474
|
+
HumanBehaviorTracker.init(apiKey);
|
|
510
475
|
}
|
|
511
476
|
}
|
|
512
477
|
});`,
|
|
@@ -514,15 +479,10 @@ export default defineNuxtPlugin(() => {
|
|
|
514
479
|
});
|
|
515
480
|
// Create environment configuration
|
|
516
481
|
const nuxtConfigFile = path.join(this.projectRoot, 'nuxt.config.ts');
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
filePath: nuxtConfigFile,
|
|
522
|
-
action: 'modify',
|
|
523
|
-
content: modifiedContent,
|
|
524
|
-
description: 'Added HumanBehavior runtime config to Nuxt config'
|
|
525
|
-
});
|
|
482
|
+
{
|
|
483
|
+
const mod = this.applyOrNotify(nuxtConfigFile, (c) => this.injectNuxtConfig(c), 'Added HumanBehavior runtime config to Nuxt config', 'Nuxt: Add inside defineNuxtConfig({ … }):\nruntimeConfig: { public: { humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY } },');
|
|
484
|
+
if (mod)
|
|
485
|
+
modifications.push(mod);
|
|
526
486
|
}
|
|
527
487
|
// Create or append to environment file
|
|
528
488
|
modifications.push(this.createEnvironmentModification(this.framework));
|
|
@@ -556,6 +516,37 @@ export default defineNuxtPlugin(() => {
|
|
|
556
516
|
const modifications = [];
|
|
557
517
|
// Find main.js or main.ts
|
|
558
518
|
const mainFile = this.findVueMainFile();
|
|
519
|
+
// Create Vue composable per docs (idempotent)
|
|
520
|
+
const composableDir = path.join(this.projectRoot, 'src', 'composables');
|
|
521
|
+
const composablePath = path.join(composableDir, 'useHumanBehavior.ts');
|
|
522
|
+
const composableContent = `import { HumanBehaviorTracker } from 'humanbehavior-js'
|
|
523
|
+
|
|
524
|
+
export function useHumanBehavior() {
|
|
525
|
+
const apiKey = import.meta.env.VITE_HUMANBEHAVIOR_API_KEY
|
|
526
|
+
|
|
527
|
+
if (apiKey) {
|
|
528
|
+
const tracker = HumanBehaviorTracker.init(apiKey);
|
|
529
|
+
|
|
530
|
+
return { tracker }
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return { tracker: null }
|
|
534
|
+
}
|
|
535
|
+
`;
|
|
536
|
+
try {
|
|
537
|
+
if (!fs.existsSync(composableDir)) {
|
|
538
|
+
fs.mkdirSync(composableDir, { recursive: true });
|
|
539
|
+
}
|
|
540
|
+
if (!fs.existsSync(composablePath)) {
|
|
541
|
+
modifications.push({
|
|
542
|
+
filePath: composablePath,
|
|
543
|
+
action: 'create',
|
|
544
|
+
content: composableContent,
|
|
545
|
+
description: 'Created Vue composable useHumanBehavior'
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
catch { }
|
|
559
550
|
if (mainFile) {
|
|
560
551
|
const content = fs.readFileSync(mainFile, 'utf8');
|
|
561
552
|
const modifiedContent = this.injectVuePlugin(content);
|
|
@@ -575,33 +566,48 @@ export default defineNuxtPlugin(() => {
|
|
|
575
566
|
*/
|
|
576
567
|
async generateAngularModifications() {
|
|
577
568
|
const modifications = [];
|
|
578
|
-
//
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
569
|
+
// Create Angular service (docs pattern)
|
|
570
|
+
const serviceDir = path.join(this.projectRoot, 'src', 'app', 'services');
|
|
571
|
+
const servicePath = path.join(serviceDir, 'hb.service.ts');
|
|
572
|
+
const serviceContent = `import { Injectable, NgZone, Inject, PLATFORM_ID } from '@angular/core';
|
|
573
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
574
|
+
import { HumanBehaviorTracker } from 'humanbehavior-js';
|
|
575
|
+
import { environment } from '../../environments/environment';
|
|
576
|
+
|
|
577
|
+
@Injectable({ providedIn: 'root' })
|
|
578
|
+
export class HumanBehavior {
|
|
579
|
+
private tracker: ReturnType<typeof HumanBehaviorTracker.init> | null = null;
|
|
580
|
+
|
|
581
|
+
constructor(private ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
|
|
582
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
583
|
+
this.ngZone.runOutsideAngular(() => {
|
|
584
|
+
this.tracker = HumanBehaviorTracker.init(environment.humanBehaviorApiKey);
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
capture(event: string, props?: Record<string, any>) {
|
|
590
|
+
this.tracker?.customEvent(event, props);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
identify(user: Record<string, any>) {
|
|
594
|
+
this.tracker?.identifyUser({ userProperties: user });
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
trackPageView(path?: string) {
|
|
598
|
+
this.tracker?.trackPageView(path);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
`;
|
|
602
|
+
if (!fs.existsSync(serviceDir)) {
|
|
603
|
+
fs.mkdirSync(serviceDir, { recursive: true });
|
|
595
604
|
}
|
|
596
|
-
|
|
597
|
-
// Legacy Angular with NgModule
|
|
598
|
-
const content = fs.readFileSync(appModuleFile, 'utf8');
|
|
599
|
-
const modifiedContent = this.injectAngularModule(content);
|
|
605
|
+
if (!fs.existsSync(servicePath)) {
|
|
600
606
|
modifications.push({
|
|
601
|
-
filePath:
|
|
602
|
-
action: '
|
|
603
|
-
content:
|
|
604
|
-
description: '
|
|
607
|
+
filePath: servicePath,
|
|
608
|
+
action: 'create',
|
|
609
|
+
content: serviceContent,
|
|
610
|
+
description: 'Created Angular HumanBehavior service (singleton)'
|
|
605
611
|
});
|
|
606
612
|
}
|
|
607
613
|
// Handle Angular environment files (proper Angular way)
|
|
@@ -670,6 +676,26 @@ export default defineNuxtPlugin(() => {
|
|
|
670
676
|
}
|
|
671
677
|
// For Angular, we don't need .env files since we use environment.ts
|
|
672
678
|
// The environment files are already created above
|
|
679
|
+
// Inject service into app component
|
|
680
|
+
const appComponentPath = path.join(this.projectRoot, 'src', 'app', 'app.ts');
|
|
681
|
+
if (fs.existsSync(appComponentPath)) {
|
|
682
|
+
const appContent = fs.readFileSync(appComponentPath, 'utf8');
|
|
683
|
+
// Check if already has HumanBehavior service
|
|
684
|
+
if (!appContent.includes('HumanBehavior')) {
|
|
685
|
+
let modifiedAppContent = appContent
|
|
686
|
+
.replace(/import { Component } from '@angular\/core';/, `import { Component } from '@angular/core';
|
|
687
|
+
import { HumanBehavior } from './services/hb.service';`)
|
|
688
|
+
.replace(/export class App {/, `export class App {
|
|
689
|
+
constructor(private readonly humanBehavior: HumanBehavior) {}`);
|
|
690
|
+
// Do not modify standalone setting; leave component decorator unchanged
|
|
691
|
+
modifications.push({
|
|
692
|
+
action: 'modify',
|
|
693
|
+
filePath: appComponentPath,
|
|
694
|
+
content: modifiedAppContent,
|
|
695
|
+
description: 'Injected HumanBehavior service into Angular app component'
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
}
|
|
673
699
|
return modifications;
|
|
674
700
|
}
|
|
675
701
|
/**
|
|
@@ -690,7 +716,7 @@ export default defineNuxtPlugin(() => {
|
|
|
690
716
|
filePath: layoutFile,
|
|
691
717
|
action: 'modify',
|
|
692
718
|
content: modifiedContent,
|
|
693
|
-
description: 'Added HumanBehavior
|
|
719
|
+
description: 'Added HumanBehavior tracker init to SvelteKit layout'
|
|
694
720
|
});
|
|
695
721
|
}
|
|
696
722
|
}
|
|
@@ -704,7 +730,7 @@ export default defineNuxtPlugin(() => {
|
|
|
704
730
|
filePath: mainFile,
|
|
705
731
|
action: 'modify',
|
|
706
732
|
content: modifiedContent,
|
|
707
|
-
description: 'Added HumanBehavior
|
|
733
|
+
description: 'Added HumanBehavior tracker init to Svelte app'
|
|
708
734
|
});
|
|
709
735
|
}
|
|
710
736
|
}
|
|
@@ -758,14 +784,9 @@ export default defineNuxtPlugin(() => {
|
|
|
758
784
|
content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
|
|
759
785
|
|
|
760
786
|
export const onClientEntry = () => {
|
|
761
|
-
console.log('Gatsby browser entry point loaded');
|
|
762
787
|
const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
|
|
763
|
-
console.log('API Key found:', apiKey ? 'Yes' : 'No');
|
|
764
788
|
if (apiKey) {
|
|
765
|
-
|
|
766
|
-
console.log('HumanBehavior SDK initialized for Gatsby');
|
|
767
|
-
} else {
|
|
768
|
-
console.log('No API key found in environment variables');
|
|
789
|
+
HumanBehaviorTracker.init(apiKey);
|
|
769
790
|
}
|
|
770
791
|
};`,
|
|
771
792
|
description: 'Created gatsby-browser.js with HumanBehavior initialization'
|
|
@@ -815,8 +836,33 @@ export const onClientEntry = () => {
|
|
|
815
836
|
if (this.framework?.type === 'react' || this.framework?.type === 'nextjs') {
|
|
816
837
|
steps.push('💡 Use the useHumanBehavior() hook to track custom events');
|
|
817
838
|
}
|
|
839
|
+
// Append any manual notes gathered during transformation
|
|
840
|
+
if (this.manualNotes.length) {
|
|
841
|
+
steps.push(...this.manualNotes.map((n) => `⚠️ ${n}`));
|
|
842
|
+
}
|
|
818
843
|
return steps;
|
|
819
844
|
}
|
|
845
|
+
/**
|
|
846
|
+
* Helper: apply a file transform or record a manual instruction if unchanged/missing
|
|
847
|
+
*/
|
|
848
|
+
applyOrNotify(filePath, transform, description, manualNote) {
|
|
849
|
+
if (!fs.existsSync(filePath)) {
|
|
850
|
+
this.manualNotes.push(`${manualNote} (file missing: ${path.relative(this.projectRoot, filePath)})`);
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
const original = fs.readFileSync(filePath, 'utf8');
|
|
854
|
+
const updated = transform(original);
|
|
855
|
+
if (updated !== original) {
|
|
856
|
+
return {
|
|
857
|
+
filePath,
|
|
858
|
+
action: 'modify',
|
|
859
|
+
content: updated,
|
|
860
|
+
description
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
this.manualNotes.push(manualNote);
|
|
864
|
+
return null;
|
|
865
|
+
}
|
|
820
866
|
// Helper methods for file detection and content injection
|
|
821
867
|
findReactAppFile() {
|
|
822
868
|
const possibleFiles = [
|
|
@@ -875,7 +921,7 @@ export const onClientEntry = () => {
|
|
|
875
921
|
const isVite = this.framework?.bundler === 'vite';
|
|
876
922
|
const envVar = isVite
|
|
877
923
|
? 'import.meta.env.VITE_HUMANBEHAVIOR_API_KEY!'
|
|
878
|
-
: 'process.env.
|
|
924
|
+
: 'process.env.REACT_APP_HUMANBEHAVIOR_API_KEY!';
|
|
879
925
|
const importStatement = `import { HumanBehaviorProvider } from 'humanbehavior-js/react';`;
|
|
880
926
|
// Enhanced parsing for React 18+ features
|
|
881
927
|
const hasReact18 = this.framework?.features?.hasReact18;
|
|
@@ -888,7 +934,7 @@ export const onClientEntry = () => {
|
|
|
888
934
|
modifiedContent = `${importStatement}\n\n${modifiedContent}`;
|
|
889
935
|
}
|
|
890
936
|
// Wrap the App component return with HumanBehaviorProvider
|
|
891
|
-
modifiedContent = modifiedContent.replace(/
|
|
937
|
+
modifiedContent = modifiedContent.replace(/return\s*\(([\s\S]*?)\)\s*;/, `return (
|
|
892
938
|
<HumanBehaviorProvider apiKey={${envVar}}>
|
|
893
939
|
$1
|
|
894
940
|
</HumanBehaviorProvider>
|
|
@@ -947,107 +993,89 @@ export const onClientEntry = () => {
|
|
|
947
993
|
if (content.includes('HumanBehaviorProvider')) {
|
|
948
994
|
return content;
|
|
949
995
|
}
|
|
950
|
-
const importStatement = `import { HumanBehaviorProvider, createHumanBehaviorLoader } from 'humanbehavior-js/remix';`;
|
|
951
|
-
const useLoaderDataImport = `import { useLoaderData } from "@remix-run/react";`;
|
|
952
|
-
// Add imports more robustly
|
|
953
996
|
let modifiedContent = content;
|
|
954
|
-
//
|
|
997
|
+
// Step 1: Add useLoaderData import
|
|
998
|
+
if (!content.includes('useLoaderData')) {
|
|
999
|
+
modifiedContent = modifiedContent.replace(/(} from ['"]@remix-run\/react['"];?\s*)/, `$1import { useLoaderData } from '@remix-run/react';
|
|
1000
|
+
`);
|
|
1001
|
+
}
|
|
1002
|
+
// Step 2: Add HumanBehaviorProvider import
|
|
955
1003
|
if (!content.includes('HumanBehaviorProvider')) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
const nextLineIndex = modifiedContent.indexOf('\n', lastImportIndex);
|
|
959
|
-
if (nextLineIndex !== -1) {
|
|
960
|
-
modifiedContent = modifiedContent.slice(0, nextLineIndex + 1) +
|
|
961
|
-
importStatement + '\n' +
|
|
962
|
-
modifiedContent.slice(nextLineIndex + 1);
|
|
963
|
-
}
|
|
964
|
-
else {
|
|
965
|
-
modifiedContent = modifiedContent + '\n' + importStatement;
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
else {
|
|
969
|
-
modifiedContent = importStatement + '\n' + modifiedContent;
|
|
970
|
-
}
|
|
1004
|
+
modifiedContent = modifiedContent.replace(/(} from ['"]@remix-run\/react['"];?\s*)/, `$1import { HumanBehaviorProvider } from 'humanbehavior-js/react';
|
|
1005
|
+
`);
|
|
971
1006
|
}
|
|
972
|
-
//
|
|
973
|
-
if (!content.includes('
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
const nextLineIndex = modifiedContent.indexOf('\n', lastImportIndex);
|
|
977
|
-
if (nextLineIndex !== -1) {
|
|
978
|
-
modifiedContent = modifiedContent.slice(0, nextLineIndex + 1) +
|
|
979
|
-
useLoaderDataImport + '\n' +
|
|
980
|
-
modifiedContent.slice(nextLineIndex + 1);
|
|
981
|
-
}
|
|
982
|
-
else {
|
|
983
|
-
modifiedContent = modifiedContent + '\n' + useLoaderDataImport;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
else {
|
|
987
|
-
modifiedContent = useLoaderDataImport + '\n' + modifiedContent;
|
|
988
|
-
}
|
|
1007
|
+
// Step 3: Add LoaderFunctionArgs import
|
|
1008
|
+
if (!content.includes('LoaderFunctionArgs')) {
|
|
1009
|
+
modifiedContent = modifiedContent.replace(/(} from ['"]@remix-run\/node['"];?\s*)/, `$1import type { LoaderFunctionArgs } from '@remix-run/node';
|
|
1010
|
+
`);
|
|
989
1011
|
}
|
|
990
|
-
// Add loader function before
|
|
1012
|
+
// Step 4: Add loader function before Layout function
|
|
991
1013
|
if (!content.includes('export const loader')) {
|
|
992
|
-
modifiedContent = modifiedContent.replace(/export
|
|
1014
|
+
modifiedContent = modifiedContent.replace(/(export function Layout)/, `export const loader = async ({ request }: LoaderFunctionArgs) => {
|
|
1015
|
+
return {
|
|
1016
|
+
ENV: {
|
|
1017
|
+
HUMANBEHAVIOR_API_KEY: process.env.HUMANBEHAVIOR_API_KEY,
|
|
1018
|
+
},
|
|
1019
|
+
};
|
|
1020
|
+
};
|
|
993
1021
|
|
|
994
|
-
|
|
1022
|
+
$1`);
|
|
995
1023
|
}
|
|
996
|
-
//
|
|
997
|
-
|
|
998
|
-
|
|
1024
|
+
// Step 5: Add useLoaderData call and wrap App function's return content with HumanBehaviorProvider
|
|
1025
|
+
if (!content.includes('const data = useLoaderData')) {
|
|
1026
|
+
modifiedContent = modifiedContent.replace(/(export default function App\(\) \{\s*)(return \(\s*<div[^>]*>[\s\S]*?<\/div>\s*\);\s*\})/, `$1const data = useLoaderData<typeof loader>();
|
|
999
1027
|
|
|
1000
1028
|
return (
|
|
1001
1029
|
<HumanBehaviorProvider apiKey={data.ENV.HUMANBEHAVIOR_API_KEY}>
|
|
1002
|
-
|
|
1030
|
+
<div className="min-h-screen bg-gray-50">
|
|
1031
|
+
<Navigation />
|
|
1032
|
+
<Outlet />
|
|
1033
|
+
</div>
|
|
1003
1034
|
</HumanBehaviorProvider>
|
|
1004
1035
|
);
|
|
1005
1036
|
}`);
|
|
1037
|
+
}
|
|
1006
1038
|
return modifiedContent;
|
|
1007
1039
|
}
|
|
1008
1040
|
injectVuePlugin(content) {
|
|
1009
|
-
|
|
1041
|
+
// New: use composable/tracker pattern per docs; idempotent and migrates from plugin
|
|
1042
|
+
if (content.includes('useHumanBehavior')) {
|
|
1010
1043
|
return content;
|
|
1011
1044
|
}
|
|
1012
|
-
const importStatement = `import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';`;
|
|
1013
|
-
// Enhanced Vue 3 support with version detection
|
|
1014
1045
|
const hasVue3 = this.framework?.features?.hasVue3;
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1046
|
+
const isVue3ByContent = content.includes('createApp') || content.includes('import { createApp }');
|
|
1047
|
+
let modifiedContent = content
|
|
1048
|
+
.replace(/import\s*\{\s*HumanBehaviorPlugin\s*\}\s*from\s*['\"]humanbehavior-js\/vue['\"];?/g, '')
|
|
1049
|
+
.replace(/app\.use\(\s*HumanBehaviorPlugin[\s\S]*?\);?/g, '');
|
|
1050
|
+
if (hasVue3 || isVue3ByContent) {
|
|
1051
|
+
const importComposable = `import { useHumanBehavior } from './composables/useHumanBehavior';`;
|
|
1052
|
+
if (!modifiedContent.includes(importComposable)) {
|
|
1053
|
+
const lastImportIndex = modifiedContent.lastIndexOf('import');
|
|
1054
|
+
if (lastImportIndex !== -1) {
|
|
1055
|
+
const nextLineIndex = modifiedContent.indexOf('\n', lastImportIndex);
|
|
1056
|
+
if (nextLineIndex !== -1) {
|
|
1057
|
+
modifiedContent = modifiedContent.slice(0, nextLineIndex + 1) + importComposable + '\n' + modifiedContent.slice(nextLineIndex + 1);
|
|
1058
|
+
}
|
|
1059
|
+
else {
|
|
1060
|
+
modifiedContent = modifiedContent + '\n' + importComposable;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
else {
|
|
1064
|
+
modifiedContent = importComposable + '\n' + modifiedContent;
|
|
1027
1065
|
}
|
|
1028
1066
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
modifiedContent = modifiedContent.replace(/(app\.mount\(.*?\))/, `${pluginUsage}\n\n$1`);
|
|
1067
|
+
if (modifiedContent.includes('createApp')) {
|
|
1068
|
+
modifiedContent = modifiedContent.replace(/(const\s+app\s*=\s*createApp\([^)]*\))/, `$1\nconst { tracker } = useHumanBehavior();`);
|
|
1032
1069
|
}
|
|
1033
1070
|
return modifiedContent;
|
|
1034
1071
|
}
|
|
1035
1072
|
else {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
});`;
|
|
1040
|
-
let modifiedContent = content;
|
|
1041
|
-
// Add import statement
|
|
1042
|
-
if (!content.includes(importStatement)) {
|
|
1043
|
-
modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
|
|
1044
|
-
if (!modifiedContent.includes(importStatement)) {
|
|
1045
|
-
modifiedContent = `${importStatement}\n\n${modifiedContent}`;
|
|
1046
|
-
}
|
|
1073
|
+
const trackerImport = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
|
|
1074
|
+
if (!modifiedContent.includes(trackerImport)) {
|
|
1075
|
+
modifiedContent = `${trackerImport}\n${modifiedContent}`;
|
|
1047
1076
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
modifiedContent = modifiedContent.replace(/(new Vue\(.*?\))/, `${pluginUsage}\n\n$1`);
|
|
1077
|
+
if (modifiedContent.includes('new Vue')) {
|
|
1078
|
+
modifiedContent = modifiedContent.replace(/(new\s+Vue\s*\()/, `HumanBehaviorTracker.init(process.env.VUE_APP_HUMANBEHAVIOR_API_KEY || import.meta?.env?.VITE_HUMANBEHAVIOR_API_KEY);\n$1`);
|
|
1051
1079
|
}
|
|
1052
1080
|
return modifiedContent;
|
|
1053
1081
|
}
|
|
@@ -1088,33 +1116,31 @@ if (typeof window !== 'undefined') {
|
|
|
1088
1116
|
return modifiedContent;
|
|
1089
1117
|
}
|
|
1090
1118
|
injectSvelteStore(content) {
|
|
1091
|
-
|
|
1119
|
+
// Direct tracker init for non-SSR Svelte
|
|
1120
|
+
if (content.includes('HumanBehaviorTracker.init')) {
|
|
1092
1121
|
return content;
|
|
1093
1122
|
}
|
|
1094
|
-
const importStatement = `import {
|
|
1095
|
-
const initCode =
|
|
1123
|
+
const importStatement = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
|
|
1124
|
+
const initCode = `// Initialize HumanBehavior SDK\nHumanBehaviorTracker.init(import.meta.env?.VITE_HUMANBEHAVIOR_API_KEY || process.env.PUBLIC_HUMANBEHAVIOR_API_KEY || '');`;
|
|
1096
1125
|
return `${importStatement}\n${initCode}\n\n${content}`;
|
|
1097
1126
|
}
|
|
1098
1127
|
injectSvelteKitLayout(content) {
|
|
1099
|
-
|
|
1128
|
+
// Direct tracker init with browser guard for SvelteKit
|
|
1129
|
+
if (content.includes('HumanBehaviorTracker.init')) {
|
|
1100
1130
|
return content;
|
|
1101
1131
|
}
|
|
1102
|
-
const importStatement = `import { humanBehaviorStore } from 'humanbehavior-js/svelte';`;
|
|
1103
1132
|
const envImport = `import { PUBLIC_HUMANBEHAVIOR_API_KEY } from '$env/static/public';`;
|
|
1104
|
-
const
|
|
1105
|
-
|
|
1133
|
+
const hbImport = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
|
|
1134
|
+
const browserImport = `import { browser } from '$app/environment';`;
|
|
1135
|
+
const initCode = `if (browser) {\n const apiKey = PUBLIC_HUMANBEHAVIOR_API_KEY || import.meta.env.VITE_HUMANBEHAVIOR_API_KEY;\n if (apiKey) {\n HumanBehaviorTracker.init(apiKey);\n }\n}`;
|
|
1106
1136
|
if (content.includes('<script lang="ts">')) {
|
|
1107
|
-
return content.replace(/<script lang="ts">/, `<script lang="ts">\n\t${envImport}\n\t${
|
|
1137
|
+
return content.replace(/<script lang="ts">/, `<script lang="ts">\n\t${browserImport}\n\t${envImport}\n\t${hbImport}\n\t${initCode}`);
|
|
1108
1138
|
}
|
|
1109
1139
|
else if (content.includes('<script>')) {
|
|
1110
|
-
return content.replace(/<script>/, `<script>\n\t${envImport}\n\t${
|
|
1111
|
-
}
|
|
1112
|
-
else if (content.includes('<script context="module">')) {
|
|
1113
|
-
return content.replace(/<script\s+context="module">/, `<script context="module">\n\t${envImport}\n\t${importStatement}\n\t${initCode}`);
|
|
1140
|
+
return content.replace(/<script>/, `<script>\n\t${browserImport}\n\t${envImport}\n\t${hbImport}\n\t${initCode}`);
|
|
1114
1141
|
}
|
|
1115
1142
|
else {
|
|
1116
|
-
|
|
1117
|
-
return content.replace(/<svelte:head>/, `<script lang="ts">\n\t${envImport}\n\t${importStatement}\n\t${initCode}\n</script>\n\n<svelte:head>`);
|
|
1143
|
+
return `<script lang="ts">\n${browserImport}\n${envImport}\n${hbImport}\n${initCode}\n</script>\n\n${content}`;
|
|
1118
1144
|
}
|
|
1119
1145
|
}
|
|
1120
1146
|
injectVanillaScript(content) {
|
|
@@ -1167,13 +1193,25 @@ if (typeof window !== 'undefined') {
|
|
|
1167
1193
|
// Enhanced Nuxt 3 support with version detection
|
|
1168
1194
|
const hasNuxt3 = this.framework?.features?.hasNuxt3;
|
|
1169
1195
|
if (hasNuxt3) {
|
|
1170
|
-
// Nuxt 3 with runtime config
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
public: {
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1196
|
+
// Nuxt 3 with runtime config (robust match for opening object)
|
|
1197
|
+
const pattern = /export\s+default\s+defineNuxtConfig\s*\(\s*\{/;
|
|
1198
|
+
if (pattern.test(content)) {
|
|
1199
|
+
const replaced = content.replace(pattern, `export default defineNuxtConfig({\n runtimeConfig: {\n public: {\n humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY\n }\n },`);
|
|
1200
|
+
if (replaced !== content)
|
|
1201
|
+
return replaced;
|
|
1202
|
+
}
|
|
1203
|
+
// Fallback: insert runtimeConfig after opening brace of defineNuxtConfig
|
|
1204
|
+
const startIdx = content.indexOf('defineNuxtConfig(');
|
|
1205
|
+
if (startIdx !== -1) {
|
|
1206
|
+
const braceIdx = content.indexOf('{', startIdx);
|
|
1207
|
+
if (braceIdx !== -1) {
|
|
1208
|
+
const insertion = `\n runtimeConfig: {\n public: {\n humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY\n }\n },`;
|
|
1209
|
+
const before = content.slice(0, braceIdx + 1);
|
|
1210
|
+
const after = content.slice(braceIdx + 1);
|
|
1211
|
+
return `${before}${insertion}${after}`;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return content;
|
|
1177
1215
|
}
|
|
1178
1216
|
else {
|
|
1179
1217
|
// Nuxt 2 with env config
|
|
@@ -1196,31 +1234,26 @@ if (typeof window !== 'undefined') {
|
|
|
1196
1234
|
return modifiedContent;
|
|
1197
1235
|
}
|
|
1198
1236
|
injectGatsbyBrowser(content) {
|
|
1199
|
-
if (content.includes('HumanBehaviorTracker')) {
|
|
1200
|
-
return content;
|
|
1201
|
-
}
|
|
1202
1237
|
const importStatement = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
if (content.trim()) {
|
|
1218
|
-
return `${importStatement}${initCode}\n\n${content}`;
|
|
1219
|
-
}
|
|
1220
|
-
else {
|
|
1221
|
-
// If file is empty, just return the new content
|
|
1222
|
-
return `${importStatement}${initCode}`;
|
|
1238
|
+
// If an onClientEntry already exists, merge init into it idempotently
|
|
1239
|
+
if (/export\s+const\s+onClientEntry\s*=\s*\(/.test(content)) {
|
|
1240
|
+
let modified = content;
|
|
1241
|
+
// Ensure import exists
|
|
1242
|
+
if (!modified.includes("from 'humanbehavior-js'")) {
|
|
1243
|
+
modified = `${importStatement}\n${modified}`;
|
|
1244
|
+
}
|
|
1245
|
+
// If init already present, return as-is
|
|
1246
|
+
if (modified.includes('HumanBehaviorTracker.init(')) {
|
|
1247
|
+
return modified;
|
|
1248
|
+
}
|
|
1249
|
+
// Inject minimal init at start of onClientEntry body
|
|
1250
|
+
modified = modified.replace(/(export\s+const\s+onClientEntry\s*=\s*\([^)]*\)\s*=>\s*\{)/, `$1\n const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;\n if (apiKey) {\n HumanBehaviorTracker.init(apiKey);\n }\n`);
|
|
1251
|
+
return modified;
|
|
1223
1252
|
}
|
|
1253
|
+
// No existing onClientEntry: create minimal file content or prepend to existing
|
|
1254
|
+
const block = `export const onClientEntry = () => {\n const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;\n if (apiKey) {\n HumanBehaviorTracker.init(apiKey);\n }\n};`;
|
|
1255
|
+
const header = content.trim() ? `${importStatement}\n` : `${importStatement}\n`;
|
|
1256
|
+
return `${header}${block}${content.trim() ? `\n\n${content}` : ''}`;
|
|
1224
1257
|
}
|
|
1225
1258
|
/**
|
|
1226
1259
|
* Helper method to find the best environment file for a framework
|
|
@@ -1243,7 +1276,7 @@ export const onClientEntry = () => {
|
|
|
1243
1276
|
}
|
|
1244
1277
|
// Framework-specific mappings
|
|
1245
1278
|
const envVarNames = {
|
|
1246
|
-
react: '
|
|
1279
|
+
react: 'REACT_APP_HUMANBEHAVIOR_API_KEY',
|
|
1247
1280
|
nextjs: 'NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
|
|
1248
1281
|
vue: 'VITE_HUMANBEHAVIOR_API_KEY',
|
|
1249
1282
|
svelte: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
|