{"_id":"@anmetric/neta","_rev":"7-5ba2e123f7f5a40b30c5a0f43192198b","name":"@anmetric/neta","dist-tags":{"latest":"1.9.9"},"versions":{"0.1.0":{"name":"@anmetric/neta","version":"0.1.0","license":"MIT","_id":"@anmetric/neta@0.1.0","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"dist":{"shasum":"4cbf69a7fc1133cfcd2bd1374c5a25f02dbc71f4","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-0.1.0.tgz","fileCount":14,"integrity":"sha512-+LZnu4oP04Y4cmJ9MXAIJUccIks0ombPsduVqdaODZ2ag6SjQPJLxo54D4vAtW3rW9dhmWfJ2bNZP2H/QIOOsg==","signatures":[{"sig":"MEQCIAnJbM5YYSlTizBYWCL4sqVrF3pKtmxOZlChqXxtQqbJAiAM+s2yaEG1V+30Ch653K2eHDORWDPBmHXeLrLW5AWpOQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":154326},"main":"./dist/index.cjs","type":"module","types":"./types/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"ce22f85b573e7036869a50881b90d81cc465d9c0","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"_npmVersion":"10.9.2","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/neta_0.1.0_1775717496298_0.45325909121068886","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@anmetric/neta","version":"1.1.0","license":"MIT","_id":"@anmetric/neta@1.1.0","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"dist":{"shasum":"40364b2b21c420c277fca2be5f0eefc7ec699fb0","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-1.1.0.tgz","fileCount":14,"integrity":"sha512-KoJUZZzpCcAFDS2VjBduYiXzzn1AxEyLfTjjJ35bjtZbjmzsM2XQhQlwGooZtCqrJsANFdRYfvXdkgmrtkA0+w==","signatures":[{"sig":"MEUCIFQf8UDZp3QgL4gY1VmrdzA+I0k3aKGJR3AtOVJ4vRAfAiEAmMplluOsqKoBiAmzt9ym6vGq83ajSW87toloV+YUxpU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":156151},"main":"./dist/index.cjs","type":"module","types":"./types/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"0e1ca37eb42baeaae4b114015a79c20f2ee0c2ff","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"_npmVersion":"10.9.2","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/neta_1.1.0_1775811322718_0.37354956319802257","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@anmetric/neta","version":"1.1.1","license":"MIT","_id":"@anmetric/neta@1.1.1","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"homepage":"https://github.com/anmetrics/neta#readme","bugs":{"url":"https://github.com/anmetrics/neta/issues"},"dist":{"shasum":"1eaea9be4726da5dc79c8a3eea48b5e2a07bd4b0","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-1.1.1.tgz","fileCount":14,"integrity":"sha512-jUvDH0Zs9ZZQ7vOafhHaFq0bCT0uEf/XTYN+n6oF+RFhCbSUFJjpmAfJh3bowf8Oyn3a0qaURxd2M4hYNlCPqA==","signatures":[{"sig":"MEUCICWYcnZqeWL2n5LaxCS/Ofe0YF6iSLjKFHtsoax615X0AiEAqnWsrSXgtXqac5FrGdddCsL9PgI38p8BoRNDJBi9pEU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":156244},"main":"./dist/index.cjs","type":"module","types":"./types/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"e0ed7f0a5697b42ff3429db97a009f347baa306f","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"repository":{"url":"git+https://github.com/anmetrics/neta.git","type":"git"},"_npmVersion":"10.9.2","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/neta_1.1.1_1775811643603_0.7487921060569065","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@anmetric/neta","version":"1.1.2","license":"MIT","_id":"@anmetric/neta@1.1.2","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"homepage":"https://github.com/anmetrics/neta#readme","bugs":{"url":"https://github.com/anmetrics/neta/issues"},"dist":{"shasum":"2122f0de8f09d086416be90ca0dae3dd4659bc74","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-1.1.2.tgz","fileCount":14,"integrity":"sha512-p5uBugKcCcmf5FganwztQJ9b0jY3Qz+3C9ELZDZ8nK/JzwtDhxoxg1BGYrYL/PHJD86Hvl33sO61BT3+0WpBuQ==","signatures":[{"sig":"MEQCIEf9O3+AcZ9/zpCDbcCvLl4BTmt8RCsOh2vthVILdb2RAiBJdYeMlaE9ADEAqS1ygMO1wsq4vcPu9ezOrQHv5ZC2FA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":156538},"main":"./dist/index.cjs","type":"module","types":"./types/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"e7539d43c3b6ee1f76fdc4863fc567d77e0bc68d","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"repository":{"url":"git+https://github.com/anmetrics/neta.git","type":"git"},"_npmVersion":"10.9.2","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/neta_1.1.2_1775813379787_0.44677816616735844","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"@anmetric/neta","version":"1.1.3","license":"MIT","_id":"@anmetric/neta@1.1.3","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"homepage":"https://github.com/anmetrics/neta#readme","bugs":{"url":"https://github.com/anmetrics/neta/issues"},"dist":{"shasum":"94ea718edebd68c041f318563994337a557fd26a","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-1.1.3.tgz","fileCount":14,"integrity":"sha512-PQOUaLAS9WfiNlYH4ngbnNcmGPh/RQzXaid/WpsNBQE/ccEsCVBA+iQZ3cMtUX4zIXyOy6nZmC7ecT0597JV3w==","signatures":[{"sig":"MEYCIQCCMAUSeNFh/jcno7rpa3CNFZfXEgulZJ8tFEc31x3QVgIhALPEIU68w2lJWg3pxi2Uqw3XIec22FNww6ZIUbMbKcN2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":156588},"main":"./dist/index.cjs","type":"module","types":"./types/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"2675dc9c51e3f59e5b42a61d1bfd9dbe0a694419","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"repository":{"url":"git+https://github.com/anmetrics/neta.git","type":"git"},"_npmVersion":"10.9.2","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/neta_1.1.3_1775813481288_0.3027262794796457","host":"s3://npm-registry-packages-npm-production"}},"1.1.4":{"name":"@anmetric/neta","version":"1.1.4","license":"MIT","_id":"@anmetric/neta@1.1.4","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"homepage":"https://github.com/anmetrics/neta#readme","bugs":{"url":"https://github.com/anmetrics/neta/issues"},"dist":{"shasum":"bcf68dc6e317e06c179277923eaf7ea641365ae8","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-1.1.4.tgz","fileCount":14,"integrity":"sha512-ZnDSvDeKdEfFbD5/PCPlY66rwvGBMB9pvXLD9HOi0HaZFWA+frCkEQmAzmdmx8zLp8WVWZONNN7tfwpKmIsDCw==","signatures":[{"sig":"MEQCIAykJipjctWelhSmZ7SA8rmVsDy2I65UMmYJ7RFJWcmfAiBw9kvsdEegzpnQ8isR/kuTTV0hj+mF0rK41/R83j9ELw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":156534},"main":"./dist/index.cjs","type":"module","types":"./types/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"79485e28cbf985e08522c38ecc60db9d410bc218","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"repository":{"url":"git+https://github.com/anmetrics/neta.git","type":"git"},"_npmVersion":"10.9.2","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/neta_1.1.4_1775813639538_0.07370421567805918","host":"s3://npm-registry-packages-npm-production"}},"1.9.9":{"name":"@anmetric/neta","version":"1.9.9","description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","repository":{"type":"git","url":"git+https://github.com/anmetrics/neta.git"},"type":"module","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./types/index.d.ts","scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","test:edge-cases":"vitest run test/edge-cases.test.ts","test:memory":"vitest run test/memory-leak.test.ts","benchmark":"node test/benchmark.js","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"engines":{"node":">=18"},"devDependencies":{"tsup":"^8.0.0","typescript":"^5.4.0","vitest":"^2.0.0"},"license":"MIT","_id":"@anmetric/neta@1.9.9","gitHead":"a87d42cda357c6d2bc91e1ee3701b4d2454f702c","bugs":{"url":"https://github.com/anmetrics/neta/issues"},"homepage":"https://github.com/anmetrics/neta#readme","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-GvpD+eSdF1FwFV6FY6+rp9GbaGubrk3j6K7xz2wbfzsJRKpwD9XOMlJ0iWvHJt9lM9w9J4XGhqvdP9b5C1zdOA==","shasum":"4ed3988081267747ab75783a8b578ebd24cca018","tarball":"https://registry.npmjs.org/@anmetric/neta/-/neta-1.9.9.tgz","fileCount":14,"unpackedSize":160746,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC6Q9jEzY/ou8e0p0sEc4t5IWQhAyV9hw05nmJ4456fXAIgeSHeAODfGqDWX7QV9V01iZnLo6Zu6PDq1MuQXOkK5iE="}]},"_npmUser":{"name":"quocthien3456","email":"tranquocthien@aol.com"},"directories":{},"maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/neta_1.9.9_1775814502131_0.755907183030972"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-09T06:51:36.160Z","modified":"2026-04-10T09:48:22.409Z","0.1.0":"2026-04-09T06:51:36.440Z","1.1.0":"2026-04-10T08:55:22.862Z","1.1.1":"2026-04-10T09:00:43.751Z","1.1.2":"2026-04-10T09:29:39.920Z","1.1.3":"2026-04-10T09:31:21.463Z","1.1.4":"2026-04-10T09:33:59.673Z","1.9.9":"2026-04-10T09:48:22.266Z"},"bugs":{"url":"https://github.com/anmetrics/neta/issues"},"license":"MIT","homepage":"https://github.com/anmetrics/neta#readme","repository":{"type":"git","url":"git+https://github.com/anmetrics/neta.git"},"description":"Tiny, elegant HTTP client built on fetch for browser and Node.js","maintainers":[{"name":"quocthien3456","email":"tranquocthien@aol.com"}],"readme":"# neta\n\n> Tiny, elegant HTTP client built on [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for browser and Node.js\n\n- **Zero dependencies** — uses native `globalThis.fetch`\n- **~12 KB** minified, ESM + CJS\n- **TypeScript ready** — full `.d.ts` type definitions\n- **Works everywhere** — browser, Node.js 18+, Deno, Bun\n\n## Install\n\n```sh\nnpm install @anmetric/neta\n```\n\n## Quick Start\n\n```js\nimport neta from \"@anmetric/neta\";\n\n// GET with JSON parsing\nconst data = await neta.get(\"https://api.example.com/users\").json();\n\n// POST with JSON body\nconst user = await neta\n  .post(\"https://api.example.com/users\", {\n    json: { name: \"John\", email: \"john@example.com\" },\n  })\n  .json();\n\n// Direct callable\nconst res = await neta(\"https://api.example.com/users\", { method: \"get\" });\n```\n\n## API\n\n### `neta(input, options?)`\n\nReturns a [`ResponsePromise`](#responsepromise).\n\n#### input\n\nType: `string | URL | Request`\n\n#### options\n\nType: `object`\n\nAll [`fetch` options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) plus:\n\n##### json\n\nType: `unknown`\n\nJSON body. Automatically stringified and sets `Content-Type: application/json`.\n\n```js\nconst data = await neta\n  .post(\"https://api.example.com/items\", {\n    json: { title: \"New Item\" },\n  })\n  .json();\n```\n\n##### searchParams\n\nType: `string | object | URLSearchParams | Array<[string, string]>`\n\nQuery parameters appended to the URL.\n\n```js\nconst data = await neta\n  .get(\"https://api.example.com/search\", {\n    searchParams: { q: \"hello\", page: 2 },\n  })\n  .json();\n// => GET https://api.example.com/search?q=hello&page=2\n```\n\nValues set to `undefined` are filtered out.\n\n##### prefix\n\nType: `string | URL`\n\nPrefix prepended to the input URL. Useful for API base paths.\n\n```js\nconst api = neta.create({ prefix: \"https://api.example.com/v2\" });\n\nawait api.get(\"users\").json();\n// => GET https://api.example.com/v2/users\n```\n\n##### baseUrl\n\nType: `string | URL`\n\nBase URL for resolving relative inputs using standard [URL resolution](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL).\n\n```js\nconst api = neta.create({ baseUrl: \"https://api.example.com/v2/\" });\n\nawait api.get(\"users\").json();\n// => GET https://api.example.com/v2/users\n\nawait api.get(\"../v1/legacy\").json();\n// => GET https://api.example.com/v1/legacy\n```\n\n##### timeout\n\nType: `number | false`\\\nDefault: `10000` (10 seconds)\n\nRequest timeout in milliseconds. Set to `false` to disable.\n\n##### totalTimeout\n\nType: `number | false`\\\nDefault: `false`\n\nTotal timeout across all retries in milliseconds.\n\n```js\nawait neta.get(\"https://api.example.com/slow\", {\n  timeout: 5000,\n  totalTimeout: 30000,\n  retry: 5,\n});\n```\n\n##### retry\n\nType: `number | object`\\\nDefault: `{ limit: 2 }`\n\nRetry configuration. Pass a number for simple retry limit, or an object for full control.\n\n```js\n// Simple\nawait neta.get(url, { retry: 3 });\n\n// Full control\nawait neta.get(url, {\n  retry: {\n    limit: 3,\n    methods: [\"get\", \"put\", \"head\", \"delete\", \"options\"],\n    statusCodes: [408, 413, 429, 500, 502, 503, 504],\n    afterStatusCodes: [413, 429, 503],\n    maxRetryAfter: Infinity,\n    backoffLimit: Infinity,\n    delay: (attemptCount) => 300 * 2 ** (attemptCount - 1),\n    jitter: false,\n    retryOnTimeout: false,\n    shouldRetry: undefined,\n  },\n});\n```\n\n###### retry.limit\n\nType: `number`\\\nDefault: `2`\n\nMaximum number of retries.\n\n###### retry.methods\n\nType: `string[]`\\\nDefault: `['get', 'put', 'head', 'delete', 'options']`\n\nHTTP methods eligible for retry.\n\n###### retry.statusCodes\n\nType: `number[]`\\\nDefault: `[408, 413, 429, 500, 502, 503, 504]`\n\nHTTP status codes that trigger a retry.\n\n###### retry.afterStatusCodes\n\nType: `number[]`\\\nDefault: `[413, 429, 503]`\n\nStatus codes where the `Retry-After` header is honored.\n\n###### retry.maxRetryAfter\n\nType: `number`\\\nDefault: `Infinity`\n\nMaximum `Retry-After` delay (ms) to accept.\n\n###### retry.backoffLimit\n\nType: `number`\\\nDefault: `Infinity`\n\nMaximum backoff delay (ms).\n\n###### retry.delay\n\nType: `(attemptCount: number) => number`\\\nDefault: `(n) => 300 * 2 ** (n - 1)`\n\nFunction returning delay in ms for each attempt.\n\n###### retry.jitter\n\nType: `boolean | ((delay: number) => number)`\\\nDefault: `false`\n\nAdd randomness to retry delay to prevent thundering herd.\n\n- `true` — random value between 0 and computed delay\n- `function` — custom jitter function\n\n```js\nawait neta.get(url, {\n  retry: {\n    limit: 5,\n    delay: (n) => 1000 * 2 ** (n - 1),\n    jitter: true,\n  },\n});\n```\n\n###### retry.retryOnTimeout\n\nType: `boolean`\\\nDefault: `false`\n\nWhether to retry when a request times out.\n\n###### retry.shouldRetry\n\nType: `({ error, retryCount }) => boolean | undefined | Promise<boolean | undefined>`\n\nCustom function to decide whether to retry. Takes precedence over default checks.\n\n- Return `true` to force retry\n- Return `false` to prevent retry\n- Return `undefined` to fall through to default behavior\n\n```js\nawait neta.get(url, {\n  retry: {\n    limit: 3,\n    shouldRetry: ({ error, retryCount }) => {\n      if (error.response?.status === 401) return false; // Don't retry auth errors\n      return undefined; // Default behavior for others\n    },\n  },\n});\n```\n\n##### throwHttpErrors\n\nType: `boolean | ((status: number) => boolean)`\\\nDefault: `true`\n\nThrow `HTTPError` for non-2xx responses. Pass a function for custom logic.\n\n```js\n// Never throw\nconst response = await neta.get(url, { throwHttpErrors: false });\n\n// Only throw on 5xx\nconst response = await neta.get(url, {\n  throwHttpErrors: (status) => status >= 500,\n});\n```\n\n##### parseJson\n\nType: `(text: string, context: { request, response }) => unknown`\n\nCustom JSON parser. Useful for reviving dates, BigInts, etc.\n\n```js\nimport LosslessJSON from \"lossless-json\";\n\nconst data = await neta\n  .get(url, {\n    parseJson: (text) => LosslessJSON.parse(text),\n  })\n  .json();\n```\n\n##### stringifyJson\n\nType: `(value: unknown) => string`\n\nCustom JSON serializer for the `json` option.\n\n```js\nimport LosslessJSON from \"lossless-json\";\n\nawait neta.post(url, {\n  json: data,\n  stringifyJson: (value) => LosslessJSON.stringify(value),\n});\n```\n\n##### bearerToken\n\nType: `string`\n\nConvenience option to set the `Authorization: Bearer <token>` header. If an `Authorization` header is already set explicitly, `bearerToken` will not override it.\n\n```js\nconst data = await neta\n  .get(\"https://api.example.com/me\", {\n    bearerToken: \"abc123\",\n  })\n  .json();\n// Sets header: Authorization: Bearer abc123\n\n// Works with create/extend\nconst api = neta.create({\n  prefix: \"https://api.example.com\",\n  bearerToken: \"abc123\",\n});\n```\n\n##### context\n\nType: `Record<string, unknown>`\\\nDefault: `{}`\n\nArbitrary data passed through to hooks. Not sent with the request.\n\n```js\nawait neta.get(url, {\n  context: { token: \"abc123\" },\n  hooks: {\n    init: [\n      (options) => {\n        options.headers = {\n          ...options.headers,\n          Authorization: `Bearer ${options.context.token}`,\n        };\n      },\n    ],\n  },\n});\n```\n\n##### fetch\n\nType: `typeof globalThis.fetch`\n\nCustom fetch implementation.\n\n```js\nimport { fetch } from \"undici\";\n\nconst api = neta.create({ fetch });\n```\n\n##### onDownloadProgress\n\nType: `(progress: { percent, transferredBytes, totalBytes }) => void`\n\nDownload progress callback. Requires `ReadableStream` support.\n\n```js\nawait neta.get(\"https://example.com/large-file\", {\n  onDownloadProgress: ({ percent, transferredBytes, totalBytes }) => {\n    console.log(\n      `${Math.round(percent * 100)}% (${transferredBytes}/${totalBytes})`,\n    );\n  },\n});\n```\n\n##### onUploadProgress\n\nType: `(progress: { percent, transferredBytes, totalBytes }) => void`\n\nUpload progress callback. Requires request streams support (`duplex: 'half'`).\n\n### HTTP Method Shortcuts\n\n```js\nneta.get(input, options?)\nneta.post(input, options?)\nneta.put(input, options?)\nneta.patch(input, options?)\nneta.delete(input, options?)\nneta.head(input, options?)\nneta.options(input, options?)\n```\n\n### ResponsePromise\n\n`neta` methods return a `ResponsePromise` — a `Promise<Response>` with body parsing shortcuts:\n\n```js\nconst json = await neta.get(url).json();\nconst text = await neta.get(url).text();\nconst blob = await neta.get(url).blob();\nconst buffer = await neta.get(url).arrayBuffer();\nconst form = await neta.get(url).formData();\n```\n\n#### .json(schema?)\n\nParse response as JSON. Optionally validate against a [Standard Schema](https://github.com/standard-schema/standard-schema):\n\n```js\nimport { z } from \"zod\";\n\nconst user = await neta.get(\"/user/1\").json(\n  z.object({\n    id: z.number(),\n    name: z.string(),\n  }),\n);\n// Throws SchemaValidationError if validation fails\n```\n\n### Instance Creation\n\n#### neta.create(defaults?)\n\nCreate a new instance with default options:\n\n```js\nconst api = neta.create({\n  prefix: \"https://api.example.com\",\n  bearerToken: \"my-token\",\n  timeout: 30000,\n  retry: 3,\n});\n\nconst data = await api.get(\"users\").json();\n```\n\n#### neta.extend(defaults?)\n\nAlias for `neta.create()`. Creates a new instance by extending existing defaults:\n\n```js\nconst api = neta.create({ prefix: \"https://api.example.com\" });\nconst authApi = api.extend({ bearerToken: \"my-token\" });\n```\n\n## Hooks\n\nFive hook points for intercepting the request lifecycle.\n\n### hooks.init\n\nType: `Array<(options) => void>`\n\nCalled synchronously before anything else. Can mutate options directly.\n\n```js\nneta.create({\n  hooks: {\n    init: [\n      (options) => {\n        options.headers = {\n          ...options.headers,\n          \"X-Request-Id\": crypto.randomUUID(),\n        };\n      },\n    ],\n  },\n});\n```\n\n### hooks.beforeRequest\n\nType: `Array<({ request, options, retryCount }) => Request | Response | void>`\n\nCalled before each request. Return a `Request` to replace it, a `Response` to short-circuit, or nothing.\n\n```js\nneta.create({\n  hooks: {\n    beforeRequest: [\n      ({ request }) => {\n        console.log(`${request.method} ${request.url}`);\n      },\n    ],\n  },\n});\n```\n\n### hooks.afterResponse\n\nType: `Array<({ request, options, response, retryCount }) => Response | RetryMarker | void>`\n\nCalled after a successful response. Return a `Response` to replace it, or `neta.retry()` to force a retry.\n\n```js\nconst api = neta.create({\n  hooks: {\n    afterResponse: [\n      async ({ request, response }) => {\n        if (response.status === 401) {\n          const token = await refreshToken();\n          return neta.retry({\n            request: new Request(request, {\n              headers: {\n                ...Object.fromEntries(request.headers),\n                Authorization: `Bearer ${token}`,\n              },\n            }),\n          });\n        }\n      },\n    ],\n  },\n});\n```\n\n### hooks.beforeError\n\nType: `Array<({ request, options, error, retryCount }) => Error | void>`\n\nCalled before an error is thrown. Return an `Error` to replace it.\n\n```js\nneta.create({\n  hooks: {\n    beforeError: [\n      ({ error }) => {\n        if (error instanceof HTTPError) {\n          error.message = `API Error: ${error.response.status}`;\n        }\n        return error;\n      },\n    ],\n  },\n});\n```\n\n### hooks.beforeRetry\n\nType: `Array<({ request, options, error, retryCount }) => Request | Response | symbol | void>`\n\nCalled before each retry attempt. Return:\n\n- `Request` — use this request for the retry\n- `Response` — skip the retry and use this response\n- `stop` — abort the retry loop\n- nothing — proceed normally\n\n```js\nimport { stop } from \"@anmetric/neta\";\n\nneta.create({\n  hooks: {\n    beforeRetry: [\n      ({ error, retryCount }) => {\n        console.log(`Retry #${retryCount}: ${error.message}`);\n        if (retryCount > 3) return stop;\n      },\n    ],\n  },\n});\n```\n\n## Error Handling\n\n### HTTPError\n\nThrown for non-2xx responses (when `throwHttpErrors` is true).\n\n```js\nimport { HTTPError } from \"@anmetric/neta\";\n\ntry {\n  await neta.get(\"https://api.example.com/missing\");\n} catch (error) {\n  if (error instanceof HTTPError) {\n    console.log(error.response.status); // 404\n    console.log(error.data); // Auto-parsed response body\n    console.log(error.request); // The Request object\n  }\n}\n```\n\n### TimeoutError\n\nThrown when a request exceeds the `timeout` or `totalTimeout`.\n\n```js\nimport { TimeoutError } from \"@anmetric/neta\";\n\ntry {\n  await neta.get(url, { timeout: 1000 });\n} catch (error) {\n  if (error instanceof TimeoutError) {\n    console.log(\"Request timed out:\", error.request.url);\n  }\n}\n```\n\n### NetworkError\n\nThrown on network failures (DNS, connection refused, etc.).\n\n```js\nimport { NetworkError } from \"@anmetric/neta\";\n\ntry {\n  await neta.get(\"https://nonexistent.invalid\");\n} catch (error) {\n  if (error instanceof NetworkError) {\n    console.log(\"Network error:\", error.message);\n    console.log(\"Cause:\", error.cause);\n  }\n}\n```\n\n### SchemaValidationError\n\nThrown when JSON response fails schema validation.\n\n```js\nimport { SchemaValidationError } from \"@anmetric/neta\";\n\ntry {\n  await neta.get(url).json(mySchema);\n} catch (error) {\n  if (error instanceof SchemaValidationError) {\n    console.log(\"Validation issues:\", error.issues);\n  }\n}\n```\n\n## TypeScript\n\nneta ships with full TypeScript definitions. Generic type parameters work on `.json()`:\n\n```ts\ninterface User {\n  id: number;\n  name: string;\n}\n\nconst user = await neta.get(\"https://api.example.com/user/1\").json<User>();\n// user is typed as User\n```\n\n## Retry-After Header Support\n\nneta automatically parses these headers during retry:\n\n- `Retry-After`\n- `RateLimit-Reset`\n- `X-RateLimit-Retry-After`\n- `X-RateLimit-Reset`\n- `X-Rate-Limit-Reset`\n\nSupports seconds, timestamps, and HTTP dates.\n\n## Browser + Node.js\n\nneta uses `globalThis.fetch` which is available natively in:\n\n- All modern browsers\n- Node.js 18+\n- Deno\n- Bun\n\nNo polyfills needed.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}