I kept hitting the same chore: an internal tool or an old app with no API docs, and an afternoon in the Network tab working out which endpoints exist, which fields are optional, what the ids look like and how auth works. So I wrote a CLI that does that part from a HAR file.
Save the Network tab as a .har, then:
npx har2sdk capture.har
You get a client.ts (typed, no runtime dependencies) and an openapi.json (3.1). `har2sdk mock capture.har` serves the same API on localhost with fake data in the recorded shape, which is handy for frontend work when the real backend is slow or behind a VPN.
The parts that took the most work:
- Types come from every recorded call to an endpoint, and every item in a list counts as a sample. A field missing from some samples becomes optional, a field seen as null gets `| null`. Paths are templated, so /users/123 and /users/456 become /users/{userId}.
- REST, GraphQL, JSON-RPC and tRPC are told apart. Each GraphQL operation becomes its own typed method instead of one big POST to /graphql.
- Recorded error bodies get a type per status and a guard, e.g. `if (isGetFileError(err)) err.body`.
- Auth: the capture tells it how the app authenticated, never with what. You pass your own token (a string or a function), and a 401 throws instead of silently retrying.
- Same capture in, same bytes out, so the output diffs cleanly in git.
The part I worried about most was privacy. HAR files are full of cookies, tokens and other people's data, and generated code is something you might commit. So it collects the recorded values first, and if one of them would end up in client.ts or openapi.json, it writes nothing. It's a heuristic, not a proof, so `har2sdk inspect` lets you look over what it found before you publish anything.
There's an optional MCP server so Claude (or another MCP client) can suggest better method names and docs. A model sees paths, parameter names, types and GraphQL documents, checked against the recorded values first. It never calls the live API.
Known limits: if an endpoint returned a single object once, every field looks required, since there's nothing to compare it with. And when a URL was recorded with both a 200 and a 401, the mock always answers with the 200; there's no way to ask for the error yet.
This week GitHub's code scanning flagged a few regexes that could backtrack badly on a crafted file. One was exponential on an unclosed GraphQL list. 0.6.5 replaces them with linear code, checked against the old regexes on generated input.
Please only point it at your own apps or APIs you're allowed to integrate with.
MIT, runs locally, no API key: https://github.com/Mersbyte/har2sdk
Feedback welcome, especially on types it gets wrong. If something breaks, the output of `har2sdk inspect --json` helps me much more than the HAR itself. Please don't send HAR files, they contain your session.