dsh-think-translate 1.2.10 → 1.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.de.md CHANGED
@@ -75,6 +75,8 @@ Für DSH **0.2.0-rc.2** verwenden Sie **dsh-think-translate 1.2.5 oder neuer**.
75
75
 
76
76
  **1.2.8 Übertragung und Wiederaufnahme:** Normale HTTP/HTTPS-Übersetzungen nutzen die nativen Netzwerkfunktionen von Node statt eines curl-Prozesses pro Textpaket. SOCKS-Proxys und der Ollama-Installer verwenden weiterhin curl. Fehler bleiben 30 Sekunden im Arbeitsspeicher; danach werden Denk- und Antwortübersetzungen automatisch erneut versucht. Die Zeitlimits berücksichtigen das Laden lokaler Modelle und alternative Anbieter.
77
77
 
78
+ **1.2.11 Bing-Korrekturen:** Der kostenlose Bing-Anbieter bleibt erhalten. Übersetzungsanfragen gehen an den endgültigen Origin der Sitzungsseite, damit die Weiterleitung `www.bing.com` → `cn.bing.com` in Festlandchina den POST-Body nicht verwirft. SOCKS/curl verwendet dieselben Browser-Header wie der native Transport und behebt damit HTTP 401; leere Antworten und Antworten ohne JSON melden klare Fehler.
79
+
78
80
  **1.2.10 DSH-Profilkompatibilität:** Die Erkennung folgt dem laufenden Desktop/Web-Profil und liest `profiles/<profile>/cordis.patch.yml` (`id` + `config`), danach die Home-Patches und Start-Overlays. Das ältere `settings.yaml` bleibt unterstützt. Die Standardmodell-Zeile heißt `default-model`; Zugangsdaten bleiben in `.credentials.yaml` im DSH-Home und nur im Arbeitsspeicher. Die Diagnose zeigt die tatsächlich gelesene Datei.
79
81
 
80
82
  **1.2.9 Sprachkorrekturen:** Japanische Vokabelhinweise gelten nur für Japanisch; OpenAI/Anthropic erhalten den vollständigen Sprachnamen. Bing nutzt `auto-detect` und `zh-Hans`/`zh-Hant`. Die Erkennung chinesischer Prosa blendet Pfade, Code und JSON aus: vereinfachte Prosa wird übersprungen, häufige traditionelle Schriftzeichen lösen eine Übersetzungsanfrage aus, japanische/koreanische Prosa wird übersetzt. Alte Übersetzungen werden einmalig aus dem Cache entfernt; Einstellungen bleiben erhalten.
package/README.es.md CHANGED
@@ -75,6 +75,8 @@ Para DSH **0.2.0-rc.2**, usa **dsh-think-translate 1.2.5 o posterior**. La versi
75
75
 
76
76
  **1.2.8 transporte y recuperación:** las traducciones HTTP/HTTPS normales usan la red nativa de Node en lugar de iniciar curl por cada lote de texto. Los proxies SOCKS y el instalador de Ollama conservan la compatibilidad con curl. Los fallos permanecen en memoria durante 30 segundos y después se reintentan automáticamente las traducciones del razonamiento y las respuestas. Los tiempos de espera permiten cargar modelos locales y probar proveedores alternativos.
77
77
 
78
+ **1.2.11 correcciones de Bing:** se mantiene el proveedor gratuito. Las solicitudes de traducción usan el origen final de la página de sesión para evitar que la redirección `www.bing.com` → `cn.bing.com` en China continental elimine el cuerpo POST. SOCKS/curl comparte las cabeceras de navegador del transporte nativo para corregir HTTP 401; las respuestas vacías o no JSON muestran errores claros.
79
+
78
80
  **1.2.10 compatibilidad con perfiles DSH:** el descubrimiento sigue el perfil Desktop/Web activo y lee `profiles/<profile>/cordis.patch.yml` (`id` + `config`), después los parches del directorio DSH y las superposiciones de inicio. Se mantiene el formato anterior `settings.yaml`. El modelo predeterminado usa `default-model`; las credenciales siguen en `.credentials.yaml` del directorio DSH y solo en memoria. El diagnóstico muestra el archivo leído.
