# ClientManager

Defined in: [core/src/client.ts:170](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L170)

ClientManager is a central class for managing the Internet Computer (IC) agent.

It initializes the agent (connecting to local or mainnet) and integrates
with TanStack Query's QueryClient for state management.
Use this as a singleton shared by all reactors in an app.

## Examples

```typescript
import { ClientManager } from "@ic-reactor/core";
import { QueryClient } from "@tanstack/query-core";

const queryClient = new QueryClient();
const clientManager = new ClientManager({
  queryClient,
  agentOptions: { host: "http://127.0.0.1:4943" },
});

await clientManager.initialize();
```

```typescript
// Reuse the same ClientManager across multiple canisters. `canisterId` is
// required in Node, where the constructor otherwise throws; a browser page
// may omit it only where the ic_env cookie is trusted (a local replica, or
// `allowEnvConfig: true`).
const backend = new Reactor<BackendService>({
  clientManager,
  idlFactory: backendIdl,
  name: "backend",
  canisterId: "rrkah-fqaaa-aaaaa-aaaaq-cai",
})
const ledger = new Reactor<LedgerService>({
  clientManager,
  idlFactory: ledgerIdl,
  name: "ledger",
  canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai",
})
```

## Constructors

### Constructor

> **new ClientManager**(`parameters`): `ClientManager`

Defined in: [core/src/client.ts:214](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L214)

Creates a new instance of ClientManager.

#### Parameters

##### parameters

