Skip to content

fix(logger-plugin): support ipv6 host and handle undefined protocol/host#1215

Merged
chimurai merged 3 commits intomasterfrom
improve-logger-plugin
Apr 26, 2026
Merged

fix(logger-plugin): support ipv6 host and handle undefined protocol/host#1215
chimurai merged 3 commits intomasterfrom
improve-logger-plugin

Conversation

@chimurai
Copy link
Copy Markdown
Owner

@chimurai chimurai commented Apr 26, 2026

Improve logger-plugin

fixed: #1035
fixed: #1056

Summary by CodeRabbit

  • New Features

    • IPv6 host support for improved network compatibility.
  • Bug Fixes

    • Better handling of undefined protocol/host values to avoid errors. (nock v13 and older)
    • Improved logging for unexpected proxy failures.
  • Tests

    • Added new end-to-end and unit tests to validate proxy behavior, routing, query/body forwarding, and URL handling. (nock & msw)

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

Adds a safe URL-construction utility with IPv6 bracket handling and fallbacks for missing protocol/host, and updates the logger plugin to use it; adds unit and E2E tests (msw, nock) and updates dev dependencies and changelog.

Changes

Cohort / File(s) Summary
Changelog & Package
CHANGELOG.md, package.json
Appends changelog entry for the logger fix; adds msw and nock to devDependencies.
Logger Plugin
src/plugins/default/logger-plugin.ts
Replaces manual URL construction with createUrl(...) in proxyRes handler; adds a console.error for unexpected failures and preserves fallback to options.target/proxyRes.req.path.
URL Utility
src/utils/create-url.ts
New createUrl export that builds a URL from optional protocol, host, port, path; wraps IPv6 hosts in brackets and provides safe fallbacks when protocol/host are undefined.
Unit Tests
test/unit/utils/create-url.spec.ts
New unit tests validating HTTP/HTTPS, port handling, IPv6 bracket behavior, undefined/empty fallbacks, and numeric port coercion.
E2E Tests
test/e2e/msw.spec.ts, test/e2e/nock.spec.ts
New E2E suites exercising proxy forwarding (GET/POST), query-string preservation, JSON bodies, and router-based retargeting using MSW and nock.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I found a URL lost in the fog and mist,
Brackets for IPv6 — a tidy little twist.
When protocol hides, fallbacks take the wheel,
Now logger hops safe, and tests cheer with zeal. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main fix: adding IPv6 host support and handling undefined protocol/host in the logger-plugin.
Linked Issues check ✅ Passed All code changes directly address the linked issues #1035 and #1056: new createUrl utility handles undefined protocol/host with sensible defaults, logger-plugin uses it to build URLs safely, and comprehensive tests verify behavior with mocking libraries.
Out of Scope Changes check ✅ Passed All changes are in scope: createUrl utility, logger-plugin updates, CHANGELOG entry, dev dependencies (msw/nock for testing), and comprehensive test suites for the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch improve-logger-plugin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 26, 2026

npm i https://pkg.pr.new/http-proxy-middleware@1215

commit: 87ae2c4

@coveralls
Copy link
Copy Markdown

coveralls commented Apr 26, 2026

Coverage Status

coverage: 94.07% (-0.7%) from 94.78% — improve-logger-plugin into master

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
src/utils/create-url.ts (1)

1-1: Use node:url to match the rest of the codebase.

src/plugins/default/logger-plugin.ts (and others) use the node: prefix; aligning here keeps imports consistent and makes the built-in module unambiguous.

♻️ Proposed change
-import { URL } from 'url';
+import { URL } from 'node:url';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/create-url.ts` at line 1, The import for the URL constructor is
using 'url' but the project standard is to use the Node built-in prefix; update
the import in src/utils/create-url.ts to import URL from 'node:url' instead of
'url' so it matches other modules (e.g., logger-plugin) and avoids ambiguity
when locating the built-in URL symbol.
test/unit/utils/create-url.spec.ts (1)

47-50: Move this test out of the "happy paths" group.

It asserts a toThrow() outcome and documents pass-through bracket behavior — better suited to the "edge cases" describe block (e.g., a new edge cases — already-bracketed IPv6 group) for accurate grouping.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/utils/create-url.spec.ts` around lines 47 - 50, The test asserting
createUrl({ protocol: 'http:', host: '[::1]', port: '9000' }) throws (checking
double-bracketing/pass-through behavior) should be relocated out of the "happy
paths" describe and into an "edge cases" describe block (e.g., "edge cases —
already-bracketed IPv6") to reflect its expected-to-throw behavior; update the
surrounding describe/it grouping so the test still uses the same it(...) title
but resides under the new edge-case describe to keep test organization clear.
src/plugins/default/logger-plugin.ts (1)

56-62: Use the configured logger instead of console.error in the catch fallback.

logger is already in scope (Line 23) and is used elsewhere in this plugin (e.g., Line 33). Routing this error through console.error bypasses any custom logger provided via the logger option, so consumers (e.g., webpack-dev-server, browser-sync) won’t see this diagnostic in their normal pipeline.

