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

@okfetch/fetch

v0.3.1

Published

A type-safe fetch wrapper with validation, retries, plugins, and streaming.

Readme

@okfetch/fetch

@okfetch/fetch is the transport core of the okfetch ecosystem.

It wraps the standard fetch API with:

  • Result-based error handling via better-result
  • Standard Schema-compatible response validation
  • request retries and timeouts
  • auth helpers
  • lifecycle plugins
  • SSE-style stream parsing

If you want typed HTTP calls without building a full generated client, this is the package to start with.

Installation

bun add @okfetch/fetch better-result
npm install @okfetch/fetch better-result

What It Exports

Functions:

  • okfetch
  • validateClientErrors
  • validateAllErrors

Errors:

  • FetchError
  • TimeoutError
  • ApiError
  • ParseError
  • ValidationError
  • PluginError

Types:

  • OkfetchOptions
  • OkfetchError
  • OkfetchPlugin
  • OkfetchPluginHooks
  • OkfetchSuccess
  • RetryOptions
  • Auth

Quick Example

import { okfetch } from "@okfetch/fetch";
import { z } from "zod/v4";

const todoSchema = z.object({
  completed: z.boolean(),
  id: z.number(),
  title: z.string(),
  userId: z.number(),
});

const result = await okfetch("https://jsonplaceholder.typicode.com/todos/1", {
  outputSchema: todoSchema,
});

result.match({
  err: (error) => console.error(error._tag, error.message),
  ok: (todo) => console.log(todo.title),
});

Request Options

okfetch(url, options) accepts standard fetch options plus okfetch-specific behavior:

  • outputSchema
  • apiErrorDataSchema
  • baseURL
  • params
  • query
  • body
  • auth
  • timeout
  • stream
  • validateOutput
  • shouldValidateError
  • plugins
  • retry
  • fetch

Any schema object that implements Standard Schema v1 can be used for outputSchema and apiErrorDataSchema.

URL building

You can pass a fully qualified URL directly, or combine a relative path with baseURL.

Path params are replaced from params, and query strings are built from query.

await okfetch("/users/:id", {
  baseURL: "https://api.example.com",
  method: "GET",
  params: { id: 42 },
  query: { include: ["teams", "profile"] },
});

Validation

outputSchema validates successful responses:

await okfetch("https://api.example.com/me", {
  outputSchema: z.object({
    id: z.string(),
    email: z.string().email(),
  }),
});

apiErrorDataSchema validates structured error bodies when shouldValidateError allows it:

import { validateClientErrors } from "@okfetch/fetch";

await okfetch("https://api.example.com/me", {
  apiErrorDataSchema: z.object({
    code: z.string(),
    message: z.string(),
  }),
  shouldValidateError: validateClientErrors,
});

Retries

Supported strategies:

  • fixed
  • linear
  • exponential
await okfetch("https://api.example.com/me", {
  retry: {
    attempts: 3,
    initialDelay: 100,
    strategy: "exponential",
  },
});

Auth

Built-in auth shapes:

  • { type: "basic", username, password }
  • { type: "bearer", token }
  • { type: "custom", prefix, value }
await okfetch("https://api.example.com/me", {
  auth: {
    type: "bearer",
    token: process.env.API_TOKEN ?? "",
  },
});

Plugins

Plugins are a core extension point.

import type { OkfetchPlugin } from "@okfetch/fetch";

const plugin: OkfetchPlugin = {
  name: "timing",
  version: "1.0.0",
  hooks: {
    onRequest(context) {
      console.log("->", context.method, context.url.toString());
      return context;
    },
    onFail(_context, _response, error) {
      console.error(error._tag, error.message);
    },
  },
};

Available lifecycle hooks:

  • init
  • onRequest
  • onResponse
  • onSuccess
  • onFail
  • onRetry

Streaming

Set stream: true to receive a ReadableStream.

const result = await okfetch("https://example.com/events", {
  stream: true,
  outputSchema: z.object({
    id: z.number(),
    message: z.string(),
  }),
});

When an outputSchema is present, each SSE data: chunk is parsed and validated independently.

Error Handling

okfetch never throws expected HTTP, parsing, timeout, or validation failures from the request API itself. Instead it returns tagged errors inside the Result.

Use match when you want explicit branching:

result.match({
  err: (error) => {
    if (error._tag === "ApiError") {
      console.error(error.statusCode, error.data);
    }
  },
  ok: (data) => console.log(data),
});

Related Packages

  • @okfetch/api builds typed API clients on top of this package
  • @okfetch/logger provides a ready-made logging plugin