-
Notifications
You must be signed in to change notification settings - Fork 0
Getting started
double-meh is a zero-dependency, ESM-only HTTP I/O library that works in browsers and on the CLI
(Node · Bun · Deno).
npm i double-mehIt ships ESM only. Import it in an ES module or a "type": "module" package:
import io from 'double-meh';CommonJS consumers on modern Node (≥ 20.19 / ≥ 22.12) can require() it directly via
require(esm) — the default instance is also a named export, so destructuring works:
// CommonJS, modern Node
const {io} = require('double-meh');
// CommonJS, older Node — dynamic import from async code
const {default: io} = await import('double-meh');The default export io is everything. Bare verbs return the parsed body:
const person = await io.get('https://api.example.com/people/42');
// ^ already-parsed JSON (or text) — not a ResponseNamed exports are the same functions, if you prefer them:
import {get, post, full, stream} from 'double-meh';The method you call fixes what comes back — options never change the return type:
await io.get(url); // → parsed data (the 99% path)
await io.full.get(url); // → the full envelope {data, status, ok, headers, response, ...}
await io.stream.get(url); // → a Web ReadableStream (the raw body)
io.stream.put(url, {as: 'ndjson'}); // → a streaming {writable, readable, response} duplexThe namespaces compose rather than multiply: io.full answers "I need the metadata", io.stream
answers "I need the raw body" — and when you need both, ask io.full for a streamed body:
const envelope = await io.full.get(url, null, {stream: true});
envelope.status; // metadata is here...
envelope.data; // ...and data is the raw ReadableStream, undrainedSee Core API for the full return model and Streaming for the last two.
verb(url, data?, options?) — for reads data is the query, for writes it is the body:
await io.get('/search', {q: 'cats', page: 2}); // → /search?q=cats&page=2
await io.post('/things', {name: 'Bob'}); // JSON body {"name":"Bob"}
await io.put('/things/7', updated, {ifMatch: etag}); // conditional writeA non-2xx response throws, and the error carries the same envelope shape:
try {
await io.get('/missing');
} catch (error) {
if (error instanceof io.BadStatus) {
console.log(error.status, error.data); // e.g. 404 and the parsed problem+json
}
}- Core API · Requests & options · Streaming
- Recipes: Basics and the rest of the cookbook (sidebar).
Guides
Concepts
Services
Modules
- fetch transport
- keys & URLs
- helpers
- records
- sse
- storage backends
- compression encoders
- Service Worker integration
Cookbook