com.jimuwd.xian.registry-proxy 1.0.15 → 1.0.17

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 (3) hide show
  1. package/dist/index.js +12 -10
  2. package/package.json +1 -1
  3. package/src/index.ts +19 -18
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createServer } from 'http';
3
3
  import { createServer as createHttpsServer } from 'https';
4
- import { readFileSync, promises as fsPromises } from 'fs';
4
+ import { promises as fsPromises, readFileSync } from 'fs';
5
5
  import { load } from 'js-yaml';
6
6
  import fetch from 'node-fetch';
7
7
  import { homedir } from 'os';
@@ -39,13 +39,21 @@ const limiter = new ConcurrencyLimiter(5); // 限制为 5 个并发请求
39
39
  function normalizeUrl(url) {
40
40
  try {
41
41
  const urlObj = new URL(url);
42
+ // 规范化端口
42
43
  if (urlObj.protocol === 'http:' && (urlObj.port === '80' || urlObj.port === '')) {
43
44
  urlObj.port = '';
44
45
  }
45
46
  else if (urlObj.protocol === 'https:' && (urlObj.port === '443' || urlObj.port === '')) {
46
47
  urlObj.port = '';
47
48
  }
48
- if (!urlObj.pathname.endsWith('/')) {
49
+ // 处理路径末尾斜杠
50
+ const pathname = urlObj.pathname;
51
+ if (pathname.endsWith('.tgz') || pathname.endsWith('.tgz/')) {
52
+ // tarball 文件,去除末尾斜杠
53
+ urlObj.pathname = pathname.replace(/\/+$/, '');
54
+ }
55
+ else if (!pathname.endsWith('/')) {
56
+ // 注册表根路径,确保末尾有斜杠
49
57
  urlObj.pathname += '/';
50
58
  }
51
59
  console.debug(`Normalized URL: ${url} -> ${urlObj.toString()}`);
@@ -53,13 +61,11 @@ function normalizeUrl(url) {
53
61
  }
54
62
  catch (e) {
55
63
  console.error(`Invalid URL: ${url}`, e);
56
- return url.endsWith('/') ? url : `${url}/`;
64
+ return url.endsWith('/') ? url.slice(0, -1) : url; // 默认去除末尾斜杠
57
65
  }
58
66
  }
59
67
  function resolvePath(path) {
60
- const resolved = path.startsWith('~/') ? join(homedir(), path.slice(2)) : resolve(path);
61
- console.debug(`Resolved path: ${path} -> ${resolved}`);
62
- return resolved;
68
+ return path.startsWith('~/') ? join(homedir(), path.slice(2)) : resolve(path);
63
69
  }
64
70
  function removeRegistryPrefix(tarballUrl, registries) {
65
71
  try {
@@ -176,7 +182,6 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
176
182
  const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
177
183
  const response = await fetch(targetUrl, { headers });
178
184
  console.log(`Response from ${url}: ${response.status} ${response.statusText}`);
179
- console.debug(`Response headers from ${url}:`, Object.fromEntries(response.headers.entries()));
180
185
  return response.ok ? response : null;
181
186
  }
182
187
  catch (e) {
@@ -195,7 +200,6 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
195
200
  return;
196
201
  }
197
202
  const contentType = successResponse.headers.get('Content-Type') || 'application/octet-stream';
198
- console.debug(`Content-Type: ${contentType}`);
199
203
  if (contentType.includes('application/json')) {
200
204
  try {
201
205
  const data = await successResponse.json();
@@ -231,7 +235,6 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
231
235
  'Content-Type': successResponse.headers.get('Content-Type'),
232
236
  'Content-Length': successResponse.headers.get('Content-Length'),
233
237
  };
234
- console.debug(`Streaming response with headers:`, safeHeaders);
235
238
  res.writeHead(successResponse.status, safeHeaders);
236
239
  successResponse.body.pipe(res).on('error', (err) => {
237
240
  console.error(`Stream error for ${relativePath}:`, err);
@@ -244,7 +247,6 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
244
247
  const { key, cert } = proxyConfig.https;
245
248
  const keyPath = resolvePath(key);
246
249
  const certPath = resolvePath(cert);
247
- console.debug(`Loading HTTPS key: ${keyPath}, cert: ${certPath}`);
248
250
  try {
249
251
  await fsPromises.access(keyPath);
250
252
  await fsPromises.access(certPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "type": "module",
5
5
  "description": "A lightweight npm registry proxy with fallback support",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { createServer, Server as HttpServer } from 'http';
3
- import { createServer as createHttpsServer, Server as HttpsServer } from 'https';
4
- import { readFileSync, promises as fsPromises } from 'fs';
5
- import { AddressInfo } from 'net';
6
- import { load } from 'js-yaml';
7
- import fetch, { Response } from 'node-fetch';
8
- import { homedir } from 'os';
9
- import { join, resolve } from 'path';
10
- import { URL } from 'url';
2
+ import {createServer, Server as HttpServer} from 'http';
3
+ import {createServer as createHttpsServer, Server as HttpsServer} from 'https';
4
+ import {promises as fsPromises, readFileSync} from 'fs';
5
+ import {AddressInfo} from 'net';
6
+ import {load} from 'js-yaml';
7
+ import fetch, {Response} from 'node-fetch';
8
+ import {homedir} from 'os';
9
+ import {join, resolve} from 'path';
10
+ import {URL} from 'url';
11
11
 
12
12
  const { readFile, writeFile } = fsPromises;
13
13
 
@@ -59,26 +59,31 @@ const limiter = new ConcurrencyLimiter(5); // 限制为 5 个并发请求
59
59
  function normalizeUrl(url: string): string {
60
60
  try {
61
61
  const urlObj = new URL(url);
62
+ // 规范化端口
62
63
  if (urlObj.protocol === 'http:' && (urlObj.port === '80' || urlObj.port === '')) {
63
64
  urlObj.port = '';
64
65
  } else if (urlObj.protocol === 'https:' && (urlObj.port === '443' || urlObj.port === '')) {
65
66
  urlObj.port = '';
66
67
  }
67
- if (!urlObj.pathname.endsWith('/')) {
68
+ // 处理路径末尾斜杠
69
+ const pathname = urlObj.pathname;
70
+ if (pathname.endsWith('.tgz') || pathname.endsWith('.tgz/')) {
71
+ // tarball 文件,去除末尾斜杠
72
+ urlObj.pathname = pathname.replace(/\/+$/, '');
73
+ } else if (!pathname.endsWith('/')) {
74
+ // 注册表根路径,确保末尾有斜杠
68
75
  urlObj.pathname += '/';
69
76
  }
70
77
  console.debug(`Normalized URL: ${url} -> ${urlObj.toString()}`);
71
78
  return urlObj.toString();
72
79
  } catch (e) {
73
80
  console.error(`Invalid URL: ${url}`, e);
74
- return url.endsWith('/') ? url : `${url}/`;
81
+ return url.endsWith('/') ? url.slice(0, -1) : url; // 默认去除末尾斜杠
75
82
  }
76
83
  }
77
84
 
78
85
  function resolvePath(path: string): string {
79
- const resolved = path.startsWith('~/') ? join(homedir(), path.slice(2)) : resolve(path);
80
- console.debug(`Resolved path: ${path} -> ${resolved}`);
81
- return resolved;
86
+ return path.startsWith('~/') ? join(homedir(), path.slice(2)) : resolve(path);
82
87
  }
83
88
 
84
89
  function removeRegistryPrefix(tarballUrl: string, registries: RegistryInfo[]): string {
@@ -215,7 +220,6 @@ export async function startProxyServer(
215
220
  const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
216
221
  const response = await fetch(targetUrl, { headers });
217
222
  console.log(`Response from ${url}: ${response.status} ${response.statusText}`);
218
- console.debug(`Response headers from ${url}:`, Object.fromEntries(response.headers.entries()));
219
223
  return response.ok ? response : null;
220
224
  } catch (e) {
221
225
  console.error(`Failed to fetch from ${url}:`, e);
@@ -234,7 +238,6 @@ export async function startProxyServer(
234
238
  }
235
239
 
236
240
  const contentType = successResponse.headers.get('Content-Type') || 'application/octet-stream';
237
- console.debug(`Content-Type: ${contentType}`);
238
241
  if (contentType.includes('application/json')) {
239
242
  try {
240
243
  const data = await successResponse.json() as PackageData;
@@ -268,7 +271,6 @@ export async function startProxyServer(
268
271
  'Content-Type': successResponse.headers.get('Content-Type'),
269
272
  'Content-Length': successResponse.headers.get('Content-Length'),
270
273
  };
271
- console.debug(`Streaming response with headers:`, safeHeaders);
272
274
  res.writeHead(successResponse.status, safeHeaders);
273
275
  successResponse.body.pipe(res).on('error', (err:any) => {
274
276
  console.error(`Stream error for ${relativePath}:`, err);
@@ -282,7 +284,6 @@ export async function startProxyServer(
282
284
  const { key, cert } = proxyConfig.https;
283
285
  const keyPath = resolvePath(key);
284
286
  const certPath = resolvePath(cert);
285
- console.debug(`Loading HTTPS key: ${keyPath}, cert: ${certPath}`);
286
287
  try {
287
288
  await fsPromises.access(keyPath);
288
289
  await fsPromises.access(certPath);