@karmaniverous/cached-axios
Version:
Tag‑aware caching for Axios: stable cache IDs, simple tag invalidation, and a drop‑in Orval mutator on top of axios‑cache‑interceptor.
105 lines (99 loc) • 5.02 kB
TypeScript
import { AxiosRequestConfig, AxiosResponse } from 'axios';
export { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { z } from 'zod';
import * as axios_cache_interceptor from 'axios-cache-interceptor';
export { CacheProperties, CacheRequestConfig } from 'axios-cache-interceptor';
export { OrvalBodyType, OrvalErrorType, orvalMutator } from './mutators/orval.js';
/**
* Branded cache key types produced by {@link buildConfig}.
* - `Id` is used for cache keys (stable, resource-specific).
* - `Tag` groups cache ids for invalidation (coarse-grained).
*/
type Id = string & {
readonly __brand: 'Id';
};
type Tag = string & {
readonly __brand: 'Tag';
};
/**
* Input config schema for {@link buildConfig}.
* - Nested objects; leaves are `undefined`.
* - The resulting structure mirrors the input and adds `id()`/`tag()` at every node.
*/
declare const ConfigInputSchema: z.ZodType<Record<string, unknown>>;
type ConfigInput = z.output<typeof ConfigInputSchema>;
/** Segment types accepted by id/tag */
type Segment = string | number;
type SegInput = Segment | Segment[] | undefined;
/** Methods at every node */ type WithFns = {
id: (seg?: SegInput) => Id;
tag: (seg?: SegInput) => Tag;
};
type Leaf = undefined;
type Shape = {
readonly [k: string]: Shape | Leaf;
};
type BuiltNode<T, P extends string[]> = WithFns & (T extends undefined ? {} : {
readonly [K in keyof T]: BuiltNode<T[K], [...P, Extract<K, string>]>;
});
/**
* Build a strongly-typed configuration object from a nested shape.
* - Validates input with {@link ConfigInputSchema}.
* - Every node exposes `id(seg?)` and `tag(seg?)` to generate colon-delimited keys.
* - See tests for usage patterns.
*
* @typeParam T The nested shape type, e.g. `{ user: { byId: undefined } }`.
* @param input Nested object whose leaves are `undefined`.
* @returns A structure mirroring `input` with `id()` and `tag()` at each node.
*/
declare const buildConfig: <T extends Shape>(input: T) => BuiltNode<T, []>;
/**
* Execute a GET-like call with a stable cache id and tag registration.
* - Merges any object-valued `base.cache` into the helper's cache config.
* - Registers the cache id under the provided tags for future invalidation.
* - Leaves response shape intact; caller validates payload type.
*
* @typeParam T Expected response data type.
* @param call Function that performs the request (e.g., `cachedAxios.request`).
* @param id Stable cache id to use for this resource.
* @param tags Tags to associate with `id` for future invalidation.
* @param base Optional Axios config; shallow-merged into the final request.
* @returns The AxiosResponse with data typed as T.
*/
declare const withQuery: <T>(call: (opts: AxiosRequestConfig) => Promise<AxiosResponse<unknown>>, id: Id, tags: Tag[], base?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
/**
* Execute a write-like call with tag-based invalidation.
* - Builds an `update` map that tells ACI to delete affected ids.
* - Clears tag buckets in the in-memory index after the call.
* - Leaves response shape intact; caller validates payload type.
*
* @typeParam T Expected response data type.
* @param call Function that performs the request (e.g., `cachedAxios.request`).
* @param invalidate Tags whose registered ids should be invalidated.
* @param base Optional Axios config; shallow-merged into the final request.
* @returns The AxiosResponse with data typed as T.
*/
declare const withMutation: <T>(call: (opts: AxiosRequestConfig) => Promise<AxiosResponse<unknown>>, invalidate: Tag[], base?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
/** Cache-aware Axios instance used by helpers and the Orval mutator. */
declare const cachedAxios: axios_cache_interceptor.AxiosCacheInstance;
/**
* Base Axios configuration for helper factories.
* - May be a static object, a factory returning a config (or undefined),
* or `undefined` to opt out.
*/
type BaseInput = AxiosRequestConfig | (() => AxiosRequestConfig | undefined) | undefined;
/**
* Create pre-bound cache helpers with a base Axios config.
* - `query(call, id, tags, options?)` delegates to {@link withQuery}.
* - `mutation(call, invalidate, options?)` delegates to {@link withMutation}.
* - Both helpers shallow-merge `options` over the resolved `base`.
*
* @param base Base Axios config or factory.
* @returns An object with `query` and `mutation` helpers.
*/
declare const makeCacheHelpers: (base?: BaseInput) => {
query: <T>(call: (opts: AxiosRequestConfig) => Promise<AxiosResponse<unknown>>, id: Id, tags: Tag[], options?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
mutation: <T>(call: (opts: AxiosRequestConfig) => Promise<AxiosResponse<unknown>>, invalidate: Tag[], options?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
};
export { ConfigInputSchema, buildConfig, cachedAxios, makeCacheHelpers, withMutation, withQuery };
export type { BaseInput, BuiltNode, ConfigInput, Id, SegInput, Segment, Shape, Tag, WithFns };