♻️ Proposed refactor
     } catch (err) {
       // should not error. keeping fallback just in case
-      console.error('[HPM] Unexpected error while creating target URL', err);
+      logger.error('[HPM] Unexpected error while creating target URL %o', err);
       // fallback to old implementation (less correct - without port)
       target = new URL(options.target as URL);
       target.pathname = proxyRes.req.path;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/default/logger-plugin.ts` around lines 56 - 62, Replace the
console.error call inside the catch block that handles target URL creation with
the configured logger: use the existing logger variable to log the error (e.g.,
logger.error or appropriate logger method) and include the error object and
context message; keep the fallback creation of target via new URL(options.target
as URL) and setting target.pathname = proxyRes.req.path unchanged. Ensure you
update the log invocation within the catch in the function that constructs the
target URL so it uses logger instead of console.
test/e2e/msw.spec.ts (1)

17-27: Align with MSW's recommended lifecycle pattern for better efficiency.

MSW's documented best practice uses server.listen() in beforeAll, server.resetHandlers() in afterEach, and server.close() in afterAll. The current setup starts and stops the interceptor per test, which adds unnecessary overhead. The handlers are correctly reset between tests, so behavior is unaffected—this is purely an optimization.

♻️ Proposed refactor
-import { afterEach, beforeEach, describe, expect, it } from 'vitest';
+import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest';
@@
-  beforeEach(() => {
-    // Supertest sends local loopback requests to the in-memory app; bypass those.
-    server.listen({ onUnhandledRequest: 'bypass' });
-  });
-
-  afterEach(() => {
-    server.resetHandlers();
-    server.close();
-  });
+  beforeAll(() => {
+    // Supertest sends local loopback requests to the in-memory app; bypass those.
+    server.listen({ onUnhandledRequest: 'bypass' });
+  });
+
+  afterEach(() => {
+    server.resetHandlers();
+  });
+
+  afterAll(() => {
+    server.close();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/msw.spec.ts` around lines 17 - 27, The MSW lifecycle is inefficient:
change the test setup to call setupServer() as now but move server.listen({
onUnhandledRequest: 'bypass' }) from beforeEach into a beforeAll, keep
server.resetHandlers() in afterEach, and move server.close() from afterEach into
an afterAll; update the test hooks referencing the server instance (setupServer,
server.listen, server.resetHandlers, server.close) accordingly so the
interceptor starts once before the suite and stops once after the suite while
still resetting handlers between tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/plugins/default/logger-plugin.ts`:
- Around line 56-62: Replace the console.error call inside the catch block that
handles target URL creation with the configured logger: use the existing logger
variable to log the error (e.g., logger.error or appropriate logger method) and
include the error object and context message; keep the fallback creation of
target via new URL(options.target as URL) and setting target.pathname =
proxyRes.req.path unchanged. Ensure you update the log invocation within the
catch in the function that constructs the target URL so it uses logger instead
of console.

In `@src/utils/create-url.ts`:
- Line 1: The import for the URL constructor is using 'url' but the project
standard is to use the Node built-in prefix; update the import in
src/utils/create-url.ts to import URL from 'node:url' instead of 'url' so it
matches other modules (e.g., logger-plugin) and avoids ambiguity when locating
the built-in URL symbol.

In `@test/e2e/msw.spec.ts`:
- Around line 17-27: The MSW lifecycle is inefficient: change the test setup to
call setupServer() as now but move server.listen({ onUnhandledRequest: 'bypass'
}) from beforeEach into a beforeAll, keep server.resetHandlers() in afterEach,
and move server.close() from afterEach into an afterAll; update the test hooks
referencing the server instance (setupServer, server.listen,
server.resetHandlers, server.close) accordingly so the interceptor starts once
before the suite and stops once after the suite while still resetting handlers
between tests.

In `@test/unit/utils/create-url.spec.ts`:
- Around line 47-50: The test asserting createUrl({ protocol: 'http:', host:
'[::1]', port: '9000' }) throws (checking double-bracketing/pass-through
behavior) should be relocated out of the "happy paths" describe and into an
"edge cases" describe block (e.g., "edge cases — already-bracketed IPv6") to
reflect its expected-to-throw behavior; update the surrounding describe/it
grouping so the test still uses the same it(...) title but resides under the new
edge-case describe to keep test organization clear.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db951e2f-1262-45c1-91f6-7ce98e023efc

📥 Commits

Reviewing files that changed from the base of the PR and between 5d28676 and d7b4e4b.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • CHANGELOG.md
  • package.json
  • src/plugins/default/logger-plugin.ts
  • src/utils/create-url.ts
  • test/e2e/msw.spec.ts
  • test/e2e/nock.spec.ts
  • test/unit/utils/create-url.spec.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
test/e2e/msw.spec.ts (2)

125-153: Router test mirrors nock parity well; consider also asserting [HPM] log here.

Since #1056 specifically targets the router (no target) code path in the logger, asserting console.info was called with the expected [HPM] ... -> http://localhost:45679/api/router [200] line in this test would directly cover the regression that motivated the PR. Currently only the GET test asserts logging; the router branch — which is the one #1056 calls out — is verified only via response body.

♻️ Suggested addition
   it('supports router to re-target specific requests', async () => {
+    await using consoleInfoSpy = await vi.spyOn(console, 'info');
+
     server.use(
       http.get(`${alternateTarget}/api/router`, () => {
         return new HttpResponse('routed target', { status: 200 });
       }),
       http.get(`${target}/api/default`, () => {
         return new HttpResponse('default target', { status: 200 });
       }),
     );

     const agent = request(
       createApp(
         createProxyMiddleware({
           pathFilter: '/api',
           // Keep msw-based e2e stable and aligned with nock e2e transport path.
           followRedirects: true,
+          logger: console,
           router(req) {
             return req.url === '/api/router' ? alternateTarget : target;
           },
         }),
       ),
     );

     const routedResponse = await agent.get('/api/router').expect(200);
     const defaultResponse = await agent.get('/api/default').expect(200);

     expect(routedResponse.text).toBe('routed target');
     expect(defaultResponse.text).toBe('default target');
+    expect(consoleInfoSpy).toHaveBeenCalledWith(
+      '[HPM] GET /api/router -> http://localhost:45679/api/router [200]',
+    );
+    expect(consoleInfoSpy).toHaveBeenCalledWith(
+      '[HPM] GET /api/default -> http://localhost:45678/api/default [200]',
+    );
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/msw.spec.ts` around lines 125 - 153, Add an assertion that the
logger emitted the HPM routing line by spying on console.info around the router
request: before calling agent.get('/api/router') create a spy (e.g., const
consoleSpy = jest.spyOn(console, 'info').mockImplementation(() => {})), perform
the routed request via routedResponse = await
agent.get('/api/router').expect(200), then
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[HPM]'),
expect.stringContaining('-> http://localhost:45679/api/router'),
expect.stringContaining('[200]')) (or use a single expect.stringMatching regex
that matches the full log line), and finally restore the spy with
consoleSpy.mockRestore(); reference the createProxyMiddleware({ router }) usage
and the routedResponse/agent variables to locate where to insert the spy and
assertion.

