|
| 1 | +# AGENTS.md — FetchClient |
| 2 | + |
| 3 | +Purpose: Help AI coding agents work productively in this repo. Keep it short, |
| 4 | +concrete, and specific to FetchClient. |
| 5 | + |
| 6 | +## 1) What this project is |
| 7 | + |
| 8 | +- Deno-first, multi-runtime JSON fetch client with: |
| 9 | + - Typed responses (`FetchClientResponse<T>`) |
| 10 | + - Middleware pipeline |
| 11 | + - Response caching |
| 12 | + - Rate limiting (global and per-domain) |
| 13 | + - Provider-based global configuration and functional helpers |
| 14 | + |
| 15 | +## 2) Codebase layout |
| 16 | + |
| 17 | +- Public entry: `mod.ts` (re-exports from `src/*.ts`) |
| 18 | +- Core client: `src/FetchClient.ts` |
| 19 | +- Provider & globals: `src/FetchClientProvider.ts`, `src/DefaultHelpers.ts` |
| 20 | +- Options & types: `src/RequestOptions.ts`, `src/FetchClientResponse.ts`, |
| 21 | + `src/ProblemDetails.ts` |
| 22 | +- Utilities: `src/FetchClientCache.ts`, `src/RateLimiter.ts`, |
| 23 | + `src/RateLimitMiddleware.ts`, `src/LinkHeader.ts`, `src/ObjectEvent.ts`, |
| 24 | + `src/Counter.ts` |
| 25 | +- Tests: `src/*test.ts` |
| 26 | +- Build tooling: `scripts/build.ts`, tasks in `deno.json` |
| 27 | + |
| 28 | +## 3) How it works (architecture) |
| 29 | + |
| 30 | +- Option merge order: provider defaults → client defaults → per-call options. |
| 31 | +- JSON helpers (`getJSON|postJSON|putJSON|patchJSON|deleteJSON`): set Accept and |
| 32 | + stringify object bodies; parse JSON using optional `reviver` and |
| 33 | + `shouldParseDates`. |
| 34 | +- URL building: `baseUrl` + relative path; `options.params` appended only if not |
| 35 | + already present in URL. |
| 36 | +- Auth: if `accessTokenFunc()` returns a token, `Authorization: Bearer <token>` |
| 37 | + is added automatically. |
| 38 | +- Model validation: if `modelValidator` is set and body is object |
| 39 | + (non-FormData), validate before fetch; returning `ProblemDetails` |
| 40 | + short-circuits the request. |
| 41 | +- Errors: unexpected non-2xx throws the Response (augmented); can be suppressed |
| 42 | + with `expectedStatusCodes`, `shouldThrowOnUnexpectedStatusCodes=false`, or |
| 43 | + `errorCallback` returning true. |
| 44 | +- Timeout/abort: merges `AbortSignal.timeout(options.timeout)` with any provided |
| 45 | + `signal`. |
| 46 | +- Caching: GET + `cacheKey` reads/writes via `FetchClientCache` (default TTL 60s |
| 47 | + unless `cacheDuration` provided). |
| 48 | +- Middleware order: `[provider.middleware, client.use(...), internal fetch]`. |
| 49 | +- Loading events: instance and provider expose `loading` via counters. |
| 50 | + |
| 51 | +## 4) Dev workflows (Deno) |
| 52 | + |
| 53 | +- Run tests (net allowed): `deno task test` |
| 54 | +- Type check: `deno task check` |
| 55 | +- Lint/format: `deno task lint`, `deno task format-check` |
| 56 | +- Build npm package: `deno task build` (dnt emits to `npm/` CJS + `.d.ts`; |
| 57 | + copies `license` and `readme.md`) |
| 58 | + |
| 59 | +## 5) Common tasks (examples) |
| 60 | + |
| 61 | +- Get a client: `useFetchClient()` or `new FetchClient()` (inherits provider |
| 62 | + defaults) |
| 63 | +- Global config: `setBaseUrl`, `setAccessTokenFunc`, `setModelValidator`, |
| 64 | + `useMiddleware` |
| 65 | +- Rate limiting: `useRateLimit({ maxRequests, windowSeconds })` or |
| 66 | + `usePerDomainRateLimit(...)` |
| 67 | +- GET cache: |
| 68 | + `client.getJSON(url, { cacheKey: ["todos","1"], cacheDuration: 60000 })` |
| 69 | +- Tolerate 404: `expectedStatusCodes: [404]` or handle via `errorCallback` |
| 70 | + |
| 71 | +## 6) Conventions & gotchas |
| 72 | + |
| 73 | +- Thrown values are Response objects; catch and inspect `.status` and `.problem` |
| 74 | + (not `Error`). |
| 75 | +- `meta.links` parsed from `Link` header (`next`/`previous` may be present). |
| 76 | +- Don’t break middleware order; provider middleware must run before client |
| 77 | + middleware. |
| 78 | +- Keep JSON header behavior aligned with |
| 79 | + `buildJsonRequestOptions`/`buildRequestInit`. |
| 80 | + |
| 81 | +### Code style |
| 82 | + |
| 83 | +- Keep comments minimal. Comment only complex or non-obvious code paths. |
| 84 | + |
| 85 | +## 7) Where to extend |
| 86 | + |
| 87 | +- Add request features by threading through `RequestOptions` and merging in |
| 88 | + `FetchClient` like existing fields. |
| 89 | +- Header-derived behaviors (pagination/limits): parse in internal fetch, enrich |
| 90 | + `response.meta`. |
| 91 | +- Rate limit updates: `RateLimitMiddleware` already auto-updates from headers. |
| 92 | + |
| 93 | +## 8) Pointers to read first |
| 94 | + |
| 95 | +`src/FetchClient.ts`, `src/FetchClientProvider.ts`, `src/DefaultHelpers.ts`, |
| 96 | +`src/RequestOptions.ts`, `src/FetchClientResponse.ts`, `src/RateLimiter.ts`, |
| 97 | +`src/RateLimitMiddleware.ts`, `src/FetchClientCache.ts`, `src/LinkHeader.ts`. |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +If something is unclear, prefer small, additive changes and tests in |
| 102 | +`src/*test.ts`. Keep middleware order and error semantics consistent. |
0 commit comments