maven-proxy 1.0.3 → 1.1.1

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.
@@ -44,7 +44,8 @@ function resolveEffectiveMode(options) {
44
44
  return forced;
45
45
  }
46
46
 
47
- return isProjectWorkspace(process.cwd()) ? "development" : "user";
47
+ // CLI defaults to user mode to load ~/maven-proxy/config unless explicitly overridden.
48
+ return "user";
48
49
  }
49
50
 
50
51
  function printHelp() {
@@ -213,9 +214,7 @@ async function startServer(options) {
213
214
  }
214
215
 
215
216
  function applyConfigOverrides(options) {
216
- if (options.mode) {
217
- process.env.MAVEN_PROXY_CONFIG_MODE = options.mode;
218
- }
217
+ process.env.MAVEN_PROXY_CONFIG_MODE = resolveEffectiveMode(options);
219
218
 
220
219
  if (options.configPath) {
221
220
  process.env.MAVEN_PROXY_CONFIG_FILE = resolvePath(options.configPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maven-proxy",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "description": "Maven proxy with cache, HTTPS MITM for selected domains, and local repo publishing",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -261,6 +261,27 @@ async function removeIfExists(filePath) {
261
261
  }
262
262
  }
263
263
 
264
+ function toHost(urlObj) {
265
+ if (!urlObj || typeof urlObj !== "object") {
266
+ return "";
267
+ }
268
+
269
+ return String(urlObj.hostname || "");
270
+ }
271
+
272
+ function toBodyPreview(value, maxLength = 512) {
273
+ const text = String(value || "").replace(/\s+/g, " ").trim();
274
+ if (!text) {
275
+ return "";
276
+ }
277
+
278
+ if (text.length <= maxLength) {
279
+ return text;
280
+ }
281
+
282
+ return `${text.slice(0, maxLength)}...(truncated)`;
283
+ }
284
+
264
285
  export class Downloader {
265
286
  constructor(config, domainMatcher, upstreamProxyManager = null) {
266
287
  this.config = config;
@@ -305,6 +326,8 @@ export class Downloader {
305
326
  }
306
327
 
307
328
  async #downloadAtomic(urlObj, finalPath, requestHeaders) {
329
+ const startedAt = Date.now();
330
+
308
331
  await fs.promises.mkdir(path.dirname(finalPath), { recursive: true });
309
332
  const tempPath = `${finalPath}.temp`;
310
333
  await removeIfExists(tempPath);
@@ -367,6 +390,14 @@ export class Downloader {
367
390
 
368
391
  await verifyFileSize(tempPath, metadata.contentLength);
369
392
  await fs.promises.rename(tempPath, finalPath);
393
+
394
+ const finalStats = await fs.promises.stat(finalPath);
395
+ this.logDownload("download succeeded", downloadUrl, {
396
+ host: hostname,
397
+ targetPath: finalPath,
398
+ size: finalStats.size,
399
+ elapsedMs: Date.now() - startedAt,
400
+ });
370
401
  } catch (error) {
371
402
  if (isLocalFsWriteError(error)) {
372
403
  if (!error.statusCode) {
@@ -381,6 +412,16 @@ export class Downloader {
381
412
  });
382
413
  }
383
414
 
415
+ this.logDownload("download failed", urlObj, {
416
+ host: toHost(urlObj),
417
+ code: error.code || "UNKNOWN",
418
+ statusCode: error.statusCode || 0,
419
+ targetPath: finalPath,
420
+ tempPath,
421
+ message: error.message,
422
+ upstreamBodyPreview: toBodyPreview(error.upstreamBody),
423
+ });
424
+
384
425
  await removeIfExists(tempPath);
385
426
  throw error;
386
427
  }
@@ -74,6 +74,11 @@ function sendText(res, statusCode, message) {
74
74
  res.end(message);
75
75
  }
76
76
 
77
+ function sendErrorText(res, statusCode, message, context = "proxy") {
78
+ console.error(`[${context}] response error status=${statusCode} message=${message}`);
79
+ sendText(res, statusCode, message);
80
+ }
81
+
77
82
  function buildUrl(req, forcedProtocol = null) {
78
83
  const raw = req.url || "/";
79
84
  if (/^https?:\/\//i.test(raw)) {
@@ -143,7 +148,8 @@ function forwardDirectRequest(req, res, urlObj, timeoutMs, upstreamProxyManager
143
148
 
144
149
  upstreamReq.on("error", (error) => {
145
150
  if (!res.headersSent) {
146
- sendText(res, 502, `Proxy forward failed: ${error.message}`);
151
+ const message = `Proxy forward failed: ${error.message}`;
152
+ sendErrorText(res, 502, message, "proxy");
147
153
  } else {
148
154
  res.destroy(error);
149
155
  }
@@ -158,7 +164,8 @@ export function createHttpRequestHandler({ config, downloader, upstreamProxyMana
158
164
  try {
159
165
  urlObj = buildUrl(req, forcedProtocol);
160
166
  } catch (error) {
161
- sendText(res, 400, `Bad request: ${error.message}`);
167
+ const message = `Bad request: ${error.message}`;
168
+ sendErrorText(res, 400, message, "proxy");
162
169
  return;
163
170
  }
164
171
 
@@ -176,7 +183,8 @@ export function createHttpRequestHandler({ config, downloader, upstreamProxyMana
176
183
  includeHost: ecosystem !== "maven",
177
184
  });
178
185
  } catch (error) {
179
- sendText(res, 400, `Invalid cache path: ${error.message}`);
186
+ const message = `Invalid cache path: ${error.message}`;
187
+ sendErrorText(res, 400, message, "proxy");
180
188
  return;
181
189
  }
182
190
 
@@ -210,7 +218,8 @@ export function createHttpRequestHandler({ config, downloader, upstreamProxyMana
210
218
 
211
219
  const statusCode = error.statusCode || 502;
212
220
  const label = statusCode === 500 ? "Local cache write failed" : "Download failed";
213
- sendText(res, statusCode, `${label}: ${error.message}`);
221
+ const message = `${label}: ${error.message}`;
222
+ sendErrorText(res, statusCode, message, "proxy");
214
223
  }
215
224
  };
216
225
  }
@@ -218,7 +227,8 @@ export function createHttpRequestHandler({ config, downloader, upstreamProxyMana
218
227
  export function createMitmHttpServer(handleHttpRequestPath) {
219
228
  const server = http.createServer((req, res) => {
220
229
  handleHttpRequestPath(req, res, "https:").catch((error) => {
221
- sendText(res, 500, `MITM request failed: ${error.message}`);
230
+ const message = `MITM request failed: ${error.message}`;
231
+ sendErrorText(res, 500, message, "proxy-mitm");
222
232
  });
223
233
  });
224
234
 
@@ -7,6 +7,11 @@ function sendText(res, statusCode, message) {
7
7
  res.end(message);
8
8
  }
9
9
 
10
+ function sendErrorText(res, statusCode, message) {
11
+ console.error(`[proxy] response error status=${statusCode} message=${message}`);
12
+ sendText(res, statusCode, message);
13
+ }
14
+
10
15
  export function startProxyServer(config, certManager, downloader, matchesDomain, upstreamProxyManager = null) {
11
16
  const handleHttpRequestPath = createHttpRequestHandler({
12
17
  config,
@@ -18,7 +23,8 @@ export function startProxyServer(config, certManager, downloader, matchesDomain,
18
23
 
19
24
  const server = http.createServer((req, res) => {
20
25
  handleHttpRequestPath(req, res, null).catch((error) => {
21
- sendText(res, 500, `Proxy request failed: ${error.message}`);
26
+ const message = `Proxy request failed: ${error.message}`;
27
+ sendErrorText(res, 500, message);
22
28
  });
23
29
  });
24
30
 
@@ -118,7 +118,13 @@ export class UpstreamProxyManager {
118
118
 
119
119
  const cacheKey = `${proxyUrl}`;
120
120
  if (!this.agentCache.has(cacheKey)) {
121
- this.agentCache.set(cacheKey, new ProxyAgent(proxyUrl));
121
+ // proxy-agent v6 expects resolver-style options for deterministic proxy routing.
122
+ this.agentCache.set(
123
+ cacheKey,
124
+ new ProxyAgent({
125
+ getProxyForUrl: () => proxyUrl,
126
+ }),
127
+ );
122
128
  }
123
129
 
124
130
  return this.agentCache.get(cacheKey);
@@ -110,8 +110,10 @@ export function startRepoServer(config, downloader = null) {
110
110
  fs.createReadStream(filePath).pipe(res);
111
111
  } catch (error) {
112
112
  const statusCode = error.statusCode && error.statusCode >= 400 ? 502 : 500;
113
+ const message = `Repo server error: ${error.message}`;
114
+ console.error(`[repo] response error status=${statusCode} message=${message}`);
113
115
  res.writeHead(statusCode, { "content-type": "text/plain; charset=utf-8" });
114
- res.end(`Repo server error: ${error.message}`);
116
+ res.end(message);
115
117
  }
116
118
  });
117
119