humanbehavior-js 0.4.14 → 0.4.16

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.
@@ -46,6 +46,28 @@ class AutoInstallationWizard {
46
46
  this.apiKey = apiKey;
47
47
  this.projectRoot = projectRoot;
48
48
  }
49
+ /**
50
+ * Simple version comparison utility
51
+ */
52
+ compareVersions(version1, version2) {
53
+ const v1Parts = version1.split('.').map(Number);
54
+ const v2Parts = version2.split('.').map(Number);
55
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
56
+ const v1 = v1Parts[i] || 0;
57
+ const v2 = v2Parts[i] || 0;
58
+ if (v1 > v2)
59
+ return 1;
60
+ if (v1 < v2)
61
+ return -1;
62
+ }
63
+ return 0;
64
+ }
65
+ isVersionGte(version, target) {
66
+ return this.compareVersions(version, target) >= 0;
67
+ }
68
+ getMajorVersion(version) {
69
+ return parseInt(version.split('.')[0]) || 0;
70
+ }
49
71
  /**
50
72
  * Main installation method - detects framework and auto-installs
51
73
  */
@@ -95,91 +117,146 @@ class AutoInstallationWizard {
95
117
  }
96
118
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
97
119
  const dependencies = Object.assign(Object.assign({}, packageJson.dependencies), packageJson.devDependencies);
98
- // Detect framework
120
+ // Detect framework with version information
99
121
  let framework = {
100
122
  name: 'vanilla',
101
123
  type: 'vanilla',
102
- projectRoot: this.projectRoot
124
+ projectRoot: this.projectRoot,
125
+ features: {}
103
126
  };
104
127
  if (dependencies.nuxt) {
128
+ const nuxtVersion = dependencies.nuxt;
129
+ const isNuxt3 = this.isVersionGte(nuxtVersion, '3.0.0');
105
130
  framework = {
106
131
  name: 'nuxt',
107
132
  type: 'nuxt',
133
+ version: nuxtVersion,
134
+ majorVersion: this.getMajorVersion(nuxtVersion),
108
135
  hasTypeScript: !!dependencies.typescript,
109
136
  hasRouter: true,
110
- projectRoot: this.projectRoot
137
+ projectRoot: this.projectRoot,
138
+ features: {
139
+ hasNuxt3: isNuxt3
140
+ }
111
141
  };
112
142
  }
113
143
  else if (dependencies.next) {
144
+ const nextVersion = dependencies.next;
145
+ const isNext13 = this.isVersionGte(nextVersion, '13.0.0');
114
146
  framework = {
115
147
  name: 'nextjs',
116
148
  type: 'nextjs',
149
+ version: nextVersion,
150
+ majorVersion: this.getMajorVersion(nextVersion),
117
151
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/node'],
118
152
  hasRouter: true,
119
- projectRoot: this.projectRoot
153
+ projectRoot: this.projectRoot,
154
+ features: {
155
+ hasNextAppRouter: isNext13
156
+ }
120
157
  };
121
158
  }
122
159
  else if (dependencies['@remix-run/react'] || dependencies['@remix-run/dev']) {
160
+ const remixVersion = dependencies['@remix-run/react'] || dependencies['@remix-run/dev'];
123
161
  framework = {
124
162
  name: 'remix',
125
163
  type: 'remix',
164
+ version: remixVersion,
165
+ majorVersion: this.getMajorVersion(remixVersion),
126
166
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
127
167
  hasRouter: true,
128
- projectRoot: this.projectRoot
168
+ projectRoot: this.projectRoot,
169
+ features: {}
129
170
  };
130
171
  }
131
172
  else if (dependencies.react) {
173
+ const reactVersion = dependencies.react;
174
+ const isReact18 = this.isVersionGte(reactVersion, '18.0.0');
132
175
  framework = {
133
176
  name: 'react',
134
177
  type: 'react',
178
+ version: reactVersion,
179
+ majorVersion: this.getMajorVersion(reactVersion),
135
180
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
136
181
  hasRouter: !!dependencies['react-router-dom'] || !!dependencies['react-router'],
137
- projectRoot: this.projectRoot
182
+ projectRoot: this.projectRoot,
183
+ features: {
184
+ hasReact18: isReact18
185
+ }
138
186
  };
139
187
  }
140
188
  else if (dependencies.vue) {
189
+ const vueVersion = dependencies.vue;
190
+ const isVue3 = this.isVersionGte(vueVersion, '3.0.0');
141
191
  framework = {
142
192
  name: 'vue',
143
193
  type: 'vue',
194
+ version: vueVersion,
195
+ majorVersion: this.getMajorVersion(vueVersion),
144
196
  hasTypeScript: !!dependencies.typescript || !!dependencies['@vue/cli-service'],
145
197
  hasRouter: !!dependencies['vue-router'],
146
- projectRoot: this.projectRoot
198
+ projectRoot: this.projectRoot,
199
+ features: {
200
+ hasVue3: isVue3
201
+ }
147
202
  };
148
203
  }
