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

@ariestools/sdk

v8.2.0

Published

All-in-one umbrella for the Aries Tools TypeScript/JavaScript utility libraries

Readme

@ariestools/sdk

All-in-one umbrella for the Aries Tools TypeScript/JavaScript utility libraries.

Import the whole SDK:

import { fetchJson } from '@ariestools/sdk'

…or a single slice via a subpath export (tree-shaking-friendly — you only pay for what you import):

import { fetchJson } from '@ariestools/sdk/fetch'
import { assertEx } from '@ariestools/sdk/assert'
import type { ApiConfig } from '@ariestools/sdk/api/model'

Fetch transport and HTTP caching

The fetch helpers are runtime-neutral and do not install an HTTP client or cache. By default, fetchCompress, fetchJson, FetchClient, and fetchJsonClient resolve globalThis.fetch when they make a request. Consumers can override that behavior with a FetchFunction through the fetcher option.

Transport resolution is, from highest to lowest precedence:

  1. A per-request fetcher.
  2. The fetcher configured on a FetchClient instance.
  3. globalThis.fetch and whatever behavior the host runtime has configured for it.

Browsers normally provide their own HTTP cache. Node's built-in fetch does not enable a response cache, but a Node application can install a compatible Undici release and configure either a module-local cached fetcher or the global Undici dispatcher. Undici remains a consumer-owned dependency; @ariestools/sdk does not depend on it.

Module-local Node cache

Inject an Undici fetcher when one module or client should own the dispatcher and cache:

import { FetchClient, type FetchFunction } from '@ariestools/sdk/fetch'
import {
  Agent,
  cacheStores,
  fetch as undiciFetch,
  interceptors,
} from 'undici'

const dispatcher = new Agent().compose(
  interceptors.cache({
    store: new cacheStores.MemoryCacheStore({
      maxSize: 20 * 1024 * 1024,
      maxCount: 250,
      maxEntrySize: 2 * 1024 * 1024,
    }),
    type: 'shared',
  }),
)

const fetcher: FetchFunction = (input, init) =>
  undiciFetch(input, { ...init, dispatcher })

const client = new FetchClient({
  baseURL: 'https://api.example.com',
  fetcher,
})

await client.get('/data')

// The module that creates a dispatcher owns its lifecycle.
await dispatcher.close()

Passing fetcher directly to fetchJson or another convenience function scopes it to that one call. Supplying a per-request fetcher to FetchClient overrides the client default.

Shared Node default

An application may instead install a cached dispatcher during process bootstrap. Every SDK call without an injected fetcher then inherits it through Node's built-in globalThis.fetch:

import { fetchJson, fetchJsonClient } from '@ariestools/sdk/fetch'
import {
  Agent,
  cacheStores,
  interceptors,
  setGlobalDispatcher,
} from 'undici'

const dispatcher = new Agent().compose(
  interceptors.cache({
    store: new cacheStores.MemoryCacheStore({
      maxSize: 100 * 1024 * 1024,
      maxCount: 1_000,
      maxEntrySize: 5 * 1024 * 1024,
    }),
    type: 'shared',
  }),
)

setGlobalDispatcher(dispatcher)

await fetchJson('https://api.example.com/data')
await fetchJsonClient.get('https://api.example.com/data')

Only a terminal application, such as a service, CLI, or worker entrypoint, should replace the global dispatcher. Imported libraries should inject a local fetcher instead. Install the global dispatcher once, before normal requests, and include any required proxy, TLS, retry, or tracing behavior in the dispatcher being installed.

An in-memory global store is shared only within the current Node isolate. Worker threads and separate processes must each configure their own dispatcher. Tests that replace the global dispatcher should retain getGlobalDispatcher(), restore it afterward, and close only the dispatcher they created.

Cache scope versus HTTP cache type

Cache ownership and Undici's HTTP cache type are independent:

  • A local dispatcher limits the store to the module or client that owns its fetcher.
  • A global dispatcher shares the store among all uninjected fetch calls in that Node isolate.
  • type: 'shared' applies shared-cache HTTP rules and is the safe default for a process-wide cache.
  • type: 'private' may cache personalized responses and should be used only when the dispatcher and store are isolated to one identity or credential context.

