com.jimuwd.xian.registry-proxy 1.0.22 → 1.0.24

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
@@ -176,13 +176,19 @@ 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}${basePathPrefixedWithSlash}`;
179
+ const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
180
+ console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
181
+ const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
182
+ console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
180
183
  for (const version in data.versions) {
181
184
  const dist = data.versions[version]?.dist;
182
185
  if (dist?.tarball) {
183
186
  const originalUrl = new URL(dist.tarball);
184
- const tarballPath = removeRegistryPrefix(dist.tarball, registries);
185
- dist.tarball = `${proxyBase}${tarballPath}${originalUrl.search || ''}`;
187
+ const originalSearchParamsStr = originalUrl.search || '';
188
+ const tarballPathPrefixedWithSlash = removeRegistryPrefix(dist.tarball, registries);
189
+ dist.tarball = `${proxyBaseUrlNoSuffixedWithSlash}${tarballPathPrefixedWithSlash}${originalSearchParamsStr}`;
190
+ console.log("tarballPathPrefixedWithSlash", tarballPathPrefixedWithSlash);
191
+ console.log("dist.tarballUrl", dist.tarball);
186
192
  }
187
193
  }
188
194
  }
@@ -202,7 +208,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
202
208
  }
203
209
  const contentLength = successResponse.headers.get('Content-Length');
204
210
  const safeHeaders = {
205
- 'Content-Type': successResponse.headers.get('Content-Type'),
211
+ 'Content-Type': successResponse.headers.get('Content-Type') || undefined,
206
212
  'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
207
213
  };
208
214
  res.writeHead(successResponse.status, safeHeaders);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
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,27 +1,47 @@
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';
11
-
12
- const { readFile, writeFile } = fsPromises;
13
-
14
- interface RegistryConfig { npmAuthToken?: string; }
15
- interface HttpsConfig { key: string; cert: string; }
2
+ import {createServer, Server as HttpServer, IncomingMessage, ServerResponse, OutgoingHttpHeaders} 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';
11
+
12
+ const {readFile, writeFile} = fsPromises;
13
+
14
+ interface RegistryConfig {
15
+ npmAuthToken?: string;
16
+ }
17
+
18
+ interface HttpsConfig {
19
+ key: string;
20
+ cert: string;
21
+ }
22
+
16
23
  interface ProxyConfig {
17
24
  registries: Record<string, RegistryConfig | null>;
18
25
  https?: HttpsConfig;
19
26
  basePath?: string;
20
27
  }
21
- interface YarnConfig { npmRegistries?: Record<string, RegistryConfig | null>; }
22
- interface RegistryInfo { url: string; token?: string; }
23
- interface PackageVersion { dist?: { tarball?: string }; }
24
- interface PackageData { versions?: Record<string, PackageVersion>; }
28
+
29
+ interface YarnConfig {
30
+ npmRegistries?: Record<string, RegistryConfig | null>;
31
+ }
32
+
33
+ interface RegistryInfo {
34
+ url: string;
35
+ token?: string;
36
+ }
37
+
38
+ interface PackageVersion {
39
+ dist?: { tarball?: string };
40
+ }
41
+
42
+ interface PackageData {
43
+ versions?: Record<string, PackageVersion>;
44
+ }
25
45
 
26
46
  class ConcurrencyLimiter {
27
47
  private maxConcurrency: number;
@@ -144,7 +164,7 @@ async function loadRegistries(
144
164
  }
145
165
  }
146
166
  }
147
- registryMap.set(normalizedUrl, { url: normalizedUrl, token });
167
+ registryMap.set(normalizedUrl, {url: normalizedUrl, token});
148
168
  }
149
169
  return Array.from(registryMap.values());
150
170
  }
@@ -165,7 +185,7 @@ export async function startProxyServer(
165
185
 
166
186
  let proxyPort: number;
167
187
 
168
- const requestHandler = async (req: any, res: any) => {
188
+ const requestHandler = async (req: IncomingMessage, res: ServerResponse) => {
169
189
  if (!req.url || !req.headers.host) {
170
190
  console.error('Invalid request: missing URL or host header');
171
191
  res.writeHead(400).end('Invalid Request');
@@ -184,14 +204,14 @@ export async function startProxyServer(
184
204
  : fullUrl.pathname;
185
205
  console.log(`Proxying: ${relativePathPrefixedWithSlash}`);
186
206
 
187
- const fetchPromises = registries.map(async ({ url, token }) => {
207
+ const fetchPromises = registries.map(async ({url, token}) => {
188
208
  await limiter.acquire();
189
209
  try {
190
210
  const cleanRelativePath = relativePathPrefixedWithSlash.replace(/^\/+|\/+$/g, '');
191
211
  const targetUrl = `${url}/${cleanRelativePath}${fullUrl.search || ''}`;
192
212
  console.log(`Fetching from: ${targetUrl}`);
193
- const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
194
- const response = await fetch(targetUrl, { headers, });
213
+ const headers = token ? {Authorization: `Bearer ${token}`} : undefined;
214
+ const response = await fetch(targetUrl, {headers,});
195
215
  console.log(`Response from ${targetUrl}: ${response.status} ${response.statusText}`);
196
216
  return response.ok ? response : null;
197
217
  } catch (e) {
@@ -215,17 +235,23 @@ export async function startProxyServer(
215
235
  try {
216
236
  const data = await successResponse.json() as PackageData;
217
237
  if (data.versions) {
218
- const proxyBase = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePathPrefixedWithSlash}`;
238
+ const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
239
+ console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
240
+ const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
241
+ console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
219
242
  for (const version in data.versions) {
220
243
  const dist = data.versions[version]?.dist;
221
244
  if (dist?.tarball) {
222
245
  const originalUrl = new URL(dist.tarball);
223
- const tarballPath = removeRegistryPrefix(dist.tarball, registries);
224
- dist.tarball = `${proxyBase}${tarballPath}${originalUrl.search || ''}`;
246
+ const originalSearchParamsStr = originalUrl.search || '';
247
+ const tarballPathPrefixedWithSlash = removeRegistryPrefix(dist.tarball, registries);
248
+ dist.tarball = `${proxyBaseUrlNoSuffixedWithSlash}${tarballPathPrefixedWithSlash}${originalSearchParamsStr}`;
249
+ console.log("tarballPathPrefixedWithSlash",tarballPathPrefixedWithSlash);
250
+ console.log("dist.tarballUrl",dist.tarball);
225
251
  }
226
252
  }