149
204
  else if (dependencies['@angular/core']) {
205
+ const angularVersion = dependencies['@angular/core'];
206
+ const isAngular17 = this.isVersionGte(angularVersion, '17.0.0');
150
207
  framework = {
151
208
  name: 'angular',
152
209
  type: 'angular',
210
+ version: angularVersion,
211
+ majorVersion: this.getMajorVersion(angularVersion),
153
212
  hasTypeScript: true,
154
213
  hasRouter: true,
155
- projectRoot: this.projectRoot
214
+ projectRoot: this.projectRoot,
215
+ features: {
216
+ hasAngularStandalone: isAngular17
217
+ }
156
218
  };
157
219
  }
158
220
  else if (dependencies.svelte) {
221
+ const svelteVersion = dependencies.svelte;
222
+ const isSvelteKit = !!dependencies['@sveltejs/kit'];
159
223
  framework = {
160
224
  name: 'svelte',
161
225
  type: 'svelte',
226
+ version: svelteVersion,
227
+ majorVersion: this.getMajorVersion(svelteVersion),
162
228
  hasTypeScript: !!dependencies.typescript || !!dependencies['svelte-check'],
163
229
  hasRouter: !!dependencies['svelte-routing'] || !!dependencies['@sveltejs/kit'],
164
- projectRoot: this.projectRoot
230
+ projectRoot: this.projectRoot,
231
+ features: {
232
+ hasSvelteKit: isSvelteKit
233
+ }
165
234
  };
166
235
  }
167
236
  else if (dependencies.astro) {
237
+ const astroVersion = dependencies.astro;
168
238
  framework = {
169
239
  name: 'astro',
170
240
  type: 'astro',
241
+ version: astroVersion,
242
+ majorVersion: this.getMajorVersion(astroVersion),
171
243
  hasTypeScript: !!dependencies.typescript || !!dependencies['@astrojs/ts-plugin'],
172
244
  hasRouter: true,
173
- projectRoot: this.projectRoot
245
+ projectRoot: this.projectRoot,
246
+ features: {}
174
247
  };
175
248
  }
176
249
  else if (dependencies.gatsby) {
250
+ const gatsbyVersion = dependencies.gatsby;
177
251
  framework = {
178
252
  name: 'gatsby',
179
253
  type: 'gatsby',
254
+ version: gatsbyVersion,
255
+ majorVersion: this.getMajorVersion(gatsbyVersion),
180
256
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
181
257
  hasRouter: true,
182
- projectRoot: this.projectRoot
258
+ projectRoot: this.projectRoot,
259
+ features: {}
183
260
  };
184
261
  }
185
262
  // Detect bundler
@@ -803,7 +880,7 @@ export const onClientEntry = () => {
803
880
  return null;
804
881
  }
