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

@attio/fetchable

v0.0.1-experimental.9

Published

`fetchable` is a library for explicitly handling errors and loading in Typescript and JavaScript.

Readme

Fetchable

fetchable is a library for explicitly handling errors and loading in Typescript and JavaScript.

Installation

> npm install @attio/fetchable

Concepts

Primitive states

There are three primitive states in fetchable.

✅ Complete

A Complete<V> is a simple JavaScript object which represents any kind of intact data.

import {complete} from "@attio/fetchable"

const completeNumber = complete(1) // Returns a Complete<1>

console.log(completeNumber.value) // 1
console.log(completeNumber.state) // "complete"

❌ Errored

An Errored<E> is another JavaScript object which represents something that went wrong.

import {errored} from "@attio/fetchable"

const erroredThing = errored("Oops") // Returns an Errored<"Oops">

console.log(erroredThing.error) // "Oops"
console.log(erroredThing.state) // "errored"

⏳ Pending

A Pending is another JavaScript object which represents some process which is in progress.

import {pending} from "@attio/fetchable"

const pendingThing = pending() // Returns a Pending

console.log(pendingThing.state) // "pending"

Higher order states

The fun comes when we start to mix up the three primitive states.

Result: Complete or Errored

A Result<V, E> is an object which is either a Complete<V> or an Errored<E>. It represents the outcome of a process which might succeed or fail.

import {isComplete} from "@attio/fetchable"

const result = doSynchronousThingWhichMightError() // Returns Result<number, "Oops">

if (isComplete(result)) {
    console.log(result.value) // number
} else {
    console.log(result.error) // "Oops"
}

Loadable: Complete or Pending

A Loadable<V> is an object which is either a Complete<V> or a Pending. It represents the outcome of an asynchronous process which cannot fail.

import {isComplete} from "@attio/fetchable"

const loadable = getStatusOfLongRunningProcess() // Returns Loadable<number>

if (isComplete(loadable)) {
    console.log(loadable.value) // number
}

Fetchable: Complete or Pending or Errored

A Fetchable<V, E> is an object which is either a Complete<V>, Errored<E> or Pending. It represents the outcome of an asynchronous process which can fail.

Fetchable is most often seen in declarative front-end code where we don't want to expose promises.

import {isComplete, isErrored} from "@attio/fetchable"

const fetchable = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">

if (isComplete(fetchable)) {
    console.log(fetchable.value) // number
} else if (isErrored(fetchable)) {
    console.log(fetchable.error) // "Oops"
}

AsyncResult

An AsyncResult<V, E> is a promise of a Result<V, E>. Complete<V>, Errored<E> or Pending. It is most often seen in imperative code where we use promises for asynchronous processes.

import {isComplete, isErrored} from "@attio/fetchable"

const asyncResult = runAsyncProcessWhichMightFail() // Returns AsyncResult<number, "Oops">

asyncResult.then(result => {
    if (isComplete(result)) {
        console.log(result.value) // number
    } else if (isErrored(result)) {
        console.log(result.error) // "Oops"
    }
})

Transformations

fetchable provides functional utilities for working with these objects without explicitly checking which state they're in.

map

import {map} from "@attio/fetchable"

const fetchable = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">

// Increments the fetchable if it's complete. 
// Returns Fetchable<number, "Oops">
const incrementedFetchable = map(fetchable, (number) => number + 1)

bind

import {map} from "@attio/fetchable"

const fetchable = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">

// Increments the fetchable if it's complete and not zero.
// Returns Fetchable<number, "Oops" | "Unexpected zero">
const incrementedFetchable = bind(fetchable, (number) =>
    number === 0 ? errored("Unexpected zero") : complete(number + 1)
)

combine

Arrays

import {combine} from "@attio/fetchable"

const fetchable1 = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
const fetchable2 = doSynchronousThingWhichMightError() // Returns Result<string, "Eek">

// If both fetchables are complete then their values will be returned in a complete array.
// Returns Fetchable<[number, string], "Oops" | "Eek">
const combinedFetchable = combine([fetchable1, fetchable2])

Objects

import {combine} from "@attio/fetchable"

const fetchableA = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
const fetchableB = doSynchronousThingWhichMightError() // Returns Result<string, "Eek">

// If both fetchables are complete then their values will be returned in a new object.
// Returns Fetchable<{a: number, b: string}, "Oops" | "Eek">
const combinedFetchable = combine({a: fetchable1, b: fetchable2})

combineAsync

Like Promise.all for AsyncResults. It takes multiple AsyncResults and resolves when they all resolve with Completes or when one resolves with an Errored.

Arrays

import {combineAsync} from "@attio/fetchable"

const asyncResult1 = runAsyncProcessWhichMightFail() // Returns AsyncResult<number, "Oops">
const asyncResult2 = runAnotherAsyncProcessWhichMightFail() // Returns AsyncResult<string, "Eek">

// Returns Result<[number, string], "Oops" | "Eek">
const combinedResult = await combineAsync([asyncResult1, asyncResult2])

Objects

import {combine} from "@attio/fetchable"

const asyncResultA = runAsyncProcessWhichMightFail() // Returns AsyncResult<number, "Oops">
const asyncResultB = runAnotherAsyncProcessWhichMightFail() // Returns AsyncResult<string, "Eek">

// If both fetchables are complete then their values will be returned in a new object.
// Returns Result<{a: number, b: string}, "Oops" | "Eek">
const combinedResult = await combineAsync({a: asyncResultA, b: asyncResultB})