com.jimuwd.xian.registry-proxy 1.0.53 → 1.0.55

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 CHANGED
@@ -7,6 +7,7 @@ import fetch from 'node-fetch';
7
7
  import { homedir } from 'os';
8
8
  import { join, resolve } from 'path';
9
9
  import { URL } from 'url';
10
+ import logger from "./utils/logger";
10
11
  const { readFile, writeFile } = fsPromises;
11
12
  class ConcurrencyLimiter {
12
13
  maxConcurrency;
@@ -84,13 +85,13 @@ async function readProxyConfig(proxyConfigPath = './.registry-proxy.yml') {
84
85
  const content = await readFile(resolvedPath, 'utf8');
85
86
  const config = load(content);
86
87
  if (!config.registries) {
87
- console.error('Missing required "registries" field in config');
88
+ logger.error('Missing required "registries" field in config');
88
89
  process.exit(1);
89
90
  }
90
91
  return config;
91
92
  }
92
93
  catch (e) {
93
- console.error(`Failed to load proxy config from ${resolvedPath}:`, e);
94
+ logger.error(`Failed to load proxy config from ${resolvedPath}:`, e);
94
95
  process.exit(1);
95
96
  }
96
97
  }
@@ -100,7 +101,7 @@ async function readYarnConfig(path) {
100
101
  return load(content);
101
102
  }
102
103
  catch (e) {
103
- console.warn(`Failed to load Yarn config from ${path}:`, e);
104
+ logger.warn(`Failed to load Yarn config from ${path}:`, e);
104
105
  return {};
105
106
  }
106
107
  }
@@ -140,16 +141,16 @@ async function loadProxyInfo(proxyConfigPath = './.registry-proxy.yml', localYar
140
141
  async function fetchFromRegistry(registry, targetUrl, limiter) {
141
142
  await limiter.acquire();
142
143
  try {
143
- console.log(`Fetching from: ${targetUrl}`);
144
+ logger.info(`Fetching from: ${targetUrl}`);
144
145
  const headers = registry.token ? { Authorization: `Bearer ${registry.token}` } : {};
145
146
  headers.Collection = "keep-alive";
146
147
  const response = await fetch(targetUrl, { headers });
147
- console.log(`Response from upstream ${targetUrl}: ${response.status} ${response.statusText}`, { headers: [...response.headers] });
148
+ logger.info(`Response from upstream ${targetUrl}: ${response.status} ${response.statusText} content-type=${response.headers.get('content-type')} content-length=${response.headers.get('content-length')} transfer-encoding=${response.headers.get('transfer-encoding')}`);
148
149
  return response.ok ? response : null;
149
150
  }
150
151
  catch (e) {
151
152
  if (e instanceof Error) {
152
- console.error(e.code === 'ECONNREFUSED'
153
+ logger.error(e.code === 'ECONNREFUSED'
153
154
  ? `Registry ${registry.normalizedRegistryUrl} unreachable [ECONNREFUSED]`
154
155
  : `Error from ${registry.normalizedRegistryUrl}: ${e.message}`);
155
156
  }
@@ -200,7 +201,7 @@ async function writeSuccessfulResponse(registryInfo, targetUrl, res, upstreamRes
200
201
  else {
201
202
  // 二进制流处理
202
203
  if (!upstreamResponse.body) {
203
- console.error(`Empty response body from ${targetUrl}`);
204
+ logger.error(`Empty response body from ${targetUrl}`);
204
205
  res.writeHead(502).end('Empty Upstream Response');
205
206
  }
206
207
  else {
@@ -218,7 +219,7 @@ async function writeSuccessfulResponse(registryInfo, targetUrl, res, upstreamRes
218
219
  }
219
220
  }
220
221
  catch (err) {
221
- console.error('Failed to write upstreamResponse:', err);
222
+ logger.error('Failed to write upstreamResponse:', err);
222
223
  if (!res.headersSent) {
223
224
  res.writeHead(502).end('Internal Server Error');
224
225
  }
@@ -228,9 +229,9 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
228
229
  const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
229
230
  const registryInfos = proxyInfo.registries;
230
231
  const basePathPrefixedWithSlash = removeEndingSlashAndForceStartingSlash(proxyInfo.basePath);
231
- console.log('Active registries:', registryInfos.map(r => r.normalizedRegistryUrl));
232
- console.log('Proxy base path:', basePathPrefixedWithSlash);
233
- console.log('HTTPS:', !!proxyInfo.https);
232
+ logger.info('Active registries:', registryInfos.map(r => r.normalizedRegistryUrl));
233
+ logger.info('Proxy base path:', basePathPrefixedWithSlash);
234
+ logger.info('HTTPS:', !!proxyInfo.https);
234
235
  let proxyPort;
235
236
  const requestHandler = async (req, res) => {
236
237
  if (!req.url || !req.headers.host) {
@@ -279,7 +280,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
279
280
  await fsPromises.access(certPath);
280
281
  }
281
282
  catch (e) {
282
- console.error(`HTTPS config error: key or cert file not found`, e);
283
+ logger.error(`HTTPS config error: key or cert file not found`, e);
283
284
  process.exit(1);
284
285
  }
285
286
  const httpsOptions = {
@@ -294,18 +295,18 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
294
295
  const promisedServer = new Promise((resolve, reject) => {
295
296
  server.on('error', (err) => {
296
297
  if (err.code === 'EADDRINUSE') {
297
- console.error(`Port ${port} is in use, please specify a different port or free it.`);
298
+ logger.error(`Port ${port} is in use, please specify a different port or free it.`);
298
299
  process.exit(1);
299
300
  }
300
- console.error('Server error:', err);
301
+ logger.error('Server error:', err);
301
302
  reject(err);
302
303
  });
303
304
  server.listen(port, () => {
304
305
  const address = server.address();
305
306
  proxyPort = address.port;
306
307
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
307
- writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
308
- console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`);
308
+ writeFile(portFile, proxyPort.toString()).catch(e => logger.error('Failed to write port file:', e));
309
+ logger.info(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`);
309
310
  resolve(server);
310
311
  });
311
312
  });
@@ -314,7 +315,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
314
315
  if (import.meta.url === `file://${process.argv[1]}`) {
315
316
  const [, , configPath, localYarnPath, globalYarnPath, port] = process.argv;
316
317
  startProxyServer(configPath, localYarnPath, globalYarnPath, parseInt(port, 10) || 0).catch(err => {
317
- console.error('Failed to start server:', err);
318
+ logger.error('Failed to start server:', err);
318
319
  process.exit(1);
319
320
  });
320
321
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
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
@@ -8,6 +8,7 @@ import fetch, {Response} from 'node-fetch';
8
8
  import {homedir} from 'os';
9
9
  import {join, resolve} from 'path';
10
10
  import {URL} from 'url';
11
+ import logger from "./utils/logger";
11
12
 
12
13
  const {readFile, writeFile} = fsPromises;
13
14
 
@@ -127,12 +128,12 @@ async function readProxyConfig(proxyConfigPath = './.registry-proxy.yml'): Promi
127
128
  const content = await readFile(resolvedPath, 'utf8');
128
129
  const config = load(content) as ProxyConfig;
129
130
  if (!config.registries) {
130
- console.error('Missing required "registries" field in config');
131
+ logger.error('Missing required "registries" field in config');
131
132
  process.exit(1);
132
133
  }
133
134
  return config;
134
135
  } catch (e) {
135
- console.error(`Failed to load proxy config from ${resolvedPath}:`, e);
136
+ logger.error(`Failed to load proxy config from ${resolvedPath}:`, e);
136
137
  process.exit(1);
137
138
  }
138
139
  }
@@ -142,7 +143,7 @@ async function readYarnConfig(path: string): Promise<YarnConfig> {
142
143
  const content = await readFile(resolvePath(path), 'utf8');
143
144
  return load(content) as YarnConfig;
144
145
  } catch (e) {
145
- console.warn(`Failed to load Yarn config from ${path}:`, e);
146
+ logger.warn(`Failed to load Yarn config from ${path}:`, e);
146
147
  return {};
147
148
  }
148
149
  }
@@ -192,15 +193,15 @@ async function fetchFromRegistry(
192
193
  ): Promise<Response | null> {
193
194
  await limiter.acquire();
194
195
  try {
195
- console.log(`Fetching from: ${targetUrl}`);
196
+ logger.info(`Fetching from: ${targetUrl}`);
196
197
  const headers: {} = registry.token ? {Authorization: `Bearer ${registry.token}`} : {};
197
198
  (headers as any).Collection = "keep-alive";
198
199
  const response = await fetch(targetUrl, {headers});
199
- console.log(`Response from upstream ${targetUrl}: ${response.status} ${response.statusText}`, {headers: [...response.headers]});
200
+ logger.info(`Response from upstream ${targetUrl}: ${response.status} ${response.statusText} content-type=${response.headers.get('content-type')} content-length=${response.headers.get('content-length')} transfer-encoding=${response.headers.get('transfer-encoding')}`);
200
201
  return response.ok ? response : null;
201
202
  } catch (e) {
202
203
  if (e instanceof Error) {
203
- console.error(
204
+ logger.error(
204
205
  (e as any).code === 'ECONNREFUSED'
205
206
  ? `Registry ${registry.normalizedRegistryUrl} unreachable [ECONNREFUSED]`
206
207
  : `Error from ${registry.normalizedRegistryUrl}: ${e.message}`
@@ -266,7 +267,7 @@ async function writeSuccessfulResponse(
266
267
  } else {
267
268
  // 二进制流处理
268
269
  if (!upstreamResponse.body) {
269
- console.error(`Empty response body from ${targetUrl}`);
270
+ logger.error(`Empty response body from ${targetUrl}`);
270
271
  res.writeHead(502).end('Empty Upstream Response');
271
272
  } else {
272
273
  // write back to client
@@ -282,7 +283,7 @@ async function writeSuccessfulResponse(
282
283
  }
283
284
  }
284
285
  } catch (err) {
285
- console.error('Failed to write upstreamResponse:', err);
286
+ logger.error('Failed to write upstreamResponse:', err);
286
287
  if (!res.headersSent) {
287
288
  res.writeHead(502).end('Internal Server Error');
288
289
  }
@@ -299,9 +300,9 @@ export async function startProxyServer(
299
300
  const registryInfos = proxyInfo.registries;
300
301
  const basePathPrefixedWithSlash: string = removeEndingSlashAndForceStartingSlash(proxyInfo.basePath);
301
302
 
302
- console.log('Active registries:', registryInfos.map(r => r.normalizedRegistryUrl));
303
- console.log('Proxy base path:', basePathPrefixedWithSlash);
304
- console.log('HTTPS:', !!proxyInfo.https);
303
+ logger.info('Active registries:', registryInfos.map(r => r.normalizedRegistryUrl));
304
+ logger.info('Proxy base path:', basePathPrefixedWithSlash);
305
+ logger.info('HTTPS:', !!proxyInfo.https);
305
306
 
306
307
  let proxyPort: number;
307
308
 
@@ -354,7 +355,7 @@ export async function startProxyServer(
354
355
  await fsPromises.access(keyPath);
355
356
  await fsPromises.access(certPath);
356
357
  } catch (e) {
357
- console.error(`HTTPS config error: key or cert file not found`, e);
358
+ logger.error(`HTTPS config error: key or cert file not found`, e);
358
359
  process.exit(1);
359
360
  }
360
361
  const httpsOptions = {
@@ -369,18 +370,18 @@ export async function startProxyServer(
369
370
  const promisedServer: Promise<HttpServer | HttpsServer> = new Promise((resolve, reject) => {
370
371
  server.on('error', (err: NodeJS.ErrnoException) => {
371
372
  if (err.code === 'EADDRINUSE') {
372
- console.error(`Port ${port} is in use, please specify a different port or free it.`);
373
+ logger.error(`Port ${port} is in use, please specify a different port or free it.`);
373
374
  process.exit(1);
374
375
  }
375
- console.error('Server error:', err);
376
+ logger.error('Server error:', err);
376
377
  reject(err);
377
378
  });
378
379
  server.listen(port, () => {
379
380
  const address = server.address() as AddressInfo;
380
381
  proxyPort = address.port;
381
382
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
382
- writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
383
- console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`);
383
+ writeFile(portFile, proxyPort.toString()).catch(e => logger.error('Failed to write port file:', e));
384
+ logger.info(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`);
384
385
  resolve(server);
385
386
  });
386
387
  });
@@ -396,7 +397,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
396
397
  globalYarnPath,
397
398
  parseInt(port, 10) || 0
398
399
  ).catch(err => {
399
- console.error('Failed to start server:', err);
400
+ logger.error('Failed to start server:', err);
400
401
  process.exit(1);
401
402
  });
402
403
  }
@@ -0,0 +1,36 @@
1
+ // utils/logger.ts
2
+ const COLORS = {
3
+ reset: '\x1b[0m',
4
+ proxy: '\x1b[36m', // 青色
5
+ success: '\x1b[32m', // 绿色
6
+ error: '\x1b[31m', // 红色
7
+ warn: '\x1b[33m', // 黄色
8
+ debug: '\x1b[35m' // 紫色
9
+ };
10
+
11
+ const PREFIX = {
12
+ proxy: `${COLORS.proxy}[PROXY]${COLORS.reset}`,
13
+ error: `${COLORS.error}[ERROR]${COLORS.reset}`,
14
+ warn: `${COLORS.warn}[WARN]${COLORS.reset}`,
15
+ debug: `${COLORS.debug}[DEBUG]${COLORS.reset}`
16
+ };
17
+
18
+ // 代理服务器专用日志
19
+ const log = {
20
+ info: (...args: any[]) =>
21
+ console.log(`${PREFIX.proxy}`, ...args),
22
+
23
+ success: (...args: any[]) =>
24
+ console.log(`${PREFIX.proxy} ${COLORS.success}✓${COLORS.reset}`, ...args),
25
+
26
+ error: (...args: any[]) =>
27
+ console.error(`${PREFIX.error}`, ...args),
28
+
29
+ warn: (...args: any[]) =>
30
+ console.warn(`${PREFIX.warn}`, ...args),
31
+
32
+ debug: (...args: any[]) =>
33
+ process.env.DEBUG && console.debug(`${PREFIX.debug}`, ...args)
34
+ };
35
+
36
+ export default log;