@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:
- A per-request
fetcher.
- The
fetcher configured on a FetchClient instance.
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')
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.
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
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.