@keak/sdk 1.0.1

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/README.md +131 -0
  2. package/dist/Conversion.d.ts +13 -0
  3. package/dist/Conversion.d.ts.map +1 -0
  4. package/dist/KeakToolbarShadow.d.ts +21 -0
  5. package/dist/KeakToolbarShadow.d.ts.map +1 -0
  6. package/dist/components/ui/card.d.ts +9 -0
  7. package/dist/components/ui/card.d.ts.map +1 -0
  8. package/dist/components/ui/html-preview.d.ts +9 -0
  9. package/dist/components/ui/html-preview.d.ts.map +1 -0
  10. package/dist/components/ui/simple-tabs.d.ts +26 -0
  11. package/dist/components/ui/simple-tabs.d.ts.map +1 -0
  12. package/dist/components/ui/spinner.d.ts +6 -0
  13. package/dist/components/ui/spinner.d.ts.map +1 -0
  14. package/dist/components/ui/tabs.d.ts +13 -0
  15. package/dist/components/ui/tabs.d.ts.map +1 -0
  16. package/dist/components/ui/textarea.d.ts +6 -0
  17. package/dist/components/ui/textarea.d.ts.map +1 -0
  18. package/dist/index.cjs.js +17407 -0
  19. package/dist/index.cjs.js.map +1 -0
  20. package/dist/index.d.ts +101 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +17395 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/runtime/sourceInjector.d.ts +2 -0
  25. package/dist/runtime/sourceInjector.d.ts.map +1 -0
  26. package/dist/scripts/sourcePathInjection.d.ts +11 -0
  27. package/dist/scripts/sourcePathInjection.d.ts.map +1 -0
  28. package/dist/services/index.d.ts +7 -0
  29. package/dist/services/index.d.ts.map +1 -0
  30. package/dist/services/telemetry/index.d.ts +20 -0
  31. package/dist/services/telemetry/index.d.ts.map +1 -0
  32. package/dist/services/telemetry/telemetryService.d.ts +66 -0
  33. package/dist/services/telemetry/telemetryService.d.ts.map +1 -0
  34. package/dist/services/telemetry/types.d.ts +64 -0
  35. package/dist/services/telemetry/types.d.ts.map +1 -0
  36. package/dist/toolbar/AIPromptPanel.d.ts +9 -0
  37. package/dist/toolbar/AIPromptPanel.d.ts.map +1 -0
  38. package/dist/toolbar/ElementSelector.d.ts +8 -0
  39. package/dist/toolbar/ElementSelector.d.ts.map +1 -0
  40. package/dist/toolbar/ExperimentPanel.d.ts +9 -0
  41. package/dist/toolbar/ExperimentPanel.d.ts.map +1 -0
  42. package/dist/toolbar/KeakToolbar.d.ts +10 -0
  43. package/dist/toolbar/KeakToolbar.d.ts.map +1 -0
  44. package/dist/toolbar/MetricsPanel.d.ts +7 -0
  45. package/dist/toolbar/MetricsPanel.d.ts.map +1 -0
  46. package/dist/toolbar/PageScanPanel.d.ts +15 -0
  47. package/dist/toolbar/PageScanPanel.d.ts.map +1 -0
  48. package/dist/toolbar/components/PrimaryButton.d.ts +12 -0
  49. package/dist/toolbar/components/PrimaryButton.d.ts.map +1 -0
  50. package/dist/toolbar/components/WarningButton.d.ts +12 -0
  51. package/dist/toolbar/components/WarningButton.d.ts.map +1 -0
  52. package/dist/toolbar/components/icons/index.d.ts +13 -0
  53. package/dist/toolbar/components/icons/index.d.ts.map +1 -0
  54. package/dist/toolbar/components/ui/Badge.d.ts +10 -0
  55. package/dist/toolbar/components/ui/Badge.d.ts.map +1 -0
  56. package/dist/toolbar/components/ui/Button.d.ts +12 -0
  57. package/dist/toolbar/components/ui/Button.d.ts.map +1 -0
  58. package/dist/toolbar/components/ui/Progress.d.ts +5 -0
  59. package/dist/toolbar/components/ui/Progress.d.ts.map +1 -0
  60. package/dist/toolbar/components/ui/Tabs.d.ts +44 -0
  61. package/dist/toolbar/components/ui/Tabs.d.ts.map +1 -0
  62. package/dist/toolbar/components/ui/dropdown-menu.d.ts +28 -0
  63. package/dist/toolbar/components/ui/dropdown-menu.d.ts.map +1 -0
  64. package/dist/toolbar/lib/utils.d.ts +3 -0
  65. package/dist/toolbar/lib/utils.d.ts.map +1 -0
  66. package/dist/toolbar/utils/fiberSource.d.ts +64 -0
  67. package/dist/toolbar/utils/fiberSource.d.ts.map +1 -0
  68. package/dist/toolbar/utils/keakCodeClient.d.ts +104 -0
  69. package/dist/toolbar/utils/keakCodeClient.d.ts.map +1 -0
  70. package/dist/toolbar.css +1 -0
  71. package/dist/toolbar.js +1257 -0
  72. package/dist/toolbar.js.map +1 -0
  73. package/dist/utils/generateElementId.d.ts +44 -0
  74. package/dist/utils/generateElementId.d.ts.map +1 -0
  75. package/dist/utils/injectDataId.d.ts +33 -0
  76. package/dist/utils/injectDataId.d.ts.map +1 -0
  77. package/package.json +152 -0
  78. package/src/cli/ai-helper.js +206 -0
  79. package/src/cli/code-transformer.js +354 -0
  80. package/src/cli/conversion-detector.js +716 -0
  81. package/src/cli/framework-config.js +477 -0
  82. package/src/cli/install.js +618 -0
  83. package/src/cli/keak-setup.js +43 -0
  84. package/src/cli/revert-conversions.js +264 -0
  85. package/src/cli/safe-transformer.js +456 -0
  86. package/src/cli/simple-transformer.js +339 -0
  87. package/src/plugins/README.md +131 -0
  88. package/src/plugins/babel-source-inject.cjs +170 -0
  89. package/src/plugins/next.cjs +145 -0