79
81
 
80
82
  **1.2.9 correcciones de idioma:** las pistas de vocabulario japonés solo se aplican al japonés; OpenAI/Anthropic reciben el nombre completo del idioma. Bing usa `auto-detect` y `zh-Hans`/`zh-Hant`. La detección del chino excluye rutas, código y JSON: omite la prosa ya simplificada, solicita conversión al detectar caracteres tradicionales frecuentes y traduce la prosa japonesa/coreana. Se elimina una vez la caché de traducciones anterior, conservando los ajustes.
package/README.fr.md CHANGED
@@ -75,6 +75,8 @@ Pour DSH **0.2.0-rc.2**, utilisez **dsh-think-translate 1.2.5 ou une version ult
75
75
 
76
76
  **1.2.8 transport et reprise :** les traductions HTTP/HTTPS ordinaires utilisent le réseau natif de Node au lieu de lancer curl pour chaque lot de texte. Les proxys SOCKS et l’installateur Ollama conservent curl. Les échecs restent en mémoire pendant 30 secondes, puis les traductions du raisonnement et des réponses sont réessayées automatiquement. Les délais tiennent compte du chargement des modèles locaux et du recours à d’autres fournisseurs.
77
77
 
78
+ **1.2.11 corrections de Bing :** le fournisseur gratuit est conservé. Les requêtes de traduction utilisent l’origine finale de la page de session pour éviter que la redirection `www.bing.com` → `cn.bing.com` en Chine continentale supprime le corps POST. SOCKS/curl utilise les mêmes en-têtes de navigateur que le transport natif pour corriger HTTP 401 ; les réponses vides ou non JSON signalent des erreurs explicites.
79
+
78
80
  **1.2.10 compatibilité des profils DSH :** la détection suit le profil Desktop/Web actif et lit `profiles/<profile>/cordis.patch.yml` (`id` + `config`), puis applique les correctifs du répertoire DSH et les surcharges de lancement. L’ancien `settings.yaml` reste pris en charge. Le modèle par défaut utilise `default-model` ; les identifiants restent dans `.credentials.yaml` du répertoire DSH et en mémoire uniquement. Le diagnostic indique le fichier lu.
79
81
 
80
82
  **1.2.9 corrections linguistiques :** les indications de vocabulaire japonais ne concernent que le japonais ; OpenAI/Anthropic reçoivent le nom complet de la langue. Bing utilise `auto-detect` et `zh-Hans`/`zh-Hant`. La détection du chinois écarte chemins, code et JSON : elle ignore la prose déjà simplifiée, demande une conversion en présence de caractères traditionnels courants et traduit la prose japonaise/coréenne. Les anciennes traductions en cache sont supprimées une fois, sans toucher aux réglages.
package/README.ja.md CHANGED
@@ -75,6 +75,8 @@ DSH **0.2.0-rc.2** では **dsh-think-translate 1.2.5 以降**を使用してく
75
75
 
76
76
  **1.2.8 通信と復帰:**通常の HTTP/HTTPS 翻訳は、テキストのバッチごとに curl を起動せず Node の標準ネットワーク機能を使います。SOCKS プロキシと Ollama インストーラーは引き続き curl に対応します。失敗結果をメモリ内に30秒間保持し、その後は思考・回答の翻訳を自動再試行します。タイムアウトはローカルモデルのロードと代替プロバイダーへの切り替えを考慮しています。
77
77
 
