@shelby-protocol/sdk 0.0.9 → 0.2.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/dist/browser/index.d.ts +17 -10
- package/dist/browser/index.mjs +89 -28
- package/dist/{chunk-XWAPNLU6.mjs → chunk-2WEX3K7C.mjs} +6 -4
- package/dist/chunk-4MG4XGY4.mjs +91 -0
- package/dist/{chunk-SEXQTDX6.mjs → chunk-4ZOFT75Q.mjs} +16 -2
- package/dist/{chunk-BTHSKDJR.mjs → chunk-7PN65RDX.mjs} +44 -10
- package/dist/chunk-AABBONAF.mjs +34 -0
- package/dist/{chunk-ZPW742E7.mjs → chunk-AUQDI5BS.mjs} +17 -2
- package/dist/{chunk-HFGEQP5N.mjs → chunk-CGYJLKBU.mjs} +4 -4
- package/dist/chunk-CQ6QPIZK.mjs +37 -0
- package/dist/{chunk-VRLIOKWG.mjs → chunk-D6GQHO6G.mjs} +5 -1
- package/dist/chunk-E5QCRTBU.mjs +493 -0
- package/dist/chunk-HPPMI7DC.mjs +56 -0
- package/dist/chunk-IE6LYVIA.mjs +26 -0
- package/dist/{chunk-67F5YZ25.mjs → chunk-JTXYKO3U.mjs} +10 -0
- package/dist/{chunk-WJKSPJSS.mjs → chunk-KJ24NKPH.mjs} +46 -0
- package/dist/{chunk-WBFEX7OM.mjs → chunk-MV6FNYAU.mjs} +31 -7
- package/dist/{chunk-PZF2VTGP.mjs → chunk-NHWWORCH.mjs} +3 -1
- package/dist/{chunk-NLPIHQ7K.mjs → chunk-OGKZ575S.mjs} +6 -19
- package/dist/{chunk-5I3MBJGN.mjs → chunk-PJVWGMVI.mjs} +164 -35
- package/dist/{chunk-7UVMDCCR.mjs → chunk-SRV4YWFH.mjs} +232 -47
- package/dist/chunk-W37FZSMA.mjs +83 -0
- package/dist/chunk-WTICJPDB.mjs +0 -0
- package/dist/chunk-Z4FZ7W6L.mjs +39 -0
- package/dist/{chunk-QFWQ7FIC.mjs → chunk-ZEDD2MPU.mjs} +1 -1
- package/dist/{clay-codes-pdZFxI_B.d.ts → clay-codes-DHP-bYcP.d.ts} +6 -2
- package/dist/core/blobs.d.ts +2 -0
- package/dist/core/chunk.d.ts +10 -1
- package/dist/core/chunk.mjs +2 -2
- package/dist/core/clients/ShelbyBlobClient.d.ts +165 -12
- package/dist/core/clients/ShelbyBlobClient.mjs +13 -11
- package/dist/core/clients/ShelbyClient.d.ts +21 -4
- package/dist/core/clients/ShelbyClient.mjs +17 -14
- package/dist/core/clients/ShelbyClientConfig.d.ts +7 -2
- package/dist/{node → core}/clients/ShelbyMetadataClient.d.ts +3 -3
- package/dist/core/clients/ShelbyMetadataClient.mjs +9 -0
- package/dist/core/clients/ShelbyMicropaymentChannelClient.d.ts +349 -0
- package/dist/core/clients/ShelbyMicropaymentChannelClient.mjs +16 -0
- package/dist/core/clients/ShelbyPlacementGroupClient.d.ts +73 -0
- package/dist/core/clients/ShelbyPlacementGroupClient.mjs +11 -0
- package/dist/core/clients/ShelbyRPCClient.d.ts +30 -4
- package/dist/core/clients/ShelbyRPCClient.mjs +8 -8
- package/dist/core/clients/index.d.ts +11 -5
- package/dist/core/clients/index.mjs +35 -15
- package/dist/core/clients/utils.d.ts +54 -0
- package/dist/core/clients/utils.mjs +1 -1
- package/dist/core/commitments.d.ts +6 -2
- package/dist/core/commitments.mjs +5 -3
- package/dist/core/constants.d.ts +18 -3
- package/dist/core/constants.mjs +5 -1
- package/dist/core/erasure/clay-codes.d.ts +1 -1
- package/dist/core/erasure/clay-codes.mjs +5 -5
- package/dist/core/erasure/constants.d.ts +15 -3
- package/dist/core/erasure/constants.mjs +3 -1
- package/dist/core/erasure/default.d.ts +5 -2
- package/dist/core/erasure/default.mjs +12 -6
- package/dist/core/erasure/index.d.ts +3 -3
- package/dist/core/erasure/index.mjs +15 -7
- 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 +1 -1
- package/dist/core/erasure/utils.d.ts +1 -1
- package/dist/core/errors.d.ts +58 -0
- package/dist/core/errors.mjs +15 -0
- package/dist/core/index.d.ts +17 -10
- package/dist/core/index.mjs +89 -28
- package/dist/core/layout.d.ts +5 -16
- package/dist/core/layout.mjs +3 -9
- package/dist/core/networks.d.ts +1 -1
- package/dist/core/networks.mjs +1 -1
- package/dist/core/operations/generated/sdk.d.ts +207 -17
- package/dist/core/operations/generated/sdk.mjs +7 -1
- package/dist/core/operations/index.d.ts +9 -3
- package/dist/core/operations/index.mjs +10 -4
- package/dist/core/rpc-responses.d.ts +69 -0
- package/dist/core/rpc-responses.mjs +15 -0
- package/dist/core/types/blobs.d.ts +8 -4
- package/dist/core/types/encodings.d.ts +1 -1
- package/dist/core/types/index.d.ts +4 -2
- package/dist/core/types/index.mjs +12 -2
- package/dist/core/types/payments.d.ts +94 -0
- package/dist/core/types/payments.mjs +9 -0
- package/dist/core/types/placement_groups.d.ts +30 -1
- package/dist/core/types/placement_groups.mjs +1 -0
- package/dist/core/types/storage_providers.d.ts +32 -2
- package/dist/node/clients/ShelbyNodeClient.d.ts +9 -6
- package/dist/node/clients/ShelbyNodeClient.mjs +18 -15
- package/dist/node/clients/index.d.ts +7 -6
- package/dist/node/clients/index.mjs +19 -17
- package/dist/node/index.d.ts +17 -11
- package/dist/node/index.mjs +91 -34
- package/package.json +3 -2
- package/dist/chunk-CPNZAQVY.mjs +0 -29
- package/dist/chunk-GY5DCVVL.mjs +0 -86
- package/dist/chunk-RBFWGDMY.mjs +0 -30
- package/dist/node/clients/ShelbyMetadataClient.mjs +0 -9
- /package/dist/{chunk-DJJD2AXO.mjs → chunk-AD2G3QYD.mjs} +0 -0
- /package/dist/{chunk-MWDW4ROU.mjs → chunk-EM67QTMR.mjs} +0 -0
- /package/dist/{chunk-RNXGC54D.mjs → chunk-QQ57OGQ2.mjs} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/core/chunk.ts
|
|
2
2
|
var ChunkSizeScheme = /* @__PURE__ */ ((ChunkSizeScheme2) => {
|
|
3
3
|
ChunkSizeScheme2["ChunkSet10MiB_Chunk1MiB"] = "ChunkSet10MiB_Chunk1MiB";
|
|
4
|
+
ChunkSizeScheme2["ChunkSet2MiB_Chunk1MiB"] = "ChunkSet2MiB_Chunk1MiB";
|
|
4
5
|
return ChunkSizeScheme2;
|
|
5
6
|
})(ChunkSizeScheme || {});
|
|
6
7
|
var CHUNK_SIZE_PARAMS = {
|
|
@@ -9,6 +10,12 @@ var CHUNK_SIZE_PARAMS = {
|
|
|
9
10
|
chunkSizeBytes: 1 * 1024 * 1024,
|
|
10
11
|
// 10MiB
|
|
11
12
|
chunksetSizeBytes: 10 * 1024 * 1024
|
|
13
|
+
},
|
|
14
|
+
["ChunkSet2MiB_Chunk1MiB" /* ChunkSet2MiB_Chunk1MiB */]: {
|
|
15
|
+
// 1MiB
|
|
16
|
+
chunkSizeBytes: 1 * 1024 * 1024,
|
|
17
|
+
// 2MiB
|
|
18
|
+
chunksetSizeBytes: 2 * 1024 * 1024
|
|
12
19
|
}
|
|
13
20
|
};
|
|
14
21
|
var DEFAULT_CHUNK_SIZE_BYTES = CHUNK_SIZE_PARAMS["ChunkSet10MiB_Chunk1MiB" /* ChunkSet10MiB_Chunk1MiB */].chunkSizeBytes;
|
|
@@ -16,6 +23,9 @@ var DEFAULT_CHUNKSET_SIZE_BYTES = CHUNK_SIZE_PARAMS["ChunkSet10MiB_Chunk1MiB" /*
|
|
|
16
23
|
var ERASURE_CODE_AND_CHUNK_MAPPING = {
|
|
17
24
|
["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */]: {
|
|
18
25
|
...CHUNK_SIZE_PARAMS.ChunkSet10MiB_Chunk1MiB
|
|
26
|
+
},
|
|
27
|
+
["ClayCode_4Total_2Data_3Helper" /* ClayCode_4Total_2Data_3Helper */]: {
|
|
28
|
+
...CHUNK_SIZE_PARAMS.ChunkSet2MiB_Chunk1MiB
|
|
19
29
|
}
|
|
20
30
|
};
|
|
21
31
|
|
|
@@ -105,6 +105,40 @@ var GetBlobActivitiesCountDocument = gql`
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
`;
|
|
108
|
+
var GetPlacementGroupSlotsDocument = gql`
|
|
109
|
+
query getPlacementGroupSlots($where: placement_group_slots_bool_exp, $orderBy: [placement_group_slots_order_by!], $limit: Int, $offset: Int) {
|
|
110
|
+
placement_group_slots(
|
|
111
|
+
where: $where
|
|
112
|
+
order_by: $orderBy
|
|
113
|
+
limit: $limit
|
|
114
|
+
offset: $offset
|
|
115
|
+
) {
|
|
116
|
+
placement_group
|
|
117
|
+
slot_index
|
|
118
|
+
storage_provider
|
|
119
|
+
status
|
|
120
|
+
updated_at
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
var GetPlacementGroupSlotsCountDocument = gql`
|
|
125
|
+
query getPlacementGroupSlotsCount($where: placement_group_slots_bool_exp) {
|
|
126
|
+
placement_group_slots_aggregate(where: $where) {
|
|
127
|
+
aggregate {
|
|
128
|
+
count
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
var GetProcessorStatusDocument = gql`
|
|
134
|
+
query getProcessorStatus {
|
|
135
|
+
processor_status {
|
|
136
|
+
last_success_version
|
|
137
|
+
last_transaction_timestamp
|
|
138
|
+
last_updated
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
108
142
|
var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
|
|
109
143
|
function getSdk(client, withWrapper = defaultWrapper) {
|
|
110
144
|
return {
|
|
@@ -119,6 +153,15 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
119
153
|
},
|
|
120
154
|
getBlobActivitiesCount(variables, requestHeaders, signal) {
|
|
121
155
|
return withWrapper((wrappedRequestHeaders) => client.request({ document: GetBlobActivitiesCountDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getBlobActivitiesCount", "query", variables);
|
|
156
|
+
},
|
|
157
|
+
getPlacementGroupSlots(variables, requestHeaders, signal) {
|
|
158
|
+
return withWrapper((wrappedRequestHeaders) => client.request({ document: GetPlacementGroupSlotsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getPlacementGroupSlots", "query", variables);
|
|
159
|
+
},
|
|
160
|
+
getPlacementGroupSlotsCount(variables, requestHeaders, signal) {
|
|
161
|
+
return withWrapper((wrappedRequestHeaders) => client.request({ document: GetPlacementGroupSlotsCountDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getPlacementGroupSlotsCount", "query", variables);
|
|
162
|
+
},
|
|
163
|
+
getProcessorStatus(variables, requestHeaders, signal) {
|
|
164
|
+
return withWrapper((wrappedRequestHeaders) => client.request({ document: GetProcessorStatusDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getProcessorStatus", "query", variables);
|
|
122
165
|
}
|
|
123
166
|
};
|
|
124
167
|
}
|
|
@@ -134,5 +177,8 @@ export {
|
|
|
134
177
|
GetBlobActivitiesDocument,
|
|
135
178
|
GetBlobsCountDocument,
|
|
136
179
|
GetBlobActivitiesCountDocument,
|
|
180
|
+
GetPlacementGroupSlotsDocument,
|
|
181
|
+
GetPlacementGroupSlotsCountDocument,
|
|
182
|
+
GetProcessorStatusDocument,
|
|
137
183
|
getSdk
|
|
138
184
|
};
|
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAptosConfig
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-AABBONAF.mjs";
|
|
4
4
|
import {
|
|
5
5
|
SHELBY_DEPLOYER
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4ZOFT75Q.mjs";
|
|
7
7
|
|
|
8
|
-
// src/
|
|
8
|
+
// src/core/clients/ShelbyMetadataClient.ts
|
|
9
9
|
import {
|
|
10
10
|
AccountAddress,
|
|
11
11
|
Aptos,
|
|
12
12
|
Hex
|
|
13
13
|
} from "@aptos-labs/ts-sdk";
|
|
14
|
+
function parseStorageProviderState(raw) {
|
|
15
|
+
switch (raw.__variant__) {
|
|
16
|
+
case "Active":
|
|
17
|
+
return {
|
|
18
|
+
variant: "Active",
|
|
19
|
+
quota: raw.quota.value,
|
|
20
|
+
stakeAtStartOfStakingEpoch: raw.stake_at_start_of_staking_epoch,
|
|
21
|
+
faulty: raw.faulty,
|
|
22
|
+
leaving: raw.leaving
|
|
23
|
+
};
|
|
24
|
+
case "Waitlisted":
|
|
25
|
+
return {
|
|
26
|
+
variant: "Waitlisted"
|
|
27
|
+
};
|
|
28
|
+
case "Frozen":
|
|
29
|
+
return {
|
|
30
|
+
variant: "Frozen",
|
|
31
|
+
frozenReason: raw.frozen_reason,
|
|
32
|
+
frozenFrom: raw.frozen_from,
|
|
33
|
+
frozenTill: raw.frozen_till
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
14
37
|
var ShelbyMetadataClient = class {
|
|
15
38
|
aptos;
|
|
16
39
|
deployer;
|
|
@@ -45,7 +68,7 @@ var ShelbyMetadataClient = class {
|
|
|
45
68
|
try {
|
|
46
69
|
const rawMetadata = await this.aptos.view({
|
|
47
70
|
payload: {
|
|
48
|
-
function: `${this.deployer.toString()}::
|
|
71
|
+
function: `${this.deployer.toString()}::storage_provider_registry::get_all_storage_providers`,
|
|
49
72
|
functionArguments: []
|
|
50
73
|
}
|
|
51
74
|
});
|
|
@@ -55,7 +78,8 @@ var ShelbyMetadataClient = class {
|
|
|
55
78
|
ipAddress: provider.ip_address,
|
|
56
79
|
port: provider.port,
|
|
57
80
|
blsPublicKey: Hex.fromHexInput(provider.bls_public_key).toUint8Array(),
|
|
58
|
-
failureDomain: provider.failure_domain
|
|
81
|
+
failureDomain: provider.failure_domain,
|
|
82
|
+
state: parseStorageProviderState(provider.state)
|
|
59
83
|
}));
|
|
60
84
|
} catch (error) {
|
|
61
85
|
if (error instanceof Error && // Depending on the network, the error message may show up differently.
|
|
@@ -79,14 +103,14 @@ var ShelbyMetadataClient = class {
|
|
|
79
103
|
try {
|
|
80
104
|
const pgSizeMetadata = await this.aptos.view({
|
|
81
105
|
payload: {
|
|
82
|
-
function: `${this.deployer.toString()}::
|
|
106
|
+
function: `${this.deployer.toString()}::placement_group_registry::get_number_of_placement_groups`,
|
|
83
107
|
functionArguments: []
|
|
84
108
|
}
|
|
85
109
|
});
|
|
86
110
|
const finalPlacementGroupIndex = pgSizeMetadata[0] - 1;
|
|
87
111
|
const addressMetadataArray = await this.aptos.view({
|
|
88
112
|
payload: {
|
|
89
|
-
function: `${this.deployer.toString()}::
|
|
113
|
+
function: `${this.deployer.toString()}::placement_group_registry::get_placement_group_addresses`,
|
|
90
114
|
functionArguments: [0, finalPlacementGroupIndex]
|
|
91
115
|
}
|
|
92
116
|
});
|
|
@@ -9,6 +9,7 @@ var ReedSolomonErasureCodingProvider = class {
|
|
|
9
9
|
const erasure_k = options?.erasure_k ?? DEFAULT_ERASURE_K;
|
|
10
10
|
const erasure_n = options?.erasure_n ?? DEFAULT_ERASURE_N;
|
|
11
11
|
const chunkSizeBytes = options?.chunkSizeBytes ?? DEFAULT_CHUNK_SIZE_BYTES;
|
|
12
|
+
const enumIndex = -1;
|
|
12
13
|
if (erasure_k <= 0)
|
|
13
14
|
throw new Error("erasure_k (number of data chunks) must be > 0");
|
|
14
15
|
if (erasure_n <= erasure_k)
|
|
@@ -19,7 +20,8 @@ var ReedSolomonErasureCodingProvider = class {
|
|
|
19
20
|
this.config = {
|
|
20
21
|
erasure_n,
|
|
21
22
|
erasure_k,
|
|
22
|
-
chunkSizeBytes
|
|
23
|
+
chunkSizeBytes,
|
|
24
|
+
enumIndex
|
|
23
25
|
};
|
|
24
26
|
}
|
|
25
27
|
encode(data) {
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_CHUNK_SIZE_BYTES
|
|
3
|
-
} from "./chunk-67F5YZ25.mjs";
|
|
4
|
-
import {
|
|
5
|
-
DEFAULT_ERASURE_D,
|
|
6
|
-
DEFAULT_ERASURE_K,
|
|
7
|
-
DEFAULT_ERASURE_N
|
|
8
|
-
} from "./chunk-ZPW742E7.mjs";
|
|
9
|
-
|
|
10
1
|
// src/core/erasure/clay-codes.ts
|
|
11
2
|
import {
|
|
12
3
|
createDecoder,
|
|
@@ -27,13 +18,7 @@ var ClayErasureCodingProvider = class _ClayErasureCodingProvider {
|
|
|
27
18
|
/**
|
|
28
19
|
* Static factory method to create an initialized ClayErasureCodingProvider
|
|
29
20
|
*/
|
|
30
|
-
static async create(
|
|
31
|
-
const config = buildClayConfig({
|
|
32
|
-
erasure_n: options?.erasure_n ?? DEFAULT_ERASURE_N,
|
|
33
|
-
erasure_k: options?.erasure_k ?? DEFAULT_ERASURE_K,
|
|
34
|
-
erasure_d: options?.erasure_d ?? DEFAULT_ERASURE_D,
|
|
35
|
-
chunkSizeBytes: options?.chunkSizeBytes ?? DEFAULT_CHUNK_SIZE_BYTES
|
|
36
|
-
});
|
|
21
|
+
static async create(config) {
|
|
37
22
|
const provider = new _ClayErasureCodingProvider(config);
|
|
38
23
|
[provider.encoderCache, provider.decoderCache] = await Promise.all([
|
|
39
24
|
createEncoder({
|
|
@@ -118,7 +103,7 @@ var ClayErasureCodingProvider = class _ClayErasureCodingProvider {
|
|
|
118
103
|
}
|
|
119
104
|
};
|
|
120
105
|
function buildClayConfig(input) {
|
|
121
|
-
const { erasure_n, erasure_k, erasure_d, chunkSizeBytes } = input;
|
|
106
|
+
const { erasure_n, erasure_k, erasure_d, chunkSizeBytes, enumIndex } = input;
|
|
122
107
|
if (erasure_n <= 0)
|
|
123
108
|
throw new Error("erasure_n (total number of chunks) must be > 0");
|
|
124
109
|
if (erasure_k <= 0)
|
|
@@ -140,10 +125,12 @@ function buildClayConfig(input) {
|
|
|
140
125
|
erasure_n,
|
|
141
126
|
erasure_k,
|
|
142
127
|
erasure_d,
|
|
143
|
-
chunkSizeBytes
|
|
128
|
+
chunkSizeBytes,
|
|
129
|
+
enumIndex
|
|
144
130
|
};
|
|
145
131
|
}
|
|
146
132
|
|
|
147
133
|
export {
|
|
148
|
-
ClayErasureCodingProvider
|
|
134
|
+
ClayErasureCodingProvider,
|
|
135
|
+
buildClayConfig
|
|
149
136
|
};
|
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
StaleChannelStateError
|
|
3
|
+
} from "./chunk-4MG4XGY4.mjs";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
} from "./chunk-
|
|
5
|
+
getShelbyIndexerClient
|
|
6
|
+
} from "./chunk-CGYJLKBU.mjs";
|
|
7
7
|
import {
|
|
8
8
|
sleep
|
|
9
9
|
} from "./chunk-I6NG5GNL.mjs";
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
StaleMicropaymentErrorResponseSchema,
|
|
12
|
+
StartMultipartUploadResponseSchema
|
|
13
|
+
} from "./chunk-IE6LYVIA.mjs";
|
|
14
|
+
import {
|
|
15
|
+
buildRequestUrl,
|
|
16
|
+
readInChunks
|
|
12
17
|
} from "./chunk-4JZO2D7T.mjs";
|
|
13
18
|
import {
|
|
14
19
|
NetworkToShelbyRPCBaseUrl
|
|
15
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-4ZOFT75Q.mjs";
|
|
21
|
+
import {
|
|
22
|
+
BlobNameSchema
|
|
23
|
+
} from "./chunk-Z4FZ7W6L.mjs";
|
|
16
24
|
|
|
17
25
|
// src/core/clients/ShelbyRPCClient.ts
|
|
18
26
|
import { AccountAddress } from "@aptos-labs/ts-sdk";
|
|
27
|
+
var MICROPAYMENT_HEADER = "X-Shelby-Micropayment";
|
|
19
28
|
function encodeURIComponentKeepSlashes(str) {
|
|
20
29
|
return encodeURIComponent(str).replace(/%2F/g, "/");
|
|
21
30
|
}
|
|
31
|
+
function validateTotalBytes(totalBytes) {
|
|
32
|
+
if (!Number.isInteger(totalBytes) || totalBytes < 0) {
|
|
33
|
+
throw new Error("totalBytes must be a non-negative integer");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function getErrorCode(error) {
|
|
37
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") {
|
|
38
|
+
return error.code;
|
|
39
|
+
}
|
|
40
|
+
if (error instanceof Error) {
|
|
41
|
+
const match = error.message.match(/\bE[A-Z0-9_]+\b/);
|
|
42
|
+
return match?.[0];
|
|
43
|
+
}
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
22
46
|
var ShelbyRPCClient = class {
|
|
23
47
|
baseUrl;
|
|
24
48
|
apiKey;
|
|
@@ -47,30 +71,53 @@ var ShelbyRPCClient = class {
|
|
|
47
71
|
}
|
|
48
72
|
async #uploadPart(uploadId, partIdx, partData) {
|
|
49
73
|
const nRetries = 5;
|
|
74
|
+
let lastResponse;
|
|
75
|
+
let lastError;
|
|
76
|
+
const partUrl = buildRequestUrl(
|
|
77
|
+
`/v1/multipart-uploads/${uploadId}/parts/${partIdx}`,
|
|
78
|
+
this.baseUrl
|
|
79
|
+
);
|
|
50
80
|
for (let i = 0; i < nRetries; ++i) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
`/v1/multipart-uploads/${uploadId}/parts/${partIdx}`,
|
|
54
|
-
this.baseUrl
|
|
55
|
-
),
|
|
56
|
-
{
|
|
81
|
+
try {
|
|
82
|
+
lastResponse = await fetch(partUrl, {
|
|
57
83
|
method: "PUT",
|
|
58
84
|
headers: {
|
|
59
85
|
"Content-Type": "application/octet-stream",
|
|
60
86
|
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
61
87
|
},
|
|
62
88
|
body: partData
|
|
89
|
+
});
|
|
90
|
+
lastError = void 0;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
lastError = error;
|
|
93
|
+
if (i < nRetries - 1) {
|
|
94
|
+
const delay = 2 ** i * 100;
|
|
95
|
+
await sleep(delay);
|
|
96
|
+
continue;
|
|
63
97
|
}
|
|
64
|
-
|
|
65
|
-
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (lastResponse.ok) return;
|
|
66
101
|
if (i < nRetries - 1) {
|
|
67
102
|
const delay = 2 ** i * 100;
|
|
68
103
|
await sleep(delay);
|
|
69
104
|
}
|
|
70
105
|
}
|
|
71
|
-
|
|
106
|
+
if (lastError !== void 0) {
|
|
107
|
+
const errorCode = getErrorCode(lastError);
|
|
108
|
+
const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Failed to upload part ${partIdx} for multipart upload ${uploadId} after ${nRetries} attempts. The connection to the Shelby RPC endpoint was interrupted while sending data${errorCode ? ` (${errorCode})` : ""}. Endpoint: ${partUrl.toString()}, partBytes: ${partData.length}. Last error: ${errorMessage}`,
|
|
111
|
+
{ cause: lastError }
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
const errorBody = await lastResponse?.text().catch(() => "");
|
|
115
|
+
throw new Error(
|
|
116
|
+
`Failed to upload part ${partIdx} for multipart upload ${uploadId} after ${nRetries} attempts. status: ${lastResponse?.status}, body: ${errorBody}`
|
|
117
|
+
);
|
|
72
118
|
}
|
|
73
|
-
async #putBlobMultipart(account, blobName, blobData, partSize = 5 * 1024 * 1024) {
|
|
119
|
+
async #putBlobMultipart(account, blobName, blobData, totalBytes, partSize = 5 * 1024 * 1024, onProgress) {
|
|
120
|
+
validateTotalBytes(totalBytes);
|
|
74
121
|
const startResponse = await fetch(
|
|
75
122
|
buildRequestUrl("/v1/multipart-uploads", this.baseUrl),
|
|
76
123
|
{
|
|
@@ -96,14 +143,38 @@ var ShelbyRPCClient = class {
|
|
|
96
143
|
`Failed to start multipart upload! status: ${startResponse.status}, body: ${errorBodyText}`
|
|
97
144
|
);
|
|
98
145
|
}
|
|
99
|
-
const { uploadId } =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
146
|
+
const { uploadId } = StartMultipartUploadResponseSchema.parse(
|
|
147
|
+
await startResponse.json()
|
|
148
|
+
);
|
|
149
|
+
const totalParts = Math.ceil(totalBytes / partSize);
|
|
150
|
+
let uploadedBytes = 0;
|
|
151
|
+
for await (const [partIdx, partData] of readInChunks(blobData, partSize)) {
|
|
105
152
|
await this.#uploadPart(uploadId, partIdx, partData);
|
|
153
|
+
uploadedBytes += partData.length;
|
|
154
|
+
onProgress?.({
|
|
155
|
+
phase: "uploading",
|
|
156
|
+
partIdx,
|
|
157
|
+
totalParts,
|
|
158
|
+
partBytes: partData.length,
|
|
159
|
+
uploadedBytes,
|
|
160
|
+
totalBytes
|
|
161
|
+
});
|
|
106
162
|
}
|
|
163
|
+
if (uploadedBytes !== totalBytes) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Uploaded bytes (${uploadedBytes}) did not match declared totalBytes (${totalBytes})`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
const finalPartIdx = totalParts > 0 ? totalParts - 1 : 0;
|
|
169
|
+
onProgress?.({
|
|
170
|
+
phase: "finalizing",
|
|
171
|
+
partIdx: finalPartIdx,
|
|
172
|
+
totalParts,
|
|
173
|
+
// no part uploaded in this phase
|
|
174
|
+
partBytes: 0,
|
|
175
|
+
uploadedBytes: totalBytes,
|
|
176
|
+
totalBytes
|
|
177
|
+
});
|
|
107
178
|
const completeResponse = await fetch(
|
|
108
179
|
buildRequestUrl(
|
|
109
180
|
`/v1/multipart-uploads/${uploadId}/complete`,
|
|
@@ -135,7 +206,8 @@ var ShelbyRPCClient = class {
|
|
|
135
206
|
*
|
|
136
207
|
* @param params.account - The account that owns the blob.
|
|
137
208
|
* @param params.blobName - The name/path of the blob (e.g. "folder/file.txt").
|
|
138
|
-
* @param params.blobData - The raw blob data as a Uint8Array.
|
|
209
|
+
* @param params.blobData - The raw blob data as a Uint8Array or ReadableStream.
|
|
210
|
+
* @param params.totalBytes - Total byte length. Required for streams; optional for Uint8Array.
|
|
139
211
|
*
|
|
140
212
|
* @example
|
|
141
213
|
* ```typescript
|
|
@@ -144,19 +216,38 @@ var ShelbyRPCClient = class {
|
|
|
144
216
|
* await client.putBlob({
|
|
145
217
|
* account: AccountAddress.from("0x1"),
|
|
146
218
|
* blobName: "greetings/hello.txt",
|
|
147
|
-
* blobData
|
|
219
|
+
* blobData,
|
|
148
220
|
* });
|
|
149
221
|
* ```
|
|
150
222
|
*/
|
|
151
223
|
async putBlob(params) {
|
|
152
224
|
BlobNameSchema.parse(params.blobName);
|
|
225
|
+
let totalBytes;
|
|
226
|
+
if (params.blobData instanceof Uint8Array) {
|
|
227
|
+
totalBytes = params.totalBytes ?? params.blobData.length;
|
|
228
|
+
if (totalBytes !== params.blobData.length) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
"totalBytes must match blobData.length when blobData is a Uint8Array"
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
if (params.totalBytes === void 0) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
"totalBytes is required when blobData is a ReadableStream"
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
totalBytes = params.totalBytes;
|
|
240
|
+
}
|
|
241
|
+
validateTotalBytes(totalBytes);
|
|
153
242
|
await this.#putBlobMultipart(
|
|
154
243
|
params.account,
|
|
155
244
|
params.blobName,
|
|
156
|
-
params.blobData
|
|
245
|
+
params.blobData,
|
|
246
|
+
totalBytes,
|
|
247
|
+
void 0,
|
|
248
|
+
params.onProgress
|
|
157
249
|
);
|
|
158
250
|
}
|
|
159
|
-
// FIXME make this possible to stream in put ^^^
|
|
160
251
|
/**
|
|
161
252
|
* Downloads a blob from the Shelby RPC node.
|
|
162
253
|
* Returns a streaming response with validation to ensure data integrity.
|
|
@@ -166,10 +257,12 @@ var ShelbyRPCClient = class {
|
|
|
166
257
|
* @param params.range - Optional byte range for partial downloads.
|
|
167
258
|
* @param params.range.start - Starting byte position (inclusive).
|
|
168
259
|
* @param params.range.end - Ending byte position (inclusive, optional).
|
|
260
|
+
* @param params.micropayment - Optional micropayment to attach to the request.
|
|
169
261
|
*
|
|
170
262
|
* @returns A ShelbyBlob object containing the account, name, readable stream, and content length.
|
|
171
263
|
*
|
|
172
264
|
* @throws Error if the download fails or content length doesn't match.
|
|
265
|
+
* @throws StaleChannelStateError if the micropayment is stale (server has newer state).
|
|
173
266
|
*
|
|
174
267
|
* @example
|
|
175
268
|
* ```typescript
|
|
@@ -185,6 +278,13 @@ var ShelbyRPCClient = class {
|
|
|
185
278
|
* blobName: "large-file.bin",
|
|
186
279
|
* range: { start: 100, end: 199 }
|
|
187
280
|
* });
|
|
281
|
+
*
|
|
282
|
+
* // Download with micropayment
|
|
283
|
+
* const blob = await client.getBlob({
|
|
284
|
+
* account: AccountAddress.from("0x1"),
|
|
285
|
+
* blobName: "documents/report.pdf",
|
|
286
|
+
* micropayment: senderBuiltMicropayment
|
|
287
|
+
* });
|
|
188
288
|
* ```
|
|
189
289
|
*/
|
|
190
290
|
async getBlob(params) {
|
|
@@ -195,9 +295,8 @@ var ShelbyRPCClient = class {
|
|
|
195
295
|
)}`,
|
|
196
296
|
this.baseUrl
|
|
197
297
|
);
|
|
198
|
-
const
|
|
298
|
+
const headers = new Headers();
|
|
199
299
|
if (params.range !== void 0) {
|
|
200
|
-
const headers = new Headers();
|
|
201
300
|
const { start, end } = params.range;
|
|
202
301
|
if (end === void 0) {
|
|
203
302
|
headers.set("Range", `bytes=${start}-`);
|
|
@@ -207,15 +306,45 @@ var ShelbyRPCClient = class {
|
|
|
207
306
|
}
|
|
208
307
|
headers.set("Range", `bytes=${start}-${end}`);
|
|
209
308
|
}
|
|
210
|
-
requestInit.headers = headers;
|
|
211
309
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
310
|
+
if (this.apiKey) {
|
|
311
|
+
headers.set("Authorization", `Bearer ${this.apiKey}`);
|
|
312
|
+
}
|
|
313
|
+
if (params.micropayment) {
|
|
314
|
+
const bytes = params.micropayment.bcsToBytes();
|
|
315
|
+
const binaryString = Array.from(
|
|
316
|
+
bytes,
|
|
317
|
+
(byte) => String.fromCharCode(byte)
|
|
318
|
+
).join("");
|
|
319
|
+
headers.set(MICROPAYMENT_HEADER, btoa(binaryString));
|
|
320
|
+
}
|
|
321
|
+
const response = await fetch(url, { headers });
|
|
322
|
+
if (response.status === 409) {
|
|
323
|
+
let json;
|
|
324
|
+
try {
|
|
325
|
+
json = await response.json();
|
|
326
|
+
} catch {
|
|
327
|
+
throw new Error(
|
|
328
|
+
`Failed to download blob: ${response.status} ${response.statusText}`
|
|
329
|
+
);
|
|
217
330
|
}
|
|
218
|
-
|
|
331
|
+
const parseResult = StaleMicropaymentErrorResponseSchema.safeParse(json);
|
|
332
|
+
if (!parseResult.success) {
|
|
333
|
+
throw new Error(
|
|
334
|
+
`Failed to download blob: ${response.status} ${response.statusText}`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
const errorBody = parseResult.data;
|
|
338
|
+
if (errorBody.storedMicropayment) {
|
|
339
|
+
throw StaleChannelStateError.fromBase64(
|
|
340
|
+
errorBody.storedMicropayment,
|
|
341
|
+
errorBody.error
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
throw new Error(
|
|
345
|
+
errorBody.error ?? `Failed to download blob: ${response.status} ${response.statusText}`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
219
348
|
if (!response.ok) {
|
|
220
349
|
throw new Error(
|
|
221
350
|
`Failed to download blob: ${response.status} ${response.statusText}`
|