17-27: Refactor MSW lifecycle to follow the recommended beforeAll/afterAll pattern.

The current code calls server.listen() in beforeEach and server.close() in afterEach, which reinstalls MSW interceptors for every test. MSW's documented pattern is to call listen() once in beforeAll, resetHandlers() in afterEach, and close() once in afterAll. This eliminates unnecessary setup/teardown overhead per test.

Suggested refactor
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
@@
-  beforeEach(() => {
-    // Supertest sends local loopback requests to the in-memory app; bypass those.
-    server.listen({ onUnhandledRequest: 'bypass' });
-  });
-
-  afterEach(() => {
-    server.resetHandlers();
-    server.close();
-  });
+  // Supertest sends local loopback requests to the in-memory app; bypass those.
+  beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
+  afterEach(() => server.resetHandlers());
+  afterAll(() => server.close());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/msw.spec.ts` around lines 17 - 27, Move MSW server lifecycle from
per-test to suite-level: call setupServer() remains, replace
beforeEach/afterEach listen/close usage with beforeAll(() => server.listen({
onUnhandledRequest: 'bypass' })) and afterAll(() => server.close()), and keep
afterEach(() => server.resetHandlers()) to reset per-test handlers; update
functions referenced: server, setupServer, beforeEach, afterEach, beforeAll,
afterAll, server.listen, server.resetHandlers, server.close.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/e2e/msw.spec.ts`:
- Around line 125-153: Add an assertion that the logger emitted the HPM routing
line by spying on console.info around the router request: before calling
agent.get('/api/router') create a spy (e.g., const consoleSpy =
jest.spyOn(console, 'info').mockImplementation(() => {})), perform the routed
request via routedResponse = await agent.get('/api/router').expect(200), then
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[HPM]'),
expect.stringContaining('-> http://localhost:45679/api/router'),
expect.stringContaining('[200]')) (or use a single expect.stringMatching regex
that matches the full log line), and finally restore the spy with
consoleSpy.mockRestore(); reference the createProxyMiddleware({ router }) usage
and the routedResponse/agent variables to locate where to insert the spy and
assertion.
- Around line 17-27: Move MSW server lifecycle from per-test to suite-level:
call setupServer() remains, replace beforeEach/afterEach listen/close usage with
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })) and afterAll(()
=> server.close()), and keep afterEach(() => server.resetHandlers()) to reset
per-test handlers; update functions referenced: server, setupServer, beforeEach,
afterEach, beforeAll, afterAll, server.listen, server.resetHandlers,
server.close.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7128c6c6-081c-4d29-ad4c-73621b3f0ed4

📥 Commits

Reviewing files that changed from the base of the PR and between d7b4e4b and 87ae2c4.

📒 Files selected for processing (2)
  • test/e2e/msw.spec.ts
  • test/e2e/nock.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/nock.spec.ts

@chimurai chimurai merged commit dcacc02 into master Apr 26, 2026
21 checks passed
@chimurai chimurai deleted the improve-logger-plugin branch April 26, 2026 12:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exception thrown in logger when trying to build URL for message Exception thrown in logger when trying to build URL for message

2 participants