# build-url-ts

> A tiny URL builder for the query-string bugs that survive code review because they look too small to matter.

`build-url-ts` is intentionally small: pass a base URL and an object, get a URL with encoded query parameters. It exists because string-built URLs are one of those tiny bugs that survive code review until a space, array, or undefined value lands in production.

## Why it exists

I do not want every codebase to grow a custom query-string helper. I also do not want a heavy dependency for a job the platform already mostly knows how to do. This repo keeps the contract narrow: take structured input, normalize it once, and let the caller stop thinking about escaping rules.

Small helpers are worth building when they remove a repeated source of defensive programming. URL construction shows up in API clients, dashboards, webhooks, redirects, and internal tools. The mistakes are rarely dramatic in review. They look like "works for this one example" and then fail when the value is empty, repeated, encoded already, or passed through another system.

The useful thing here is not clever URL logic. It is reducing the number of places a team has to remember the same edge case.

```mermaid
flowchart LR
  A[structured params] --> B[drop empty values]
  B --> C[encode once]
  C --> D[append to base URL]
  D --> E[stable request URL]
```

<Principle title="Make tiny edge cases boring">
  If every caller has to remember URL escaping, arrays, and empty values, the bug will eventually
  ship. Put the rule in one small primitive and test the primitive hard.
</Principle>

## What's inside

- Object-to-query handling with predictable encoding.
- TypeScript types around the input shape.
- Existing query parameters are merged instead of accidentally discarded.
- Array parameters, empty values, and already-encoded input get one shared rule.
- ESM, CommonJS, and browser/CDN builds exist because tiny utilities often travel farther than the
  app they started in.
- A small surface area that is easy to test and delete if the platform covers it later.

## Where it earns its place

The repo is not trying to replace `URL` or `URLSearchParams`. It wraps the part where teams usually
get inconsistent: how object values become query parameters, what gets skipped, what gets repeated,
and how a base URL with existing parameters should behave.

That matters in generated SDKs, webhook calls, analytics links, signed redirects, and internal
tools. A single wrong separator or double-encoded value can turn into a support issue that looks
larger than the bug really is. I would rather put that boring edge in a tiny package with tests than
debug it again in every caller.

## The engineering habit

When a bug class repeats, I prefer a tiny boring primitive over scattered comments. The primitive should be easy to read, easy to test, and small enough that nobody feels trapped by it. If the standard platform later covers the same behavior cleanly, delete the helper and move on.

That is the whole point of this repo: make the common path safer without creating a framework around a URL.
