@mahe_pkm/buzl-capi 0.1.2 → 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.
- package/CHANGELOG.md +0 -16
- package/bin/cli.js +1 -2
- package/package.json +1 -1
- package/src/cli/terminal.js +4 -15
- package/src/core/scanner.js +2 -25
- package/src/core/tester.js +11 -19
- package/src/gui/public/app.js +10 -30
- package/src/gui/public/index.html +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -7,22 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## [0.1.2] - 2026-09-14
|
|
11
|
-
|
|
12
|
-
### Changed & Improved
|
|
13
|
-
- **100% Dynamic Test Lead Generation**:
|
|
14
|
-
- Removed all hardcoded mock client data (`9585950059`, `Sports Injury Rehabilitation`, `samya-sports-clinic`, `Bengaluru`, `Test Patient`).
|
|
15
|
-
- `tester.js`: `domain` dynamically resolves from `config.domain`, URL hostname, or folder name (`path.basename(rootDir)`).
|
|
16
|
-
- `tester.js`: `phone`, `service`, `location`, and `email` dynamically pull from detected website metadata and actual form fields with clean neutral fallbacks.
|
|
17
|
-
- `scanner.js`: Removed hardcoded `Bengaluru` fallback, dynamically extracts `detectedDomain` and `detectedService`.
|
|
18
|
-
- `app.js` & `index.html`: Web GUI test cards dynamically pre-fill phone, service, and location from live site scan results instead of static mock strings.
|
|
19
|
-
- `bin/cli.js`: CLI version output dynamically loads from `package.json`.
|
|
20
|
-
- **Enhanced Test Suite Resilience**:
|
|
21
|
-
- `multipage.test.js`: Added transient in-process HTTP mock server to guarantee 100% offline self-contained test execution.
|
|
22
|
-
- Added Test 13 in `injector.test.js` verifying dynamic test lead dispatch parameters.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
10
|
## [1.0.0] - 2026-09-14
|
|
27
11
|
|
|
28
12
|
### Initial Release
|
package/bin/cli.js
CHANGED
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
const path = require('path');
|
|
29
|
-
const pkg = require('../package.json');
|
|
30
29
|
const { runTerminalWizard } = require('../src/cli/terminal');
|
|
31
30
|
const { startGuiServer } = require('../src/gui/server');
|
|
32
31
|
const { restoreBackup, restoreLatestBackup, listBackups, manualBackup } = require('../src/core/rollback');
|
|
@@ -45,7 +44,7 @@ const rootDir = positionalArgs.length > 0 ? path.resolve(positionalArgs[0]) : pr
|
|
|
45
44
|
// ============================================================================
|
|
46
45
|
if (args.includes('--help') || args.includes('-h')) {
|
|
47
46
|
console.log(`
|
|
48
|
-
⚡ BUZL TRACKING & FORM DISPATCHER CLI (
|
|
47
|
+
⚡ BUZL TRACKING & FORM DISPATCHER CLI (v1.0.0)
|
|
49
48
|
|
|
50
49
|
USAGE:
|
|
51
50
|
$ npx buzl-tracker [dir] Launch interactive terminal wizard
|
package/package.json
CHANGED
package/src/cli/terminal.js
CHANGED
|
@@ -244,25 +244,14 @@ async function runTerminalWizard(rootDir) {
|
|
|
244
244
|
return;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
console.log(`\n Testing Form: ${colors.cyan(selectedForm.selector
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
const testPhone = (await askQuestion(rl, phonePrompt)).trim() || defaultPhone;
|
|
251
|
-
const testName = (await askQuestion(rl, ' Enter test name [Test Lead]: ')).trim() || 'Test Lead';
|
|
247
|
+
console.log(`\n Testing Form: ${colors.cyan(selectedForm.selector)}`);
|
|
248
|
+
const testPhone = (await askQuestion(rl, ' Enter test phone [9585950059]: ')).trim() || '9585950059';
|
|
249
|
+
const testName = (await askQuestion(rl, ' Enter test name [Buzl Test Lead]: ')).trim() || 'Buzl Test Lead';
|
|
252
250
|
|
|
253
251
|
const formFields = { phone: testPhone, name: testName, formId: selectedForm.formId };
|
|
254
252
|
selectedForm.inputs.forEach(inp => {
|
|
255
253
|
if (!formFields[inp.name]) {
|
|
256
|
-
|
|
257
|
-
if (lower.includes('service') || lower.includes('inquiry') || lower.includes('treatment') || lower.includes('subject')) {
|
|
258
|
-
formFields[inp.name] = selectedForm.formId || 'General Inquiry';
|
|
259
|
-
} else if (lower.includes('email') || lower.includes('mail')) {
|
|
260
|
-
formFields[inp.name] = 'test-lead@example.com';
|
|
261
|
-
} else if (lower.includes('city') || lower.includes('loc')) {
|
|
262
|
-
formFields[inp.name] = scan.detectedLocation || '';
|
|
263
|
-
} else {
|
|
264
|
-
formFields[inp.name] = 'Test Value';
|
|
265
|
-
}
|
|
254
|
+
formFields[inp.name] = inp.name.includes('service') ? 'Sports Injury Rehabilitation' : 'Test Value';
|
|
266
255
|
}
|
|
267
256
|
});
|
|
268
257
|
|
package/src/core/scanner.js
CHANGED
|
@@ -144,7 +144,7 @@ function detectSiteLocation(rootDir, htmlContent = '') {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
return '';
|
|
147
|
+
return 'Bengaluru';
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
/**
|
|
@@ -429,24 +429,6 @@ function scanProject(rootDir) {
|
|
|
429
429
|
return dir === '.' ? '/' : `/${dir}`;
|
|
430
430
|
}))).sort();
|
|
431
431
|
|
|
432
|
-
const cleanDirName = path.basename(rootDir).toLowerCase().replace(/[^a-z0-9_-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
433
|
-
const detectedDomain = cleanDirName || 'landing-page';
|
|
434
|
-
|
|
435
|
-
let detectedService = '';
|
|
436
|
-
for (const form of allDiscoveredForms) {
|
|
437
|
-
const sInput = (form.inputs || []).find(i => {
|
|
438
|
-
const lower = (i.name || '').toLowerCase();
|
|
439
|
-
return lower.includes('service') || lower.includes('inquiry') || lower.includes('treatment') || lower.includes('course') || lower.includes('department');
|
|
440
|
-
});
|
|
441
|
-
if (sInput) {
|
|
442
|
-
detectedService = form.id || form.selector || 'Website Inquiry';
|
|
443
|
-
break;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
if (!detectedService && allDiscoveredForms.length > 0) {
|
|
447
|
-
detectedService = allDiscoveredForms[0].id || 'General Inquiry';
|
|
448
|
-
}
|
|
449
|
-
|
|
450
432
|
const liveState = {
|
|
451
433
|
gtm: { active: !!gtmId, id: gtmId },
|
|
452
434
|
meta: { active: !!metaPixelId, id: metaPixelId },
|
|
@@ -462,9 +444,6 @@ function scanProject(rootDir) {
|
|
|
462
444
|
number: (waCfg && waCfg.number) || '',
|
|
463
445
|
detectedNumber: detectedWhatsapp || ''
|
|
464
446
|
},
|
|
465
|
-
detectedLocation: detectedLocation || '',
|
|
466
|
-
detectedDomain: detectedDomain,
|
|
467
|
-
detectedService: detectedService || 'General Inquiry',
|
|
468
447
|
forms: allDiscoveredForms,
|
|
469
448
|
formArchetypes: formArchetypes,
|
|
470
449
|
directories: directories,
|
|
@@ -486,10 +465,8 @@ function scanProject(rootDir) {
|
|
|
486
465
|
filesWithGtm,
|
|
487
466
|
filesWithMeta,
|
|
488
467
|
uniqueFields,
|
|
489
|
-
detectedLocation
|
|
468
|
+
detectedLocation,
|
|
490
469
|
detectedWhatsapp,
|
|
491
|
-
detectedDomain,
|
|
492
|
-
detectedService: detectedService || 'General Inquiry',
|
|
493
470
|
existingConfig,
|
|
494
471
|
liveState,
|
|
495
472
|
forms: allDiscoveredForms,
|
package/src/core/tester.js
CHANGED
|
@@ -140,11 +140,9 @@ async function runVerification(rootDir, htmlFiles, config) {
|
|
|
140
140
|
async function testDispatch(arg1, arg2 = {}, arg3 = {}) {
|
|
141
141
|
let config = arg1;
|
|
142
142
|
let sampleLead = arg2;
|
|
143
|
-
let rootDir = '';
|
|
144
143
|
|
|
145
144
|
// Polymorphic support: if called as (rootDir, config, sampleLead)
|
|
146
145
|
if (typeof arg1 === 'string' && typeof arg2 === 'object') {
|
|
147
|
-
rootDir = arg1;
|
|
148
146
|
config = arg2;
|
|
149
147
|
sampleLead = arg3;
|
|
150
148
|
}
|
|
@@ -152,10 +150,10 @@ async function testDispatch(arg1, arg2 = {}, arg3 = {}) {
|
|
|
152
150
|
if (!sampleLead) sampleLead = {};
|
|
153
151
|
|
|
154
152
|
const leadId = sampleLead.leadId || ('test-lead-' + Date.now());
|
|
155
|
-
const name = sampleLead.name || 'Test Lead';
|
|
156
|
-
const phone = sampleLead.phone ||
|
|
157
|
-
const location = sampleLead.location || config.siteLocation || '';
|
|
158
|
-
const service = sampleLead.service || 'General
|
|
153
|
+
const name = sampleLead.name || 'Buzl Test Lead';
|
|
154
|
+
const phone = sampleLead.phone || '9585950059';
|
|
155
|
+
const location = sampleLead.location || config.siteLocation || 'Bengaluru';
|
|
156
|
+
const service = sampleLead.service || 'General Consultation';
|
|
159
157
|
|
|
160
158
|
const results = {
|
|
161
159
|
leadId,
|
|
@@ -175,7 +173,7 @@ async function testDispatch(arg1, arg2 = {}, arg3 = {}) {
|
|
|
175
173
|
siteLocation: config.siteLocation || location,
|
|
176
174
|
phone: phone,
|
|
177
175
|
service: service,
|
|
178
|
-
email: sampleLead.email ||
|
|
176
|
+
email: sampleLead.email || 'test@gobuzl.com',
|
|
179
177
|
source: service,
|
|
180
178
|
utm: { source: 'live_test_button', medium: 'gui_test', campaign: 'buzl_verification' },
|
|
181
179
|
eventSourceUrl: sampleLead.eventSourceUrl || 'http://localhost:3333/test',
|
|
@@ -231,15 +229,9 @@ async function testDispatch(arg1, arg2 = {}, arg3 = {}) {
|
|
|
231
229
|
|
|
232
230
|
if (capiEndpoint && authUser) {
|
|
233
231
|
try {
|
|
234
|
-
const resolvedDomain = sampleLead.domain ||
|
|
235
|
-
config.domain ||
|
|
236
|
-
(config.siteUrl ? new URL(config.siteUrl).hostname : '') ||
|
|
237
|
-
(rootDir ? path.basename(rootDir).toLowerCase().replace(/[^a-z0-9_-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') : '') ||
|
|
238
|
-
'landing-page';
|
|
239
|
-
|
|
240
232
|
const capiPayload = {
|
|
241
233
|
leadId: leadId,
|
|
242
|
-
domain:
|
|
234
|
+
domain: 'samya-sports-clinic',
|
|
243
235
|
eventName: 'Lead',
|
|
244
236
|
eventTime: Math.floor(Date.now() / 1000),
|
|
245
237
|
actionSource: 'website',
|
|
@@ -327,10 +319,10 @@ async function testDispatch(arg1, arg2 = {}, arg3 = {}) {
|
|
|
327
319
|
async function testIndividualForm(rootDir, formId, formFields = {}, config = {}, extraOpts = {}) {
|
|
328
320
|
const leadId = 'test-' + (formId || 'form').replace(/[^a-zA-Z0-9_-]/g, '') + '-' + Date.now();
|
|
329
321
|
|
|
330
|
-
const name = formFields.name || formFields.fullName || 'Test Lead';
|
|
331
|
-
const phone = formFields.phone || formFields.mobile ||
|
|
332
|
-
const location = formFields.location || formFields.city || config.siteLocation || '';
|
|
333
|
-
const service = formFields.service || formFields.subject ||
|
|
322
|
+
const name = formFields.name || formFields.fullName || 'Buzl Form Test Lead';
|
|
323
|
+
const phone = formFields.phone || formFields.mobile || '9585950059';
|
|
324
|
+
const location = formFields.location || formFields.city || config.siteLocation || 'Bengaluru';
|
|
325
|
+
const service = formFields.service || formFields.subject || formId || 'General Inquiry';
|
|
334
326
|
const pagePath = extraOpts.pagePath || formFields.pagePath || '/';
|
|
335
327
|
|
|
336
328
|
const sampleLead = {
|
|
@@ -346,7 +338,7 @@ async function testIndividualForm(rootDir, formId, formFields = {}, config = {},
|
|
|
346
338
|
rawFields: Object.assign({}, formFields, { formId, pagePath, isTest: true })
|
|
347
339
|
};
|
|
348
340
|
|
|
349
|
-
return await testDispatch(
|
|
341
|
+
return await testDispatch(config, sampleLead);
|
|
350
342
|
}
|
|
351
343
|
|
|
352
344
|
module.exports = {
|
package/src/gui/public/app.js
CHANGED
|
@@ -20,10 +20,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
20
20
|
const testLeadName = document.getElementById('testLeadName');
|
|
21
21
|
const testLeadService = document.getElementById('testLeadService');
|
|
22
22
|
|
|
23
|
-
[testLeadPhone, testLeadName, testLeadService].forEach(el => {
|
|
24
|
-
if (el) el.addEventListener('input', () => { el.dataset.userEdited = 'true'; });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
23
|
// Individual Form elements
|
|
28
24
|
const formsCountBadge = document.getElementById('formsCountBadge');
|
|
29
25
|
const individualFormsList = document.getElementById('individualFormsList');
|
|
@@ -106,18 +102,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
106
102
|
updateLiveStateBar(data.liveState, data.rootDir);
|
|
107
103
|
|
|
108
104
|
// Auto-detect site location
|
|
109
|
-
if (data.detectedLocation && siteLocationInput && !siteLocationInput.
|
|
105
|
+
if (data.detectedLocation && siteLocationInput && !siteLocationInput.value) {
|
|
110
106
|
siteLocationInput.value = data.detectedLocation;
|
|
111
107
|
}
|
|
112
108
|
|
|
113
|
-
// Auto-detect phone and service for quick test dispatch
|
|
114
|
-
if (testLeadPhone && !testLeadPhone.dataset.userEdited) {
|
|
115
|
-
testLeadPhone.value = data.detectedWhatsapp || (data.liveState && data.liveState.whatsapp && data.liveState.whatsapp.detectedNumber) || '';
|
|
116
|
-
}
|
|
117
|
-
if (testLeadService && !testLeadService.dataset.userEdited) {
|
|
118
|
-
testLeadService.value = data.detectedService || 'General Inquiry';
|
|
119
|
-
}
|
|
120
|
-
|
|
121
109
|
// Populate dynamic fields checklist
|
|
122
110
|
if (dynamicFieldsChecklist && data.uniqueFields) {
|
|
123
111
|
dynamicFieldsChecklist.innerHTML = '';
|
|
@@ -421,19 +409,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
421
409
|
|
|
422
410
|
// Build sample test input controls
|
|
423
411
|
const inputElements = f.inputs.map(i => {
|
|
424
|
-
let sampleVal = 'Test
|
|
412
|
+
let sampleVal = 'Test';
|
|
425
413
|
const lower = i.name.toLowerCase();
|
|
426
|
-
if (lower.includes('phone') || lower.includes('mobile'))
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
} else if (lower.includes('mail')) {
|
|
431
|
-
sampleVal = 'test-lead@example.com';
|
|
432
|
-
} else if (lower.includes('service') || lower.includes('inquiry') || lower.includes('treatment') || lower.includes('subject')) {
|
|
433
|
-
sampleVal = f.formTitle || f.id || (currentScanData && currentScanData.detectedService) || 'General Inquiry';
|
|
434
|
-
} else if (lower.includes('city') || lower.includes('loc')) {
|
|
435
|
-
sampleVal = (currentScanData && currentScanData.detectedLocation) || '';
|
|
436
|
-
}
|
|
414
|
+
if (lower.includes('phone') || lower.includes('mobile')) sampleVal = '9585950059';
|
|
415
|
+
else if (lower.includes('name')) sampleVal = `Test Patient ${idx + 1}`;
|
|
416
|
+
else if (lower.includes('mail')) sampleVal = 'test@gobuzl.com';
|
|
417
|
+
else if (lower.includes('service')) sampleVal = 'Sports Injury Rehabilitation';
|
|
437
418
|
|
|
438
419
|
return `
|
|
439
420
|
<div class="form-field-input-group">
|
|
@@ -852,10 +833,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
852
833
|
if (btnTestSubmit) {
|
|
853
834
|
btnTestSubmit.addEventListener('click', async () => {
|
|
854
835
|
const config = getCurrentConfig();
|
|
855
|
-
const phone = testLeadPhone.value.trim() ||
|
|
856
|
-
const name = testLeadName.value.trim() || 'Test Lead';
|
|
857
|
-
const service = testLeadService.value.trim() ||
|
|
858
|
-
const loc = (siteLocationInput ? siteLocationInput.value.trim() : '') || (currentScanData && currentScanData.detectedLocation) || '';
|
|
836
|
+
const phone = testLeadPhone.value.trim() || '9585950059';
|
|
837
|
+
const name = testLeadName.value.trim() || 'Buzl Test Lead';
|
|
838
|
+
const service = testLeadService.value.trim() || 'Sports Injury Rehabilitation';
|
|
859
839
|
|
|
860
840
|
btnTestSubmit.disabled = true;
|
|
861
841
|
btnTestSubmit.innerHTML = '<svg class="icon-sm icon-spin"><use href="#icon-refresh"/></svg> <span>Sending Live Test Lead...</span>';
|
|
@@ -874,7 +854,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
874
854
|
phone,
|
|
875
855
|
name,
|
|
876
856
|
service,
|
|
877
|
-
location:
|
|
857
|
+
location: siteLocationInput ? siteLocationInput.value.trim() : 'Bengaluru'
|
|
878
858
|
}
|
|
879
859
|
})
|
|
880
860
|
});
|
|
@@ -305,7 +305,7 @@
|
|
|
305
305
|
</div>
|
|
306
306
|
<div class="form-group">
|
|
307
307
|
<label for="siteLocation">Default Site Location (Fallback for Column B)</label>
|
|
308
|
-
<input type="text" id="siteLocation" placeholder="
|
|
308
|
+
<input type="text" id="siteLocation" placeholder="e.g. Sahakar Nagar, Bengaluru">
|
|
309
309
|
<small class="helper-text">Auto-detected from metadata. Fills Column B if forms omit location.</small>
|
|
310
310
|
</div>
|
|
311
311
|
|
|
@@ -470,16 +470,16 @@
|
|
|
470
470
|
<div class="form-row">
|
|
471
471
|
<div class="form-group">
|
|
472
472
|
<label for="testLeadPhone">Phone Number</label>
|
|
473
|
-
<input type="text" id="testLeadPhone"
|
|
473
|
+
<input type="text" id="testLeadPhone" value="9585950059">
|
|
474
474
|
</div>
|
|
475
475
|
<div class="form-group">
|
|
476
476
|
<label for="testLeadName">Full Name</label>
|
|
477
|
-
<input type="text" id="testLeadName" value="Test Lead">
|
|
477
|
+
<input type="text" id="testLeadName" value="Buzl Test Lead">
|
|
478
478
|
</div>
|
|
479
479
|
</div>
|
|
480
480
|
<div class="form-group" style="margin-top: 8px;">
|
|
481
481
|
<label for="testLeadService">Service / Inquiry</label>
|
|
482
|
-
<input type="text" id="testLeadService"
|
|
482
|
+
<input type="text" id="testLeadService" value="Sports Injury Rehabilitation">
|
|
483
483
|
</div>
|
|
484
484
|
<button type="button" id="btnTestSubmit" class="btn btn-primary" style="width: 100%; margin-top: 12px;">
|
|
485
485
|
<svg class="icon-sm"><use href="#icon-send"/></svg>
|