Skip to content

@ic-reactor/core

@ic-reactor/core is the client of ic-reactor 4. It sits on a module that candid-core-cli gen writes from a .did file, and it has no React in it. It gives you:

  • a client with query keys that carry the caller, TanStack Query options for reads and writes, and network resolution;
  • one error type that says whether a call may have executed;
  • strict helpers for token amounts;
  • a test client over an in-memory replica, in a separate entry.

It works in a browser, in Node and on a server. It ships as ES modules only, with no CommonJS build: use it from a package with "type": "module" or through a bundler (see ES modules only). For React, add @ic-reactor/react. For Vite, add @ic-reactor/vite-plugin.

Terminal window
npm install @ic-reactor/core @icp-sdk/core @tanstack/query-core
npm install --save-exact @candid-core/schema@0.4.0
npm install @icp-sdk/auth # for Internet Identity

The generator is a separate dev dependency, pinned to the version that pairs with @candid-core/schema:

Terminal window
npm install --save-dev --save-exact @candid-core/cli@0.3.0

See Getting started for the first read and write.

Node >=22.12.0, the first Node 22 that loads an ES module with require() (22.12 itself prints an experimental warning when it does).

Peer Range
@candid-core/schema exactly 0.4.0: the module candid-core-cli gen writes imports it
@icp-sdk/core ^6.1.0
@tanstack/query-core ^5.62.0
@noble/curves ^2.2.0, optional: only @ic-reactor/core/testing signs with it, and @icp-sdk/core installs it already

With React, install @tanstack/query-core at the exact version your @tanstack/react-query depends on, and check that npm ls @tanstack/query-core shows one copy; see the React package.

@icp-sdk/auth is not a peer. Install it when users sign in with Internet Identity: its AuthClient is an AuthLike as it is, see Auth.

The entry has 13 names: four at runtime and nine types. The export budget caps it at 13.

Export Kind What it is
createClient runtime Builds a client from a network and a caller. See The client.
isReactorError runtime Tests whether a thrown value is a ReactorError; with a canister and a method, one of that call’s, its err typed. See Errors.
parseUnits runtime Text to base units: parseUnits("1.5", 8) is 150000000n. See Values and units.
formatUnits runtime Base units to text, without losing digits. See Values and units.
Client type A client offers: canister, canisterId, queryOptions, mutationOptions, resendOf, queryKey, encode, func, time, signIn, signOut, caller, authState, subscribe, queryClient, network, dispose.
ClientOptions type The argument of createClient: a network, and exactly one of identity and auth.
Network type "ic", "local", "env", or { host, rootKey?, name?, fetchRootKey? }.
AuthLike type What auth must be: the shape of an @icp-sdk/auth 10 AuthClient. See Auth.
AuthState type { status, principal, expiresAt? }: who calls now, why, and until when.
Canister type What client.canister<Actor>(actor, target) returns: one async method per Candid method.
CanisterTarget type { id } or { name }, each with an optional certified. See Reads.
ReactorError type The error every call rejects with. A type only: there is no class, so test with isReactorError.
ReactorErrorKind type The eight kinds of a ReactorError.

The signatures that matter most:

function createClient(options: ClientOptions): Client
type ClientOptions = {
readonly network: Network
readonly allowEnvConfig?: boolean
readonly fetch?: typeof globalThis.fetch
readonly maxDepth?: number
readonly maxElements?: number
} & (
| { readonly identity: Identity | "anonymous"; readonly auth?: never }
| {
readonly auth: (network: AuthNetwork) => AuthLike
readonly identity?: never
}
)
// Not exported: what the auth factory is handed, `network` in `(network) => new AuthClient(network)`.
type AuthNetwork = {
readonly agentOptions: {
readonly host: string
readonly rootKey?: Uint8Array
readonly shouldFetchRootKey: boolean
readonly fetch?: typeof globalThis.fetch
}
readonly identityProvider?: {
readonly authorizeUrl: string
readonly canisterId: string
}
}
function isReactorError(error: unknown): error is ReactorError<unknown>
function isReactorError<A, M extends keyof A & string>(
error: unknown,
canister: Canister<A>,
method: M
): error is ReactorError<ErrorOf<A, M>> & { readonly method: M } // ErrorOf: the method's Err arm, or never
function parseUnits(
text: string,
decimals: number,
options?: { signed?: boolean }
): bigint
function formatUnits(
value: bigint,
decimals: number,
options?: { maxFractionDigits?: number; minFractionDigits?: number }
): string

createClient does no work until it is used, so the same line runs in a server render and in a browser. It throws a TypeError for options that do not say who calls, say it twice, or name a network, maxDepth or maxElements it cannot use; for an option it does not have, in the options or in a network object; and for an allowEnvConfig or fetchRootKey that is not a boolean, a rootKey that is not 133 bytes in a Uint8Array, or a fetch that is not a function. parseUnits and formatUnits refuse an option they do not have too. The auth factory is handed the client’s network: Auth says where its identityProvider comes from.

A separate entry with two names. The main entry never imports it, so none of it reaches an app bundle.

Export Kind What it is
createTestClient runtime A real client over an in-memory replica, with mocked canisters and a sign-in a test controls.
TestHandlers type The handlers of a mocked canister, typed from the generated Actor.

See Testing.

The package exports exactly these names, from exactly two subpaths: . and ./testing (and ./package.json). Every name has one import path, so it does not re-export what lives elsewhere:

  • principal, isPrincipal and the Principal type come from @candid-core/schema.
  • skipToken, useQuery, useMutation, useSuspenseQuery, useInfiniteQuery, dehydrate and HydrationBoundary come from TanStack Query (@tanstack/react-query, or @tanstack/query-core outside React).

The tarball carries a guide for people and coding agents, written against this version: node_modules/@ic-reactor/core/llms.txt. It covers setup, values, reads, writes, errors and a complete React example. These pages go into more depth and agree with it.

Coming from 3.x? See Migrating from 3.x.