Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ If you want to submit a pull request to fix an issue or add a feature, here's a
git add path-to-changed-file
```
8. Commit your changes to store the contents you added to the index along with a descriptive message by running a command similar to the following:

```shell
cz commit
```

- See [Conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for more information on the commit message formats.

9. Push the changes to the remote repository by running a command similar to the following:
```shell
git push origin my-branch-name-here
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
# Changelog

## Unreleased

### Feat

- add http gateway support (#233)
- bump PocketIC server to v12.0.0 (#231)
- transparent large WASM installation via chunked upload for `installCode`, `reinstallCode`, `upgradeCanister`, and `setupCanister`
- add `canisterStatus` method to `PocketIc` for querying canister status

### Chore

- remove unnecessary pnpm overrides

## 0.18.0 (2026-01-21)

### BREAKING CHANCE
### BREAKING CHANGE

- Reverts "introduce a new `rounds` option for `awaitCall` method on `PocketIcClient` (#223)"

Expand Down
419 changes: 76 additions & 343 deletions bun.lock

Large diffs are not rendered by default.

19 changes: 7 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,17 @@
"devDependencies": {
"@icp-sdk/bindgen": "^0.2.1",
"@icp-sdk/core": "^5.0.0",
"@swc/core": "^1.15.3",
"@swc/core": "^1.15.18",
"@swc/jest": "^0.2.39",
"@tsconfig/node24": "^24.0.3",
"@types/jest": "^29.5.14",
"@types/node": "^22.13.10",
"@tsconfig/node24": "^24.0.4",
"@types/jest": "^30.0.0",
"@types/node": "^25.3.3",
"bip39": "^3.1.0",
"jest": "^30.2.0",
"npm-run-all": "^4.1.5",
"prettier": "3.4.1",
"prettier": "3.8.1",
"ts-node": "^10.9.2",
"typescript": "^5.8.2",
"vitest": "^4.0.15"
},
"overrides": {
"path-to-regexp@<0.1.12": ">=0.1.12",
"path-to-regexp@>=2.0.0 <3.3.0": ">=3.3.0",
"esbuild@<=0.24.2": ">=0.25.0"
"typescript": "^5.9.3",
"vitest": "^4.0.18"
}
}
163 changes: 163 additions & 0 deletions packages/pic/src/management-canister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,166 @@ export function encodeUpdateCanisterSettingsRequest(
): Uint8Array {
return new Uint8Array(IDL.encode([UpdateCanisterSettingsRequest], [arg]));
}

// Canister status types

const CanisterStatusRequest = IDL.Record({
canister_id: IDL.Principal,
});

export interface CanisterStatusRequest {
canister_id: Principal;
}

export function encodeCanisterStatusRequest(
arg: CanisterStatusRequest,
): Uint8Array {
return new Uint8Array(IDL.encode([CanisterStatusRequest], [arg]));
}

const DefiniteCanisterSettings = IDL.Record({
controllers: IDL.Vec(IDL.Principal),
compute_allocation: IDL.Nat,
memory_allocation: IDL.Nat,
freezing_threshold: IDL.Nat,
reserved_cycles_limit: IDL.Nat,
});

export interface DefiniteCanisterSettings {
controllers: Principal[];
compute_allocation: bigint;
memory_allocation: bigint;
freezing_threshold: bigint;
reserved_cycles_limit: bigint;
}

const QueryStats = IDL.Record({
num_calls_total: IDL.Nat,
num_instructions_total: IDL.Nat,
request_payload_bytes_total: IDL.Nat,
response_payload_bytes_total: IDL.Nat,
});

export interface QueryStats {
num_calls_total: bigint;
num_instructions_total: bigint;
request_payload_bytes_total: bigint;
response_payload_bytes_total: bigint;
}

const CanisterStatusResponse = IDL.Record({
status: IDL.Variant({
running: IDL.Null,
stopping: IDL.Null,
stopped: IDL.Null,
}),
settings: DefiniteCanisterSettings,
module_hash: IDL.Opt(IDL.Vec(IDL.Nat8)),
memory_size: IDL.Nat,
cycles: IDL.Nat,
reserved_cycles: IDL.Nat,
idle_cycles_burned_per_day: IDL.Nat,
query_stats: QueryStats,
});

export interface CanisterStatusResponse {
status: { running: null } | { stopping: null } | { stopped: null };
settings: DefiniteCanisterSettings;
module_hash: [] | [Uint8Array];
memory_size: bigint;
cycles: bigint;
reserved_cycles: bigint;
idle_cycles_burned_per_day: bigint;
query_stats: QueryStats;
}

export function decodeCanisterStatusResponse(
arg: Uint8Array,
): CanisterStatusResponse {
const payload = decodeCandid<CanisterStatusResponse>(
[CanisterStatusResponse],
arg,
);

if (isNil(payload)) {
throw new Error('Failed to decode CanisterStatusResponse');
}

return payload;
}

// Chunked code installation types

const ClearChunkStoreRequest = IDL.Record({
canister_id: IDL.Principal,
});

export interface ClearChunkStoreRequest {
canister_id: Principal;
}

export function encodeClearChunkStoreRequest(
arg: ClearChunkStoreRequest,
): Uint8Array {
return new Uint8Array(IDL.encode([ClearChunkStoreRequest], [arg]));
}

const UploadChunkRequest = IDL.Record({
canister_id: IDL.Principal,
chunk: IDL.Vec(IDL.Nat8),
});

export interface UploadChunkRequest {
canister_id: Principal;
chunk: Uint8Array;
}

export function encodeUploadChunkRequest(arg: UploadChunkRequest): Uint8Array {
return new Uint8Array(IDL.encode([UploadChunkRequest], [arg]));
}

const ChunkHash = IDL.Record({
hash: IDL.Vec(IDL.Nat8),
});

export interface ChunkHash {
hash: Uint8Array;
}

const UploadChunkResponse = ChunkHash;

export function decodeUploadChunkResponse(arg: Uint8Array): ChunkHash {
const payload = decodeCandid<ChunkHash>([UploadChunkResponse], arg);

if (isNil(payload)) {
throw new Error('Failed to decode UploadChunkResponse');
}

return payload;
}

const InstallChunkedCodeRequest = IDL.Record({
mode: CanisterInstallMode,
target_canister: IDL.Principal,
store_canister: IDL.Opt(IDL.Principal),
chunk_hashes_list: IDL.Vec(ChunkHash),
wasm_module_hash: IDL.Vec(IDL.Nat8),
arg: IDL.Vec(IDL.Nat8),
sender_canister_version: IDL.Opt(IDL.Nat64),
});

export interface InstallChunkedCodeRequest {
mode: CanisterInstallMode;
target_canister: Principal;
store_canister: [] | [Principal];
chunk_hashes_list: ChunkHash[];
wasm_module_hash: Uint8Array;
arg: Uint8Array;
sender_canister_version: [] | [bigint];
}

export function encodeInstallChunkedCodeRequest(
arg: InstallChunkedCodeRequest,
): Uint8Array {
return new Uint8Array(IDL.encode([InstallChunkedCodeRequest], [arg]));
}
99 changes: 97 additions & 2 deletions packages/pic/src/pocket-ic-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -685,8 +685,7 @@ export interface UpgradeCanisterOptions {
* @category Types
* @see [Principal](https://js.icp.build/core/latest/libs/principal/api/classes/principal/)
*/
export interface UpdateCanisterSettingsOptions
extends Partial<CanisterSettings> {
export interface UpdateCanisterSettingsOptions extends Partial<CanisterSettings> {
/**
* The Principal of the canister to update the settings for.
*/
Expand All @@ -699,6 +698,102 @@ export interface UpdateCanisterSettingsOptions
sender?: Principal;
}

/**
* Options for querying the status of a given canister.
*
* @category Types
* @see [Principal](https://js.icp.build/core/latest/libs/principal/api/classes/principal/)
*/
export interface CanisterStatusOptions {
/**
* The Principal of the canister to query the status of.
*/
canisterId: Principal;

/**
* The Principal to send the request as.
* Defaults to the anonymous principal.
*/
sender?: Principal;
}

/**
* The status of a canister.
*
* @category Types
*/
export type CanisterStatus =
| { running: null }
| { stopping: null }
| { stopped: null };

/**
* Query statistics for a canister.
*
* @category Types
*/
export interface CanisterQueryStats {
numCallsTotal: bigint;
numInstructionsTotal: bigint;
requestPayloadBytesTotal: bigint;
responsePayloadBytesTotal: bigint;
}

/**
* The result of querying the status of a canister.
* Matches the IC management canister `canister_status` response.
*
* @category Types
* @see [Principal](https://js.icp.build/core/latest/libs/principal/api/classes/principal/)
*/
export interface CanisterStatusResult {
/**
* The current status of the canister.
*/
status: CanisterStatus;

/**
* The definite settings of the canister.
*/
settings: {
controllers: Principal[];
computeAllocation: bigint;
memoryAllocation: bigint;
freezingThreshold: bigint;
reservedCyclesLimit: bigint;
};

/**
* The SHA-256 hash of the installed WASM module, if any.
*/
moduleHash: Uint8Array | null;

/**
* The total memory size of the canister in bytes.
*/
memorySize: bigint;

/**
* The current cycle balance of the canister.
*/
cycles: bigint;

/**
* The reserved cycles of the canister.
*/
reservedCycles: bigint;

/**
* The amount of cycles burned per day when idle.
*/
idleCyclesBurnedPerDay: bigint;

/**
* Query call statistics for the canister.
*/
queryStats: CanisterQueryStats;
}

//#endregion CanisterLifecycle

//#region CanisterCall
Expand Down
Loading