227
253
  }
228
- res.writeHead(200, { 'Content-Type': 'application/json' });
254
+ res.writeHead(200, {'Content-Type': 'application/json'});
229
255
  res.end(JSON.stringify(data));
230
256
  } catch (e) {
231
257
  console.error('Failed to parse JSON response:', e);
@@ -238,12 +264,12 @@ export async function startProxyServer(
238
264
  return;
239
265
  }
240
266
  const contentLength = successResponse.headers.get('Content-Length');
241
- const safeHeaders = {
242
- 'Content-Type': successResponse.headers.get('Content-Type'),
267
+ const safeHeaders: OutgoingHttpHeaders = {
268
+ 'Content-Type': successResponse.headers.get('Content-Type') || undefined,
243
269
  'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
244
270
  };
245
271
  res.writeHead(successResponse.status, safeHeaders);
246
- successResponse.body.pipe(res).on('error', (err:any) => {
272
+ successResponse.body.pipe(res).on('error', (err: any) => {
247
273
  console.error(`Stream error for ${relativePathPrefixedWithSlash}:`, err);
248
274
  res.writeHead(502).end('Stream Error');
249
275
  });
@@ -252,7 +278,7 @@ export async function startProxyServer(
252
278
 
253
279
  let server: HttpServer | HttpsServer;
254
280
  if (proxyConfig.https) {
255
- const { key, cert } = proxyConfig.https;
281
+ const {key, cert} = proxyConfig.https;
256
282
  const keyPath = resolvePath(key);
257
283
  const certPath = resolvePath(cert);
258
284
  try {
@@ -292,7 +318,7 @@ export async function startProxyServer(
292
318
  }
293
319
 
294
320
  if (import.meta.url === `file://${process.argv[1]}`) {
295
- const [,, configPath, localYarnPath, globalYarnPath, port] = process.argv;
321
+ const [, , configPath, localYarnPath, globalYarnPath, port] = process.argv;
296
322
  startProxyServer(
297
323
  configPath,
298
324
  localYarnPath,