irys-complete-toolkit
Version:
Complete Irys SDK toolkit supporting all chains, tokens, and features
425 lines (364 loc) • 10.4 kB
text/typescript
/**
* Irys REST API Client
* Comprehensive REST API client for Irys operations
*/
import {
AccountInfo,
TransactionInfo,
IrysTag,
BalanceApproval,
IrysError,
NetworkError
} from '../types';
export class IrysRestClient {
private baseUrl: string;
private timeout: number;
constructor(baseUrl: string = 'https://uploader.irys.xyz', timeout: number = 30000) {
this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash
this.timeout = timeout;
}
/**
* Make HTTP request with error handling
*/
private async request(
endpoint: string,
options: RequestInit = {}
): Promise<any> {
const url = `${this.baseUrl}${endpoint}`;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
});
clearTimeout(timeoutId);
if (!response.ok) {
const errorText = await response.text().catch(() => '');
throw new NetworkError(
`HTTP ${response.status}: ${response.statusText}${errorText ? ` - ${errorText}` : ''}`,
response.status
);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof NetworkError) {
throw error;
}
if ((error as any)?.name === 'AbortError') {
throw new IrysError(`Request timeout after ${this.timeout}ms`);
}
throw new IrysError(`Request failed: ${error}`);
}
}
/**
* Get general info about the Irys node
*/
async getInfo(): Promise<any> {
return this.request('/info');
}
/**
* Get public information
*/
async getPublicInfo(): Promise<any> {
return this.request('/public');
}
/**
* Get node status
*/
async getStatus(): Promise<any> {
return this.request('/status');
}
/**
* Get account balance
*/
async getBalance(address: string, token?: string): Promise<string> {
const params = new URLSearchParams({ address });
if (token) {
params.append('token', token);
}
const result = await this.request(`/account/balance?${params}`);
return result.balance || '0';
}
/**
* Get account information
*/
async getAccountInfo(address: string): Promise<AccountInfo> {
const result = await this.request(`/account/${address}`);
return result;
}
/**
* Get transaction by ID
*/
async getTransaction(txId: string): Promise<TransactionInfo> {
return this.request(`/tx/${txId}`);
}
/**
* Get transaction status
*/
async getTransactionStatus(txId: string): Promise<any> {
return this.request(`/tx/${txId}/status`);
}
/**
* Get transaction data
*/
async getTransactionData(txId: string): Promise<any> {
return this.request(`/tx/${txId}/data`);
}
/**
* Get transaction metadata (tags)
*/
async getTransactionTags(txId: string): Promise<IrysTag[]> {
const result = await this.request(`/tx/${txId}/tags`);
return result.tags || [];
}
/**
* Get balance approvals for an address
*/
async getBalanceApprovals(
payingAddress?: string,
token?: string,
approvedAddress?: string
): Promise<BalanceApproval[]> {
const params = new URLSearchParams();
if (payingAddress) params.append('payingAddress', payingAddress);
if (token) params.append('token', token);
if (approvedAddress) params.append('approvedAddress', approvedAddress);
const result = await this.request(`/account/approval?${params}`);
return result.approvals || [];
}
/**
* Get upload price for data size
*/
async getPrice(bytes: number, target?: string): Promise<string> {
const params = new URLSearchParams({ bytes: bytes.toString() });
if (target) params.append('target', target);
const result = await this.request(`/price?${params}`);
return result.price || '0';
}
/**
* Get upload prices for multiple data sizes
*/
async getPrices(sizes: number[]): Promise<Record<number, string>> {
const promises = sizes.map(async size => {
const price = await this.getPrice(size);
return { size, price };
});
const results = await Promise.all(promises);
return results.reduce((acc, { size, price }) => {
acc[size] = price;
return acc;
}, {} as Record<number, string>);
}
/**
* Post data to Irys (raw HTTP upload)
*/
async postData(
data: string | ArrayBuffer | Uint8Array,
tags: IrysTag[] = [],
target?: string
): Promise<any> {
const headers: Record<string, string> = {};
// Add tags as headers
tags.forEach((tag, index) => {
headers[`Tag-${index}-Name`] = tag.name;
headers[`Tag-${index}-Value`] = tag.value;
});
if (target) {
headers['Target'] = target;
}
return this.request('/tx', {
method: 'POST',
headers,
body: data as BodyInit,
});
}
/**
* Get peers information
*/
async getPeers(): Promise<any> {
return this.request('/peers');
}
/**
* Get wallet information
*/
async getWallet(address: string): Promise<any> {
return this.request(`/wallet/${address}`);
}
/**
* Get block by height
*/
async getBlock(height: number): Promise<any> {
return this.request(`/block/height/${height}`);
}
/**
* Get current block height
*/
async getCurrentHeight(): Promise<number> {
const result = await this.request('/block/current');
return result.height || 0;
}
/**
* Get network metrics
*/
async getMetrics(): Promise<any> {
return this.request('/metrics');
}
/**
* Health check endpoint
*/
async healthCheck(): Promise<boolean> {
try {
await this.request('/health');
return true;
} catch (error) {
return false;
}
}
/**
* Download data from Irys gateway
*/
async downloadData(txId: string): Promise<any> {
const gatewayUrl = `https://gateway.irys.xyz/${txId}`;
try {
const response = await fetch(gatewayUrl);
if (!response.ok) {
throw new NetworkError(
`Failed to download data: ${response.status} ${response.statusText}`,
response.status
);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else if (contentType && contentType.startsWith('text/')) {
return await response.text();
} else {
return await response.arrayBuffer();
}
} catch (error) {
if (error instanceof NetworkError) {
throw error;
}
throw new IrysError(`Failed to download data: ${error}`);
}
}
/**
* Get data as stream (for large files)
*/
async downloadDataStream(txId: string): Promise<ReadableStream | null> {
const gatewayUrl = `https://gateway.irys.xyz/${txId}`;
try {
const response = await fetch(gatewayUrl);
if (!response.ok) {
throw new NetworkError(
`Failed to download data: ${response.status} ${response.statusText}`,
response.status
);
}
return response.body;
} catch (error) {
if (error instanceof NetworkError) {
throw error;
}
throw new IrysError(`Failed to download data stream: ${error}`);
}
}
/**
* Verify transaction receipt
*/
async verifyReceipt(receipt: any): Promise<boolean> {
try {
const result = await this.request('/receipt/verify', {
method: 'POST',
body: JSON.stringify(receipt),
});
return result.valid === true;
} catch (error) {
throw new IrysError(`Failed to verify receipt: ${error}`);
}
}
/**
* Get transaction receipt
*/
async getReceipt(txId: string): Promise<any> {
return this.request(`/tx/${txId}/receipt`);
}
/**
* Search transactions by owner
*/
async searchTransactionsByOwner(
owner: string,
limit: number = 100,
offset: number = 0
): Promise<TransactionInfo[]> {
const params = new URLSearchParams({
owner,
limit: limit.toString(),
offset: offset.toString(),
});
const result = await this.request(`/tx/search?${params}`);
return result.transactions || [];
}
/**
* Search transactions by tag
*/
async searchTransactionsByTag(
name: string,
value: string,
limit: number = 100,
offset: number = 0
): Promise<TransactionInfo[]> {
const params = new URLSearchParams({
'tag-name': name,
'tag-value': value,
limit: limit.toString(),
offset: offset.toString(),
});
const result = await this.request(`/tx/search?${params}`);
return result.transactions || [];
}
/**
* Get bundle information
*/
async getBundleInfo(bundleId: string): Promise<any> {
return this.request(`/bundle/${bundleId}`);
}
/**
* Get data item from bundle
*/
async getDataItem(bundleId: string, itemId: string): Promise<any> {
return this.request(`/bundle/${bundleId}/data/${itemId}`);
}
/**
* Set custom base URL
*/
setBaseUrl(baseUrl: string): void {
this.baseUrl = baseUrl.replace(/\/$/, '');
}
/**
* Set request timeout
*/
setTimeout(timeout: number): void {
this.timeout = timeout;
}
/**
* Get current configuration
*/
getConfig(): { baseUrl: string; timeout: number } {
return {
baseUrl: this.baseUrl,
timeout: this.timeout,
};
}
}