[`ClientManagerParameters`](https://ic-reactor.b3pay.net/v3/libs/interfaces/clientmanagerparameters/)

Configuration options for the agent and network environment.

#### Returns

`ClientManager`

## Properties

### queryClient

> **queryClient**: `QueryClient`

Defined in: [core/src/client.ts:202](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L202)

The TanStack QueryClient used for managing cached canister data and invalidating queries on identity changes.

***

### agentState

> **agentState**: [`AgentState`](https://ic-reactor.b3pay.net/v3/libs/interfaces/agentstate/)

Defined in: [core/src/client.ts:206](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L206)

Current state of the HttpAgent, including initialization status, network, and error information.

## Accessors

### agent

#### Get Signature

> **get** **agent**(): `HttpAgent`

Defined in: [core/src/client.ts:489](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L489)

The underlying HttpAgent managed by this class.

##### Returns

`HttpAgent`

***

### agentHost

#### Get Signature

> **get** **agentHost**(): `URL` \| `undefined`

Defined in: [core/src/client.ts:496](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L496)

The host URL of the current IC agent.

##### Returns

`URL` \| `undefined`

***

### agentHostName

#### Get Signature

> **get** **agentHostName**(): `string`

Defined in: [core/src/client.ts:503](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L503)

The hostname of the current IC agent.

##### Returns

`string`

***

### trustsEnvConfig

#### Get Signature

> **get** **trustsEnvConfig**(): `boolean`

Defined in: [core/src/client.ts:523](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L523)

Whether the configuration carried by the `ic_env` cookie may be trusted for
this agent's host.

`true` when BOTH the agent host and the page origin are unambiguously a
local replica (loopback, `localhost` and its subdomains), or when the
caller passed `allowEnvConfig`. The page counts because the page is what
decides who can write the cookie. A Codespaces or Gitpod domain shares its
parent with other users' workspaces, so it needs `allowEnvConfig`.
Every consumer of that cookie reads this one decision, so the root key, the
Internet Identity provider and a reactor's canister ID cannot disagree
about whether the environment is trustworthy.

The deprecated `allowEnvRootKey` is not enough on its own: it granted the
root key alone, and is honoured for the root key alone.

##### Returns

`boolean`

***

### explicitRootKey

#### Get Signature

> **get** **explicitRootKey**(): `Uint8Array`\<`ArrayBufferLike`\> \| `undefined`

Defined in: [core/src/client.ts:533](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L533)

The root key the caller passed as `agentOptions.rootKey`, which the agent
keeps: on a local host [initializeAgent](#initializeagent) does not replace it with
the key the host serves. `undefined` when none was passed, also when the
agent took one from the `ic_env` cookie.

##### Returns

`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`

***

### isLocal

#### Get Signature

> **get** **isLocal**(): `boolean`

Defined in: [core/src/client.ts:540](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L540)

Returns true if the agent is connecting to a local environment.

##### Returns

`boolean`

***

### network

#### Get Signature

> **get** **network**(): `"local"` \| `"remote"` \| `"ic"`

Defined in: [core/src/client.ts:547](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L547)

Returns the current network type ('ic' or 'local').

##### Returns

`"local"` \| `"remote"` \| `"ic"`

***

### identity

#### Get Signature

> **get** **identity**(): `Identity` \| `undefined`

Defined in: [core/src/client.ts:559](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L559)

The identity currently installed on the agent, if one was set explicitly.

Calls capture this at submit time and pass it back on every request they
make, so a sign-in or sign-out part-way through cannot re-sign a request
that is already in flight.

##### Returns

`Identity` \| `undefined`

## Methods

### initialize()

> **initialize**(): `Promise`\<`ClientManager`\>

Defined in: [core/src/client.ts:380](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L380)

Orchestrates the complete initialization of the ClientManager.
This method awaits the agent's core initialization (e.g., fetching root keys)
Authentication session restoration is handled by AuthenticationManager.

#### Returns

`Promise`\<`ClientManager`\>

A promise that resolves to the ClientManager instance when core initialization is complete.

***

### initializeAgent()

> **initializeAgent**(): `Promise`\<`void`\>

Defined in: [core/src/client.ts:399](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L399)

Specifically initializes the HttpAgent.
On local networks, this includes fetching the root key for certificate verification.
That covers every host whose network isn't `"ic"`, Codespaces and Gitpod
included. The fetched key replaces the key the agent holds: one from the
`ic_env` cookie, or mainnet's when `shouldFetchRootKey` is `false`.

A key passed as `agentOptions.rootKey` is kept instead: nothing is
fetched, so `/api/v2/status` is not requested and need not be reachable,
and the agent verifies against that key before and after this call alike.
On a mainnet host nothing is fetched either way.

#### Returns

`Promise`\<`void`\>

A promise that resolves when the agent is fully initialized.

***

### getUserPrincipal()

> **getUserPrincipal**(): `Promise`\<`Principal`\>

Defined in: [core/src/client.ts:566](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L566)

Returns the current user's Principal identity.

#### Returns

`Promise`\<`Principal`\>

***

### registerCanisterId()

> **registerCanisterId**(`canisterId`, `name?`): `void`

Defined in: [core/src/client.ts:574](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L574)

Registers a canister ID that this agent will interact with.
This is used for informational purposes and network detection.

#### Parameters

##### canisterId

`string`

##### name?

`string`

#### Returns

`void`

***

### connectedCanisterIds()

> **connectedCanisterIds**(): `string`[]

Defined in: [core/src/client.ts:597](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L597)

Returns a list of all canister IDs registered with this agent.

#### Returns

`string`[]

***

### getSubnetIdFromCanister()

> **getSubnetIdFromCanister**(`canisterId`): `Promise`\<`Principal`\>

Defined in: [core/src/client.ts:604](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L604)

Get the subnet ID for a canister.

#### Parameters

##### canisterId

`string`

#### Returns

`Promise`\<`Principal`\>

***

### syncTimeWithSubnet()

> **syncTimeWithSubnet**(`subnetId`): `Promise`\<`void`\>

Defined in: [core/src/client.ts:611](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L611)

Sync time with a specific subnet.

#### Parameters

##### subnetId

`Principal`

#### Returns

`Promise`\<`void`\>

***

### subscribe()

> **subscribe**(`callback`): () => `void`

Defined in: [core/src/client.ts:627](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L627)

Subscribes to identity changes (e.g., after login/logout).

Callbacks run in the order they subscribed, after the agent already holds
the new identity. A callback that throws does not stop the others; the
first error is rethrown from `updateAgent` once they have all run. When a
callback itself calls `updateAgent`, the identity that replaced this one
is the last each callback hears.

#### Parameters

##### callback

(`identity`) => `void`

Function called with the new identity.

#### Returns

An unsubscribe function.

() => `void`

***

### subscribeAgentState()

> **subscribeAgentState**(`callback`): () => `void`

Defined in: [core/src/client.ts:650](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L650)

Subscribes to changes in the agent's initialization state.

Delivery works as for [subscribe](#subscribe): every callback runs even when one
throws, and a newer state set from inside a callback is the last state
each callback hears.

#### Parameters

##### callback

(`state`) => `void`

Function called with the updated agent state.

#### Returns

An unsubscribe function.

() => `void`

***

### updateAgent()

> **updateAgent**(`identity`): `void`

Defined in: [core/src/client.ts:688](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L688)

Installs `identity` on the agent, cleans the cached queries of every
registered canister when the principal changes, and notifies identity
subscribers.

Query keys carry no principal, so on a switch to another principal
(signing in, signing out, switching users) the cache is swept: queries in
flight are cancelled, inactive entries are removed, and the rest are
invalidated, so mounted queries refetch as the new principal.

When `identity` has the principal already installed (a renewed delegation,
a sign-in while signed in, an identity attribute request), the cached
answers are already that principal's and are kept: nothing is cancelled or
removed, and no query that succeeded refetches. Only queries whose last
fetch failed are invalidated, since the old identity may be why they
failed (an expired delegation, or one not valid for that canister), and
so is a query whose fetch was in flight and fails afterwards. The first
call after construction always sweeps.

The comparison sees only the principal. An identity that changes what a
canister is told under the same principal, such as an `AttributesIdentity`
adding signed `sender_info` to each request, keeps answers computed
without it. After installing or removing one, invalidate the affected
queries yourself, e.g. with `reactor.invalidateQueries()`.

#### Parameters

##### identity

`Identity`

The new identity to use.

#### Returns

`void`

***

### fetchAcrossIdentitySwitch()

> **fetchAcrossIdentitySwitch**\<`T`\>(`fetch`): `Promise`\<`T`\>

Defined in: [core/src/client.ts:893](https://github.com/B3Pay/ic-reactor/blob/ebca60584de1b5acd9e698f0b8af70d26e0fa097/packages/core/src/client.ts#L893)

Runs `fetch`, a fetch of a registered canister's query through
[queryClient](#queryclient), and runs it again when the principal switches while
it runs.

`updateAgent` cancels those queries when the principal changes, so an
answer fetched for the previous principal never reaches the cache. A
query with a mounted observer refetches afterwards. An imperative fetch
has no observer: TanStack rejects its promise with a `CancelledError`,
which is neither a `CallError` nor a `CanisterError`, or, when the entry
held data before the fetch began, resolves it with that data, which is
the previous principal's. Through this method it resolves with the
answer for the identity installed now, as a mounted query would show; the
previous identity's answer is still never cached.

`Reactor.fetchQuery`, and with it the query factories' `fetch()`, runs
through here. Wrap any other fetch of a canister query the same way.

Whatever `fetch` settles with while the principal stays is passed on as
is, including a cancellation from `queryClient.cancelQueries()`. After
three runs again, each overtaken by another switch, it rejects with a
`CallError` whose `cause` is what the last run settled with, if it
rejected, so the loop always ends and never returns an answer that may
be another principal's.

#### Type Parameters

##### T

`T`

#### Parameters

##### fetch

() => `Promise`\<`T`\>

Starts the fetch. It is called once per run, so it has to
start a fetch each time rather than return one promise it kept.

#### Returns

`Promise`\<`T`\>

What `fetch` resolved with.

#### Example

```typescript
const pages = await clientManager.fetchAcrossIdentitySwitch(() =>
  clientManager.queryClient.fetchInfiniteQuery(options)
)
```