805
882
  injectReactProvider(content, filePath) {
806
- var _a;
883
+ var _a, _b, _c;
807
884
  filePath.endsWith('.tsx') || filePath.endsWith('.ts');
808
885
  // Check if already has HumanBehaviorProvider
809
886
  if (content.includes('HumanBehaviorProvider')) {
@@ -815,14 +892,39 @@ export const onClientEntry = () => {
815
892
  ? 'import.meta.env.VITE_HUMANBEHAVIOR_API_KEY!'
816
893
  : 'process.env.HUMANBEHAVIOR_API_KEY!';
817
894
  const importStatement = `import { HumanBehaviorProvider } from 'humanbehavior-js/react';`;
818
- // Simple injection - in production, you'd want more sophisticated parsing
895
+ // Enhanced parsing for React 18+ features
896
+ const hasReact18 = (_c = (_b = this.framework) === null || _b === void 0 ? void 0 : _b.features) === null || _c === void 0 ? void 0 : _c.hasReact18;
897
+ // Handle different React patterns
819
898
  if (content.includes('function App()') || content.includes('const App =')) {
820
- return content.replace(/(function App\(\)|const App =)/, `${importStatement}\n\n$1`).replace(/return \(([\s\S]*?)\);/, `return (
899
+ // Add import statement
900
+ let modifiedContent = content.replace(/(import.*?from.*?['"]react['"];?)/, `$1\n${importStatement}`);
901
+ // If no React import found, add it at the top
902
+ if (!modifiedContent.includes(importStatement)) {
903
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
904
+ }
905
+ // Wrap the App component return with HumanBehaviorProvider
906
+ modifiedContent = modifiedContent.replace(/(return\s*\([\s\S]*?\)\s*;)/, `return (
907
+ <HumanBehaviorProvider apiKey={${envVar}}>
908
+ $1
909
+ </HumanBehaviorProvider>
910
+ );`);
911
+ return modifiedContent;
912
+ }
913
+ // Handle React 18+ createRoot pattern
914
+ if (hasReact18 && content.includes('createRoot')) {
915
+ let modifiedContent = content.replace(/(import.*?from.*?['"]react['"];?)/, `$1\n${importStatement}`);
916
+ if (!modifiedContent.includes(importStatement)) {
917
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
918
+ }
919
+ // Wrap the root render with HumanBehaviorProvider
920
+ modifiedContent = modifiedContent.replace(/(root\.render\s*\([\s\S]*?\)\s*;)/, `root.render(
821
921
  <HumanBehaviorProvider apiKey={${envVar}}>
822
922
  $1
823
923
  </HumanBehaviorProvider>
824
924
  );`);
925
+ return modifiedContent;
825
926
  }
927
+ // Fallback: simple injection
826
928
  return `${importStatement}\n\n${content}`;
827
929
  }
828
930
  injectNextJSAppRouter(content) {
@@ -919,21 +1021,51 @@ export default function App()`);
919
1021
  return modifiedContent;
920
1022
  }
921
1023
  injectVuePlugin(content) {
1024
+ var _a, _b;
922
1025
  if (content.includes('HumanBehaviorPlugin')) {
923
1026
  return content;
924
1027
  }
925
1028
  const importStatement = `import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';`;
926
- const pluginUsage = `app.use(HumanBehaviorPlugin, {
1029
+ // Enhanced Vue 3 support with version detection
1030
+ const hasVue3 = (_b = (_a = this.framework) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.hasVue3;
1031
+ if (hasVue3) {
1032
+ // Vue 3 with Composition API
1033
+ const pluginUsage = `app.use(HumanBehaviorPlugin, {
927
1034
  apiKey: import.meta.env.VITE_HUMANBEHAVIOR_API_KEY
928
1035
  });`;
929
- // Handle both Vue 2 and Vue 3 patterns
930
- if (content.includes('createApp')) {
931
- // Vue 3
932
- return content.replace(/import.*from.*['"]vue['"]/, `$&\n${importStatement}`).replace(/app\.mount\(/, `${pluginUsage}\n\napp.mount(`);
1036
+ let modifiedContent = content;
1037
+ // Add import statement
1038
+ if (!content.includes(importStatement)) {
1039
+ modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
1040
+ // If no Vue import found, add it at the top
1041
+ if (!modifiedContent.includes(importStatement)) {
1042
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1043
+ }
1044
+ }
1045
+ // Handle createApp pattern
1046
+ if (content.includes('createApp')) {
1047
+ modifiedContent = modifiedContent.replace(/(app\.mount\(.*?\))/, `${pluginUsage}\n\n$1`);
1048
+ }
1049
+ return modifiedContent;
933
1050
  }
934
1051
  else {
935
- // Vue 2
936
- return content.replace(/import.*from.*['"]vue['"]/, `$&\n${importStatement}`).replace(/new Vue\(/, `${pluginUsage}\n\nnew Vue(`);
1052
+ // Vue 2 with Options API
1053
+ const pluginUsage = `Vue.use(HumanBehaviorPlugin, {
1054
+ apiKey: process.env.VUE_APP_HUMANBEHAVIOR_API_KEY
1055
+ });`;
1056
+ let modifiedContent = content;
1057
+ // Add import statement
1058
+ if (!content.includes(importStatement)) {
1059
+ modifiedContent = content.replace(/(import.*?from.*?['"]vue['"];?)/, `$1\n${importStatement}`);
1060
+ if (!modifiedContent.includes(importStatement)) {
1061
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1062
+ }
1063
+ }
1064
+ // Handle new Vue pattern
1065
+ if (content.includes('new Vue')) {
1066
+ modifiedContent = modifiedContent.replace(/(new Vue\(.*?\))/, `${pluginUsage}\n\n$1`);
1067
+ }
1068
+ return modifiedContent;
937
1069
  }
938
1070
  }
939
1071
  injectAngularModule(content) {
@@ -1046,16 +1178,28 @@ if (typeof window !== 'undefined') {
1046
1178
  return modifiedContent.slice(0, bodyCloseIndex) + ' <HumanBehavior />\n' + modifiedContent.slice(bodyCloseIndex);
1047
1179
  }
1048
1180
  injectNuxtConfig(content) {
1181
+ var _a, _b;
1049
1182
  if (content.includes('humanBehaviorApiKey')) {
1050
1183
  return content;
1051
1184
  }
1052
- // Add runtime config by inserting it after the opening brace
1053
- return content.replace(/export default defineNuxtConfig\(\{/, `export default defineNuxtConfig({
1185
+ // Enhanced Nuxt 3 support with version detection
1186
+ const hasNuxt3 = (_b = (_a = this.framework) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.hasNuxt3;
1187
+ if (hasNuxt3) {
1188
+ // Nuxt 3 with runtime config
1189
+ return content.replace(/export default defineNuxtConfig\(\{/, `export default defineNuxtConfig({
1054
1190
  runtimeConfig: {
1055
1191
  public: {
1056
1192
  humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY
1057
1193
  }
1058
1194
  },`);
1195
+ }
1196
+ else {
1197
+ // Nuxt 2 with env config
1198
+ return content.replace(/export default \{/, `export default {
1199
+ env: {
1200
+ humanBehaviorApiKey: process.env.HUMANBEHAVIOR_API_KEY
1201
+ },`);
1202
+ }
1059
1203
  }
1060
1204
  injectGatsbyLayout(content) {
1061
1205
  if (content.includes('HumanBehavior')) {