Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
**dist/
!**/packages/bundler/dist
**.idea/
**.npmrc
**.npmrc
**.env
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ Queries Arweave gateways using GraphQL for transaction data.

```typescript
const response = await permaweb.getGQLData({
gateway: 'arweave.net',
ids: ['TX_ID_1', 'TX_ID_2'],
tags: [{ name: 'App-Name', values: ['MyApp'] }],
owners: ['OWNER_ADDRESS'],
Expand All @@ -172,7 +171,6 @@ Fetches all pages of GraphQL data automatically.

```typescript
const allData = await permaweb.getAggregatedGQLData({
gateway: 'arweave.net',
tags: [{ name: 'App-Name', values: ['MyApp'] }],
paginator: 100
}, (message) => console.log(message)); // Optional progress callback
Expand Down
4 changes: 2 additions & 2 deletions sdk/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 80 additions & 6 deletions sdk/src/common/ao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
TagType,
} from '../helpers/types.ts';
import { getTagValue, globalLog } from '../helpers/utils.ts';
import { getArweaveDataWith } from './arweave.ts';
import { getGQLDataWith } from './gql.ts';

const GATEWAY_RETRY_COUNT = 100;

export async function aoSpawn(deps: DependencyType, args: ProcessSpawnType): Promise<string> {
const tags = [{ name: 'Authority', value: deps.node?.authority ?? AO.mu }];
Expand Down Expand Up @@ -48,7 +52,10 @@ export function aoSendWith(deps: DependencyType) {

export async function aoSend(deps: DependencyType, args: MessageSendType): Promise<string> {
try {
const tags: TagType[] = [{ name: 'Action', value: args.action }, { name: 'Message-Timestamp', value: new Date().getTime().toString() }];
const tags: TagType[] = [
{ name: 'Action', value: args.action },
{ name: 'Message-Timestamp', value: new Date().getTime().toString() },
];
if (args.tags) tags.push(...args.tags);

const data = args.useRawData ? args.data : JSON.stringify(args.data);
Expand All @@ -73,7 +80,7 @@ export function readProcessWith(deps: DependencyType) {
}

export async function readProcess(deps: DependencyType, args: ProcessReadType) {
const node = deps.node?.url ?? HB.defaultNode
const node = deps.node?.url ?? HB.defaultNode;
let url = `${node}/${args.processId}[email protected]/now/${args.path}`;
if (args.serialize) url += '/[email protected]';

Expand All @@ -83,8 +90,7 @@ export async function readProcess(deps: DependencyType, args: ProcessReadType) {
return res.json();
}

throw new Error('Error getting state from HyperBEAM.')

throw new Error('Error getting state from HyperBEAM.');
} catch (e: any) {
if (args.fallbackAction) {
const result = await aoDryRun(deps, { processId: args.processId, action: args.fallbackAction });
Expand Down Expand Up @@ -282,9 +288,9 @@ export async function handleProcessEval(

if (args.evalSrc) src = args.evalSrc;
else if (args.evalTxId) {
const getArweaveData = getArweaveDataWith(deps);
try {
const srcFetch = await fetch(getTxEndpoint(args.evalTxId));
src = await srcFetch.text();
src = await getArweaveData(getTxEndpoint(args.evalTxId));
} catch (e: any) {
throw new Error(e);
}
Expand Down Expand Up @@ -354,4 +360,72 @@ export function aoCreateProcessWith(deps: DependencyType) {
throw new Error(e.message ?? 'Error creating process');
}
};
}

export async function aoCreateProcess(
deps: DependencyType,
args: ProcessCreateType,
statusCB?: (status: any) => void,
): Promise<string> {
try {
const spawnArgs: any = {
module: args.module || AO.module,
scheduler: args.scheduler || AO.scheduler,
};

if (args.data) spawnArgs.data = args.data;
if (args.tags) spawnArgs.tags = args.tags;

statusCB && statusCB(`Spawning process...`);
const processId = await aoSpawn(deps, spawnArgs);

if (args.evalTxId || args.evalSrc) {
statusCB && statusCB(`Process retrieved!`);
statusCB && statusCB('Sending eval...');

try {
const evalResult = await handleProcessEval(deps, {
processId: processId,
evalTxId: args.evalTxId || null,
evalSrc: args.evalSrc || null,
evalTags: args.evalTags,
});

if (evalResult && statusCB) statusCB('Eval complete');
} catch (e: any) {
throw new Error(e.message ?? 'Error creating process');
}
}

return processId;
} catch (e: any) {
throw new Error(e.message ?? 'Error creating process');
}
}

export async function waitForProcess(deps:DependencyType,args: { processId: string; noRetryLimit?: boolean }) {
let retries = 0;
const retryLimit = args.noRetryLimit ? Infinity : GATEWAY_RETRY_COUNT;
const getGQLData = getGQLDataWith(deps)

while (retries < retryLimit) {
await new Promise((resolve) => setTimeout(resolve, 2000));

const gqlResponse = await getGQLData({
ids: [args.processId],
});

if (gqlResponse?.data?.length) {
const foundProcess = gqlResponse.data[0].node.id;
globalLog(`Process found: ${foundProcess} (Try ${retries + 1})`);
return foundProcess;
} else {
globalLog(`Process not found: ${args.processId} (Try ${retries + 1})`);
retries++;
}
}

if (retryLimit !== Infinity) {
throw new Error(`Process not found, please try again`);
}
}
15 changes: 15 additions & 0 deletions sdk/src/common/ario.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { DependencyType } from 'helpers/types.ts';

export function getPrimaryNameWith(deps: DependencyType) {
return async (address: string): Promise<string> => {
try {
const { name } = await deps.ario.getPrimaryName({
address,
});
return name;
} catch (error: any) {
console.error(error.message ?? `Error fetching ArNS primary name for ${address}`);
return '';
}
};
}
17 changes: 16 additions & 1 deletion sdk/src/common/arweave.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ArconnectSigner, createData } from '@dha-team/arbundles/web';

import { TAGS, UPLOAD } from '../helpers/config.ts';
import { GATEWAYS, TAGS, UPLOAD } from '../helpers/config.ts';
import { DependencyType, TagType } from '../helpers/types.ts';
import { checkValidAddress, getBase64Data, getByteSize, getDataURLContentType } from '../helpers/utils.ts';

Expand Down Expand Up @@ -204,3 +204,18 @@ export async function runUpload(

return finishRes.json();
}

export function getArweaveDataWith(deps: DependencyType) {
return async (url: string, args: any = {}) => {
try {
if (deps.wayfinder) {
const result = await deps.wayfinder.request(`ar://${url}`, args);
return await result.json();
}
const result = await fetch(`https://${GATEWAYS.arweave}/${url}`, args);
return await result.json();
} catch (error) {
throw error;
}
};
}
35 changes: 20 additions & 15 deletions sdk/src/common/gql.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { GATEWAYS } from '../helpers/config.ts';
import {
BaseGQLArgsType,
BatchAGQLResponseType,
BatchGQLArgsType,
DefaultGQLResponseType,
GQLArgsType,
DependencyType,
GQLNodeResponseType,
QueryBodyGQLArgsType,
} from '../helpers/types.ts';

import { getArweaveDataWith } from './arweave.ts';

const CURSORS = {
p1: 'P1',
end: 'END',
Expand All @@ -17,7 +20,8 @@ const PAGINATORS = {
default: 100,
};

export async function getGQLData(args: GQLArgsType): Promise<DefaultGQLResponseType> {
export function getGQLDataWith(deps:DependencyType) {
return async function getGQLData(args: BaseGQLArgsType): Promise<DefaultGQLResponseType> {
const paginator = args.paginator ? args.paginator : PAGINATORS.default;
let data: GQLNodeResponseType[] = [];
let count: number = 0;
Expand All @@ -29,7 +33,7 @@ export async function getGQLData(args: GQLArgsType): Promise<DefaultGQLResponseT

try {
let queryBody: string = getQueryBody(args);
const response = await getResponse({ gateway: args.gateway ?? GATEWAYS.ao, query: getQuery(queryBody) });
const response = await getResponse(deps, { query: getQuery(queryBody) });

if (response?.data?.transactions?.edges?.length) {
data = [...response.data.transactions.edges];
Expand All @@ -53,9 +57,11 @@ export async function getGQLData(args: GQLArgsType): Promise<DefaultGQLResponseT
console.error(e);
return { data: data, count: count, nextCursor: nextCursor, previousCursor: null };
}
}
}}

export async function getAggregatedGQLData(args: GQLArgsType, callback?: (message: string) => void) {
export function getAggregatedGQLDataWith(deps:DependencyType) {
const getGQLData = getGQLDataWith(deps)
return async function getAggregatedGQLData(args: BaseGQLArgsType, callback?: (message: string) => void) {
let index = 1;
let fetchResult = await getGQLData(args);

Expand Down Expand Up @@ -86,19 +92,19 @@ export async function getAggregatedGQLData(args: GQLArgsType, callback?: (messag
}

return null;
}
}}

export async function getBatchGQLData(args: BatchGQLArgsType): Promise<BatchAGQLResponseType> {
export async function getBatchGQLData(deps: DependencyType, args: BatchGQLArgsType): Promise<BatchAGQLResponseType> {
let responseObject: BatchAGQLResponseType = {};
let queryBody: string = '';

for (const [queryKey, baseArgs] of Object.entries(args.entries)) {
responseObject[queryKey] = { data: [], count: 0, nextCursor: null, previousCursor: null };
queryBody += getQueryBody({ ...baseArgs, gateway: args.gateway ?? GATEWAYS.ao, queryKey: queryKey });
queryBody += getQueryBody({ ...baseArgs, queryKey: queryKey });
}

try {
const response = await getResponse({ gateway: args.gateway ?? GATEWAYS.ao, query: getQuery(queryBody) });
const response = await getResponse(deps,{ query: getQuery(queryBody) });

if (response && response.data) {
for (const queryKey of Object.keys(response.data)) {
Expand Down Expand Up @@ -177,10 +183,8 @@ function getQueryBody(args: QueryBodyGQLArgsType): string {
let nodeFields: string = `data { size type } owner { address } block { height timestamp }`;
let recipientsfield: string = '';

const gateway = args.gateway ?? GATEWAYS.ao;
const gateway = args.gateway ?? '';
switch (gateway) {
case GATEWAYS.arweave:
break;
case GATEWAYS.ao:
if (!cursor) txCount = `count`;
if (recipients) recipientsfield = `recipients: ${recipients}`;
Expand Down Expand Up @@ -221,12 +225,13 @@ function getQueryBody(args: QueryBodyGQLArgsType): string {
return body;
}

async function getResponse(args: { gateway: string; query: string }): Promise<any> {
async function getResponse(deps:DependencyType,args: { query: string }): Promise<any> {
const getArweaveData = getArweaveDataWith(deps);
try {
const response = await fetch(`https://${args.gateway}/graphql`, {
const response = await getArweaveData('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: args.query,
body: JSON.stringify({ query: args.query }),
});
return await response.json();
} catch (e: any) {
Expand Down
22 changes: 11 additions & 11 deletions sdk/src/helpers/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { checkValidAddress } from './utils.ts';
//import { checkValidAddress } from './utils.ts';

const arweaveEndpoint = 'https://arweave.net';
// TO DO : Needs to consider the ar://protocol and restructure `getRendererEndpoint`

export function getARBalanceEndpoint(walletAddress: string) {
return `${arweaveEndpoint}/wallet/${walletAddress}/balance`;
return `/wallet/${walletAddress}/balance`;
}

export function getTxEndpoint(txId: string) {
return `${arweaveEndpoint}/${txId}`;
return txId;
}

export function getRendererEndpoint(renderWith: string, tx: string) {
if (checkValidAddress(renderWith)) {
return `${arweaveEndpoint}/${renderWith}/?tx=${tx}`;
} else {
return `https://${renderWith}.arweave.net/?tx=${tx}`;
}
}
// export function getRendererEndpoint(renderWith: string, tx: string) {
// if (checkValidAddress(renderWith)) {
// return `ar://${renderWith}/?tx=${tx}`;
// } else {
// return `https://${renderWith}.arweave.net/?tx=${tx}`;
// }
// }
9 changes: 5 additions & 4 deletions sdk/src/helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ export type DependencyType = {
ao: any;
signer?: any;
arweave?: any;
node?: { url: string, scheduler: string, authority: string };
node?: { url: string; scheduler: string; authority: string };
ario?: any;
wayfinder?: any;
};

export type ProcessReadType = {
Expand Down Expand Up @@ -180,11 +182,10 @@ export type BaseGQLArgsType = {
minBlock?: number;
maxBlock?: number;
sort?: GQLSortType;
gateway?: string;
};

export type GQLArgsType = { gateway: string } & BaseGQLArgsType;

export type QueryBodyGQLArgsType = BaseGQLArgsType & { gateway?: string; queryKey?: string };
export type QueryBodyGQLArgsType = BaseGQLArgsType & { queryKey?: string };

export type BatchGQLArgsType = {
gateway: string;
Expand Down
1 change: 0 additions & 1 deletion sdk/src/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,3 @@ export function getBootTag(key: string, value: string) {
export function isValidMediaData(data: any) {
return checkValidAddress(data) || data.startsWith('data');
}

6 changes: 3 additions & 3 deletions sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function init(deps: Helpers.DependencyType) {
/* Assets */
createAtomicAsset: Services.createAtomicAssetWith(deps),
getAtomicAsset: Services.getAtomicAssetWith(deps),
getAtomicAssets: Services.getAtomicAssets,
getAtomicAssets: Services.getAtomicAssetsWith(deps),

/* Comments */
createComment: Services.createCommentWith(deps),
Expand All @@ -50,8 +50,8 @@ function init(deps: Helpers.DependencyType) {

/* Common */
resolveTransaction: Common.resolveTransactionWith(deps),
getGQLData: Common.getGQLData,
getAggregatedGQLData: Common.getAggregatedGQLData,
getGQLData: Common.getGQLDataWith(deps),
getAggregatedGQLData: Common.getAggregatedGQLDataWith(deps),
createProcess: Common.aoCreateProcessWith(deps),
readProcess: Common.aoDryRunWith(deps),
readState: Common.readProcessWith(deps),
Expand Down
Loading