Files
justvitamin/scripts/validate-dataforseo-reviews-docs-status.ts
T
Omair Saleh 056c47581f feat: editorial review dashboard + elite-grade pilot batch (5 SKUs)
Ships the second dashboard surface — a Pattern Library + Preview Theatre — that
presents the 4-section PDP pilot batch back to Umar, compliance, and the board
in an editorial format. Adds the full data layer that drives it: 5 source-backed
per-SKU drafts at QA 100/100, 15 competitor PDP semantic extracts, PubMed
evidence packs, EFSA claims library extension, JV brand voice guide, hand-curated
product FAQs, and the Matrixify-ready CSV exports for Lewis.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 18:50:09 +08:00

119 lines
4.5 KiB
TypeScript

#!/usr/bin/env bun
import { mkdirSync, writeFileSync } from 'fs'
import { join } from 'path'
const root = process.cwd()
const outRoot = join(root, 'content_population_exports')
mkdirSync(outRoot, { recursive: true })
const docsUrl = 'https://docs.dataforseo.com/v3/merchant-amazon-reviews-task_post/'
function csv(rows: any[], headers: string[]) {
const esc = (value: any) => {
if (value === undefined || value === null) value = ''
if (Array.isArray(value)) value = value.join(' | ')
value = String(value)
return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value
}
return [headers.join(','), ...rows.map(row => headers.map(header => esc(row[header])).join(','))].join('\n') + '\n'
}
function compact(text: string) {
return text.replace(/<script[\s\S]*?<\/script>/gi, ' ')
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
.replace(/<[^>]+>/g, ' ')
.replace(/\s+/g, ' ')
.trim()
}
const generatedAt = new Date().toISOString()
let httpStatus = 0
let fetchOk = false
let endpointTemporarilyUnavailable = false
let endpointMentioned = false
let evidence = ''
let error = ''
try {
const res = await fetch(docsUrl, { headers: { 'User-Agent': 'jv-dashboard-source-gate/1.0' } })
httpStatus = res.status
const html = await res.text()
const text = compact(html)
fetchOk = res.ok
endpointMentioned = text.includes('merchant/amazon/reviews/task_post')
endpointTemporarilyUnavailable = /endpoint is temporarily unavailable|function temporarily unavailable/i.test(text)
const unavailableIndex = text.toLowerCase().indexOf('temporarily unavailable')
if (unavailableIndex >= 0) evidence = text.slice(Math.max(0, unavailableIndex - 80), unavailableIndex + 160)
} catch (err: any) {
error = err.message || String(err)
}
const checks = [
{
Check: 'Official docs reachable',
Status: fetchOk ? 'pass' : 'blocked',
Evidence: fetchOk ? `Fetched ${docsUrl} with HTTP ${httpStatus}` : `HTTP ${httpStatus || 'n/a'} ${error}`
},
{
Check: 'Amazon Reviews task_post endpoint documented',
Status: endpointMentioned ? 'pass' : 'blocked',
Evidence: endpointMentioned ? 'Docs page mentions merchant/amazon/reviews/task_post.' : 'Endpoint string not found in fetched docs.'
},
{
Check: 'Official unavailable note detected',
Status: endpointTemporarilyUnavailable ? 'blocked' : 'pass',
Evidence: endpointTemporarilyUnavailable
? 'Official DataForSEO docs currently state the Amazon Reviews endpoint is temporarily unavailable.'
: 'No temporary-unavailable note detected in fetched docs.'
}
]
const manifest = {
generatedAt,
ready: fetchOk && endpointMentioned && !endpointTemporarilyUnavailable,
provider: 'DataForSEO',
endpoint: 'POST https://api.dataforseo.com/v3/merchant/amazon/reviews/task_post',
docsUrl,
httpStatus,
credentialPrinted: false,
endpointTemporarilyUnavailable,
recommendation: endpointTemporarilyUnavailable
? 'Do not retry paid Amazon Reviews task_post while the official docs page marks the endpoint temporarily unavailable. Use support response or manual capture fallback.'
: 'Official docs no longer show the endpoint unavailable; still require local preflight, support/approval/spend gates before any capped retry.',
evidenceSnippet: evidence,
counts: {
checks: checks.length,
passing: checks.filter(row => row.Status === 'pass').length,
blocked: checks.filter(row => row.Status !== 'pass').length
},
checks
}
writeFileSync(join(outRoot, 'dataforseo_reviews_docs_status.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'dataforseo_reviews_docs_status.csv'), csv(checks, ['Check', 'Status', 'Evidence']), 'utf8')
writeFileSync(join(outRoot, 'dataforseo_reviews_docs_status.md'), [
'# DataForSEO Amazon Reviews docs status',
'',
`Generated: ${generatedAt}`,
'',
`Ready for retry by docs status: ${manifest.ready ? 'YES' : 'NO'}`,
'',
`Official docs: ${docsUrl}`,
'',
manifest.recommendation,
'',
'## Checks',
...checks.map(row => `- [${row.Status}] ${row.Check}: ${row.Evidence}`),
'',
evidence ? '## Evidence snippet' : '',
evidence ? `> ${evidence}` : '',
'',
'## Guardrail',
'This check fetches official DataForSEO documentation only. It does not load credentials, print secrets, or call any paid endpoint.',
''
].filter(Boolean).join('\n'), 'utf8')
console.log(`DataForSEO Reviews docs status ready: ${manifest.ready}`)
console.log(`Official unavailable note: ${manifest.endpointTemporarilyUnavailable}`)
console.log(`Checks passing: ${manifest.counts.passing}/${manifest.counts.checks}`)