Do not use a global private cache for unrelated users or tenants. Cache headers and Vary do not replace an explicit application identity boundary.

Bounded response reads and cancellation

JSON helpers and FetchClient / FetchJsonClient accept an optional maxResponseBytes, a positive safe integer. It is validated before starting the request. Omit it for the existing unlimited behavior; a per-request value overrides the client default, including undefined to remove that default.

import { FetchJsonClient } from '@ariestools/sdk/fetch'

const controller = new AbortController()
const client = new FetchJsonClient({
  maxResponseBytes: 1024 * 1024,
  timeout: 5000,
  redirect: 'error',
  credentials: 'omit',
})
const result = await client.get('https://api.example.com/data', {
  signal: controller.signal,
})

The cap counts the bytes exposed by Response.body, incrementally, before text decoding or JSON parsing. It applies to successful and non-2xx bodies. Content-Length is not used as evidence that a body fits. Native Fetch normally decompresses content encodings before exposing these bytes, so a small compressed response can still exceed the cap. This does not bound raw network bytes, headers, buffering inside the transport, decompressor memory, or allocations already made for an individual chunk. JSON parsing is synchronous and cannot be interrupted mid-parse; choose an appropriate byte cap for the application's budget.

A caller signal remains active through body consumption. A client timeout composes with that signal instead of replacing it; the first abort reason wins. An oversized body rejects with FetchError.type === 'response-too-large'; body cancellation uses 'aborted' or 'timeout' and retains the signal reason as cause. The reader is cancelled and unlocked on early exit without waiting indefinitely for the transport's cancellation hook. Injected fetchers must honor the provided signal while acquiring the response.

Non-2xx malformed JSON still produces data: null. Without a byte cap or signal, non-2xx read errors retain their historical null behavior. With either policy option, read errors propagate so cancellation and limits cannot be silently ignored; validateStatus: null does not disable these checks.

For callers that need text rather than JSON, use the same neutral primitive:

import { readResponseText } from '@ariestools/sdk/fetch'
import type { ReadResponseTextOptions } from '@ariestools/sdk/fetch/model'

const options: ReadResponseTextOptions = {
  maxResponseBytes: 1024 * 1024,
  signal: controller.signal,
}
const response = await fetch('https://api.example.com/data', {
  signal: options.signal,
  redirect: 'error',
  credentials: 'omit',
})
const text = await readResponseText(response, options)

readResponseText consumes the response once and never returns a truncated success. It requires native Fetch/Web Streams and TextDecoder; client timeout support also requires AbortSignal.timeout. These APIs are available in the SDK's supported Node baseline (18.17.1+) and modern browsers; no HTTP dependency or global dispatcher is installed by the SDK.

Redirects, credentials, destination validation, and fetcher behavior remain application choices. Set native redirect: 'error' and credentials: 'omit' explicitly when required; validate allowed destinations before making requests. The SDK does not add an SSRF policy, strip explicit authorization headers, or change the existing fetcher precedence.

Monolithic layout

All barreled library code lives in a single source tree under src/modules/. Cross-module imports use package.json imports aliases (for example #zod, #api, #fetch). Top-level src/*.ts files are compile entry shims that produce the published subpath exports in dist/. Tests live under src/spec/ only (not inside src/modules/).

Module membership, import aliases, build entries, and shims are declared in xy.config.ts as sdkModules (intended to become first-class @ariestools/toolchain support). Generated files are synced by scripts/sync-sdk-layout.mjs (runs automatically before compile). After editing sdkModules, build or sync explicitly:

pnpm xy build @ariestools/sdk
# or: pnpm sync-sdk-layout

Runtime notes:

  • async-mutex is a direct dependency.
  • zod is an optional peer (only if you use zod helpers).
  • @opentelemetry/api is a required peer while telemetry is still re-exported from this package. Prefer @ariestools/telemetry for new code; the @ariestools/sdk / @ariestools/sdk/telemetry re-exports are deprecated and will be removed from the main barrel in a future major release.

Specialist packages (@ariestools/express, @ariestools/telemetry, @ariestools/threads, etc.) remain separate installs.