78
+ **1.2.11 Bing 修正:**無料の Bing を引き続き提供します。翻訳リクエストはセッションページの最終オリジンに送信し、中国本土の `www.bing.com` → `cn.bing.com` リダイレクトによる POST 本文の消失を防ぎます。SOCKS/curl はネイティブ通信と同じブラウザーヘッダーを使用して HTTP 401 を修正。空の応答と JSON 以外の応答には明確なエラーを表示します。
79
+
78
80
  **1.2.10 DSH プロファイル対応:**実行中の Desktop/Web プロファイルに従い、`profiles/<profile>/cordis.patch.yml`(`id` + `config`)、DSH home のパッチ、起動時のオーバーレイを順に読み込みます。旧形式の `settings.yaml` も対応。既定モデル行は `default-model` に対応し、資格情報は DSH home の `.credentials.yaml` から解決してメモリ内だけに保持します。再スキャン時に実際の設定パスを表示します。
79
81
 
80
82
  **1.2.9 言語修正:**日本語の語彙ヒントは日本語の翻訳先に限定し、OpenAI/Anthropic に完全な言語名を渡します。Bing は `auto-detect` と `zh-Hans`/`zh-Hant` を使用。中国語の判定ではパス・コード・JSON を除外し、簡体字の本文はスキップ、よく使われる繁体字を検出すると変換を依頼、日本語・韓国語の本文は翻訳します。旧訳文キャッシュを一度削除し、設定は保持します。
package/README.ko.md CHANGED
@@ -75,6 +75,8 @@ DSH **0.2.0-rc.2**에서는 **dsh-think-translate 1.2.5 이상**을 사용하세
75
75
 
76
76
  **1.2.8 전송 및 복구:** 일반 HTTP/HTTPS 번역은 텍스트 배치마다 curl을 실행하는 대신 Node 기본 네트워크 기능을 사용합니다. SOCKS 프록시와 Ollama 설치 프로그램은 curl 호환 경로를 유지합니다. 실패 결과를 메모리에 30초간 보관한 뒤 사고·답변 번역을 자동 재시도합니다. 타임아웃은 로컬 모델 로드와 다른 제공자로의 전환 시간을 고려합니다.
77
77
 
78
+ **1.2.11 Bing 수정:** 무료 Bing 제공자를 유지합니다. 세션 페이지의 최종 출처로 번역 요청을 보내 중국 본토의 `www.bing.com` → `cn.bing.com` 리디렉션에서 POST 본문이 사라지는 문제를 방지합니다. SOCKS/curl도 네이티브 통신과 같은 브라우저 헤더를 사용해 HTTP 401을 수정하며, 빈 응답과 JSON이 아닌 응답에 명확한 오류를 표시합니다.
79
+
78
80
  **1.2.10 DSH 프로필 호환:** 실행 중인 Desktop/Web 프로필의 `profiles/<profile>/cordis.patch.yml`(`id` + `config`)을 읽고 DSH 홈 패치와 시작 오버레이를 순서대로 적용합니다. 이전 `settings.yaml`도 지원합니다. 기본 모델 행은 `default-model`을 지원하며 자격 증명은 DSH 홈의 `.credentials.yaml`에서 읽어 메모리에만 유지합니다. 다시 검사하면 실제 설정 경로가 표시됩니다.
79
81
 
80
82
  **1.2.9 언어 수정:** 일본어 어휘 힌트는 일본어 대상에만 적용하며 OpenAI/Anthropic에 전체 언어 이름을 전달합니다. Bing은 `auto-detect`와 `zh-Hans`/`zh-Hant`를 사용합니다. 중국어 감지 시 경로·코드·JSON을 제외하고, 이미 간체인 본문은 건너뛰며 자주 쓰는 번체 글자를 감지하면 변환을 요청합니다. 일본어·한국어 본문은 번역합니다. 이전 번역 캐시만 한 번 삭제하고 설정은 유지합니다.
package/README.md CHANGED
@@ -72,6 +72,8 @@ Version **1.2.6** fixes duplicated thinking and answer text in DSH 0.2: the assi
72
72
 
