@shelby-protocol/sdk 0.2.4 → 0.3.1
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/dist/browser/index.d.ts +13 -4
- package/dist/browser/index.mjs +3719 -140
- package/dist/{clay-codes-DHP-bYcP.d.ts → clay-codes-DdXABBDx.d.ts} +0 -7
- package/dist/core/aptos-explorer.mjs +46 -5
- package/dist/core/blobs.d.ts +1 -1
- package/dist/core/blobs.mjs +12 -4
- package/dist/core/chunk.mjs +58 -9
- package/dist/core/clients/ShelbyBlobClient.d.ts +9 -44
- package/dist/core/clients/ShelbyBlobClient.mjs +1084 -17
- package/dist/core/clients/ShelbyClient.d.ts +12 -2
- package/dist/core/clients/ShelbyClient.mjs +2915 -23
- package/dist/core/clients/ShelbyClientConfig.d.ts +8 -0
- package/dist/core/clients/ShelbyClientConfig.mjs +0 -1
- package/dist/core/clients/ShelbyMetadataClient.d.ts +0 -18
- package/dist/core/clients/ShelbyMetadataClient.mjs +306 -6
- package/dist/core/clients/ShelbyMicropaymentChannelClient.d.ts +7 -49
- package/dist/core/clients/ShelbyMicropaymentChannelClient.mjs +839 -13
- package/dist/core/clients/ShelbyPlacementGroupClient.mjs +307 -8
- package/dist/core/clients/ShelbyRPCClient.d.ts +107 -4
- package/dist/core/clients/ShelbyRPCClient.mjs +1261 -12
- package/dist/core/clients/index.d.ts +3 -2
- package/dist/core/clients/index.mjs +3421 -40
- package/dist/core/clients/utils.mjs +65 -6
- package/dist/core/commitments.d.ts +3 -12
- package/dist/core/commitments.mjs +270 -11
- package/dist/core/constants.d.ts +4 -4
- package/dist/core/constants.mjs +39 -16
- package/dist/core/erasure/clay-codes.d.ts +1 -1
- package/dist/core/erasure/clay-codes.mjs +129 -4
- package/dist/core/erasure/constants.mjs +33 -10
- package/dist/core/erasure/default.d.ts +1 -1
- package/dist/core/erasure/default.mjs +191 -9
- package/dist/core/erasure/index.d.ts +1 -1
- package/dist/core/erasure/index.mjs +266 -23
- package/dist/core/erasure/provider.d.ts +1 -1
- package/dist/core/erasure/reed-solomon.d.ts +1 -1
- package/dist/core/erasure/reed-solomon.mjs +68 -4
- package/dist/core/erasure/utils.d.ts +1 -1
- package/dist/core/erasure/utils.mjs +0 -2
- package/dist/core/errors.mjs +29 -8
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.mjs +3713 -140
- package/dist/core/layout.d.ts +1 -1
- package/dist/core/layout.mjs +37 -5
- package/dist/core/networks.mjs +10 -5
- package/dist/core/operations/generated/sdk.d.ts +9 -0
- package/dist/core/operations/generated/sdk.mjs +183 -18
- package/dist/core/operations/index.mjs +284 -24
- package/dist/core/promises.mjs +4 -4
- package/dist/core/rpc-responses.d.ts +38 -1
- package/dist/core/rpc-responses.mjs +31 -8
- package/dist/core/shelby-explorer.mjs +31 -6
- package/dist/core/strings.mjs +0 -2
- package/dist/core/types/blobs.d.ts +1 -1
- package/dist/core/types/blobs.mjs +0 -1
- package/dist/core/types/index.d.ts +1 -1
- package/dist/core/types/index.mjs +230 -9
- package/dist/core/types/payments.d.ts +6 -6
- package/dist/core/types/payments.mjs +230 -5
- package/dist/core/types/placement_groups.mjs +0 -1
- package/dist/core/types/storage_providers.mjs +0 -1
- package/dist/core/utils.mjs +94 -8
- package/dist/node/clients/ShelbyNodeClient.d.ts +2 -1
- package/dist/node/clients/ShelbyNodeClient.mjs +2919 -24
- package/dist/node/clients/index.d.ts +2 -1
- package/dist/node/clients/index.mjs +2920 -26
- package/dist/node/index.d.ts +4 -4
- package/dist/node/index.mjs +3736 -147
- package/dist/node/parallel/commitment_worker.d.ts +9 -0
- package/dist/node/parallel/commitment_worker.mjs +298 -0
- package/dist/node/parallel/commitment_worker_pool.d.ts +35 -0
- package/dist/node/parallel/commitment_worker_pool.mjs +286 -0
- package/dist/node/parallel/default_commitment_worker_pool.d.ts +24 -0
- package/dist/node/parallel/default_commitment_worker_pool.mjs +302 -0
- package/dist/node/parallel/index.d.ts +11 -0
- package/dist/node/parallel/index.mjs +563 -0
- package/dist/node/parallel/parallel_commitments.d.ts +32 -0
- package/dist/node/parallel/parallel_commitments.mjs +561 -0
- package/dist/node/parallel/worker_pool.d.ts +74 -0
- package/dist/node/parallel/worker_pool.mjs +248 -0
- package/dist/node/testUtil.mjs +8 -4
- package/package.json +9 -6
- package/dist/chunk-3NRBHSMQ.mjs +0 -12
- package/dist/chunk-3PCG7PNP.mjs +0 -375
- package/dist/chunk-7OV5ZYW6.mjs +0 -55
- package/dist/chunk-7P6ASYW6.mjs +0 -9
- package/dist/chunk-A4IG6GSE.mjs +0 -21
- package/dist/chunk-AD2G3QYD.mjs +0 -0
- package/dist/chunk-AEDVYYGD.mjs +0 -11
- package/dist/chunk-AUQDI5BS.mjs +0 -43
- package/dist/chunk-BDSW5PHM.mjs +0 -37
- package/dist/chunk-BKL7NCUB.mjs +0 -412
- package/dist/chunk-BUWAD67L.mjs +0 -505
- package/dist/chunk-BXEVML7N.mjs +0 -169
- package/dist/chunk-C6RQ3AEU.mjs +0 -51
- package/dist/chunk-CQ6QPIZK.mjs +0 -37
- package/dist/chunk-D6GQHO6G.mjs +0 -15
- package/dist/chunk-EM67QTMR.mjs +0 -0
- package/dist/chunk-I6NG5GNL.mjs +0 -8
- package/dist/chunk-IE6LYVIA.mjs +0 -26
- package/dist/chunk-IKRWBDG5.mjs +0 -42
- package/dist/chunk-JTXYKO3U.mjs +0 -38
- package/dist/chunk-KYQRWJ3U.mjs +0 -49
- package/dist/chunk-MB7C7VQF.mjs +0 -0
- package/dist/chunk-MQUVYMNQ.mjs +0 -0
- package/dist/chunk-NHWWORCH.mjs +0 -72
- package/dist/chunk-NI6XBZLI.mjs +0 -83
- package/dist/chunk-OGKZ575S.mjs +0 -136
- package/dist/chunk-QQ57OGQ2.mjs +0 -0
- package/dist/chunk-SSE4MFNN.mjs +0 -278
- package/dist/chunk-TET3DJEO.mjs +0 -199
- package/dist/chunk-TVLV7C74.mjs +0 -207
- package/dist/chunk-UEZNZBJO.mjs +0 -104
- package/dist/chunk-WJTVYLKW.mjs +0 -782
- package/dist/chunk-WTICJPDB.mjs +0 -0
- package/dist/chunk-XNEIWM4O.mjs +0 -0
- package/dist/chunk-XRLHLAOW.mjs +0 -51
- package/dist/chunk-Z4FZ7W6L.mjs +0 -39
- package/dist/chunk-Z7RFCADT.mjs +0 -0
- package/dist/chunk-ZHXCVRZX.mjs +0 -0
- package/dist/core/operations/generated/types.d.ts +0 -908
- package/dist/core/operations/generated/types.mjs +0 -63
- package/dist/core/types/encodings.d.ts +0 -11
- package/dist/core/types/encodings.mjs +0 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// src/node/parallel/worker_pool.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { Worker } from "worker_threads";
|
|
6
|
+
var WorkerPool = class {
|
|
7
|
+
workers = [];
|
|
8
|
+
queue = [];
|
|
9
|
+
maxWorkers;
|
|
10
|
+
workerPath;
|
|
11
|
+
isTerminating = false;
|
|
12
|
+
activeTasks = /* @__PURE__ */ new Set();
|
|
13
|
+
inFlightCount = 0;
|
|
14
|
+
slotWaiters = [];
|
|
15
|
+
constructor(maxWorkers, workerPath) {
|
|
16
|
+
if (!Number.isSafeInteger(maxWorkers) || maxWorkers < 1) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`maxWorkers must be a positive safe integer, got ${maxWorkers}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
this.maxWorkers = maxWorkers;
|
|
22
|
+
this.workerPath = workerPath;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the path to a worker script relative to the calling module.
|
|
26
|
+
*
|
|
27
|
+
* Pass `import.meta.url` from the subclass file along with the script name
|
|
28
|
+
* (without extension). The extension is inferred from the calling module's
|
|
29
|
+
* own extension so that both the TypeScript source (.ts) and the compiled
|
|
30
|
+
* output (.mjs / .js) are handled correctly.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* constructor(maxWorkers: number) {
|
|
34
|
+
* super(maxWorkers, WorkerPool.resolveWorkerPath(import.meta.url, "my_worker"));
|
|
35
|
+
* }
|
|
36
|
+
*/
|
|
37
|
+
static resolveWorkerPath(importMetaUrl, scriptName) {
|
|
38
|
+
const currentPath = fileURLToPath(importMetaUrl);
|
|
39
|
+
const dir = path.dirname(currentPath);
|
|
40
|
+
const ext = path.extname(currentPath);
|
|
41
|
+
const workerExt = ext === ".mjs" ? ".mjs" : ext === ".js" ? ".js" : ".ts";
|
|
42
|
+
return path.join(dir, `${scriptName}${workerExt}`);
|
|
43
|
+
}
|
|
44
|
+
initialize() {
|
|
45
|
+
this.isTerminating = false;
|
|
46
|
+
if (!fs.existsSync(this.workerPath)) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Could not find worker script at ${this.workerPath}. Running as ${path.extname(this.workerPath)}, expected worker at same extension.`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
for (let i = 0; i < this.maxWorkers; i++) {
|
|
52
|
+
this.workers.push({ worker: new Worker(this.workerPath), busy: false });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
isInitialized() {
|
|
56
|
+
return this.workers.length > 0;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Acquire a back-pressure slot before submitting work to the pool.
|
|
60
|
+
* Resolves immediately if fewer than `maxWorkers` chunksets are in flight;
|
|
61
|
+
* otherwise waits until a slot is released. Callers must call `releaseSlot()`
|
|
62
|
+
* when the submitted task settles (resolve or reject).
|
|
63
|
+
*
|
|
64
|
+
* Moving back-pressure into the pool ensures a single global bound on
|
|
65
|
+
* buffered memory regardless of how many concurrent callers share the pool.
|
|
66
|
+
*/
|
|
67
|
+
acquireSlot() {
|
|
68
|
+
if (this.inFlightCount < this.maxWorkers) {
|
|
69
|
+
this.inFlightCount++;
|
|
70
|
+
return Promise.resolve();
|
|
71
|
+
}
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
this.slotWaiters.push({
|
|
74
|
+
resolve: () => {
|
|
75
|
+
this.inFlightCount++;
|
|
76
|
+
resolve();
|
|
77
|
+
},
|
|
78
|
+
reject
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
releaseSlot() {
|
|
83
|
+
this.inFlightCount--;
|
|
84
|
+
const next = this.slotWaiters.shift();
|
|
85
|
+
if (next) {
|
|
86
|
+
next.resolve();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
enqueueTask(task) {
|
|
90
|
+
this.activeTasks.add(task);
|
|
91
|
+
if (this.isTerminating) {
|
|
92
|
+
this.activeTasks.delete(task);
|
|
93
|
+
task.reject(
|
|
94
|
+
new Error("Worker pool is being terminated - cannot process new tasks")
|
|
95
|
+
);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const availableWorker = this.workers.find((w) => !w.busy);
|
|
99
|
+
if (availableWorker) {
|
|
100
|
+
this.executeTask(availableWorker, task);
|
|
101
|
+
} else {
|
|
102
|
+
this.queue.push(task);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
processNextQueuedTask(preferredWorker) {
|
|
106
|
+
const nextTask = this.queue.shift();
|
|
107
|
+
if (!nextTask) return;
|
|
108
|
+
if (preferredWorker && !preferredWorker.busy && preferredWorker.worker) {
|
|
109
|
+
this.executeTask(preferredWorker, nextTask);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const availableWorker = this.workers.find((w) => !w.busy && w.worker);
|
|
113
|
+
if (availableWorker) {
|
|
114
|
+
this.executeTask(availableWorker, nextTask);
|
|
115
|
+
} else {
|
|
116
|
+
this.queue.unshift(nextTask);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
rejectAllQueuedTasks(error) {
|
|
120
|
+
const tasks = this.queue.splice(0);
|
|
121
|
+
for (const task of tasks) {
|
|
122
|
+
this.activeTasks.delete(task);
|
|
123
|
+
task.reject(error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
rejectAllActiveTasks(error) {
|
|
127
|
+
const tasks = Array.from(this.activeTasks);
|
|
128
|
+
this.activeTasks.clear();
|
|
129
|
+
for (const task of tasks) {
|
|
130
|
+
task.reject(error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
executeTask(workerWrapper, task) {
|
|
134
|
+
workerWrapper.busy = true;
|
|
135
|
+
const cleanup = () => {
|
|
136
|
+
workerWrapper.worker.off("message", messageHandler);
|
|
137
|
+
workerWrapper.worker.off("error", errorHandler);
|
|
138
|
+
workerWrapper.worker.off("exit", exitHandler);
|
|
139
|
+
workerWrapper.busy = false;
|
|
140
|
+
};
|
|
141
|
+
const messageHandler = (message) => {
|
|
142
|
+
cleanup();
|
|
143
|
+
this.activeTasks.delete(task);
|
|
144
|
+
if (message.success && message.result !== void 0) {
|
|
145
|
+
task.resolve(message.result);
|
|
146
|
+
} else {
|
|
147
|
+
task.reject(new Error(message.error ?? "Worker processing failed"));
|
|
148
|
+
}
|
|
149
|
+
this.processNextQueuedTask(workerWrapper);
|
|
150
|
+
};
|
|
151
|
+
const errorHandler = (error) => {
|
|
152
|
+
workerWrapper.worker.off("message", messageHandler);
|
|
153
|
+
workerWrapper.worker.off("error", errorHandler);
|
|
154
|
+
workerWrapper.busy = false;
|
|
155
|
+
this.activeTasks.delete(task);
|
|
156
|
+
task.reject(error);
|
|
157
|
+
};
|
|
158
|
+
const exitHandler = (exitCode) => {
|
|
159
|
+
workerWrapper.worker.off("message", messageHandler);
|
|
160
|
+
workerWrapper.worker.off("error", errorHandler);
|
|
161
|
+
workerWrapper.worker.off("exit", exitHandler);
|
|
162
|
+
workerWrapper.busy = false;
|
|
163
|
+
this.activeTasks.delete(task);
|
|
164
|
+
task.reject(
|
|
165
|
+
new Error(`Worker terminated unexpectedly with exit code ${exitCode}`)
|
|
166
|
+
);
|
|
167
|
+
if (this.isTerminating) return;
|
|
168
|
+
try {
|
|
169
|
+
const newWorker = new Worker(this.workerPath);
|
|
170
|
+
if (this.isTerminating) {
|
|
171
|
+
newWorker.terminate().catch(() => {
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
workerWrapper.worker = newWorker;
|
|
176
|
+
this.processNextQueuedTask(workerWrapper);
|
|
177
|
+
} catch (_error) {
|
|
178
|
+
const index = this.workers.indexOf(workerWrapper);
|
|
179
|
+
if (index > -1) this.workers.splice(index, 1);
|
|
180
|
+
if (this.workers.length === 0) {
|
|
181
|
+
this.rejectAllQueuedTasks(
|
|
182
|
+
new Error(
|
|
183
|
+
"All workers have died and could not be replaced - worker pool is non-functional"
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.processNextQueuedTask();
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
workerWrapper.worker.on("message", messageHandler);
|
|
192
|
+
workerWrapper.worker.on("error", errorHandler);
|
|
193
|
+
workerWrapper.worker.on("exit", exitHandler);
|
|
194
|
+
this.postTaskMessage(workerWrapper.worker, task);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Terminate all workers and reject all pending tasks.
|
|
198
|
+
*
|
|
199
|
+
* This pool is NOT designed to be reused after termination.
|
|
200
|
+
* Create a new instance if a fresh pool is needed.
|
|
201
|
+
*/
|
|
202
|
+
async terminate() {
|
|
203
|
+
this.isTerminating = true;
|
|
204
|
+
const terminationError = new Error(
|
|
205
|
+
"Worker pool is being terminated - task cancelled"
|
|
206
|
+
);
|
|
207
|
+
this.rejectAllQueuedTasks(terminationError);
|
|
208
|
+
this.rejectAllActiveTasks(terminationError);
|
|
209
|
+
const waiters = this.slotWaiters.splice(0);
|
|
210
|
+
for (const waiter of waiters) {
|
|
211
|
+
waiter.reject(terminationError);
|
|
212
|
+
}
|
|
213
|
+
const terminatePromises = this.workers.map((workerWrapper) => {
|
|
214
|
+
return new Promise((resolve) => {
|
|
215
|
+
const worker = workerWrapper.worker;
|
|
216
|
+
let resolved = false;
|
|
217
|
+
const doResolve = () => {
|
|
218
|
+
if (!resolved) {
|
|
219
|
+
resolved = true;
|
|
220
|
+
resolve();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
let timeoutId;
|
|
224
|
+
const exitHandler = () => {
|
|
225
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
226
|
+
doResolve();
|
|
227
|
+
};
|
|
228
|
+
worker.removeAllListeners("message");
|
|
229
|
+
worker.removeAllListeners("error");
|
|
230
|
+
worker.once("exit", exitHandler);
|
|
231
|
+
timeoutId = setTimeout(() => {
|
|
232
|
+
worker.removeListener("exit", exitHandler);
|
|
233
|
+
doResolve();
|
|
234
|
+
}, 2e3);
|
|
235
|
+
worker.terminate().catch(() => {
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
await Promise.all(terminatePromises);
|
|
240
|
+
this.workers = [];
|
|
241
|
+
this.queue = [];
|
|
242
|
+
this.inFlightCount = 0;
|
|
243
|
+
this.isTerminating = false;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
export {
|
|
247
|
+
WorkerPool
|
|
248
|
+
};
|
package/dist/node/testUtil.mjs
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// src/node/testUtil.ts
|
|
2
|
+
function makeChunk(n) {
|
|
3
|
+
const c = Buffer.alloc(n);
|
|
4
|
+
for (let i = 0; i < n; ++i) {
|
|
5
|
+
c[i] = i % 256;
|
|
6
|
+
}
|
|
7
|
+
return c;
|
|
8
|
+
}
|
|
5
9
|
export {
|
|
6
10
|
makeChunk
|
|
7
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shelby-protocol/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"types": "./dist/node/index.d.ts",
|
|
15
15
|
"import": "./dist/node/index.mjs"
|
|
16
16
|
},
|
|
17
|
+
"./node/parallel": {
|
|
18
|
+
"types": "./dist/node/parallel/index.d.ts",
|
|
19
|
+
"import": "./dist/node/parallel/index.mjs"
|
|
20
|
+
},
|
|
17
21
|
"./browser": {
|
|
18
22
|
"types": "./dist/browser/index.d.ts",
|
|
19
23
|
"import": "./dist/browser/index.mjs"
|
|
@@ -25,8 +29,8 @@
|
|
|
25
29
|
"graphql-tag": "^2.12.6",
|
|
26
30
|
"p-limit": "7.1.1",
|
|
27
31
|
"zod": "^3.24.3",
|
|
28
|
-
"@shelby-protocol/
|
|
29
|
-
"@shelby-protocol/
|
|
32
|
+
"@shelby-protocol/clay-codes": "0.0.2",
|
|
33
|
+
"@shelby-protocol/reed-solomon": "0.0.1"
|
|
30
34
|
},
|
|
31
35
|
"devDependencies": {
|
|
32
36
|
"@aptos-labs/ts-sdk": "5.2.1",
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
"vitest": "^3.1.2"
|
|
45
49
|
},
|
|
46
50
|
"peerDependencies": {
|
|
47
|
-
"@aptos-labs/ts-sdk": "^2.
|
|
51
|
+
"@aptos-labs/ts-sdk": "^5.2.1 || ^6.0.0"
|
|
48
52
|
},
|
|
49
53
|
"scripts": {
|
|
50
54
|
"lint": "biome check .",
|
|
@@ -54,8 +58,7 @@
|
|
|
54
58
|
"verify:config": "tsx scripts/verify-config.ts",
|
|
55
59
|
"build": "tsc --noEmit && (rimraf dist; tsup) && pnpm run verify:config",
|
|
56
60
|
"test": "vitest dev",
|
|
57
|
-
"test:once": "vitest run",
|
|
58
|
-
"test:integration": "vitest run --config vitest.integration.config.ts --reporter=verbose",
|
|
61
|
+
"test:once": "pnpm run build && vitest run",
|
|
59
62
|
"benchmark:erasure": "tsx benchmark/erasure.ts"
|
|
60
63
|
}
|
|
61
64
|
}
|
package/dist/chunk-3NRBHSMQ.mjs
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
normalizeAddress
|
|
3
|
-
} from "./chunk-UEZNZBJO.mjs";
|
|
4
|
-
|
|
5
|
-
// src/core/blobs.ts
|
|
6
|
-
var createBlobKey = (params) => {
|
|
7
|
-
return `@${normalizeAddress(params.account).toStringLongWithoutPrefix()}/${params.blobName}`;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
createBlobKey
|
|
12
|
-
};
|
package/dist/chunk-3PCG7PNP.mjs
DELETED
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ShelbyBlobClient
|
|
3
|
-
} from "./chunk-WJTVYLKW.mjs";
|
|
4
|
-
import {
|
|
5
|
-
defaultErasureCodingConfig
|
|
6
|
-
} from "./chunk-XRLHLAOW.mjs";
|
|
7
|
-
import {
|
|
8
|
-
ClayErasureCodingProvider
|
|
9
|
-
} from "./chunk-OGKZ575S.mjs";
|
|
10
|
-
import {
|
|
11
|
-
ShelbyMetadataClient
|
|
12
|
-
} from "./chunk-SSE4MFNN.mjs";
|
|
13
|
-
import {
|
|
14
|
-
ShelbyRPCClient
|
|
15
|
-
} from "./chunk-BKL7NCUB.mjs";
|
|
16
|
-
import {
|
|
17
|
-
getAptosConfig,
|
|
18
|
-
getShelbyRPCBaseUrl
|
|
19
|
-
} from "./chunk-IKRWBDG5.mjs";
|
|
20
|
-
import {
|
|
21
|
-
createBlobKey
|
|
22
|
-
} from "./chunk-3NRBHSMQ.mjs";
|
|
23
|
-
import {
|
|
24
|
-
generateCommitments
|
|
25
|
-
} from "./chunk-BXEVML7N.mjs";
|
|
26
|
-
import {
|
|
27
|
-
normalizeAddress
|
|
28
|
-
} from "./chunk-UEZNZBJO.mjs";
|
|
29
|
-
|
|
30
|
-
// src/core/clients/ShelbyClient.ts
|
|
31
|
-
import {
|
|
32
|
-
Aptos,
|
|
33
|
-
DEFAULT_TXN_TIMEOUT_SEC,
|
|
34
|
-
Network,
|
|
35
|
-
TransactionResponseType
|
|
36
|
-
} from "@aptos-labs/ts-sdk";
|
|
37
|
-
import pLimit from "p-limit";
|
|
38
|
-
var ShelbyClient = class {
|
|
39
|
-
/**
|
|
40
|
-
* The coordination client is used to interact with the Aptos blockchain which handles the commitments
|
|
41
|
-
* and metadata for blobs.
|
|
42
|
-
*/
|
|
43
|
-
coordination;
|
|
44
|
-
/**
|
|
45
|
-
* The metadata client is used for protocol-level metadata queries.
|
|
46
|
-
*/
|
|
47
|
-
metadata;
|
|
48
|
-
/**
|
|
49
|
-
* The RPC client is used to interact with the Shelby RPC node which can be responsible for storing,
|
|
50
|
-
* confirming, and retrieving blobs from the storage layer.
|
|
51
|
-
*
|
|
52
|
-
* If not provided, the default RPC client will be created.
|
|
53
|
-
*/
|
|
54
|
-
rpc;
|
|
55
|
-
/**
|
|
56
|
-
* The configuration for the Shelby client.
|
|
57
|
-
*/
|
|
58
|
-
config;
|
|
59
|
-
/**
|
|
60
|
-
* The Aptos client.
|
|
61
|
-
*
|
|
62
|
-
* If not provided, a default Aptos client will be created.
|
|
63
|
-
*/
|
|
64
|
-
aptos;
|
|
65
|
-
/**
|
|
66
|
-
* The erasure coding provider used for encoding/decoding operations.
|
|
67
|
-
* Lazily initialized on first use if not provided.
|
|
68
|
-
*/
|
|
69
|
-
_provider;
|
|
70
|
-
/**
|
|
71
|
-
* Creates a new ShelbyClient instance for interacting with the Shelby Protocol.
|
|
72
|
-
* This client combines blockchain operations (via coordination) and storage operations (via RPC).
|
|
73
|
-
*
|
|
74
|
-
* @param config - The client configuration object.
|
|
75
|
-
* @param config.aptos.config - The Aptos network configuration.
|
|
76
|
-
* @param config.shelby.rpc.baseUrl - The base URL of the Shelby RPC node (optional, defaults to devnet).
|
|
77
|
-
* @param config.shelby.indexer - The indexer configuration for GraphQL queries.
|
|
78
|
-
* @param provider - Optional erasure coding provider for encoding/decoding operations.
|
|
79
|
-
* If not provided, a ClayErasureCodingProvider will be created on first use.
|
|
80
|
-
* Pass a shared provider to reuse across multiple clients.
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```typescript
|
|
84
|
-
* // Basic usage (provider created automatically)
|
|
85
|
-
* const client = new ShelbyClient({
|
|
86
|
-
* network: Network.SHELBYNET,
|
|
87
|
-
* });
|
|
88
|
-
*
|
|
89
|
-
* // Advanced: Share provider across multiple clients
|
|
90
|
-
* const provider = await ClayErasureCodingProvider.create();
|
|
91
|
-
* const mainnetClient = new ShelbyClient(mainnetConfig, provider);
|
|
92
|
-
* const devnetClient = new ShelbyClient(devnetConfig, provider);
|
|
93
|
-
* ```
|
|
94
|
-
*/
|
|
95
|
-
constructor(config, provider) {
|
|
96
|
-
this.config = config;
|
|
97
|
-
this.aptos = new Aptos(getAptosConfig(config));
|
|
98
|
-
this.coordination = new ShelbyBlobClient(config);
|
|
99
|
-
this.metadata = new ShelbyMetadataClient(config);
|
|
100
|
-
this.rpc = new ShelbyRPCClient(config);
|
|
101
|
-
this._provider = provider;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Get the erasure coding provider, creating it if necessary.
|
|
105
|
-
* This allows lazy initialization for users who don't provide a provider.
|
|
106
|
-
*/
|
|
107
|
-
async getProvider() {
|
|
108
|
-
if (!this._provider) {
|
|
109
|
-
this._provider = await ClayErasureCodingProvider.create(
|
|
110
|
-
defaultErasureCodingConfig()
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
return this._provider;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* The base URL for the Shelby RPC node.
|
|
117
|
-
*/
|
|
118
|
-
get baseUrl() {
|
|
119
|
-
return getShelbyRPCBaseUrl(this.config);
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Uploads a blob to the Shelby network.
|
|
123
|
-
* This method handles the complete upload flow including commitment generation,
|
|
124
|
-
* blockchain registration, and storage upload.
|
|
125
|
-
*
|
|
126
|
-
* Note: This method accepts only `Uint8Array` and buffers the entire blob in memory.
|
|
127
|
-
* For streaming uploads of large files (e.g. >2 GiB), orchestrate the steps manually
|
|
128
|
-
* using `generateCommitments()`, `coordination.registerBlob()`, and `rpc.putBlob()`
|
|
129
|
-
* with a `ReadableStream`.
|
|
130
|
-
*
|
|
131
|
-
* @param params.blobData - The raw data to upload as a Uint8Array.
|
|
132
|
-
* @param params.signer - The account that signs and pays for the transaction.
|
|
133
|
-
* @param params.blobName - The name/path of the blob (e.g. "folder/file.txt").
|
|
134
|
-
* @param params.expirationMicros - The expiration time in microseconds since Unix epoch.
|
|
135
|
-
* @param params.options - Optional upload configuration.
|
|
136
|
-
* @param params.options.chunksetSizeBytes - Custom chunkset size.
|
|
137
|
-
* @param params.options.build - Additional Aptos transaction options.
|
|
138
|
-
*
|
|
139
|
-
* @returns The transaction and generated blob commitments (when implemented).
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* ```typescript
|
|
143
|
-
* await client.upload({
|
|
144
|
-
* blobData: Buffer.from("Hello, World!"),
|
|
145
|
-
* signer: account,
|
|
146
|
-
* blobName: "hello.txt",
|
|
147
|
-
* expirationMicros: Date.now() * 1000 + 86400_000_000 // 24 hours from now
|
|
148
|
-
* });
|
|
149
|
-
* ```
|
|
150
|
-
*/
|
|
151
|
-
async upload(params) {
|
|
152
|
-
const existingBlobMetadata = await this.coordination.getBlobMetadata({
|
|
153
|
-
account: params.signer.accountAddress,
|
|
154
|
-
name: params.blobName
|
|
155
|
-
});
|
|
156
|
-
if (!existingBlobMetadata) {
|
|
157
|
-
const provider = await this.getProvider();
|
|
158
|
-
const blobCommitments = await generateCommitments(
|
|
159
|
-
provider,
|
|
160
|
-
params.blobData
|
|
161
|
-
);
|
|
162
|
-
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.registerBlob({
|
|
163
|
-
account: params.signer,
|
|
164
|
-
blobName: params.blobName,
|
|
165
|
-
blobMerkleRoot: blobCommitments.blob_merkle_root,
|
|
166
|
-
size: params.blobData.length,
|
|
167
|
-
expirationMicros: params.expirationMicros,
|
|
168
|
-
config: provider.config,
|
|
169
|
-
options: params.options
|
|
170
|
-
});
|
|
171
|
-
await this.coordination.aptos.waitForTransaction({
|
|
172
|
-
transactionHash: pendingRegisterBlobTransaction.hash
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
await this.rpc.putBlob({
|
|
176
|
-
account: params.signer.accountAddress,
|
|
177
|
-
blobName: params.blobName,
|
|
178
|
-
blobData: params.blobData
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Uploads a batch of blobs to the Shelby network.
|
|
183
|
-
* This method handles the complete upload flow including commitment generation,
|
|
184
|
-
* blockchain registration, and storage upload.
|
|
185
|
-
*
|
|
186
|
-
* Note: This method accepts only `Uint8Array` and buffers each blob in memory.
|
|
187
|
-
* For streaming uploads of large files, orchestrate the steps manually using
|
|
188
|
-
* `generateCommitments()`, `coordination.registerBlob()`, and `rpc.putBlob()`
|
|
189
|
-
* with a `ReadableStream`.
|
|
190
|
-
*
|
|
191
|
-
* @param params.blobs - The blobs to upload.
|
|
192
|
-
* @param params.blobs.blobData - The raw data to upload as a Uint8Array.
|
|
193
|
-
* @param params.blobs.blobName - The name/path of the blob (e.g. "folder/file.txt").
|
|
194
|
-
* @param params.expirationMicros - The expiration time in microseconds since Unix epoch.
|
|
195
|
-
* @param params.signer - The account that signs and pays for the transaction.
|
|
196
|
-
* @param params.options - Optional upload configuration.
|
|
197
|
-
* @param params.options.chunksetSizeBytes - Custom chunkset size.
|
|
198
|
-
* @param params.options.build - Additional Aptos transaction options.
|
|
199
|
-
*
|
|
200
|
-
* @returns The transaction and generated blob commitments (when implemented).
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```typescript
|
|
204
|
-
* await client.batchUpload({
|
|
205
|
-
* blobs: [
|
|
206
|
-
* { blobData: Buffer.from("Hello, World!"), blobName: "hello.txt" },
|
|
207
|
-
* { blobData: Buffer.from("Hello, World 2!"), blobName: "hello2.txt" },
|
|
208
|
-
* ],
|
|
209
|
-
* expirationMicros: Date.now() * 1000 + 86400_000_000 // 24 hours from now
|
|
210
|
-
* });
|
|
211
|
-
* ```
|
|
212
|
-
*/
|
|
213
|
-
async batchUpload(params) {
|
|
214
|
-
const existingBlobs = await this.coordination.getBlobs({
|
|
215
|
-
where: {
|
|
216
|
-
blob_name: {
|
|
217
|
-
_in: params.blobs.map(
|
|
218
|
-
(blob) => createBlobKey({
|
|
219
|
-
account: params.signer.accountAddress,
|
|
220
|
-
blobName: blob.blobName
|
|
221
|
-
})
|
|
222
|
-
)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
const blobsToRegister = params.blobs.filter(
|
|
227
|
-
(blob) => !existingBlobs.some(
|
|
228
|
-
(existingBlob) => existingBlob.name === createBlobKey({
|
|
229
|
-
account: params.signer.accountAddress,
|
|
230
|
-
blobName: blob.blobName
|
|
231
|
-
})
|
|
232
|
-
)
|
|
233
|
-
);
|
|
234
|
-
if (blobsToRegister.length > 0) {
|
|
235
|
-
const provider = await this.getProvider();
|
|
236
|
-
const blobCommitments = await Promise.all(
|
|
237
|
-
blobsToRegister.map(
|
|
238
|
-
async (blob) => generateCommitments(provider, blob.blobData)
|
|
239
|
-
)
|
|
240
|
-
);
|
|
241
|
-
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.batchRegisterBlobs({
|
|
242
|
-
account: params.signer,
|
|
243
|
-
expirationMicros: params.expirationMicros,
|
|
244
|
-
blobs: blobsToRegister.map((blob, index) => ({
|
|
245
|
-
blobName: blob.blobName,
|
|
246
|
-
blobSize: blob.blobData.length,
|
|
247
|
-
blobMerkleRoot: blobCommitments[index].blob_merkle_root
|
|
248
|
-
})),
|
|
249
|
-
config: provider.config,
|
|
250
|
-
options: params.options
|
|
251
|
-
});
|
|
252
|
-
await this.coordination.aptos.waitForTransaction({
|
|
253
|
-
transactionHash: pendingRegisterBlobTransaction.hash,
|
|
254
|
-
options: { waitForIndexer: true }
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
const limit = pLimit(3);
|
|
258
|
-
await Promise.all(
|
|
259
|
-
params.blobs.map(
|
|
260
|
-
(blob) => limit(
|
|
261
|
-
() => this.rpc.putBlob({
|
|
262
|
-
account: params.signer.accountAddress,
|
|
263
|
-
blobName: blob.blobName,
|
|
264
|
-
blobData: blob.blobData
|
|
265
|
-
})
|
|
266
|
-
)
|
|
267
|
-
)
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Downloads a blob from the Shelby RPC node.
|
|
272
|
-
*
|
|
273
|
-
* @param params.account - The account namespace the blob is stored in (e.g. "0x1")
|
|
274
|
-
* @param params.blobName - The name of the blob (e.g. "foo/bar")
|
|
275
|
-
* @param params.range - The range of the blob to download.
|
|
276
|
-
*
|
|
277
|
-
* @returns A `ShelbyBlob` object containing the blob data.
|
|
278
|
-
*
|
|
279
|
-
* @example
|
|
280
|
-
* ```typescript
|
|
281
|
-
* const blob = await client.download({
|
|
282
|
-
* account,
|
|
283
|
-
* blobName: "foo/bar.txt",
|
|
284
|
-
* });
|
|
285
|
-
* ```
|
|
286
|
-
*/
|
|
287
|
-
async download(params) {
|
|
288
|
-
return await this.rpc.getBlob(params);
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
*
|
|
292
|
-
* Funds an account with ShelbyUSD tokens.
|
|
293
|
-
*
|
|
294
|
-
* @param params.address - The address to fund.
|
|
295
|
-
* @param params.amount - The amount to fund.
|
|
296
|
-
* @returns The transaction hash of the funded account.
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* ```typescript
|
|
300
|
-
* const hash = await client.fundAccountWithShelbyUSD({
|
|
301
|
-
* address: "0x1",
|
|
302
|
-
* amount: 100000000,
|
|
303
|
-
* });
|
|
304
|
-
* ```
|
|
305
|
-
*/
|
|
306
|
-
async fundAccountWithShelbyUSD(params) {
|
|
307
|
-
if (this.config.network === Network.TESTNET) {
|
|
308
|
-
throw new Error(
|
|
309
|
-
`ShelbyUSD cannot be minted programmatically on ${Network.TESTNET}. Please use the faucet at https://docs.shelby.xyz/apis/faucet/shelbyusd instead.`
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
const { address, amount } = params;
|
|
313
|
-
try {
|
|
314
|
-
const faucet = this.config.faucet?.baseUrl ?? "https://faucet.shelbynet.shelby.xyz/fund?asset=shelbyusd";
|
|
315
|
-
const authToken = this.config.faucet?.authToken;
|
|
316
|
-
const response = await fetch(`${faucet}`, {
|
|
317
|
-
method: "POST",
|
|
318
|
-
body: JSON.stringify({
|
|
319
|
-
address: normalizeAddress(address).toString(),
|
|
320
|
-
amount
|
|
321
|
-
}),
|
|
322
|
-
headers: {
|
|
323
|
-
"Content-Type": "application/json",
|
|
324
|
-
...authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
if (!response.ok) {
|
|
328
|
-
const errorBody = await response.text();
|
|
329
|
-
throw new Error(`Failed to fund account: ${errorBody}`);
|
|
330
|
-
}
|
|
331
|
-
const json = await response.json();
|
|
332
|
-
const res = await this.aptos.waitForTransaction({
|
|
333
|
-
transactionHash: json.txn_hashes[0],
|
|
334
|
-
options: {
|
|
335
|
-
timeoutSecs: DEFAULT_TXN_TIMEOUT_SEC,
|
|
336
|
-
checkSuccess: true
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
if (res.type === TransactionResponseType.User) {
|
|
340
|
-
return res.hash;
|
|
341
|
-
}
|
|
342
|
-
throw new Error(
|
|
343
|
-
`Unexpected transaction received for fund account: ${res.type}`
|
|
344
|
-
);
|
|
345
|
-
} catch (error) {
|
|
346
|
-
throw new Error(`Failed to fund account: ${error}`);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Fund an account with APT tokens
|
|
351
|
-
*
|
|
352
|
-
* @param params.address - The address to fund
|
|
353
|
-
* @param params.amount - The amount to fund
|
|
354
|
-
* @returns The transaction hash of the funded account
|
|
355
|
-
*
|
|
356
|
-
* @example
|
|
357
|
-
* ```typescript
|
|
358
|
-
* const hash = await client.fundAccountWithAPT({
|
|
359
|
-
* address: "0x1",
|
|
360
|
-
* amount: 100000000,
|
|
361
|
-
* });
|
|
362
|
-
* ```
|
|
363
|
-
*/
|
|
364
|
-
async fundAccountWithAPT(params) {
|
|
365
|
-
const transaction = await this.aptos.fundAccount({
|
|
366
|
-
accountAddress: params.address,
|
|
367
|
-
amount: params.amount
|
|
368
|
-
});
|
|
369
|
-
return transaction.hash;
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
export {
|
|
374
|
-
ShelbyClient
|
|
375
|
-
};
|