humanbehavior-js 0.4.15 → 0.4.17

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.
Files changed (89) hide show
  1. package/dist/cjs/wizard/index.cjs +6 -8
  2. package/dist/cjs/wizard/index.cjs.map +1 -1
  3. package/dist/cli/ai-auto-install.js +6 -8
  4. package/dist/cli/ai-auto-install.js.map +1 -1
  5. package/dist/esm/wizard/index.js +6 -8
  6. package/dist/esm/wizard/index.js.map +1 -1
  7. package/package/WIZARD_USAGE_GUIDE.md +381 -0
  8. package/package/canvas-recording-demo.html +143 -0
  9. package/package/clean-console-demo.html +39 -0
  10. package/package/dist/cjs/angular/index.cjs +14354 -0
  11. package/package/dist/cjs/angular/index.cjs.map +1 -0
  12. package/package/dist/cjs/index.cjs +14323 -0
  13. package/package/dist/cjs/index.cjs.map +1 -0
  14. package/package/dist/cjs/install-wizard.cjs +1530 -0
  15. package/package/dist/cjs/install-wizard.cjs.map +1 -0
  16. package/package/dist/cjs/react/index.cjs +14478 -0
  17. package/package/dist/cjs/react/index.cjs.map +1 -0
  18. package/package/dist/cjs/remix/index.cjs +14452 -0
  19. package/package/dist/cjs/remix/index.cjs.map +1 -0
  20. package/package/dist/cjs/svelte/index.cjs +14308 -0
  21. package/package/dist/cjs/svelte/index.cjs.map +1 -0
  22. package/package/dist/cjs/vue/index.cjs +14317 -0
  23. package/package/dist/cjs/vue/index.cjs.map +1 -0
  24. package/package/dist/cjs/wizard/index.cjs +3446 -0
  25. package/package/dist/cjs/wizard/index.cjs.map +1 -0
  26. package/package/dist/cli/ai-auto-install.cjs +57161 -0
  27. package/package/dist/cli/ai-auto-install.cjs.map +1 -0
  28. package/package/dist/cli/ai-auto-install.js +1969 -0
  29. package/package/dist/cli/ai-auto-install.js.map +1 -0
  30. package/package/dist/cli/auto-install.cjs +56352 -0
  31. package/package/dist/cli/auto-install.cjs.map +1 -0
  32. package/package/dist/cli/auto-install.js +1957 -0
  33. package/package/dist/cli/auto-install.js.map +1 -0
  34. package/package/dist/esm/angular/index.js +14350 -0
  35. package/package/dist/esm/angular/index.js.map +1 -0
  36. package/package/dist/esm/index.js +14309 -0
  37. package/package/dist/esm/index.js.map +1 -0
  38. package/package/dist/esm/install-wizard.js +1507 -0
  39. package/package/dist/esm/install-wizard.js.map +1 -0
  40. package/package/dist/esm/react/index.js +14472 -0
  41. package/package/dist/esm/react/index.js.map +1 -0
  42. package/package/dist/esm/remix/index.js +14448 -0
  43. package/package/dist/esm/remix/index.js.map +1 -0
  44. package/package/dist/esm/svelte/index.js +14306 -0
  45. package/package/dist/esm/svelte/index.js.map +1 -0
  46. package/package/dist/esm/vue/index.js +14315 -0
  47. package/package/dist/esm/vue/index.js.map +1 -0
  48. package/package/dist/esm/wizard/index.js +3415 -0
  49. package/package/dist/esm/wizard/index.js.map +1 -0
  50. package/package/dist/index.min.js +2 -0
  51. package/package/dist/index.min.js.map +1 -0
  52. package/package/dist/types/angular/index.d.ts +267 -0
  53. package/package/dist/types/index.d.ts +373 -0
  54. package/package/dist/types/install-wizard.d.ts +156 -0
  55. package/package/dist/types/react/index.d.ts +255 -0
  56. package/package/dist/types/remix/index.d.ts +246 -0
  57. package/package/dist/types/svelte/index.d.ts +232 -0
  58. package/package/dist/types/vue/index.d.ts +15 -0
  59. package/package/dist/types/wizard/index.d.ts +523 -0
  60. package/package/package.json +105 -0
  61. package/package/readme.md +281 -0
  62. package/package/rollup.config.js +422 -0
  63. package/package/simple-demo.html +26 -0
  64. package/package/simple-spa.html +838 -0
  65. package/package/src/angular/index.ts +79 -0
  66. package/package/src/api.ts +376 -0
  67. package/package/src/index.ts +28 -0
  68. package/package/src/react/AutoInstallWizard.tsx +557 -0
  69. package/package/src/react/browser.ts +8 -0
  70. package/package/src/react/index.tsx +308 -0
  71. package/package/src/redact.ts +521 -0
  72. package/package/src/remix/index.ts +16 -0
  73. package/package/src/svelte/index.ts +14 -0
  74. package/package/src/tracker.ts +1319 -0
  75. package/package/src/types/clack.d.ts +31 -0
  76. package/package/src/utils/logger.ts +144 -0
  77. package/package/src/vue/index.ts +29 -0
  78. package/package/src/wizard/README.md +114 -0
  79. package/package/src/wizard/ai/ai-install-wizard.ts +897 -0
  80. package/package/src/wizard/ai/manual-framework-wizard.ts +238 -0
  81. package/package/src/wizard/cli/ai-auto-install.ts +243 -0
  82. package/package/src/wizard/cli/auto-install.ts +224 -0
  83. package/package/src/wizard/core/install-wizard.ts +1744 -0
  84. package/package/src/wizard/index.ts +23 -0
  85. package/package/src/wizard/services/centralized-ai-service.ts +668 -0
  86. package/package/src/wizard/services/remote-ai-service.ts +240 -0
  87. package/package/tsconfig.json +24 -0
  88. package/package.json +1 -1
  89. package/src/wizard/cli/ai-auto-install.ts +4 -6
