{"_id":"@autorunai/fetcher","_rev":"2-59b826c2cc36d4a2179ba6419836bb88","name":"@autorunai/fetcher","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@autorunai/fetcher","version":"1.0.0","keywords":["fetch","http","client","typescript","type-safe","hooks","api","request","wrapper"],"author":{"name":"autorun"},"license":"MIT","_id":"@autorunai/fetcher@1.0.0","maintainers":[{"name":"efuzul","email":"efuzul@gmail.com"},{"name":"lovro_autorun","email":"lovro.zagar@rearm.co"}],"homepage":"https://github.com/autorunai/fetcher#readme","bugs":{"url":"https://github.com/autorunai/fetcher/issues"},"dist":{"shasum":"73da31b89baef681e5dfdd091752cb79ed784448","tarball":"https://registry.npmjs.org/@autorunai/fetcher/-/fetcher-1.0.0.tgz","fileCount":5,"integrity":"sha512-UFdccikScx04Hap/LeRVAZFOkDfxz54SoB0en2U4p1mnVnLED6nfhbd5iD0SStpG3dfX8PLr3tXkNZOw8DSIww==","signatures":[{"sig":"MEYCIQCvcWC4KHY4CX9jmhSJzRORZuzWg88uwvX+dv91a7j/3AIhANudtoJzqz7G1DMzVfAQ+SIrl0z15/UEn1eDR10eN9o4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":29374},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"b00328372f14f33df0f78c05432c9eaf2b0afb86","private":false,"scripts":{"build":"bunchee -m","setup":"bunx lefthook install && chmod +x .lefthook/commit-msg/commitlint.sh && bun install","lint:fix":"bunx biome check --linter-enabled=true --formatter-enabled=false --organize-imports-enabled=false --write ./src","precommit":"bun run format:fix && bun run import-sort:fix && bun run lint:fix && bun run type:check","format:fix":"bunx biome check --formatter-enabled=true --organize-imports-enabled=false --linter-enabled=false --write ./src","lint:check":"bunx biome check --linter-enabled=true --formatter-enabled=false --organize-imports-enabled=false .","preinstall":"bunx only-allow bun","type:check":"tsc --noEmit","format:check":"bunx biome check --formatter-enabled=true --organize-imports-enabled=false --linter-enabled=false ./src","unused:check":"knip","update:check":"bun x npm-check-updates","lefthook:init":"bunx lefthook install","type:coverage":"typescript-coverage-report","madge:circular":"madge --circular src/","update:install":"bunx npm-check-updates --deep -u && bun install","commitlint:init":"chmod +x .lefthook/commit-msg/commitlint.sh","import-sort:fix":"bunx biome check --organize-imports-enabled=true --formatter-enabled=false --linter-enabled=false --write --unsafe ./src","lint:fix:unsafe":"bunx biome check --linter-enabled=true --formatter-enabled=false --organize-imports-enabled=false --write --unsafe ./src","import-sort:check":"bunx biome check --organize-imports-enabled=true --formatter-enabled=false --linter-enabled=false ./src","circular-dep:check":"bunx madge --circular $(find ./src -type f -name '*.ts' -o -name '*.tsx' -o -name '*.js')","madge:dependencies":"madge --image deps.svg src/index.ts"},"_npmUser":{"name":"lovro_autorun","email":"lovro.zagar@rearm.co"},"repository":{"url":"git+https://github.com/autorunai/fetcher.git","type":"git"},"_npmVersion":"11.0.0","description":"Type-safe fetch wrapper with hooks, error handling, and flexible configuration for modern web applications","directories":{},"sideEffects":false,"_nodeVersion":"22.12.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ms":"^2.1.3","knip":"^5.50.5","madge":"^8.0.0","bunchee":"^6.5.0","lefthook":"^1.11.10","only-allow":"^1.2.1","typescript":"^5.8.3","@biomejs/biome":"^1.9.4","@commitlint/cli":"^19.8.0","npm-check-updates":"^17.1.18","@semantic-release/git":"^10.0.1","@semantic-release/npm":"^12.0.1","@semantic-release/github":"^11.0.1","@total-typescript/ts-reset":"^0.6.1","typescript-coverage-report":"^1.1.1","@semantic-release/changelog":"^6.0.3","@commitlint/config-conventional":"^19.8.0","@semantic-release/commit-analyzer":"^13.0.1","@semantic-release/release-notes-generator":"^14.0.3"},"_npmOperationalInternal":{"tmp":"tmp/fetcher_1.0.0_1749125509019_0.533974355068124","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"author":{"name":"autorun"},"bugs":{"url":"https://github.com/autorunai/fetcher/issues"},"description":"Type-safe fetch wrapper with hooks, error handling, and flexible configuration for modern web applications","devDependencies":{"@biomejs/biome":"^1.9.4","@commitlint/cli":"^19.8.0","@commitlint/config-conventional":"^19.8.0","@semantic-release/changelog":"^6.0.3","@semantic-release/commit-analyzer":"^13.0.1","@semantic-release/git":"^10.0.1","@semantic-release/github":"^11.0.1","@semantic-release/npm":"^12.0.1","@semantic-release/release-notes-generator":"^14.0.3","@total-typescript/ts-reset":"^0.6.1","bunchee":"^6.5.0","knip":"^5.50.5","lefthook":"^1.11.10","madge":"^8.0.0","ms":"^2.1.3","npm-check-updates":"^17.1.18","only-allow":"^1.2.1","typescript":"^5.8.3","typescript-coverage-report":"^1.1.1"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"homepage":"https://github.com/autorunai/fetcher#readme","keywords":["fetch","http","client","typescript","type-safe","hooks","api","request","wrapper"],"license":"MIT","main":"./dist/index.js","module":"./dist/index.js","name":"@autorunai/fetcher","private":false,"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/autorunai/fetcher.git"},"scripts":{"build":"bunchee -m","circular-dep:check":"bunx madge --circular $(find ./src -type f -name '*.ts' -o -name '*.tsx' -o -name '*.js')","commitlint:init":"chmod +x .lefthook/commit-msg/commitlint.sh","format:check":"bunx biome check --formatter-enabled=true --organize-imports-enabled=false --linter-enabled=false ./src","format:fix":"bunx biome check --formatter-enabled=true --organize-imports-enabled=false --linter-enabled=false --write ./src","import-sort:check":"bunx biome check --organize-imports-enabled=true --formatter-enabled=false --linter-enabled=false ./src","import-sort:fix":"bunx biome check --organize-imports-enabled=true --formatter-enabled=false --linter-enabled=false --write --unsafe ./src","lefthook:init":"bunx lefthook install","lint:check":"bunx biome check --linter-enabled=true --formatter-enabled=false --organize-imports-enabled=false .","lint:fix":"bunx biome check --linter-enabled=true --formatter-enabled=false --organize-imports-enabled=false --write ./src","lint:fix:unsafe":"bunx biome check --linter-enabled=true --formatter-enabled=false --organize-imports-enabled=false --write --unsafe ./src","madge:circular":"madge --circular src/","madge:dependencies":"madge --image deps.svg src/index.ts","precommit":"bun run format:fix && bun run import-sort:fix && bun run lint:fix && bun run type:check","preinstall":"bunx only-allow bun","setup":"bunx lefthook install && chmod +x .lefthook/commit-msg/commitlint.sh && bun install","type:check":"tsc --noEmit","type:coverage":"typescript-coverage-report","unused:check":"knip","update:check":"bun x npm-check-updates","update:install":"bunx npm-check-updates --deep -u && bun install"},"sideEffects":false,"type":"module","types":"./dist/index.d.ts","version":"1.0.1","_id":"@autorunai/fetcher@1.0.1","gitHead":"cdf72c7b7d9f9f7181d307c074137bede6d31ddf","_nodeVersion":"22.12.0","_npmVersion":"11.0.0","dist":{"integrity":"sha512-+BDIYFCUPmF4d4K6GjvrfrSR/FHG3s3Z15KlNfnzwSmFRjn9nZb7jW0zlc3D/JxdNJk+629LWoMLjPifDsbfiA==","shasum":"582ae37260f2f7f97349dc980174bda3a31a2702","tarball":"https://registry.npmjs.org/@autorunai/fetcher/-/fetcher-1.0.1.tgz","fileCount":5,"unpackedSize":22983,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCQPc1UlHAqr/WdLCdnKEqaUsxNuNBCY6/INBbPdl8qcwIhAKK9ovW9/m41pg4nSeyY2CDcnvlaAd9b6JFWooGochph"}]},"_npmUser":{"name":"lovro_autorun","email":"lovro.zagar@rearm.co"},"directories":{},"maintainers":[{"name":"efuzul","email":"efuzul@gmail.com"},{"name":"lovro_autorun","email":"lovro.zagar@rearm.co"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fetcher_1.0.1_1749126043042_0.04104058358754581"},"_hasShrinkwrap":false}},"time":{"created":"2025-06-05T12:11:48.942Z","modified":"2025-06-05T12:20:43.414Z","1.0.0":"2025-06-05T12:11:49.184Z","1.0.1":"2025-06-05T12:20:43.195Z"},"bugs":{"url":"https://github.com/autorunai/fetcher/issues"},"author":{"name":"autorun"},"license":"MIT","homepage":"https://github.com/autorunai/fetcher#readme","keywords":["fetch","http","client","typescript","type-safe","hooks","api","request","wrapper"],"repository":{"type":"git","url":"git+https://github.com/autorunai/fetcher.git"},"description":"Type-safe fetch wrapper with hooks, error handling, and flexible configuration for modern web applications","maintainers":[{"name":"efuzul","email":"efuzul@gmail.com"},{"name":"lovro_autorun","email":"lovro.zagar@rearm.co"}],"readme":"# @autorunai/fetcher\r\n\r\n**Built by Autorun**\r\nThis package is developed and maintained by [Autorun](https://autorun.ai/), an AI-powered platform for building and deploying intelligent applications. If you need enterprise support or custom integrations, contact us at [hello@autorun.ai](mailto:hello@autorun.ai).\r\n\r\nA powerful, type-safe fetch wrapper with hooks, error handling, and flexible configuration for modern web applications.\r\n\r\n## Features\r\n\r\n- 🔒 **Type-safe** - Full TypeScript support with generic constraints\r\n- 🎣 **Hook system** - Intercept and customize request/response lifecycle\r\n- ⚡ **Zero dependencies** - Built on native fetch API\r\n- 🛠 **Flexible configuration** - Base URL, default options, custom headers\r\n- 🎯 **Method-specific types** - Different types for GET/DELETE vs POST/PUT/PATCH\r\n- 🚫 **Smart error handling** - Configurable via hooks, no forced throwing\r\n- 📦 **Tree-shakeable** - ESM with no side effects\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @autorunai/fetcher\r\n```\r\n\r\n```bash\r\nyarn add @autorunai/fetcher\r\n```\r\n\r\n```bash\r\npnpm add @autorunai/fetcher\r\n```\r\n\r\n```bash\r\nbun add @autorunai/fetcher\r\n```\r\n\r\n## Quick Start\r\n\r\n```typescript\r\nimport { createFetcher } from '@autorunai/fetcher'\r\n\r\nconst api = createFetcher({\r\n  baseUrl: 'https://api.example.com'\r\n})\r\n\r\n/* GET request */\r\nconst { data, response } = await api.get({\r\n  url: '/users'\r\n}).json<User[]>()\r\n\r\n/* POST request */\r\nconst { data } = await api.post({\r\n  url: '/users',\r\n  data: { name: 'John', email: 'john@example.com' }\r\n}).json<User>()\r\n```\r\n\r\n## Configuration\r\n\r\n```typescript\r\nconst api = createFetcher({\r\n  baseUrl: 'https://api.example.com',\r\n  fetch: {\r\n    headers: {\r\n      'Authorization': 'Bearer token'\r\n    }\r\n  }\r\n})\r\n```\r\n\r\n## Hook System\r\n\r\n### Request Transformation\r\n\r\n```typescript\r\nconst api = createFetcher({\r\n  hooks: {\r\n    onBeforeRequest: (url, init) => {\r\n      /* Add auth token */\r\n      init.headers = {\r\n        ...init.headers,\r\n        'Authorization': `Bearer ${getToken()}`\r\n      }\r\n      return [url, init]\r\n    }\r\n  }\r\n})\r\n```\r\n\r\n### Error Handling\r\n\r\n```typescript\r\nconst api = createFetcher({\r\n  hooks: {\r\n    onFetchResourceError: (url, init) => {\r\n      console.error('Network error:', url)\r\n      /* Let default error throw */\r\n    },\r\n\r\n    onJsonTransformError: ({ response }) => {\r\n      console.error('Invalid JSON from:', response.url)\r\n      /* Throw custom error */\r\n      throw new Error('Server returned invalid data')\r\n    },\r\n\r\n    onResponseNotOkError: ({ response, data }) => {\r\n      if (response.status === 401) {\r\n        redirectToLogin()\r\n        return /* Don't throw, handle gracefully */\r\n      }\r\n      /* Let other errors be handled manually */\r\n    }\r\n  }\r\n})\r\n```\r\n\r\n```typescript\r\n/* Custom error class */\r\nclass ApiError extends Error {\r\n  constructor(\r\n    public status: number,\r\n    public data: unknown,\r\n    message: string\r\n  ) {\r\n    super(message)\r\n    this.name = 'ApiError'\r\n  }\r\n}\r\n\r\nconst api = createFetcher({\r\n  hooks: {\r\n    onFetchResourceError: (url, init) => {\r\n      console.error('Network error:', url)\r\n      /* Let default error throw */\r\n    },\r\n\r\n    onJsonTransformError: ({ response }) => {\r\n      console.error('Invalid JSON from:', response.url)\r\n      /* Throw custom error */\r\n      throw new Error('Server returned invalid data')\r\n    },\r\n\r\n    onResponseNotOkError: ({ response, data }) => {\r\n      if (response.status === 401) {\r\n        redirectToLogin()\r\n        return /* Don't throw, handle gracefully */\r\n      }\r\n\r\n      /* Throw custom error class */\r\n      throw new ApiError(\r\n        response.status,\r\n        data,\r\n        `API Error: ${response.status} ${response.statusText}`\r\n      )\r\n    }\r\n  }\r\n})\r\n\r\n/* Usage with custom error handling */\r\ntry {\r\n  const { data } = await api.get({ url: '/users' }).json()\r\n} catch (error) {\r\n  if (error instanceof ApiError) {\r\n    console.error(`API failed with ${error.status}:`, error.data)\r\n  }\r\n}\r\n```\r\n\r\n## Default thrown errors\r\n\r\n```typescript\r\nimport { EXCEPTION } from '@autorunai/fetcher'\r\n\r\ntry {\r\n  await api.get({ url: '/test' }).json()\r\n} catch (error) {\r\n  if (error.message === EXCEPTION.RESPONSE) {\r\n    /* Network/fetch error */\r\n  }\r\n  if (error.message === EXCEPTION.JSON) {\r\n    /* Invalid JSON response */\r\n  }\r\n}\r\n```\r\n\r\n### Response Logging\r\n\r\n```typescript\r\nconst api = createFetcher({\r\n  hooks: {\r\n    onResponseOk: ({ response, data }) => {\r\n      console.log(`✅ ${response.status} ${response.url}`)\r\n    }\r\n  }\r\n})\r\n```\r\n\r\n## Advanced Usage\r\n\r\n### Custom Headers per Request\r\n\r\n```typescript\r\nconst { data } = await api.post({\r\n  url: '/upload',\r\n  data: formData,\r\n  headers: {\r\n    'Content-Type': 'multipart/form-data'\r\n  }\r\n}).json()\r\n```\r\n\r\n### URL Path Parameters\r\n\r\n```typescript\r\nconst api = createFetcher<`/users/${string}` | '/users'>({\r\n  baseUrl: 'https://api.example.com'\r\n})\r\n\r\n/* TypeScript will enforce correct URL patterns */\r\nawait api.get({ url: '/users/123' }).json()\r\nawait api.get({ url: '/users' }).json()\r\n```\r\n\r\n## API Reference\r\n\r\n### createFetcher(config?)\r\n\r\nCreates a new fetcher instance.\r\n\r\n**Parameters:**\r\n- `config.baseUrl` - URL prefix for all requests\r\n- `config.fetch` - Default fetch options\r\n- `config.hooks` - Lifecycle hooks\r\n\r\n### Methods\r\n\r\n- `get(options)` - GET request (no body)\r\n- `post(options)` - POST request (requires data)\r\n- `put(options)` - PUT request (requires data)\r\n- `patch(options)` - PATCH request (requires data)\r\n- `delete(options)` - DELETE request (no body)\r\n\r\n### Options\r\n\r\n**Body-less methods (GET, DELETE):**\r\n```typescript\r\n{\r\n  url: string\r\n  headers?: Record<string, string>\r\n  /* ...other RequestInit options except method/body */\r\n}\r\n```\r\n\r\n**Body-full methods (POST, PUT, PATCH):**\r\n```typescript\r\n{\r\n  url: string\r\n  data: unknown  /* Will be JSON.stringify'd */\r\n  headers?: Record<string, string>\r\n  /* ...other RequestInit options except method/body */\r\n}\r\n```\r\n\r\n## TypeScript Support\r\n\r\nFull type inference and safety:\r\n\r\n```typescript\r\ninterface User {\r\n  id: number\r\n  name: string\r\n  email: string\r\n}\r\n\r\n/* Return type automatically inferred as User[] */\r\nconst users = await api.get({ url: '/users' }).json<User[]>()\r\n\r\n/* TypeScript enforces data property for POST */\r\nconst newUser = await api.post({\r\n  url: '/users',\r\n  data: { name: 'John', email: 'john@example.com' }\r\n}).json<User>()\r\n```\r\n\r\n## License\r\n\r\nMIT © autorun\r\n","readmeFilename":"README.md"}