@@ -0,0 +1,354 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ class CodeTransformer {
7
+ constructor() {
8
+ this.importAdded = false;
9
+ this.stats = {
10
+ filesProcessed: 0,
11
+ elementsWrapped: 0,
12
+ filesModified: 0
13
+ };
14
+ }
15
+
16
+ // Transform React/JSX files to wrap clickable elements with Conversion component
17
+ transformReactFile(content, filePath) {
18
+ let modified = content;
19
+ this.importAdded = false;
20
+
21
+ // Skip if file already has Conversion imports
22
+ if (content.includes('import') && content.includes('Conversion') && content.includes('keak-sdk')) {
23
+ return content;
24
+ }
25
+
26
+ // Patterns for clickable elements that should be wrapped
27
+ const clickablePatterns = [
28
+ // Button elements
29
+ {
30
+ pattern: /<button([^]*?)([\s\S]*?)<\/button/g,
31
+ type: 'button',
32
+ category: this.detectCategoryFromContent
33
+ },
34
+ // Link elements
35
+ {
36
+ pattern: /<a([^]*?)([\s\S]*?)<\/a/g,
37
+ type: 'link',
38
+ category: this.detectCategoryFromContent
39
+ },
40
+ // Input buttons (self-closing)
41
+ {
42
+ pattern: /<input([^]*?type=["'](?:button|submit)["'][^]*?)(\s*\/)/g,
43
+ type: 'button',
44
+ category: this.detectCategoryFromContent,
45
+ selfClosing: true
46
+ },
47
+ // Clickable divs/spans (with onClick)
48
+ {
49
+ pattern: /<(div|span)([^]*?onClick[^]*?)([\s\S]*?)<\/\1/g,
50
+ type: 'custom',
51
+ category: this.detectCategoryFromContent
52
+ }
53
+ ];
54
+
55
+ let elementsFound = 0;
56
+
57
+ // Transform each pattern
58
+ clickablePatterns.forEach(({ pattern, type, category, selfClosing }) => {
59
+ modified = modified.replace(pattern, (match, ...args) => {
60
+ // Skip if already wrapped with Conversion
61
+ if (match.includes('data-keak-conversion') ||
62
+ (match.toLowerCase().includes('<conversion') && match.toLowerCase().includes('</conversion'))) {
63
+ return match;
64
+ }
65
+
66
+ let attributes, content, elementType, selfClosingPart;
67
+
68
+ if (selfClosing) {
69
+ // For input elements: match, attributes, selfClosingPart
70
+ [, attributes, selfClosingPart] = args;
71
+ content = '';
72
+ elementType = 'input';
73
+ } else if (type === 'custom') {
74
+ // For div/span with onClick: match, elementType, attributes, content
75
+ [, elementType, attributes, content] = args;
76
+ } else {
77
+ // For button/a elements: match, attributes, content
78
+ [, attributes, content] = args;
79
+ elementType = type === 'button' ? 'button' : 'a';
80
+ }
81
+
82
+ // Skip form elements that might break functionality
83
+ if (attributes && (attributes.includes('type="hidden"') || attributes.includes('type="password"'))) {
84
+ return match;
85
+ }
86
+
87
+ elementsFound++;
88
+
89
+ // Mark that we found elements (import will be added later)
90
+ this.importAdded = true;
91
+
92
+ // Detect category from content and attributes
93
+ const detectedCategory = category(content || '', attributes || '');
94
+
95
+ // Build Conversion wrapper
96
+ const conversionProps = [
97
+ `type="${type}"`,
98
+ detectedCategory ? `category="${detectedCategory}"` : '',
99
+ // Add label from content for better tracking
100
+ content && content.trim() ? `label="${this.escapeJSX(this.extractTextContent(content))}"` : ''
101
+ ].filter(Boolean).join(' ');
102
+
103
+ if (selfClosing) {
104
+ // For self-closing elements like input
105
+ return `<input${attributes}${selfClosingPart}
106
+ `;
107
+ } else {
108
+ // For regular elements
109
+ return `<${elementType}${attributes}${content}</${elementType}`;
110
+ }
111
+ });
112
+ });
113
+
114
+ if (elementsFound 0) {
115
+ // Add the import at the top
116
+ modified = this.addImportToContent(modified);
117
+ this.stats.elementsWrapped += elementsFound;
118
+ this.stats.filesModified++;
119
+ }
120
+
121
+ return modified;
122
+ }
123
+
124
+ // Add import statement to the file content
125
+ addImportToContent(content) {
126
+ if (this.importAdded) return content;
127
+
128
+ const importStatement = "\n";
129
+
130
+ // Find the best place to add the import
131
+ const lines = content.split('\n');
132
+ let insertIndex = 0;
133
+
134
+ // Look for existing imports
135
+ for (let i = 0; i < lines.length; i++) {
136
+ const line = lines[i].trim();
137
+
138
+ // Skip comments and empty lines at the top
139
+ if (line.startsWith('//') || line.startsWith('/*') || line === '' || line.startsWith("'use client'") || line.startsWith('"use client"')) {
140
+ insertIndex = i + 1;
141
+ continue;
142
+ }
143
+
144
+ // If we find an import, set insert point after imports
145
+ if (line.startsWith('import ')) {
146
+ // Find the end of import block
147
+ while (i < lines.length && (lines[i].trim().startsWith('import ') || lines[i].trim() === '')) {
148
+ i++;
149
+ }
150
+ insertIndex = i;
151
+ break;
152
+ }
153
+
154
+ // If we find any other code, insert before it
155
+ if (line !== '') {
156
+ insertIndex = i;
157
+ break;
158
+ }
159
+ }
160
+
161
+ lines.splice(insertIndex, 0, importStatement);
162
+ this.importAdded = true;
163
+ return lines.join('\n');
164
+ }
165
+
166
+ // Detect conversion category from element content and attributes
167
+ detectCategoryFromContent(content, attributes) {
168
+ const text = (content + ' ' + attributes).toLowerCase();
169
+
170
+ if (/buy|purchase|checkout|order|cart|pay|billing/.test(text)) return 'purchase';
171
+ if (/sign.?up|register|join|create.?account/.test(text)) return 'signup';
172
+ if (/download|install|get.?app/.test(text)) return 'download';
173
+ if (/demo|trial|preview|try/.test(text)) return 'demo';
174
+ if (/contact|call|phone|support|help/.test(text)) return 'contact';
175
+ if (/learn.?more|read.?more|details|info/.test(text)) return 'engagement';
176
+ if (/subscribe|newsletter|updates/.test(text)) return 'subscription';
177
+
178
+ return 'interaction';
179
+ }
180
+
181
+ // Extract text content from JSX, removing tags
182
+ extractTextContent(jsx) {
183
+ return jsx
184
+ .replace(/<[^]*/g, ' ') // Remove HTML/JSX tags
185
+ .replace(/\s+/g, ' ') // Normalize whitespace
186
+ .trim()
187
+ .substring(0, 50); // Limit length
188
+ }
189
+
190
+ // Escape JSX string content
191
+ escapeJSX(str) {
192
+ return str
193
+ .replace(/"/g, '&quot;')
194
+ .replace(/'/g, '&#39;')
195
+ .replace(/</g, '&lt;')
196
+ .replace(//g, '&gt;');
197
+ }
198
+
199
+ // Process a single file
200
+ processFile(filePath) {
201
+ try {
202
+ const content = fs.readFileSync(filePath, 'utf-8');
203
+ const transformed = this.transformReactFile(content, filePath);
204
+
205
+ if (transformed !== content) {
206
+ // Create backup
207
+ const backupPath = `${filePath}.keak-backup`;
208
+ fs.writeFileSync(backupPath, content);
209
+
210
+ // Write transformed content
211
+ fs.writeFileSync(filePath, transformed);
212
+
213
+ return { success: true, modified: true, backup: backupPath };
214
+ }
215
+
216
+ return { success: true, modified: false };
217
+ } catch (error) {
218
+ return { success: false, error: error.message };
219
+ }
220
+ }
221
+
222
+ // Find all React/JSX files in a directory
223
+ findReactFiles(dir, extensions = ['.jsx', '.tsx', '.js', '.ts']) {
224
+ const files = [];
225
+
226
+ if (!fs.existsSync(dir)) return files;
227
+
228
+ const items = fs.readdirSync(dir);
229
+
230
+ for (const item of items) {
231
+ const fullPath = path.join(dir, item);
232
+
233
+ // Skip common directories
234
+ if (['node_modules', '.git', 'dist', 'build', '.next', 'coverage'].includes(item)) {
235
+ continue;
236
+ }
237
+
238
+ const stat = fs.statSync(fullPath);
239
+
240
+ if (stat.isDirectory()) {
241
+ files.push(...this.findReactFiles(fullPath, extensions));
242
+ } else if (extensions.some(ext =item.endsWith(ext))) {
243
+ // Check if file contains JSX/React content
244
+ try {
245
+ const content = fs.readFileSync(fullPath, 'utf-8');
246
+ if (this.isReactFile(content)) {
247
+ files.push(fullPath);
248
+ }
249
+ } catch (error) {
250
+ // Skip files that can't be read
251
+ }
252
+ }
253
+ }
254
+
255
+ return files;
256
+ }
257
+
258
+ // Check if file contains React/JSX content
259
+ isReactFile(content) {
260
+ return (
261
+ content.includes('import') && (
262
+ content.includes('react') ||
263
+ content.includes('React') ||
264
+ content.includes('<') && content.includes('') // JSX-like syntax
265
+ )
266
+ ) || content.includes('jsx') || content.includes('tsx');
267
+ }
268
+
269
+ // Process all React files in a directory
270
+ processDirectory(rootDir) {
271
+ console.log(`šŸ” Scanning for React files in ${rootDir}...`);
272
+
273
+ const reactFiles = this.findReactFiles(rootDir);
274
+ console.log(`šŸ“ Found ${reactFiles.length} React files`);
275
+
276
+ const results = [];
277
+
278
+ for (const filePath of reactFiles) {
279
+ console.log(`āš™ļø Processing ${path.relative(rootDir, filePath)}...`);
280
+
281
+ const result = this.processFile(filePath);
282
+ result.filePath = filePath;
283
+ results.push(result);
284
+
285
+ this.stats.filesProcessed++;
286
+
287
+ if (result.success && result.modified) {
288
+ console.log(`āœ… Modified ${path.relative(rootDir, filePath)}`);
289
+ if (result.backup) {
290
+ console.log(`šŸ“‹ Backup created: ${path.basename(result.backup)}`);
291
+ }
292
+ }
293
+ }
294
+
295
+ return results;
296
+ }
297
+
298
+ // Generate a summary report
299
+ generateReport() {
300
+ return {
301
+ summary: `
302
+ šŸŽÆ Conversion Tracking Integration Complete!
303
+
304
+ šŸ“Š Summary:
305
+ • Files processed: ${this.stats.filesProcessed}
306
+ • Files modified: ${this.stats.filesModified}
307
+ • Elements wrapped: ${this.stats.elementsWrapped}
308
+
309
+ āœ… All clickable elements have been automatically wrapped with components.
310
+ šŸ”„ Backup files created for all modified files (*.keak-backup)
311
+ šŸ“” Conversion telemetry is now active for all interactions.
312
+ `,
313
+ stats: this.stats
314
+ };
315
+ }
316
+ }
317
+
318
+ export default CodeTransformer;
319
+
320
+ // CLI execution
321
+ if (import.meta.url === `file://${process.argv[1]}`) {
322
+ const transformer = new CodeTransformer();
323
+ const targetDir = process.argv[2] || process.cwd();
324
+
325
+ console.log('šŸŽÆ Setting up automatic conversion tracking...\n');
326
+
327
+ const results = transformer.processDirectory(targetDir);
328
+ const report = transformer.generateReport();
329
+
330
+ console.log(report.summary);
331
+
332
+ // Show any errors
333
+ const errors = results.filter(r =!r.success);
334
+ if (errors.length 0) {
335
+ console.log('\nāš ļø Some files had issues:');
336
+ errors.forEach(error ={
337
+ console.log(`āŒ ${path.relative(targetDir, error.filePath)}: ${error.error}`);
338
+ });
339
+ }
340
+
341
+ if (report.stats.filesModified 0) {
342
+ console.log(`
343
+ šŸ”§ Next steps:
344
+ 1. Review the modified files
345
+ 2. Test your application to ensure everything works
346
+ 3. The components will automatically track all interactions
347
+ 4. Check your Keak dashboard for conversion analytics
348
+
349
+ šŸ’” To undo changes, restore from the .keak-backup files
350
+ `);
351
+ } else {
352
+ console.log('\n✨ No files needed modification. Your code is already optimized!');
353
+ }
354
+ }