@@ -0,0 +1,1530 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+
6
+ function _interopNamespaceDefault(e) {
7
+ var n = Object.create(null);
8
+ if (e) {
9
+ Object.keys(e).forEach(function (k) {
10
+ if (k !== 'default') {
11
+ var d = Object.getOwnPropertyDescriptor(e, k);
12
+ Object.defineProperty(n, k, d.get ? d : {
13
+ enumerable: true,
14
+ get: function () { return e[k]; }
15
+ });
16
+ }
17
+ });
18
+ }
19
+ n.default = e;
20
+ return Object.freeze(n);
21
+ }
22
+
23
+ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
24
+ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
25
+
26
+ /******************************************************************************
27
+ Copyright (c) Microsoft Corporation.
28
+
29
+ Permission to use, copy, modify, and/or distribute this software for any
30
+ purpose with or without fee is hereby granted.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
33
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
34
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
35
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
36
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
37
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
38
+ PERFORMANCE OF THIS SOFTWARE.
39
+ ***************************************************************************** */
40
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
41
+
42
+
43
+ function __awaiter(thisArg, _arguments, P, generator) {
44
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
45
+ return new (P || (P = Promise))(function (resolve, reject) {
46
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
47
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
48
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
49
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
50
+ });
51
+ }
52
+
53
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
54
+ var e = new Error(message);
55
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
56
+ };
57
+
58
+ /**
59
+ * HumanBehavior SDK Auto-Installation Wizard
60
+ *
61
+ * This wizard automatically detects the user's framework and modifies their codebase
62
+ * to integrate the SDK with minimal user intervention.
63
+ */
64
+ class AutoInstallationWizard {
65
+ constructor(apiKey, projectRoot = process.cwd()) {
66
+ this.framework = null;
67
+ this.apiKey = apiKey;
68
+ this.projectRoot = projectRoot;
69
+ }
70
+ /**
71
+ * Simple version comparison utility
72
+ */
73
+ compareVersions(version1, version2) {
74
+ const v1Parts = version1.split('.').map(Number);
75
+ const v2Parts = version2.split('.').map(Number);
76
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
77
+ const v1 = v1Parts[i] || 0;
78
+ const v2 = v2Parts[i] || 0;
79
+ if (v1 > v2)
80
+ return 1;
81
+ if (v1 < v2)
82
+ return -1;
83
+ }
84
+ return 0;
85
+ }
86
+ isVersionGte(version, target) {
87
+ return this.compareVersions(version, target) >= 0;
88
+ }
89
+ getMajorVersion(version) {
90
+ return parseInt(version.split('.')[0]) || 0;
91
+ }
92
+ /**
93
+ * Main installation method - detects framework and auto-installs
94
+ */
95
+ install() {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ try {
98
+ // Step 1: Detect framework
99
+ this.framework = yield this.detectFramework();
100
+ // Step 2: Install package
101
+ yield this.installPackage();
102
+ // Step 3: Generate and apply code modifications
103
+ const modifications = yield this.generateModifications();
104
+ yield this.applyModifications(modifications);
105
+ // Step 4: Generate next steps
106
+ const nextSteps = this.generateNextSteps();
107
+ return {
108
+ success: true,
109
+ framework: this.framework,
110
+ modifications,
111
+ errors: [],
112
+ nextSteps
113
+ };
114
+ }
115
+ catch (error) {
116
+ return {
117
+ success: false,
118
+ framework: this.framework || { name: 'unknown', type: 'vanilla' },
119
+ modifications: [],
120
+ errors: [error instanceof Error ? error.message : 'Unknown error'],
121
+ nextSteps: []
122
+ };
123
+ }
124
+ });
125
+ }
126
+ /**
127
+ * Detect the current framework and project setup
128
+ */
129
+ detectFramework() {
130
+ return __awaiter(this, void 0, void 0, function* () {
131
+ const packageJsonPath = path__namespace.join(this.projectRoot, 'package.json');
132
+ if (!fs__namespace.existsSync(packageJsonPath)) {
133
+ return {
134
+ name: 'vanilla',
135
+ type: 'vanilla',
136
+ projectRoot: this.projectRoot
137
+ };
138
+ }
139
+ const packageJson = JSON.parse(fs__namespace.readFileSync(packageJsonPath, 'utf8'));
140
+ const dependencies = Object.assign(Object.assign({}, packageJson.dependencies), packageJson.devDependencies);
141
+ // Detect framework with version information
142
+ let framework = {
143
+ name: 'vanilla',
144
+ type: 'vanilla',
145
+ projectRoot: this.projectRoot,
146
+ features: {}
147
+ };
148
+ if (dependencies.nuxt) {
149
+ const nuxtVersion = dependencies.nuxt;
150
+ const isNuxt3 = this.isVersionGte(nuxtVersion, '3.0.0');
151
+ framework = {
152
+ name: 'nuxt',
153
+ type: 'nuxt',
154
+ version: nuxtVersion,
155
+ majorVersion: this.getMajorVersion(nuxtVersion),
156
+ hasTypeScript: !!dependencies.typescript,
157
+ hasRouter: true,
158
+ projectRoot: this.projectRoot,
159
+ features: {
160
+ hasNuxt3: isNuxt3
161
+ }
162
+ };
163
+ }
164
+ else if (dependencies.next) {
165
+ const nextVersion = dependencies.next;
166
+ const isNext13 = this.isVersionGte(nextVersion, '13.0.0');
167
+ framework = {
168
+ name: 'nextjs',
169
+ type: 'nextjs',
170
+ version: nextVersion,
171
+ majorVersion: this.getMajorVersion(nextVersion),
172
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/node'],
173
+ hasRouter: true,
174
+ projectRoot: this.projectRoot,
175
+ features: {
176
+ hasNextAppRouter: isNext13
177
+ }
178
+ };
179
+ }
180
+ else if (dependencies['@remix-run/react'] || dependencies['@remix-run/dev']) {
181
+ const remixVersion = dependencies['@remix-run/react'] || dependencies['@remix-run/dev'];
182
+ framework = {
183
+ name: 'remix',
184
+ type: 'remix',
185
+ version: remixVersion,
186
+ majorVersion: this.getMajorVersion(remixVersion),
187
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
188
+ hasRouter: true,
189
+ projectRoot: this.projectRoot,
190
+ features: {}
191
+ };
192
+ }
193
+ else if (dependencies.react) {
194
+ const reactVersion = dependencies.react;
195
+ const isReact18 = this.isVersionGte(reactVersion, '18.0.0');
196
+ framework = {
197
+ name: 'react',
198
+ type: 'react',
199
+ version: reactVersion,
200
+ majorVersion: this.getMajorVersion(reactVersion),
201
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
202
+ hasRouter: !!dependencies['react-router-dom'] || !!dependencies['react-router'],
203
+ projectRoot: this.projectRoot,
204
+ features: {
205
+ hasReact18: isReact18
206
+ }
207
+ };
208
+ }
209
+ else if (dependencies.vue) {
210
+ const vueVersion = dependencies.vue;
211
+ const isVue3 = this.isVersionGte(vueVersion, '3.0.0');
212
+ framework = {
213
+ name: 'vue',
214
+ type: 'vue',
215
+ version: vueVersion,
216
+ majorVersion: this.getMajorVersion(vueVersion),
217
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@vue/cli-service'],
218
+ hasRouter: !!dependencies['vue-router'],
219
+ projectRoot: this.projectRoot,
220
+ features: {
221
+ hasVue3: isVue3
222
+ }
223
+ };
224
+ }
225
+ else if (dependencies['@angular/core']) {
226
+ const angularVersion = dependencies['@angular/core'];
227
+ const isAngular17 = this.isVersionGte(angularVersion, '17.0.0');
228
+ framework = {
229
+ name: 'angular',
230
+ type: 'angular',
231
+ version: angularVersion,
232
+ majorVersion: this.getMajorVersion(angularVersion),
233
+ hasTypeScript: true,
234
+ hasRouter: true,
235
+ projectRoot: this.projectRoot,
236
+ features: {
237
+ hasAngularStandalone: isAngular17
238
+ }
239
+ };
240
+ }
241
+ else if (dependencies.svelte) {
242
+ const svelteVersion = dependencies.svelte;
243
+ const isSvelteKit = !!dependencies['@sveltejs/kit'];
244
+ framework = {
245
+ name: 'svelte',
246
+ type: 'svelte',
247
+ version: svelteVersion,
248
+ majorVersion: this.getMajorVersion(svelteVersion),
249
+ hasTypeScript: !!dependencies.typescript || !!dependencies['svelte-check'],
250
+ hasRouter: !!dependencies['svelte-routing'] || !!dependencies['@sveltejs/kit'],
251
+ projectRoot: this.projectRoot,
252
+ features: {
253
+ hasSvelteKit: isSvelteKit
254
+ }
255
+ };
256
+ }
257
+ else if (dependencies.astro) {
258
+ const astroVersion = dependencies.astro;
259
+ framework = {
260
+ name: 'astro',
261
+ type: 'astro',
262
+ version: astroVersion,
263
+ majorVersion: this.getMajorVersion(astroVersion),
264
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@astrojs/ts-plugin'],
265
+ hasRouter: true,
266
+ projectRoot: this.projectRoot,
267
+ features: {}
268
+ };
269
+ }
270
+ else if (dependencies.gatsby) {
271
+ const gatsbyVersion = dependencies.gatsby;
272
+ framework = {
273
+ name: 'gatsby',
274
+ type: 'gatsby',
275
+ version: gatsbyVersion,
276
+ majorVersion: this.getMajorVersion(gatsbyVersion),
277
+ hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
278
+ hasRouter: true,
279
+ projectRoot: this.projectRoot,
280
+ features: {}
281
+ };
282
+ }
283
+ // Detect bundler
284
+ if (dependencies.vite) {
285
+ framework.bundler = 'vite';
286
+ }
287
+ else if (dependencies.webpack) {
288
+ framework.bundler = 'webpack';
289
+ }
290
+ else if (dependencies.esbuild) {
291
+ framework.bundler = 'esbuild';
292
+ }
293
+ else if (dependencies.rollup) {
294
+ framework.bundler = 'rollup';
295
+ }
296
+ // Detect package manager
297
+ if (fs__namespace.existsSync(path__namespace.join(this.projectRoot, 'yarn.lock'))) {
298
+ framework.packageManager = 'yarn';
299
+ }
300
+ else if (fs__namespace.existsSync(path__namespace.join(this.projectRoot, 'pnpm-lock.yaml'))) {
301
+ framework.packageManager = 'pnpm';
302
+ }
303
+ else {
304
+ framework.packageManager = 'npm';
305
+ }
306
+ return framework;
307
+ });
308
+ }
309
+ /**
310
+ * Install the SDK package
311
+ */
312
+ installPackage() {
313
+ return __awaiter(this, void 0, void 0, function* () {
314
+ var _a, _b, _c, _d;
315
+ const { execSync } = yield import('child_process');
316
+ // Build base command
317
+ let command = ((_a = this.framework) === null || _a === void 0 ? void 0 : _a.packageManager) === 'yarn'
318
+ ? 'yarn add humanbehavior-js'
319
+ : ((_b = this.framework) === null || _b === void 0 ? void 0 : _b.packageManager) === 'pnpm'
320
+ ? 'pnpm add humanbehavior-js'
321
+ : 'npm install humanbehavior-js';
322
+ // Add legacy peer deps flag for npm to handle dependency conflicts
323
+ 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') {
324
+ command += ' --legacy-peer-deps';
325
+ }
326
+ try {
327
+ execSync(command, { cwd: this.projectRoot, stdio: 'inherit' });
328
+ }
329
+ catch (error) {
330
+ throw new Error(`Failed to install humanbehavior-js: ${error}`);
331
+ }
332
+ });
333
+ }
334
+ /**
335
+ * Generate code modifications based on framework
336
+ */
337
+ generateModifications() {
338
+ return __awaiter(this, void 0, void 0, function* () {
339
+ var _a;
340
+ const modifications = [];
341
+ switch ((_a = this.framework) === null || _a === void 0 ? void 0 : _a.type) {
342
+ case 'react':
343
+ modifications.push(...yield this.generateReactModifications());
344
+ break;
345
+ case 'nextjs':
346
+ modifications.push(...yield this.generateNextJSModifications());
347
+ break;
348
+ case 'nuxt':
349
+ modifications.push(...yield this.generateNuxtModifications());
350
+ break;
351
+ case 'astro':
352
+ modifications.push(...yield this.generateAstroModifications());
353
+ break;
354
+ case 'gatsby':
355
+ modifications.push(...yield this.generateGatsbyModifications());
356
+ break;
357
+ case 'remix':
358
+ modifications.push(...yield this.generateRemixModifications());
359
+ break;
360
+ case 'vue':
361
+ modifications.push(...yield this.generateVueModifications());
362
+ break;
363
+ case 'angular':
364
+ modifications.push(...yield this.generateAngularModifications());
365
+ break;
366
+ case 'svelte':
367
+ modifications.push(...yield this.generateSvelteModifications());
368
+ break;
369
+ default:
370
+ modifications.push(...yield this.generateVanillaModifications());
371
+ }
372
+ return modifications;
373
+ });
374
+ }
375
+ /**
376
+ * Generate React-specific modifications
377
+ */
378
+ generateReactModifications() {
379
+ return __awaiter(this, void 0, void 0, function* () {
380
+ const modifications = [];
381
+ // Find main App component or index file
382
+ const appFile = this.findReactAppFile();
383
+ if (appFile) {
384
+ const content = fs__namespace.readFileSync(appFile, 'utf8');
385
+ const modifiedContent = this.injectReactProvider(content, appFile);
386
+ modifications.push({
387
+ filePath: appFile,
388
+ action: 'modify',
389
+ content: modifiedContent,
390
+ description: 'Added HumanBehaviorProvider to React app'
391
+ });
392
+ }
393
+ // Create or append to environment file
394
+ modifications.push(this.createEnvironmentModification(this.framework));
395
+ return modifications;
396
+ });
397
+ }
398
+ /**
399
+ * Generate Next.js-specific modifications
400
+ */
401
+ generateNextJSModifications() {
402
+ return __awaiter(this, void 0, void 0, function* () {
403
+ const modifications = [];
404
+ // Check for App Router
405
+ const appLayoutFile = path__namespace.join(this.projectRoot, 'src', 'app', 'layout.tsx');
406
+ const pagesLayoutFile = path__namespace.join(this.projectRoot, 'src', 'pages', '_app.tsx');
407
+ if (fs__namespace.existsSync(appLayoutFile)) {
408
+ // Create providers.tsx file for App Router
409
+ modifications.push({
410
+ filePath: path__namespace.join(this.projectRoot, 'src', 'app', 'providers.tsx'),
411
+ action: 'create',
412
+ content: `'use client';
413
+
414
+ import { HumanBehaviorProvider } from 'humanbehavior-js/react';
415
+
416
+ export function Providers({ children }: { children: React.ReactNode }) {
417
+ return (
418
+ <HumanBehaviorProvider apiKey={process.env.NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY}>
419
+ {children}
420
+ </HumanBehaviorProvider>
421
+ );
422
+ }`,
423
+ description: 'Created providers.tsx file for Next.js App Router'
424
+ });
425
+ // Modify layout.tsx to use the provider
426
+ const content = fs__namespace.readFileSync(appLayoutFile, 'utf8');
427
+ const modifiedContent = this.injectNextJSAppRouter(content);
428
+ modifications.push({
429
+ filePath: appLayoutFile,
430
+ action: 'modify',
431
+ content: modifiedContent,
432
+ description: 'Added Providers wrapper to Next.js App Router layout'
433
+ });
434
+ }
435
+ else if (fs__namespace.existsSync(pagesLayoutFile)) {
436
+ // Create providers.tsx file for Pages Router
437
+ modifications.push({
438
+ filePath: path__namespace.join(this.projectRoot, 'src', 'components', 'providers.tsx'),
439
+ action: 'create',
440
+ content: `'use client';
441
+
442
+ import { HumanBehaviorProvider } from 'humanbehavior-js/react';
443
+
444
+ export function Providers({ children }: { children: React.ReactNode }) {
445
+ return (
446
+ <HumanBehaviorProvider apiKey={process.env.NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY}>
447
+ {children}
448
+ </HumanBehaviorProvider>
449
+ );
450
+ }`,
451
+ description: 'Created providers.tsx file for Pages Router'
452
+ });
453
+ // Modify _app.tsx to use the provider
454
+ const content = fs__namespace.readFileSync(pagesLayoutFile, 'utf8');
455
+ const modifiedContent = this.injectNextJSPagesRouter(content);
456
+ modifications.push({
457
+ filePath: pagesLayoutFile,
458
+ action: 'modify',
459
+ content: modifiedContent,
460
+ description: 'Added Providers wrapper to Next.js Pages Router'
461
+ });
462
+ }
463
+ // Create or append to environment file
464
+ modifications.push(this.createEnvironmentModification(this.framework));
465
+ return modifications;
466
+ });
467
+ }
468
+ /**
469
+ * Generate Astro-specific modifications
470
+ */
471
+ generateAstroModifications() {
472
+ return __awaiter(this, void 0, void 0, function* () {
473
+ const modifications = [];
474
+ // Create Astro component for HumanBehavior
475
+ const astroComponentPath = path__namespace.join(this.projectRoot, 'src', 'components', 'HumanBehavior.astro');
476
+ const astroComponentContent = `---
477
+ // This component will only run on the client side
478
+ ---
479
+
480
+ <script>
481
+ import { HumanBehaviorTracker } from 'humanbehavior-js';
482
+
483
+ // Get API key from environment variable
484
+ const apiKey = import.meta.env.PUBLIC_HUMANBEHAVIOR_API_KEY;
485
+
486
+ console.log('HumanBehavior: API key found:', apiKey ? 'Yes' : 'No');
487
+
488
+ if (apiKey) {
489
+ try {
490
+ const tracker = HumanBehaviorTracker.init(apiKey);
491
+ console.log('HumanBehavior: Tracker initialized successfully');
492
+
493
+ // Test event to verify tracking is working
494
+ setTimeout(() => {
495
+ tracker.customEvent('astro_page_view', {
496
+ page: window.location.pathname,
497
+ framework: 'astro'
498
+ }).then(() => {
499
+ console.log('HumanBehavior: Test event sent successfully');
500
+ }).catch((error) => {
501
+ console.error('HumanBehavior: Failed to send test event:', error);
502
+ });
503
+ }, 1000);
504
+
505
+ } catch (error) {
506
+ console.error('HumanBehavior: Failed to initialize tracker:', error);
507
+ }
508
+ } else {
509
+ console.error('HumanBehavior: No API key found');
510
+ }
511
+ </script>`;
512
+ modifications.push({
513
+ filePath: astroComponentPath,
514
+ action: 'create',
515
+ content: astroComponentContent,
516
+ description: 'Created Astro component for HumanBehavior SDK'
517
+ });
518
+ // Find and update layout file
519
+ const layoutFiles = [
520
+ path__namespace.join(this.projectRoot, 'src', 'layouts', 'Layout.astro'),
521
+ path__namespace.join(this.projectRoot, 'src', 'layouts', 'layout.astro'),
522
+ path__namespace.join(this.projectRoot, 'src', 'layouts', 'BaseLayout.astro')
523
+ ];
524
+ let layoutFile = null;
525
+ for (const file of layoutFiles) {
526
+ if (fs__namespace.existsSync(file)) {
527
+ layoutFile = file;
528
+ break;
529
+ }
530
+ }
531
+ if (layoutFile) {
532
+ const content = fs__namespace.readFileSync(layoutFile, 'utf8');
533
+ const modifiedContent = this.injectAstroLayout(content);
534
+ modifications.push({
535
+ filePath: layoutFile,
536
+ action: 'modify',
537
+ content: modifiedContent,
538
+ description: 'Added HumanBehavior component to Astro layout'
539
+ });
540
+ }
541
+ // Add environment variable
542
+ modifications.push(this.createEnvironmentModification(this.framework));
543
+ return modifications;
544
+ });
545
+ }
546
+ /**
547
+ * Generate Nuxt-specific modifications
548
+ */
549
+ generateNuxtModifications() {
550
+ return __awaiter(this, void 0, void 0, function* () {
551
+ const modifications = [];
552
+ // Create plugin file for Nuxt (in app directory)
553
+ const pluginFile = path__namespace.join(this.projectRoot, 'app', 'plugins', 'humanbehavior.client.ts');
554
+ modifications.push({
555
+ filePath: pluginFile,
556
+ action: 'create',
557
+ content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
558
+
559
+ export default defineNuxtPlugin(() => {
560
+ const config = useRuntimeConfig();
561
+
562
+ // Initialize HumanBehavior SDK (client-side only)
563
+ if (typeof window !== 'undefined') {
564
+ const apiKey = config.public.humanBehaviorApiKey;
565
+ console.log('HumanBehavior: API key:', apiKey ? 'present' : 'missing');
566
+
567
+ if (apiKey) {
568
+ try {
569
+ const tracker = HumanBehaviorTracker.init(apiKey);
570
+ console.log('HumanBehavior: Tracker initialized successfully');
571
+ } catch (error) {
572
+ console.error('HumanBehavior: Failed to initialize tracker:', error);
573
+ }
574
+ } else {
575
+ console.error('HumanBehavior: No API key found in runtime config');
576
+ }
577
+ }
578
+ });`,
579
+ description: 'Created Nuxt plugin for HumanBehavior SDK in app directory'
580
+ });
581
+ // Create environment configuration
582
+ const nuxtConfigFile = path__namespace.join(this.projectRoot, 'nuxt.config.ts');
583
+ if (fs__namespace.existsSync(nuxtConfigFile)) {
584
+ const content = fs__namespace.readFileSync(nuxtConfigFile, 'utf8');
585
+ const modifiedContent = this.injectNuxtConfig(content);
586
+ modifications.push({
587
+ filePath: nuxtConfigFile,
588
+ action: 'modify',
589
+ content: modifiedContent,
590
+ description: 'Added HumanBehavior runtime config to Nuxt config'
591
+ });
592
+ }
593
+ // Create or append to environment file
594
+ modifications.push(this.createEnvironmentModification(this.framework));
595
+ return modifications;
596
+ });
597
+ }
598
+ /**
599
+ * Generate Remix-specific modifications
600
+ */
601
+ generateRemixModifications() {
602
+ return __awaiter(this, void 0, void 0, function* () {
603
+ const modifications = [];
604
+ // Find root.tsx file
605
+ const rootFile = path__namespace.join(this.projectRoot, 'app', 'root.tsx');
606
+ if (fs__namespace.existsSync(rootFile)) {
607
+ const content = fs__namespace.readFileSync(rootFile, 'utf8');
608
+ const modifiedContent = this.injectRemixProvider(content);
609
+ modifications.push({
610
+ filePath: rootFile,
611
+ action: 'modify',
612
+ content: modifiedContent,
613
+ description: 'Added HumanBehaviorProvider to Remix root component'
614
+ });
615
+ }
616
+ // Create or append to environment file
617
+ modifications.push(this.createEnvironmentModification(this.framework));
618
+ return modifications;
619
+ });
620
+ }
621
+ /**
622
+ * Generate Vue-specific modifications
623
+ */
624
+ generateVueModifications() {
625
+ return __awaiter(this, void 0, void 0, function* () {
626
+ const modifications = [];
627
+ // Find main.js or main.ts
628
+ const mainFile = this.findVueMainFile();
629
+ if (mainFile) {
630
+ const content = fs__namespace.readFileSync(mainFile, 'utf8');
631
+ const modifiedContent = this.injectVuePlugin(content);
632
+ modifications.push({
633
+ filePath: mainFile,
634
+ action: 'modify',
635
+ content: modifiedContent,
636
+ description: 'Added HumanBehaviorPlugin to Vue app'
637
+ });
638
+ }
639
+ // Create or append to environment file
640
+ modifications.push(this.createEnvironmentModification(this.framework));
641
+ return modifications;
642
+ });
643
+ }
644
+ /**
645
+ * Generate Angular-specific modifications
646
+ */
647
+ generateAngularModifications() {
648
+ return __awaiter(this, void 0, void 0, function* () {
649
+ const modifications = [];
650
+ // Check for modern Angular (standalone components) vs legacy (NgModule)
651
+ const appModuleFile = path__namespace.join(this.projectRoot, 'src', 'app', 'app.module.ts');
652
+ const appComponentFile = path__namespace.join(this.projectRoot, 'src', 'app', 'app.ts');
653
+ const mainFile = path__namespace.join(this.projectRoot, 'src', 'main.ts');
654
+ const isModernAngular = fs__namespace.existsSync(appComponentFile) && !fs__namespace.existsSync(appModuleFile);
655
+ if (isModernAngular) {
656
+ // Modern Angular 17+ with standalone components
657
+ if (fs__namespace.existsSync(mainFile)) {
658
+ const content = fs__namespace.readFileSync(mainFile, 'utf8');
659
+ const modifiedContent = this.injectAngularStandaloneInit(content);
660
+ modifications.push({
661
+ filePath: mainFile,
662
+ action: 'modify',
663
+ content: modifiedContent,
664
+ description: 'Added HumanBehavior initialization to Angular main.ts'
665
+ });
666
+ }
667
+ }
668
+ else if (fs__namespace.existsSync(appModuleFile)) {
669
+ // Legacy Angular with NgModule
670
+ const content = fs__namespace.readFileSync(appModuleFile, 'utf8');
671
+ const modifiedContent = this.injectAngularModule(content);
672
+ modifications.push({
673
+ filePath: appModuleFile,
674
+ action: 'modify',
675
+ content: modifiedContent,
676
+ description: 'Added HumanBehaviorModule to Angular app'
677
+ });
678
+ }
679
+ // Handle Angular environment file (legacy structure)
680
+ const envFile = path__namespace.join(this.projectRoot, 'src', 'environments', 'environment.ts');
681
+ if (fs__namespace.existsSync(envFile)) {
682
+ const content = fs__namespace.readFileSync(envFile, 'utf8');
683
+ if (!content.includes('humanBehaviorApiKey')) {
684
+ const modifiedContent = content.replace(/export const environment = {([\s\S]*?)};/, `export const environment = {
685
+ $1,
686
+ humanBehaviorApiKey: process.env['HUMANBEHAVIOR_API_KEY'] || ''
687
+ };`);
688
+ modifications.push({
689
+ filePath: envFile,
690
+ action: 'modify',
691
+ content: modifiedContent,
692
+ description: 'Added API key to Angular environment'
693
+ });
694
+ }
695
+ }
696
+ // Create or append to environment file
697
+ modifications.push(this.createEnvironmentModification(this.framework));
698
+ return modifications;
699
+ });
700
+ }
701
+ /**
702
+ * Generate Svelte-specific modifications
703
+ */
704
+ generateSvelteModifications() {
705
+ return __awaiter(this, void 0, void 0, function* () {
706
+ const modifications = [];
707
+ // Check for SvelteKit
708
+ const svelteConfigFile = path__namespace.join(this.projectRoot, 'svelte.config.js');
709
+ const isSvelteKit = fs__namespace.existsSync(svelteConfigFile);
710
+ if (isSvelteKit) {
711
+ // SvelteKit - create layout file
712
+ const layoutFile = path__namespace.join(this.projectRoot, 'src', 'routes', '+layout.svelte');
713
+ if (fs__namespace.existsSync(layoutFile)) {
714
+ const content = fs__namespace.readFileSync(layoutFile, 'utf8');
715
+ const modifiedContent = this.injectSvelteKitLayout(content);
716
+ modifications.push({
717
+ filePath: layoutFile,
718
+ action: 'modify',
719
+ content: modifiedContent,
720
+ description: 'Added HumanBehavior store to SvelteKit layout'
721
+ });
722
+ }
723
+ }
724
+ else {
725
+ // Regular Svelte - modify main file
726
+ const mainFile = this.findSvelteMainFile();
727
+ if (mainFile) {
728
+ const content = fs__namespace.readFileSync(mainFile, 'utf8');
729
+ const modifiedContent = this.injectSvelteStore(content);
730
+ modifications.push({
731
+ filePath: mainFile,
732
+ action: 'modify',
733
+ content: modifiedContent,
734
+ description: 'Added HumanBehavior store to Svelte app'
735
+ });
736
+ }
737
+ }
738
+ // Create or append to environment file
739
+ modifications.push(this.createEnvironmentModification(this.framework));
740
+ return modifications;
741
+ });
742
+ }
743
+ /**
744
+ * Generate vanilla JS/TS modifications
745
+ */
746
+ generateVanillaModifications() {
747
+ return __awaiter(this, void 0, void 0, function* () {
748
+ const modifications = [];
749
+ // Find HTML file to inject script
750
+ const htmlFile = this.findHTMLFile();
751
+ if (htmlFile) {
752
+ const content = fs__namespace.readFileSync(htmlFile, 'utf8');
753
+ const modifiedContent = this.injectVanillaScript(content);
754
+ modifications.push({
755
+ filePath: htmlFile,
756
+ action: 'modify',
757
+ content: modifiedContent,
758
+ description: 'Added HumanBehavior CDN script to HTML file'
759
+ });
760
+ }
761
+ // Create or append to environment file
762
+ modifications.push(this.createEnvironmentModification(this.framework));
763
+ return modifications;
764
+ });
765
+ }
766
+ /**
767
+ * Generate Gatsby-specific modifications
768
+ */
769
+ generateGatsbyModifications() {
770
+ return __awaiter(this, void 0, void 0, function* () {
771
+ const modifications = [];
772
+ // Modify or create gatsby-browser.js for Gatsby
773
+ const gatsbyBrowserFile = path__namespace.join(this.projectRoot, 'gatsby-browser.js');
774
+ if (fs__namespace.existsSync(gatsbyBrowserFile)) {
775
+ const content = fs__namespace.readFileSync(gatsbyBrowserFile, 'utf8');
776
+ const modifiedContent = this.injectGatsbyBrowser(content);
777
+ modifications.push({
778
+ filePath: gatsbyBrowserFile,
779
+ action: 'modify',
780
+ content: modifiedContent,
781
+ description: 'Added HumanBehavior initialization to Gatsby browser'
782
+ });
783
+ }
784
+ else {
785
+ // Create gatsby-browser.js if it doesn't exist
786
+ modifications.push({
787
+ filePath: gatsbyBrowserFile,
788
+ action: 'create',
789
+ content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
790
+
791
+ export const onClientEntry = () => {
792
+ console.log('Gatsby browser entry point loaded');
793
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
794
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
795
+ if (apiKey) {
796
+ const tracker = HumanBehaviorTracker.init(apiKey);
797
+ console.log('HumanBehavior SDK initialized for Gatsby');
798
+ } else {
799
+ console.log('No API key found in environment variables');
800
+ }
801
+ };`,
802
+ description: 'Created gatsby-browser.js with HumanBehavior initialization'
803
+ });
804
+ }
805
+ // Create or append to environment file
806
+ modifications.push(this.createEnvironmentModification(this.framework));
807
+ return modifications;
808
+ });
809
+ }
810
+ /**
811
+ * Apply modifications to the codebase
812
+ */
813
+ applyModifications(modifications) {
814
+ return __awaiter(this, void 0, void 0, function* () {
815
+ for (const modification of modifications) {
816
+ try {
817
+ const dir = path__namespace.dirname(modification.filePath);
818
+ if (!fs__namespace.existsSync(dir)) {
819
+ fs__namespace.mkdirSync(dir, { recursive: true });
820
+ }
821
+ switch (modification.action) {
822
+ case 'create':
823
+ fs__namespace.writeFileSync(modification.filePath, modification.content);
824
+ break;
825
+ case 'modify':
826
+ fs__namespace.writeFileSync(modification.filePath, modification.content);
827
+ break;
828
+ case 'append':
829
+ fs__namespace.appendFileSync(modification.filePath, '\n' + modification.content);
830
+ break;
831
+ }
832
+ }
833
+ catch (error) {
834
+ throw new Error(`Failed to apply modification to ${modification.filePath}: ${error}`);
835
+ }
836
+ }
837
+ });
838
+ }
839
+ /**
840
+ * Generate next steps for the user
841
+ */
842
+ generateNextSteps() {
843
+ var _a, _b;
844
+ const steps = [
845
+ '✅ SDK installed and configured automatically!',
846
+ '🚀 Your app is now tracking user behavior',
847
+ '📊 View sessions in your HumanBehavior dashboard',
848
+ '🔧 Customize tracking in your code as needed'
849
+ ];
850
+ if (((_a = this.framework) === null || _a === void 0 ? void 0 : _a.type) === 'react' || ((_b = this.framework) === null || _b === void 0 ? void 0 : _b.type) === 'nextjs') {
851
+ steps.push('💡 Use the useHumanBehavior() hook to track custom events');
852
+ }
853
+ return steps;
854
+ }
855
+ // Helper methods for file detection and content injection
856
+ findReactAppFile() {
857
+ const possibleFiles = [
858
+ 'src/App.jsx', 'src/App.js', 'src/App.tsx', 'src/App.ts',
859
+ 'src/index.js', 'src/index.tsx', 'src/main.js', 'src/main.tsx'
860
+ ];
861
+ for (const file of possibleFiles) {
862
+ const fullPath = path__namespace.join(this.projectRoot, file);
863
+ if (fs__namespace.existsSync(fullPath)) {
864
+ return fullPath;
865
+ }
866
+ }
867
+ return null;
868
+ }
869
+ findVueMainFile() {
870
+ const possibleFiles = [
871
+ 'src/main.js', 'src/main.ts', 'src/main.jsx', 'src/main.tsx'
872
+ ];
873
+ for (const file of possibleFiles) {
874
+ const fullPath = path__namespace.join(this.projectRoot, file);
875
+ if (fs__namespace.existsSync(fullPath)) {
876
+ return fullPath;
877
+ }
878
+ }
879
+ return null;
880
+ }
881
+ findSvelteMainFile() {
882
+ const possibleFiles = [
883
+ 'src/main.js', 'src/main.ts', 'src/main.svelte'
884
+ ];
885
+ for (const file of possibleFiles) {
886
+ const fullPath = path__namespace.join(this.projectRoot, file);
887
+ if (fs__namespace.existsSync(fullPath)) {
888
+ return fullPath;
889
+ }
890
+ }
891
+ return null;
892
+ }
893
+ findHTMLFile() {
894
+ const possibleFiles = ['index.html', 'public/index.html', 'dist/index.html'];
895
+ for (const file of possibleFiles) {
896
+ const fullPath = path__namespace.join(this.projectRoot, file);
897
+ if (fs__namespace.existsSync(fullPath)) {
898
+ return fullPath;
899
+ }
900
+ }
901
+ return null;
902
+ }
903
+ injectReactProvider(content, filePath) {
904
+ var _a, _b, _c;
905
+ filePath.endsWith('.tsx') || filePath.endsWith('.ts');
906
+ // Check if already has HumanBehaviorProvider
907
+ if (content.includes('HumanBehaviorProvider')) {
908
+ return content;
909
+ }
910
+ // Determine the correct environment variable syntax based on bundler
911
+ const isVite = ((_a = this.framework) === null || _a === void 0 ? void 0 : _a.bundler) === 'vite';
912
+ const envVar = isVite
913
+ ? 'import.meta.env.VITE_HUMANBEHAVIOR_API_KEY!'
914
+ : 'process.env.HUMANBEHAVIOR_API_KEY!';
915
+ const importStatement = `import { HumanBehaviorProvider } from 'humanbehavior-js/react';`;
916
+ // Enhanced parsing for React 18+ features
917
+ const hasReact18 = (_c = (_b = this.framework) === null || _b === void 0 ? void 0 : _b.features) === null || _c === void 0 ? void 0 : _c.hasReact18;
918
+ // Handle different React patterns
919
+ if (content.includes('function App()') || content.includes('const App =')) {
920
+ // Add import statement
921
+ let modifiedContent = content.replace(/(import.*?from.*?['"]react['"];?)/, `$1\n${importStatement}`);
922
+ // If no React import found, add it at the top
923
+ if (!modifiedContent.includes(importStatement)) {
924
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
925
+ }
926
+ // Wrap the App component return with HumanBehaviorProvider
927
+ modifiedContent = modifiedContent.replace(/(return\s*\([\s\S]*?\)\s*;)/, `return (
928
+ <HumanBehaviorProvider apiKey={${envVar}}>
929
+ $1
930
+ </HumanBehaviorProvider>
931
+ );`);
932
+ return modifiedContent;
933
+ }
934
+ // Handle React 18+ createRoot pattern
935
+ if (hasReact18 && content.includes('createRoot')) {
936
+ let modifiedContent = content.replace(/(import.*?from.*?['"]react['"];?)/, `$1\n${importStatement}`);
937
+ if (!modifiedContent.includes(importStatement)) {
938
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
939
+ }
940
+ // Wrap the root render with HumanBehaviorProvider
941
+ modifiedContent = modifiedContent.replace(/(root\.render\s*\([\s\S]*?\)\s*;)/, `root.render(
942
+ <HumanBehaviorProvider apiKey={${envVar}}>
943
+ $1
944
+ </HumanBehaviorProvider>
945
+ );`);
946
+ return modifiedContent;
947
+ }
948
+ // Fallback: simple injection
949
+ return `${importStatement}\n\n${content}`;
950
+ }
951
+ injectNextJSAppRouter(content) {
952
+ if (content.includes('Providers')) {
953
+ return content;
954
+ }
955
+ const importStatement = `import { Providers } from './providers';`;
956
+ // First, add the import statement
957
+ let modifiedContent = content.replace(/export default function RootLayout/, `${importStatement}\n\nexport default function RootLayout`);
958
+ // Then wrap the body content with Providers
959
+ // Use a more specific approach to handle the body content
960
+ modifiedContent = modifiedContent.replace(/<body([^>]*)>([\s\S]*?)<\/body>/, (match, bodyAttrs, bodyContent) => {
961
+ // Trim whitespace and newlines from bodyContent
962
+ const trimmedContent = bodyContent.trim();
963
+ return `<body${bodyAttrs}>
964
+ <Providers>
965
+ ${trimmedContent}
966
+ </Providers>
967
+ </body>`;
968
+ });
969
+ return modifiedContent;
970
+ }
971
+ injectNextJSPagesRouter(content) {
972
+ if (content.includes('Providers')) {
973
+ return content;
974
+ }
975
+ const importStatement = `import { Providers } from '../components/providers';`;
976
+ return content.replace(/function MyApp/, `${importStatement}\n\nfunction MyApp`).replace(/return \(([\s\S]*?)\);/, `return (
977
+ <Providers>
978
+ $1
979
+ </Providers>
980
+ );`);
981
+ }
982
+ injectRemixProvider(content) {
983
+ if (content.includes('HumanBehaviorProvider')) {
984
+ return content;
985
+ }
986
+ const importStatement = `import { HumanBehaviorProvider, createHumanBehaviorLoader } from 'humanbehavior-js/remix';`;
987
+ const useLoaderDataImport = `import { useLoaderData } from "@remix-run/react";`;
988
+ // Add imports more robustly
989
+ let modifiedContent = content;
990
+ // Add HumanBehaviorProvider import - find the last import and add after it
991
+ if (!content.includes('HumanBehaviorProvider')) {
992
+ const lastImportIndex = modifiedContent.lastIndexOf('import');
993
+ if (lastImportIndex !== -1) {
994
+ const nextLineIndex = modifiedContent.indexOf('\n', lastImportIndex);
995
+ if (nextLineIndex !== -1) {
996
+ modifiedContent = modifiedContent.slice(0, nextLineIndex + 1) +
997
+ importStatement + '\n' +
998
+ modifiedContent.slice(nextLineIndex + 1);
999
+ }
1000
+ else {
1001
+ modifiedContent = modifiedContent + '\n' + importStatement;
1002
+ }
1003
+ }
1004
+ else {
1005
+ modifiedContent = importStatement + '\n' + modifiedContent;
1006
+ }
1007
+ }
1008
+ // Add useLoaderData import - find the last import and add after it
1009
+ if (!content.includes('useLoaderData')) {
1010
+ const lastImportIndex = modifiedContent.lastIndexOf('import');
1011
+ if (lastImportIndex !== -1) {
1012
+ const nextLineIndex = modifiedContent.indexOf('\n', lastImportIndex);
1013
+ if (nextLineIndex !== -1) {
1014
+ modifiedContent = modifiedContent.slice(0, nextLineIndex + 1) +
1015
+ useLoaderDataImport + '\n' +
1016
+ modifiedContent.slice(nextLineIndex + 1);
1017
+ }
1018
+ else {
1019
+ modifiedContent = modifiedContent + '\n' + useLoaderDataImport;
1020
+ }
1021
+ }
1022
+ else {
1023
+ modifiedContent = useLoaderDataImport + '\n' + modifiedContent;
1024
+ }
1025
+ }
1026
+ // Add loader function before the App component
1027
+ if (!content.includes('export const loader')) {
1028
+ modifiedContent = modifiedContent.replace(/export default function App\(\)/, `export const loader = createHumanBehaviorLoader();
1029
+
1030
+ export default function App()`);
1031
+ }
1032
+ // Wrap the App component content with HumanBehaviorProvider
1033
+ modifiedContent = modifiedContent.replace(/export default function App\(\) \{[\s\S]*?return \(([\s\S]*?)\);[\s\S]*?\}/, `export default function App() {
1034
+ const data = useLoaderData<typeof loader>();
1035
+
1036
+ return (
1037
+ <HumanBehaviorProvider apiKey={data.ENV.HUMANBEHAVIOR_API_KEY}>
1038
+ $1
1039
+ </HumanBehaviorProvider>
1040
+ );
1041
+ }`);
1042
+ return modifiedContent;
1043
+ }
1044
+ injectVuePlugin(content) {
1045
+ var _a, _b;
1046
+ if (content.includes('HumanBehaviorPlugin')) {
1047
+ return content;
1048
+ }
1049
+ const importStatement = `import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';`;
1050
+ // Enhanced Vue 3 support with version detection
1051
+ const hasVue3 = (_b = (_a = this.framework) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.hasVue3;
1052
+ if (hasVue3) {
1053
+ // Vue 3 with Composition API
1054
+ const pluginUsage = `app.use(HumanBehaviorPlugin, {
1055
+ apiKey: import.meta.env.VITE_HUMANBEHAVIOR_API_KEY
1056
+ });`;
1057
+ let modifiedContent = content;
1058
+ // Add import statement
1059
+ if (!content.includes(importStatement)) {
1060
+ modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
1061
+ // If no Vue import found, add it at the top
1062
+ if (!modifiedContent.includes(importStatement)) {
1063
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1064
+ }
1065
+ }
1066
+ // Handle createApp pattern
1067
+ if (content.includes('createApp')) {
1068
+ modifiedContent = modifiedContent.replace(/(app\.mount\(.*?\))/, `${pluginUsage}\n\n$1`);
1069
+ }
1070
+ return modifiedContent;
1071
+ }
1072
+ else {
1073
+ // Vue 2 with Options API
1074
+ const pluginUsage = `Vue.use(HumanBehaviorPlugin, {
1075
+ apiKey: process.env.VUE_APP_HUMANBEHAVIOR_API_KEY
1076
+ });`;
1077
+ let modifiedContent = content;
1078
+ // Add import statement
1079
+ if (!content.includes(importStatement)) {
1080
+ modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
1081
+ if (!modifiedContent.includes(importStatement)) {
1082
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1083
+ }
1084
+ }
1085
+ // Handle new Vue pattern
1086
+ if (content.includes('new Vue')) {
1087
+ modifiedContent = modifiedContent.replace(/(new Vue\(.*?\))/, `${pluginUsage}\n\n$1`);
1088
+ }
1089
+ return modifiedContent;
1090
+ }
1091
+ }
1092
+ injectAngularModule(content) {
1093
+ if (content.includes('HumanBehaviorModule')) {
1094
+ return content;
1095
+ }
1096
+ const importStatement = `import { HumanBehaviorModule } from 'humanbehavior-js/angular';`;
1097
+ const environmentImport = `import { environment } from '../environments/environment';`;
1098
+ // Add environment import if not present
1099
+ let modifiedContent = content;
1100
+ if (!content.includes('environment')) {
1101
+ modifiedContent = content.replace(/import.*from.*['"]@angular/, `${environmentImport}\n$&`);
1102
+ }
1103
+ return modifiedContent.replace(/imports:\s*\[([\s\S]*?)\]/, `imports: [
1104
+ $1,
1105
+ HumanBehaviorModule.forRoot({
1106
+ apiKey: environment.humanBehaviorApiKey
1107
+ })
1108
+ ]`).replace(/import.*from.*['"]@angular/, `$&\n${importStatement}`);
1109
+ }
1110
+ injectAngularStandaloneInit(content) {
1111
+ if (content.includes('initializeHumanBehavior')) {
1112
+ return content;
1113
+ }
1114
+ const importStatement = `import { initializeHumanBehavior } from 'humanbehavior-js/angular';`;
1115
+ // Add import at the top
1116
+ let modifiedContent = content.replace(/import.*from.*['"]@angular/, `${importStatement}\n$&`);
1117
+ // Add initialization after bootstrapApplication
1118
+ modifiedContent = modifiedContent.replace(/(bootstrapApplication\([^}]+\}?\)(?:\s*\.catch[^;]+;)?)/, `$1
1119
+
1120
+ // Initialize HumanBehavior SDK (client-side only)
1121
+ if (typeof window !== 'undefined') {
1122
+ const tracker = initializeHumanBehavior(
1123
+ '${this.apiKey}'
1124
+ );
1125
+ }`);
1126
+ return modifiedContent;
1127
+ }
1128
+ injectSvelteStore(content) {
1129
+ if (content.includes('humanBehaviorStore')) {
1130
+ return content;
1131
+ }
1132
+ const importStatement = `import { humanBehaviorStore } from 'humanbehavior-js/svelte';`;
1133
+ const initCode = `humanBehaviorStore.init(process.env.PUBLIC_HUMANBEHAVIOR_API_KEY || '');`;
1134
+ return `${importStatement}\n${initCode}\n\n${content}`;
1135
+ }
1136
+ injectSvelteKitLayout(content) {
1137
+ if (content.includes('humanBehaviorStore')) {
1138
+ return content;
1139
+ }
1140
+ const importStatement = `import { humanBehaviorStore } from 'humanbehavior-js/svelte';`;
1141
+ const envImport = `import { PUBLIC_HUMANBEHAVIOR_API_KEY } from '$env/static/public';`;
1142
+ const initCode = `humanBehaviorStore.init(PUBLIC_HUMANBEHAVIOR_API_KEY || '');`;
1143
+ // Add to script section - handle different script tag patterns
1144
+ if (content.includes('<script lang="ts">')) {
1145
+ return content.replace(/<script lang="ts">/, `<script lang="ts">\n\t${envImport}\n\t${importStatement}\n\t${initCode}`);
1146
+ }
1147
+ else if (content.includes('<script>')) {
1148
+ return content.replace(/<script>/, `<script>\n\t${envImport}\n\t${importStatement}\n\t${initCode}`);
1149
+ }
1150
+ else if (content.includes('<script context="module">')) {
1151
+ return content.replace(/<script\s+context="module">/, `<script context="module">\n\t${envImport}\n\t${importStatement}\n\t${initCode}`);
1152
+ }
1153
+ else {
1154
+ // If no script tag found, add one at the beginning
1155
+ return content.replace(/<svelte:head>/, `<script lang="ts">\n\t${envImport}\n\t${importStatement}\n\t${initCode}\n</script>\n\n<svelte:head>`);
1156
+ }
1157
+ }
1158
+ injectVanillaScript(content) {
1159
+ if (content.includes('humanbehavior-js')) {
1160
+ return content;
1161
+ }
1162
+ const cdnScript = `<script src="https://unpkg.com/humanbehavior-js@latest/dist/index.min.js"></script>`;
1163
+ const initScript = `<script>
1164
+ // Initialize HumanBehavior SDK
1165
+ // Note: For vanilla HTML, the API key must be hardcoded since env vars aren't available
1166
+ const tracker = HumanBehaviorTracker.init('${this.apiKey}');
1167
+ </script>`;
1168
+ return content.replace(/<\/head>/, ` ${cdnScript}\n ${initScript}\n</head>`);
1169
+ }
1170
+ /**
1171
+ * Inject Astro layout with HumanBehavior component
1172
+ */
1173
+ injectAstroLayout(content) {
1174
+ // Check if HumanBehavior component is already imported
1175
+ if (content.includes('HumanBehavior') || content.includes('humanbehavior-js')) {
1176
+ return content; // Already has HumanBehavior
1177
+ }
1178
+ // Add import inside frontmatter if not present
1179
+ let modifiedContent = content;
1180
+ if (!content.includes('import HumanBehavior')) {
1181
+ const importStatement = 'import HumanBehavior from \'../components/HumanBehavior.astro\';';
1182
+ const frontmatterEndIndex = content.indexOf('---', 3);
1183
+ if (frontmatterEndIndex !== -1) {
1184
+ // Insert import inside frontmatter, before the closing ---
1185
+ modifiedContent = content.slice(0, frontmatterEndIndex) + '\n' + importStatement + '\n' + content.slice(frontmatterEndIndex);
1186
+ }
1187
+ else {
1188
+ // No frontmatter, add at the very beginning
1189
+ modifiedContent = '---\n' + importStatement + '\n---\n\n' + content;
1190
+ }
1191
+ }
1192
+ // Find the closing </body> tag and add HumanBehavior component before it
1193
+ const bodyCloseIndex = modifiedContent.lastIndexOf('</body>');
1194
+ if (bodyCloseIndex === -1) {
1195
+ // No body tag found, append to end
1196
+ return modifiedContent + '\n\n<HumanBehavior />';
1197
+ }
1198
+ // Add component before closing body tag
1199
+ return modifiedContent.slice(0, bodyCloseIndex) + ' <HumanBehavior />\n' + modifiedContent.slice(bodyCloseIndex);
1200
+ }
1201
+ injectNuxtConfig(content) {
1202
+ var _a, _b;
1203
+ if (content.includes('humanBehaviorApiKey')) {
1204
+ return content;
1205
+ }
1206
+ // Enhanced Nuxt 3 support with version detection
1207
+ const hasNuxt3 = (_b = (_a = this.framework) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.hasNuxt3;
1208
+ if (hasNuxt3) {
1209
+ // Nuxt 3 with runtime config
1210
+ return content.replace(/export default defineNuxtConfig\(\{/, `export default defineNuxtConfig({
1211
+ runtimeConfig: {
1212
+ public: {
1213
+ humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY
1214
+ }
1215
+ },`);
1216
+ }
1217
+ else {
1218
+ // Nuxt 2 with env config
1219
+ return content.replace(/export default \{/, `export default {
1220
+ env: {
1221
+ humanBehaviorApiKey: process.env.HUMANBEHAVIOR_API_KEY
1222
+ },`);
1223
+ }
1224
+ }
1225
+ injectGatsbyLayout(content) {
1226
+ if (content.includes('HumanBehavior')) {
1227
+ return content;
1228
+ }
1229
+ const importStatement = `import HumanBehavior from './HumanBehavior';`;
1230
+ const componentUsage = `<HumanBehavior apiKey={process.env.GATSBY_HUMANBEHAVIOR_API_KEY || ''} />`;
1231
+ // Add import at the top
1232
+ let modifiedContent = content.replace(/import.*from.*['"]\./, `${importStatement}\n$&`);
1233
+ // Add component before closing body tag
1234
+ modifiedContent = modifiedContent.replace(/(\s*<\/body>)/, `\n ${componentUsage}\n$1`);
1235
+ return modifiedContent;
1236
+ }
1237
+ injectGatsbyBrowser(content) {
1238
+ if (content.includes('HumanBehaviorTracker')) {
1239
+ return content;
1240
+ }
1241
+ const importStatement = `import { HumanBehaviorTracker } from 'humanbehavior-js';`;
1242
+ const initCode = `
1243
+ // Initialize HumanBehavior SDK
1244
+ export const onClientEntry = () => {
1245
+ console.log('Gatsby browser entry point loaded');
1246
+ const apiKey = process.env.GATSBY_HUMANBEHAVIOR_API_KEY;
1247
+ console.log('API Key found:', apiKey ? 'Yes' : 'No');
1248
+ if (apiKey) {
1249
+ const tracker = HumanBehaviorTracker.init(apiKey);
1250
+ console.log('HumanBehavior SDK initialized for Gatsby');
1251
+ } else {
1252
+ console.log('No API key found in environment variables');
1253
+ }
1254
+ };`;
1255
+ // If the file already has content, add the import and init code
1256
+ if (content.trim()) {
1257
+ return `${importStatement}${initCode}\n\n${content}`;
1258
+ }
1259
+ else {
1260
+ // If file is empty, just return the new content
1261
+ return `${importStatement}${initCode}`;
1262
+ }
1263
+ }
1264
+ /**
1265
+ * Helper method to find the best environment file for a framework
1266
+ */
1267
+ findBestEnvFile(framework) {
1268
+ const possibleEnvFiles = [
1269
+ '.env.local',
1270
+ '.env.development.local',
1271
+ '.env.development',
1272
+ '.env.local.development',
1273
+ '.env',
1274
+ '.env.production',
1275
+ '.env.staging'
1276
+ ];
1277
+ // Framework-specific environment variable names
1278
+ const getEnvVarName = (framework) => {
1279
+ // Handle React+Vite specifically
1280
+ if (framework.type === 'react' && framework.bundler === 'vite') {
1281
+ return 'VITE_HUMANBEHAVIOR_API_KEY';
1282
+ }
1283
+ // Framework-specific mappings
1284
+ const envVarNames = {
1285
+ react: 'HUMANBEHAVIOR_API_KEY',
1286
+ nextjs: 'NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1287
+ vue: 'VITE_HUMANBEHAVIOR_API_KEY',
1288
+ svelte: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1289
+ angular: 'HUMANBEHAVIOR_API_KEY',
1290
+ nuxt: 'NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY',
1291
+ remix: 'HUMANBEHAVIOR_API_KEY',
1292
+ vanilla: 'HUMANBEHAVIOR_API_KEY',
1293
+ astro: 'PUBLIC_HUMANBEHAVIOR_API_KEY',
1294
+ gatsby: 'GATSBY_HUMANBEHAVIOR_API_KEY',
1295
+ node: 'HUMANBEHAVIOR_API_KEY',
1296
+ auto: 'HUMANBEHAVIOR_API_KEY'
1297
+ };
1298
+ return envVarNames[framework.type] || 'HUMANBEHAVIOR_API_KEY';
1299
+ };
1300
+ const envVarName = getEnvVarName(framework);
1301
+ // Check for existing files
1302
+ for (const envFile of possibleEnvFiles) {
1303
+ const fullPath = path__namespace.join(this.projectRoot, envFile);
1304
+ if (fs__namespace.existsSync(fullPath)) {
1305
+ return { filePath: fullPath, envVarName };
1306
+ }
1307
+ }
1308
+ // Framework-specific default file creation
1309
+ const defaultFiles = {
1310
+ react: '.env.local',
1311
+ nextjs: '.env.local',
1312
+ vue: '.env.local',
1313
+ svelte: '.env',
1314
+ angular: '.env',
1315
+ nuxt: '.env',
1316
+ remix: '.env.local',
1317
+ vanilla: '.env',
1318
+ astro: '.env',
1319
+ gatsby: '.env.development',
1320
+ node: '.env',
1321
+ auto: '.env'
1322
+ };
1323
+ const defaultFile = defaultFiles[framework.type] || '.env';
1324
+ return {
1325
+ filePath: path__namespace.join(this.projectRoot, defaultFile),
1326
+ envVarName
1327
+ };
1328
+ }
1329
+ /**
1330
+ * Helper method to create or append to environment files
1331
+ */
1332
+ createEnvironmentModification(framework) {
1333
+ const { filePath, envVarName } = this.findBestEnvFile(framework);
1334
+ // Clean the API key to prevent formatting issues
1335
+ const cleanApiKey = this.apiKey.trim();
1336
+ if (fs__namespace.existsSync(filePath)) {
1337
+ // Check if the variable already exists
1338
+ const content = fs__namespace.readFileSync(filePath, 'utf8');
1339
+ if (content.includes(envVarName)) {
1340
+ // Variable exists, don't modify
1341
+ return {
1342
+ filePath,
1343
+ action: 'modify',
1344
+ content: content, // No change
1345
+ description: `API key already exists in ${path__namespace.basename(filePath)}`
1346
+ };
1347
+ }
1348
+ else {
1349
+ // Append to existing file
1350
+ return {
1351
+ filePath,
1352
+ action: 'append',
1353
+ content: `\n${envVarName}=${cleanApiKey}`,
1354
+ description: `Added API key to existing ${path__namespace.basename(filePath)}`
1355
+ };
1356
+ }
1357
+ }
1358
+ else {
1359
+ // Create new file
1360
+ return {
1361
+ filePath,
1362
+ action: 'create',
1363
+ content: `${envVarName}=${cleanApiKey}`,
1364
+ description: `Created ${path__namespace.basename(filePath)} with API key`
1365
+ };
1366
+ }
1367
+ }
1368
+ }
1369
+ /**
1370
+ * Browser-based auto-installation wizard
1371
+ */
1372
+ class BrowserAutoInstallationWizard {
1373
+ constructor(apiKey) {
1374
+ this.apiKey = apiKey;
1375
+ }
1376
+ install() {
1377
+ return __awaiter(this, void 0, void 0, function* () {
1378
+ try {
1379
+ // Detect framework in browser
1380
+ const framework = this.detectFramework();
1381
+ // Generate installation instructions
1382
+ const modifications = this.generateBrowserModifications(framework);
1383
+ return {
1384
+ success: true,
1385
+ framework,
1386
+ modifications,
1387
+ errors: [],
1388
+ nextSteps: [
1389
+ '✅ Framework detected automatically',
1390
+ '📋 Copy the generated code to your project',
1391
+ '🚀 Your app will be ready to track user behavior'
1392
+ ]
1393
+ };
1394
+ }
1395
+ catch (error) {
1396
+ return {
1397
+ success: false,
1398
+ framework: { name: 'unknown', type: 'vanilla' },
1399
+ modifications: [],
1400
+ errors: [error instanceof Error ? error.message : 'Unknown error'],
1401
+ nextSteps: []
1402
+ };
1403
+ }
1404
+ });
1405
+ }
1406
+ detectFramework() {
1407
+ if (typeof window !== 'undefined') {
1408
+ if (window.React) {
1409
+ return { name: 'react', type: 'react' };
1410
+ }
1411
+ if (window.Vue) {
1412
+ return { name: 'vue', type: 'vue' };
1413
+ }
1414
+ if (window.angular) {
1415
+ return { name: 'angular', type: 'angular' };
1416
+ }
1417
+ }
1418
+ return { name: 'vanilla', type: 'vanilla' };
1419
+ }
1420
+ generateBrowserModifications(framework) {
1421
+ // Return code snippets for browser environment
1422
+ const modifications = [];
1423
+ switch (framework.type) {
1424
+ case 'react':
1425
+ modifications.push({
1426
+ filePath: 'App.jsx',
1427
+ action: 'create',
1428
+ content: `import { HumanBehaviorProvider } from 'humanbehavior-js/react';
1429
+
1430
+ function App() {
1431
+ return (
1432
+ <HumanBehaviorProvider apiKey="${this.apiKey}">
1433
+ {/* Your app components */}
1434
+ </HumanBehaviorProvider>
1435
+ );
1436
+ }
1437
+
1438
+ export default App;`,
1439
+ description: 'React component with HumanBehaviorProvider'
1440
+ });
1441
+ break;
1442
+ case 'remix':
1443
+ modifications.push({
1444
+ filePath: 'app/root.tsx',
1445
+ action: 'create',
1446
+ content: `import {
1447
+ Links,
1448
+ Meta,
1449
+ Outlet,
1450
+ Scripts,
1451
+ ScrollRestoration,
1452
+ useLoaderData,
1453
+ } from "@remix-run/react";
1454
+ import { HumanBehaviorProvider } from 'humanbehavior-js/react';
1455
+ import type { LoaderFunctionArgs } from "@remix-run/node";
1456
+
1457
+ export async function loader({ request }: LoaderFunctionArgs) {
1458
+ return {
1459
+ ENV: {
1460
+ HUMANBEHAVIOR_API_KEY: process.env.HUMANBEHAVIOR_API_KEY,
1461
+ },
1462
+ };
1463
+ }
1464
+
1465
+ export function Layout({ children }: { children: React.ReactNode }) {
1466
+ return (
1467
+ <html lang="en">
1468
+ <head>
1469
+ <meta charSet="utf-8" />
1470
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1471
+ <Meta />
1472
+ <Links />
1473
+ </head>
1474
+ <body>
1475
+ {children}
1476
+ <ScrollRestoration />
1477
+ <Scripts />
1478
+ </body>
1479
+ </html>
1480
+ );
1481
+ }
1482
+
1483
+ export default function App() {
1484
+ const data = useLoaderData<typeof loader>();
1485
+
1486
+ return (
1487
+ <HumanBehaviorProvider apiKey={data.ENV.HUMANBEHAVIOR_API_KEY}>
1488
+ <div className="min-h-screen bg-gray-50">
1489
+ {/* Your app content */}
1490
+ <Outlet />
1491
+ </div>
1492
+ </HumanBehaviorProvider>
1493
+ );
1494
+ }`,
1495
+ description: 'Remix root component with HumanBehaviorProvider'
1496
+ });
1497
+ break;
1498
+ case 'vue':
1499
+ modifications.push({
1500
+ filePath: 'main.js',
1501
+ action: 'create',
1502
+ content: `import { createApp } from 'vue';
1503
+ import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';
1504
+ import App from './App.vue';
1505
+
1506
+ const app = createApp(App);
1507
+ app.use(HumanBehaviorPlugin, {
1508
+ apiKey: '${this.apiKey}'
1509
+ });
1510
+ app.mount('#app');`,
1511
+ description: 'Vue app with HumanBehaviorPlugin'
1512
+ });
1513
+ break;
1514
+ default:
1515
+ modifications.push({
1516
+ filePath: 'humanbehavior-init.js',
1517
+ action: 'create',
1518
+ content: `import { HumanBehaviorTracker } from 'humanbehavior-js';
1519
+
1520
+ const tracker = HumanBehaviorTracker.init('${this.apiKey}');`,
1521
+ description: 'Vanilla JS initialization'
1522
+ });
1523
+ }
1524
+ return modifications;
1525
+ }
1526
+ }
1527
+
1528
+ exports.AutoInstallationWizard = AutoInstallationWizard;
1529
+ exports.BrowserAutoInstallationWizard = BrowserAutoInstallationWizard;
1530
+ //# sourceMappingURL=install-wizard.cjs.map