npm.io
1.1.0 • Published 18h agoCLI

@andrei.fyi/devproxy

Licence
Version
1.1.0
Deps
3
Size
24 kB
Vulns
0
Weekly
0

devproxy

WIP

A local HTTPS-intercepting proxy (mockttp) with user-defined request/response rewrite rules. It can also launch Chromium through the proxy.

Requires Node.js 22 or later.

Usage

devproxy init                 write a starter config.js
devproxy check                validate config.js and list its rules
devproxy start                start the proxy for any browser or tool
devproxy start --browser      also launch Chromium through the proxy
devproxy start -o <url>       launch Chromium on a page (implies --browser)
devproxy ca                   show the CA certificate to trust, creating it if missing

Run devproxy <command> --help for each command's options. start, check, and ca read config.js unless -c <file> names another file. start flags override the corresponding config values.

The proxy signs intercepted HTTPS traffic with a local CA stored in cert.pem and cert.key (paths set by the ca config key). Chromium launched by start trusts it automatically. For other browsers or tools, import the certificate that devproxy ca prints as a trusted authority. If the CA has expired, delete both files and run devproxy ca to create a new one.

An invalid flag, a config file that is missing, fails to load, or does not match the shape below, or an unusable CA exits with code 2 and names the problem.

Configuration

module.exports = {
  // launch Chromium when running `devproxy start` (default: false)
  browser: false,
  // page Chromium opens (default: "https://github.com/3rd/devproxy")
  open: "https://example.com",
  // chromium binary to launch (default: "google-chrome-stable")
  chromiumBinary: "google-chrome-stable",
  // proxy port (default: auto-assigned)
  port: 8080,
  // chromium profile directory (default: "<cwd>/devproxy_profile")
  profilePath: "./devproxy_profile",
  // launch chromium with --disable-web-security (default: false)
  disableWebSecurity: false,
  // CA used to intercept HTTPS, created on first use
  ca: {
    certPath: "cert.pem",
    keyPath: "cert.key",
  },
  // websockets pass through unless forwarded
  ws: {
    // apply the forward map (default: true)
    enabled: true,
    // optional hostname -> target forwarding
    forward: {
      "example.com": "ws://localhost:3000",
    },
  },
  rules: [
    {
      // match receives the intercepted request
      match: ({ url, method, headers }) => url.includes("example.com"),
      // optionally patch the outgoing request (return {} to leave it untouched)
      beforeRequest: (request) => ({
        url: request.url.replace("http://", "https://"),
      }),
      // optionally patch the upstream response
      beforeResponse: (request, response) => {
        // response: { id, statusCode, headers, body, ... }
        return { statusCode: 200, body: "patched" };
      },
    },
  ],
};

At most one rule may match a given request per phase (beforeRequest / beforeResponse); if more than one rule matches, that request fails with a 500 response and the error is logged.

Rules receive mockttp 4 request and response objects. Requests have no hostname field; read the host from new URL(request.url).hostname or request.headers.host. Bodies are read asynchronously, for example await request.body.getText(). Hooks set the response status with statusCode.