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 +10 -4
- package/package.json +1 -1
- package/src/index.ts +58 -32
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
|
|
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
|
|
185
|
-
|
|
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
package/src/index.ts
CHANGED
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -144,7 +164,7 @@ async function loadRegistries(
|
|
|
144
164
|
}
|
|
145
165
|
}
|
|
146
166
|
}
|
|
147
|
-
registryMap.set(normalizedUrl, {
|
|
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:
|
|
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 ({
|
|
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 ? {
|
|
194
|
-
const response = await fetch(targetUrl, {
|
|
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
|
|
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
|
|
224
|
-
|
|
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, {
|
|
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 {
|
|
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 [
|
|
321
|
+
const [, , configPath, localYarnPath, globalYarnPath, port] = process.argv;
|
|
296
322
|
startProxyServer(
|
|
297
323
|
configPath,
|
|
298
324
|
localYarnPath,
|