@ar.io/sdk 3.14.0-alpha.8 → 3.14.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.
@@ -41,6 +41,7 @@ class AoANTReadable {
41
41
  strict;
42
42
  hyperbeamUrl;
43
43
  checkHyperBeamPromise;
44
+ logger = index_js_2.Logger.default;
44
45
  constructor(config) {
45
46
  this.strict = config.strict || false;
46
47
  if ((0, index_js_1.isProcessConfiguration)(config)) {
@@ -55,42 +56,67 @@ class AoANTReadable {
55
56
  throw new index_js_2.InvalidContractConfigurationError();
56
57
  }
57
58
  this.processId = this.process.processId;
58
- this.hyperbeamUrl = new URL(config.hyperbeamUrl || 'https://hyperbeam.ario.permaweb.services').toString();
59
- this.checkHyperBeamPromise = this.checkHyperBeamCompatibility();
59
+ // only use hyperbeam if the client has provided a hyperbeamUrl
60
+ // this will avoid overwhelming the HyperBeam node with requests
61
+ // as we shift using HyperBEAM for all ANT operations
62
+ if (config.hyperbeamUrl) {
63
+ this.hyperbeamUrl = new URL(config.hyperbeamUrl).toString();
64
+ }
60
65
  }
61
66
  /**
62
- * Check if the process is hyperbeam compatible. If so, we'll use the hyperbeam node to fetch the state.
67
+ * Check if the process is HyperBeam compatible. If so, we'll use the HyperBeam node to fetch the state.
63
68
  *
64
- * @returns {Promise<boolean>} True if the process is hyperbeam compatible, false otherwise.
69
+ * @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise.
65
70
  */
66
71
  async checkHyperBeamCompatibility() {
72
+ if (!this.hyperbeamUrl) {
73
+ return false;
74
+ }
67
75
  if (this.checkHyperBeamPromise !== undefined) {
68
76
  return this.checkHyperBeamPromise;
69
77
  }
70
- const res = await fetch(`${this.hyperbeamUrl.toString()}${this.processId}~process@1.0/now/cache`, {
71
- method: 'GET',
78
+ this.checkHyperBeamPromise = fetch(`${this.hyperbeamUrl.toString()}${this.processId}~process@1.0/now/cache`, {
79
+ method: 'HEAD',
80
+ }).then((res) => {
81
+ if (res.ok) {
82
+ return true;
83
+ }
84
+ return false;
72
85
  });
73
- let isHyperBeamCompatible = false;
74
- if (res.ok) {
75
- isHyperBeamCompatible = true;
76
- }
77
- this.checkHyperBeamPromise = Promise.resolve(isHyperBeamCompatible);
78
- return isHyperBeamCompatible;
86
+ return this.checkHyperBeamPromise;
79
87
  }
80
88
  async getState({ strict } = { strict: this.strict }) {
81
89
  if (await this.checkHyperBeamCompatibility()) {
82
- const res = await fetch(`${this.hyperbeamUrl}${this.processId}~process@1.0/now/cache/serialize~json@1.0`, {
83
- method: 'GET',
84
- redirect: 'follow',
85
- mode: 'cors',
86
- headers: {
87
- 'Content-Type': 'application/json',
88
- },
89
- });
90
- if (!res.ok) {
91
- throw new Error('Failed to fetch ant state');
90
+ let retries = 0;
91
+ while (retries < 3) {
92
+ try {
93
+ const res = await fetch(`${this.hyperbeamUrl}${this.processId}~process@1.0/compute/cache/serialize~json@1.0`, {
94
+ method: 'GET',
95
+ redirect: 'follow',
96
+ mode: 'cors',
97
+ headers: {
98
+ 'Content-Type': 'application/json',
99
+ },
100
+ });
101
+ if (res.status !== 200) {
102
+ throw new Error(`Failed to fetch ant state: ${res?.statusText ?? 'Unknown error'}`);
103
+ }
104
+ const unnormalizedState = (await res.json());
105
+ if (!(0, ant_js_2.isHyperBeamANTState)(unnormalizedState)) {
106
+ // don't retry if the state is bad, fallback to the CU
107
+ break;
108
+ }
109
+ // normalize and return the state
110
+ return (0, ant_js_2.convertHyperBeamStateToAoANTState)(unnormalizedState);
111
+ }
112
+ catch (error) {
113
+ this.logger.error(`Failed to fetch process state from HyperBEAM (attempt ${retries + 1} / 3)`, {
114
+ cause: error,
115
+ });
116
+ retries++;
117
+ await new Promise((resolve) => setTimeout(resolve, 1000 * retries ** 2));
118
+ }
92
119
  }
93
- return (0, ant_js_2.convertHyperBeamStateToAoANTState)((await res.json()));
94
120
  }
95
121
  const tags = [{ name: 'Action', value: 'State' }];
96
122
  const res = await this.process.read({
@@ -264,25 +290,8 @@ class AoANTReadable {
264
290
  * ```
265
291
  */
266
292
  async getBalances({ strict } = { strict: this.strict }) {
267
- if (await this.checkHyperBeamCompatibility()) {
268
- const res = await fetch(`${this.hyperbeamUrl}${this.processId}~process@1.0/now/cache/balances/serialize~json@1.0`, {
269
- method: 'GET',
270
- redirect: 'follow',
271
- mode: 'cors',
272
- headers: {
273
- 'Content-Type': 'application/json',
274
- },
275
- });
276
- if (!res.ok) {
277
- throw new Error('Failed to fetch ant balances');
278
- }
279
- const result = (await res.json());
280
- return result.balances;
281
- }
282
- const tags = [{ name: 'Action', value: 'Balances' }];
283
- const balances = await this.process.read({
284
- tags,
285
- });
293
+ const state = await this.getState();
294
+ const balances = state.Balances;
286
295
  if (strict)
287
296
  (0, schema_js_1.parseSchemaResult)(ant_js_1.AntBalancesSchema, balances);
288
297
  return balances;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertHyperBeamStateToAoANTState = exports.sortANTRecords = void 0;
3
+ exports.convertHyperBeamStateToAoANTState = exports.isHyperBeamANTState = exports.sortANTRecords = void 0;
4
4
  /**
5
5
  * Sorts ANT records by priority and then lexicographically.
6
6
  *
@@ -41,6 +41,21 @@ const sortANTRecords = (antRecords) => {
41
41
  return Object.fromEntries(sortedEntries.map(([a, aRecord], index) => [a, { ...aRecord, index }]));
42
42
  };
43
43
  exports.sortANTRecords = sortANTRecords;
44
+ const isHyperBeamANTState = (state) => {
45
+ return ('name' in state &&
46
+ 'ticker' in state &&
47
+ 'description' in state &&
48
+ 'keywords' in state &&
49
+ 'denomination' in state &&
50
+ 'owner' in state &&
51
+ 'controllers' in state &&
52
+ 'records' in state &&
53
+ 'balances' in state &&
54
+ 'logo' in state &&
55
+ 'totalsupply' in state &&
56
+ 'initialized' in state);
57
+ };
58
+ exports.isHyperBeamANTState = isHyperBeamANTState;
44
59
  /**
45
60
  * Convert HyperBeam serialized ANT state to backwards compatible format.
46
61
  *
@@ -17,4 +17,4 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.version = void 0;
19
19
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
20
- exports.version = '3.14.0-alpha.8';
20
+ exports.version = '3.14.0';
@@ -16,11 +16,11 @@
16
16
  import { z } from 'zod';
17
17
  import { AntBalancesSchema, AntControllersSchema, AntInfoSchema, AntRecordSchema, AntRecordsSchema, AntStateSchema, } from '../types/ant.js';
18
18
  import { isProcessConfiguration, isProcessIdConfiguration, } from '../types/index.js';
19
- import { convertHyperBeamStateToAoANTState, sortANTRecords, } from '../utils/ant.js';
19
+ import { convertHyperBeamStateToAoANTState, isHyperBeamANTState, sortANTRecords, } from '../utils/ant.js';
20
20
  import { createAoSigner } from '../utils/ao.js';
21
21
  import { parseSchemaResult } from '../utils/schema.js';
22
22
  import { ANTVersions } from './ant-versions.js';
23
- import { AOProcess, InvalidContractConfigurationError } from './index.js';
23
+ import { AOProcess, InvalidContractConfigurationError, Logger, } from './index.js';
24
24
  export class ANT {
25
25
  static versions = ANTVersions.init();
26
26
  // implementation
@@ -37,6 +37,7 @@ export class AoANTReadable {
37
37
  strict;
38
38
  hyperbeamUrl;
39
39
  checkHyperBeamPromise;
40
+ logger = Logger.default;
40
41
  constructor(config) {
41
42
  this.strict = config.strict || false;
42
43
  if (isProcessConfiguration(config)) {
@@ -51,42 +52,67 @@ export class AoANTReadable {
51
52
  throw new InvalidContractConfigurationError();
52
53
  }
53
54
  this.processId = this.process.processId;
54
- this.hyperbeamUrl = new URL(config.hyperbeamUrl || 'https://hyperbeam.ario.permaweb.services').toString();
55
- this.checkHyperBeamPromise = this.checkHyperBeamCompatibility();
55
+ // only use hyperbeam if the client has provided a hyperbeamUrl
56
+ // this will avoid overwhelming the HyperBeam node with requests
57
+ // as we shift using HyperBEAM for all ANT operations
58
+ if (config.hyperbeamUrl) {
59
+ this.hyperbeamUrl = new URL(config.hyperbeamUrl).toString();
60
+ }
56
61
  }
57
62
  /**
58
- * Check if the process is hyperbeam compatible. If so, we'll use the hyperbeam node to fetch the state.
63
+ * Check if the process is HyperBeam compatible. If so, we'll use the HyperBeam node to fetch the state.
59
64
  *
60
- * @returns {Promise<boolean>} True if the process is hyperbeam compatible, false otherwise.
65
+ * @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise.
61
66
  */
62
67
  async checkHyperBeamCompatibility() {
68
+ if (!this.hyperbeamUrl) {
69
+ return false;
70
+ }
63
71
  if (this.checkHyperBeamPromise !== undefined) {
64
72
  return this.checkHyperBeamPromise;
65
73
  }
66
- const res = await fetch(`${this.hyperbeamUrl.toString()}${this.processId}~process@1.0/now/cache`, {
67
- method: 'GET',
74
+ this.checkHyperBeamPromise = fetch(`${this.hyperbeamUrl.toString()}${this.processId}~process@1.0/now/cache`, {
75
+ method: 'HEAD',
76
+ }).then((res) => {
77
+ if (res.ok) {
78
+ return true;
79
+ }
80
+ return false;
68
81
  });
69
- let isHyperBeamCompatible = false;
70
- if (res.ok) {
71
- isHyperBeamCompatible = true;
72
- }
73
- this.checkHyperBeamPromise = Promise.resolve(isHyperBeamCompatible);
74
- return isHyperBeamCompatible;
82
+ return this.checkHyperBeamPromise;
75
83
  }
76
84
  async getState({ strict } = { strict: this.strict }) {
77
85
  if (await this.checkHyperBeamCompatibility()) {
78
- const res = await fetch(`${this.hyperbeamUrl}${this.processId}~process@1.0/now/cache/serialize~json@1.0`, {
79
- method: 'GET',
80
- redirect: 'follow',
81
- mode: 'cors',
82
- headers: {
83
- 'Content-Type': 'application/json',
84
- },
85
- });
86
- if (!res.ok) {
87
- throw new Error('Failed to fetch ant state');
86
+ let retries = 0;
87
+ while (retries < 3) {
88
+ try {
89
+ const res = await fetch(`${this.hyperbeamUrl}${this.processId}~process@1.0/compute/cache/serialize~json@1.0`, {
90
+ method: 'GET',
91
+ redirect: 'follow',
92
+ mode: 'cors',
93
+ headers: {
94
+ 'Content-Type': 'application/json',
95
+ },
96
+ });
97
+ if (res.status !== 200) {
98
+ throw new Error(`Failed to fetch ant state: ${res?.statusText ?? 'Unknown error'}`);
99
+ }
100
+ const unnormalizedState = (await res.json());
101
+ if (!isHyperBeamANTState(unnormalizedState)) {
102
+ // don't retry if the state is bad, fallback to the CU
103
+ break;
104
+ }
105
+ // normalize and return the state
106
+ return convertHyperBeamStateToAoANTState(unnormalizedState);
107
+ }
108
+ catch (error) {
109
+ this.logger.error(`Failed to fetch process state from HyperBEAM (attempt ${retries + 1} / 3)`, {
110
+ cause: error,
111
+ });
112
+ retries++;
113
+ await new Promise((resolve) => setTimeout(resolve, 1000 * retries ** 2));
114
+ }
88
115
  }
89
- return convertHyperBeamStateToAoANTState((await res.json()));
90
116
  }
91
117
  const tags = [{ name: 'Action', value: 'State' }];
92
118
  const res = await this.process.read({
@@ -260,25 +286,8 @@ export class AoANTReadable {
260
286
  * ```
261
287
  */
262
288
  async getBalances({ strict } = { strict: this.strict }) {
263
- if (await this.checkHyperBeamCompatibility()) {
264
- const res = await fetch(`${this.hyperbeamUrl}${this.processId}~process@1.0/now/cache/balances/serialize~json@1.0`, {
265
- method: 'GET',
266
- redirect: 'follow',
267
- mode: 'cors',
268
- headers: {
269
- 'Content-Type': 'application/json',
270
- },
271
- });
272
- if (!res.ok) {
273
- throw new Error('Failed to fetch ant balances');
274
- }
275
- const result = (await res.json());
276
- return result.balances;
277
- }
278
- const tags = [{ name: 'Action', value: 'Balances' }];
279
- const balances = await this.process.read({
280
- tags,
281
- });
289
+ const state = await this.getState();
290
+ const balances = state.Balances;
282
291
  if (strict)
283
292
  parseSchemaResult(AntBalancesSchema, balances);
284
293
  return balances;
@@ -37,6 +37,20 @@ export const sortANTRecords = (antRecords) => {
37
37
  // now that they are sorted, add the index to each record - this is their position in the sorted list and is used to enforce undername limits
38
38
  return Object.fromEntries(sortedEntries.map(([a, aRecord], index) => [a, { ...aRecord, index }]));
39
39
  };
40
+ export const isHyperBeamANTState = (state) => {
41
+ return ('name' in state &&
42
+ 'ticker' in state &&
43
+ 'description' in state &&
44
+ 'keywords' in state &&
45
+ 'denomination' in state &&
46
+ 'owner' in state &&
47
+ 'controllers' in state &&
48
+ 'records' in state &&
49
+ 'balances' in state &&
50
+ 'logo' in state &&
51
+ 'totalsupply' in state &&
52
+ 'initialized' in state);
53
+ };
40
54
  /**
41
55
  * Convert HyperBeam serialized ANT state to backwards compatible format.
42
56
  *
@@ -14,4 +14,4 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
17
- export const version = '3.14.0-alpha.8';
17
+ export const version = '3.14.0';
@@ -18,11 +18,12 @@ export declare class AoANTReadable implements AoANTRead {
18
18
  private strict;
19
19
  private hyperbeamUrl;
20
20
  private checkHyperBeamPromise;
21
+ private logger;
21
22
  constructor(config: ANTConfigOptionalStrict);
22
23
  /**
23
- * Check if the process is hyperbeam compatible. If so, we'll use the hyperbeam node to fetch the state.
24
+ * Check if the process is HyperBeam compatible. If so, we'll use the HyperBeam node to fetch the state.
24
25
  *
25
- * @returns {Promise<boolean>} True if the process is hyperbeam compatible, false otherwise.
26
+ * @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise.
26
27
  */
27
28
  private checkHyperBeamCompatibility;
28
29
  getState({ strict }?: AntReadOptions): Promise<AoANTState>;
@@ -24,6 +24,7 @@ import { ANTRecords, AoANTState, HyperBeamANTState, SortedANTRecords } from '../
24
24
  * @param antRecords - The ANT records to sort.
25
25
  */
26
26
  export declare const sortANTRecords: (antRecords: ANTRecords) => SortedANTRecords;
27
+ export declare const isHyperBeamANTState: (state: any) => state is HyperBeamANTState;
27
28
  /**
28
29
  * Convert HyperBeam serialized ANT state to backwards compatible format.
29
30
  *
@@ -13,4 +13,4 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- export declare const version = "3.14.0-alpha.7";
16
+ export declare const version = "3.14.0-alpha.9";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ar.io/sdk",
3
- "version": "3.14.0-alpha.8",
3
+ "version": "3.14.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ar-io/ar-io-sdk.git"