This release marks a major update to the ICP JavaScript SDK, introducing several breaking changes, new features, and improvements. This guide is intended to help developers upgrade their projects to the latest version. Among the key improvements, this release eliminates Buffer and similar dependencies, significantly reducing bundle size and improving performance across all packages.
The behavior of the shouldFetchRootKey flag has been changed. If you were using the HttpAgent constructor with the shouldFetchRootKey flag, you will need to update your code to use the rootKey option instead.
Before:
// When constructing the agent synchronously, the root key was fetched automatically in the background,
// causing potential race conditions
const agent = HttpAgent.createSync({ shouldFetchRootKey: true }); // or, even if deprecated, new HttpAgent({ shouldFetchRootKey: true })
agent.call(...); // we don't know if the root key was fetched or not at this point
// When constructing the agent asynchronously, the root key was fetched directly
The agent-js’ implementation of the management canister actor was a duplicate of the one in the @dfinity/ic-management package. It has been removed and you will need to update your code to use this package instead.
Note: The @dfinity/ic-management package may still depend on the v2 of the ICP JavaScript SDK, which could cause issues depending on your project’s dependencies.
Internally, we have replaced the usage of ArrayBuffer with Uint8Array.
Specifically, all @dfinity/candid interfaces that previously accepted or returned ArrayBuffer now use Uint8Array. You will need to update your code to handle Uint8Array instead of ArrayBuffer.
The fromHex, toHex, and concat utility functions have been removed. Use the bytesToHex, hexToBytes, and concatBytes functions from @noble/hashes/utils instead.
The Expiry class has been refactored to use static factory methods and no longer exposes a public constructor. It also now supports JSON serialization/deserialization.
The lookup_path standalone function has been renamed to lookup_subtree.
The lookup method of the Certificate class has been renamed into lookup_subtree, and uses the lookup_subtree standalone function internally.
A new lookup_path has been introduced both as a standalone function and as a method of the Certificate class. Its behavior is now aligned with the IC Interface Specification.
The lookup_label method has been removed from the Certificate class. Use Certificate.lookup_subtree or Certificate.lookup_path instead, according to your use case.
The @dfinity/agent package now uses @dfinity/cbor instead of the borc and simple-cbor dependencies, reducing the bundle size of most packages by at least 30% (gzipped) 🤯.
Before:
import { Cbor } from'@dfinity/agent';
const encoded:ArrayBuffer = Cbor.encode(myValue);
const decoded:MyType = Cbor.decode(encoded);
After:
import { Cbor } from'@dfinity/agent';
const encoded:Uint8Array = Cbor.encode(myValue); // now returns Uint8Array
const decoded = Cbor.decode<MyType>(encoded); // now accepts Uint8Array
Support for Node.js v19 and lower, and Node.js v21 has been dropped. Please ensure you are using a supported version of Node.js (LTS versions like 20 or 22 are recommended).
Improved Polling Strategy: The polling strategy for read_state requests has been changed to support presigned requests. A new preSignReadStateRequest option allows for a single signature to be used for all polling requests, which is beneficial for hardware wallets.
New documentation website: The documentation website available at agent-js.icp.xyz has been renewed. It is now build using the Starlight framework.
If an API call to the IC network fails due to an ingress expiry error, the HttpAgent will now automatically adjust the ingress expiry time based on the latest subnet’s certified time. You can also sync time before an error occurs by using the shouldSyncTime option.
Example:
const agent = await HttpAgent.create({
shouldSyncTime: true,
});
Note: The shouldSyncTime flag behavior follows the same logic as the new shouldFetchRootKey flag behavior. For this reason, depending on your use case, you may prefer to defer the time sync until the first request is made by constructing the agent synchronously:
// When constructing the agent synchronously, the time is not synced until the first request is made
const agent = HttpAgent.createSync({
shouldSyncTime: true,
// shouldFetchRootKey: true, // even more relevant if you want to sync the root key as well
});
agent.call(...); // the time is synced at this point, before the call is made
// When constructing the agent asynchronously, the time is synced when the agent is created
const agent = await HttpAgent.create({
shouldSyncTime: true,
// shouldFetchRootKey: true, // if both flags are enabled, the agent creation will take longer
});
agent.call(...); // the time is already synced at this point
The agent no longer checks for watermarks on query responses. This removes a lot of watermark errors that projects were frequently facing when interacting with the IC mainnet.
The HttpAgent now checks if the node signature is not older than the ingressExpiryInMinutes option, to prevent stale query responses. This takes into account clock drift, if enabled.
Dependency Updates: @noble/* dependencies have been updated. Old unused dependencies have been removed.
@noble/hashes Dependency: @noble/hashes is now correctly marked as a dependency.
Candid Subtyping: Subtyping relationships are now checked when decoding function or service references, improving compliance with the Candid spec and reducing the risk of calling services with incorrect argument types.
Request Retries: Requests that fail due to a malformed response body will now be retried.
isAuthenticated Fix: AuthClient.isAuthenticated now correctly returns false if the delegation chain is invalid (e.g., due to an expired session).
Large BigInt values encoding in Candid: A bug in the Candid’s leb128 encoding of large BigInt values has been fixed, solving the issue of the encoding breaking when encountering large BigInt values.