Skip to content

Commit

Permalink
feat(first issue): setup examples, readme, and initial gateways provider
Browse files Browse the repository at this point in the history
  • Loading branch information
atticusofsparta committed Feb 23, 2024
1 parent 5d87e2e commit 5a9e232
Show file tree
Hide file tree
Showing 16 changed files with 273 additions and 180 deletions.
55 changes: 45 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ar-io/sdk
# @ar-io/sdk

This is the home of ar.io SDK. This SDK provides functionality for interacting with the ArNS and ar.io ecosystem. It is available for both NodeJS and Web environments.

Expand Down Expand Up @@ -35,11 +35,18 @@ yarn add @ar-io/sdk
## Quick Start

```typescript
const arIO = new ArIO();
import { ArIO } from '@ar-io/sdk';

const state = arIO.getContractState({
contractTxId: 'bLAgYxAdX2Ry-nt6aH2ixgvJXbpsEYm28NgJgyqfs-U',
});
const address = 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ';
const arIO = new ArIO({});

const testnetClient = arIO.testnet;
const devnetClient = arIO.devnet;

const testnetBalance = await testnetClient.getBalance({ address });
const tesnetBalances = await testnetClient.getBalances();
const testnetGateway = await testnetClient.getGateway({ address });
const testnetGateways = await testnetClient.getGateways();
```

## Usage
Expand All @@ -51,19 +58,40 @@ The SDK is provided in both CommonJS and ESM formats, and it's compatible with b
#### Bundlers (Webpack, Rollup, ESbuild, etc.)

```javascript
// INSERT EXAMPLE FOR USING IN ESM PROJECT
import { ArIO } from '@ar-io/sdk';

const arIO = new ArIO({});
const testnetClient = arIO.testnet;
const devnetClient = arIO.devnet;

const testnetGateways = await testnetClient.getGateways();
const devnetGateways = await devnetClient.getGateways();
```

#### Browser

```javascript
// INSERT EXAMPLE FOR USING IN BROWSER PROJECT
```html
<script type="module">
import { ArIO } from 'https://unpkg.com/@ar-io/sdk';
// set up our client
const arIO = new ArIO({}).testnet;
// fetch gateways
const gateways = await arIO.getGateways();
</script>
```

### Node

```javascript
// INSERT EXAMPLE FOR USING IN CJS PROJECT
const { ArIO } = require('@ar-io/sdk');

const arIO = new ArIO({});
const testnetClient = arIO.testnet;
const devnetClient = arIO.devnet;

