> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# URL

> Parse and manipulate URLs with typed query strings, path normalization, and convenient accessors for common parameters.

`@ooneex/url` wraps the native `URL` with a friendlier, typed API. It parses a URL into its parts (protocol, subdomain, domain, port, path, queries, fragment), coerces query values to their natural types, and exposes helpers for common parameters like `lang`, `page`, `limit`, and `order`. A chainable `Url` class lets you mutate and rebuild URLs, while `ReadonlyUrl` offers the same read accessors without mutation.

## Installation

Add the package with Bun.

```bash theme={null}
bun add @ooneex/url
```

## Usage

Construct a `Url` from a string (or a native `URL`) and read its parts. Query values are automatically parsed: `"true"`/`"false"` become booleans and numeric strings become numbers.

```typescript theme={null}
import { Url } from "@ooneex/url";

const url = new Url("https://app.ooneex.com/articles?page=2&limit=20&active=true#section");

url.getProtocol();  // "https"
url.getSubdomain(); // "app"
url.getDomain();    // "ooneex.com"
url.getHostname();  // "app.ooneex.com"
url.getPath();      // "/articles"
url.getFragment();  // "section"
url.getQueries();   // { page: 2, limit: 20, active: true }
url.getQuery("active"); // true
```

Typed convenience accessors return sensible defaults when a parameter is missing, which is handy for list/pagination endpoints.

```typescript theme={null}
const url = new Url("https://ooneex.com/posts?lang=fr&order=DESC&orderBy=createdAt&q=hello");

url.getLang();    // "fr" (falls back to "en" if not a known locale)
url.getPage();    // 1   (default when absent)
url.getLimit();   // 100 (default when absent)
url.getOrder();   // "DESC" (defaults to "ASC")
url.getOrderBy(); // "createdAt"
url.getSearch();  // "hello" (the `q` param)
```

The `Url` class is chainable: every setter returns the instance and rebuilds the underlying URL, so you can read the result with `toString()`.

```typescript theme={null}
const url = new Url("https://ooneex.com/")
  .setPath("articles/latest")
  .addQuery("page", 1)
  .addQuery("limit", 20)
  .setFragment("top");

url.toString(); // "https://ooneex.com/articles/latest?page=1&limit=20#top"

url.removeQuery("limit");
url.setQueries({ q: "search", lang: "en" });
url.clearQueries();
```

When you only need to read a URL and want to prevent mutation, use `ReadonlyUrl`, which exposes all the getters but none of the setters.

```typescript theme={null}
import { ReadonlyUrl } from "@ooneex/url";

const url = new ReadonlyUrl("https://api.ooneex.com:8080/v1/users?limit=50");

url.getPort();    // 8080
url.getBase();    // "https://api.ooneex.com:8080"
url.getOrigin();  // "https://api.ooneex.com:8080"
url.getNative();  // the underlying native URL instance
```

## When to use it

* You need to read URL query parameters already coerced to their natural types (numbers, booleans) instead of raw strings.
* You handle list endpoints and want typed accessors with defaults for `page`, `limit`, `order`, `orderBy`, `lang`, and search (`q`).
* You want to build or modify URLs fluently with a chainable API that handles path normalization, default ports, and query rebuilding for you.
* You want a read-only view of a URL (`ReadonlyUrl`) to pass around without risk of mutation.
* You don't need it for trivial cases where the native `URL` and `URLSearchParams` already cover what you do.
