UNPKG

@ar.io/sdk

Version:

[![codecov](https://codecov.io/gh/ar-io/ar-io-sdk/graph/badge.svg?token=7dXKcT7dJy)](https://codecov.io/gh/ar-io/ar-io-sdk)

156 lines (155 loc) 6.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AoANTRegistryWriteable = exports.AoANTRegistryReadable = exports.ANTRegistry = void 0; /** * Copyright (C) 2022-2024 Permanent Data Solutions, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const constants_js_1 = require("../constants.js"); const index_js_1 = require("../types/index.js"); const ao_js_1 = require("../utils/ao.js"); const index_js_2 = require("./index.js"); const logger_js_1 = require("./logger.js"); class ANTRegistry { static init(config) { if (config !== undefined && 'signer' in config) { return new AoANTRegistryWriteable(config); } return new AoANTRegistryReadable(config); } } exports.ANTRegistry = ANTRegistry; class AoANTRegistryReadable { process; hyperbeamUrl; checkHyperBeamPromise; logger; constructor(config) { this.logger = config?.logger ?? logger_js_1.Logger.default; if (config === undefined || Object.keys(config).length === 0) { this.process = new index_js_2.AOProcess({ processId: constants_js_1.ANT_REGISTRY_ID, }); } else if ((0, index_js_1.isProcessConfiguration)(config)) { this.process = config.process; } else if ((0, index_js_1.isProcessIdConfiguration)(config)) { this.process = new index_js_2.AOProcess({ processId: config.processId, }); } else { throw new index_js_2.InvalidContractConfigurationError(); } if (config?.hyperbeamUrl !== undefined) { this.hyperbeamUrl = new URL(config.hyperbeamUrl).toString(); this.checkHyperBeamPromise = this.checkHyperBeamCompatibility(); } } /** * Check if the process is HyperBeam compatible. If so, we'll use the HyperBeam node to fetch the state. * * @returns {Promise<boolean>} True if the process is HyperBeam compatible, false otherwise. */ async checkHyperBeamCompatibility() { if (this.hyperbeamUrl === undefined) { return Promise.resolve(false); } if (this.checkHyperBeamPromise !== undefined) { return this.checkHyperBeamPromise; } this.logger.debug('Checking HyperBeam compatibility'); this.checkHyperBeamPromise = fetch( // use /now to force a refresh of the cache state, then compute when calling it for keys `${this.hyperbeamUrl.toString()}${this.process.processId}~process@1.0/now/cache/acl`, { method: 'HEAD', signal: AbortSignal.timeout(5000), // 5 second timeout }) .then((res) => { if (res.ok) { this.logger.debug('HyperBeam compatible'); return true; } this.logger.debug('HyperBeam not compatible'); return false; }) .catch((error) => { this.logger.debug('Failed to check HyperBeam compatibility', { cause: error, }); return false; }); return this.checkHyperBeamPromise; } // Should we rename this to "getANTsByAddress"? seems more clear, though not same as handler name async accessControlList({ address, }) { if (await this.checkHyperBeamCompatibility()) { let retries = 0; while (retries < 3) { try { this.logger.debug('Fetching ant registry acl for address from hyperbeam', address); const res = await fetch(`${this.hyperbeamUrl?.toString()}${this.process.processId}~process@1.0/compute/cache/acl/${address}/serialize~json@1.0`); if (res.status !== 200) { this.logger.debug('Failed to fetch ant registry acl for address from hyperbeam', address, res.status, res.statusText); throw new Error(`Failed to fetch ant registry acl for address ${address}: ${res?.statusText ?? 'Unknown error'}`); } this.logger.debug('Fetched ant registry acl for address from hyperbeam', address); const json = (await res.json()); return { Owned: json.Owned, Controlled: json.Controlled, }; } catch (error) { retries++; this.logger.debug('Failed to fetch ant registry acl for address from hyperbeam', address, retries); await new Promise((resolve) => setTimeout(resolve, 1000 * retries ** 2)); } } } this.logger.debug('Fetching ant registry acl for address from process', address); return this.process.read({ tags: [ { name: 'Action', value: 'Access-Control-List' }, { name: 'Address', value: address }, ], }); } /* * This is the same as accessControlList, but with a cleaner DX to make it clearer * that we're fetching the list of ANTs owned or controlled by an address. */ async getAntsForAddress({ address, }) { return this.accessControlList({ address }); } } exports.AoANTRegistryReadable = AoANTRegistryReadable; class AoANTRegistryWriteable extends AoANTRegistryReadable { signer; constructor({ signer, ...config }) { super(config); this.signer = (0, ao_js_1.createAoSigner)(signer); } async register({ processId, }) { return this.process.send({ tags: [ { name: 'Action', value: 'Register' }, { name: 'Process-Id', value: processId }, ], signer: this.signer, }); } } exports.AoANTRegistryWriteable = AoANTRegistryWriteable;