com.jimuwd.xian.registry-proxy 1.0.35 → 1.0.36
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/dist/index.js +66 -24
- package/package.json +1 -1
- package/src/index.ts +70 -29
package/dist/index.js
CHANGED
|
@@ -161,36 +161,78 @@ async function fetchFromRegistry(registry, path, search, limiter) {
|
|
|
161
161
|
limiter.release();
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
+
// 修改后的 writeResponse 函数
|
|
164
165
|
async function writeResponse(res, response, req, proxyInfo, proxyPort, registryInfos) {
|
|
165
166
|
const contentType = response.headers.get('Content-Type') || 'application/octet-stream';
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
167
|
+
// 准备通用头信息
|
|
168
|
+
const safeHeaders = {
|
|
169
|
+
'content-type': contentType,
|
|
170
|
+
'connection': 'keep-alive'
|
|
171
|
+
};
|
|
172
|
+
// 复制所有可能需要的头信息
|
|
173
|
+
const headersToCopy = [
|
|
174
|
+
'cache-control', 'etag', 'last-modified',
|
|
175
|
+
'content-encoding', 'content-length'
|
|
176
|
+
];
|
|
177
|
+
headersToCopy.forEach(header => {
|
|
178
|
+
const value = response.headers.get(header);
|
|
179
|
+
if (value)
|
|
180
|
+
safeHeaders[header] = value;
|
|
181
|
+
});
|
|
182
|
+
try {
|
|
183
|
+
if (contentType.includes('application/json')) {
|
|
184
|
+
// JSON 处理逻辑
|
|
185
|
+
const data = await response.json();
|
|
186
|
+
if (data.versions) {
|
|
187
|
+
const host = req.headers.host || `localhost:${proxyPort}`;
|
|
188
|
+
const baseUrl = `${proxyInfo.https ? 'https' : 'http'}://${host}${proxyInfo.basePath === '/' ? '' : proxyInfo.basePath}`;
|
|
189
|
+
for (const version in data.versions) {
|
|
190
|
+
const tarball = data.versions[version]?.dist?.tarball;
|
|
191
|
+
if (tarball) {
|
|
192
|
+
const path = removeRegistryPrefix(tarball, registryInfos);
|
|
193
|
+
data.versions[version].dist.tarball = `${baseUrl}${path}${new URL(tarball).search || ''}`;
|
|
194
|
+
}
|
|
176
195
|
}
|
|
177
196
|
}
|
|
197
|
+
res.writeHead(200, safeHeaders);
|
|
198
|
+
res.end(JSON.stringify(data));
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// 二进制流处理
|
|
202
|
+
if (!response.body) {
|
|
203
|
+
console.error('Empty response body');
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
// 修复流类型转换问题
|
|
207
|
+
let nodeStream;
|
|
208
|
+
if (typeof Readable.fromWeb === 'function') {
|
|
209
|
+
// Node.js 17+ 标准方式
|
|
210
|
+
nodeStream = Readable.fromWeb(response.body);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// Node.js 16 及以下版本的兼容方案
|
|
214
|
+
const { PassThrough } = await import('stream');
|
|
215
|
+
const passThrough = new PassThrough();
|
|
216
|
+
const reader = response.body.getReader();
|
|
217
|
+
const pump = async () => {
|
|
218
|
+
const { done, value } = await reader.read();
|
|
219
|
+
if (done)
|
|
220
|
+
return passThrough.end();
|
|
221
|
+
passThrough.write(value);
|
|
222
|
+
await pump();
|
|
223
|
+
};
|
|
224
|
+
pump().catch(err => passThrough.destroy(err));
|
|
225
|
+
nodeStream = passThrough;
|
|
226
|
+
}
|
|
227
|
+
res.writeHead(response.status, safeHeaders);
|
|
228
|
+
await pipeline(nodeStream, res);
|
|
178
229
|
}
|
|
179
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
180
|
-
res.end(JSON.stringify(data));
|
|
181
230
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
'
|
|
186
|
-
}
|
|
187
|
-
['cache-control', 'etag', 'last-modified', 'content-encoding'].forEach(header => {
|
|
188
|
-
const value = response.headers.get(header);
|
|
189
|
-
if (value)
|
|
190
|
-
safeHeaders[header] = value;
|
|
191
|
-
});
|
|
192
|
-
res.writeHead(response.status, safeHeaders);
|
|
193
|
-
await pipeline(Readable.fromWeb(response.body), res);
|
|
231
|
+
catch (err) {
|
|
232
|
+
console.error('Failed to write response:', err);
|
|
233
|
+
if (!res.headersSent) {
|
|
234
|
+
res.writeHead(502).end('Internal Server Error');
|
|
235
|
+
}
|
|
194
236
|
}
|
|
195
237
|
}
|
|
196
238
|
export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ interface PackageData {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
class ConcurrencyLimiter {
|
|
55
|
-
private maxConcurrency: number;
|
|
55
|
+
private readonly maxConcurrency: number;
|
|
56
56
|
private current: number = 0;
|
|
57
57
|
private queue: Array<() => void> = [];
|
|
58
58
|
|
|
@@ -215,6 +215,7 @@ async function fetchFromRegistry(
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
// 修改后的 writeResponse 函数
|
|
218
219
|
async function writeResponse(
|
|
219
220
|
res: ServerResponse,
|
|
220
221
|
response: Response,
|
|
@@ -225,38 +226,78 @@ async function writeResponse(
|
|
|
225
226
|
): Promise<void> {
|
|
226
227
|
const contentType = response.headers.get('Content-Type') || 'application/octet-stream';
|
|
227
228
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
229
|
+
// 准备通用头信息
|
|
230
|
+
const safeHeaders: OutgoingHttpHeaders = {
|
|
231
|
+
'content-type': contentType,
|
|
232
|
+
'connection': 'keep-alive'
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// 复制所有可能需要的头信息
|
|
236
|
+
const headersToCopy = [
|
|
237
|
+
'cache-control', 'etag', 'last-modified',
|
|
238
|
+
'content-encoding', 'content-length'
|
|
239
|
+
];
|
|
240
|
+
|
|
241
|
+
headersToCopy.forEach(header => {
|
|
242
|
+
const value = response.headers.get(header);
|
|
243
|
+
if (value) safeHeaders[header] = value;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
if (contentType.includes('application/json')) {
|
|
248
|
+
// JSON 处理逻辑
|
|
249
|
+
const data = await response.json() as PackageData;
|
|
250
|
+
if (data.versions) {
|
|
251
|
+
const host = req.headers.host || `localhost:${proxyPort}`;
|
|
252
|
+
const baseUrl = `${proxyInfo.https ? 'https' : 'http'}://${host}${proxyInfo.basePath === '/' ? '' : proxyInfo.basePath}`;
|
|
253
|
+
|
|
254
|
+
for (const version in data.versions) {
|
|
255
|
+
const tarball = data.versions[version]?.dist?.tarball;
|
|
256
|
+
if (tarball) {
|
|
257
|
+
const path = removeRegistryPrefix(tarball, registryInfos);
|
|
258
|
+
data.versions[version]!.dist!.tarball = `${baseUrl}${path}${new URL(tarball).search || ''}`;
|
|
259
|
+
}
|
|
239
260
|
}
|
|
240
261
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
262
|
+
res.writeHead(200, safeHeaders);
|
|
263
|
+
res.end(JSON.stringify(data));
|
|
264
|
+
} else {
|
|
265
|
+
// 二进制流处理
|
|
266
|
+
if (!response.body) {
|
|
267
|
+
console.error('Empty response body');
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
249
270
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
|
|
271
|
+
// 修复流类型转换问题
|
|
272
|
+
let nodeStream: NodeJS.ReadableStream;
|
|
273
|
+
if (typeof Readable.fromWeb === 'function') {
|
|
274
|
+
// Node.js 17+ 标准方式
|
|
275
|
+
nodeStream = Readable.fromWeb(response.body as any);
|
|
276
|
+
} else {
|
|
277
|
+
// Node.js 16 及以下版本的兼容方案
|
|
278
|
+
const { PassThrough } = await import('stream');
|
|
279
|
+
const passThrough = new PassThrough();
|
|
280
|
+
const reader = (response.body as any).getReader();
|
|
281
|
+
|
|
282
|
+
const pump = async () => {
|
|
283
|
+
const { done, value } = await reader.read();
|
|
284
|
+
if (done) return passThrough.end();
|
|
285
|
+
passThrough.write(value);
|
|
286
|
+
await pump();
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
pump().catch(err => passThrough.destroy(err));
|
|
290
|
+
nodeStream = passThrough;
|
|
291
|
+
}
|
|
254
292
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
);
|
|
293
|
+
res.writeHead(response.status, safeHeaders);
|
|
294
|
+
await pipeline(nodeStream, res);
|
|
295
|
+
}
|
|
296
|
+
} catch (err) {
|
|
297
|
+
console.error('Failed to write response:', err);
|
|
298
|
+
if (!res.headersSent) {
|
|
299
|
+
res.writeHead(502).end('Internal Server Error');
|
|
300
|
+
}
|
|
260
301
|
}
|
|
261
302
|
}
|
|
262
303
|
|