Client
Defined in: core/src/client.ts:181
A client made by createClient: one per browser tab, or one per request on a server, so that no cache or agent is shared between users.
Properties
Section titled “Properties”network
Section titled “network”
readonlynetwork:string
Defined in: core/src/client.ts:183
The network’s segment in query keys: "ic", "local", a custom network’s name ?? host, or the resolved host for "env".
queryClient
Section titled “queryClient”
readonlyqueryClient:QueryClient
Defined in: core/src/client.ts:191
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
Section titled “Methods”caller()
Section titled “caller()”caller():
string
Defined in: core/src/client.ts:193
The principal calls go out as now, as text: the anonymous principal unless signed in.
Returns
Section titled “Returns”string
authState()
Section titled “authState()”authState():
AuthState
Defined in: core/src/client.ts:198
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
Section titled “Returns”subscribe()
Section titled “subscribe()”subscribe(
listener): () =>void
Defined in: core/src/client.ts:205
Calls listener once after each change of Client.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
Section titled “Parameters”listener
Section titled “listener”() => void
Returns
Section titled “Returns”() => void
signIn()
Section titled “signIn()”signIn(
options?):Promise<void>
Defined in: core/src/client.ts:212
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.
Parameters
Section titled “Parameters”options?
Section titled “options?”unknown
Returns
Section titled “Returns”Promise<void>
signOut()
Section titled “signOut()”signOut(
options?):Promise<void>
Defined in: core/src/client.ts:217
Signs out through the client’s auth, passing options on (such as
AuthClient’s { returnTo }). Rejects like Client.signIn.
Parameters
Section titled “Parameters”options?
Section titled “options?”unknown
Returns
Section titled “Returns”Promise<void>
dispose()
Section titled “dispose()”dispose():
void
Defined in: core/src/client.ts:231
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
Section titled “Returns”void
canister()
Section titled “canister()”canister<
A>(service,target):Canister<A>
Defined in: core/src/client.ts:264
A canister to call: a frozen object with one plain async method per
Candid method of service, typed from the generated Actor you name.
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 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 for { id }, { name } and certified.
Type Parameters
Section titled “Type Parameters”A
Parameters
Section titled “Parameters”service
Section titled “service”Schema<Principal>
target
Section titled “target”Returns
Section titled “Returns”Canister<A>
Throws
Section titled “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()
Section titled “queryKey()”queryKey<
A,M>(canister,method?,vars?): readonlyunknown[]
Defined in: core/src/client.ts:292
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 asqueryKey(c, method, undefined), soqueryClient.getQueryData(client.queryKey(ledger, "icrc1_fee"))finds whatqueryOptions(ledger, "icrc1_fee")cached.queryKey(c, method, vars): the keyqueryOptions(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
Section titled “Type Parameters”A
M extends string
Parameters
Section titled “Parameters”canister
Section titled “canister”Canister<A>
method?
Section titled “method?”M
VarsOf<A, M>
Returns
Section titled “Returns”readonly unknown[]
Throws
Section titled “Throws”TypeError for a canister of another client, or a method the service does not have.
queryOptions()
Section titled “queryOptions()”Call Signature
Section titled “Call Signature”queryOptions<
A,M>(canister,method, …args):CanisterQueryOptions<DataOf<A,M>,ErrorOf<A,M>,never>
Defined in: core/src/client.ts:354
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 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 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
Section titled “Type Parameters”A
M extends string
Parameters
Section titled “Parameters”canister
Section titled “canister”Canister<A>
method
Section titled “method”M
…QueryArgs<A, M, never>
Returns
Section titled “Returns”CanisterQueryOptions<DataOf<A, M>, ErrorOf<A, M>, never>
Throws
Section titled “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
Section titled “Call Signature”queryOptions<
A,M>(canister,method, …args):CanisterQueryOptions<DataOf<A,M>,ErrorOf<A,M>>
Defined in: core/src/client.ts:368
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
Section titled “Type Parameters”A
M extends string
Parameters
Section titled “Parameters”canister
Section titled “canister”Canister<A>
method
Section titled “method”M
…QueryArgs<A, M>
Returns
Section titled “Returns”CanisterQueryOptions<DataOf<A, M>, ErrorOf<A, M>>
Throws
Section titled “Throws”TypeError as the call with variables that cannot be skipped.
mutationOptions()
Section titled “mutationOptions()”mutationOptions<
A,M>(canister,method,options?):CanisterMutationOptions<VarsOf<A,M>,DataOf<A,M>,ErrorOf<A,M>>
Defined in: core/src/client.ts:418
TanStack Query options for a write: useMutation(client.mutationOptions( ledger, "icrc1_transfer")), then mutate(arg) with the same argument
convention as Client.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), 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
Section titled “Type Parameters”A
M extends string
Parameters
Section titled “Parameters”canister
Section titled “canister”Canister<A>
method
Section titled “method”M
options?
Section titled “options?”MutationOptionsOptions
Returns
Section titled “Returns”CanisterMutationOptions<VarsOf<A, M>, DataOf<A, M>, ErrorOf<A, M>>
Throws
Section titled “Throws”TypeError for a canister of another client, a method a service
does not have, or a third argument other than { invalidates }.
func()
Section titled “func()”func<
F>(funcSchema,ref):F
Defined in: core/src/client.ts:446
An async function for a func reference a reply carried, such as an ICRC ledger’s archive callback:
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
Section titled “Type Parameters”F extends (…args) => Promise<unknown>
Parameters
Section titled “Parameters”funcSchema
Section titled “funcSchema”Schema<FuncValue>
FuncValue
Returns
Section titled “Returns”F
Throws
Section titled “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.