{"_id":"@api-hooks/crates","name":"@api-hooks/crates","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@api-hooks/crates","version":"1.0.0","description":"React hooks for the crates.io REST API, built on @tanstack/react-query","keywords":["react","hooks","crates","crates.io","rust","registry","api","react-query","tanstack"],"license":"MIT","homepage":"https://github.com/ElJijuna/api-hooks#readme","repository":{"type":"git","url":"git+https://github.com/ElJijuna/api-hooks.git","directory":"packages/crates"},"bugs":{"url":"https://github.com/ElJijuna/api-hooks/issues"},"publishConfig":{"access":"public"},"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"},"./types":{"types":"./dist/types.d.ts","import":"./dist/types.js"}},"sideEffects":false,"scripts":{"build":"vite build && tsc --emitDeclarationOnly --declarationMap","dev":"vite build --watch","test":"jest --passWithNoTests","test:coverage":"jest --coverage --passWithNoTests","typecheck":"tsc --noEmit","docs":"typedoc"},"peerDependencies":{"@tanstack/react-query":"^5.0.0","react":">=19.0.0"},"dependencies":{"crates-api-client":"^1.0.0"},"devDependencies":{"@tanstack/react-query":"^5.101.0","@testing-library/react":"^16.3.2","jest":"^30.4.2","jest-environment-jsdom":"^30.4.1","react":"^19.2.7","react-dom":"^19.2.7","typedoc":"^0.28.19","vite":"^8.0.16","vite-magic-tree-shaking":"^1.0.0"},"author":{"name":"pilmee","email":"pilmee@gmail.com","url":"https://github.com/ElJijuna"},"gitHead":"8e914c0286f3a965f02d34a9736c2fd807339d41","_id":"@api-hooks/crates@1.0.0","_nodeVersion":"22.23.1","_npmVersion":"11.18.0","dist":{"integrity":"sha512-lseA9x41ltIyHKeNqXny41d8kOtrHV5U4ou7uavggXNRuDDwze5Lodq40x+yE8pkOdYGm0GJyOUJGli6ONO5nQ==","shasum":"0581c38b78f66cb6a9ba42f5d95b9b95088734b4","tarball":"https://registry.npmjs.org/@api-hooks/crates/-/crates-1.0.0.tgz","fileCount":43,"unpackedSize":41588,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCnVUl1/F/lDwMPmNXDkJyQsWKpsIkYb7A7xhykzv6d2gIhANBet9IMgazS+7CQwBDKA5fZJVEbZV1BONQtRacVRGXt"}]},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"directories":{},"maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/crates_1.0.0_1782996682657_0.17639021906145436"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-02T12:51:22.428Z","1.0.0":"2026-07-02T12:51:22.909Z","modified":"2026-07-02T12:51:23.223Z"},"maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"description":"React hooks for the crates.io REST API, built on @tanstack/react-query","homepage":"https://github.com/ElJijuna/api-hooks#readme","keywords":["react","hooks","crates","crates.io","rust","registry","api","react-query","tanstack"],"repository":{"type":"git","url":"git+https://github.com/ElJijuna/api-hooks.git","directory":"packages/crates"},"author":{"name":"pilmee","email":"pilmee@gmail.com","url":"https://github.com/ElJijuna"},"bugs":{"url":"https://github.com/ElJijuna/api-hooks/issues"},"license":"MIT","readme":"# @api-hooks/crates\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ElJijuna/api-hooks/main/public/assets/api-hooks.png\" alt=\"api-hooks logo\" width=\"240\" />\n</p>\n\nReact hooks for the [crates.io REST API](https://crates.io/data-access), built on [`crates-api-client`](https://www.npmjs.com/package/crates-api-client) and [`@tanstack/react-query`](https://tanstack.com/query).\n\n[![npm](https://img.shields.io/npm/v/@api-hooks/crates)](https://www.npmjs.com/package/@api-hooks/crates)\n[![npm downloads](https://img.shields.io/npm/dm/@api-hooks/crates)](https://www.npmjs.com/package/@api-hooks/crates)\n[![CI](https://github.com/ElJijuna/api-hooks/actions/workflows/ci.yml/badge.svg)](https://github.com/ElJijuna/api-hooks/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)\n\n## Requirements\n\n| Peer dependency | Version |\n| --------------- | ------- |\n| `react` | `>=19.0.0` |\n| `@tanstack/react-query` | `^5.0.0` |\n\n## Installation\n\n```bash\nnpm install @api-hooks/crates @tanstack/react-query\n```\n\n## Setup\n\nWrap your application with a `QueryClientProvider` and a `CratesClientProvider` once at the root:\n\n```tsx\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { CratesClientProvider } from '@api-hooks/crates';\n\nconst queryClient = new QueryClient();\n\nexport default function App() {\n  return (\n    <QueryClientProvider client={queryClient}>\n      <CratesClientProvider>\n        <YourApp />\n      </CratesClientProvider>\n    </QueryClientProvider>\n  );\n}\n```\n\nBy default, requests go to `crates.io`. crates.io requires a descriptive `User-Agent` header for server-side requests — override it (or point at a private/mirrored registry) through `CratesClientProvider`:\n\n```tsx\n<CratesClientProvider\n  options={{\n    baseUrl: 'https://my-registry.example.com',\n    userAgent: 'my-app/1.0 (contact@example.com)',\n  }}\n>\n  <YourApp />\n</CratesClientProvider>\n```\n\n`CratesClientProvider` is optional — hooks fall back to a default `CratesClient` (pointed at `crates.io`) when no provider is present.\n\n## Hooks\n\nQuery hooks return a [`UseQueryResult`](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) — you get the full TanStack Query API: `data`, `isLoading`, `isFetching`, `isError`, `error`, `refetch`, and more. `useCratesSearchInfinite` returns a [`UseInfiniteQueryResult`](https://tanstack.com/query/latest/docs/framework/react/reference/useInfiniteQuery).\n\n| Hook | Description | Returns |\n| ---- | ----------- | ------- |\n| [`useCratesSearch(params?, options?)`](#usecratessearchparams-options) | Search crates.io | `CratesSearchResult` |\n| [`useCratesSearchInfinite(options?)`](#usecratessearchinfiniteoptions) | Infinite-scroll variant of `useCratesSearch` | `InfiniteData<CratesSearchResult>` |\n| [`useCratesCrateSummary(name, options?)`](#usecratescratesummaryname-options) | Crate metadata plus versions, keywords, categories | `CrateResult` |\n| [`useCratesCrateVersions(name, options?)`](#usecratescrateversionsname-options) | All published versions of a crate | `CrateVersion[]` |\n| [`useCratesCrateVersion(name, version, options?)`](#usecratescrateversionname-version-options) | Metadata for a specific version | `CrateVersion` |\n| [`useCratesCrateLatest(name, options?)`](#usecratescratelatestname-options) | Metadata for the latest (`max_version`) release | `CrateVersion` |\n\n---\n\n## API Reference\n\n### `useCratesSearch(params?, options?)`\n\nSearches crates.io by text, with pagination and sort order.\n\n```tsx\nimport { useCratesSearch } from '@api-hooks/crates';\n\nfunction CrateSearch() {\n  const { data, isLoading } = useCratesSearch({ query: 'serde', perPage: 10 });\n\n  if (isLoading) return <p>Loading…</p>;\n\n  return (\n    <ul>\n      {data?.crates.map(c => (\n        <li key={c.id}>{c.name} — {c.max_version} ({c.downloads} downloads)</li>\n      ))}\n    </ul>\n  );\n}\n```\n\n| Option | Type | Default | Description |\n| ------ | ---- | ------- | ----------- |\n| `enabled` | `boolean` | `true` | Disable the query |\n| `queryOptions` | `QueryOverrides<TData>` | `undefined` | Override TanStack Query options (`staleTime`, `retry`, `gcTime`, `select`, etc.) |\n\n---\n\n### `useCratesSearchInfinite(options?)`\n\nInfinite-scroll variant of `useCratesSearch`. Each page is fetched by advancing the 1-based `page` number. Call `fetchNextPage()` to load the next batch — results accumulate in `data.pages`.\n\n```tsx\nimport { useCratesSearchInfinite } from '@api-hooks/crates';\n\nfunction CrateSearchInfinite() {\n  const { data, fetchNextPage, hasNextPage } = useCratesSearchInfinite({ query: 'serialization' });\n\n  return (\n    <>\n      {data?.pages.flatMap(page => page.crates).map(c => (\n        <div key={c.id}>{c.name}</div>\n      ))}\n      {hasNextPage && <button onClick={() => fetchNextPage()}>Load more</button>}\n    </>\n  );\n}\n```\n\n| Option | Type | Default | Description |\n| ------ | ---- | ------- | ----------- |\n| `query` | `string` | `undefined` | Search text |\n| `perPage` | `number` | `10` | Page size |\n| `sort` | `CratesSort` | `undefined` | Sort order (`'alpha'`, `'downloads'`, `'recent-downloads'`, `'recent-updates'`, `'new'`) |\n| `enabled` | `boolean` | `true` | Disable the query |\n| `queryOptions` | `InfiniteQueryOverrides<TData>` | `undefined` | Override TanStack Query options |\n\n---\n\n### `useCratesCrateSummary(name, options?)`\n\nFetches crate metadata plus its included versions, keywords, and categories.\n\n```tsx\nimport { useCratesCrateSummary } from '@api-hooks/crates';\n\nfunction CrateDetail() {\n  const { data } = useCratesCrateSummary('serde');\n\n  return <p>{data?.crate.description}</p>;\n}\n```\n\n| Option | Type | Default | Description |\n| ------ | ---- | ------- | ----------- |\n| `enabled` | `boolean` | `true` | Disable the query (also disabled when `name` is empty) |\n| `queryOptions` | `QueryOverrides<TData>` | `undefined` | Override TanStack Query options (`staleTime`, `retry`, `gcTime`, `select`, etc.) |\n\n---\n\n### `useCratesCrateVersions(name, options?)`\n\nFetches all versions published for a crate.\n\n```tsx\nimport { useCratesCrateVersions } from '@api-hooks/crates';\n\nfunction VersionList() {\n  const { data } = useCratesCrateVersions('serde');\n\n  return <ul>{data?.map(v => <li key={v.num}>{v.num}</li>)}</ul>;\n}\n```\n\n| Option | Type | Default | Description |\n| ------ | ---- | ------- | ----------- |\n| `enabled` | `boolean` | `true` | Disable the query (also disabled when `name` is empty) |\n| `queryOptions` | `QueryOverrides<TData>` | `undefined` | Override TanStack Query options (`staleTime`, `retry`, `gcTime`, `select`, etc.) |\n\n---\n\n### `useCratesCrateVersion(name, version, options?)`\n\nFetches metadata for a specific published version of a crate.\n\n```tsx\nimport { useCratesCrateVersion } from '@api-hooks/crates';\n\nfunction VersionDetail() {\n  const { data } = useCratesCrateVersion('serde', '1.0.210');\n\n  return <p>{data?.license} — {data?.downloads} downloads</p>;\n}\n```\n\n| Option | Type | Default | Description |\n| ------ | ---- | ------- | ----------- |\n| `enabled` | `boolean` | `true` | Disable the query (also disabled when `name` or `version` is empty) |\n| `queryOptions` | `QueryOverrides<TData>` | `undefined` | Override TanStack Query options (`staleTime`, `retry`, `gcTime`, `select`, etc.) |\n\n---\n\n### `useCratesCrateLatest(name, options?)`\n\nFetches version metadata matching the crate's `max_version` (the latest non-yanked version).\n\n```tsx\nimport { useCratesCrateLatest } from '@api-hooks/crates';\n\nfunction LatestVersion() {\n  const { data } = useCratesCrateLatest('serde');\n\n  return <p>Latest: {data?.num}</p>;\n}\n```\n\n| Option | Type | Default | Description |\n| ------ | ---- | ------- | ----------- |\n| `enabled` | `boolean` | `true` | Disable the query (also disabled when `name` is empty) |\n| `queryOptions` | `QueryOverrides<TData>` | `undefined` | Override TanStack Query options (`staleTime`, `retry`, `gcTime`, `select`, etc.) |\n\n---\n\n## License\n\nMIT © [ElJijuna](https://github.com/ElJijuna)\n","readmeFilename":"README.md","_rev":"1-d6482cdd379606024777b995f88f493b"}