const testnetGateways = await testnetClient.getGateways();
const devnetGateways = await devnetClient.getGateways();
```

### Typescript
Expand All @@ -74,7 +102,14 @@ Types are exported from `./lib/types/[node/web]/index.d.ts` and should be automa

## APIs

[INSERT A LIST OF ALL THE APIS PROVIDED BY THE SDK AND HOW TO USE THEM]
The contract that the following methods retrieve data from are determined by the `testnet` or `devnet` clients - see examples above for implementation details.

| Method Name | Description |
| ------------------------- | ----------------------------------------------- |
| `getBalance({ address })` | Retrieves the balance of the specified address. |
| `getBalances()` | Retrieves all balances on the ArIO contract. |
| `getGateway({ address })` | Retrieves the specified gateway by address. |
| `getGateways()` | Retrieves all gateways. |

## Developers

Expand Down
12 changes: 9 additions & 3 deletions examples/node/index.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const { DefaultClient } = require('../../lib/index.js');
const { ArIO } = require('../../lib/cjs/node');

(async () => {
const client = new DefaultClient();
console.log(client);
const arIO = new ArIO({});
const testnetClient = arIO.testnet;
const devnetClient = arIO.devnet;

const testnetGateways = await testnetClient.getGateways();
const devnetGateways = await devnetClient.getGateways();

console.dir({ testnetGateways, devnetGateways }, { depth: 2 });
})();
12 changes: 9 additions & 3 deletions examples/node/index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { DefaultClient } from '../../lib/index.js';
import { ArIO } from '../../lib/esm/node/index.js';

(async () => {
const client = new DefaultClient();
console.log(client);
const arIO = new ArIO({});
const testnetClient = arIO.testnet;
const devnetClient = arIO.devnet;

const testnetGateways = await testnetClient.getGateways();
const devnetGateways = await devnetClient.getGateways();

console.dir({ testnetGateways, devnetGateways }, { depth: 2 });
})();
90 changes: 78 additions & 12 deletions examples/web/index.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,88 @@
<html>
<head>
<script type="module" src="./web.bundle.min.js"></script>
<style>
/* Center the button */
body {
padding: 10px;
}
</style>
<!-- import permanent tailwind -->
<script src="https://arweave.net/RjXXBjP2GCZZUg4gSW1Hyr9GtLG-o59QCHrKiITtpQw"></script>
<script>
tailwind.config = {
theme: {
borderWidth: {
1: '1px',
},
extend: {
colors: {
primary: '#FFBB38',
background: '#141416',
surface: '#222224',
surfaceSecondary: '#2E2E30',
textPrimary: '#F5F5F5',
textSubtle: '#7A7A7C',
},
},
},
};
</script>
</head>
<body>
<body class="bg-background flex flex-col items-center p-10">
<div
class="bg-surface flex flex-col gap-5 items-end justify-center p-5 rounded-md h-full"
style="width: 750px"
>
<div class="h-full w-full" style="overflow-y: scroll">
<table class="w-full bg-background text-textPrimary">
<thead>
<tr>
<th class="px-4 py-2">Domain</th>
<th class="px-4 py-2">Owner</th>
<th class="px-4 py-2">Stake</th>
</tr>
</thead>
<tbody id="table-body">
<!-- Add more rows as needed -->
</tbody>
</table>
</div>
<button
id="fetch-gateways-button"
class="animate-bounce bg-primary text-textPrimary p-2 rounded-md w-full text-surface hover:shadow-xl"
style="color: black"
>
Fetch Gateways
</button>
</div>
<script type="module">
import { DefaultClient } from './web.bundle.min.js';
import { ArIO } from './web.bundle.min.js';

// set up our client
const client = new DefaultClient();
const arIO = new ArIO({}).testnet;

async function setGateways() {
const tableBody = document.getElementById('table-body');
tableBody.innerHTML = `
<tr>
<td class="border border-surface px-4 py-2">Loading...</td>
</tr>
`;
const gateways = await arIO.getGateways();

tableBody.innerHTML = Object.entries(gateways)
.map(([gatewayOwner, gateway]) => {
return `
<tr>
<td class="border border-surface px-4 py-2 text-primary"><a href="https://${gateway.settings.fqdn}" target="_blank">${gateway.settings.fqdn}</a></td>
<td class="border border-surface px-4 py-2 text-primary"><a href="https://arscan.io/address/${gatewayOwner}" target="_blank">${gatewayOwner}</a></td>
<td class="border border-surface px-4 py-2">${gateway.operatorStake} IO</td>
</tr>
`;
})
.join('');
}

// print the client to the console
console.log(client);
const fetchGatewaysButton = document.getElementById(
'fetch-gateways-button',
);
fetchGatewaysButton.addEventListener('click', () => {
setGateways();
});
</script>
</body>
</html>
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"scripts": {
"build:web": "node bundle.mjs",
"build:esm": "yarn tsc -p tsconfig.json",
"build:cjs": "yarn tsc -p tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > lib/cjs/package.json",
"build:cjs": "yarn tsc -p tsconfig.cjs.json && echo {\"type\": \"commonjs\"} > lib/cjs/package.json",
"build:types": "yarn tsc -p tsconfig.types.json",
"build": "yarn clean && yarn build:web && yarn build:esm && yarn build:cjs && yarn build:types",
"clean": "rimraf [ lib coverage bundles ]",
Expand All @@ -50,10 +50,10 @@
"lint:fix": "eslint src --fix",
"format": "prettier --check .",
"format:fix": "prettier --write .",
"test": "c8 jest .",
"test": "yarn clean && c8 jest .",
"prepare": "husky install",
"example:mjs": "yarn build:esm && node examples/node/index.mjs",
"example:cjs": "yarn build:esm && node examples/node/index.mjs",
"example:cjs": "yarn build:cjs && node examples/node/index.cjs",
"example:web": "yarn build:web && cp -r bundles/* examples/web && http-server --port 8080 --host -o examples/web"
},
"devDependencies": {
Expand Down Expand Up @@ -97,6 +97,7 @@
"dependencies": {
"arweave": "^1.14.4",
"axios": "1.4.0",
"setimmediate": "^1.0.5",
"warp-contracts": "^1.4.34",
"winston": "^3.11.0"
}
Expand Down
57 changes: 28 additions & 29 deletions src/common/caches/arns-remote-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
import { ARNS_TESTNET_REGISTRY_TX } from '../../constants.js';
import {
ArIOContract,
ArNSStateResponse,
ContractCache,
EvaluatedContractState,
Gateway,
HTTPClient,
} from '../../types/index.js';
import { NotFound } from '../error.js';
import { AxiosHTTPService } from '../http.js';
import { DefaultLogger } from '../logger.js';

Expand Down Expand Up @@ -53,31 +54,18 @@ export class ArNSRemoteCache implements ContractCache, ArIOContract {
return this;
}

async getContractState<ContractState>({
contractTxId,
}: {
contractTxId: string;
}): Promise<ContractState> {
this.logger.debug(`Fetching contract state`);

const { state } = await this.http.get<
EvaluatedContractState<ContractState>
>({
endpoint: `/contract/${contractTxId.toString()}`,
});

return state;
}

async getGateway({ address }: { address: string }) {
if (!this.contractTxId) {
throw new Error(
'Contract TxId not set, set one before calling this function.',
);
}
this.logger.debug(`Fetching gateway ${address}`);
const gateway = await this.http.get<Gateway>({
endpoint: `/gateway/${address}`,
const gateway = await this.getGateways().then((gateways) => {
if (gateways[address] === undefined) {
throw new NotFound(`Gateway not found: ${address}`);
}
return gateways[address];
});
return gateway;
}
Expand All @@ -89,10 +77,12 @@ export class ArNSRemoteCache implements ContractCache, ArIOContract {
);
}
this.logger.debug(`Fetching gateways`);
const gateways = await this.http.get<Gateway[]>({
endpoint: `/gateways`,
const { result } = await this.http.get<
ArNSStateResponse<'result', Record<string, Gateway>>
>({
endpoint: `/contract/${this.contractTxId.toString()}/read/gateways`,
});
return gateways;
return result;
}

async getBalance({ address }: { address: string }) {
Expand All @@ -102,10 +92,17 @@ export class ArNSRemoteCache implements ContractCache, ArIOContract {
);
}
this.logger.debug(`Fetching balance for ${address}`);
const balance = await this.http.get<number>({
endpoint: `/balance/${address}`,
});
return balance;
const { result } = await this.http
.get<ArNSStateResponse<'result', number>>({
endpoint: `/contract/${this.contractTxId.toString()}/state/balances/${address}`,
})
.catch((e) => {
if (e instanceof NotFound) {
return { result: 0 };
}
throw e;
});
return result;
}

async getBalances() {
Expand All @@ -115,9 +112,11 @@ export class ArNSRemoteCache implements ContractCache, ArIOContract {
);
}
this.logger.debug(`Fetching balances`);
const balances = await this.http.get<Record<string, number>>({
endpoint: `/balances`,
const { result } = await this.http.get<
ArNSStateResponse<'result', Record<string, number>>
>({
endpoint: `/contract/${this.contractTxId.toString()}/state/balances`,
});
return balances;
return result;
}
}
6 changes: 6 additions & 0 deletions src/common/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ export class FailedRequestError extends BaseError {
super(`Failed request: ${status}: ${message}`);
}
}

export class UnknownError extends BaseError {
constructor(message: string) {
super(message);
}
}

0 comments on commit 5a9e232

Please sign in to comment.