{"_id":"@abubakriz/talab","_rev":"6-f3b1c51097c84c6c17cf19afc6638123","name":"@abubakriz/talab","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.1":{"name":"@abubakriz/talab","version":"1.0.1","keywords":["http","fetch","request","typescript","javascript","http-client","web","browser","node"],"author":{"name":"Abu Bakr Iznain"},"license":"MIT","_id":"@abubakriz/talab@1.0.1","maintainers":[{"name":"abubakriz","email":"abubakr.iznain@gmail.com"}],"homepage":"https://github.com/abubakriz/talab#readme","bugs":{"url":"https://github.com/abubakriz/talab/issues"},"dist":{"shasum":"4b78ad9da2911c2884f260de13245be6b49fb36d","tarball":"https://registry.npmjs.org/@abubakriz/talab/-/talab-1.0.1.tgz","fileCount":8,"integrity":"sha512-vaviyHUuUzd1NMBqG9deG1vGFNc8RgxKDUxQDsaF7/o9sjJKHuflZ8kdfvbOi2HlhC2Wpoa12ca8qiwapMh+9w==","signatures":[{"sig":"MEUCIQDP67TWPbpoCPH6KEWAaV3rSFbXJEAMgpnr2cCMWouUPwIgE+QAOt3vY5cDKRfl08rVsIZx1vFV4qqiTEFcQsRzkvM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":20749},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"dc94fecfe7f5d752068ce101674a9cdff26a9c1b","scripts":{"lint":"biome check . && tsc --noEmit","test":"bun test","build":"rm -rf ./dist && bun build src/index.ts --minify --sourcemap --target=node --outdir=./dist && tsc","check":"tsc --noEmit","format":"biome format --write .","docs:dev":"cd docs && bun run dev","lint:fix":"biome check --unsafe --write .","docs:build":"cd docs && bun run build","build:types":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"abubakriz","email":"abubakr.iznain@gmail.com"},"repository":{"url":"git+https://github.com/abubakriz/talab.git","type":"git"},"_npmVersion":"11.12.1","description":"Zero-dependency HTTP client for JavaScript & Typescript with results-based error handling.","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/bun":"^1.3.13","typescript":"^6.0.3","@types/node":"^25.6.0","@biomejs/biome":"^2.4.13"},"_npmOperationalInternal":{"tmp":"tmp/talab_1.0.1_1777056626137_0.8154731919852978","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@abubakriz/talab","version":"1.0.2","keywords":["http","fetch","request","typescript","javascript","http-client","web","browser","node"],"author":{"name":"Abu Bakr Iznain"},"license":"MIT","_id":"@abubakriz/talab@1.0.2","maintainers":[{"name":"abubakriz","email":"abubakr.iznain@gmail.com"}],"homepage":"https://github.com/abubakriz/talab#readme","bugs":{"url":"https://github.com/abubakriz/talab/issues"},"dist":{"shasum":"5f8d96c212f6e9a4173bc9c0bb89eabae547eb88","tarball":"https://registry.npmjs.org/@abubakriz/talab/-/talab-1.0.2.tgz","fileCount":11,"integrity":"sha512-pvsm/85aFRS7rDQ8Aiyb3v6crtxHK8oqRa96PLheTRoGV/uyZEPfLzaudgzuAOZMPpF0C2xhr2Oc0xlPC5DOfg==","signatures":[{"sig":"MEYCIQCquLXSPVDvzVNKXoqapYti1isvkSPAvgoAppWpoFdmCgIhALZVeeee16uiz2OpDFDUIYYvHh5zMmGJ7Ftkt+31J+q7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":24575},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2b341094996bd0e25b38613e91bbee77af531f87","scripts":{"lint":"biome check . && tsc --noEmit","test":"bun test","build":"rm -rf ./dist && bun build src/index.ts --minify --sourcemap --target=node --outdir=./dist && tsc","check":"tsc --noEmit","format":"biome format --write .","docs:dev":"cd docs && bun run dev","lint:fix":"biome check --unsafe --write .","docs:build":"cd docs && bun run build","build:types":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"abubakriz","email":"abubakr.iznain@gmail.com"},"repository":{"url":"git+https://github.com/abubakriz/talab.git","type":"git"},"_npmVersion":"11.12.1","description":"Zero-dependency HTTP client for JavaScript & Typescript with results-based error handling.","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/bun":"^1.3.13","typescript":"^6.0.3","@types/node":"^25.6.0","@biomejs/biome":"^2.4.13"},"_npmOperationalInternal":{"tmp":"tmp/talab_1.0.2_1777058503225_0.7932339385519704","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@abubakriz/talab","version":"1.0.3","author":{"name":"Abu Bakr Iznain"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/abubakriz/talab.git"},"publishConfig":{"access":"public"},"keywords":["http","fetch","request","typescript","javascript","http-client","web","browser","node"],"description":"Zero-dependency HTTP client for JavaScript & Typescript with results-based error handling.","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"bun build src/index.ts --minify --sourcemap --target=node --outdir=./dist && tsc","build:types":"tsc --emitDeclarationOnly","test":"bun test","check":"tsc --noEmit","lint":"biome check . && tsc --noEmit","lint:fix":"biome check --unsafe --write .","format":"biome format --write .","docs:dev":"cd docs && bun run dev","docs:build":"cd docs && bun run build"},"devDependencies":{"@biomejs/biome":"^2.4.13","@types/bun":"^1.3.13","@types/node":"^25.6.0","typescript":"^6.0.3"},"gitHead":"4e217edbd9bc420b555b0c5eeaecb39b80bff34b","_id":"@abubakriz/talab@1.0.3","bugs":{"url":"https://github.com/abubakriz/talab/issues"},"homepage":"https://github.com/abubakriz/talab#readme","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-G766QCLgv0AbSz/1o7w9q1+8uP7clDJXnQFcuZPWP2rN6PTcsfMKpvlIbSaGnRSlzJCUnYDjLDEU2V3xMJF5/Q==","shasum":"9f9791e9e8f0a6a218c599dd10cb8629d8d0d8f2","tarball":"https://registry.npmjs.org/@abubakriz/talab/-/talab-1.0.3.tgz","fileCount":8,"unpackedSize":20744,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAGb/9tutGdnQmGQ6ikAKAQb1jj3Jg/ZfnnEiY0Bnf+eAiB54hBscBo+oMcQrmjGly9sDulfd48GgS8nYLUKMWfE3w=="}]},"_npmUser":{"name":"abubakriz","email":"abubakr.iznain@gmail.com"},"directories":{},"maintainers":[{"name":"abubakriz","email":"abubakr.iznain@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/talab_1.0.3_1777059977281_0.701771521134251"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-24T18:50:26.049Z","modified":"2026-04-24T19:46:17.539Z","1.0.0":"2026-04-24T18:45:04.590Z","1.0.1":"2026-04-24T18:50:26.287Z","1.0.2":"2026-04-24T19:21:43.420Z","1.0.3":"2026-04-24T19:46:17.437Z"},"bugs":{"url":"https://github.com/abubakriz/talab/issues"},"author":{"name":"Abu Bakr Iznain"},"license":"MIT","homepage":"https://github.com/abubakriz/talab#readme","keywords":["http","fetch","request","typescript","javascript","http-client","web","browser","node"],"repository":{"type":"git","url":"git+https://github.com/abubakriz/talab.git"},"description":"Zero-dependency HTTP client for JavaScript & Typescript with results-based error handling.","maintainers":[{"name":"abubakriz","email":"abubakr.iznain@gmail.com"}],"readme":"# Talab\r\n\r\nTalab is an HTTP client for JavaScript and TypeScript. It uses results-based error handling, eliminating the need for `try/catch` blocks \r\naround requests.\r\n\r\n<sub>Fun Fact: \"Talab\" (طلب) is an Arabic word for \"request\"<sub>\r\n\r\n## Features\r\n\r\n- **No `try/catch` blocks:** Network failures and HTTP status codes are returned as values.\r\n- **Linear control flow:** Reduces nesting and keeps your business logic flat.\r\n- **Type-safe:** Strong TypeScript inference directly on the response object.\r\n- **Zero dependencies:** A lightweight wrapper around native `fetch`.\r\n- **Tiny footprint:** ~1kb gzipped.\r\n- **Middleware support:** Intercept and modify requests and responses.\r\n- **Addon support:** Extend the `TalabInstance` API with custom fluent methods.\r\n- **Resolver addons:** Extend the resolver (response handler) with custom parsing methods.\r\n\r\n## Why Talab?\r\n\r\nStandard HTTP clients throw exceptions for network errors and non-2xx status codes. However, network failures, timeouts, and 4xx/5xx responses are common, expected occurrences in web applications. It does not make sense to use exceptions for expected control flow. This approach forces developers to rely on nested `try/catch` blocks and repetitive type-guards.\r\n\r\nTalab treats network behavior as data. It catches network failures, timeouts, and parse errors, returning them as a typed error value. Additionally, 4xx/5xx HTTP responses are treated as successful network requests rather than errors. This guarantees that your business logic is handled linearly and exceptions are reserved strictly for actual runtime bugs.\r\n\r\n## Comparison\r\n\r\n### Using Axios (Exception-based)\r\n\r\n```ts\r\nimport axios from \"axios\";\r\n\r\nasync function getPost(id: number) {\r\n  try {\r\n    const res = await axios.get(`https://api.example.com/posts/${id}`);\r\n    return res.data;\r\n  } catch (error) {\r\n    if (axios.isAxiosError(error)) {\r\n      if (error.response?.status === 404) {\r\n        return null; // Handle status codes\r\n      }\r\n      return null; // Handle network errors\r\n    }\r\n    throw error;\r\n  }\r\n}\r\n```\r\n\r\n### Using Talab (Results-based)\r\n\r\n```ts\r\nimport { talab } from \"talab\";\r\n\r\nasync function getPost(id: number) {\r\n  const res = await talab\r\n    .get(`https://api.example.com/posts/${id}`)\r\n    .json<Post>();\r\n\r\n  if (!res.ok) {\r\n    return null; // Handle network errors\r\n  }\r\n\r\n  if (res.status === 404) {\r\n    return null; // Handle status codes\r\n  }\r\n\r\n  return res.data;\r\n}\r\n```\r\n\r\n## Advanced Features\r\n\r\n### Instances and Configuration\r\n\r\nYou can create instances with default configurations that merge intelligently:\r\n\r\n```ts\r\nconst api = talab.create({\r\n  base: \"https://api.example.com\",\r\n  headers: { \"X-App-Version\": \"1.0.0\" }\r\n});\r\n\r\n// Inherits base URL and headers from `api`\r\nconst authed = api.create({\r\n  headers: { Authorization: \"Bearer token\" }\r\n});\r\n```\r\n\r\n### Middlewares\r\n\r\nMiddlewares allow you to intercept and modify requests and responses.\r\n\r\n```ts\r\nimport type { Middleware } from \"talab\";\r\n\r\nconst addHeader: Middleware = (next) => (url, init) => {\r\n  const headers = new Headers(init.headers);\r\n  headers.set(\"X-Timing\", Date.now().toString());\r\n  return next(url, { ...init, headers });\r\n};\r\n\r\nconst api = talab.create({ middlewares: [addHeader] });\r\n```\r\n\r\n### Addons\r\n\r\nExtend the `TalabInstance` API with custom fluent methods.\r\n\r\n```ts\r\nimport type { Addon, TalabInstance } from \"talab\";\r\n\r\ntype BearerAddon = Addon<{ bearer(token: string): TalabInstance }>;\r\n\r\nconst bearerAddon: BearerAddon = (instance) => ({\r\n  ...instance,\r\n  bearer(token: string) {\r\n    return instance.create({\r\n      headers: { Authorization: `Bearer ${token}` },\r\n    });\r\n  },\r\n});\r\n\r\nconst api = talab.create().addon(bearerAddon);\r\n\r\nawait api.bearer(\"my-token\").get(\"/protected\").json();\r\n```\r\n\r\n### Resolver Addons\r\n\r\nResolver addons extend the resolver object (the response handler returned by `.get()`, `.post()`, etc.) with custom parsing methods. While addons extend the *instance*, resolver addons extend the *resolver*.\r\n\r\n```ts\r\nimport type { ResolverAddon } from \"talab\";\r\n\r\n// Add a custom `.jsonStrict()` that treats non-2xx as errors\r\nconst strictResolver: ResolverAddon<{\r\n  jsonStrict<T>(): Promise<Result<T>>;\r\n}> = (resolver) => ({\r\n  ...resolver,\r\n  async jsonStrict<T>() {\r\n    const raw = await resolver.raw();\r\n    if (!raw.ok) return raw;\r\n    if (raw.status >= 400) {\r\n      return {\r\n        ok: false as const,\r\n        error: { type: \"network\" as const, original: new Error(`HTTP ${raw.status}`) },\r\n      };\r\n    }\r\n    const data = (await raw.data.json()) as T;\r\n    return { ok: true as const, data, response: raw.data, status: raw.status };\r\n  },\r\n});\r\n\r\n// Apply via .resolver()\r\nconst api = talab.create({ base: \"https://api.example.com\" }).resolver(strictResolver);\r\n\r\n// Every request now has .jsonStrict() available\r\nconst res = await api.get(\"/users\").jsonStrict<User[]>();\r\n```\r\n\r\nResolver addons compose and inherit through `.create()`, just like middlewares.\r\n\r\n### Timeouts and Abort Signals\r\n\r\nTalab supports native `AbortSignal` and timeout configurations. You can set a timeout globally on an instance or pass it per-request.\r\n\r\n```ts\r\n// Set a 5-second timeout on the instance\r\nconst api = talab.create({ timeout: 5000 });\r\n\r\n// Override with a 1-second timeout for a specific request\r\nawait api.get(\"/fast\", { timeout: 1000 }).json();\r\n\r\n// Or use a custom AbortController\r\nconst controller = new AbortController();\r\nawait api.get(\"/custom\", { signal: controller.signal }).json();\r\ncontroller.abort();\r\n```\r\n\r\n### Custom Fetchers\r\n\r\nYou can provide a custom `fetch` implementation, which is useful for testing, proxies, or alternate runtimes.\r\n\r\n```ts\r\nconst api = talab.create({\r\n  fetcher: myCustomFetch\r\n});\r\n```","readmeFilename":"README.md"}