73
73
  **1.2.8 transport and recovery:** ordinary HTTP/HTTPS translation requests use native Node networking instead of spawning curl per text batch; SOCKS proxies and the Ollama installer retain curl compatibility. Failures stay in memory for 30 seconds, then reasoning and answer translation resume automatically. Request deadlines allow time for local-model loading and provider fallback.
74
74
 
75
+ **1.2.11 Bing fixes:** the free Bing provider is retained. Translation requests use the session page's final origin, preventing the mainland China `www.bing.com` → `cn.bing.com` redirect from dropping the POST body. SOCKS/curl now shares the native browser headers to fix HTTP 401; empty and non-JSON responses report clear errors.
76
+
75
77
  **1.2.10 DSH profile compatibility:** discovery follows the running Desktop/Web profile and reads `profiles/<profile>/cordis.patch.yml` (`id` + `config`), with home patches and launcher overlays applied afterward. Legacy `settings.yaml` is still supported. Default model rows use `default-model`; credentials remain in the DSH home `.credentials.yaml` and stay in memory. Rescan diagnostics show the file actually read.
76
78
 
77
79
  **1.2.9 language fixes:** Japanese vocabulary hints now apply only to Japanese targets; OpenAI/Anthropic requests include a full language name. Bing uses `auto-detect` and maps Chinese targets to `zh-Hans`/`zh-Hant`. Chinese detection examines prose after removing paths, code and JSON: already-Simplified prose is skipped, common Traditional script cues request conversion, and Japanese/Korean prose is translated. Old persisted translation results are cleared once; settings remain intact.
package/README.ru.md CHANGED
@@ -75,6 +75,8 @@ New-Item -ItemType Junction -Path "$HOME\.dsh\profiles\node_modules\dsh-think-tr
75
75
 
76
76
  **1.2.8 передача запросов и восстановление:** обычные HTTP/HTTPS-запросы перевода используют сетевые средства Node без запуска curl для каждого пакета текста. Для SOCKS-прокси и установщика Ollama сохранён путь через curl. Ошибки хранятся в памяти 30 секунд, после чего перевод рассуждений и ответов автоматически повторяется. Тайм-ауты учитывают загрузку локальной модели и переход к другим провайдерам.
77
77
 
78
+ **1.2.11 исправления Bing:** бесплатный провайдер сохранён. Запросы перевода отправляются на конечный origin страницы сеанса, чтобы перенаправление `www.bing.com` → `cn.bing.com` в материковом Китае не удаляло тело POST. SOCKS/curl использует те же заголовки браузера, что и нативный транспорт, устраняя HTTP 401; пустые ответы и ответы не в формате JSON дают понятные ошибки.
79
+
78
80
  **1.2.10 совместимость с профилями DSH:** обнаружение следует активному профилю Desktop/Web и читает `profiles/<profile>/cordis.patch.yml` (`id` + `config`), затем патчи домашнего каталога DSH и параметры запуска. Прежний `settings.yaml` поддерживается. Модель по умолчанию использует `default-model`; ключи читаются из `.credentials.yaml` домашнего каталога DSH и остаются только в памяти. Диагностика показывает прочитанный файл.
79
81
 
80
82
  **1.2.9 языковые исправления:** подсказки японской лексики применяются только к японскому; OpenAI/Anthropic получают полное название языка. Bing использует `auto-detect` и `zh-Hans`/`zh-Hant`. Определение китайского исключает пути, код и JSON: упрощённая проза пропускается, частые традиционные иероглифы вызывают запрос преобразования, японская/корейская проза переводится. Старый кэш переводов очищается один раз, настройки сохраняются.
package/README.zh-CN.md CHANGED
@@ -75,6 +75,8 @@ DSH **0.2.0-rc.2** 请使用 **dsh-think-translate 1.2.5 或更新版本**。1.2
75
75
 
