dsh-pocket 1.5.0 → 1.6.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.
Files changed (2) hide show
  1. package/lib/proxy.mjs +32 -0
  2. package/package.json +1 -1
package/lib/proxy.mjs CHANGED
@@ -13,6 +13,7 @@
13
13
 
14
14
  import { createServer } from 'node:http';
15
15
  import { request as httpRequest } from 'node:http';
16
+ import { createGzip, createBrotliCompress } from 'node:zlib';
16
17
 
17
18
  const DEFAULT_UPSTREAM = { host: '127.0.0.1', port: 3080 };
18
19
 
@@ -98,6 +99,37 @@ export function createPocketProxy({ port = 3081, host = '0.0.0.0', upstream = DE
98
99
  proxyRes.on('error', () => res.destroy());
99
100
  return;
100
101
  }
102
+ // 大 JSON/text 响应**流式压缩**(issue #12):长会话历史一次返回 17MB+,
103
+ // 局域网直连与隧道段都吃满带宽;压缩到 ~1.3MB。跳过已压缩、SSE 流
104
+ // (/api/events.* 原样透传)、HTML(走上面的注入分支)。
105
+ const acceptEncoding = String(req.headers['accept-encoding'] ?? '');
106
+ const canGzip = /\bgzip\b/.test(acceptEncoding);
107
+ const canBr = /\bbr\b/.test(acceptEncoding);
108
+ const isEventStream = contentType.includes('text/event-stream');
109
+ const knownLen = Number(proxyRes.headers['content-length'] || 0);
110
+ const shouldCompress = (canGzip || canBr)
111
+ && !isCompressed(proxyRes.headers)
112
+ && !isEventStream
113
+ && (contentType.includes('application/json') || contentType.startsWith('text/'))
114
+ && (knownLen === 0 || knownLen >= 1024);
115
+ if (shouldCompress) {
116
+ const enc = canBr ? 'br' : 'gzip';
117
+ const outHeaders = { ...proxyRes.headers };
118
+ delete outHeaders['content-length'];
119
+ delete outHeaders['transfer-encoding'];
120
+ outHeaders['content-encoding'] = enc;
121
+ res.writeHead(proxyRes.statusCode ?? 200, outHeaders);
122
+ const z = enc === 'br' ? createBrotliCompress() : createGzip();
123
+ proxyRes.pipe(z).pipe(res);
124
+ // 任一端断开都要清理(含压缩流)。注意:不能用 proxyRes 的 'close'
125
+ // 来掐 res——正常结束后 close 也会触发,此时压缩流可能还没写完,
126
+ // 会误杀连接;异常中止用 'aborted'。
127
+ res.on('close', () => { proxyRes.destroy(); z.destroy(); });
128
+ proxyRes.on('error', () => { z.destroy(); res.destroy(); });
129
+ proxyRes.on('aborted', () => { z.destroy(); res.destroy(); });
130
+ z.on('error', () => res.destroy());
131
+ return;
132
+ }
101
133
  res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
102
134
  proxyRes.pipe(res);
103
135
  // 任一端断开都要清理另一端:客户端断连销毁上游流(不留僵尸),
package/package.json CHANGED
@@ -76,5 +76,5 @@
76
76
  "access": "public",
77
77
  "registry": "https://registry.npmjs.org/"
78
78
  },
79
- "version": "1.5.0"
79
+ "version": "1.6.0"
80
80
  }