dsh-read-url 1.7.0 → 1.8.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-read-url",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "DeepSeek Harness URL reader: fetch any webpage (HTML/JSON/RSS/Atom), auto-detect encoding (UTF-16 BOM/GBK/Big5/Shift-JIS), extract clean main content with auto-pagination, output compact text/Markdown to save tokens. Zero runtime dependencies, no API key, drop-in. Follows meta-refresh shells, reads JSON-LD metadata, honors base href.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/proxy-fallback.js CHANGED
@@ -23,6 +23,19 @@ import { execFile, execFileSync } from 'node:child_process'
23
23
  export function looksBinary(buffer) {
24
24
  const n = Math.min(buffer.length, 512)
25
25
  if (!n) return false
26
+ const utf16le = buffer[0] === 0xff && buffer[1] === 0xfe
27
+ const utf16be = buffer[0] === 0xfe && buffer[1] === 0xff
28
+ if ((utf16le || utf16be) && buffer.length % 2 === 0) {
29
+ let controls = 0
30
+ let units = 0
31
+ for (let i = 2; i + 1 < n; i += 2) {
32
+ const code = utf16le ? buffer[i] | (buffer[i + 1] << 8) : (buffer[i] << 8) | buffer[i + 1]
33
+ if (code === 0) return true
34
+ if (code < 9 || (code > 13 && code < 32)) controls++
35
+ units++
36
+ }
37
+ return units > 0 && controls / units > 0.3
38
+ }
26
39
  let ctrl = 0
27
40
  for (let i = 0; i < n; i++) {
28
41
  const b = buffer[i]
@@ -32,6 +45,14 @@ export function looksBinary(buffer) {
32
45
  return ctrl / n > 0.3
33
46
  }
34
47
 
48
+ // Shared by direct and proxy retrieval so a document's route cannot change
49
+ // which text formats are accepted. Structured suffixes include vendor APIs.
50
+ export function isFetchableContentType(contentType) {
51
+ const mime = (contentType || '').split(';', 1)[0].trim().toLowerCase()
52
+ return ['text/html', 'application/xhtml+xml', 'text/plain', 'text/markdown', 'text/csv', 'application/json', 'text/json', 'application/xml', 'text/xml'].includes(mime) ||
53
+ /^[a-z][a-z0-9!#$&^_.+-]{0,63}\/(?:[a-z0-9!#$&^_.+-]{1,127}\+)?(?:json|xml)$/.test(mime)
54
+ }
55
+
35
56
  let sysProxyCache = null // '' = checked & absent; string = proxy URL
36
57
  let sysProxyCheckedAt = 0 // cache timestamp; a failed read is re-tried after 60s
37
58
  const SYS_PROXY_RETRY_MS = 60 * 1000
@@ -129,7 +150,7 @@ export async function fetchViaCurlProxy(url, cfg, externalSignal, proxyOverride)
129
150
  }
130
151
  }
131
152
  if (!(code >= 200 && code < 300)) return { error: `HTTP ${code}` }
132
- if (contentType && !/text\/html|application\/xhtml|text\/plain|\/json|[+/]xml/i.test(contentType)) {
153
+ if (contentType && !isFetchableContentType(contentType)) {
133
154
  return { error: `Unsupported content-type: ${contentType.split(';')[0]}` }
134
155
  }
135
156
  return { buffer: body, contentType, finalUrl: finalUrlEff, viaProxy: proxy }