Commit 9920f907 authored by nextime's avatar nextime

Enforce strict ID matching and complete JSON validation before serving responses

- Add comprehensive logging with emojis for better debugging visibility
- Implement strict validation requiring exact ID match and non-empty response
- Enhanced observer logic to only resolve on complete, validated JSON
- Add priority-based detection: HTML code blocks first, then text content
- Prevent premature response serving until complete JSON with matching ID is found
- Add detailed console logging for tracking detection progress
- Ensure system waits for complete ID match before serving any API response

This ensures the API absolutely waits for the complete JSON response
with the matching request ID before serving any reply to clients.
parent c0d398f4
......@@ -603,18 +603,19 @@ async def detect_json_response_with_id(page, container_selector, request_id, pro
};
const observer = new MutationObserver((mutations) => {
// Only resolve if we have complete, valid JSON
// Only resolve if we have complete, valid JSON with exact ID match
const result = getCompleteJsonResponse();
if (result && !result.startsWith("Error:")) {
if (result && typeof result === 'string' && result.length > 0) {
console.log(`🎯 Observer found complete response, disconnecting...`);
observer.disconnect();
resolveOnce(result);
return;
}
// Update best partial match for debugging
if (partialJsonContent.length > (bestMatch?.length || 0)) {
bestMatch = partialJsonContent;
console.log(`Updated partial match: ${partialJsonContent.substring(0, 100)}...`);
// Log progress for debugging but don't resolve yet
const hasPartialId = container.textContent && container.textContent.includes(requestId);
if (hasPartialId) {
console.log(`⏳ Found request ID in content, waiting for complete JSON...`);
}
});
......@@ -624,45 +625,77 @@ async def detect_json_response_with_id(page, container_selector, request_id, pro
characterData: true
});
// Function to validate complete JSON with both required keys
// Function to validate complete JSON with both required keys and exact ID match
const isCompleteValidJson = (text) => {
try {
const jsonObj = JSON.parse(text);
return jsonObj.id && jsonObj.id.includes(requestId) &&
jsonObj.response && typeof jsonObj.response === 'string' &&
jsonObj.response.length > 0;
// Strict validation: must have exact ID match and non-empty response
const hasValidId = jsonObj.id &&
typeof jsonObj.id === 'string' &&
jsonObj.id.includes(requestId) &&
jsonObj.id.length >= requestId.length;
const hasValidResponse = jsonObj.response &&
typeof jsonObj.response === 'string' &&
jsonObj.response.trim().length > 0;
if (hasValidId && hasValidResponse) {
console.log(`✓ Complete valid JSON found - ID: ${jsonObj.id}, Response length: ${jsonObj.response.length}`);
return true;
} else {
console.log(`✗ Incomplete JSON - ID valid: ${hasValidId}, Response valid: ${hasValidResponse}`);
return false;
}
} catch (e) {
console.log(`✗ JSON parse error: ${e.message}`);
return false;
}
};
// Enhanced check that only returns complete, valid JSON
// Enhanced check that only returns complete, valid JSON with exact ID match
const getCompleteJsonResponse = () => {
const htmlResult = extractJsonFromHtml();
if (htmlResult) {
// Verify we have a complete JSON by trying to find the original JSON
const codeBlocks = container.querySelectorAll([
'pre code.language-json',
'pre code[class*="json"]',
'code.language-json',
'code[class*="json"]',
'pre code',
'code'
].join(', '));
for (const codeBlock of codeBlocks) {
const jsonText = codeBlock.textContent ? codeBlock.textContent.trim() : '';
if (jsonText && isCompleteValidJson(jsonText)) {
console.log(`Found complete valid JSON: ${jsonText.substring(0, 100)}...`);
console.log(`🔍 Searching for complete JSON with ID: ${requestId}`);
// First priority: Check HTML formatted code blocks
const codeBlocks = container.querySelectorAll([
'pre code.language-json',
'pre code[class*="json"]',
'code.language-json',
'code[class*="json"]',
'pre code',
'code'
].join(', '));
for (const codeBlock of codeBlocks) {
const jsonText = codeBlock.textContent ? codeBlock.textContent.trim() : '';
if (jsonText && jsonText.includes(requestId)) {
console.log(`📋 Found code block with request ID: ${jsonText.substring(0, 150)}...`);
if (isCompleteValidJson(jsonText)) {
const jsonObj = JSON.parse(jsonText);
console.log(`✅ Returning validated response for ID: ${jsonObj.id}`);
return jsonObj.response;
}
}
}
// Fallback to text-based extraction with validation
const result = getCombinedText();
return result;
// Second priority: Check all text content for JSON patterns
const allElements = container.querySelectorAll('*');
for (const element of allElements) {
const text = element.textContent ? element.textContent.trim() : '';
if (text && text.includes(requestId) && text.includes('{') && text.includes('"response"')) {
console.log(`📄 Found element with potential JSON: ${text.substring(0, 150)}...`);
// Try to extract JSON from this text
const jsonMatch = text.match(/\{[^{}]*"id"[^{}]*"' + requestId + '"[^{}]*"response"[^{}]*\}|\{[^{}]*"response"[^{}]*"id"[^{}]*"' + requestId + '"[^{}]*\}/);
if (jsonMatch && isCompleteValidJson(jsonMatch[0])) {
const jsonObj = JSON.parse(jsonMatch[0]);
console.log(`✅ Returning validated response from text for ID: ${jsonObj.id}`);
return jsonObj.response;
}
}
}
console.log(`❌ No complete JSON found with ID: ${requestId}`);
return null;
};
// Initial check after a longer delay to allow content to load
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment