fix(accounting): verify and fix Zarrin driver on real v228 install
Tested 20/20 on the owner's live Zarrin v228 (870 accounts, 656 items): Reads fixed: - listKarSakhte: now pages by 100 via pageNum (was returning only first 100 of 656) - goroohSakhte: HTTP 400 with a valid body is now accepted (was treated as missing) - parvande «مانده از قبل» row is not a balance; skip it and anchor the running balance on the live listMandeHesabha balance, walked back through movements - infogardeshsakhte: hand-printed JSON repaired, timeout raised to 90s - document delete: now searches all ledger pages, not just the first one - listhesabha names are «first * last»; the «*» is now stripped - keep-alive ECONNRESET: a socket hang-up on a reused connection is retried once on a fresh connection (server closes idle connections) Writes fixed (test account 953 «تست اپ گلدبانک»): - temporary flag: set from shomareSanad («موقت»), not noeFactor - noeFactor «فاکتور موقت» also flags a document left open in Zarrin's own UI New: test script apps/api/scripts/test-accounting-zarrin.ts (13 read + 7 write checks) Docs: §13 added to ACCOUNTING-INTEGRATION-PLAN.md; ACC-01 in ISSUES.md updated New: docs/FRESH-SERVER-DEPLOY-AUDIT.md (fresh-server deploy checklist) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
9fc0886a57
commit
8b74c85a2a
@@ -86,6 +86,16 @@ function tlsErrorMessage(err: NodeJS.ErrnoException, pinned: boolean): string {
|
||||
}
|
||||
|
||||
export function httpRequest(req: HttpRequest): Promise<HttpResponse> {
|
||||
return send(req, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* One attempt. `fresh` = on a new connection: a server that closes idle
|
||||
* kept-alive connections (Zarrin v228 does) makes the next request on a pooled
|
||||
* one fail with ECONNRESET / "socket hang up" before it was received. That one
|
||||
* case is repeated once on a fresh connection; nothing else is ever retried.
|
||||
*/
|
||||
function send(req: HttpRequest, fresh: boolean): Promise<HttpResponse> {
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(req.url);
|
||||
@@ -106,6 +116,7 @@ export function httpRequest(req: HttpRequest): Promise<HttpResponse> {
|
||||
port: url.port || (isHttps ? 443 : 80),
|
||||
path: `${url.pathname}${url.search}`,
|
||||
headers,
|
||||
...(fresh ? { agent: false } : {}),
|
||||
};
|
||||
const pins = isHttps ? pinnedFingerprints(req.ca) : new Set<string>();
|
||||
if (isHttps) {
|
||||
@@ -176,6 +187,10 @@ export function httpRequest(req: HttpRequest): Promise<HttpResponse> {
|
||||
}, req.timeoutMs);
|
||||
|
||||
request.on('error', (err: NodeJS.ErrnoException) => {
|
||||
if (!fresh && request.reusedSocket && err.code === 'ECONNRESET') {
|
||||
finish(() => resolve(send(req, true)));
|
||||
return;
|
||||
}
|
||||
// Node's own text for these suggests flags that do not apply here.
|
||||
const text = isHttps && err.code && TLS_CERT_ERRORS.test(err.code) ? tlsErrorMessage(err, pins.size > 0) : err.message;
|
||||
finish(() => reject(new AccountingHttpError(text, connected, err.code)));
|
||||
|
||||
Reference in New Issue
Block a user