76
76
  **1.2.8 传输与恢复:**普通 HTTP/HTTPS 翻译请求改用 Node 原生网络,不再为每个文本批次启动 curl;SOCKS 代理和 Ollama 安装器保留 curl 兼容路径。失败结果在内存缓存 30 秒,冷却结束后思考与回答翻译会自动恢复重试。请求超时为本地模型加载和提供方回退留出时间。
77
77
 
78
+ **1.2.11 Bing 修复:**保留免费 Bing 通道。翻译请求跟随会话页最终域名,避免国内 `www.bing.com` → `cn.bing.com` 跳转丢失 POST 正文;SOCKS/curl 同步原生浏览器请求头,修复 HTTP 401。空响应和非 JSON 响应给出明确错误。
79
+
78
80
  **1.2.10 DSH 配置兼容:**发现提供方时跟随当前 Desktop/Web profile,读取 `profiles/<profile>/cordis.patch.yml`(`id` + `config`),随后应用 home 补丁与启动覆盖;继续支持旧版 `settings.yaml`。默认模型行支持 `default-model`,凭据仍从 DSH home 的 `.credentials.yaml` 解析且只留在内存;重新扫描会显示实际读取的配置路径。
79
81
 
80
82
  **1.2.9 语言修复:**日语词汇提示仅用于日语目标,OpenAI/Anthropic 请求带上完整语言名称。Bing 使用 `auto-detect`,并将中文目标映射为 `zh-Hans`/`zh-Hant`。中文检测先排除路径、代码和 JSON:已是简体的正文跳过,常用繁体区别字触发转换请求,日语/韩语正文正常翻译。升级时一次性清理旧译文缓存,保留设置。
package/lib/client.js CHANGED
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
23
23
  // there yet (an older process still serving the port), and the contract test
24
24
  // pins PLUGIN_VERSION to package.json so the two can never drift.
25
25
  var PLUGIN_NAME = "dsh-think-translate";
26
- var PLUGIN_VERSION = "1.2.10";
26
+ var PLUGIN_VERSION = "1.2.11";
27
27
  var PLUGIN_REPO = "https://github.com/UncleK/dsh-think-translate";
28
28
  // The official MarkdownText contract changed in 0.1.2-alpha: it now takes a
29
29
  // nested `labels` object and dereferences it without defaults inside its code
package/lib/index.js CHANGED
@@ -11,7 +11,7 @@ import { tmpdir } from 'node:os'
11
11
  import { randomUUID } from 'node:crypto'
12
12
  import { createLocalPreparation, ollamaOrigin, localFirst, validOllamaSignature } from './ollama.js'
13
13
  import { fileURLToPath } from 'node:url'
14
- import { requestText, isLoopback } from './transport.js'
14
+ import { requestTextInfo, isLoopback, DEFAULT_HEADERS } from './transport.js'
15
15
  import { scanDshProviders, extractDshProviders, extractCredRefs, extractHarnessDefaultRoute } from './discovery.js'
16
16
 
17
17
  export const name = 'dsh-think-translate'
@@ -332,24 +332,39 @@ async function curlArgs(extra) {
332
332
  return args.concat(extra)
333
333
  }
334
334
 
