ic-mops 0.36.1 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/moc-wrapper.sh +3 -0
- package/bin/mops.ts +3 -0
- package/cache.ts +2 -2
- package/cli.ts +61 -4
- package/commands/add.ts +3 -1
- package/commands/bench-replica.ts +5 -3
- package/commands/docs.ts +9 -6
- package/commands/install-all.ts +7 -2
- package/commands/install.ts +5 -1
- package/commands/publish.ts +2 -0
- package/commands/test/test.ts +42 -19
- package/commands/toolchain/index.ts +325 -0
- package/commands/toolchain/moc.ts +58 -0
- package/commands/toolchain/pocket-ic.ts +74 -0
- package/commands/toolchain/toolchain-utils.ts +83 -0
- package/commands/toolchain/wasmtime.ts +45 -0
- package/dist/bin/mops.d.ts +1 -1
- package/dist/cache.js +2 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +52 -3
- package/dist/commands/add.js +2 -1
- package/dist/commands/bench-replica.d.ts +1 -1
- package/dist/commands/bench-replica.js +5 -3
- package/dist/commands/docs.js +9 -6
- package/dist/commands/install-all.js +5 -2
- package/dist/commands/install.js +5 -1
- package/dist/commands/publish.js +1 -0
- package/dist/commands/test/test.js +41 -19
- package/dist/commands/toolchain/index.d.ts +26 -0
- package/dist/commands/toolchain/index.js +274 -0
- package/dist/commands/toolchain/moc.d.ts +5 -1
- package/dist/commands/toolchain/moc.js +18 -6
- package/dist/commands/toolchain/mocv.js +0 -1
- package/dist/commands/toolchain/pocket-ic.d.ts +12 -0
- package/dist/commands/toolchain/pocket-ic.js +62 -0
- package/dist/commands/toolchain/toolchain-utils.d.ts +2 -2
- package/dist/commands/toolchain/toolchain-utils.js +22 -6
- package/dist/commands/toolchain/wasmtime.d.ts +5 -1
- package/dist/commands/toolchain/wasmtime.js +16 -4
- package/dist/integrity.js +40 -15
- package/dist/mops.js +2 -2
- package/dist/package.json +9 -4
- package/dist/pic-js/examples/clock/tests/clock/index.d.ts +1 -0
- package/dist/pic-js/examples/clock/tests/clock/index.js +5 -0
- package/dist/pic-js/examples/clock/tests/jest.config.d.ts +3 -0
- package/dist/pic-js/examples/clock/tests/jest.config.js +8 -0
- package/dist/pic-js/examples/clock/tests/src/clock.spec.d.ts +1 -0
- package/dist/pic-js/examples/clock/tests/src/clock.spec.js +48 -0
- package/dist/pic-js/examples/counter/tests/counter/index.d.ts +1 -0
- package/dist/pic-js/examples/counter/tests/counter/index.js +5 -0
- package/dist/pic-js/examples/counter/tests/jest.config.d.ts +3 -0
- package/dist/pic-js/examples/counter/tests/jest.config.js +8 -0
- package/dist/pic-js/examples/counter/tests/src/counter.spec.d.ts +1 -0
- package/dist/pic-js/examples/counter/tests/src/counter.spec.js +80 -0
- package/dist/pic-js/examples/todo/tests/jest.config.d.ts +3 -0
- package/dist/pic-js/examples/todo/tests/jest.config.js +8 -0
- package/dist/pic-js/examples/todo/tests/src/todo.spec.d.ts +1 -0
- package/dist/pic-js/examples/todo/tests/src/todo.spec.js +211 -0
- package/dist/pic-js/examples/todo/tests/todo/index.d.ts +1 -0
- package/dist/pic-js/examples/todo/tests/todo/index.js +5 -0
- package/dist/pic-js/packages/pic/src/error.d.ts +12 -0
- package/dist/pic-js/packages/pic/src/error.js +36 -0
- package/dist/pic-js/packages/pic/src/http-client.d.ts +15 -0
- package/dist/pic-js/packages/pic/src/http-client.js +37 -0
- package/dist/pic-js/packages/pic/src/identity.d.ts +66 -0
- package/dist/pic-js/packages/pic/src/identity.js +86 -0
- package/dist/pic-js/packages/pic/src/index.d.ts +4 -0
- package/dist/pic-js/packages/pic/src/index.js +8 -0
- package/dist/pic-js/packages/pic/src/management-canister.d.ts +30 -0
- package/dist/pic-js/packages/pic/src/management-canister.js +43 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-actor.d.ts +83 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-actor.js +58 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-client-types.d.ts +61 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-client-types.js +2 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-client.d.ts +24 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-client.js +123 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-server.d.ts +10 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-server.js +55 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-types.d.ts +40 -0
- package/dist/pic-js/packages/pic/src/pocket-ic-types.js +2 -0
- package/dist/pic-js/packages/pic/src/pocket-ic.d.ts +447 -0
- package/dist/pic-js/packages/pic/src/pocket-ic.js +551 -0
- package/dist/pic-js/packages/pic/src/util/candid.d.ts +1 -0
- package/dist/pic-js/packages/pic/src/util/candid.js +7 -0
- package/dist/pic-js/packages/pic/src/util/encoding.d.ts +5 -0
- package/dist/pic-js/packages/pic/src/util/encoding.js +19 -0
- package/dist/pic-js/packages/pic/src/util/fs.d.ts +4 -0
- package/dist/pic-js/packages/pic/src/util/fs.js +29 -0
- package/dist/pic-js/packages/pic/src/util/index.d.ts +5 -0
- package/dist/pic-js/packages/pic/src/util/index.js +21 -0
- package/dist/pic-js/packages/pic/src/util/os.d.ts +4 -0
- package/dist/pic-js/packages/pic/src/util/os.js +19 -0
- package/dist/pic-js/packages/pic/src/util/poll.d.ts +5 -0
- package/dist/pic-js/packages/pic/src/util/poll.js +28 -0
- package/dist/templates/mops-test.yml +4 -4
- package/dist/types.d.ts +7 -0
- package/dist/vessel.js +5 -1
- package/global.d.ts +2 -1
- package/integrity.ts +57 -17
- package/mops.ts +3 -3
- package/package.json +9 -4
- package/templates/mops-test.yml +4 -4
- package/types.ts +10 -1
- package/vessel.ts +6 -1
- package/bun.lockb +0 -0
- package/cli-local.ts +0 -3
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_path_1 = require("node:path");
|
|
4
|
+
const agent_1 = require("@dfinity/agent");
|
|
5
|
+
const pic_1 = require("@hadronous/pic");
|
|
6
|
+
const todo_1 = require("../todo");
|
|
7
|
+
const WASM_PATH = (0, node_path_1.resolve)(__dirname, '..', '..', '..', '..', '.dfx', 'local', 'canisters', 'todo', 'todo.wasm');
|
|
8
|
+
describe('Todo', () => {
|
|
9
|
+
let pic;
|
|
10
|
+
let actor;
|
|
11
|
+
let canisterId;
|
|
12
|
+
const alice = (0, pic_1.createIdentity)('superSecretAlicePassword');
|
|
13
|
+
const bob = (0, pic_1.createIdentity)('superSecretBobPassword');
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
pic = await pic_1.PocketIc.create();
|
|
16
|
+
const fixture = await pic.setupCanister(todo_1.idlFactory, WASM_PATH);
|
|
17
|
+
actor = fixture.actor;
|
|
18
|
+
canisterId = fixture.canisterId;
|
|
19
|
+
});
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await pic.tearDown();
|
|
22
|
+
});
|
|
23
|
+
describe('with an anonymous user', () => {
|
|
24
|
+
const identity = new agent_1.AnonymousIdentity();
|
|
25
|
+
const expectedError = 'Anonymous principals are not allowed to call this method';
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
actor.setIdentity(identity);
|
|
28
|
+
});
|
|
29
|
+
it('should prevent creating a todo', async () => {
|
|
30
|
+
await expect(actor.create_todo({
|
|
31
|
+
text: 'Learn Rust',
|
|
32
|
+
})).rejects.toThrow(expectedError);
|
|
33
|
+
});
|
|
34
|
+
it('should prevent getting todos', async () => {
|
|
35
|
+
await expect(actor.get_todos()).rejects.toThrow(expectedError);
|
|
36
|
+
});
|
|
37
|
+
it('should prevent updating a todo', async () => {
|
|
38
|
+
await expect(actor.update_todo(1n, {
|
|
39
|
+
text: ['Learn Rust'],
|
|
40
|
+
done: [],
|
|
41
|
+
})).rejects.toThrow(expectedError);
|
|
42
|
+
});
|
|
43
|
+
it('should prevent deleting a todo', async () => {
|
|
44
|
+
await expect(actor.delete_todo(1n)).rejects.toThrow(expectedError);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('with alice', () => {
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
actor.setIdentity(alice);
|
|
50
|
+
});
|
|
51
|
+
it('should allow creating a todo', async () => {
|
|
52
|
+
const initialGetResponse = await actor.get_todos();
|
|
53
|
+
const createResponse = await actor.create_todo({ text: 'Learn Rust' });
|
|
54
|
+
const getResponse = await actor.get_todos();
|
|
55
|
+
expect(initialGetResponse.todos).toHaveLength(0);
|
|
56
|
+
expect(getResponse.todos).toHaveLength(1);
|
|
57
|
+
expect(getResponse.todos).toContainEqual({
|
|
58
|
+
id: createResponse.id,
|
|
59
|
+
text: 'Learn Rust',
|
|
60
|
+
done: false,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('should allow updating a todo', async () => {
|
|
64
|
+
const initialGetResponse = await actor.get_todos();
|
|
65
|
+
const createResponse = await actor.create_todo({
|
|
66
|
+
text: 'Learn Rust',
|
|
67
|
+
});
|
|
68
|
+
const afterCreateGetResponse = await actor.get_todos();
|
|
69
|
+
await actor.update_todo(createResponse.id, {
|
|
70
|
+
text: ['Learn Rust and WebAssembly'],
|
|
71
|
+
done: [],
|
|
72
|
+
});
|
|
73
|
+
const afterUpdateGetResponse = await actor.get_todos();
|
|
74
|
+
expect(initialGetResponse.todos).toHaveLength(0);
|
|
75
|
+
expect(afterCreateGetResponse.todos).toHaveLength(1);
|
|
76
|
+
expect(afterCreateGetResponse.todos).toContainEqual({
|
|
77
|
+
id: createResponse.id,
|
|
78
|
+
text: 'Learn Rust',
|
|
79
|
+
done: false,
|
|
80
|
+
});
|
|
81
|
+
expect(afterUpdateGetResponse.todos).toHaveLength(1);
|
|
82
|
+
expect(afterUpdateGetResponse.todos).toContainEqual({
|
|
83
|
+
id: createResponse.id,
|
|
84
|
+
text: 'Learn Rust and WebAssembly',
|
|
85
|
+
done: false,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it('should allow deleting a todo', async () => {
|
|
89
|
+
const initialGetResponse = await actor.get_todos();
|
|
90
|
+
const createResponse = await actor.create_todo({
|
|
91
|
+
text: 'Learn Rust',
|
|
92
|
+
});
|
|
93
|
+
const afterCreateGetResponse = await actor.get_todos();
|
|
94
|
+
await actor.delete_todo(createResponse.id);
|
|
95
|
+
const afterDeleteGetResponse = await actor.get_todos();
|
|
96
|
+
expect(initialGetResponse.todos).toHaveLength(0);
|
|
97
|
+
expect(afterCreateGetResponse.todos).toHaveLength(1);
|
|
98
|
+
expect(afterCreateGetResponse.todos).toContainEqual({
|
|
99
|
+
id: createResponse.id,
|
|
100
|
+
text: 'Learn Rust',
|
|
101
|
+
done: false,
|
|
102
|
+
});
|
|
103
|
+
expect(afterDeleteGetResponse.todos).toHaveLength(0);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('with alice and bob', () => {
|
|
107
|
+
it("should return alice's todos to alice and bob's todos to bob", async () => {
|
|
108
|
+
actor.setIdentity(alice);
|
|
109
|
+
const aliceCreateResponse = await actor.create_todo({
|
|
110
|
+
text: 'Learn Rust',
|
|
111
|
+
});
|
|
112
|
+
const aliceAfterCreateGetResponse = await actor.get_todos();
|
|
113
|
+
actor.setIdentity(bob);
|
|
114
|
+
const bobCreateResponse = await actor.create_todo({
|
|
115
|
+
text: 'Learn WebAssembly',
|
|
116
|
+
});
|
|
117
|
+
const bobAfterCreateGetResponse = await actor.get_todos();
|
|
118
|
+
expect(aliceAfterCreateGetResponse.todos).toHaveLength(1);
|
|
119
|
+
expect(aliceAfterCreateGetResponse.todos).toContainEqual({
|
|
120
|
+
id: aliceCreateResponse.id,
|
|
121
|
+
text: 'Learn Rust',
|
|
122
|
+
done: false,
|
|
123
|
+
});
|
|
124
|
+
expect(bobAfterCreateGetResponse.todos).toHaveLength(1);
|
|
125
|
+
expect(bobAfterCreateGetResponse.todos).toContainEqual({
|
|
126
|
+
id: bobCreateResponse.id,
|
|
127
|
+
text: 'Learn WebAssembly',
|
|
128
|
+
done: false,
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
it("should prevent bob from updating alice's todo", async () => {
|
|
132
|
+
actor.setIdentity(alice);
|
|
133
|
+
const aliceCreateResponse = await actor.create_todo({
|
|
134
|
+
text: 'Learn Rust',
|
|
135
|
+
});
|
|
136
|
+
actor.setIdentity(bob);
|
|
137
|
+
await expect(actor.update_todo(aliceCreateResponse.id, {
|
|
138
|
+
text: ['Learn Rust and WebAssembly'],
|
|
139
|
+
done: [],
|
|
140
|
+
})).rejects.toThrow(`Caller with principal ${bob
|
|
141
|
+
.getPrincipal()
|
|
142
|
+
.toText()} does not own todo with id ${aliceCreateResponse.id}`);
|
|
143
|
+
});
|
|
144
|
+
it('should prevent bob from deleting alices todo', async () => {
|
|
145
|
+
actor.setIdentity(alice);
|
|
146
|
+
const aliceCreateResponse = await actor.create_todo({
|
|
147
|
+
text: 'Learn Rust',
|
|
148
|
+
});
|
|
149
|
+
actor.setIdentity(bob);
|
|
150
|
+
await expect(actor.delete_todo(aliceCreateResponse.id)).rejects.toThrow(`Caller with principal ${bob
|
|
151
|
+
.getPrincipal()
|
|
152
|
+
.toText()} does not own todo with id ${aliceCreateResponse.id}`);
|
|
153
|
+
});
|
|
154
|
+
it('should survive an upgrade', async () => {
|
|
155
|
+
actor.setIdentity(alice);
|
|
156
|
+
const aliceCreateResponse = await actor.create_todo({
|
|
157
|
+
text: 'Learn Rust',
|
|
158
|
+
});
|
|
159
|
+
actor.setIdentity(bob);
|
|
160
|
+
const bobCreateResponse = await actor.create_todo({
|
|
161
|
+
text: 'Learn WebAssembly',
|
|
162
|
+
});
|
|
163
|
+
await pic.upgradeCanister(canisterId, WASM_PATH);
|
|
164
|
+
actor.setIdentity(alice);
|
|
165
|
+
const aliceAfterUpgradeGetResponse = await actor.get_todos();
|
|
166
|
+
actor.setIdentity(bob);
|
|
167
|
+
const bobAfterUpgradeGetResponse = await actor.get_todos();
|
|
168
|
+
expect(aliceAfterUpgradeGetResponse.todos).toHaveLength(1);
|
|
169
|
+
expect(aliceAfterUpgradeGetResponse.todos).toContainEqual({
|
|
170
|
+
id: aliceCreateResponse.id,
|
|
171
|
+
text: 'Learn Rust',
|
|
172
|
+
done: false,
|
|
173
|
+
});
|
|
174
|
+
expect(bobAfterUpgradeGetResponse.todos).toHaveLength(1);
|
|
175
|
+
expect(bobAfterUpgradeGetResponse.todos).toContainEqual({
|
|
176
|
+
id: bobCreateResponse.id,
|
|
177
|
+
text: 'Learn WebAssembly',
|
|
178
|
+
done: false,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
it('should survive a reset and stable memory restore', async () => {
|
|
182
|
+
actor.setIdentity(alice);
|
|
183
|
+
const aliceCreateResponse = await actor.create_todo({
|
|
184
|
+
text: 'Learn Rust',
|
|
185
|
+
});
|
|
186
|
+
actor.setIdentity(bob);
|
|
187
|
+
const bobCreateResponse = await actor.create_todo({
|
|
188
|
+
text: 'Learn WebAssembly',
|
|
189
|
+
});
|
|
190
|
+
const stableMemory = await pic.getStableMemory(canisterId);
|
|
191
|
+
await pic.reinstallCode(canisterId, WASM_PATH);
|
|
192
|
+
await pic.setStableMemory(canisterId, stableMemory);
|
|
193
|
+
actor.setIdentity(alice);
|
|
194
|
+
const aliceAfterUpgradeGetResponse = await actor.get_todos();
|
|
195
|
+
actor.setIdentity(bob);
|
|
196
|
+
const bobAfterUpgradeGetResponse = await actor.get_todos();
|
|
197
|
+
expect(aliceAfterUpgradeGetResponse.todos).toHaveLength(1);
|
|
198
|
+
expect(aliceAfterUpgradeGetResponse.todos).toContainEqual({
|
|
199
|
+
id: aliceCreateResponse.id,
|
|
200
|
+
text: 'Learn Rust',
|
|
201
|
+
done: false,
|
|
202
|
+
});
|
|
203
|
+
expect(bobAfterUpgradeGetResponse.todos).toHaveLength(1);
|
|
204
|
+
expect(bobAfterUpgradeGetResponse.todos).toContainEqual({
|
|
205
|
+
id: bobCreateResponse.id,
|
|
206
|
+
text: 'Learn WebAssembly',
|
|
207
|
+
done: false,
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.idlFactory = void 0;
|
|
4
|
+
var todo_did_1 = require("../../declarations/todo.did");
|
|
5
|
+
Object.defineProperty(exports, "idlFactory", { enumerable: true, get: function () { return todo_did_1.idlFactory; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class BinStartError extends Error {
|
|
2
|
+
constructor(cause: Error);
|
|
3
|
+
}
|
|
4
|
+
export declare class BinStartMacOSArmError extends Error {
|
|
5
|
+
constructor(cause: Error);
|
|
6
|
+
}
|
|
7
|
+
export declare class BinNotFoundError extends Error {
|
|
8
|
+
constructor(picBinPath: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class BinTimeoutError extends Error {
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BinTimeoutError = exports.BinNotFoundError = exports.BinStartMacOSArmError = exports.BinStartError = void 0;
|
|
4
|
+
class BinStartError extends Error {
|
|
5
|
+
constructor(cause) {
|
|
6
|
+
super(`There was an error starting the PocketIC Binary.
|
|
7
|
+
|
|
8
|
+
Original error: ${cause.name} ${cause.message}.
|
|
9
|
+
${cause.stack}`, { cause });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.BinStartError = BinStartError;
|
|
13
|
+
class BinStartMacOSArmError extends Error {
|
|
14
|
+
constructor(cause) {
|
|
15
|
+
super(`There was an error starting the PocketIC Binary.
|
|
16
|
+
|
|
17
|
+
It seems you are running on an Apple Silicon Mac. The PocketIC binary can not run with the ARM architecture on Apple Silicon Macs.
|
|
18
|
+
Please install and enable Rosetta if it is not enabled and try again.
|
|
19
|
+
|
|
20
|
+
Original error: ${cause.name} ${cause.message}.
|
|
21
|
+
${cause.stack}`, { cause });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.BinStartMacOSArmError = BinStartMacOSArmError;
|
|
25
|
+
class BinNotFoundError extends Error {
|
|
26
|
+
constructor(picBinPath) {
|
|
27
|
+
super(`Could not find the PocketIC binary. The PocketIC binary could not be found at ${picBinPath}. Please try installing @hadronous/pic again.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.BinNotFoundError = BinNotFoundError;
|
|
31
|
+
class BinTimeoutError extends Error {
|
|
32
|
+
constructor() {
|
|
33
|
+
super('The PocketIC binary took too long to start. Please try again.');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.BinTimeoutError = BinTimeoutError;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type HeadersInit = Record<string, string>;
|
|
2
|
+
export interface GetOptions {
|
|
3
|
+
headers?: HeadersInit;
|
|
4
|
+
}
|
|
5
|
+
export interface PostOptions<P> {
|
|
6
|
+
body?: P;
|
|
7
|
+
headers?: HeadersInit;
|
|
8
|
+
}
|
|
9
|
+
export declare const JSON_HEADER: HeadersInit;
|
|
10
|
+
export declare class HttpClient {
|
|
11
|
+
private constructor();
|
|
12
|
+
static get<R>(url: string, options?: GetOptions): Promise<R>;
|
|
13
|
+
static post<P, R>(url: string, options?: PostOptions<P>): Promise<R>;
|
|
14
|
+
}
|
|
15
|
+
export declare function handleFetchError(response: Response): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleFetchError = exports.HttpClient = exports.JSON_HEADER = void 0;
|
|
4
|
+
exports.JSON_HEADER = {
|
|
5
|
+
'Content-Type': 'application/json',
|
|
6
|
+
};
|
|
7
|
+
class HttpClient {
|
|
8
|
+
constructor() { }
|
|
9
|
+
static async get(url, options) {
|
|
10
|
+
const headers = options?.headers ?? {};
|
|
11
|
+
const response = await fetch(url, {
|
|
12
|
+
method: 'GET',
|
|
13
|
+
headers: { ...headers, ...exports.JSON_HEADER },
|
|
14
|
+
});
|
|
15
|
+
handleFetchError(response);
|
|
16
|
+
return (await response.json());
|
|
17
|
+
}
|
|
18
|
+
static async post(url, options) {
|
|
19
|
+
const body = options?.body ? JSON.stringify(options.body) : null;
|
|
20
|
+
const headers = options?.headers ?? {};
|
|
21
|
+
const response = await fetch(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
body,
|
|
24
|
+
headers: { ...headers, ...exports.JSON_HEADER },
|
|
25
|
+
});
|
|
26
|
+
handleFetchError(response);
|
|
27
|
+
return (await response.json());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.HttpClient = HttpClient;
|
|
31
|
+
function handleFetchError(response) {
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
console.error('Error response', response.url, response.statusText);
|
|
34
|
+
throw new Error(`${response.url} ${response.statusText}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.handleFetchError = handleFetchError;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Identity } from '@dfinity/agent';
|
|
2
|
+
/**
|
|
3
|
+
* Create an Identity from a seed phrase.
|
|
4
|
+
* The seed phrase can be any arbitrary string.
|
|
5
|
+
*
|
|
6
|
+
* The Identity is generated deterministically from the seed phrase,
|
|
7
|
+
* so subsequent calls to this function with the same seed phrase will
|
|
8
|
+
* produce the same Identity.
|
|
9
|
+
*
|
|
10
|
+
* This is useful for tests where a persistent Identity is necessary
|
|
11
|
+
* but it's easier to store the seed phrase than the Identity itself.
|
|
12
|
+
*
|
|
13
|
+
* @category API
|
|
14
|
+
* @param seedPhrase The seed phrase to create the identity from. Can be any arbitrary string.
|
|
15
|
+
* @returns An identity created from the seed phrase.
|
|
16
|
+
*
|
|
17
|
+
* @see [Identity](https://agent-js.icp.xyz/agent/interfaces/Identity.html)
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { PocketIc, createIdentity } from '@hadronous/pic';
|
|
22
|
+
* import { AnonymousIdentity } from '@dfinity/agent';
|
|
23
|
+
* import { _SERVICE, idlFactory } from '../declarations';
|
|
24
|
+
*
|
|
25
|
+
* const wasmPath = resolve('..', '..', 'canister.wasm');
|
|
26
|
+
*
|
|
27
|
+
* const pic = await PocketIc.create();
|
|
28
|
+
* const fixture = await pic.setupCanister<_SERVICE>(idlFactory, wasmPath);
|
|
29
|
+
* const { actor } = fixture;
|
|
30
|
+
*
|
|
31
|
+
* const bob = createIdentity('SuperSecretSeedPhraseForBob');
|
|
32
|
+
* actor.setIdentity(bob);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function createIdentity(seedPhrase: string): Identity;
|
|
36
|
+
/**
|
|
37
|
+
* Create an Identity from a randomly generated bip39 seed phrase.
|
|
38
|
+
* Subsequent calls to this function will produce different Identities
|
|
39
|
+
* with an extremely low probability of collision.
|
|
40
|
+
*
|
|
41
|
+
* This is useful for tests where it is important to avoid conflicts arising
|
|
42
|
+
* from multiple identities accessing the same canister and maintaining
|
|
43
|
+
* the necessary seed phrases would become cumbersome.
|
|
44
|
+
*
|
|
45
|
+
* @category API
|
|
46
|
+
* @returns An identity created from a random seed phrase.
|
|
47
|
+
*
|
|
48
|
+
* @see [Identity](https://agent-js.icp.xyz/agent/interfaces/Identity.html)
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { PocketIc, generateRandomIdentity } from '@hadronous/pic';
|
|
53
|
+
* import { AnonymousIdentity } from '@dfinity/agent';
|
|
54
|
+
* import { _SERVICE, idlFactory } from '../declarations';
|
|
55
|
+
*
|
|
56
|
+
* const wasmPath = resolve('..', '..', 'canister.wasm');
|
|
57
|
+
*
|
|
58
|
+
* const pic = await PocketIc.create();
|
|
59
|
+
* const fixture = await pic.setupCanister<_SERVICE>(idlFactory, wasmPath);
|
|
60
|
+
* const { actor } = fixture;
|
|
61
|
+
*
|
|
62
|
+
* const bob = generateRandomIdentity();
|
|
63
|
+
* actor.setIdentity(bob);
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function generateRandomIdentity(): Identity;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRandomIdentity = exports.createIdentity = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const bip39_1 = require("bip39");
|
|
6
|
+
const identity_1 = require("@dfinity/identity");
|
|
7
|
+
/**
|
|
8
|
+
* Create an Identity from a seed phrase.
|
|
9
|
+
* The seed phrase can be any arbitrary string.
|
|
10
|
+
*
|
|
11
|
+
* The Identity is generated deterministically from the seed phrase,
|
|
12
|
+
* so subsequent calls to this function with the same seed phrase will
|
|
13
|
+
* produce the same Identity.
|
|
14
|
+
*
|
|
15
|
+
* This is useful for tests where a persistent Identity is necessary
|
|
16
|
+
* but it's easier to store the seed phrase than the Identity itself.
|
|
17
|
+
*
|
|
18
|
+
* @category API
|
|
19
|
+
* @param seedPhrase The seed phrase to create the identity from. Can be any arbitrary string.
|
|
20
|
+
* @returns An identity created from the seed phrase.
|
|
21
|
+
*
|
|
22
|
+
* @see [Identity](https://agent-js.icp.xyz/agent/interfaces/Identity.html)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { PocketIc, createIdentity } from '@hadronous/pic';
|
|
27
|
+
* import { AnonymousIdentity } from '@dfinity/agent';
|
|
28
|
+
* import { _SERVICE, idlFactory } from '../declarations';
|
|
29
|
+
*
|
|
30
|
+
* const wasmPath = resolve('..', '..', 'canister.wasm');
|
|
31
|
+
*
|
|
32
|
+
* const pic = await PocketIc.create();
|
|
33
|
+
* const fixture = await pic.setupCanister<_SERVICE>(idlFactory, wasmPath);
|
|
34
|
+
* const { actor } = fixture;
|
|
35
|
+
*
|
|
36
|
+
* const bob = createIdentity('SuperSecretSeedPhraseForBob');
|
|
37
|
+
* actor.setIdentity(bob);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function createIdentity(seedPhrase) {
|
|
41
|
+
const hash = (0, node_crypto_1.createHash)('sha256');
|
|
42
|
+
hash.update(seedPhrase);
|
|
43
|
+
const digest = hash.digest('hex').slice(0, 32);
|
|
44
|
+
const encodedDigest = new TextEncoder().encode(digest);
|
|
45
|
+
return identity_1.Ed25519KeyIdentity.generate(encodedDigest);
|
|
46
|
+
}
|
|
47
|
+
exports.createIdentity = createIdentity;
|
|
48
|
+
function generateMnemonic() {
|
|
49
|
+
const entropy = (0, node_crypto_1.randomBytes)(16);
|
|
50
|
+
return (0, bip39_1.entropyToMnemonic)(entropy);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create an Identity from a randomly generated bip39 seed phrase.
|
|
54
|
+
* Subsequent calls to this function will produce different Identities
|
|
55
|
+
* with an extremely low probability of collision.
|
|
56
|
+
*
|
|
57
|
+
* This is useful for tests where it is important to avoid conflicts arising
|
|
58
|
+
* from multiple identities accessing the same canister and maintaining
|
|
59
|
+
* the necessary seed phrases would become cumbersome.
|
|
60
|
+
*
|
|
61
|
+
* @category API
|
|
62
|
+
* @returns An identity created from a random seed phrase.
|
|
63
|
+
*
|
|
64
|
+
* @see [Identity](https://agent-js.icp.xyz/agent/interfaces/Identity.html)
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { PocketIc, generateRandomIdentity } from '@hadronous/pic';
|
|
69
|
+
* import { AnonymousIdentity } from '@dfinity/agent';
|
|
70
|
+
* import { _SERVICE, idlFactory } from '../declarations';
|
|
71
|
+
*
|
|
72
|
+
* const wasmPath = resolve('..', '..', 'canister.wasm');
|
|
73
|
+
*
|
|
74
|
+
* const pic = await PocketIc.create();
|
|
75
|
+
* const fixture = await pic.setupCanister<_SERVICE>(idlFactory, wasmPath);
|
|
76
|
+
* const { actor } = fixture;
|
|
77
|
+
*
|
|
78
|
+
* const bob = generateRandomIdentity();
|
|
79
|
+
* actor.setIdentity(bob);
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function generateRandomIdentity() {
|
|
83
|
+
const mnemonic = generateMnemonic();
|
|
84
|
+
return createIdentity(mnemonic);
|
|
85
|
+
}
|
|
86
|
+
exports.generateRandomIdentity = generateRandomIdentity;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PocketIc = exports.generateRandomIdentity = exports.createIdentity = void 0;
|
|
4
|
+
var identity_1 = require("./identity");
|
|
5
|
+
Object.defineProperty(exports, "createIdentity", { enumerable: true, get: function () { return identity_1.createIdentity; } });
|
|
6
|
+
Object.defineProperty(exports, "generateRandomIdentity", { enumerable: true, get: function () { return identity_1.generateRandomIdentity; } });
|
|
7
|
+
var pocket_ic_1 = require("./pocket-ic");
|
|
8
|
+
Object.defineProperty(exports, "PocketIc", { enumerable: true, get: function () { return pocket_ic_1.PocketIc; } });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IDL } from '@dfinity/candid';
|
|
2
|
+
import { Principal } from '@dfinity/principal';
|
|
3
|
+
export declare const MANAGEMENT_CANISTER_ID: Principal;
|
|
4
|
+
export interface CanisterSettings {
|
|
5
|
+
controllers: Principal[];
|
|
6
|
+
compute_allocation: [] | [bigint];
|
|
7
|
+
memory_allocation: [] | [bigint];
|
|
8
|
+
freezing_threshold: [] | [bigint];
|
|
9
|
+
}
|
|
10
|
+
export declare const CanisterSettings: IDL.OptClass<Record<string, any>>;
|
|
11
|
+
export interface CreateCanisterRequest {
|
|
12
|
+
settings: [] | [CanisterSettings];
|
|
13
|
+
amount: [] | [bigint];
|
|
14
|
+
}
|
|
15
|
+
export declare function encodeCreateCanisterRequest(arg: CreateCanisterRequest): Uint8Array;
|
|
16
|
+
export interface CreateCanisterResponse {
|
|
17
|
+
canister_id: Principal;
|
|
18
|
+
}
|
|
19
|
+
export declare function decodeCreateCanisterResponse(arg: Uint8Array): CreateCanisterResponse;
|
|
20
|
+
export interface InstallCodeRequest {
|
|
21
|
+
arg: Uint8Array;
|
|
22
|
+
wasm_module: Uint8Array;
|
|
23
|
+
mode: {
|
|
24
|
+
reinstall?: null;
|
|
25
|
+
upgrade?: null;
|
|
26
|
+
install?: null;
|
|
27
|
+
};
|
|
28
|
+
canister_id: Principal;
|
|
29
|
+
}
|
|
30
|
+
export declare function encodeInstallCodeRequest(arg: InstallCodeRequest): Uint8Array;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeInstallCodeRequest = exports.decodeCreateCanisterResponse = exports.encodeCreateCanisterRequest = exports.CanisterSettings = exports.MANAGEMENT_CANISTER_ID = void 0;
|
|
4
|
+
const candid_1 = require("@dfinity/candid");
|
|
5
|
+
const principal_1 = require("@dfinity/principal");
|
|
6
|
+
exports.MANAGEMENT_CANISTER_ID = principal_1.Principal.fromText('aaaaa-aa');
|
|
7
|
+
exports.CanisterSettings = candid_1.IDL.Opt(candid_1.IDL.Record({
|
|
8
|
+
controllers: candid_1.IDL.Opt(candid_1.IDL.Vec(candid_1.IDL.Principal)),
|
|
9
|
+
compute_allocation: candid_1.IDL.Opt(candid_1.IDL.Nat),
|
|
10
|
+
memory_allocation: candid_1.IDL.Opt(candid_1.IDL.Nat),
|
|
11
|
+
freezing_threshold: candid_1.IDL.Opt(candid_1.IDL.Nat),
|
|
12
|
+
}));
|
|
13
|
+
const CreateCanisterRequest = candid_1.IDL.Record({
|
|
14
|
+
settings: exports.CanisterSettings,
|
|
15
|
+
amount: candid_1.IDL.Opt(candid_1.IDL.Nat),
|
|
16
|
+
});
|
|
17
|
+
function encodeCreateCanisterRequest(arg) {
|
|
18
|
+
return new Uint8Array(candid_1.IDL.encode([CreateCanisterRequest], [arg]));
|
|
19
|
+
}
|
|
20
|
+
exports.encodeCreateCanisterRequest = encodeCreateCanisterRequest;
|
|
21
|
+
const CreateCanisterResponse = candid_1.IDL.Record({
|
|
22
|
+
canister_id: candid_1.IDL.Principal,
|
|
23
|
+
});
|
|
24
|
+
function decodeCreateCanisterResponse(arg) {
|
|
25
|
+
const [payload] = candid_1.IDL.decode([CreateCanisterResponse], arg);
|
|
26
|
+
// [TODO] - type check?
|
|
27
|
+
return payload;
|
|
28
|
+
}
|
|
29
|
+
exports.decodeCreateCanisterResponse = decodeCreateCanisterResponse;
|
|
30
|
+
const InstallCodeRequest = candid_1.IDL.Record({
|
|
31
|
+
arg: candid_1.IDL.Vec(candid_1.IDL.Nat8),
|
|
32
|
+
wasm_module: candid_1.IDL.Vec(candid_1.IDL.Nat8),
|
|
33
|
+
mode: candid_1.IDL.Variant({
|
|
34
|
+
reinstall: candid_1.IDL.Null,
|
|
35
|
+
upgrade: candid_1.IDL.Null,
|
|
36
|
+
install: candid_1.IDL.Null,
|
|
37
|
+
}),
|
|
38
|
+
canister_id: candid_1.IDL.Principal,
|
|
39
|
+
});
|
|
40
|
+
function encodeInstallCodeRequest(arg) {
|
|
41
|
+
return new Uint8Array(candid_1.IDL.encode([InstallCodeRequest], [arg]));
|
|
42
|
+
}
|
|
43
|
+
exports.encodeInstallCodeRequest = encodeInstallCodeRequest;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { IDL } from '@dfinity/candid';
|
|
2
|
+
import { Principal } from '@dfinity/principal';
|
|
3
|
+
import { Identity } from '@dfinity/agent';
|
|
4
|
+
import { PocketIcClient } from './pocket-ic-client';
|
|
5
|
+
/**
|
|
6
|
+
* Typesafe method of a canister.
|
|
7
|
+
*
|
|
8
|
+
* @category Types
|
|
9
|
+
*/
|
|
10
|
+
export interface ActorMethod<Args extends unknown[] = unknown[], Ret = unknown> {
|
|
11
|
+
(...args: Args): Promise<Ret>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Candid interface of a canister.
|
|
15
|
+
*
|
|
16
|
+
* @category Types
|
|
17
|
+
*/
|
|
18
|
+
export type ActorInterface = Record<string, ActorMethod>;
|
|
19
|
+
/**
|
|
20
|
+
* A typesafe class that implements the Candid interface of a canister.
|
|
21
|
+
* This is acquired by calling {@link PocketIc.setupCanister | setupCanister}
|
|
22
|
+
* or {@link PocketIc.createActor | createActor}.
|
|
23
|
+
*
|
|
24
|
+
* @category API
|
|
25
|
+
* @typeparam T The type of the {@link Actor}. Must implement {@link ActorInterface}.
|
|
26
|
+
* @interface
|
|
27
|
+
*/
|
|
28
|
+
export type Actor<T = ActorInterface> = T & {
|
|
29
|
+
/**
|
|
30
|
+
* @ignore
|
|
31
|
+
*/
|
|
32
|
+
new (): Actor<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Set a Principal to be used as sender for all calls to the canister.
|
|
35
|
+
*
|
|
36
|
+
* @param principal The Principal to set.
|
|
37
|
+
*
|
|
38
|
+
* @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { PocketIc } from '@hadronous/pic';
|
|
43
|
+
* import { Principal } from '@dfinity/principal';
|
|
44
|
+
* import { _SERVICE, idlFactory } from '../declarations';
|
|
45
|
+
*
|
|
46
|
+
* const wasmPath = resolve('..', '..', 'canister.wasm');
|
|
47
|
+
*
|
|
48
|
+
* const pic = await PocketIc.create();
|
|
49
|
+
* const fixture = await pic.setupCanister<_SERVICE>(idlFactory, wasmPath);
|
|
50
|
+
* const { actor } = fixture;
|
|
51
|
+
*
|
|
52
|
+
* actor.setPrincipal(Principal.anonymous());
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
setPrincipal(principal: Principal): void;
|
|
56
|
+
/**
|
|
57
|
+
* Set a Principal to be used as sender for all calls to the canister.
|
|
58
|
+
* This is a convenience method over {@link setPrincipal} that accepts an
|
|
59
|
+
* Identity and internally extracts the Principal.
|
|
60
|
+
*
|
|
61
|
+
* @param identity The identity to set.
|
|
62
|
+
*
|
|
63
|
+
* @see [Identity](https://agent-js.icp.xyz/agent/interfaces/Identity.html)
|
|
64
|
+
* @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html)
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { PocketIc } from '@hadronous/pic';
|
|
69
|
+
* import { AnonymousIdentity } from '@dfinity/agent';
|
|
70
|
+
* import { _SERVICE, idlFactory } from '../declarations';
|
|
71
|
+
*
|
|
72
|
+
* const wasmPath = resolve('..', '..', 'canister.wasm');
|
|
73
|
+
*
|
|
74
|
+
* const pic = await PocketIc.create();
|
|
75
|
+
* const fixture = await pic.setupCanister<_SERVICE>(idlFactory, wasmPath);
|
|
76
|
+
* const { actor } = fixture;
|
|
77
|
+
*
|
|
78
|
+
* actor.setIdentity(new AnonymousIdentity());
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
setIdentity(identity: Identity): void;
|
|
82
|
+
};
|
|
83
|
+
export declare function createActorClass<T = ActorInterface>(interfaceFactory: IDL.InterfaceFactory, canisterId: Principal, pocketIcClient: PocketIcClient): Actor<T>;
|