pic-js-mops
Version:
An Internet Computer Protocol canister testing library for TypeScript and JavaScript.
167 lines • 7.27 kB
JavaScript
import { Http2Client } from './http2-client.js';
import { decodeGetTopologyResponse, encodeGetStableMemoryRequest, decodeGetStableMemoryResponse, encodeSetStableMemoryRequest, encodeAddCyclesRequest, decodeAddCyclesResponse, decodeGetCyclesBalanceResponse, encodeGetCyclesBalanceRequest, encodeGetSubnetIdRequest, decodeGetSubnetIdResponse, decodeGetTimeResponse, encodeSetTimeRequest, encodeCanisterCallRequest, decodeUploadBlobResponse, encodeUploadBlobRequest, encodeCreateInstanceRequest, encodeGetPubKeyRequest, decodeCanisterCallResponse, decodeGetPendingHttpsOutcallsResponse, encodeMockPendingHttpsOutcallRequest, decodeSubmitCanisterCallResponse, encodeSubmitCanisterCallRequest, encodeIngressStatusRequest, decodeIngressStatusResponse, encodeAwaitCanisterCallRequest, decodeGetControllersResponse, encodeGetControllersRequest, } from './pocket-ic-client-types.js';
import { isNotNil } from './util/index.js';
const PROCESSING_TIME_VALUE_MS = 30_000;
const AWAIT_INGRESS_STATUS_ROUNDS = 100;
export class PocketIcClient {
serverClient;
instancePath;
isInstanceDeleted = false;
constructor(serverClient, instancePath) {
this.serverClient = serverClient;
this.instancePath = instancePath;
}
static async create(url, req) {
const processingTimeoutMs = req?.processingTimeoutMs ?? PROCESSING_TIME_VALUE_MS;
const serverClient = new Http2Client(url, processingTimeoutMs);
const res = await serverClient.jsonPost({
path: '/instances',
body: encodeCreateInstanceRequest(req),
});
if ('Error' in res) {
console.error('Error creating instance', res.Error.message);
throw new Error(res.Error.message);
}
const instanceId = res.Created.instance_id;
return new PocketIcClient(serverClient, `/instances/${instanceId}`);
}
async deleteInstance() {
this.assertInstanceNotDeleted();
await this.serverClient.request({
method: 'DELETE',
path: this.instancePath,
});
this.isInstanceDeleted = true;
}
async getControllers(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/read/get_controllers', encodeGetControllersRequest(req));
return decodeGetControllersResponse(res);
}
async tick() {
this.assertInstanceNotDeleted();
return await this.post('/update/tick', {});
}
async getPubKey(req) {
this.assertInstanceNotDeleted();
return await this.post('/read/pub_key', encodeGetPubKeyRequest(req));
}
async getTopology() {
this.assertInstanceNotDeleted();
const res = await this.get('/_/topology');
return decodeGetTopologyResponse(res);
}
async getTime() {
this.assertInstanceNotDeleted();
const res = await this.get('/read/get_time');
return decodeGetTimeResponse(res);
}
async setTime(req) {
this.assertInstanceNotDeleted();
await this.post('/update/set_time', encodeSetTimeRequest(req));
}
async setCertifiedTime(req) {
this.assertInstanceNotDeleted();
await this.post('/update/set_certified_time', encodeSetTimeRequest(req));
}
async getSubnetId(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/read/get_subnet', encodeGetSubnetIdRequest(req));
return decodeGetSubnetIdResponse(res);
}
async getCyclesBalance(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/read/get_cycles', encodeGetCyclesBalanceRequest(req));
return decodeGetCyclesBalanceResponse(res);
}
async addCycles(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/update/add_cycles', encodeAddCyclesRequest(req));
return decodeAddCyclesResponse(res);
}
async uploadBlob(req) {
this.assertInstanceNotDeleted();
const res = await this.serverClient.request({
method: 'POST',
path: '/blobstore',
body: encodeUploadBlobRequest(req),
});
const body = await res.text();
return decodeUploadBlobResponse(body);
}
async setStableMemory(req) {
this.assertInstanceNotDeleted();
await this.serverClient.jsonPost({
path: `${this.instancePath}/update/set_stable_memory`,
body: encodeSetStableMemoryRequest(req),
});
}
async getStableMemory(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/read/get_stable_memory', encodeGetStableMemoryRequest(req));
return decodeGetStableMemoryResponse(res);
}
async getPendingHttpsOutcalls() {
this.assertInstanceNotDeleted();
const res = await this.get('/read/get_canister_http');
return decodeGetPendingHttpsOutcallsResponse(res);
}
async mockPendingHttpsOutcall(req) {
this.assertInstanceNotDeleted();
await this.post('/update/mock_canister_http', encodeMockPendingHttpsOutcallRequest(req));
}
async updateCall(req) {
this.assertInstanceNotDeleted();
const res = await this.submitCall(req);
return await this.awaitCall(res);
}
async queryCall(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/read/query', encodeCanisterCallRequest(req));
return decodeCanisterCallResponse(res);
}
async submitCall(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/update/submit_ingress_message', encodeSubmitCanisterCallRequest(req));
return decodeSubmitCanisterCallResponse(res);
}
async ingressStatus(req) {
this.assertInstanceNotDeleted();
const res = await this.post('/read/ingress_status', encodeIngressStatusRequest(req));
return decodeIngressStatusResponse(res);
}
async awaitCall(req) {
this.assertInstanceNotDeleted();
const encodedReq = {
messageId: encodeAwaitCanisterCallRequest(req),
// since this is always called immediately after making a call, there is no need to check the caller
// the `ingressStatus` method is not exposed publicly, so it is safe to assume that the caller is the same as the one who made the call
caller: undefined,
};
for (let i = 0; i < AWAIT_INGRESS_STATUS_ROUNDS; i++) {
await this.tick();
const result = await this.ingressStatus(encodedReq);
if (isNotNil(result)) {
return result;
}
}
throw new Error(`PocketIC did not complete the update call within ${AWAIT_INGRESS_STATUS_ROUNDS} rounds`);
}
async post(endpoint, body) {
return await this.serverClient.jsonPost({
path: `${this.instancePath}${endpoint}`,
body,
});
}
async get(endpoint) {
return await this.serverClient.jsonGet({
path: `${this.instancePath}${endpoint}`,
});
}
assertInstanceNotDeleted() {
if (this.isInstanceDeleted) {
throw new Error('Instance was deleted');
}
}
}
//# sourceMappingURL=pocket-ic-client.js.map