com.jimuwd.xian.registry-proxy 1.0.23 → 1.0.25
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 +14 -3
- package/package.json +1 -1
- package/src/index.ts +60 -30
package/dist/index.js
CHANGED
|
@@ -34,6 +34,13 @@ class ConcurrencyLimiter {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
const limiter = new ConcurrencyLimiter(3);
|
|
37
|
+
function removeEndingSlashButReserveStartingSlash(str) {
|
|
38
|
+
if (!str)
|
|
39
|
+
return '/';
|
|
40
|
+
if (str === '/')
|
|
41
|
+
return '/';
|
|
42
|
+
return str.replace(/\/+$/, '');
|
|
43
|
+
}
|
|
37
44
|
function normalizeUrl(url) {
|
|
38
45
|
try {
|
|
39
46
|
const urlObj = new URL(url);
|
|
@@ -43,7 +50,7 @@ function normalizeUrl(url) {
|
|
|
43
50
|
else if (urlObj.protocol === 'https:' && (urlObj.port === '443' || urlObj.port === '')) {
|
|
44
51
|
urlObj.port = '';
|
|
45
52
|
}
|
|
46
|
-
urlObj.pathname = urlObj.pathname
|
|
53
|
+
urlObj.pathname = removeEndingSlashButReserveStartingSlash(urlObj.pathname);
|
|
47
54
|
return urlObj.toString();
|
|
48
55
|
}
|
|
49
56
|
catch (e) {
|
|
@@ -176,8 +183,10 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
176
183
|
try {
|
|
177
184
|
const data = await successResponse.json();
|
|
178
185
|
if (data.versions) {
|
|
179
|
-
|
|
180
|
-
|
|
186
|
+
const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
|
|
187
|
+
console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
|
|
188
|
+
const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
|
|
189
|
+
console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
|
|
181
190
|
for (const version in data.versions) {
|
|
182
191
|
const dist = data.versions[version]?.dist;
|
|
183
192
|
if (dist?.tarball) {
|
|
@@ -185,6 +194,8 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
185
194
|
const originalSearchParamsStr = originalUrl.search || '';
|
|
186
195
|
const tarballPathPrefixedWithSlash = removeRegistryPrefix(dist.tarball, registries);
|
|
187
196
|
dist.tarball = `${proxyBaseUrlNoSuffixedWithSlash}${tarballPathPrefixedWithSlash}${originalSearchParamsStr}`;
|
|
197
|
+
console.log("tarballPathPrefixedWithSlash", tarballPathPrefixedWithSlash);
|
|
198
|
+
console.log("dist.tarballUrl", dist.tarball);
|
|
188
199
|
}
|
|
189
200
|
}
|
|
190
201
|
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {createServer, Server as HttpServer, IncomingMessage, ServerResponse, OutgoingHttpHeaders} from 'http';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import fetch, {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
interface RegistryConfig {
|
|
15
|
-
|
|
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
|
-
|
|
22
|
-
interface
|
|
23
|
-
|
|
24
|
-
|
|
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;
|
|
@@ -54,6 +74,12 @@ class ConcurrencyLimiter {
|
|
|
54
74
|
|
|
55
75
|
const limiter = new ConcurrencyLimiter(3);
|
|
56
76
|
|
|
77
|
+
function removeEndingSlashButReserveStartingSlash(str: string): string {
|
|
78
|
+
if (!str) return '/';
|
|
79
|
+
if (str === '/') return '/';
|
|
80
|
+
return str.replace(/\/+$/, '');
|
|
81
|
+
}
|
|
82
|
+
|
|
57
83
|
function normalizeUrl(url: string): string {
|
|
58
84
|
try {
|
|
59
85
|
const urlObj = new URL(url);
|
|
@@ -62,7 +88,7 @@ function normalizeUrl(url: string): string {
|
|
|
62
88
|
} else if (urlObj.protocol === 'https:' && (urlObj.port === '443' || urlObj.port === '')) {
|
|
63
89
|
urlObj.port = '';
|
|
64
90
|
}
|
|
65
|
-
urlObj.pathname = urlObj.pathname
|
|
91
|
+
urlObj.pathname = removeEndingSlashButReserveStartingSlash(urlObj.pathname);
|
|
66
92
|
return urlObj.toString();
|
|
67
93
|
} catch (e) {
|
|
68
94
|
console.error(`Invalid URL: ${url}`, e);
|
|
@@ -144,7 +170,7 @@ async function loadRegistries(
|
|
|
144
170
|
}
|
|
145
171
|
}
|
|
146
172
|
}
|
|
147
|
-
registryMap.set(normalizedUrl, {
|
|
173
|
+
registryMap.set(normalizedUrl, {url: normalizedUrl, token});
|
|
148
174
|
}
|
|
149
175
|
return Array.from(registryMap.values());
|
|
150
176
|
}
|
|
@@ -184,14 +210,14 @@ export async function startProxyServer(
|
|
|
184
210
|
: fullUrl.pathname;
|
|
185
211
|
console.log(`Proxying: ${relativePathPrefixedWithSlash}`);
|
|
186
212
|
|
|
187
|
-
const fetchPromises = registries.map(async ({
|
|
213
|
+
const fetchPromises = registries.map(async ({url, token}) => {
|
|
188
214
|
await limiter.acquire();
|
|
189
215
|
try {
|
|
190
216
|
const cleanRelativePath = relativePathPrefixedWithSlash.replace(/^\/+|\/+$/g, '');
|
|
191
217
|
const targetUrl = `${url}/${cleanRelativePath}${fullUrl.search || ''}`;
|
|
192
218
|
console.log(`Fetching from: ${targetUrl}`);
|
|
193
|
-
const headers = token ? {
|
|
194
|
-
const response = await fetch(targetUrl, {
|
|
219
|
+
const headers = token ? {Authorization: `Bearer ${token}`} : undefined;
|
|
220
|
+
const response = await fetch(targetUrl, {headers,});
|
|
195
221
|
console.log(`Response from ${targetUrl}: ${response.status} ${response.statusText}`);
|
|
196
222
|
return response.ok ? response : null;
|
|
197
223
|
} catch (e) {
|
|
@@ -215,8 +241,10 @@ export async function startProxyServer(
|
|
|
215
241
|
try {
|
|
216
242
|
const data = await successResponse.json() as PackageData;
|
|
217
243
|
if (data.versions) {
|
|
218
|
-
|
|
219
|
-
|
|
244
|
+
const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
|
|
245
|
+
console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
|
|
246
|
+
const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
|
|
247
|
+
console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
|
|
220
248
|
for (const version in data.versions) {
|
|
221
249
|
const dist = data.versions[version]?.dist;
|
|
222
250
|
if (dist?.tarball) {
|
|
@@ -224,10 +252,12 @@ export async function startProxyServer(
|
|
|
224
252
|
const originalSearchParamsStr = originalUrl.search || '';
|
|
225
253
|
const tarballPathPrefixedWithSlash = removeRegistryPrefix(dist.tarball, registries);
|
|
226
254
|
dist.tarball = `${proxyBaseUrlNoSuffixedWithSlash}${tarballPathPrefixedWithSlash}${originalSearchParamsStr}`;
|
|
255
|
+
console.log("tarballPathPrefixedWithSlash", tarballPathPrefixedWithSlash);
|
|
256
|
+
console.log("dist.tarballUrl", dist.tarball);
|
|
227
257
|
}
|
|
228
258
|
}
|
|
229
259
|
}
|
|
230
|
-
res.writeHead(200, {
|
|
260
|
+
res.writeHead(200, {'Content-Type': 'application/json'});
|
|
231
261
|
res.end(JSON.stringify(data));
|
|
232
262
|
} catch (e) {
|
|
233
263
|
console.error('Failed to parse JSON response:', e);
|
|
@@ -240,12 +270,12 @@ export async function startProxyServer(
|
|
|
240
270
|
return;
|
|
241
271
|
}
|
|
242
272
|
const contentLength = successResponse.headers.get('Content-Length');
|
|
243
|
-
const safeHeaders:OutgoingHttpHeaders = {
|
|
244
|
-
'Content-Type': successResponse.headers.get('Content-Type')||undefined,
|
|
273
|
+
const safeHeaders: OutgoingHttpHeaders = {
|
|
274
|
+
'Content-Type': successResponse.headers.get('Content-Type') || undefined,
|
|
245
275
|
'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
|
|
246
276
|
};
|
|
247
277
|
res.writeHead(successResponse.status, safeHeaders);
|
|
248
|
-
successResponse.body.pipe(res).on('error', (err:any) => {
|
|
278
|
+
successResponse.body.pipe(res).on('error', (err: any) => {
|
|
249
279
|
console.error(`Stream error for ${relativePathPrefixedWithSlash}:`, err);
|
|
250
280
|
res.writeHead(502).end('Stream Error');
|
|
251
281
|
});
|
|
@@ -254,7 +284,7 @@ export async function startProxyServer(
|
|
|
254
284
|
|
|
255
285
|
let server: HttpServer | HttpsServer;
|
|
256
286
|
if (proxyConfig.https) {
|
|
257
|
-
const {
|
|
287
|
+
const {key, cert} = proxyConfig.https;
|
|
258
288
|
const keyPath = resolvePath(key);
|
|
259
289
|
const certPath = resolvePath(cert);
|
|
260
290
|
try {
|
|
@@ -294,7 +324,7 @@ export async function startProxyServer(
|
|
|
294
324
|
}
|
|
295
325
|
|
|
296
326
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
297
|
-
const [
|
|
327
|
+
const [, , configPath, localYarnPath, globalYarnPath, port] = process.argv;
|
|
298
328
|
startProxyServer(
|
|
299
329
|
configPath,
|
|
300
330
|
localYarnPath,
|