@ic-reactor/core 2.0.1 → 3.0.0-beta.2
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/README.md +398 -175
- package/dist/client.d.ts +161 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +499 -0
- package/dist/client.js.map +1 -0
- package/dist/display/helper.d.ts +10 -0
- package/dist/display/helper.d.ts.map +1 -0
- package/dist/display/helper.js +67 -0
- package/dist/display/helper.js.map +1 -0
- package/dist/display/index.d.ts +4 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +4 -0
- package/dist/display/index.js.map +1 -0
- package/dist/display/types.d.ts +31 -0
- package/dist/display/types.d.ts.map +1 -0
- package/dist/display/types.js +2 -0
- package/dist/display/types.js.map +1 -0
- package/dist/display/visitor.d.ts +28 -0
- package/dist/display/visitor.d.ts.map +1 -0
- package/dist/display/visitor.js +318 -0
- package/dist/display/visitor.js.map +1 -0
- package/dist/display-reactor.d.ts +245 -0
- package/dist/display-reactor.d.ts.map +1 -0
- package/dist/display-reactor.js +331 -0
- package/dist/display-reactor.js.map +1 -0
- package/dist/errors/index.d.ts +118 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +204 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +9 -8
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -47
- package/dist/index.js.map +1 -0
- package/dist/reactor.d.ts +133 -0
- package/dist/reactor.d.ts.map +1 -0
- package/dist/reactor.js +325 -0
- package/dist/reactor.js.map +1 -0
- package/dist/types/client.d.ts +89 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/client.js +2 -0
- package/dist/types/client.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/reactor.d.ts +117 -0
- package/dist/types/reactor.d.ts.map +1 -0
- package/dist/types/reactor.js +2 -0
- package/dist/types/reactor.js.map +1 -0
- package/dist/types/result.d.ts +48 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +2 -0
- package/dist/types/result.js.map +1 -0
- package/dist/types/transform.d.ts +7 -0
- package/dist/types/transform.d.ts.map +1 -0
- package/dist/types/transform.js +2 -0
- package/dist/types/transform.js.map +1 -0
- package/dist/types/variant.d.ts +18 -0
- package/dist/types/variant.d.ts.map +1 -0
- package/dist/types/variant.js +2 -0
- package/dist/types/variant.js.map +1 -0
- package/dist/utils/agent.d.ts +30 -1
- package/dist/utils/agent.d.ts.map +1 -0
- package/dist/utils/agent.js +118 -16
- package/dist/utils/agent.js.map +1 -0
- package/dist/utils/candid.d.ts +39 -1
- package/dist/utils/candid.d.ts.map +1 -0
- package/dist/utils/candid.js +76 -16
- package/dist/utils/candid.js.map +1 -0
- package/dist/utils/constants.d.ts +3 -4
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +7 -11
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/helper.d.ts +16 -39
- package/dist/utils/helper.d.ts.map +1 -0
- package/dist/utils/helper.js +53 -155
- package/dist/utils/helper.js.map +1 -0
- package/dist/utils/index.d.ts +4 -5
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -49
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/polling.d.ts +176 -0
- package/dist/utils/polling.d.ts.map +1 -0
- package/dist/utils/polling.js +170 -0
- package/dist/utils/polling.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +65 -39
- package/LICENSE.md +0 -8
- package/dist/classes/actor/index.d.ts +0 -34
- package/dist/classes/actor/index.js +0 -245
- package/dist/classes/actor/types.d.ts +0 -113
- package/dist/classes/actor/types.js +0 -2
- package/dist/classes/adapter/index.d.ts +0 -19
- package/dist/classes/adapter/index.js +0 -140
- package/dist/classes/adapter/types.d.ts +0 -14
- package/dist/classes/adapter/types.js +0 -2
- package/dist/classes/agent/index.d.ts +0 -37
- package/dist/classes/agent/index.js +0 -221
- package/dist/classes/agent/types.d.ts +0 -87
- package/dist/classes/agent/types.js +0 -2
- package/dist/classes/index.d.ts +0 -3
- package/dist/classes/index.js +0 -19
- package/dist/classes/types.d.ts +0 -15
- package/dist/classes/types.js +0 -20
- package/dist/createActorManager.d.ts +0 -12
- package/dist/createActorManager.js +0 -17
- package/dist/createAgentManager.d.ts +0 -12
- package/dist/createAgentManager.js +0 -17
- package/dist/createCandidAdapter.d.ts +0 -11
- package/dist/createCandidAdapter.js +0 -16
- package/dist/createReactorCore.d.ts +0 -10
- package/dist/createReactorCore.js +0 -112
- package/dist/createReactorStore.d.ts +0 -11
- package/dist/createReactorStore.js +0 -31
- package/dist/types.d.ts +0 -96
- package/dist/types.js +0 -17
- package/dist/utils/hash.d.ts +0 -12
- package/dist/utils/hash.js +0 -70
- package/dist/utils/principal.d.ts +0 -1
- package/dist/utils/principal.js +0 -17
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module polling
|
|
3
|
+
* @description
|
|
4
|
+
* Polling strategy for Internet Computer (Dfinity) agent update calls.
|
|
5
|
+
*
|
|
6
|
+
* This module provides a configurable, intelligent polling mechanism that:
|
|
7
|
+
* - Starts with rapid polling for quick responses (fast phase)
|
|
8
|
+
* - Gradually increases delay intervals (ramp phase)
|
|
9
|
+
* - Settles into steady-state polling (plateau phase)
|
|
10
|
+
* - Adds jitter to prevent thundering herd problems
|
|
11
|
+
* - Provides structured logging with elapsed time and status
|
|
12
|
+
* - Supports graceful cancellation via AbortSignal
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const strategy = createPollingStrategy({
|
|
17
|
+
* context: "signer-creation",
|
|
18
|
+
* fastAttempts: 10,
|
|
19
|
+
* plateauDelayMs: 5000
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const result = await actor.createSigner(params, {
|
|
23
|
+
* pollingOptions: { strategy }
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import { RequestStatusResponseStatus, } from "@icp-sdk/core/agent";
|
|
28
|
+
/**
|
|
29
|
+
* Creates an polling strategy for Internet Computer agent update calls.
|
|
30
|
+
*
|
|
31
|
+
* The strategy implements three phases:
|
|
32
|
+
* 1. **Fast Phase**: Initial rapid polling (default: 10 attempts @ 100ms intervals)
|
|
33
|
+
* 2. **Ramp Phase**: Exponential backoff growth (default: up to 20s elapsed)
|
|
34
|
+
* 3. **Plateau Phase**: Steady-state polling (default: 5s intervals)
|
|
35
|
+
*
|
|
36
|
+
* The strategy continues polling while request status is RECEIVED/PROCESSING,
|
|
37
|
+
* and only terminates on REPLIED/REJECTED/DONE status or when aborted.
|
|
38
|
+
*
|
|
39
|
+
* @param {PollingConfig} [cfg={}] - Configuration options
|
|
40
|
+
* @returns {PollStrategy} - Async strategy function compatible with agent pollingOptions.strategy
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // Basic usage
|
|
45
|
+
* const strategy = createPollingStrategy();
|
|
46
|
+
*
|
|
47
|
+
* // Custom configuration for long-running operations
|
|
48
|
+
* const strategy = createPollingStrategy({
|
|
49
|
+
* context: "blockchain-sync",
|
|
50
|
+
* fastAttempts: 5,
|
|
51
|
+
* fastDelayMs: 200,
|
|
52
|
+
* rampUntilMs: 30_000,
|
|
53
|
+
* plateauDelayMs: 10_000,
|
|
54
|
+
* jitterRatio: 0.3
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // With abort signal
|
|
58
|
+
* const controller = new AbortController();
|
|
59
|
+
* const strategy = createPollingStrategy({
|
|
60
|
+
* context: "transaction-signing",
|
|
61
|
+
* abortSignal: controller.signal
|
|
62
|
+
* });
|
|
63
|
+
* // Later: controller.abort();
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @throws {Error} When abortSignal is triggered during polling
|
|
67
|
+
*/
|
|
68
|
+
export function createPollingStrategy(cfg = {}) {
|
|
69
|
+
const { context = "operation", logPrefix = "[Polling]", fastAttempts = 10, fastDelayMs = 100, rampUntilMs = 20000, plateauDelayMs = 5000, jitterRatio = 0.4, maxLogIntervalMs = 15000, abortSignal, } = cfg;
|
|
70
|
+
let attempt = 0;
|
|
71
|
+
const start = Date.now();
|
|
72
|
+
let lastLog = 0;
|
|
73
|
+
/**
|
|
74
|
+
* Structured logging function that outputs polling state information.
|
|
75
|
+
* Implements intelligent log throttling to prevent console spam while ensuring
|
|
76
|
+
* periodic heartbeat logs for long-running operations.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} phase - Current polling phase ("fast", "ramp", or "plateau")
|
|
79
|
+
* @param {string | undefined} statusKind - Request status from IC agent
|
|
80
|
+
* @param {number} nextDelay - Calculated delay until next poll (ms)
|
|
81
|
+
*/
|
|
82
|
+
const log = (phase, statusKind, nextDelay) => {
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
// Suppress ultra-noisy logs: skip if < 1s since last log and not in fast phase
|
|
85
|
+
if (now - lastLog < 1000 && phase !== "fast" && nextDelay < 1000)
|
|
86
|
+
return;
|
|
87
|
+
// Force a heartbeat log if too much time has passed (prevents silent operations)
|
|
88
|
+
if (now - lastLog > maxLogIntervalMs) {
|
|
89
|
+
phase += "+heartbeat";
|
|
90
|
+
}
|
|
91
|
+
lastLog = now;
|
|
92
|
+
// eslint-disable-next-line no-console
|
|
93
|
+
console.info(`${logPrefix} ${context} attempt=${attempt} elapsed=${now - start}ms status=${statusKind} phase=${phase} nextDelay=${Math.round(nextDelay)}ms`);
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Computes the next polling delay based on elapsed time and attempt count.
|
|
97
|
+
* Implements three-phase strategy:
|
|
98
|
+
* - Fast: Initial rapid polling
|
|
99
|
+
* - Ramp: Exponential growth with power curve
|
|
100
|
+
* - Plateau: Steady-state polling
|
|
101
|
+
*
|
|
102
|
+
* @param {number} elapsed - Milliseconds elapsed since start
|
|
103
|
+
* @param {number} a - Current attempt number
|
|
104
|
+
* @returns {{ delay: number; phase: string }} - Calculated delay and phase name
|
|
105
|
+
*/
|
|
106
|
+
const computeDelay = (elapsed, a) => {
|
|
107
|
+
// Phase 1: Fast initial polling
|
|
108
|
+
if (a < fastAttempts) {
|
|
109
|
+
return { delay: withJitter(fastDelayMs), phase: "fast" };
|
|
110
|
+
}
|
|
111
|
+
// Phase 2: Ramp with exponential growth (power curve 0.7 for smooth acceleration)
|
|
112
|
+
if (elapsed < rampUntilMs) {
|
|
113
|
+
const progress = elapsed / rampUntilMs; // Normalized progress: 0..1
|
|
114
|
+
const base = fastDelayMs + (plateauDelayMs - fastDelayMs) * Math.pow(progress, 0.7);
|
|
115
|
+
return { delay: withJitter(base), phase: "ramp" };
|
|
116
|
+
}
|
|
117
|
+
// Phase 3: Plateau - steady-state polling
|
|
118
|
+
return { delay: withJitter(plateauDelayMs), phase: "plateau" };
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Applies random jitter to prevent synchronized polling across multiple clients.
|
|
122
|
+
* Uses configured jitterRatio to add ±N% randomness to the base delay.
|
|
123
|
+
*
|
|
124
|
+
* @param {number} base - Base delay in milliseconds
|
|
125
|
+
* @returns {number} - Jittered delay, minimum 50ms
|
|
126
|
+
*/
|
|
127
|
+
const withJitter = (base) => {
|
|
128
|
+
const spread = base * jitterRatio;
|
|
129
|
+
return Math.max(50, base - spread + Math.random() * spread * 2);
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Async strategy function invoked by the IC agent on each polling cycle.
|
|
133
|
+
* Determines whether to continue waiting based on request status.
|
|
134
|
+
*
|
|
135
|
+
* @param {Principal} _canisterId - Target canister principal (unused but required by interface)
|
|
136
|
+
* @param {RequestId} _requestId - Request identifier (unused but required by interface)
|
|
137
|
+
* @param {RequestStatusResponseStatus} [rawStatus] - Current request status from IC
|
|
138
|
+
* @returns {Promise<void>} - Resolves after calculated delay, or immediately for terminal states
|
|
139
|
+
* @throws {Error} - If abortSignal is triggered
|
|
140
|
+
*/
|
|
141
|
+
return async function strategy(_canisterId, _requestId, rawStatus) {
|
|
142
|
+
// Check for external cancellation
|
|
143
|
+
if (abortSignal?.aborted) {
|
|
144
|
+
throw new Error(`${context} polling aborted`);
|
|
145
|
+
}
|
|
146
|
+
attempt++;
|
|
147
|
+
const statusKind = rawStatus;
|
|
148
|
+
// Terminal states: Stop polling immediately
|
|
149
|
+
// - Replied: Request completed successfully
|
|
150
|
+
// - Rejected: Request was rejected by canister
|
|
151
|
+
// - Done: Request processing complete
|
|
152
|
+
// Note: Agent typically stops before we reach here, but we handle defensively
|
|
153
|
+
if (statusKind === RequestStatusResponseStatus.Replied ||
|
|
154
|
+
statusKind === RequestStatusResponseStatus.Rejected ||
|
|
155
|
+
statusKind === RequestStatusResponseStatus.Done) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Continue polling for:
|
|
159
|
+
// - Received: Request received but not yet processed
|
|
160
|
+
// - Processing: Request is being processed
|
|
161
|
+
// - Unknown: Status not yet available
|
|
162
|
+
// - undefined: No status information yet
|
|
163
|
+
const elapsed = Date.now() - start;
|
|
164
|
+
const { delay, phase } = computeDelay(elapsed, attempt);
|
|
165
|
+
log(phase, statusKind, delay);
|
|
166
|
+
// Sleep for calculated delay before next poll
|
|
167
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=polling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.js","sourceRoot":"","sources":["../../src/utils/polling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,OAAO,UAAU,CAAA"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,60 +1,86 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ic-reactor/core",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0-beta.2",
|
|
4
|
+
"description": "IC Reactor Core Library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
7
17
|
"files": [
|
|
8
|
-
"dist
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
9
20
|
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -b",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"version:sync": "node -e \"const pkg = require('./package.json'); const fs = require('fs'); fs.writeFileSync('./src/version.ts', '/**\\n * Library version - automatically synced from package.json.\\n */\\nexport const VERSION = \\\"' + pkg.version + '\\\"\\n');\"",
|
|
25
|
+
"size": "size-limit",
|
|
26
|
+
"analyze": "size-limit --why"
|
|
27
|
+
},
|
|
10
28
|
"repository": {
|
|
11
29
|
"type": "git",
|
|
12
|
-
"url": "
|
|
30
|
+
"url": "https://github.com/B3Pay/ic-reactor",
|
|
31
|
+
"directory": "packages/core"
|
|
13
32
|
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/B3Pay/ic-reactor/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://ic-reactor.dev",
|
|
14
37
|
"keywords": [
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"candid",
|
|
38
|
+
"internet-computer",
|
|
39
|
+
"icp",
|
|
18
40
|
"dfinity",
|
|
19
41
|
"web3",
|
|
20
|
-
"
|
|
42
|
+
"blockchain",
|
|
43
|
+
"canister",
|
|
44
|
+
"actor",
|
|
45
|
+
"reactor",
|
|
46
|
+
"tanstack-query"
|
|
21
47
|
],
|
|
22
|
-
"author": "
|
|
48
|
+
"author": "Behrad Deylami",
|
|
23
49
|
"license": "MIT",
|
|
24
|
-
"bugs": {
|
|
25
|
-
"url": "https://github.com/b3hr4d/ic-reactor/issues"
|
|
26
|
-
},
|
|
27
|
-
"homepage": "https://b3pay.github.io/ic-reactor/modules/core.html",
|
|
28
50
|
"dependencies": {
|
|
29
|
-
"@
|
|
30
|
-
"
|
|
31
|
-
"@dfinity/candid": "^3.1.0",
|
|
32
|
-
"@dfinity/identity": "^3.1.0",
|
|
33
|
-
"@dfinity/principal": "^3.1.0",
|
|
34
|
-
"zustand": "5.0.6"
|
|
51
|
+
"@noble/curves": "^2.0.1",
|
|
52
|
+
"zod": "^4.3.2"
|
|
35
53
|
},
|
|
36
54
|
"peerDependencies": {
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
"@icp-sdk/core": "^5.0.0",
|
|
56
|
+
"@icp-sdk/auth": "^5.0.0",
|
|
57
|
+
"@tanstack/query-core": "^5.0.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependenciesMeta": {
|
|
60
|
+
"@icp-sdk/auth": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@tanstack/query-core": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
42
66
|
},
|
|
43
67
|
"devDependencies": {
|
|
44
|
-
"@
|
|
68
|
+
"@icp-sdk/auth": "^5.0.0",
|
|
69
|
+
"@icp-sdk/core": "^5.0.0",
|
|
70
|
+
"@size-limit/preset-small-lib": "^11.2.0",
|
|
71
|
+
"@tanstack/query-core": "^5.90",
|
|
72
|
+
"@tanstack/react-query": "^5.90",
|
|
73
|
+
"@types/node": "^24.10.1",
|
|
74
|
+
"fake-indexeddb": "^6.2.5",
|
|
75
|
+
"size-limit": "^11.2.0",
|
|
76
|
+
"vitest": "^4.0.16"
|
|
45
77
|
},
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"clean": "bun run rimraf dist && bun run rimraf umd && bun run rimraf node_modules"
|
|
55
|
-
},
|
|
56
|
-
"engines": {
|
|
57
|
-
"node": ">=22.0.0"
|
|
58
|
-
},
|
|
59
|
-
"gitHead": "1c8f5bfc6b0fea9347602beeebd6443f79d7d54e"
|
|
78
|
+
"size-limit": [
|
|
79
|
+
{
|
|
80
|
+
"name": "Core Library",
|
|
81
|
+
"path": "dist/index.js",
|
|
82
|
+
"limit": "50 KB",
|
|
83
|
+
"gzip": true
|
|
84
|
+
}
|
|
85
|
+
]
|
|
60
86
|
}
|
package/LICENSE.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
Copyright © 2023 B3Pay
|
|
3
|
-
|
|
4
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
5
|
-
|
|
6
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
7
|
-
|
|
8
|
-
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { CallConfig } from "@dfinity/agent";
|
|
2
|
-
import type { ActorMethodParameters, ActorMethodReturnType, ActorStore, ActorManagerParameters, FunctionName, VisitService, BaseActor, ActorMethodState, MethodAttributes } from "./types";
|
|
3
|
-
import { IDL } from "@dfinity/candid";
|
|
4
|
-
import type { AgentManager } from "../agent";
|
|
5
|
-
import type { UpdateAgentParameters } from "../types";
|
|
6
|
-
export declare class ActorManager<A = BaseActor> {
|
|
7
|
-
private _actor;
|
|
8
|
-
private _idlFactory;
|
|
9
|
-
private _agentManager;
|
|
10
|
-
private _unsubscribeAgent;
|
|
11
|
-
private _subscribers;
|
|
12
|
-
canisterId: string;
|
|
13
|
-
actorStore: ActorStore<A>;
|
|
14
|
-
visitFunction: VisitService<A>;
|
|
15
|
-
methodAttributes: MethodAttributes<A>;
|
|
16
|
-
private updateState;
|
|
17
|
-
updateMethodState: (method: FunctionName<A>, hash: string, newState: Partial<ActorMethodState<A, typeof method>[string]>) => void;
|
|
18
|
-
constructor(actorConfig: ActorManagerParameters);
|
|
19
|
-
initialize: (options?: UpdateAgentParameters) => Promise<void>;
|
|
20
|
-
extractInterface: () => IDL.ServiceClass;
|
|
21
|
-
extractMethodAttributes: () => MethodAttributes<A>;
|
|
22
|
-
extractVisitor: () => VisitService<A>;
|
|
23
|
-
private initializeActor;
|
|
24
|
-
private _getActorMethod;
|
|
25
|
-
callMethod: <M extends FunctionName<A>>(functionName: M, ...args: ActorMethodParameters<A[M]>) => Promise<ActorMethodReturnType<A[M]>>;
|
|
26
|
-
callMethodWithOptions: (options: CallConfig) => <M extends FunctionName<A>>(functionName: M, ...args: ActorMethodParameters<A[M]>) => Promise<ActorMethodReturnType<A[M]>>;
|
|
27
|
-
call: <M extends FunctionName<A>>(functionName: M, ...args: ActorMethodParameters<A[M]>) => Promise<ActorMethodReturnType<A[M]>>;
|
|
28
|
-
get agentManager(): AgentManager;
|
|
29
|
-
getActor: () => A | null;
|
|
30
|
-
getState: ActorStore<A>["getState"];
|
|
31
|
-
subscribeActorState: ActorStore<A>["subscribe"];
|
|
32
|
-
setState: ActorStore<A>["setState"];
|
|
33
|
-
cleanup: () => void;
|
|
34
|
-
}
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ActorManager = void 0;
|
|
4
|
-
/* eslint-disable no-console */
|
|
5
|
-
const agent_1 = require("@dfinity/agent");
|
|
6
|
-
const helper_1 = require("../../utils/helper");
|
|
7
|
-
const candid_1 = require("@dfinity/candid");
|
|
8
|
-
const ACTOR_INITIAL_STATE = {
|
|
9
|
-
name: "",
|
|
10
|
-
version: 0,
|
|
11
|
-
methodState: {},
|
|
12
|
-
initializing: false,
|
|
13
|
-
isInitializing: false,
|
|
14
|
-
initialized: false,
|
|
15
|
-
isInitialized: false,
|
|
16
|
-
error: undefined,
|
|
17
|
-
};
|
|
18
|
-
class ActorManager {
|
|
19
|
-
_actor = null;
|
|
20
|
-
_idlFactory;
|
|
21
|
-
_agentManager;
|
|
22
|
-
_unsubscribeAgent;
|
|
23
|
-
_subscribers = [];
|
|
24
|
-
canisterId;
|
|
25
|
-
actorStore;
|
|
26
|
-
visitFunction;
|
|
27
|
-
methodAttributes;
|
|
28
|
-
updateState = (newState, action) => {
|
|
29
|
-
this.actorStore.setState((state) => ({ ...state, ...newState }), false, action);
|
|
30
|
-
};
|
|
31
|
-
updateMethodState = (method, hash, newState) => {
|
|
32
|
-
const actionName = `${method}:${newState.error ? "error" : newState.isLoading ? "loading..." : "loaded"}`;
|
|
33
|
-
this.actorStore.setState((state) => {
|
|
34
|
-
const methodState = state.methodState[method] || {};
|
|
35
|
-
const currentMethodState = methodState[hash] || DEFAULT_STATE;
|
|
36
|
-
const updatedMethodState = {
|
|
37
|
-
...methodState,
|
|
38
|
-
[hash]: { ...currentMethodState, ...newState },
|
|
39
|
-
};
|
|
40
|
-
return {
|
|
41
|
-
...state,
|
|
42
|
-
methodState: {
|
|
43
|
-
...state.methodState,
|
|
44
|
-
[method]: updatedMethodState,
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}, false, actionName);
|
|
48
|
-
};
|
|
49
|
-
constructor(actorConfig) {
|
|
50
|
-
const { agentManager, idlFactory, canisterId, name = canisterId.toString(), withVisitor = false, withDevtools = false, initializeOnCreate = true, } = actorConfig;
|
|
51
|
-
if (!canisterId) {
|
|
52
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode("CanisterId is required!"), agent_1.ErrorKindEnum.Unknown);
|
|
53
|
-
}
|
|
54
|
-
this.canisterId = canisterId.toString();
|
|
55
|
-
if (!idlFactory) {
|
|
56
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode("IDLFactory is required!"), agent_1.ErrorKindEnum.Unknown);
|
|
57
|
-
}
|
|
58
|
-
this._idlFactory = idlFactory;
|
|
59
|
-
this.methodAttributes = this.extractMethodAttributes();
|
|
60
|
-
if (!agentManager) {
|
|
61
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode("AgentManager is required!"), agent_1.ErrorKindEnum.Unknown);
|
|
62
|
-
}
|
|
63
|
-
this._agentManager = agentManager;
|
|
64
|
-
// Initialize stores
|
|
65
|
-
this.actorStore = (0, helper_1.createStoreWithOptionalDevtools)({ ...ACTOR_INITIAL_STATE, name }, {
|
|
66
|
-
withDevtools,
|
|
67
|
-
name: "reactor-actor",
|
|
68
|
-
store: canisterId.toString(),
|
|
69
|
-
});
|
|
70
|
-
this._unsubscribeAgent = this._agentManager.subscribeAgent(this.initializeActor, initializeOnCreate);
|
|
71
|
-
if (withVisitor) {
|
|
72
|
-
this.visitFunction = this.extractVisitor();
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
this.visitFunction = emptyVisitor;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
initialize = async (options) => {
|
|
79
|
-
await this._agentManager.updateAgent(options);
|
|
80
|
-
};
|
|
81
|
-
extractInterface = () => {
|
|
82
|
-
return this._idlFactory({ IDL: candid_1.IDL });
|
|
83
|
-
};
|
|
84
|
-
extractMethodAttributes = () => {
|
|
85
|
-
const iface = this.extractInterface();
|
|
86
|
-
const methodAttributesArray = iface._fields.map(([name, func]) => ({
|
|
87
|
-
name: name,
|
|
88
|
-
attributes: {
|
|
89
|
-
numberOfArgs: func.argTypes.length,
|
|
90
|
-
type: ((0, helper_1.isQuery)(func) ? "query" : "update"),
|
|
91
|
-
validate: (arg) => func.argTypes.some((t, i) => t.covariant(arg[i])),
|
|
92
|
-
},
|
|
93
|
-
}));
|
|
94
|
-
methodAttributesArray.sort((a, b) => {
|
|
95
|
-
if (a.attributes.type === b.attributes.type) {
|
|
96
|
-
return a.attributes.numberOfArgs - b.attributes.numberOfArgs;
|
|
97
|
-
}
|
|
98
|
-
return a.attributes.type === "query" ? -1 : 1;
|
|
99
|
-
});
|
|
100
|
-
return methodAttributesArray.reduce((acc, { name, attributes }) => {
|
|
101
|
-
acc[name] = attributes;
|
|
102
|
-
return acc;
|
|
103
|
-
}, {});
|
|
104
|
-
};
|
|
105
|
-
extractVisitor = () => {
|
|
106
|
-
const iface = this.extractInterface();
|
|
107
|
-
return iface._fields.reduce((acc, service) => {
|
|
108
|
-
const functionName = service[0];
|
|
109
|
-
const type = service[1];
|
|
110
|
-
const visit = ((extractorClass, data) => {
|
|
111
|
-
return type.accept(extractorClass, data);
|
|
112
|
-
});
|
|
113
|
-
acc[functionName] = visit;
|
|
114
|
-
return acc;
|
|
115
|
-
}, {});
|
|
116
|
-
};
|
|
117
|
-
initializeActor = (agent) => {
|
|
118
|
-
const network = this._agentManager.getNetwork();
|
|
119
|
-
console.info(`Initializing actor ${this.canisterId} on ${network} network`);
|
|
120
|
-
const { _idlFactory, canisterId } = this;
|
|
121
|
-
this.updateState({
|
|
122
|
-
initializing: true,
|
|
123
|
-
isInitializing: true,
|
|
124
|
-
initialized: false,
|
|
125
|
-
isInitialized: false,
|
|
126
|
-
methodState: {},
|
|
127
|
-
}, "initializing");
|
|
128
|
-
try {
|
|
129
|
-
if (!agent) {
|
|
130
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode("Agent not initialized"), agent_1.ErrorKindEnum.Unknown);
|
|
131
|
-
}
|
|
132
|
-
this._actor = agent_1.Actor.createActor(_idlFactory, {
|
|
133
|
-
agent,
|
|
134
|
-
canisterId,
|
|
135
|
-
});
|
|
136
|
-
if (!this._actor) {
|
|
137
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode("Failed to initialize actor"), agent_1.ErrorKindEnum.Unknown);
|
|
138
|
-
}
|
|
139
|
-
this.updateState({
|
|
140
|
-
initializing: false,
|
|
141
|
-
isInitializing: false,
|
|
142
|
-
initialized: true,
|
|
143
|
-
isInitialized: true,
|
|
144
|
-
}, "initialized");
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
console.error("Error in initializeActor:", error);
|
|
148
|
-
this.updateState({
|
|
149
|
-
error: error,
|
|
150
|
-
initializing: false,
|
|
151
|
-
isInitializing: false,
|
|
152
|
-
}, "error");
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
_getActorMethod = (functionName) => {
|
|
156
|
-
if (!this._actor) {
|
|
157
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode("Actor not initialized"), agent_1.ErrorKindEnum.Unknown);
|
|
158
|
-
}
|
|
159
|
-
if (!this._actor[functionName] ||
|
|
160
|
-
typeof this._actor[functionName] !== "function") {
|
|
161
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode(`Method ${String(functionName)} not found`), agent_1.ErrorKindEnum.Unknown);
|
|
162
|
-
}
|
|
163
|
-
return this._actor[functionName];
|
|
164
|
-
};
|
|
165
|
-
callMethod = async (functionName, ...args) => {
|
|
166
|
-
const method = this._getActorMethod(functionName);
|
|
167
|
-
const data = await method(...args);
|
|
168
|
-
return data;
|
|
169
|
-
};
|
|
170
|
-
callMethodWithOptions = (options) => {
|
|
171
|
-
return async (functionName, ...args) => {
|
|
172
|
-
const method = this._getActorMethod(functionName);
|
|
173
|
-
const data = await method.withOptions(options)(...args);
|
|
174
|
-
return data;
|
|
175
|
-
};
|
|
176
|
-
};
|
|
177
|
-
call = async (functionName, ...args) => {
|
|
178
|
-
const requestHash = (0, helper_1.generateRequestHash)(args);
|
|
179
|
-
try {
|
|
180
|
-
this.updateMethodState(functionName, requestHash, {
|
|
181
|
-
loading: true,
|
|
182
|
-
isLoading: true,
|
|
183
|
-
error: undefined,
|
|
184
|
-
});
|
|
185
|
-
const data = await this.callMethod(functionName, ...args);
|
|
186
|
-
this.updateMethodState(functionName, requestHash, {
|
|
187
|
-
loading: false,
|
|
188
|
-
isLoading: false,
|
|
189
|
-
data,
|
|
190
|
-
});
|
|
191
|
-
return data;
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
this.updateMethodState(functionName, requestHash, {
|
|
195
|
-
loading: false,
|
|
196
|
-
isLoading: false,
|
|
197
|
-
error: error,
|
|
198
|
-
data: undefined,
|
|
199
|
-
});
|
|
200
|
-
throw error;
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
// agent store
|
|
204
|
-
get agentManager() {
|
|
205
|
-
return this._agentManager;
|
|
206
|
-
}
|
|
207
|
-
// actor store
|
|
208
|
-
getActor = () => {
|
|
209
|
-
return this._actor;
|
|
210
|
-
};
|
|
211
|
-
getState = () => {
|
|
212
|
-
return this.actorStore.getState();
|
|
213
|
-
};
|
|
214
|
-
// @ts-expect-error: Overrides subscribe method signature
|
|
215
|
-
subscribeActorState = (selectorOrListener, listener, options) => {
|
|
216
|
-
let unsubscribe = helper_1.noop;
|
|
217
|
-
if (listener) {
|
|
218
|
-
unsubscribe = this.actorStore.subscribe(selectorOrListener, listener, options);
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
unsubscribe = this.actorStore.subscribe(selectorOrListener);
|
|
222
|
-
}
|
|
223
|
-
this._subscribers.push(unsubscribe);
|
|
224
|
-
return unsubscribe;
|
|
225
|
-
};
|
|
226
|
-
setState = (updater) => {
|
|
227
|
-
return this.actorStore.setState(updater);
|
|
228
|
-
};
|
|
229
|
-
cleanup = () => {
|
|
230
|
-
this._unsubscribeAgent();
|
|
231
|
-
this._subscribers.forEach((unsubscribe) => unsubscribe());
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
exports.ActorManager = ActorManager;
|
|
235
|
-
const emptyVisitor = new Proxy({}, {
|
|
236
|
-
get: function (_, prop) {
|
|
237
|
-
throw new agent_1.AgentError(new agent_1.UnexpectedErrorCode(`Cannot visit function "${String(prop)}" without initializing the actor with the visitor option, please set the withVisitor option to true when creating the actor manager.`), agent_1.ErrorKindEnum.Unknown);
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
const DEFAULT_STATE = {
|
|
241
|
-
data: undefined,
|
|
242
|
-
error: undefined,
|
|
243
|
-
loading: false,
|
|
244
|
-
isLoading: false,
|
|
245
|
-
};
|