npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cogs/fetch-client

v0.2.0

Published

Zero-dependency HTTP transport implementing the Kubb client contract — the single seam where base URL, auth, headers, timeouts and error shape live for generated API clients

Readme

@cogs/fetch-client

The HTTP transport seam that Kubb-generated API clients compile against. One place to configure base URL, auth, per-request headers, timeouts, credentials, and error shape — swap or instrument the transport without regenerating a single client.

Zero runtime dependencies (native fetch, AbortSignal.timeout, AbortSignal.any). Node 20+ / modern browsers.

Why a seam

Generated clients should never import fetch or a specific HTTP library directly. If they do, every regen re-bakes transport policy into hundreds of files, and changing auth means changing generated code. Instead, Kubb is pointed at this package:

// kubb.config.ts
pluginClient({ importPath: '@cogs/fetch-client', /* ... */ })
pluginReactQuery({ client: { importPath: '@cogs/fetch-client' } })

Generated code then emits import fetch from '@cogs/fetch-client/client' and types its requests with Client, RequestConfig, ResponseErrorConfig from here.

Configure once at bootstrap

import { configureClient } from '@cogs/fetch-client'

configureClient({
  baseUrl: process.env.NEXT_PUBLIC_API_URL!,
  getToken: () => supabase.auth.getSession().then((s) => s.data.session?.access_token),
  getHeaders: () => ({ 'X-Selected-Org-Id': selectedOrgId() }),
})

Every generated call now flows through it. Call configureClient again to rebuild after a token refresh or tenant switch.

Multi-API process, SSR request scope, or parallel tests? Use an isolated instance instead of the module singleton:

import { createFetchClient } from '@cogs/fetch-client'
const api = createFetchClient({ baseUrl })
await getFoo({ client: api.request })

Error contract

Any non-2xx response and any transport failure throws FetchClientError:

  • .status — HTTP status, or undefined for network/timeout failures
  • .error / .data — the parsed response body (structurally satisfies ResponseErrorConfig<T>, so generated call sites keep their types)
  • .url, .method, .headers

.status is exactly where @cogs/react-query's createQueryClient looks to detect a 401 and trigger logout.

Body handling

  • Plain objects → JSON, with Content-Type: application/json set for you
  • FormData / Blob / URLSearchParams / typed arrays → passed through so the runtime sets the boundary/content-type
  • Query params are serialised OpenAPI-style: null/undefined dropped, arrays repeat the key, Date → ISO, nested objects → JSON

Optional: multi-service config registry + URL routing trie

Everything above assumes one API. If a process talks to several generated (Kubb) APIs — each with its own base URL, auth, or headers — this package also ships an optional, additive registry + routing layer. Single-API consumers can ignore this section entirely and keep using configureClient.

The pieces:

  • Config registry (setConfig/getConfig/setConfigs/updateConfig/addConfig/getAllConfigs) — a generic Record<string, Partial<ClientConfig>> keyed by whatever name you choose (a "confkey"). Ships empty; you decide the keys.
  • Operations registry (addOperation/addOperations/getOperation/getAllOperations/updateOperation/deleteOperation) — a typed map of { path, method, confkey, operationId? }, one entry per generated endpoint, pointing at which confkey it belongs to. addOperation/addOperations take a ConflictPolicy ('throw' | 'ignore' | 'overwrite', default 'throw') for what happens when a key is registered twice with a different definition.
  • OperationTriePath — a URL + HTTP-method routing trie. initializeTrie(operations) builds a shared trie from an operations snapshot; findMatchingOperation(url, method) resolves the operation key for an outgoing request.
import {
  setConfig,
  addOperations,
  getAllOperations,
  initializeTrie,
  findMatchingOperation,
  getOperation,
  getConfig,
} from '@cogs/fetch-client'

setConfig('envmgr', { baseUrl: 'https://envmgr.internal' })
setConfig('yellowpages', { baseUrl: 'https://yellowpages.internal' })

addOperations({
  listEnvironments: { path: '/api/environments', method: 'get', confkey: 'envmgr' },
  getService: { path: '/api/services/:id', method: 'get', confkey: 'yellowpages' },
})

initializeTrie(getAllOperations())

const opKey = findMatchingOperation('/api/services/42', 'GET') // 'getService'
const confkey = opKey ? getOperation(opKey)?.confkey : undefined // 'yellowpages'
const config = confkey ? getConfig(confkey) : undefined // { baseUrl: 'https://yellowpages.internal' }

Pair config with createFetchClient (or a small wrapper of your own) to build/select the right FetchClient instance per service. This layer is pure bookkeeping — it does not itself perform requests.