Skip to content

Commit 92f48c9

Browse files
authored
core: arweave state reader (#991)
1 parent e3541f2 commit 92f48c9

5 files changed

Lines changed: 1614 additions & 3 deletions

File tree

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
export interface Options {
2+
readonly namespace?: string
3+
readonly owners?: string[]
4+
readonly arweaveUrl?: string
5+
readonly graphqlUrl?: string
6+
readonly rateLimitRetryDelayMs?: number
7+
}
8+
9+
export const defaults = {
10+
namespace: 'Sequence-Sessions',
11+
owners: ['AZ6R2mG8zxW9q7--iZXGrBknjegHoPzmG5IG-nxvMaM'],
12+
arweaveUrl: 'https://arweave.net',
13+
graphqlUrl: 'https://arweave.net/graphql',
14+
rateLimitRetryDelayMs: 5 * 60 * 1000,
15+
}
16+
17+
export async function findItems(
18+
filter: { [name: string]: undefined | string | string[] },
19+
options?: Options & { pageSize?: number; maxResults?: number },
20+
): Promise<{ [id: string]: { [tag: string]: string } }> {
21+
const namespace = options?.namespace ?? defaults.namespace
22+
const owners = options?.owners ?? defaults.owners
23+
const graphqlUrl = options?.graphqlUrl ?? defaults.graphqlUrl
24+
const rateLimitRetryDelayMs = options?.rateLimitRetryDelayMs ?? defaults.rateLimitRetryDelayMs
25+
const pageSize = options?.pageSize ?? 100
26+
const maxResults = options?.maxResults
27+
28+
const tags = Object.entries(filter).flatMap(([name, values]) =>
29+
values === undefined
30+
? []
31+
: [
32+
`{ name: "${namespace ? `${namespace}-${name}` : name}", values: [${typeof values === 'string' ? `"${values}"` : values.map((value) => `"${value}"`).join(', ')}] }`,
33+
],
34+
)
35+
36+
const edges: Array<{ cursor: string; node: { id: string; tags: Array<{ name: string; value: string }> } }> = []
37+
38+
for (let hasNextPage = true; hasNextPage && (maxResults === undefined || edges.length < maxResults); ) {
39+
const results = maxResults === undefined ? pageSize : Math.min(pageSize, maxResults - edges.length)
40+
41+
const query = `
42+
query {
43+
transactions(sort: HEIGHT_DESC, ${edges.length ? `first: ${results}, after: "${edges[edges.length - 1]!.cursor}"` : `first: ${results}`}, tags: [${tags.join(', ')}]${owners.length ? `, owners: [${owners.map((owner) => `"${owner}"`).join(', ')}]` : ''}) {
44+
pageInfo {
45+
hasNextPage
46+
}
47+
edges {
48+
cursor
49+
node {
50+
id
51+
tags {
52+
name
53+
value
54+
}
55+
}
56+
}
57+
}
58+
}
59+
`
60+
61+
let response: Response
62+
while (true) {
63+
response = await fetch(graphqlUrl, {
64+
method: 'POST',
65+
headers: { 'Content-Type': 'application/json' },
66+
body: JSON.stringify({ query }),
67+
redirect: 'follow',
68+
})
69+
if (response.status !== 429) {
70+
break
71+
}
72+
console.warn(
73+
`rate limited by ${graphqlUrl}, trying again in ${rateLimitRetryDelayMs / 1000} seconds at ${new Date(Date.now() + rateLimitRetryDelayMs).toLocaleTimeString()}`,
74+
)
75+
await new Promise((resolve) => setTimeout(resolve, rateLimitRetryDelayMs))
76+
}
77+
78+
const {
79+
data: { transactions },
80+
} = await response.json()
81+
82+
edges.push(...transactions.edges.slice(0, results))
83+
84+
hasNextPage = transactions.pageInfo.hasNextPage
85+
}
86+
87+
return Object.fromEntries(
88+
edges.map(({ node: { id, tags } }) => [
89+
id,
90+
Object.fromEntries(
91+
tags.map(({ name, value }) => [
92+
namespace && name.startsWith(`${namespace}-`) ? name.slice(namespace.length + 1) : name,
93+
value,
94+
]),
95+
),
96+
]),
97+
)
98+
}
99+
100+
export async function fetchItem(
101+
id: string,
102+
rateLimitRetryDelayMs = defaults.rateLimitRetryDelayMs,
103+
arweaveUrl = defaults.arweaveUrl,
104+
): Promise<Response> {
105+
while (true) {
106+
const response = await fetch(`${arweaveUrl}/${id}`, { redirect: 'follow' })
107+
if (response.status !== 429) {
108+
return response
109+
}
110+
console.warn(
111+
`rate limited by ${arweaveUrl}, trying again in ${rateLimitRetryDelayMs / 1000} seconds at ${new Date(Date.now() + rateLimitRetryDelayMs).toLocaleTimeString()}`,
112+
)
113+
await new Promise((resolve) => setTimeout(resolve, rateLimitRetryDelayMs))
114+
}
115+
}

0 commit comments

Comments
 (0)