Split out from the TypeScript port (#66), which was an annotation-only faithful translation — these are pre-existing behaviors present verbatim in the JS baseline (ad7be30), surfaced by CodeRabbit on the port diff. Fixing them changes runtime behavior, so they belong here, not in the port PR.
Findings (all confirmed present pre-port)
src/lib/http.ts — PARTIFUL_MAX_RETRIES NaN wedge. parseInt(process.env.PARTIFUL_MAX_RETRIES || '3', 10) — a non-numeric env value → NaN, attempt <= NaN is false on iteration 0, so no HTTP call is ever made and every command throws 'Request failed after retries'. Add Number.isFinite + floor guard.
src/lib/http.ts — Retry-After HTTP-date → NaN backoff. parseFloat on a date string yields NaN → setTimeout(…, NaN) fires immediately, discarding server backoff on 429s. Handle the HTTP-date form.
src/lib/http.ts — no request timeout on the three fetch call sites (apiRequest, firestoreRequest, firestoreListDocuments). A stalled socket hangs the CLI forever. Add AbortSignal.timeout(...) (composes with withRetry). upload.ts already bounds its fetches.
src/helpers/watch.ts — --interval/--duration unvalidated. parseInt('x') → NaN → setTimeout(resolve, NaN) fires immediately, turning the poll loop into a request storm against Firestore; bad --duration exits instantly with a misleading 'Watch complete'. Add radix + positive-integer validation.
src/lib/auth.ts — token refresh trusts response without resp.ok/id_token check. A non-{error}-shaped error body persists accessToken=undefined + tokenExpiry=Date.now() to auth.json and returns undefined, producing Authorization: Bearer undefined. Guard !resp.ok and missing id_token; lets getValidToken drop its ! assertions.
Recommended fix pattern
Centralize numeric-env parsing in one parsePositiveInt(value, fallback) helper, add a shared fetchWithTimeout, and tighten the auth refresh guard. All five are quick wins except the shared-timeout wiring.
Split out from the TypeScript port (#66), which was an annotation-only faithful translation — these are pre-existing behaviors present verbatim in the JS baseline (ad7be30), surfaced by CodeRabbit on the port diff. Fixing them changes runtime behavior, so they belong here, not in the port PR.
Findings (all confirmed present pre-port)
src/lib/http.ts—PARTIFUL_MAX_RETRIESNaN wedge.parseInt(process.env.PARTIFUL_MAX_RETRIES || '3', 10)— a non-numeric env value →NaN,attempt <= NaNis false on iteration 0, so no HTTP call is ever made and every command throws 'Request failed after retries'. AddNumber.isFinite+ floor guard.src/lib/http.ts—Retry-AfterHTTP-date →NaNbackoff.parseFloaton a date string yields NaN →setTimeout(…, NaN)fires immediately, discarding server backoff on 429s. Handle the HTTP-date form.src/lib/http.ts— no request timeout on the threefetchcall sites (apiRequest, firestoreRequest, firestoreListDocuments). A stalled socket hangs the CLI forever. AddAbortSignal.timeout(...)(composes with withRetry). upload.ts already bounds its fetches.src/helpers/watch.ts—--interval/--durationunvalidated.parseInt('x')→ NaN →setTimeout(resolve, NaN)fires immediately, turning the poll loop into a request storm against Firestore; bad--durationexits instantly with a misleading 'Watch complete'. Add radix + positive-integer validation.src/lib/auth.ts— token refresh trusts response withoutresp.ok/id_tokencheck. A non-{error}-shaped error body persistsaccessToken=undefined+tokenExpiry=Date.now()to auth.json and returns undefined, producingAuthorization: Bearer undefined. Guard!resp.okand missingid_token; lets getValidToken drop its!assertions.Recommended fix pattern
Centralize numeric-env parsing in one
parsePositiveInt(value, fallback)helper, add a sharedfetchWithTimeout, and tighten the auth refresh guard. All five are quick wins except the shared-timeout wiring.