com.jimuwd.xian.registry-proxy 1.0.16 → 1.0.18
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 +15 -40
- package/package.json +1 -1
- package/src/index.ts +15 -40
package/dist/index.js
CHANGED
|
@@ -8,7 +8,6 @@ import { homedir } from 'os';
|
|
|
8
8
|
import { join, resolve } from 'path';
|
|
9
9
|
import { URL } from 'url';
|
|
10
10
|
const { readFile, writeFile } = fsPromises;
|
|
11
|
-
// 并发控制队列
|
|
12
11
|
class ConcurrencyLimiter {
|
|
13
12
|
maxConcurrency;
|
|
14
13
|
current = 0;
|
|
@@ -34,8 +33,7 @@ class ConcurrencyLimiter {
|
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
const limiter = new ConcurrencyLimiter(5); // 限制为 5 个并发请求
|
|
36
|
+
const limiter = new ConcurrencyLimiter(3);
|
|
39
37
|
function normalizeUrl(url) {
|
|
40
38
|
try {
|
|
41
39
|
const urlObj = new URL(url);
|
|
@@ -45,20 +43,16 @@ function normalizeUrl(url) {
|
|
|
45
43
|
else if (urlObj.protocol === 'https:' && (urlObj.port === '443' || urlObj.port === '')) {
|
|
46
44
|
urlObj.port = '';
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
urlObj.pathname += '/';
|
|
50
|
-
}
|
|
51
|
-
console.debug(`Normalized URL: ${url} -> ${urlObj.toString()}`);
|
|
46
|
+
urlObj.pathname = urlObj.pathname.replace(/\/+$/, '');
|
|
52
47
|
return urlObj.toString();
|
|
53
48
|
}
|
|
54
49
|
catch (e) {
|
|
55
50
|
console.error(`Invalid URL: ${url}`, e);
|
|
56
|
-
return url.
|
|
51
|
+
return url.replace(/\/+$/, '');
|
|
57
52
|
}
|
|
58
53
|
}
|
|
59
54
|
function resolvePath(path) {
|
|
60
|
-
|
|
61
|
-
return resolved;
|
|
55
|
+
return path.startsWith('~/') ? join(homedir(), path.slice(2)) : resolve(path);
|
|
62
56
|
}
|
|
63
57
|
function removeRegistryPrefix(tarballUrl, registries) {
|
|
64
58
|
try {
|
|
@@ -66,15 +60,11 @@ function removeRegistryPrefix(tarballUrl, registries) {
|
|
|
66
60
|
const normalizedRegistries = registries
|
|
67
61
|
.map(r => normalizeUrl(r.url))
|
|
68
62
|
.sort((a, b) => b.length - a.length);
|
|
69
|
-
console.debug(`Removing registry prefix from tarball: ${normalizedTarball}`);
|
|
70
63
|
for (const registry of normalizedRegistries) {
|
|
71
64
|
if (normalizedTarball.startsWith(registry)) {
|
|
72
|
-
|
|
73
|
-
console.debug(`Matched registry ${registry}, result: ${result}`);
|
|
74
|
-
return result;
|
|
65
|
+
return normalizedTarball.slice(registry.length) || '/';
|
|
75
66
|
}
|
|
76
67
|
}
|
|
77
|
-
console.debug(`No registry prefix matched for ${normalizedTarball}`);
|
|
78
68
|
}
|
|
79
69
|
catch (e) {
|
|
80
70
|
console.error(`Invalid URL in removeRegistryPrefix: ${tarballUrl}`, e);
|
|
@@ -83,14 +73,12 @@ function removeRegistryPrefix(tarballUrl, registries) {
|
|
|
83
73
|
}
|
|
84
74
|
async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml') {
|
|
85
75
|
const resolvedPath = resolvePath(proxyConfigPath);
|
|
86
|
-
console.debug(`Loading proxy config from: ${resolvedPath}`);
|
|
87
76
|
try {
|
|
88
77
|
const content = await readFile(resolvedPath, 'utf8');
|
|
89
78
|
const config = load(content);
|
|
90
79
|
if (!config.registries) {
|
|
91
80
|
throw new Error('Missing required "registries" field in config');
|
|
92
81
|
}
|
|
93
|
-
console.debug('Loaded proxy config:', JSON.stringify(config, null, 2));
|
|
94
82
|
return config;
|
|
95
83
|
}
|
|
96
84
|
catch (e) {
|
|
@@ -99,12 +87,9 @@ async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml') {
|
|
|
99
87
|
}
|
|
100
88
|
}
|
|
101
89
|
async function loadYarnConfig(path) {
|
|
102
|
-
console.debug(`Loading Yarn config from: ${path}`);
|
|
103
90
|
try {
|
|
104
91
|
const content = await readFile(resolvePath(path), 'utf8');
|
|
105
|
-
|
|
106
|
-
console.debug(`Loaded Yarn config from ${path}:`, JSON.stringify(config, null, 2));
|
|
107
|
-
return config;
|
|
92
|
+
return load(content);
|
|
108
93
|
}
|
|
109
94
|
catch (e) {
|
|
110
95
|
console.warn(`Failed to load Yarn config from ${path}:`, e);
|
|
@@ -112,7 +97,6 @@ async function loadYarnConfig(path) {
|
|
|
112
97
|
}
|
|
113
98
|
}
|
|
114
99
|
async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYarnConfigPath = './.yarnrc.yml', globalYarnConfigPath = join(homedir(), '.yarnrc.yml')) {
|
|
115
|
-
console.debug('Loading registries...');
|
|
116
100
|
const [proxyConfig, localYarnConfig, globalYarnConfig] = await Promise.all([
|
|
117
101
|
loadProxyConfig(proxyConfigPath),
|
|
118
102
|
loadYarnConfig(localYarnConfigPath),
|
|
@@ -129,16 +113,13 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
129
113
|
config.npmRegistries?.[url];
|
|
130
114
|
if (registryConfig?.npmAuthToken) {
|
|
131
115
|
token = registryConfig.npmAuthToken;
|
|
132
|
-
console.debug(`Found token for ${normalizedUrl} in Yarn config`);
|
|
133
116
|
break;
|
|
134
117
|
}
|
|
135
118
|
}
|
|
136
119
|
}
|
|
137
120
|
registryMap.set(normalizedUrl, { url: normalizedUrl, token });
|
|
138
121
|
}
|
|
139
|
-
|
|
140
|
-
console.log('Loaded registries:', registries);
|
|
141
|
-
return registries;
|
|
122
|
+
return Array.from(registryMap.values());
|
|
142
123
|
}
|
|
143
124
|
export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
|
|
144
125
|
const proxyConfig = await loadProxyConfig(proxyConfigPath);
|
|
@@ -149,14 +130,12 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
149
130
|
console.log('HTTPS:', !!proxyConfig.https);
|
|
150
131
|
let proxyPort;
|
|
151
132
|
const requestHandler = async (req, res) => {
|
|
152
|
-
console.debug(`Received request: ${req.method} ${req.url}`);
|
|
153
133
|
if (!req.url || !req.headers.host) {
|
|
154
134
|
console.error('Invalid request: missing URL or host header');
|
|
155
135
|
res.writeHead(400).end('Invalid Request');
|
|
156
136
|
return;
|
|
157
137
|
}
|
|
158
138
|
const fullUrl = new URL(req.url, `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host}`);
|
|
159
|
-
console.debug(`Full URL: ${fullUrl.toString()}`);
|
|
160
139
|
if (basePath && !fullUrl.pathname.startsWith(basePath)) {
|
|
161
140
|
console.error(`Path ${fullUrl.pathname} does not match basePath ${basePath}`);
|
|
162
141
|
res.writeHead(404).end('Not Found');
|
|
@@ -167,13 +146,13 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
167
146
|
: fullUrl.pathname;
|
|
168
147
|
console.log(`Proxying: ${relativePath}`);
|
|
169
148
|
const fetchPromises = registries.map(async ({ url, token }) => {
|
|
170
|
-
await limiter.acquire();
|
|
149
|
+
await limiter.acquire();
|
|
171
150
|
try {
|
|
172
|
-
const cleanRelativePath = relativePath.replace(
|
|
173
|
-
const targetUrl = `${url}
|
|
151
|
+
const cleanRelativePath = relativePath.replace(/^\/+|\/+$/g, '');
|
|
152
|
+
const targetUrl = `${url}/${cleanRelativePath}${fullUrl.search || ''}`.replace(/\/+/g, '/');
|
|
174
153
|
console.log(`Fetching from: ${targetUrl}`);
|
|
175
154
|
const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
|
|
176
|
-
const response = await fetch(targetUrl, { headers });
|
|
155
|
+
const response = await fetch(targetUrl, { headers, });
|
|
177
156
|
console.log(`Response from ${url}: ${response.status} ${response.statusText}`);
|
|
178
157
|
return response.ok ? response : null;
|
|
179
158
|
}
|
|
@@ -182,7 +161,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
182
161
|
return null;
|
|
183
162
|
}
|
|
184
163
|
finally {
|
|
185
|
-
limiter.release();
|
|
164
|
+
limiter.release();
|
|
186
165
|
}
|
|
187
166
|
});
|
|
188
167
|
const responses = await Promise.all(fetchPromises);
|
|
@@ -198,20 +177,17 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
198
177
|
const data = await successResponse.json();
|
|
199
178
|
if (data.versions) {
|
|
200
179
|
const proxyBase = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePath}`;
|
|
201
|
-
console.debug(`Rewriting tarball URLs with proxy base: ${proxyBase}`);
|
|
202
180
|
for (const version in data.versions) {
|
|
203
181
|
const dist = data.versions[version]?.dist;
|
|
204
182
|
if (dist?.tarball) {
|
|
205
183
|
const originalUrl = new URL(dist.tarball);
|
|
206
184
|
const tarballPath = removeRegistryPrefix(dist.tarball, registries);
|
|
207
185
|
dist.tarball = `${proxyBase}${tarballPath}${originalUrl.search || ''}`;
|
|
208
|
-
console.debug(`Rewrote tarball: ${originalUrl} -> ${dist.tarball}`);
|
|
209
186
|
}
|
|
210
187
|
}
|
|
211
188
|
}
|
|
212
189
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
213
|
-
|
|
214
|
-
res.end(jsonResponse);
|
|
190
|
+
res.end(JSON.stringify(data));
|
|
215
191
|
}
|
|
216
192
|
catch (e) {
|
|
217
193
|
console.error('Failed to parse JSON response:', e);
|
|
@@ -224,9 +200,10 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
224
200
|
res.writeHead(502).end('Empty Response Body');
|
|
225
201
|
return;
|
|
226
202
|
}
|
|
203
|
+
const contentLength = successResponse.headers.get('Content-Length');
|
|
227
204
|
const safeHeaders = {
|
|
228
205
|
'Content-Type': successResponse.headers.get('Content-Type'),
|
|
229
|
-
'Content-Length':
|
|
206
|
+
'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
|
|
230
207
|
};
|
|
231
208
|
res.writeHead(successResponse.status, safeHeaders);
|
|
232
209
|
successResponse.body.pipe(res).on('error', (err) => {
|
|
@@ -270,7 +247,6 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
270
247
|
const address = server.address();
|
|
271
248
|
proxyPort = address.port;
|
|
272
249
|
const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
|
|
273
|
-
console.debug(`Writing port ${proxyPort} to file: ${portFile}`);
|
|
274
250
|
writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
|
|
275
251
|
console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePath}`);
|
|
276
252
|
resolve(server);
|
|
@@ -279,7 +255,6 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
279
255
|
}
|
|
280
256
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
281
257
|
const [, , configPath, localYarnPath, globalYarnPath, port] = process.argv;
|
|
282
|
-
console.log(`Starting server with args: configPath=${configPath}, localYarnPath=${localYarnPath}, globalYarnPath=${globalYarnPath}, port=${port}`);
|
|
283
258
|
startProxyServer(configPath, localYarnPath, globalYarnPath, parseInt(port, 10) || 0).catch(err => {
|
|
284
259
|
console.error('Failed to start server:', err);
|
|
285
260
|
process.exit(1);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -23,7 +23,6 @@ interface RegistryInfo { url: string; token?: string; }
|
|
|
23
23
|
interface PackageVersion { dist?: { tarball?: string }; }
|
|
24
24
|
interface PackageData { versions?: Record<string, PackageVersion>; }
|
|
25
25
|
|
|
26
|
-
// 并发控制队列
|
|
27
26
|
class ConcurrencyLimiter {
|
|
28
27
|
private maxConcurrency: number;
|
|
29
28
|
private current: number = 0;
|
|
@@ -53,8 +52,7 @@ class ConcurrencyLimiter {
|
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
const limiter = new ConcurrencyLimiter(5); // 限制为 5 个并发请求
|
|
55
|
+
const limiter = new ConcurrencyLimiter(3);
|
|
58
56
|
|
|
59
57
|
function normalizeUrl(url: string): string {
|
|
60
58
|
try {
|
|
@@ -64,20 +62,16 @@ function normalizeUrl(url: string): string {
|
|
|
64
62
|
} else if (urlObj.protocol === 'https:' && (urlObj.port === '443' || urlObj.port === '')) {
|
|
65
63
|
urlObj.port = '';
|
|
66
64
|
}
|
|
67
|
-
|
|
68
|
-
urlObj.pathname += '/';
|
|
69
|
-
}
|
|
70
|
-
console.debug(`Normalized URL: ${url} -> ${urlObj.toString()}`);
|
|
65
|
+
urlObj.pathname = urlObj.pathname.replace(/\/+$/, '');
|
|
71
66
|
return urlObj.toString();
|
|
72
67
|
} catch (e) {
|
|
73
68
|
console.error(`Invalid URL: ${url}`, e);
|
|
74
|
-
return url.
|
|
69
|
+
return url.replace(/\/+$/, '');
|
|
75
70
|
}
|
|
76
71
|
}
|
|
77
72
|
|
|
78
73
|
function resolvePath(path: string): string {
|
|
79
|
-
|
|
80
|
-
return resolved;
|
|
74
|
+
return path.startsWith('~/') ? join(homedir(), path.slice(2)) : resolve(path);
|
|
81
75
|
}
|
|
82
76
|
|
|
83
77
|
function removeRegistryPrefix(tarballUrl: string, registries: RegistryInfo[]): string {
|
|
@@ -87,15 +81,11 @@ function removeRegistryPrefix(tarballUrl: string, registries: RegistryInfo[]): s
|
|
|
87
81
|
.map(r => normalizeUrl(r.url))
|
|
88
82
|
.sort((a, b) => b.length - a.length);
|
|
89
83
|
|
|
90
|
-
console.debug(`Removing registry prefix from tarball: ${normalizedTarball}`);
|
|
91
84
|
for (const registry of normalizedRegistries) {
|
|
92
85
|
if (normalizedTarball.startsWith(registry)) {
|
|
93
|
-
|
|
94
|
-
console.debug(`Matched registry ${registry}, result: ${result}`);
|
|
95
|
-
return result;
|
|
86
|
+
return normalizedTarball.slice(registry.length) || '/';
|
|
96
87
|
}
|
|
97
88
|
}
|
|
98
|
-
console.debug(`No registry prefix matched for ${normalizedTarball}`);
|
|
99
89
|
} catch (e) {
|
|
100
90
|
console.error(`Invalid URL in removeRegistryPrefix: ${tarballUrl}`, e);
|
|
101
91
|
}
|
|
@@ -104,14 +94,12 @@ function removeRegistryPrefix(tarballUrl: string, registries: RegistryInfo[]): s
|
|
|
104
94
|
|
|
105
95
|
async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml'): Promise<ProxyConfig> {
|
|
106
96
|
const resolvedPath = resolvePath(proxyConfigPath);
|
|
107
|
-
console.debug(`Loading proxy config from: ${resolvedPath}`);
|
|
108
97
|
try {
|
|
109
98
|
const content = await readFile(resolvedPath, 'utf8');
|
|
110
99
|
const config = load(content) as ProxyConfig;
|
|
111
100
|
if (!config.registries) {
|
|
112
101
|
throw new Error('Missing required "registries" field in config');
|
|
113
102
|
}
|
|
114
|
-
console.debug('Loaded proxy config:', JSON.stringify(config, null, 2));
|
|
115
103
|
return config;
|
|
116
104
|
} catch (e) {
|
|
117
105
|
console.error(`Failed to load proxy config from ${resolvedPath}:`, e);
|
|
@@ -120,12 +108,9 @@ async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml'): Promi
|
|
|
120
108
|
}
|
|
121
109
|
|
|
122
110
|
async function loadYarnConfig(path: string): Promise<YarnConfig> {
|
|
123
|
-
console.debug(`Loading Yarn config from: ${path}`);
|
|
124
111
|
try {
|
|
125
112
|
const content = await readFile(resolvePath(path), 'utf8');
|
|
126
|
-
|
|
127
|
-
console.debug(`Loaded Yarn config from ${path}:`, JSON.stringify(config, null, 2));
|
|
128
|
-
return config;
|
|
113
|
+
return load(content) as YarnConfig;
|
|
129
114
|
} catch (e) {
|
|
130
115
|
console.warn(`Failed to load Yarn config from ${path}:`, e);
|
|
131
116
|
return {};
|
|
@@ -137,7 +122,6 @@ async function loadRegistries(
|
|
|
137
122
|
localYarnConfigPath = './.yarnrc.yml',
|
|
138
123
|
globalYarnConfigPath = join(homedir(), '.yarnrc.yml')
|
|
139
124
|
): Promise<RegistryInfo[]> {
|
|
140
|
-
console.debug('Loading registries...');
|
|
141
125
|
const [proxyConfig, localYarnConfig, globalYarnConfig] = await Promise.all([
|
|
142
126
|
loadProxyConfig(proxyConfigPath),
|
|
143
127
|
loadYarnConfig(localYarnConfigPath),
|
|
@@ -156,16 +140,13 @@ async function loadRegistries(
|
|
|
156
140
|
config.npmRegistries?.[url];
|
|
157
141
|
if (registryConfig?.npmAuthToken) {
|
|
158
142
|
token = registryConfig.npmAuthToken;
|
|
159
|
-
console.debug(`Found token for ${normalizedUrl} in Yarn config`);
|
|
160
143
|
break;
|
|
161
144
|
}
|
|
162
145
|
}
|
|
163
146
|
}
|
|
164
147
|
registryMap.set(normalizedUrl, { url: normalizedUrl, token });
|
|
165
148
|
}
|
|
166
|
-
|
|
167
|
-
console.log('Loaded registries:', registries);
|
|
168
|
-
return registries;
|
|
149
|
+
return Array.from(registryMap.values());
|
|
169
150
|
}
|
|
170
151
|
|
|
171
152
|
export async function startProxyServer(
|
|
@@ -185,7 +166,6 @@ export async function startProxyServer(
|
|
|
185
166
|
let proxyPort: number;
|
|
186
167
|
|
|
187
168
|
const requestHandler = async (req: any, res: any) => {
|
|
188
|
-
console.debug(`Received request: ${req.method} ${req.url}`);
|
|
189
169
|
if (!req.url || !req.headers.host) {
|
|
190
170
|
console.error('Invalid request: missing URL or host header');
|
|
191
171
|
res.writeHead(400).end('Invalid Request');
|
|
@@ -193,7 +173,6 @@ export async function startProxyServer(
|
|
|
193
173
|
}
|
|
194
174
|
|
|
195
175
|
const fullUrl = new URL(req.url, `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host}`);
|
|
196
|
-
console.debug(`Full URL: ${fullUrl.toString()}`);
|
|
197
176
|
if (basePath && !fullUrl.pathname.startsWith(basePath)) {
|
|
198
177
|
console.error(`Path ${fullUrl.pathname} does not match basePath ${basePath}`);
|
|
199
178
|
res.writeHead(404).end('Not Found');
|
|
@@ -206,20 +185,20 @@ export async function startProxyServer(
|
|
|
206
185
|
console.log(`Proxying: ${relativePath}`);
|
|
207
186
|
|
|
208
187
|
const fetchPromises = registries.map(async ({ url, token }) => {
|
|
209
|
-
await limiter.acquire();
|
|
188
|
+
await limiter.acquire();
|
|
210
189
|
try {
|
|
211
|
-
const cleanRelativePath = relativePath.replace(
|
|
212
|
-
const targetUrl = `${url}
|
|
190
|
+
const cleanRelativePath = relativePath.replace(/^\/+|\/+$/g, '');
|
|
191
|
+
const targetUrl = `${url}/${cleanRelativePath}${fullUrl.search || ''}`.replace(/\/+/g, '/');
|
|
213
192
|
console.log(`Fetching from: ${targetUrl}`);
|
|
214
193
|
const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
|
|
215
|
-
const response = await fetch(targetUrl, { headers });
|
|
194
|
+
const response = await fetch(targetUrl, { headers, });
|
|
216
195
|
console.log(`Response from ${url}: ${response.status} ${response.statusText}`);
|
|
217
196
|
return response.ok ? response : null;
|
|
218
197
|
} catch (e) {
|
|
219
198
|
console.error(`Failed to fetch from ${url}:`, e);
|
|
220
199
|
return null;
|
|
221
200
|
} finally {
|
|
222
|
-
limiter.release();
|
|
201
|
+
limiter.release();
|
|
223
202
|
}
|
|
224
203
|
});
|
|
225
204
|
|
|
@@ -237,20 +216,17 @@ export async function startProxyServer(
|
|
|
237
216
|
const data = await successResponse.json() as PackageData;
|
|
238
217
|
if (data.versions) {
|
|
239
218
|
const proxyBase = `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host || 'localhost:' + proxyPort}${basePath}`;
|
|
240
|
-
console.debug(`Rewriting tarball URLs with proxy base: ${proxyBase}`);
|
|
241
219
|
for (const version in data.versions) {
|
|
242
220
|
const dist = data.versions[version]?.dist;
|
|
243
221
|
if (dist?.tarball) {
|
|
244
222
|
const originalUrl = new URL(dist.tarball);
|
|
245
223
|
const tarballPath = removeRegistryPrefix(dist.tarball, registries);
|
|
246
224
|
dist.tarball = `${proxyBase}${tarballPath}${originalUrl.search || ''}`;
|
|
247
|
-
console.debug(`Rewrote tarball: ${originalUrl} -> ${dist.tarball}`);
|
|
248
225
|
}
|
|
249
226
|
}
|
|
250
227
|
}
|
|
251
228
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
252
|
-
|
|
253
|
-
res.end(jsonResponse);
|
|
229
|
+
res.end(JSON.stringify(data));
|
|
254
230
|
} catch (e) {
|
|
255
231
|
console.error('Failed to parse JSON response:', e);
|
|
256
232
|
res.writeHead(502).end('Invalid Upstream Response');
|
|
@@ -261,9 +237,10 @@ export async function startProxyServer(
|
|
|
261
237
|
res.writeHead(502).end('Empty Response Body');
|
|
262
238
|
return;
|
|
263
239
|
}
|
|
240
|
+
const contentLength = successResponse.headers.get('Content-Length');
|
|
264
241
|
const safeHeaders = {
|
|
265
242
|
'Content-Type': successResponse.headers.get('Content-Type'),
|
|
266
|
-
'Content-Length':
|
|
243
|
+
'Content-Length': contentLength && !isNaN(Number(contentLength)) ? contentLength : undefined,
|
|
267
244
|
};
|
|
268
245
|
res.writeHead(successResponse.status, safeHeaders);
|
|
269
246
|
successResponse.body.pipe(res).on('error', (err:any) => {
|
|
@@ -307,7 +284,6 @@ export async function startProxyServer(
|
|
|
307
284
|
const address = server.address() as AddressInfo;
|
|
308
285
|
proxyPort = address.port;
|
|
309
286
|
const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
|
|
310
|
-
console.debug(`Writing port ${proxyPort} to file: ${portFile}`);
|
|
311
287
|
writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
|
|
312
288
|
console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePath}`);
|
|
313
289
|
resolve(server);
|
|
@@ -317,7 +293,6 @@ export async function startProxyServer(
|
|
|
317
293
|
|
|
318
294
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
319
295
|
const [,, configPath, localYarnPath, globalYarnPath, port] = process.argv;
|
|
320
|
-
console.log(`Starting server with args: configPath=${configPath}, localYarnPath=${localYarnPath}, globalYarnPath=${globalYarnPath}, port=${port}`);
|
|
321
296
|
startProxyServer(
|
|
322
297
|
configPath,
|
|
323
298
|
localYarnPath,
|