Skip to content
IC Reactor

@ic-reactor/core

@ic-reactor/core is the framework-agnostic foundation of IC Reactor. It gives you the runtime building blocks for agent management, identity wiring, TanStack Query integration, and typed canister interaction without depending on React.

  • You need ClientManager, Reactor, or DisplayReactor in non-React code.
  • You want to use IC Reactor in loaders, services, scripts, or framework adapters.
  • You are building your own abstractions on top of IC Reactor’s runtime layer.
Terminal window
pnpm add @ic-reactor/core @icp-sdk/core @tanstack/query-core
import { ClientManager, Reactor } from "@ic-reactor/core"
import { QueryClient } from "@tanstack/query-core"
import { idlFactory, type _SERVICE } from "./declarations/backend"
const queryClient = new QueryClient()
const clientManager = new ClientManager({
queryClient,
})
await clientManager.initialize()
const backend = new Reactor<_SERVICE>({
clientManager,
idlFactory,
name: "backend",
})
const greeting = await backend.fetchQuery({
functionName: "greet",
args: ["World"],
})

Whether a failed call is worth retrying is decided by what failed, and most failures are deterministic. @ic-reactor/core exports the classification (@ic-reactor/react re-exports both functions):

import { reactorRetry, isRetryableReactorError } from "@ic-reactor/core"
import { QueryClient } from "@tanstack/query-core"
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: reactorRetry } },
})

isRetryableReactorError(error) returns true only for a CallError whose cause is an agent-level fault — a transport, protocol, or certificate failure, or a SysTransient/SysUnknown replica rejection. A canister Err variant (CanisterError), a ValidationError, a Candid encode failure (no request was ever made), and a decode failure on the reply are never retryable: identical input — or the identical reply — produces the identical failure. Within agent errors the bias is toward retrying — an unrecognized kind, or a rejection whose code cannot be read, still retries, so an unfamiliar transport-level fault is never silently made fatal.

reactorRetry(failureCount, error) is a ready-made TanStack Query retry predicate on top of it — up to 3 retries (4 attempts in total) for retryable errors, none otherwise, and always false on the server so a failed prefetch keeps failing fast. defineReactor in @ic-reactor/react already installs it as the query default on the QueryClient it creates; a QueryClient you construct yourself opts in as shown above.

Identity attributes are not part of @ic-reactor/core. IdentityAttributesManager in @ic-reactor/react requests signed OpenID identity attributes through @icp-sdk/auth v8:

import {
AuthenticationManager,
IdentityAttributesManager,
identityAttributeKeys,
} from "@ic-reactor/react"
const authentication = new AuthenticationManager({ clientManager })
const identityAttributes = new IdentityAttributesManager(authentication)
const result = await identityAttributes.requestOpenId({
// Pass the nonce as a callback: awaiting it first ends the user gesture
// and the browser blocks the Internet Identity window.
nonce: () => backend.callMethod({ functionName: "register_begin" }),
openIdProvider: "microsoft",
keys: ["email", "name"],
})
await backend.callMethod({
functionName: "register_finish",
args: [
{
data: result.signedAttributes.data,
signature: result.signedAttributes.signature,
},
],
})

Use openIdProvider: "google", "apple", "microsoft", or a provider issuer URL. For lower-level requests, build scoped keys with identityAttributeKeys() and pass them to identityAttributes.request().