← back to Marketing Command Center
copy: consolidate onto shared lib/fetch-timeout.js (drop duplicate helper)
0c84eb55de9914a389d447c17b962cbc87668766 · 2026-08-17 06:13:09 -0700 · Steve Abrams
Files touched
Diff
commit 0c84eb55de9914a389d447c17b962cbc87668766
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 17 06:13:09 2026 -0700
copy: consolidate onto shared lib/fetch-timeout.js (drop duplicate helper)
---
modules/copy/index.js | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/modules/copy/index.js b/modules/copy/index.js
index 353a192..78046f0 100644
--- a/modules/copy/index.js
+++ b/modules/copy/index.js
@@ -13,6 +13,7 @@
// No outbound sends here — this only DRAFTS copy. CAN-SPAM footer is flagged as
// a required manual add for the 'email' kind (compliance lives in brand.js).
const brand = require('../../lib/brand.js');
+const { fetchWithTimeout: sharedFetchWithTimeout } = require('../../lib/fetch-timeout.js');
const KINDS = [
{ id: 'subject-lines', label: 'Email subject lines' },
@@ -205,19 +206,13 @@ function userPromptFor(ctx, n) {
// fetch() with a hard timeout. Node's fetch has NO default timeout, so a stalled
// upstream (Anthropic/Gemini) would hang the POST /generate|/score request
-// forever, spinning the user's button. Aborts after LLM_TIMEOUT_MS and throws an
-// AbortError the existing callers already catch (→ 500 for generate, heuristic
-// fallback for score).
+// forever, spinning the user's button. Shared AbortController logic lives in
+// lib/fetch-timeout.js; we keep copy's own COPY_LLM_TIMEOUT_MS default so this
+// module stays independently tunable. The thrown AbortError is caught by the
+// existing callers (→ 500 for generate, heuristic fallback for score).
const LLM_TIMEOUT_MS = Number(process.env.COPY_LLM_TIMEOUT_MS) || 45000;
-async function fetchWithTimeout(url, opts = {}, ms = LLM_TIMEOUT_MS) {
- const ctrl = new AbortController();
- const timer = setTimeout(() => ctrl.abort(), ms);
- try {
- return await fetch(url, { ...opts, signal: ctrl.signal });
- } finally {
- clearTimeout(timer);
- }
-}
+const fetchWithTimeout = (url, opts = {}, ms = LLM_TIMEOUT_MS) =>
+ sharedFetchWithTimeout(url, opts, ms);
async function llmGenerate(ctx, n) {
const key = process.env.ANTHROPIC_API_KEY;
← f6af2dd auto-data-snapshot: 2026-08-16T09:54:36 (1 data files) — pub
·
back to Marketing Command Center
·
ig-activity: IG Posts panel — show all fleet IG posts + per- 4fd1cb4 →