@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.
When to Use This Package
Section titled “When to Use This Package”- You need
ClientManager,Reactor, orDisplayReactorin 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.
Installation
Section titled “Installation”pnpm add @ic-reactor/core @icp-sdk/core @tanstack/query-coreWhat’s Included
Section titled “What’s Included”Quick Start
Section titled “Quick Start”import { ClientManager, Reactor } from "@ic-reactor/core"import { QueryClient } from "@tanstack/query-core"import { canisterId, idlFactory, type _SERVICE } from "./declarations/backend"
const queryClient = new QueryClient()export const clientManager = new ClientManager({ queryClient,})
await clientManager.initialize()
export const backend = new Reactor<_SERVICE>({ clientManager, idlFactory, name: "backend", // Required in Node, where the constructor otherwise throws. A browser page // may omit it only when the ic_env cookie is trusted there (a local replica, // or `allowEnvConfig: true`). canisterId,})
const greeting = await backend.fetchQuery({ functionName: "greet", args: ["World"],})Retry Classification
Section titled “Retry Classification”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 these 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,
an HTTP 5xx, 408 or 429 answer, 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. Neither is any other HTTP 4xx answer, such as
the 400 for an expired delegation or a 403: it refuses the request itself,
and the agent has already sent it retryTimes more times (3 by default)
before reporting it. The status is read from the agent’s HttpErrorCode by
its name and status, so an error from another copy of @icp-sdk/core
classifies the same way. 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.
An update call is different: each attempt is a new call that the canister
runs, so only a failure that proves the first attempt never ran is safe to
retry. isRetryableUpdateError(error) accepts just that, a SysTransient
rejection, and reactorUpdateRetry(failureCount, error) retries it up to 3
times in a browser. A query of an update method with no retry of its own
retries this way within the QueryClient’s retry default, as
Reactor.getQueryRetry(functionName, queryKey) returns; getQueryOptions and
fetchQuery apply it. See
Update Methods in Queries.
Identity Attributes
Section titled “Identity Attributes”Identity attributes are not part of @ic-reactor/core.
IdentityAttributesManager in @ic-reactor/react requests
signed OpenID identity attributes through @icp-sdk/auth v8 or v10:
import { AuthenticationManager, IdentityAttributesManager, identityAttributeKeys,} from "@ic-reactor/react"// The `clientManager` and `backend` the Quick Start's module exportsimport { backend, clientManager } from "./reactor"
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().
Testing
Section titled “Testing”@ic-reactor/core/testing is a separate entry point for tests. It installs a
fake replica that answers your agent with canisters written as typed handlers,
so ClientManager, Reactor and DisplayReactor run unmodified with no
replica:
import { createTestCanister, installFakeReplica,} from "@ic-reactor/core/testing"import { canisterId, idlFactory, type _SERVICE } from "./declarations/backend"
const replica = installFakeReplica({ canisters: { [canisterId]: createTestCanister<_SERVICE>(idlFactory, { greet: ([name]) => `Hello, ${name}!`, }), },})// Build the ClientManager afterwards, with agentOptions: { host: replica.host }.The main entry never imports it. See the Testing guide.
See Also
Section titled “See Also”- @ic-reactor/react — React bindings built on top of this package
- Authentication — Internet Identity and identity attributes
- React Setup — End-to-end React integration guide
- @ic-reactor/candid — Dynamic runtime Candid support