@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
fetcherconfigured on aFetchClientinstance. globalThis.fetchand 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.
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-mutexis a direct dependency.zodis an optional peer (only if you use zod helpers).@opentelemetry/apiis a required peer while telemetry is still re-exported from this package. Prefer@ariestools/telemetryfor new code; the@ariestools/sdk/@ariestools/sdk/telemetryre-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.