integration · copy-ready
Validate before you publish.
Safe defaults, bounded network behaviour and explicit failure handling for local development, CI and feed delivery.
CLI workflow
node tools/zentra-feed.mjs --help
node tools/zentra-feed.mjs validate feed.xml --json > report.json
node tools/zentra-feed.mjs audit-media feed.xml --json --concurrency 4
node tools/diff-indexes.mjs old/cities.json new/cities.json --jsoncurl
curl --fail --silent --show-error \
--connect-timeout 10 --max-time 60 \
--user "$FEED_USER:$FEED_PASSWORD" \
--upload-file feed.xml \
https://feeds.example.invalid/zentra.xmlnode
import { readFile } from 'node:fs/promises';
const xml = await readFile('feed.xml');
const response = await fetch(process.env.FEED_URL, {
method: 'PUT', body: xml,
headers: { 'content-type': 'application/xml; charset=utf-8' },
signal: AbortSignal.timeout(60_000)
});
if (!response.ok) throw new Error(`publish failed: ${response.status}`);python
from pathlib import Path
from urllib.request import Request, urlopen
request = Request(FEED_URL, data=Path('feed.xml').read_bytes(),
method='PUT', headers={'Content-Type': 'application/xml; charset=utf-8'})
with urlopen(request, timeout=60) as response:
assert 200 <= response.status < 300php
use Illuminate\Support\Facades\Http;
$response = Http::connectTimeout(10)->timeout(60)
->withBody(file_get_contents($path), 'application/xml; charset=utf-8')
->put(config('feeds.zentra_url'));
$response->throw();Production-size guidance
Generate XML as a UTF-8 stream, write one property at a time, calculate a content fingerprint while writing, validate from disk, then publish the immutable file. Do not construct a multi-gigabyte DOM in application memory. Bound redirects, payload size, connect timeout and total timeout at every network boundary.