{"id":49581885,"url":"https://github.com/crescendolab-open/override-proxy","last_synced_at":"2026-05-03T20:42:29.274Z","repository":{"id":311103212,"uuid":"1042473690","full_name":"crescendolab-open/override-proxy","owner":"crescendolab-open","description":"Pluggable local development server that serves rule-based overrides first, then proxies unmatched requests to an upstream PROXY_TARGET.","archived":false,"fork":false,"pushed_at":"2026-04-24T15:04:19.000Z","size":93,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-24T17:07:05.776Z","etag":null,"topics":["cors","debug","development","http","https","javascript","mock","nodejs","overrides","proxy","stub","typescript"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crescendolab-open.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-08-22T04:36:41.000Z","updated_at":"2026-04-24T15:04:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"e676b6aa-3af9-416c-aedb-377c8f6381b1","html_url":"https://github.com/crescendolab-open/override-proxy","commit_stats":null,"previous_names":["crescendolab-open/override-proxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/crescendolab-open/override-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Foverride-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Foverride-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Foverride-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Foverride-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crescendolab-open","download_url":"https://codeload.github.com/crescendolab-open/override-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Foverride-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32584651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cors","debug","development","http","https","javascript","mock","nodejs","overrides","proxy","stub","typescript"],"created_at":"2026-05-03T20:42:24.011Z","updated_at":"2026-05-03T20:42:29.265Z","avatar_url":"https://github.com/crescendolab-open.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# override-proxy\n\nPluggable local development server that serves rule-based HTTP and WebSocket overrides first, then proxies unmatched traffic to upstream targets.\n\nKey features:\n\n- Override-first: if a rule matches, respond immediately; otherwise proxy.\n- Multi-server, route-scoped config with root and subdirectory routes.\n- Inline HTTP and WebSocket rules through config imports.\n- Raw WebSocket direct proxy or bridge mode with bidirectional message actions.\n- CLI entry with config discovery, `serve`, `validate`, and legacy fallback.\n- Layered environment loading via `dotenvx` (`.env.local` then `.env.default`).\n\n## Documentation\n\n| Document                                                                 | Purpose                                            |\n| ------------------------------------------------------------------------ | -------------------------------------------------- |\n| [README.md](README.md)                                                   | User guide and overview (you are here)             |\n| [AGENTS.md](AGENTS.md)                                                   | Detailed guide for AI agents                       |\n| [docs/TOOLS.md](docs/TOOLS.md)                                           | Development commands and verification workflow     |\n| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)                             | Visual diagrams and code location index            |\n| [docs/design/config.md](docs/design/config.md)                           | Config model for multi-server routing              |\n| [docs/design/websocket.md](docs/design/websocket.md)                     | WebSocket proxy and rule semantics                 |\n| [docs/design/cli.md](docs/design/cli.md)                                 | CLI behavior                                       |\n| [docs/design/implementation-plan.md](docs/design/implementation-plan.md) | Ordered implementation checklist                   |\n| [docs/EXAMPLES.md](docs/EXAMPLES.md)                                     | Copy-paste examples for common scenarios           |\n| [docs/PATTERNS.md](docs/PATTERNS.md)                                     | Best practices and common pitfalls                 |\n| [docs/DOC-WRITING-GUIDE.md](docs/DOC-WRITING-GUIDE.md)                   | Documentation writing standards (for contributors) |\n| [skills/override-proxy/SKILL.md](skills/override-proxy/SKILL.md)         | Codex skill for agent-assisted usage               |\n\n## Development Tools\n\nThe workflow is config-driven: import rule values in config, validate the config,\nthen run focused tests or the built CLI. See [docs/TOOLS.md](docs/TOOLS.md) for\nthe current command list.\n\n## Codex Skill\n\nThis repository includes an installable Codex skill at\n`skills/override-proxy`. Install it from this GitHub repository with the\nskill-installer workflow by using repo `crescendolab-open/override-proxy` and\npath `skills/override-proxy`.\n\nThe skill guides agents toward a project-local devDependency setup, then helps\nthem author configs or rules with the same commands the repository will use.\n\n## Quick Start\n\nInstall it in your app or mock workspace:\n\n```bash\npnpm install -D @crescendolab/override-proxy\n```\n\nCreate `override-proxy.config.ts`:\n\n```ts\nimport { defineConfig, rule } from \"@crescendolab/override-proxy\";\n\nconst Ping = rule(\"GET\", \"/__ping\", (_req, res) =\u003e {\n  res.json({ ok: true, source: \"override-proxy\" });\n});\n\nexport default defineConfig({\n  servers: [\n    {\n      port: 4000,\n      routes: [\n        {\n          path: \"/\",\n          target: \"https://pokeapi.co/api/v2/\",\n          http: { rules: [Ping] },\n        },\n      ],\n    },\n  ],\n});\n```\n\nValidate and serve:\n\n```bash\npnpm exec override-proxy validate\npnpm exec override-proxy serve\ncurl http://localhost:4000/__ping\n```\n\nFor repeatable team usage, add package scripts in the consuming project:\n\n```json\n{\n  \"scripts\": {\n    \"proxy:validate\": \"override-proxy validate\",\n    \"proxy:serve\": \"override-proxy serve\"\n  }\n}\n```\n\nThen run `pnpm run proxy:validate` and `pnpm run proxy:serve`.\n\n## Repository Development\n\nFrom this source checkout:\n\n```bash\npnpm install\npnpm dev\n```\n\n`pnpm dev` runs the CLI serve path through `nodemon`.\n\nValidate a config file without listening:\n\n```bash\npnpm exec tsx cli.ts validate\npnpm exec tsx cli.ts validate --config ./override-proxy.config.ts\n```\n\nBuild the standalone package entrypoints:\n\n```bash\npnpm run build\nnode dist/cli.js validate\n```\n\nRelease workflow:\n\n```bash\npnpm changeset\n```\n\nEvery user-facing change should include a changeset. After changes land on\n`main`, the Release workflow uses Changesets to open a version PR. Merging that\nversion PR publishes to npm through `pnpm release`; the repository must provide\nan `NPM_TOKEN` secret for publishing.\n\n## Environment Variables\n\nLoad order (first wins, no overwrite): `.env.local` → `.env.default`\n\nSample `.env.default` (do not put secrets here):\n\n```dotenv\nPROXY_TARGET=https://pokeapi.co/api/v2/\nPORT=4000\n# CORS_ORIGINS=http://localhost:3000,https://your-app.local\n```\n\n| Name         | Description                                     | Default                      |\n| ------------ | ----------------------------------------------- | ---------------------------- |\n| PROXY_TARGET | Upstream target when no rule matches            | \u003chttps://pokeapi.co/api/v2/\u003e |\n| PORT         | Preferred port (auto-increments if busy)        | 4000                         |\n| CORS_ORIGINS | Allowed origins (comma list, empty = allow all) | (empty)                      |\n\n\u003e Put secrets only in `.env.local` (ignored by git). `.env.default` is committed and should remain non-sensitive.\n\n## CLI And Config Files\n\nThe CLI command defaults to `serve`. In this source checkout, run it through `tsx`:\n\n```bash\npnpm exec tsx cli.ts\npnpm exec tsx cli.ts serve --config ./override-proxy.config.ts\npnpm exec tsx cli.ts validate --config ./override-proxy.config.ts\n```\n\nAfter `pnpm run build`, the package exposes `override-proxy` from `./dist/cli.js`. Installed package usage should go through the consuming project's local dependency:\n\n```bash\npnpm exec override-proxy\npnpm exec override-proxy serve --config ./override-proxy.config.ts\npnpm exec override-proxy validate --config ./override-proxy.config.ts\n```\n\nWhen consuming the built or installed package, config files can import helpers from `@crescendolab/override-proxy`. In this source checkout before building, import from local source files such as `./config.js`.\n\nDefault config discovery checks the current working directory for:\n\n1. `override-proxy.local.config.ts`\n2. `override-proxy.local.config.mts`\n3. `override-proxy.local.config.js`\n4. `override-proxy.local.config.mjs`\n5. `override-proxy.config.local.ts`\n6. `override-proxy.config.local.mts`\n7. `override-proxy.config.local.js`\n8. `override-proxy.config.local.mjs`\n9. `override-proxy.config.ts`\n10. `override-proxy.config.mts`\n11. `override-proxy.config.js`\n12. `override-proxy.config.mjs`\n\nLocal config names are ignored by the repository's default `.gitignore`.\n\nIf no config file exists, override-proxy runs in legacy proxy mode using `PROXY_TARGET`, `PORT`, and `CORS_ORIGINS`.\n\nExample multi-route config:\n\n```ts\nimport { defineConfig } from \"./config.js\";\nimport { ApiUser } from \"./rules/api-user.js\";\nimport { RootFallback } from \"./rules/root-fallback.js\";\n\nexport default defineConfig({\n  servers: [\n    {\n      name: \"main\",\n      host: \"127.0.0.1\",\n      port: 4000,\n      routes: [\n        {\n          name: \"api\",\n          path: \"/api\",\n          target: \"https://api.example.com\",\n          http: {\n            rules: [ApiUser],\n          },\n          rewrite: { stripPrefix: true },\n        },\n        {\n          name: \"root\",\n          path: \"/\",\n          target: \"https://www.example.com\",\n          http: {\n            rules: [RootFallback],\n          },\n        },\n      ],\n    },\n  ],\n});\n```\n\nRoutes are matched by pathname with priority, longest segment-aware prefix, declaration order, and root fallback.\n\nConfig exports can be objects, factories, or async factories:\n\n```ts\nimport { readFile } from \"node:fs/promises\";\nimport { LocalRule } from \"./rules/local.js\";\n\nexport default defineConfig(async () =\u003e {\n  const fixture = JSON.parse(await readFile(\"./fixtures/user.json\", \"utf8\"));\n\n  return {\n    servers: [\n      {\n        routes: [{ path: \"/\", http: { rules: [LocalRule(fixture)] } }],\n      },\n    ],\n  };\n});\n```\n\n## Rule System\n\nRules are ordinary JavaScript values attached to config. Put them inline or import them from any module; config may be an object, function, or async function, so filesystem reads and other setup belong in userland config code.\n\nInterface:\n\n```ts\ninterface OverrideRule {\n  name?: string;\n  enabled?: boolean; // default true\n  methods: [Method, ...Method[]]; // non-empty, uppercase\n  test(req: Request): boolean;\n  handler(\n    req: Request,\n    res: Response,\n    next: NextFunction,\n  ): void | Promise\u003cvoid\u003e;\n}\n```\n\nHelper creation styles:\n\n1. Overload form:\n\n```ts\nrule(method: Method | readonly Method[], path: string | RegExp, handler, options?)\n```\n\n1. Config object form:\n\n```ts\nrule({ path?: string|RegExp, test?: (req)=\u003eboolean, methods?: readonly Method[], name?, enabled?, handler })\n```\n\nConstraints:\n\n- Provide either `path` or `test` (if both given, `test` augments path match logic you control).\n- If `methods` omitted in config form it defaults to `[\"GET\"]`.\n- First matching enabled rule short-circuits.\n\nAuthoring patterns:\n\n1. `export const SomeRule = rule(...)` and import it from config.\n2. Export arrays for scenario packs, then spread them into `http.rules` or `ws.rules`.\n3. Use `name` when logs need a stable display value; otherwise the helper derives one from `path` when possible.\n\n## WebSocket Rules\n\nWebSocket support targets raw WebSocket traffic. It does not implement Socket.IO protocol semantics.\n\nRoute config supports three modes:\n\n| Mode     | Behavior                                                                 |\n| -------- | ------------------------------------------------------------------------ |\n| `direct` | Transparent WebSocket proxy using the upstream target                    |\n| `bridge` | Accept client socket, optionally connect upstream, and run message rules |\n| `mock`   | Accept client socket without opening an upstream connection              |\n\nFor WebSocket routes, set `ws.target` to the upstream origin or base path. The\nclient request path is appended after route rewrites, and bridge mode forwards\nthe client query string to the upstream URL.\n\nBridge and mock message rules use `wsRule()`:\n\n```ts\nimport { wsRule } from \"../../utils.js\";\n\nexport const PatchChatMessage = wsRule({\n  test: (ctx) =\u003e\n    ctx.direction === \"client\" \u0026\u0026 ctx.jsonObject?.[\"type\"] === \"message\",\n  handler: (ctx) =\u003e {\n    ctx.emitToClient({ type: \"proxy:seen\" });\n    return ctx.forward({\n      ...ctx.jsonObject,\n      patchedByProxy: true,\n    });\n  },\n});\n```\n\nEach message context includes `raw`, `text`, `json`, `jsonObject`, `direction`, route metadata, request headers, and action helpers. Supported actions are `forward`, `skip`, `emitToClient`, `emitToUpstream`, `close`, and `fail`.\n\nUse `wsConnectionRule()` when the proxy should send messages without waiting for client or upstream traffic, such as welcome events, heartbeat pings, or server-push mocks:\n\n```ts\nimport { wsConnectionRule } from \"../../utils.js\";\n\nexport const Heartbeat = wsConnectionRule({\n  onConnect: (ctx) =\u003e {\n    ctx.client.send({ type: \"proxy:ready\" });\n\n    ctx.every(30_000, () =\u003e {\n      ctx.client.send({ type: \"proxy:ping\", at: Date.now() });\n    });\n  },\n});\n```\n\nThe connection context exposes typed `client` and optional `upstream` peers with `send`, `close`, and `readyState`. Advanced rules can use `ctx.raw.client` / `ctx.raw.upstream` for the underlying `ws` sockets. Timers registered with `ctx.every()` and disposers returned from `onConnect()` are cleaned up when the connection closes.\n\n## Examples\n\n### 4.1 Simple path\n\n```ts\nimport { rule } from \"../utils.js\";\nexport default rule({\n  name: \"ping\",\n  path: \"/__ping\",\n  methods: [\"GET\"],\n  handler: (_req, res) =\u003e res.json({ ok: true, t: Date.now() }),\n});\n```\n\n### 4.2 RegExp capture\n\n```ts\nimport { rule } from \"../utils.js\";\nexport default rule({\n  name: \"user-detail\",\n  path: /^\\/api\\/users\\/(\\d+)$/,\n  methods: [\"GET\"],\n  handler: (req, res) =\u003e {\n    const match = /^\\/api\\/users\\/(\\d+)$/.exec(req.path);\n    if (!match) {\n      res.status(404).json({ error: \"not_found\" });\n      return;\n    }\n    const [, id] = match;\n    res.json({ id, name: `User ${id}`, from: \"override\" });\n  },\n});\n```\n\n### 4.3 Custom test\n\n```ts\nimport { rule } from \"../utils.js\";\nexport const rules = [\n  rule({\n    name: \"feature-core\",\n    test: (req) =\u003e\n      req.method === \"GET\" \u0026\u0026\n      req.path === \"/feature-controls\" \u0026\u0026\n      req.query[\"only\"] === \"core\",\n    handler: (_req, res) =\u003e\n      res.json({ features: [\"core-a\", \"core-b\"], ts: Date.now() }),\n  }),\n];\n```\n\n### 4.4 Disabled rule\n\n```ts\nexport default rule({\n  name: \"temp-off\",\n  path: \"/disabled\",\n  enabled: false,\n  handler: (_r, res) =\u003e res.json({ off: true }),\n});\n```\n\n## Built-in Endpoints\n\n| Path          | Method | Description                           |\n| ------------- | ------ | ------------------------------------- |\n| `/__env`      | GET    | Legacy non-sensitive environment info |\n| `/__override` | GET    | Config-mode server and route snapshot |\n| `*`           | ANY    | Route-specific proxy fallback         |\n\nRoute CORS settings apply to route traffic, not built-in control endpoints.\n\nLogging pattern: `[id] -\u003e METHOD path` / `match ruleName` / completion line with status \u0026 source.\n\n## Development Workflow\n\n1. Add or edit rule modules.\n2. Import the active rules from `override-proxy.config.ts`.\n3. Run `pnpm exec tsx cli.ts validate`.\n4. Start with `pnpm dev` and send requests to validate behavior.\n\nChange upstream: set `PROXY_TARGET` in `.env.local`  \nRestrict CORS: `CORS_ORIGINS=http://localhost:3000,https://dev.example.com`\n\n## Project Structure\n\n```text\n.\n├─ cli.ts\n├─ index.ts\n├─ config.ts\n├─ server-runtime.ts\n├─ http-app.ts\n├─ ws-direct-proxy.ts\n├─ ws-bridge.ts\n├─ main.ts\n├─ utils.ts\n├─ tests/\n├─ .env.default\n├─ package.json\n├─ tsconfig.json\n├─ tsconfig.build.json\n└─ nodemon.json\n```\n\n## Common Scenarios\n\n- Simulate latency: `await new Promise(r =\u003e setTimeout(r, 800));`\n- Conditional override: `test: (req)=\u003e req.path === \"/api/users\" \u0026\u0026 req.headers[\"x-mock-mode\"] === \"1\"`\n- Header trigger: `test: (req)=\u003e req.headers[\"x-mock-mode\"] === \"1\"`\n- WebSocket mock event: `ctx.emitToClient({ type: \"proxy:ready\" }); return ctx.skip();`\n\n## Security Notes\n\n- Keep secrets only in `.env.local`.\n- Remove or protect `/__env` if exposing externally.\n- Rules execute arbitrary code: review sources.\n- Avoid exposing this service directly to the public Internet.\n\n## Extension Ideas\n\n| Feature                 | Description                      |\n| ----------------------- | -------------------------------- |\n| /\\_\\_rules              | List rules + status + hit counts |\n| Runtime toggle          | Enable/disable via PATCH         |\n| Hot replace             | chokidar-based in-process swap   |\n| Fault / delay injection | Simulate 4xx/5xx/timeout         |\n| Stats                   | hit count / last hit timestamp   |\n| Priority control        | Explicit rule ordering           |\n\n## Rule Organization \u0026 Archival\n\nYou can still keep rule modules under `rules/`, but runtime does not scan that directory. Config decides exactly which rule values are active.\n\n### 11.1 Group Related Rules\n\n- Group by feature / domain / scenario using either subfolders _and/or_ multi-export files.\n- Import the packs you want in `override-proxy.config.ts`.\n\n### 11.2 Disable Single Rule\n\nTo temporarily disable a single rule without deleting it, add `enabled: false` to the rule configuration:\n\n```ts\nexport const UserDetail = rule({\n  methods: ['GET'],\n  path: /^\\/api\\/users\\/\\d+$/,\n  enabled: false,\n  handler: (req, res) =\u003e res.json({ ... })\n});\n```\n\nThe rule remains in config but won't match requests.\n\n### 11.3 Disable an Entire Group\n\nRemove that pack from the config array, or branch inside an async config factory:\n\n```ts\nconst rules = process.env[\"MOCK_PACK\"] === \"checkout\" ? checkoutRules : [];\n```\n\n### 11.4 Shareable by Design\n\n- Committed config and rule modules are instantly shared—teammates restart and get the same overrides.\n- Avoid secrets / PII in responses. Use env vars or synthetic placeholders if needed.\n- Scenario-oriented packs let you prepare multiple demo states and enable exactly one by config import or factory branch.\n\n### 11.5 Personal / WIP Rules\n\n- For scratch work you _do not_ want committed, use `override-proxy.local.config.ts` and keep it git-ignored.\n\n### 11.6 Naming Guidance\n\n- Module names: concise, kebab-case domain or scenario (`billing-refunds`, `chat-surge-test`).\n- Rule `name` (shown in logs): stable identifier (PascalCase or kebab-case) reflecting purpose.\n\n### 11.7 Quick Lifecycle Table\n\n| Action              | Steps                                 |\n| ------------------- | ------------------------------------- |\n| Add feature pack    | Create module, import rules in config |\n| Disable single rule | Add `enabled: false` to rule config   |\n| Disable rule group  | Remove pack from config or branch env |\n| Share               | Push config/rule modules and restart  |\n\n### 11.8 Why Inline over Runtime Scanning?\n\nInline config keeps runtime simple and makes TypeScript point directly at missing imports, wrong rule shapes, and dead code.\n\n## Comparison with MSW\n\n`override-proxy` and [MSW](https://mswjs.io/) both solve API interception/mocking but sit at different layers: this project is a standalone reverse proxy that applies override rules first and transparently forwards the rest; MSW runs inside your runtime (Service Worker in the browser or a Node process). They are often complementary (team‑wide shared partial overrides via `override-proxy`; fully deterministic isolated tests \u0026 Storybook via MSW).\n\n| Aspect                   | override-proxy                                                   | MSW                                                               | When to favor override-proxy                           | When to favor MSW                             |\n| ------------------------ | ---------------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------- |\n| Deployment form          | Standalone Node reverse proxy                                    | In-process (Service Worker / Node)                                | Need one shared layer for Web, Mobile, backend scripts | Only JS app/tests, want zero base URL changes |\n| Override strategy        | First matching rule short-circuits, rest passthrough             | All requests potentially intercepted; passthrough needs opting in | Partial mock + keep real behavior for the rest         | Fully controlled, offline, deterministic data |\n| Upstream realism         | Unmatched hits real upstream (reduced mock drift)                | All data must be defined/generative                               | Want to reduce divergence between mock and prod        | Want fully stable replayable fixtures         |\n| Team sharing             | Point base URL; everyone instantly uses same overrides           | Must add handlers per repo                                        | Fast alignment “what’s overridden today”               | Single codebase control is enough             |\n| Client languages         | Any (JS, iOS, Android, backend) via HTTP                         | Primarily JavaScript ecosystems                                   | Multi-language integration workflows                   | Pure JS/UI workflows                          |\n| Logging \u0026 observability  | Centralized request log (latency, status, source, rule)          | Distributed per environment                                       | Need mixed real+mock traffic insight                   | Local test verbosity sufficient               |\n| CORS / network semantics | Real browser/network semantics preserved                         | Simulated inside SW/Node                                          | Need to validate real cookies/CORS/TLS                 | Network realism not required                  |\n| Adoption cost            | Run one process + point base URL                                 | Install lib + configure handlers in each env                      | Want zero code intrusion                               | Prefer inline mocks in tests                  |\n| Extensibility surface    | Natural spot for caching, record/replay, fault/latency injection | Built-in REST/GraphQL/WebSocket already                           | Need proxy aggregation / caching                       | Need protocol breadth immediately             |\n| Non-JS test integration  | Any stack via HTTP                                               | Requires JS runtime                                               | Mixed polyglot E2E                                     | JS-only test matrix                           |\n\n### Key strengths of this project\n\n1. Override‑first with transparent passthrough: author only what you need to change; everything else stays real, reducing maintenance \u0026 data drift.\n2. Cross‑client sharing: any device or language adopts overrides by switching a base URL (or system proxy).\n3. Low intrusion: no library embedded in the app—easy to adopt or discard.\n4. Real network conditions: genuine CORS, cookies, caching, TLS; good for integration sanity checks.\n5. Flexible rules: an override is just an Express handler—inject latency, errors, dynamic data, conditional passthrough.\n6. Layered env loading: safe defaults in `.env.default`, secrets in `.env.local` (git‑ignored).\n7. Evolution friendly: ideal anchor point for future record \u0026 replay, metrics, runtime toggles, chaos/fault injection, priority control.\n8. Short learning curve: minimal API (`defineConfig()` + `rule()` / `wsRule()`); experienced Node/Express users are productive immediately.\n\n### Typical combined workflow with MSW\n\n- Day-to-day team development: run `override-proxy` for shared partial overrides + live upstream behavior.\n- Test / CI: use MSW for 100% deterministic, offline, fast tests.\n- Demo / Storybook: point at `override-proxy` for realistic hybrid data; fall back to MSW when full offline determinism needed.\n\n\u003e Summary: `override-proxy` is a shared, real-network, partial-override layer; MSW is an in-process, fully controllable interception layer. They complement rather than exclude each other.\n\n### Architecture \u0026 Flow (Mermaid)\n\n```mermaid\nflowchart LR\n  subgraph Client\n    A[Request]\n  end\n  A --\u003e B[override-proxy]\n  B --\u003e|rule match| C[Override handler]\n  B --\u003e|no match| U[(Upstream API)]\n  C --\u003e R[Response]\n  U --\u003e R\n  R --\u003e A\n  %% Behaviors: dynamic JSON, latency, error injection\n  classDef proxy fill:#0d6efd,stroke:#084298,stroke-width:1px,color:#fff;\n  class B proxy;\n```\n\n### Complementary Usage with MSW\n\n```mermaid\nsequenceDiagram\n  participant DevApp as Frontend App\n  participant OP as override-proxy\n  participant Up as Upstream API\n  participant MSW as MSW (test env)\n\n  Note over DevApp,OP: Local dev (shared partial overrides)\n  DevApp-\u003e\u003eOP: GET /api/items\n  OP-\u003e\u003eOP: Match rule?\n  alt Rule matches\n    OP--\u003e\u003eDevApp: Mocked JSON\n  else No match\n    OP-\u003e\u003eUp: Forward request\n    Up--\u003e\u003eOP: Real response\n    OP--\u003e\u003eDevApp: Real JSON\n  end\n  Note over DevApp,MSW: Test/CI (fully mocked)\n  DevApp-\u003e\u003eMSW: GET /api/items\n  MSW--\u003e\u003eDevApp: Deterministic mocked JSON\n```\n\n## License\n\nApache License 2.0 © 2025 Crescendo Lab. See `LICENSE` for full text.\n\n---\n\nAuthor: Crescendo Lab — 2025\n\nNeed extras (rule listing, runtime toggles, latency/error injection)? Open an issue or ask.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrescendolab-open%2Foverride-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrescendolab-open%2Foverride-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrescendolab-open%2Foverride-proxy/lists"}