335
- async function httpFetch(url, options = {}, timeoutMs = 25000) {
335
+ async function httpFetch(url, options = {}, timeoutMs = 25000, wantInfo = false) {
336
336
  const proxy = isLoopback(url) ? null : await getProxy()
337
337
  if (proxy && /^socks/i.test(proxy)) {
338
338
  const extra = ['--fail', '-L', '--max-time', String(Math.ceil(timeoutMs / 1000)), '-X', options.method || 'GET']
339
- for (const [key, value] of Object.entries(options.headers || {})) extra.push('-H', key + ': ' + value)
339
+ // Bing rejects the default curl user agent with HTTP 401. Keep both
340
+ // transports' session and translation headers consistent.
341
+ for (const [key, value] of Object.entries({ ...DEFAULT_HEADERS, ...options.headers })) extra.push('-H', key + ': ' + value)
340
342
  if (options.body !== undefined) extra.push('--data-binary', options.body)
343
+ const marker = '\n__DSH_RESPONSE_INFO__\n'
344
+ if (wantInfo) extra.push('-w', marker + '%{url_effective}\n%{http_code}')
341
345
  extra.push(url)
342
- return runProgram('curl', await curlArgs(extra), timeoutMs + 5000)
346
+ const out = await runProgram('curl', await curlArgs(extra), timeoutMs + 5000)
347
+ if (!wantInfo) return out
348
+ const at = out.lastIndexOf(marker)
349
+ if (at < 0) throw new Error('curl response metadata missing')
350
+ const [finalUrl, status] = out.slice(at + marker.length).trim().split(/\r?\n/)
351
+ if (!/^https?:\/\//i.test(finalUrl) || !/^\d{3}$/.test(status)) throw new Error('curl response metadata invalid')
352
+ return { text: out.slice(0, at), url: finalUrl, status: Number(status) }
343
353
  }
344
354
  // A failed proxy request is a provider failure. Do not silently bypass the
345
355
  // configured proxy or send a second copy of a potentially billable POST.
346
- return requestText(url, { ...options, proxy, timeoutMs })
356
+ const result = await requestTextInfo(url, { ...options, proxy, timeoutMs })
357
+ return wantInfo ? result : result.text
347
358
  }
348
359
 
349
360
  async function curlGet(url, timeoutMs = 25000) {
350
361
  return httpFetch(url, { method: 'GET' }, timeoutMs)
351
362
  }
352
363
 
364
+ async function curlGetInfo(url, timeoutMs = 25000) {
365
+ return httpFetch(url, { method: 'GET' }, timeoutMs, true)
366
+ }
367
+
353
368
  async function curlPostForm(url, form, timeoutMs = 25000) {
354
369
  return httpFetch(url, {
355
370
  method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: form,
@@ -405,13 +420,17 @@ async function viaGoogle(text, to) {
405
420
 
406
421
  async function bingSession() {
407
422
  if (bingCache !== null && Date.now() < bingCache.exp) return bingCache
408
- const html = await curlGet('https://www.bing.com/translator')
423
+ const page = await curlGetInfo('https://www.bing.com/translator')
424
+ const html = page.text
409
425
  const ig = html.match(/IG:"([^"]+)"/)
410
426
  const ab = html.match(/params_AbusePreventionHelper\s*=\s*\[([^\]]*)\]/)
411
427
  if (!ig || !ab) throw new Error('bing page shape changed')
412
428
  const parts = ab[1].split(',').map(function (s) { return s.trim().replace(/^"/, '').replace(/"$/, '') })
413
429
  if (parts.length < 2 || !parts[0] || !parts[1]) throw new Error('bing params empty')
414
- bingCache = { ig: ig[1], key: parts[0], token: parts[1], exp: Date.now() + 50 * 60 * 1000 }
430
+ const translator = html.match(/<[^>]*\bid\s*=\s*["']rich_tta["'][^>]*>/i)
431
+ const iid = translator && translator[0].match(/\bdata-iid\s*=\s*["']([^"']+)["']/i)
432
+ bingCache = { ig: ig[1], key: parts[0], token: parts[1],
433
+ origin: new URL(page.url).origin, iid: iid ? iid[1] : 'SERP', exp: Date.now() + 50 * 60 * 1000 }
415
434
  return bingCache
416
435
  }
417
436
 
@@ -425,12 +444,12 @@ function bingTarget(to) {
425
444
  async function viaBing(text, to) {
426
445
  const s = await bingSession()
427
446
  const form = 'fromLang=auto-detect&text=' + encodeURIComponent(text) + '&to=' + encodeURIComponent(bingTarget(to)) + '&token=' + encodeURIComponent(s.token) + '&key=' + encodeURIComponent(s.key)
428
- // The current translator page builds /ttranslatev3?isVertical=1 (the old
429
- // isIntl=1 param is gone); curlPostForm follows redirects (-L), so CN users
430
- // get auto-redirected www.bing.com -> cn.bing.com while the rest of the
431
- // world stays on www.bing.com.
432
- const raw = await curlPostForm('https://www.bing.com/ttranslatev3?isVertical=1&IG=' + encodeURIComponent(s.ig) + '&IID=SERP', form)
433
- const arr = JSON.parse(raw)
447
+ // CN networks redirect the session page to cn.bing.com. Post back to that
448
+ // origin: following a 302 on the POST itself would discard the form body.
449
+ const raw = await curlPostForm(s.origin + '/ttranslatev3?isVertical=1&IG=' + encodeURIComponent(s.ig) + '&IID=' + encodeURIComponent(s.iid), form)
450
+ if (!raw || !raw.trim()) throw new Error('bing empty response')
451
+ let arr
452
+ try { arr = JSON.parse(raw) } catch { throw new Error('bing non-JSON response') }
434
453
  if (!Array.isArray(arr) && arr && arr.statusCode) throw new Error('bing API ' + arr.statusCode + ': ' + (arr.errorMessage || 'request rejected'))
435
454
  const tr = Array.isArray(arr) && arr[0] && arr[0].translations && arr[0].translations[0]
436
455
  if (!tr || typeof tr.text !== 'string' || !tr.text.trim()) throw new Error('bing empty translation')
package/lib/transport.js CHANGED
@@ -3,6 +3,11 @@ import https from 'node:https'
3
3
  import tls from 'node:tls'
4
4
  import { isIP } from 'node:net'
5
5
 
6
+ export const DEFAULT_HEADERS = {
7
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
8
+ Accept: 'application/json,text/plain,*/*',
9
+ }
10
+
6
11
  export function isLoopback(url) {
7
12
  const host = new URL(url).hostname.replace(/^\[|\]$/g, '').toLowerCase()
8
13
  return ['localhost', '127.0.0.1', '::1', '::ffff:7f00:1'].includes(host)
@@ -101,11 +106,12 @@ function requestOnce(url, options) {
101
106
  })
102
107
  }
103
108
 
104
- export async function requestText(urlString, options = {}) {
109
+ // Report the final URL so session-based callers can post back to the origin
110
+ // that served their page instead of redirecting a POST and losing its body.
111
+ export async function requestTextInfo(urlString, options = {}) {
105
112
  let url = new URL(urlString)
106
113
  let method = options.method || 'GET', body = options.body
107
- let headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
108
- Accept: 'application/json,text/plain,*/*', ...options.headers }
114
+ let headers = { ...DEFAULT_HEADERS, ...options.headers }
109
115
  const deadline = Date.now() + (options.timeoutMs || 25000)
110
116
  for (let redirects = 0; redirects <= 5; redirects++) {
111
117
  if (!['http:', 'https:'].includes(url.protocol)) throw new Error('Unsupported request protocol: ' + url.protocol)
@@ -130,6 +136,10 @@ export async function requestText(urlString, options = {}) {
130
136
  continue
131
137
  }
132
138
  if (response.status < 200 || response.status >= 300) throw new Error('HTTP ' + response.status)
133
- return response.text
139
+ return { text: response.text, url: url.href, status: response.status }
134
140
  }
135
141
  }
142
+
143
+ export async function requestText(urlString, options = {}) {
144
+ return (await requestTextInfo(urlString, options)).text
145
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-think-translate",
3
3
  "description": "Display-layer translation for the DSH web app: thinking chain, task cards, and optional answer text, in 8 target languages (local Ollama / any OpenAI-compatible or Anthropic endpoint / Google / Bing, fail-open)",
4
- "version": "1.2.10",
4
+ "version": "1.2.11",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {