com.jimuwd.xian.registry-proxy 1.0.21 → 1.0.23

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 +20 -18
  2. package/package.json +1 -1
  3. package/src/index.ts +23 -21
package/dist/index.js CHANGED
@@ -60,9 +60,9 @@ function removeRegistryPrefix(tarballUrl, registries) {
60
60
  const normalizedRegistries = registries
61
61
  .map(r => normalizeUrl(r.url))
62
62
  .sort((a, b) => b.length - a.length);
63
- for (const registry of normalizedRegistries) {
64
- if (normalizedTarball.startsWith(registry)) {
65
- return normalizedTarball.slice(registry.length) || '/';
63
+ for (const normalizedRegistry of normalizedRegistries) {
64
+ if (normalizedTarball.startsWith(normalizedRegistry)) {
65
+ return normalizedTarball.slice(normalizedRegistry.length) || '/';
66
66
  }
67
67
  }
68
68
  }
@@ -124,9 +124,9 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
124
124
  export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
125
125
  const proxyConfig = await loadProxyConfig(proxyConfigPath);
126
126
  const registries = await loadRegistries(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
127
- const basePath = proxyConfig.basePath ? `/${proxyConfig.basePath.replace(/^\/|\/$/g, '')}` : '';
127
+ const basePathPrefixedWithSlash = proxyConfig.basePath ? `/${proxyConfig.basePath.replace(/^\/|\/$/g, '')}` : '/';
128
128
  console.log('Active registries:', registries.map(r => r.url));
129
- console.log('Proxy base path:', basePath || '/');
129
+ console.log('Proxy base path:', basePathPrefixedWithSlash);
130
130
  console.log('HTTPS:', !!proxyConfig.https);
131
131
  let proxyPort;
132
132
  const requestHandler = async (req, res) => {
@@ -136,19 +136,19 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
136
136
  return;
137
137
  }
138
138
  const fullUrl = new URL(req.url, `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host}`);
139
- if (basePath && !fullUrl.pathname.startsWith(basePath)) {
140
- console.error(`Path ${fullUrl.pathname} does not match basePath ${basePath}`);
139
+ if (basePathPrefixedWithSlash && !fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
140
+ console.error(`Path ${fullUrl.pathname} does not match basePath ${basePathPrefixedWithSlash}`);
141
141
  res.writeHead(404).end('Not Found');
142
142
  return;
143
143
  }
144
- const relativePath = basePath
145
- ? fullUrl.pathname.slice(basePath.length)
144
+ const relativePathPrefixedWithSlash = basePathPrefixedWithSlash
145
+ ? fullUrl.pathname.slice(basePathPrefixedWithSlash.length)
146
146
  : fullUrl.pathname;
147
- console.log(`Proxying: ${relativePath}`);
147
+ console.log(`Proxying: ${relativePathPrefixedWithSlash}`);
148
148
  const fetchPromises = registries.map(async ({ url, token }) => {
149
149
  await limiter.acquire();
150
150
  try {
151
- const cleanRelativePath = relativePath.replace(/^\/+|\/+$/g, '');
151
+ const cleanRelativePath = relativePathPrefixedWithSlash.replace(/^\/+|\/+$/g, '');
152
152
  const targetUrl = `${url}/${cleanRelativePath}${fullUrl.search || ''}`;
153
153
  console.log(`Fetching from: ${targetUrl}`);
154
154
  const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
@@ -167,7 +167,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
167
167
  const responses = await Promise.all(fetchPromises);
168
168
  const successResponse = responses.find((r) => r !== null);
169
169
  if (!successResponse) {
170
- console.error(`All registries failed for ${relativePath}`);
170
+ console.error(`All registries failed for ${relativePathPrefixedWithSlash}`);
171
171
  res.writeHead(404).end('Not Found - All upstream registries failed');
172
172
  return;
173
173
  }
@@ -176,13 +176,15 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
176
176
  try {
177
177
  const data = await successResponse.json();
178
178
  if (data.versions) {
179
- const proxyBase = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePath}`;
179
+ console.log("Requested url is", req.url);
180
+ const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
180
181
  for (const version in data.versions) {
181
182
  const dist = data.versions[version]?.dist;
182
183
  if (dist?.tarball) {
183
184
  const originalUrl = new URL(dist.tarball);
184
- const tarballPath = removeRegistryPrefix(dist.tarball, registries);
185
- dist.tarball = `${proxyBase}${tarballPath}${originalUrl.search || ''}`;
185
+ const originalSearchParamsStr = originalUrl.search || '';
186
+ const tarballPathPrefixedWithSlash = removeRegistryPrefix(dist.tarball, registries);
187
+ dist.tarball = `${proxyBaseUrlNoSuffixedWithSlash}${tarballPathPrefixedWithSlash}${originalSearchParamsStr}`;
186
188
  }
187
189
  }
188
190
  }
@@ -202,12 +204,12 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
202
204
  }
203
205
  const contentLength = successResponse.headers.get('Content-Length');
204
206
  const safeHeaders = {
205
- 'Content-Type': successResponse.headers.get('Content-Type'),
207
+ 'Content-Type': successResponse.headers.get('Content-Type') || undefined,
206
208
  'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
207
209
  };
208
210
  res.writeHead(successResponse.status, safeHeaders);
209
211
  successResponse.body.pipe(res).on('error', (err) => {
210
- console.error(`Stream error for ${relativePath}:`, err);
212
+ console.error(`Stream error for ${relativePathPrefixedWithSlash}:`, err);
211
213
  res.writeHead(502).end('Stream Error');
212
214
  });
213
215
  }
@@ -248,7 +250,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
248
250
  proxyPort = address.port;
249
251
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
250
252
  writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
251
- console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePath}`);
253
+ console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
252
254
  resolve(server);
253
255
  });
254
256
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createServer, Server as HttpServer } from 'http';
2
+ import {createServer, Server as HttpServer, IncomingMessage, ServerResponse, OutgoingHttpHeaders} from 'http';
3
3
  import { createServer as createHttpsServer, Server as HttpsServer } from 'https';
4
4
  import { readFileSync, promises as fsPromises } from 'fs';
5
5
  import { AddressInfo } from 'net';
@@ -81,9 +81,9 @@ function removeRegistryPrefix(tarballUrl: string, registries: RegistryInfo[]): s
81
81
  .map(r => normalizeUrl(r.url))
82
82
  .sort((a, b) => b.length - a.length);
83
83
 
84
- for (const registry of normalizedRegistries) {
85
- if (normalizedTarball.startsWith(registry)) {
86
- return normalizedTarball.slice(registry.length) || '/';
84
+ for (const normalizedRegistry of normalizedRegistries) {
85
+ if (normalizedTarball.startsWith(normalizedRegistry)) {
86
+ return normalizedTarball.slice(normalizedRegistry.length) || '/';
87
87
  }
88
88
  }
89
89
  } catch (e) {
@@ -157,15 +157,15 @@ export async function startProxyServer(
157
157
  ): Promise<HttpServer | HttpsServer> {
158
158
  const proxyConfig = await loadProxyConfig(proxyConfigPath);
159
159
  const registries = await loadRegistries(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
160
- const basePath = proxyConfig.basePath ? `/${proxyConfig.basePath.replace(/^\/|\/$/g, '')}` : '';
160
+ const basePathPrefixedWithSlash = proxyConfig.basePath ? `/${proxyConfig.basePath.replace(/^\/|\/$/g, '')}` : '/';
161
161
 
162
162
  console.log('Active registries:', registries.map(r => r.url));
163
- console.log('Proxy base path:', basePath || '/');
163
+ console.log('Proxy base path:', basePathPrefixedWithSlash);
164
164
  console.log('HTTPS:', !!proxyConfig.https);
165
165
 
166
166
  let proxyPort: number;
167
167
 
168
- const requestHandler = async (req: any, res: any) => {
168
+ const requestHandler = async (req: IncomingMessage, res: ServerResponse) => {
169
169
  if (!req.url || !req.headers.host) {
170
170
  console.error('Invalid request: missing URL or host header');
171
171
  res.writeHead(400).end('Invalid Request');
@@ -173,21 +173,21 @@ export async function startProxyServer(
173
173
  }
174
174
 
175
175
  const fullUrl = new URL(req.url, `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host}`);
176
- if (basePath && !fullUrl.pathname.startsWith(basePath)) {
177
- console.error(`Path ${fullUrl.pathname} does not match basePath ${basePath}`);
176
+ if (basePathPrefixedWithSlash && !fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
177
+ console.error(`Path ${fullUrl.pathname} does not match basePath ${basePathPrefixedWithSlash}`);
178
178
  res.writeHead(404).end('Not Found');
179
179
  return;
180
180
  }
181
181
 
182
- const relativePath = basePath
183
- ? fullUrl.pathname.slice(basePath.length)
182
+ const relativePathPrefixedWithSlash = basePathPrefixedWithSlash
183
+ ? fullUrl.pathname.slice(basePathPrefixedWithSlash.length)
184
184
  : fullUrl.pathname;
185
- console.log(`Proxying: ${relativePath}`);
185
+ console.log(`Proxying: ${relativePathPrefixedWithSlash}`);
186
186
 
187
187
  const fetchPromises = registries.map(async ({ url, token }) => {
188
188
  await limiter.acquire();
189
189
  try {
190
- const cleanRelativePath = relativePath.replace(/^\/+|\/+$/g, '');
190
+ const cleanRelativePath = relativePathPrefixedWithSlash.replace(/^\/+|\/+$/g, '');
191
191
  const targetUrl = `${url}/${cleanRelativePath}${fullUrl.search || ''}`;
192
192
  console.log(`Fetching from: ${targetUrl}`);
193
193
  const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
@@ -205,7 +205,7 @@ export async function startProxyServer(
205
205
  const responses = await Promise.all(fetchPromises);
206
206
  const successResponse = responses.find((r): r is Response => r !== null);
207
207
  if (!successResponse) {
208
- console.error(`All registries failed for ${relativePath}`);
208
+ console.error(`All registries failed for ${relativePathPrefixedWithSlash}`);
209
209
  res.writeHead(404).end('Not Found - All upstream registries failed');
210
210
  return;
211
211
  }
@@ -215,13 +215,15 @@ export async function startProxyServer(
215
215
  try {
216
216
  const data = await successResponse.json() as PackageData;
217
217
  if (data.versions) {
218
- const proxyBase = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePath}`;
218
+ console.log("Requested url is", req.url);
219
+ const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePathPrefixedWithSlash==='/'?'':basePathPrefixedWithSlash}`;
219
220
  for (const version in data.versions) {
220
221
  const dist = data.versions[version]?.dist;
221
222
  if (dist?.tarball) {
222
223
  const originalUrl = new URL(dist.tarball);
223
- const tarballPath = removeRegistryPrefix(dist.tarball, registries);
224
- dist.tarball = `${proxyBase}${tarballPath}${originalUrl.search || ''}`;
224
+ const originalSearchParamsStr = originalUrl.search || '';
225
+ const tarballPathPrefixedWithSlash = removeRegistryPrefix(dist.tarball, registries);
226
+ dist.tarball = `${proxyBaseUrlNoSuffixedWithSlash}${tarballPathPrefixedWithSlash}${originalSearchParamsStr}`;
225
227
  }
226
228
  }
227
229
  }
@@ -238,13 +240,13 @@ export async function startProxyServer(
238
240
  return;
239
241
  }
240
242
  const contentLength = successResponse.headers.get('Content-Length');
241
- const safeHeaders = {
242
- 'Content-Type': successResponse.headers.get('Content-Type'),
243
+ const safeHeaders:OutgoingHttpHeaders = {
244
+ 'Content-Type': successResponse.headers.get('Content-Type')||undefined,
243
245
  'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
244
246
  };
245
247
  res.writeHead(successResponse.status, safeHeaders);
246
248
  successResponse.body.pipe(res).on('error', (err:any) => {
247
- console.error(`Stream error for ${relativePath}:`, err);
249
+ console.error(`Stream error for ${relativePathPrefixedWithSlash}:`, err);
248
250
  res.writeHead(502).end('Stream Error');
249
251
  });
250
252
  }
@@ -285,7 +287,7 @@ export async function startProxyServer(
285
287
  proxyPort = address.port;
286
288
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
287
289
  writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
288
- console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePath}`);
290
+ console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
289
291
  resolve(server);
290
292
  });
291
293
  });