@ar.io/sdk 3.22.0-alpha.1 → 3.22.0-alpha.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/bundles/web.bundle.min.js +69 -69
- package/lib/cjs/cli/cli.js +1 -5
- package/lib/cjs/cli/options.js +1 -0
- package/lib/cjs/cli/utils.js +2 -0
- package/lib/cjs/common/hyperbeam/hb.js +173 -0
- package/lib/cjs/common/io.js +33 -1
- package/lib/cjs/version.js +1 -1
- package/lib/esm/cli/cli.js +1 -5
- package/lib/esm/cli/options.js +1 -0
- package/lib/esm/cli/utils.js +2 -0
- package/lib/esm/common/hyperbeam/hb.js +169 -0
- package/lib/esm/common/io.js +33 -1
- package/lib/esm/version.js +1 -1
- package/lib/types/common/hyperbeam/hb.d.ts +88 -0
- package/lib/types/common/io.d.ts +2 -0
- package/lib/types/types/common.d.ts +3 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
package/lib/cjs/cli/cli.js
CHANGED
|
@@ -448,11 +448,7 @@ const utils_js_1 = require("./utils.js");
|
|
|
448
448
|
(0, utils_js_1.makeCommand)({
|
|
449
449
|
name: 'get-ants-for-address',
|
|
450
450
|
description: 'Get the list of ANTs owned by an address according to the ANT registry',
|
|
451
|
-
options: [
|
|
452
|
-
options_js_1.optionMap.address,
|
|
453
|
-
options_js_1.optionMap.antRegistryProcessId,
|
|
454
|
-
options_js_1.optionMap.hyperbeamUrl,
|
|
455
|
-
],
|
|
451
|
+
options: [options_js_1.optionMap.address, options_js_1.optionMap.antRegistryProcessId],
|
|
456
452
|
action: readCommands_js_1.listAntsForAddress,
|
|
457
453
|
});
|
|
458
454
|
// # ANTS
|
package/lib/cjs/cli/options.js
CHANGED
|
@@ -339,6 +339,7 @@ exports.globalOptions = [
|
|
|
339
339
|
exports.optionMap.debug,
|
|
340
340
|
exports.optionMap.arioProcessId,
|
|
341
341
|
exports.optionMap.cuUrl,
|
|
342
|
+
exports.optionMap.hyperbeamUrl,
|
|
342
343
|
];
|
|
343
344
|
exports.writeActionOptions = [exports.optionMap.skipConfirmation, exports.optionMap.tags];
|
|
344
345
|
exports.arnsPurchaseOptions = [
|
package/lib/cjs/cli/utils.js
CHANGED
|
@@ -181,6 +181,7 @@ function aoProcessFromOptions(options) {
|
|
|
181
181
|
function readARIOFromOptions(options) {
|
|
182
182
|
setLoggerIfDebug(options);
|
|
183
183
|
return index_js_1.ARIO.init({
|
|
184
|
+
hyperbeamUrl: options.hyperbeamUrl,
|
|
184
185
|
process: aoProcessFromOptions({
|
|
185
186
|
cuUrl: 'https://cu.ardrive.io', // default to ardrive cu for ARIO process
|
|
186
187
|
...options,
|
|
@@ -227,6 +228,7 @@ function writeARIOFromOptions(options) {
|
|
|
227
228
|
process: aoProcessFromOptions(options),
|
|
228
229
|
signer,
|
|
229
230
|
paymentUrl: options.paymentUrl,
|
|
231
|
+
hyperbeamUrl: options.hyperbeamUrl,
|
|
230
232
|
}),
|
|
231
233
|
signerAddress,
|
|
232
234
|
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HB = void 0;
|
|
4
|
+
const logger_js_1 = require("../logger.js");
|
|
5
|
+
class HB {
|
|
6
|
+
url;
|
|
7
|
+
processId;
|
|
8
|
+
isHyperBeamCompatible;
|
|
9
|
+
checkHyperBeamPromise;
|
|
10
|
+
logger;
|
|
11
|
+
hbTimeoutMs;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.url = config.url;
|
|
14
|
+
this.processId = config.processId;
|
|
15
|
+
this.logger = config.logger ?? logger_js_1.Logger.default;
|
|
16
|
+
this.hbTimeoutMs = config.hbTimeoutMs ?? 5000;
|
|
17
|
+
this.isHyperBeamCompatible = undefined;
|
|
18
|
+
this.checkHyperBeamPromise = this.checkHyperBeamCompatibility();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* fetches the meta data for the process
|
|
22
|
+
*
|
|
23
|
+
* @returns The meta data for the process
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
27
|
+
* const meta = await hyperbeam.meta();
|
|
28
|
+
* console.log(meta);
|
|
29
|
+
*/
|
|
30
|
+
async meta() {
|
|
31
|
+
const url = new URL(`${this.url}/${this.processId}~process@1.0/meta`);
|
|
32
|
+
return this.fetchHyperbeamPath({
|
|
33
|
+
path: url.toString(),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* calls the process device /now function, which evaluates the current process state pulling new messages
|
|
38
|
+
* to get the latest state
|
|
39
|
+
*
|
|
40
|
+
* @param path - The path to the hb state
|
|
41
|
+
* @param json - Whether to return the result as JSON, defaults to true
|
|
42
|
+
* @returns The result of the compute operation
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
46
|
+
* const result = await hyperbeam.now({ path: 'balances/QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ' });
|
|
47
|
+
* console.log(result);
|
|
48
|
+
*/
|
|
49
|
+
async now({ path, json = false, }) {
|
|
50
|
+
return this.fetchHyperbeamPath({
|
|
51
|
+
path: `${this.url}/${this.processId}~process@1.0/now/${path}`,
|
|
52
|
+
json,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* calls the process device /compute function, which uses the currently evaluated state in the node
|
|
57
|
+
*
|
|
58
|
+
* @param path - The path to the compute resource
|
|
59
|
+
* @param json - Whether to return the result as JSON, defaults to true
|
|
60
|
+
* @returns The result of the compute operation
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
64
|
+
* const result = await hyperbeam.compute({ path: 'balances/QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ' });
|
|
65
|
+
* console.log(result);
|
|
66
|
+
*/
|
|
67
|
+
async compute({ path, json = false, }) {
|
|
68
|
+
return this.fetchHyperbeamPath({
|
|
69
|
+
path: `${this.url}/${this.processId}~process@1.0/compute/${path}`,
|
|
70
|
+
json,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Checks if the process is HyperBeam compatible and caches the result.
|
|
75
|
+
*
|
|
76
|
+
* @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise.
|
|
77
|
+
*/
|
|
78
|
+
async checkHyperBeamCompatibility({ minSlot, } = {}) {
|
|
79
|
+
// refetch if min slot is provided
|
|
80
|
+
if (minSlot !== undefined) {
|
|
81
|
+
this.isHyperBeamCompatible = undefined;
|
|
82
|
+
this.checkHyperBeamPromise = undefined;
|
|
83
|
+
}
|
|
84
|
+
if (this.checkHyperBeamPromise !== undefined) {
|
|
85
|
+
return this.checkHyperBeamPromise;
|
|
86
|
+
}
|
|
87
|
+
if (this.isHyperBeamCompatible !== undefined) {
|
|
88
|
+
return Promise.resolve(this.isHyperBeamCompatible);
|
|
89
|
+
}
|
|
90
|
+
const result = fetch(
|
|
91
|
+
// use /now to force a refresh of the cache state, then compute when calling it for keys
|
|
92
|
+
`${this.url.toString()}/${this.processId}~process@1.0/now`, {
|
|
93
|
+
method: 'HEAD',
|
|
94
|
+
signal: AbortSignal.timeout(this.hbTimeoutMs),
|
|
95
|
+
})
|
|
96
|
+
.then(async (res) => {
|
|
97
|
+
if (res.ok) {
|
|
98
|
+
if (minSlot !== undefined) {
|
|
99
|
+
const slotRes = await this.compute({
|
|
100
|
+
path: 'at-slot',
|
|
101
|
+
json: false,
|
|
102
|
+
});
|
|
103
|
+
const slot = Number(slotRes);
|
|
104
|
+
if (slot < minSlot) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.isHyperBeamCompatible = true;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
this.isHyperBeamCompatible = false;
|
|
112
|
+
return false;
|
|
113
|
+
})
|
|
114
|
+
.catch((error) => {
|
|
115
|
+
this.logger.debug('Failed to check HyperBeam compatibility', {
|
|
116
|
+
cause: error,
|
|
117
|
+
});
|
|
118
|
+
this.isHyperBeamCompatible = false;
|
|
119
|
+
return false;
|
|
120
|
+
});
|
|
121
|
+
this.checkHyperBeamPromise = result;
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
async fetchHyperbeamPath({ path, json = true, }) {
|
|
125
|
+
try {
|
|
126
|
+
const url = new URL(path);
|
|
127
|
+
if (json) {
|
|
128
|
+
this.logger.debug('Fetching path as JSON', { path });
|
|
129
|
+
/**
|
|
130
|
+
* This is the (current) way to access data as json
|
|
131
|
+
* the old way is /~json@1.0/serialize path
|
|
132
|
+
*/
|
|
133
|
+
url.searchParams.set('require-codec', 'application/json');
|
|
134
|
+
url.searchParams.set('accept-bundle', 'true');
|
|
135
|
+
const res = await fetch(url);
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
throw new Error(`Failed to fetch path as JSON: ${res.statusText}`);
|
|
138
|
+
}
|
|
139
|
+
const jsonResult = await res
|
|
140
|
+
.json()
|
|
141
|
+
.then((json) => json)
|
|
142
|
+
.catch((error) => {
|
|
143
|
+
this.logger.error('Failed to parse JSON', {
|
|
144
|
+
cause: error,
|
|
145
|
+
});
|
|
146
|
+
throw new Error(`Received response but failed to parse JSON: ${error.message}`);
|
|
147
|
+
});
|
|
148
|
+
if (typeof jsonResult !== 'object' ||
|
|
149
|
+
jsonResult === null ||
|
|
150
|
+
!('body' in jsonResult)) {
|
|
151
|
+
throw new Error('Response body missing in JSON response');
|
|
152
|
+
}
|
|
153
|
+
return jsonResult.body;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
this.logger.debug('Fetching path as text', { path });
|
|
157
|
+
const res = await fetch(url);
|
|
158
|
+
if (!res.ok) {
|
|
159
|
+
throw new Error(`Failed to fetch path: ${res.statusText}`);
|
|
160
|
+
}
|
|
161
|
+
const body = await res.text();
|
|
162
|
+
return body;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
this.logger.error('Failed to fetch path as JSON', {
|
|
167
|
+
cause: error,
|
|
168
|
+
});
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.HB = HB;
|
package/lib/cjs/common/io.js
CHANGED
|
@@ -27,6 +27,7 @@ const arweave_js_2 = require("./arweave.js");
|
|
|
27
27
|
const ao_process_js_1 = require("./contracts/ao-process.js");
|
|
28
28
|
const error_js_1 = require("./error.js");
|
|
29
29
|
const faucet_js_1 = require("./faucet.js");
|
|
30
|
+
const hb_js_1 = require("./hyperbeam/hb.js");
|
|
30
31
|
const logger_js_1 = require("./logger.js");
|
|
31
32
|
const turbo_js_1 = require("./turbo.js");
|
|
32
33
|
class ARIO {
|
|
@@ -104,9 +105,9 @@ class ARIOReadable {
|
|
|
104
105
|
hyperbeamUrl;
|
|
105
106
|
paymentProvider; // TODO: this could be an array/map of payment providers
|
|
106
107
|
logger = logger_js_1.Logger.default;
|
|
108
|
+
hb;
|
|
107
109
|
constructor(config) {
|
|
108
110
|
this.arweave = config?.arweave ?? arweave_js_2.defaultArweave;
|
|
109
|
-
this.hyperbeamUrl = config?.hyperbeamUrl;
|
|
110
111
|
if (config === undefined || Object.keys(config).length === 0) {
|
|
111
112
|
this.process = new ao_process_js_1.AOProcess({
|
|
112
113
|
processId: constants_js_1.ARIO_MAINNET_PROCESS_ID,
|
|
@@ -123,6 +124,19 @@ class ARIOReadable {
|
|
|
123
124
|
else {
|
|
124
125
|
throw new error_js_1.InvalidContractConfigurationError();
|
|
125
126
|
}
|
|
127
|
+
// only use hyperbeam if the client has provided a hyperbeamUrl
|
|
128
|
+
// this will avoid overwhelming the HyperBeam node with requests
|
|
129
|
+
// as we shift using HyperBEAM for all ANT operations
|
|
130
|
+
if (config?.hyperbeamUrl !== undefined) {
|
|
131
|
+
this.hyperbeamUrl = config.hyperbeamUrl;
|
|
132
|
+
this.hb = new hb_js_1.HB({
|
|
133
|
+
url: this.hyperbeamUrl,
|
|
134
|
+
processId: this.process.processId,
|
|
135
|
+
});
|
|
136
|
+
this.logger.debug(`Using HyperBEAM node for process ${this.process.processId}`, {
|
|
137
|
+
hyperbeamUrl: this.hyperbeamUrl,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
126
140
|
this.paymentProvider = turbo_js_1.TurboArNSPaymentFactory.init({
|
|
127
141
|
paymentUrl: config?.paymentUrl,
|
|
128
142
|
});
|
|
@@ -222,6 +236,24 @@ class ARIOReadable {
|
|
|
222
236
|
});
|
|
223
237
|
}
|
|
224
238
|
async getBalance({ address }) {
|
|
239
|
+
if (this.hb && (await this.hb.checkHyperBeamCompatibility())) {
|
|
240
|
+
this.logger.debug('Getting balance from HyperBEAM', { address });
|
|
241
|
+
const res = await this.hb
|
|
242
|
+
.compute({
|
|
243
|
+
path: `balances/${address}`,
|
|
244
|
+
})
|
|
245
|
+
.then((res) => Number(res))
|
|
246
|
+
.catch((error) => {
|
|
247
|
+
this.logger.error('Failed to get balance from HyperBEAM', {
|
|
248
|
+
cause: error,
|
|
249
|
+
});
|
|
250
|
+
return null;
|
|
251
|
+
});
|
|
252
|
+
if (res !== null)
|
|
253
|
+
return res;
|
|
254
|
+
// else fall through to CU read
|
|
255
|
+
this.logger.info('Failed to get balance from HyperBEAM, failing over to to CU read', { address });
|
|
256
|
+
}
|
|
225
257
|
return this.process.read({
|
|
226
258
|
tags: [
|
|
227
259
|
{ name: 'Action', value: 'Balance' },
|
package/lib/cjs/version.js
CHANGED
package/lib/esm/cli/cli.js
CHANGED
|
@@ -446,11 +446,7 @@ makeCommand({
|
|
|
446
446
|
makeCommand({
|
|
447
447
|
name: 'get-ants-for-address',
|
|
448
448
|
description: 'Get the list of ANTs owned by an address according to the ANT registry',
|
|
449
|
-
options: [
|
|
450
|
-
optionMap.address,
|
|
451
|
-
optionMap.antRegistryProcessId,
|
|
452
|
-
optionMap.hyperbeamUrl,
|
|
453
|
-
],
|
|
449
|
+
options: [optionMap.address, optionMap.antRegistryProcessId],
|
|
454
450
|
action: listAntsForAddress,
|
|
455
451
|
});
|
|
456
452
|
// # ANTS
|
package/lib/esm/cli/options.js
CHANGED
|
@@ -336,6 +336,7 @@ export const globalOptions = [
|
|
|
336
336
|
optionMap.debug,
|
|
337
337
|
optionMap.arioProcessId,
|
|
338
338
|
optionMap.cuUrl,
|
|
339
|
+
optionMap.hyperbeamUrl,
|
|
339
340
|
];
|
|
340
341
|
export const writeActionOptions = [optionMap.skipConfirmation, optionMap.tags];
|
|
341
342
|
export const arnsPurchaseOptions = [
|
package/lib/esm/cli/utils.js
CHANGED
|
@@ -127,6 +127,7 @@ function aoProcessFromOptions(options) {
|
|
|
127
127
|
export function readARIOFromOptions(options) {
|
|
128
128
|
setLoggerIfDebug(options);
|
|
129
129
|
return ARIO.init({
|
|
130
|
+
hyperbeamUrl: options.hyperbeamUrl,
|
|
130
131
|
process: aoProcessFromOptions({
|
|
131
132
|
cuUrl: 'https://cu.ardrive.io', // default to ardrive cu for ARIO process
|
|
132
133
|
...options,
|
|
@@ -173,6 +174,7 @@ export function writeARIOFromOptions(options) {
|
|
|
173
174
|
process: aoProcessFromOptions(options),
|
|
174
175
|
signer,
|
|
175
176
|
paymentUrl: options.paymentUrl,
|
|
177
|
+
hyperbeamUrl: options.hyperbeamUrl,
|
|
176
178
|
}),
|
|
177
179
|
signerAddress,
|
|
178
180
|
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Logger } from '../logger.js';
|
|
2
|
+
export class HB {
|
|
3
|
+
url;
|
|
4
|
+
processId;
|
|
5
|
+
isHyperBeamCompatible;
|
|
6
|
+
checkHyperBeamPromise;
|
|
7
|
+
logger;
|
|
8
|
+
hbTimeoutMs;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.url = config.url;
|
|
11
|
+
this.processId = config.processId;
|
|
12
|
+
this.logger = config.logger ?? Logger.default;
|
|
13
|
+
this.hbTimeoutMs = config.hbTimeoutMs ?? 5000;
|
|
14
|
+
this.isHyperBeamCompatible = undefined;
|
|
15
|
+
this.checkHyperBeamPromise = this.checkHyperBeamCompatibility();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* fetches the meta data for the process
|
|
19
|
+
*
|
|
20
|
+
* @returns The meta data for the process
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
24
|
+
* const meta = await hyperbeam.meta();
|
|
25
|
+
* console.log(meta);
|
|
26
|
+
*/
|
|
27
|
+
async meta() {
|
|
28
|
+
const url = new URL(`${this.url}/${this.processId}~process@1.0/meta`);
|
|
29
|
+
return this.fetchHyperbeamPath({
|
|
30
|
+
path: url.toString(),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* calls the process device /now function, which evaluates the current process state pulling new messages
|
|
35
|
+
* to get the latest state
|
|
36
|
+
*
|
|
37
|
+
* @param path - The path to the hb state
|
|
38
|
+
* @param json - Whether to return the result as JSON, defaults to true
|
|
39
|
+
* @returns The result of the compute operation
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
43
|
+
* const result = await hyperbeam.now({ path: 'balances/QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ' });
|
|
44
|
+
* console.log(result);
|
|
45
|
+
*/
|
|
46
|
+
async now({ path, json = false, }) {
|
|
47
|
+
return this.fetchHyperbeamPath({
|
|
48
|
+
path: `${this.url}/${this.processId}~process@1.0/now/${path}`,
|
|
49
|
+
json,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* calls the process device /compute function, which uses the currently evaluated state in the node
|
|
54
|
+
*
|
|
55
|
+
* @param path - The path to the compute resource
|
|
56
|
+
* @param json - Whether to return the result as JSON, defaults to true
|
|
57
|
+
* @returns The result of the compute operation
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
61
|
+
* const result = await hyperbeam.compute({ path: 'balances/QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ' });
|
|
62
|
+
* console.log(result);
|
|
63
|
+
*/
|
|
64
|
+
async compute({ path, json = false, }) {
|
|
65
|
+
return this.fetchHyperbeamPath({
|
|
66
|
+
path: `${this.url}/${this.processId}~process@1.0/compute/${path}`,
|
|
67
|
+
json,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Checks if the process is HyperBeam compatible and caches the result.
|
|
72
|
+
*
|
|
73
|
+
* @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise.
|
|
74
|
+
*/
|
|
75
|
+
async checkHyperBeamCompatibility({ minSlot, } = {}) {
|
|
76
|
+
// refetch if min slot is provided
|
|
77
|
+
if (minSlot !== undefined) {
|
|
78
|
+
this.isHyperBeamCompatible = undefined;
|
|
79
|
+
this.checkHyperBeamPromise = undefined;
|
|
80
|
+
}
|
|
81
|
+
if (this.checkHyperBeamPromise !== undefined) {
|
|
82
|
+
return this.checkHyperBeamPromise;
|
|
83
|
+
}
|
|
84
|
+
if (this.isHyperBeamCompatible !== undefined) {
|
|
85
|
+
return Promise.resolve(this.isHyperBeamCompatible);
|
|
86
|
+
}
|
|
87
|
+
const result = fetch(
|
|
88
|
+
// use /now to force a refresh of the cache state, then compute when calling it for keys
|
|
89
|
+
`${this.url.toString()}/${this.processId}~process@1.0/now`, {
|
|
90
|
+
method: 'HEAD',
|
|
91
|
+
signal: AbortSignal.timeout(this.hbTimeoutMs),
|
|
92
|
+
})
|
|
93
|
+
.then(async (res) => {
|
|
94
|
+
if (res.ok) {
|
|
95
|
+
if (minSlot !== undefined) {
|
|
96
|
+
const slotRes = await this.compute({
|
|
97
|
+
path: 'at-slot',
|
|
98
|
+
json: false,
|
|
99
|
+
});
|
|
100
|
+
const slot = Number(slotRes);
|
|
101
|
+
if (slot < minSlot) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.isHyperBeamCompatible = true;
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
this.isHyperBeamCompatible = false;
|
|
109
|
+
return false;
|
|
110
|
+
})
|
|
111
|
+
.catch((error) => {
|
|
112
|
+
this.logger.debug('Failed to check HyperBeam compatibility', {
|
|
113
|
+
cause: error,
|
|
114
|
+
});
|
|
115
|
+
this.isHyperBeamCompatible = false;
|
|
116
|
+
return false;
|
|
117
|
+
});
|
|
118
|
+
this.checkHyperBeamPromise = result;
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
async fetchHyperbeamPath({ path, json = true, }) {
|
|
122
|
+
try {
|
|
123
|
+
const url = new URL(path);
|
|
124
|
+
if (json) {
|
|
125
|
+
this.logger.debug('Fetching path as JSON', { path });
|
|
126
|
+
/**
|
|
127
|
+
* This is the (current) way to access data as json
|
|
128
|
+
* the old way is /~json@1.0/serialize path
|
|
129
|
+
*/
|
|
130
|
+
url.searchParams.set('require-codec', 'application/json');
|
|
131
|
+
url.searchParams.set('accept-bundle', 'true');
|
|
132
|
+
const res = await fetch(url);
|
|
133
|
+
if (!res.ok) {
|
|
134
|
+
throw new Error(`Failed to fetch path as JSON: ${res.statusText}`);
|
|
135
|
+
}
|
|
136
|
+
const jsonResult = await res
|
|
137
|
+
.json()
|
|
138
|
+
.then((json) => json)
|
|
139
|
+
.catch((error) => {
|
|
140
|
+
this.logger.error('Failed to parse JSON', {
|
|
141
|
+
cause: error,
|
|
142
|
+
});
|
|
143
|
+
throw new Error(`Received response but failed to parse JSON: ${error.message}`);
|
|
144
|
+
});
|
|
145
|
+
if (typeof jsonResult !== 'object' ||
|
|
146
|
+
jsonResult === null ||
|
|
147
|
+
!('body' in jsonResult)) {
|
|
148
|
+
throw new Error('Response body missing in JSON response');
|
|
149
|
+
}
|
|
150
|
+
return jsonResult.body;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
this.logger.debug('Fetching path as text', { path });
|
|
154
|
+
const res = await fetch(url);
|
|
155
|
+
if (!res.ok) {
|
|
156
|
+
throw new Error(`Failed to fetch path: ${res.statusText}`);
|
|
157
|
+
}
|
|
158
|
+
const body = await res.text();
|
|
159
|
+
return body;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
this.logger.error('Failed to fetch path as JSON', {
|
|
164
|
+
cause: error,
|
|
165
|
+
});
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
package/lib/esm/common/io.js
CHANGED
|
@@ -24,6 +24,7 @@ import { defaultArweave } from './arweave.js';
|
|
|
24
24
|
import { AOProcess } from './contracts/ao-process.js';
|
|
25
25
|
import { InvalidContractConfigurationError } from './error.js';
|
|
26
26
|
import { createFaucet } from './faucet.js';
|
|
27
|
+
import { HB } from './hyperbeam/hb.js';
|
|
27
28
|
import { Logger } from './logger.js';
|
|
28
29
|
import { TurboArNSPaymentFactory, TurboArNSPaymentProviderAuthenticated, isTurboArNSSigner, } from './turbo.js';
|
|
29
30
|
export class ARIO {
|
|
@@ -100,9 +101,9 @@ export class ARIOReadable {
|
|
|
100
101
|
hyperbeamUrl;
|
|
101
102
|
paymentProvider; // TODO: this could be an array/map of payment providers
|
|
102
103
|
logger = Logger.default;
|
|
104
|
+
hb;
|
|
103
105
|
constructor(config) {
|
|
104
106
|
this.arweave = config?.arweave ?? defaultArweave;
|
|
105
|
-
this.hyperbeamUrl = config?.hyperbeamUrl;
|
|
106
107
|
if (config === undefined || Object.keys(config).length === 0) {
|
|
107
108
|
this.process = new AOProcess({
|
|
108
109
|
processId: ARIO_MAINNET_PROCESS_ID,
|
|
@@ -119,6 +120,19 @@ export class ARIOReadable {
|
|
|
119
120
|
else {
|
|
120
121
|
throw new InvalidContractConfigurationError();
|
|
121
122
|
}
|
|
123
|
+
// only use hyperbeam if the client has provided a hyperbeamUrl
|
|
124
|
+
// this will avoid overwhelming the HyperBeam node with requests
|
|
125
|
+
// as we shift using HyperBEAM for all ANT operations
|
|
126
|
+
if (config?.hyperbeamUrl !== undefined) {
|
|
127
|
+
this.hyperbeamUrl = config.hyperbeamUrl;
|
|
128
|
+
this.hb = new HB({
|
|
129
|
+
url: this.hyperbeamUrl,
|
|
130
|
+
processId: this.process.processId,
|
|
131
|
+
});
|
|
132
|
+
this.logger.debug(`Using HyperBEAM node for process ${this.process.processId}`, {
|
|
133
|
+
hyperbeamUrl: this.hyperbeamUrl,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
122
136
|
this.paymentProvider = TurboArNSPaymentFactory.init({
|
|
123
137
|
paymentUrl: config?.paymentUrl,
|
|
124
138
|
});
|
|
@@ -218,6 +232,24 @@ export class ARIOReadable {
|
|
|
218
232
|
});
|
|
219
233
|
}
|
|
220
234
|
async getBalance({ address }) {
|
|
235
|
+
if (this.hb && (await this.hb.checkHyperBeamCompatibility())) {
|
|
236
|
+
this.logger.debug('Getting balance from HyperBEAM', { address });
|
|
237
|
+
const res = await this.hb
|
|
238
|
+
.compute({
|
|
239
|
+
path: `balances/${address}`,
|
|
240
|
+
})
|
|
241
|
+
.then((res) => Number(res))
|
|
242
|
+
.catch((error) => {
|
|
243
|
+
this.logger.error('Failed to get balance from HyperBEAM', {
|
|
244
|
+
cause: error,
|
|
245
|
+
});
|
|
246
|
+
return null;
|
|
247
|
+
});
|
|
248
|
+
if (res !== null)
|
|
249
|
+
return res;
|
|
250
|
+
// else fall through to CU read
|
|
251
|
+
this.logger.info('Failed to get balance from HyperBEAM, failing over to to CU read', { address });
|
|
252
|
+
}
|
|
221
253
|
return this.process.read({
|
|
222
254
|
tags: [
|
|
223
255
|
{ name: 'Action', value: 'Balance' },
|
package/lib/esm/version.js
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { JSONValue } from '../../types/common.js';
|
|
17
|
+
import { Logger } from '../logger.js';
|
|
18
|
+
export type HBConfig = {
|
|
19
|
+
url: string;
|
|
20
|
+
processId: string;
|
|
21
|
+
logger?: Logger;
|
|
22
|
+
hbTimeoutMs?: number;
|
|
23
|
+
};
|
|
24
|
+
export declare class HB {
|
|
25
|
+
readonly url: string;
|
|
26
|
+
readonly processId: string;
|
|
27
|
+
protected isHyperBeamCompatible: boolean | undefined;
|
|
28
|
+
protected checkHyperBeamPromise: Promise<boolean> | undefined;
|
|
29
|
+
private logger;
|
|
30
|
+
private hbTimeoutMs;
|
|
31
|
+
constructor(config: HBConfig);
|
|
32
|
+
/**
|
|
33
|
+
* fetches the meta data for the process
|
|
34
|
+
*
|
|
35
|
+
* @returns The meta data for the process
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
39
|
+
* const meta = await hyperbeam.meta();
|
|
40
|
+
* console.log(meta);
|
|
41
|
+
*/
|
|
42
|
+
meta(): Promise<Record<string, JSONValue>>;
|
|
43
|
+
/**
|
|
44
|
+
* calls the process device /now function, which evaluates the current process state pulling new messages
|
|
45
|
+
* to get the latest state
|
|
46
|
+
*
|
|
47
|
+
* @param path - The path to the hb state
|
|
48
|
+
* @param json - Whether to return the result as JSON, defaults to true
|
|
49
|
+
* @returns The result of the compute operation
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
53
|
+
* const result = await hyperbeam.now({ path: 'balances/QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ' });
|
|
54
|
+
* console.log(result);
|
|
55
|
+
*/
|
|
56
|
+
now<T extends JSONValue>({ path, json, }: {
|
|
57
|
+
path: string;
|
|
58
|
+
json?: boolean;
|
|
59
|
+
}): Promise<T>;
|
|
60
|
+
/**
|
|
61
|
+
* calls the process device /compute function, which uses the currently evaluated state in the node
|
|
62
|
+
*
|
|
63
|
+
* @param path - The path to the compute resource
|
|
64
|
+
* @param json - Whether to return the result as JSON, defaults to true
|
|
65
|
+
* @returns The result of the compute operation
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const hyperbeam = new Hyperbeam({ url: 'https://hyperbeam.ario.permaweb.services', processId: 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE' });
|
|
69
|
+
* const result = await hyperbeam.compute({ path: 'balances/QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ' });
|
|
70
|
+
* console.log(result);
|
|
71
|
+
*/
|
|
72
|
+
compute<T extends JSONValue>({ path, json, }: {
|
|
73
|
+
path: string;
|
|
74
|
+
json?: boolean;
|
|
75
|
+
}): Promise<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Checks if the process is HyperBeam compatible and caches the result.
|
|
78
|
+
*
|
|
79
|
+
* @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise.
|
|
80
|
+
*/
|
|
81
|
+
checkHyperBeamCompatibility({ minSlot, }?: {
|
|
82
|
+
minSlot?: number;
|
|
83
|
+
}): Promise<boolean>;
|
|
84
|
+
fetchHyperbeamPath<T extends JSONValue>({ path, json, }: {
|
|
85
|
+
path: string;
|
|
86
|
+
json?: boolean;
|
|
87
|
+
}): Promise<T>;
|
|
88
|
+
}
|
package/lib/types/common/io.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Arweave from 'arweave';
|
|
2
2
|
import { ARIOWithFaucet, AoARIORead, AoARIOWrite, AoAllDelegates, AoAllGatewayVaults, AoArNSNameData, AoArNSNameDataWithName, AoArNSPurchaseParams, AoArNSReservedNameData, AoArNSReservedNameDataWithName, AoBalanceWithAddress, AoBuyRecordParams, AoCreatePrimaryNameRequest, AoCreateVaultParams, AoDelegation, AoEligibleDistribution, AoEpochData, AoEpochDistributed, AoEpochDistributionData, AoEpochDistributionTotalsData, AoEpochObservationData, AoEpochSettings, AoExtendLeaseParams, AoExtendVaultParams, AoGateway, AoGatewayDelegateWithAddress, AoGatewayRegistrySettings, AoGatewayVault, AoGatewayWithAddress, AoGetCostDetailsParams, AoIncreaseUndernameLimitParams, AoIncreaseVaultParams, AoJoinNetworkParams, AoMessageResult, AoPaginatedAddressParams, AoPrimaryName, AoPrimaryNameRequest, AoRedelegationFeeInfo, AoRegistrationFees, AoReturnedName, AoRevokeVaultParams, AoTokenSupplyData, AoUpdateGatewaySettingsParams, AoVaultData, AoVaultedTransferParams, AoWalletVault, AoWeightedObserver, ArNSNameResolutionData, ArNSNameResolver, BuyArNSNameProgressEvents, CostDetailsResult, DemandFactorSettings, EpochInput, OptionalArweave, OptionalPaymentUrl, PaginationParams, PaginationResult, ProcessConfiguration, SetPrimaryNameProgressEvents, TransactionId, WalletAddress, WithSigner, WriteOptions, mARIOToken } from '../types/index.js';
|
|
3
3
|
import { AOProcess } from './contracts/ao-process.js';
|
|
4
|
+
import { HB } from './hyperbeam/hb.js';
|
|
4
5
|
import { Logger } from './logger.js';
|
|
5
6
|
import { TurboArNSPaymentProviderAuthenticated, TurboArNSPaymentProviderUnauthenticated } from './turbo.js';
|
|
6
7
|
type ARIOConfigNoSigner = OptionalPaymentUrl<OptionalArweave<ProcessConfiguration & {
|
|
@@ -31,6 +32,7 @@ export declare class ARIOReadable implements AoARIORead, ArNSNameResolver {
|
|
|
31
32
|
protected hyperbeamUrl: string | undefined;
|
|
32
33
|
protected paymentProvider: TurboArNSPaymentProviderUnauthenticated;
|
|
33
34
|
protected logger: Logger;
|
|
35
|
+
protected hb: HB | undefined;
|
|
34
36
|
constructor(config?: ARIOConfigNoSigner);
|
|
35
37
|
getInfo(): Promise<{
|
|
36
38
|
Name: string;
|