stopcock
Fast, composable TypeScript.
A handful of functional TypeScript packages that play nicely together. Pipeable utilities covering arrays, dates, async tasks, state management, diffing, and image processing, with more to come.
import { pipe, A } from '@stopcock/fp'
const top10 = pipe( users, A.filter(u => u.active), A.map(u => ({ name: u.name, score: u.score })), A.take(10),)import { pipe } from '@stopcock/fp'import { create, add, format } from '@stopcock/date'
const nextWeek = pipe( create.now(), add('days', 7), format('yyyy-MM-dd'),)import { pipe } from '@stopcock/fp'import { fromPromise, map, flatMap, retry, timeout, run } from '@stopcock/async'
const fetchUser = pipe( fromPromise(() => fetch('/api/user')), flatMap(res => fromPromise(() => res.json())), map(data => data.name), retry({ attempts: 3 }), timeout(5000),)
const name = await run(fetchUser)import { diff, apply, invert } from '@stopcock/diff'
const patch = diff( { user: 'Tom', scores: [10, 20] }, { user: 'Tom', scores: [10, 20, 30] },)const restored = apply(patch.target, invert(patch))import { create, history } from '@stopcock/state'
const store = create({ count: 0, name: 'Tom' })store.subscribe(s => s.count, (next) => console.log(next))store.set(s => s.count, 1)import { pipe } from '@stopcock/fp'import { fromRGBA, resize, sharpen, contrast } from '@stopcock/img'
const thumbnail = (data: Uint8ClampedArray, w: number, h: number) => pipe( fromRGBA(data, w, h), resize(200, 200), sharpen, contrast(30),) @stopcock/fp Pipe, Option, Result, Array, String, lenses, and Stream. The core everything else builds on. @stopcock/date Date arithmetic, formatting, parsing, timezones, and business day logic. @stopcock/async Lazy Task type with retry, timeout, concurrency limits, and cancellation via AbortSignal. @stopcock/http Typed HTTP client with retry, timeout, dedup, and Task integration. @stopcock/img Pixel-level image processing. Filters, convolution, resize, crop. @stopcock/diff Structural diffing, patching, composition, and rebasing for objects and arrays. @stopcock/state Reactive stores with fine-grained subscriptions, middleware, undo/redo, and devtools.
Array pipelines fuse automatically
Section titled “Array pipelines fuse automatically”pipe detects chainable array operations and fuses them into a single loop. take(10) bails after 10 hits. On a million-element array, that’s dozens of items touched instead of three full passes.
9xfilter→map→take(10) on 100K elements
10xfilter→map→take(10) on 100K elements
6xfilter→map→take(10) on 100K elements
bun add @stopcock/fp