humanbehavior-js 0.4.14 → 0.4.15

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