# Client

Defined in: [core/src/client.ts:181](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L181)

A client made by [createClient](https://ic-reactor.b3pay.net/v4/libs/functions/createclient/): one per browser tab, or one per
request on a server, so that no cache or agent is shared between users.

## Properties

### network

> `readonly` **network**: `string`

Defined in: [core/src/client.ts:183](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L183)

The network's segment in query keys: `"ic"`, `"local"`, a custom network's `name ?? host`, or the resolved host for `"env"`.

***

### queryClient

> `readonly` **queryClient**: `QueryClient`

Defined in: [core/src/client.ts:191](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L191)

The `QueryClient` this client owns. Its default `retry` retries a read
only after a failure that proves it was not delivered, and never on a
server; its dehydrate and hydrate defaults keep `bigint`, `Uint8Array`
and the floats JSON cannot write, so a server's `dehydrate()` survives
`JSON.stringify` and comes back exact.

## Methods

### caller()

> **caller**(): `string`

Defined in: [core/src/client.ts:193](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L193)

The principal calls go out as now, as text: the anonymous principal unless signed in.

#### Returns

`string`

***

### authState()

> **authState**(): [`AuthState`](https://ic-reactor.b3pay.net/v4/libs/interfaces/authstate/)

Defined in: [core/src/client.ts:198](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L198)

Who calls go out as, and why. The object is the same until the status or
the principal changes, so it can be read with `useSyncExternalStore`.

#### Returns

[`AuthState`](https://ic-reactor.b3pay.net/v4/libs/interfaces/authstate/)

***

### subscribe()

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

Defined in: [core/src/client.ts:205](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L205)

Calls `listener` once after each change of [Client.authState](#authstate), and
never for a notification of the auth that changed neither the status nor
the principal (a renewed delegation, for one). Returns a function that
stops listening. On a disposed client it adds nothing.

#### Parameters

##### listener

() => `void`

#### Returns

() => `void`

***

### signIn()

> **signIn**(`options?`): `Promise`\<`void`\>

Defined in: [core/src/client.ts:212](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L212)

Signs in through the client's auth, passing `options` on. Listeners are
told once the auth settles, even if the auth itself did not notify.
Rejects a `TypeError` on a client built with `identity`, which has no
sign-in, and an `Error` on a server or after [Client.dispose](#dispose).

#### Parameters

##### options?

`unknown`

#### Returns

`Promise`\<`void`\>

***

### signOut()

> **signOut**(`options?`): `Promise`\<`void`\>

Defined in: [core/src/client.ts:217](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L217)

Signs out through the client's auth, passing `options` on (such as
`AuthClient`'s `{ returnTo }`). Rejects like [Client.signIn](#signin).

#### Parameters

##### options?

`unknown`

#### Returns

`Promise`\<`void`\>

***

### dispose()

> **dispose**(): `void`

Defined in: [core/src/client.ts:231](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L231)

Releases everything the client holds: it stops listening to its auth and
disposes it, clears the `QueryClient`, and drops its agents. Calling it
again does nothing.

Every call made on the client afterwards, a write included, rejects
`cancelled` with code `client_disposed` and `mayHaveExecuted: false`, and
sends nothing: a direct call, a query or mutation function, a func
reference's function. A call still waiting to be sent (for its caller's
identity, or to be sent again) is cancelled the same way. A direct call
already sent settles as the replica answers; a read the client's
`QueryClient` was running is dropped with the cache.

#### Returns

`void`

***

### canister()

> **canister**\<`A`\>(`service`, `target`): [`Canister`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)\<`A`\>

Defined in: [core/src/client.ts:264](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L264)

A canister to call: a frozen object with one plain async method per
Candid method of `service`, typed from the generated `Actor` you name.

```ts
import { actor, type Actor } from "./canisters/icrc1"
const ledger = client.canister<Actor>(actor, { id: LEDGER_ID })
const balance = await ledger.icrc1_balance_of({ owner, subaccount: null })
```

`service` is the `actor` export of a module `candid-core-cli gen` wrote,
or the `actor` of `schemaFromContract()`: both make the same calls and the
same keys. `<A>` is not checked against `service`; pass the `Actor` of
the same module.

A method sends its call as the caller signed in at the moment it is
called, decodes the reply, and resolves with it as the `Actor` types it,
except that a method whose one result is an `Ok`/`Err` variant resolves
with the `Ok` payload and rejects `canister_err` with the `Err` one. An
update or a oneway by a caller who is not signed in rejects
`unauthenticated` and sends nothing. Every failure is a `ReactorError`;
see [Canister](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/) for what is re-sent.

The same service object and the same target give the same canister
object on every call, so it can be made during render. See
[CanisterTarget](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canistertarget/) for `{ id }`, `{ name }` and `certified`.

#### Type Parameters

##### A

`A`

#### Parameters

##### service

`Schema`\<`Principal`\>

##### target

[`CanisterTarget`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canistertarget/)

#### Returns

[`Canister`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)\<`A`\>

#### Throws

TypeError for a `service` that is not a service schema, or a
target that is not one of the allowed shapes or whose `id` is not
principal text.

***

### queryKey()

> **queryKey**\<`A`, `M`\>(`canister`, `method?`, `vars?`): readonly `unknown`[]

Defined in: [core/src/client.ts:292](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L292)

The query key of a read, or the prefix of a group of reads, for
`queryClient.invalidateQueries`, `getQueryData` and filters:

- `queryKey(c)`: every read of the canister by the current caller.
- `queryKey(c, method)`: every read of that method by the current caller,
  whatever its arguments. For a method without arguments, which has one
  read, this is that read's key, the same as `queryKey(c, method,
  undefined)`, so `queryClient.getQueryData(client.queryKey(ledger,
  "icrc1_fee"))` finds what `queryOptions(ledger, "icrc1_fee")` cached.
- `queryKey(c, method, vars)`: the key `queryOptions(c, method, vars)`
  gives, as built now.

`getQueryData` and `setQueryData` match a key exactly: hand them a read's
whole key, never a prefix (a method's with arguments, or a canister's).

Keys are `['ic-reactor', network, caller, canisterId, method, args]` plus
`'certified'` for a certified canister (DECISIONS Q5). Build them with
this method, never by hand: a key typed out as an array literal is a
`QueryKey` like any other, and matches nothing the client invalidates.
It never throws for `vars` that do not encode: the key then holds
`'$invalid'` and a text of the value.

#### Type Parameters

##### A

`A`

##### M

`M` *extends* `string`

#### Parameters

##### canister

[`Canister`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)\<`A`\>

##### method?

`M`

##### vars?

`VarsOf`\<`A`, `M`\>

#### Returns

readonly `unknown`[]

#### Throws

TypeError for a canister of another client, or a method the
service does not have.

***

### queryOptions()

#### Call Signature

> **queryOptions**\<`A`, `M`\>(`canister`, `method`, ...`args`): `CanisterQueryOptions`\<`DataOf`\<`A`, `M`\>, `ErrorOf`\<`A`, `M`\>, `never`\>

Defined in: [core/src/client.ts:354](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L354)

TanStack Query options for a read: `useQuery(client.queryOptions(ledger,
"icrc1_balance_of", account))`, `queryClient.fetchQuery(...)`, a
`QueryObserver`.

The variables after `method` follow one rule (DECISIONS Q3): nothing for
a method without arguments, the value for one argument, the tuple for two
or more. Pass `skipToken` (from `@tanstack/query-core` or
`@tanstack/react-query`) in their place while they are not known yet.

The read is made as the caller current when the options are built: the
key holds their principal, and the query function refuses to run
(`cancelled`, nothing sent) once someone else is signed in. Build the
options again when the caller changes, as a component does on every
render, and the read moves to the new caller's key: one principal's data
is never shown under another's.

Arguments that do not encode give a key tagged `'$invalid'` and a query
function that rejects `invalid_args` with the codec's issues, so a render
never throws on half-typed input.

`retry` retries only a failure that proves the call was not delivered, at
most 3 times, and never on a server.

No type says whether a method is a query or an update, so this checks at
run time and throws a `TypeError` for an update or a oneway method: a
query refetches, and every refetch would run the update again. Use
[Client.mutationOptions](#mutationoptions) for a write. An update that returns the
same answer however often it runs (ckBTC's `get_btc_address`) can be read
with `{ update: "idempotent" }` as the fourth argument: it is fetched once
per key and caller (`staleTime: Infinity`, no refetch on mount, focus or
reconnect), needs a signed-in caller like any update, and is retried only
after a failure that proves it never got in (DECISIONS Q2). It is still a
read of its canister, so a write to that canister through
[Client.mutationOptions](#mutationoptions) invalidates it by default and it runs once
more, as a replicated call: safe for an idempotent method, but a cost. To
keep it cached across writes, name the reads a write changes in
`invalidates`.

A method without results (`() -> () query`) has nothing to cache: its
call resolves `undefined`, which TanStack Query takes for a failed read.
This throws a `TypeError` for it too; call it directly, as
`await canister.method()`.

Built from variables that cannot be `skipToken`, the options' `queryFn`
is never `skipToken` either, so `useSuspenseQuery` and
`useSuspenseQueries` take them as they are. Variables of a type
`skipToken` is assignable to, such as `unknown` (a Candid `reserved`
argument) or `{}`, may be, so every read of such a method takes the next
signature and keeps `SkipToken`.

##### Type Parameters

###### A

`A`

###### M

`M` *extends* `string`

##### Parameters

###### canister

[`Canister`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)\<`A`\>

###### method

`M`

###### args

...`QueryArgs`\<`A`, `M`, `never`\>

##### Returns

`CanisterQueryOptions`\<`DataOf`\<`A`, `M`\>, `ErrorOf`\<`A`, `M`\>, `never`\>

##### Throws

TypeError for an update or oneway method without the opt-in, a
method without results, a composite query of a certified canister, a
canister of another client, a method the service does not have, or a
fourth argument other than `{ update: "idempotent" }`.

#### Call Signature

> **queryOptions**\<`A`, `M`\>(`canister`, `method`, ...`args`): `CanisterQueryOptions`\<`DataOf`\<`A`, `M`\>, `ErrorOf`\<`A`, `M`\>\>

Defined in: [core/src/client.ts:368](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L368)

TanStack Query options for a read whose variables may be `skipToken`
(`V | SkipToken`, or `skipToken` itself): the options' `queryFn` is
`skipToken` for a skipped read, which `useQuery` takes and
`useSuspenseQuery` does not. Otherwise the same as the call with
variables that cannot be skipped: see that signature for the rules.

##### Type Parameters

###### A

`A`

###### M

`M` *extends* `string`

##### Parameters

###### canister

[`Canister`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)\<`A`\>

###### method

`M`

###### args

...`QueryArgs`\<`A`, `M`\>

##### Returns

`CanisterQueryOptions`\<`DataOf`\<`A`, `M`\>, `ErrorOf`\<`A`, `M`\>\>

##### Throws

TypeError as the call with variables that cannot be skipped.

***

### mutationOptions()

> **mutationOptions**\<`A`, `M`\>(`canister`, `method`, `options?`): `CanisterMutationOptions`\<`VarsOf`\<`A`, `M`\>, `DataOf`\<`A`, `M`\>, `ErrorOf`\<`A`, `M`\>\>

Defined in: [core/src/client.ts:418](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L418)

TanStack Query options for a write: `useMutation(client.mutationOptions(
ledger, "icrc1_transfer"))`, then `mutate(arg)` with the same argument
convention as [Client.queryOptions](#queryoptions).

The mutation function calls the method as the caller current when it
runs, and an update by a caller who is not signed in rejects
`unauthenticated` before anything is sent. `retry` is `false`: an update
re-sends itself only when the failure proves the first attempt never got
in (see [Canister](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)), and a TanStack retry would re-send after
failures that do not prove it, running the write twice.

`onSettled` invalidates the reads the write may have changed, on this
client's `queryClient`, for every caller, certified or not, and waits for
the active ones to refetch: after a success, a `canister_err`, and any
failure whose `mayHaveExecuted` is `true` (a lost reply: the re-read shows
whether it happened). Not after a failure that proves nothing ran
(`invalid_args`, `unauthenticated`, `not_delivered`, a reject 1 or 3, a
`cancelled` before sending). The reads are every read of the canister
written to (DECISIONS Q10), or those listed in `invalidates`: canisters
and `[canister, method]` pairs of this client; `[]` invalidates nothing.
"Every read" includes an update read with `{ update: "idempotent" }`
(such as a ckBTC minter's `get_btc_address` after `update_balance`),
whose re-read is one more replicated call; list the reads in
`invalidates` to leave it cached.

A `{ name }` (the canister written to, or one in `invalidates`) is
resolved once per run, in `onMutate`, which TanStack Query runs first
and whose result it hands to `onSettled`: a write whose `ic_env` cookie
entry changes before it settles (a local redeploy) invalidates the reads
of the canister it wrote to. To add your own `onSettled`, call this one
from it with every argument it gets; to add your own `onMutate`, call
this one from it with both and spread its result into yours:
`{ ...options.onMutate(variables, context), previous }`. An `onMutate`
that replaces this one keeps the write and its invalidation together
from TanStack Query 5.89 on, which hands `mutationFn` and `onSettled` the
same run context: `mutationFn` resolves the targets when it starts, and
`onSettled` reads them from there. Before 5.89 it leaves `mutationFn` and
`onSettled` each to resolve the targets when it runs, so a cookie
rewritten between the two can split the write from its invalidation.

#### Type Parameters

##### A

`A`

##### M

`M` *extends* `string`

#### Parameters

##### canister

[`Canister`](https://ic-reactor.b3pay.net/v4/libs/type-aliases/canister/)\<`A`\>

##### method

`M`

##### options?

`MutationOptionsOptions`

#### Returns

`CanisterMutationOptions`\<`VarsOf`\<`A`, `M`\>, `DataOf`\<`A`, `M`\>, `ErrorOf`\<`A`, `M`\>\>

#### Throws

TypeError for a canister of another client, a method a service
does not have, or a third argument other than `{ invalidates }`.

***

### func()

> **func**\<`F`\>(`funcSchema`, `ref`): `F`

Defined in: [core/src/client.ts:446](https://github.com/B3Pay/ic-reactor/blob/6b3b9f58b7868082175216ca6e3688d278d17c1f/packages/core/src/client.ts#L446)

An async function for a func reference a reply carried, such as an ICRC
ledger's archive callback:

```ts
import { QueryArchiveFn, type GetBlocksArgs, type BlockRange } from "./canisters/ledger"
for (const range of reply.archived_blocks) {
  const read = client.func<(arg: GetBlocksArgs) => Promise<BlockRange>>(QueryArchiveFn, range.callback)
  const { blocks } = await read({ start: range.start, length: range.length })
}
```

The call goes to `ref.principal` and `ref.method`, with the arguments,
results and mode of `funcSchema` (the generated schema of the func type),
through the same path as a canister's methods: the same errors, the same
caller rules, the same unwrapping. `F` is not checked against
`funcSchema`: a generated func type carries no signature, so write the
one its `.did` gives, with the `Ok` payload as the reply of a result.

#### Type Parameters

##### F

`F` *extends* (...`args`) => `Promise`\<`unknown`\>

#### Parameters

##### funcSchema

`Schema`\<`FuncValue`\>

##### ref

`FuncValue`

#### Returns

`F`

#### Throws

TypeError for a schema that is not a func schema, or a `ref`
whose principal is not principal text or whose method is not a name.