#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
console.log('🔍 TRACING: Parameter Validation Flow\n');
console.log('='.repeat(80));
const serverWithAuthPath = path.join(__dirname, '../../src/server-with-auth.ts');
const serverCode = fs.readFileSync(serverWithAuthPath, 'utf8');
console.log('\nđź“‹ STEP 1: Parameter Validation Flow (lines 608-750)\n');
console.log('-'.repeat(80));
// Extract handleApiCall function
const handleApiCallMatch = serverCode.match(/private async handleApiCall\(path: string, args: any\)[^{]*\{[\s\S]*?^ \}/m);
if (handleApiCallMatch) {
const lines = handleApiCallMatch[0].split('\n');
console.log('Key points in parameter flow:\n');
// Find where args are processed
lines.forEach((line, i) => {
if (line.includes('const { username: _, ...apiArgs } = args')) {
console.log(`Line ${i}: Extracting apiArgs from args (removes username)`);
}
if (line.includes('const queryParams: any = {}')) {
console.log(`Line ${i}: Initialize queryParams`);
}
if (line.includes('Object.entries(apiArgs).forEach')) {
console.log(`Line ${i}: Process apiArgs into queryParams`);
}
if (line.includes('queryParams[key] = value')) {
console.log(`Line ${i}: Add parameter to queryParams`);
}
if (line.includes('const filterParams: Record<string, any> = {}')) {
console.log(`Line ${i}: Initialize filterParams`);
}
if (line.includes('const regularParams: Record<string, any> = {}')) {
console.log(`Line ${i}: Initialize regularParams`);
}
if (line.includes('Object.entries(queryParams).forEach')) {
console.log(`Line ${i}: Split queryParams into filter and regular params`);
}
if (line.includes('QueryParamsSchema.partial().parse(regularParams)')) {
console.log(`Line ${i}: ⚠️ VALIDATION - This strips unknown params!`);
}
if (line.includes('validatedParams = {')) {
console.log(`Line ${i}: Combine validated regular params with filter params`);
}
});
}
console.log('\nđź“‹ STEP 2: Parameter Mapping Logic (lines 760-797)\n');
console.log('-'.repeat(80));
// Find the parameter mapping section
const mappingSection = serverCode.match(/const ENDPOINTS_REQUIRING_CUSTOMER_PARAMS[\s\S]*?if \(validatedParams\.accountKey && validatedParams\.divisionId\)[\s\S]*?\} else \{[\s\S]*?\}/);
if (mappingSection) {
console.log('Parameter Mapping Code:\n');
const lines = mappingSection[0].split('\n').slice(0, 40);
lines.forEach((line, i) => {
if (line.includes('ENDPOINTS_REQUIRING_CUSTOMER_PARAMS.includes(path)')) {
console.log(`Line ${i}: Check if endpoint requires customer params`);
}
if (line.includes('[PARAM-DEBUG]')) {
console.log(`Line ${i}: Debug log - should show validated params`);
}
if (line.includes('if (validatedParams.accountKey && validatedParams.divisionId)')) {
console.log(`Line ${i}: ⚠️ CRITICAL CHECK - needs accountKey & divisionId`);
}
if (line.includes('validatedParams.customer_account_key = validatedParams.accountKey')) {
console.log(`Line ${i}: Map accountKey to customer_account_key`);
}
});
}
console.log('\nđź“‹ STEP 3: The Problem Chain\n');
console.log('-'.repeat(80));
console.log(`
PROBLEM FLOW:
1. Claude sends: args = {accountKey: "24223", divisionId: "1", ...}
2. Line 608: apiArgs = {accountKey: "24223", divisionId: "1", ...} (username removed)
3. Lines 612-719: apiArgs processed into queryParams
4. Lines 721-732: queryParams split into filterParams and regularParams
- regularParams = {accountKey: "24223", divisionId: "1", ...}
5. Line 749: validatedParams = QueryParamsSchema.partial().parse(regularParams)
⚠️ THIS STRIPS accountKey if not in schema!
6. Line 770: Check ENDPOINTS_REQUIRING_CUSTOMER_PARAMS
7. Line 772: Check if validatedParams.accountKey exists
❌ FAILS because accountKey was stripped at line 749!
`);
console.log('\nđź“‹ STEP 4: Checking Current Schema\n');
console.log('-'.repeat(80));
const typesPath = path.join(__dirname, '../../src/types.ts');
const typesCode = fs.readFileSync(typesPath, 'utf8');
const schemaMatch = typesCode.match(/export const QueryParamsSchema = z\.object\(\{[\s\S]*?\}\);/);
if (schemaMatch) {
const hasAccountKey = schemaMatch[0].includes('accountKey:');
const hasDivisionId = schemaMatch[0].includes('divisionId:');
console.log(`QueryParamsSchema status:`);
console.log(` ${hasAccountKey ? '✅' : '❌'} accountKey field ${hasAccountKey ? 'EXISTS' : 'MISSING'}`);
console.log(` ${hasDivisionId ? '✅' : '❌'} divisionId field ${hasDivisionId ? 'EXISTS' : 'MISSING'}`);
if (hasAccountKey) {
const accountKeyLine = schemaMatch[0].match(/accountKey:.*$/m);
console.log(` Field definition: ${accountKeyLine ? accountKeyLine[0] : 'Not found'}`);
}
}
console.log('\nđź“‹ STEP 5: Why [PARAM-DEBUG] Never Appears\n');
console.log('-'.repeat(80));
console.log(`
The [PARAM-DEBUG] log at line 771 never appears because:
1. Line 770 checks: if (ENDPOINTS_REQUIRING_CUSTOMER_PARAMS.includes(path))
- This check PASSES for /v1/invoices/caui
2. Line 771 should log: [PARAM-DEBUG] Checking params...
- This NEVER appears in logs
3. Line 772 checks: if (validatedParams.accountKey && validatedParams.divisionId)
- This check MUST be failing
HOWEVER: The code flow suggests line 771 should execute if line 770 passes.
The fact that it doesn't appear means either:
a) The code isn't reaching line 770 at all
b) The compiled JavaScript is different from the TypeScript
c) There's a build/deployment issue
`);
console.log('\nđź“‹ STEP 6: Solution Status\n');
console.log('-'.repeat(80));
console.log(`
CURRENT STATUS:
1. âś… accountKey added to QueryParamsSchema
2. âś… TypeScript compiled (npm run build)
3. ❌ Server still using old compiled code?
NEXT STEPS:
1. Check if dist/ has latest compiled code
2. Verify the server is loading from dist/
3. Restart server properly
`);
console.log('\n' + '='.repeat(80));
console.log('TRACE COMPLETE');
console.log('='.repeat(80));