envio 3.13.0 → 3.14.0-subgraph
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.mjs +10 -1
- package/index.d.ts +11 -0
- package/package.json +8 -20
- package/rescript.json +1 -4
- package/src/Config.res +78 -100
- package/src/Config.res.mjs +55 -64
- package/src/Core.res +67 -6
- package/src/Core.res.mjs +58 -4
- package/src/EventConfigBuilder.res +4 -10
- package/src/EventConfigBuilder.res.mjs +1 -3
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +8 -6
- package/src/ExitOnCaughtUp.res +5 -1
- package/src/ExitOnCaughtUp.res.mjs +8 -3
- package/src/HandlerLoader.res +98 -36
- package/src/HandlerLoader.res.mjs +89 -24
- package/src/HandlerTypeCheck.mjs +14 -0
- package/src/HandlerTypeCheckWorker.mjs +68 -0
- package/src/Internal.res +1 -1
- package/src/LoadLayer.res +39 -7
- package/src/LoadLayer.res.mjs +65 -38
- package/src/LoadLayer.resi +28 -0
- package/src/Main.res +17 -12
- package/src/Main.res.mjs +9 -3
- package/src/NodeVersion.mjs +13 -0
- package/src/Persistence.res +79 -38
- package/src/Persistence.res.mjs +41 -10
- package/src/PgStorage.res +86 -39
- package/src/PgStorage.res.mjs +83 -32
- package/src/ResumePlan.res +172 -0
- package/src/ResumePlan.res.mjs +122 -0
- package/src/Supervisor.res +8 -8
- package/src/Supervisor.res.mjs +6 -1
- package/src/SyncWrites.res +86 -0
- package/src/SyncWrites.res.mjs +85 -0
- package/src/TestIndexer.res +14 -4
- package/src/TestIndexer.res.mjs +3 -2
- package/src/TsModuleHooks.mjs +121 -0
- package/src/UserContext.res +377 -62
- package/src/UserContext.res.mjs +297 -39
- package/src/Utils.res +0 -8
- package/src/Worker.res +8 -0
- package/src/Worker.res.mjs +11 -0
- package/src/bindings/NodeJs.res +8 -7
- package/src/bindings/NodeJs.res.mjs +0 -3
- package/src/bindings/Pino.res +2 -2
- package/src/db/InternalTable.res +52 -2
- package/src/db/InternalTable.res.mjs +32 -3
- package/src/db/Table.res +10 -0
- package/src/db/Table.res.mjs +22 -11
- package/src/sources/FuelHyperSync.res +2 -0
- package/src/sources/FuelHyperSync.res.mjs +1 -0
- package/src/sources/FuelHyperSync.resi +1 -0
- package/src/sources/FuelHyperSyncClient.res +25 -8
- package/src/sources/FuelHyperSyncClient.res.mjs +8 -2
- package/src/sources/FuelHyperSyncSource.res +24 -22
- package/src/sources/FuelHyperSyncSource.res.mjs +18 -13
- package/src/subgraph/abi-types.ts +63 -0
- package/src/subgraph/assemblyscript.ts +85 -0
- package/src/subgraph/blocks.ts +183 -0
- package/src/subgraph/calls.ts +149 -0
- package/src/subgraph/conformance.ts +83 -0
- package/src/subgraph/errors.ts +96 -0
- package/src/subgraph/graph-cli-worker.mjs +26 -0
- package/src/subgraph/graph-cli.ts +190 -0
- package/src/subgraph/graph-ts-enums.ts +28 -0
- package/src/subgraph/graph-ts-types/VERSION +2 -0
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
- package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
- package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
- package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
- package/src/subgraph/graph-ts-types/index.d.ts +102 -0
- package/src/subgraph/graph-ts.ts +2285 -0
- package/src/subgraph/hosts.ts +158 -0
- package/src/subgraph/rpc.ts +65 -0
- package/src/subgraph/runtime.ts +595 -0
- package/src/subgraph/scope.ts +68 -0
- package/src/tui/InitApi.res +85 -0
- package/src/tui/{components/CustomHooks.res.mjs → InitApi.res.mjs} +11 -64
- package/src/tui/Tui.res +142 -249
- package/src/tui/Tui.res.mjs +123 -332
- package/src/Js.shim.ts +0 -11
- package/src/bindings/DateFns.res +0 -74
- package/src/bindings/DateFns.res.mjs +0 -22
- package/src/sources/FuelSDK.res +0 -38
- package/src/sources/FuelSDK.res.mjs +0 -27
- package/src/sources/vendored-fuel-abi-coder.js +0 -1792
- package/src/tui/bindings/Ink.res +0 -369
- package/src/tui/bindings/Ink.res.mjs +0 -66
- package/src/tui/bindings/Style.res +0 -123
- package/src/tui/bindings/Style.res.mjs +0 -2
- package/src/tui/components/BufferedProgressBar.res +0 -40
- package/src/tui/components/BufferedProgressBar.res.mjs +0 -57
- package/src/tui/components/CustomHooks.res +0 -122
- package/src/tui/components/Messages.res +0 -40
- package/src/tui/components/Messages.res.mjs +0 -71
- package/src/tui/components/SyncETA.res +0 -179
- package/src/tui/components/SyncETA.res.mjs +0 -249
- package/src/tui/components/TuiData.res +0 -98
- package/src/tui/components/TuiData.res.mjs +0 -73
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The graph-node host ops that reach outside the chain data envio already has:
|
|
3
|
+
* IPFS, Arweave, ENS, `eth_getBalance`/`eth_getCode`, and a block handler's
|
|
4
|
+
* timestamp. Each is an envio effect, so preload batches and dedupes them and
|
|
5
|
+
* the sync bridge suspends the mapping until the answer lands.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { rpcClient } from "./rpc.ts";
|
|
9
|
+
import * as Sury from "rescript-schema";
|
|
10
|
+
import { createEffect } from "../Envio.res.mjs";
|
|
11
|
+
import { configureBlockTimestamps, requestBlockTimestamp } from "./blocks.ts";
|
|
12
|
+
import { missingRpcMessage } from "./errors.ts";
|
|
13
|
+
|
|
14
|
+
const IPFS_GATEWAY = "https://ipfs.io/ipfs/";
|
|
15
|
+
const ARWEAVE_GATEWAY = "https://arweave.net/";
|
|
16
|
+
/** graph-node heals a hash from its rainbow table; this is the public one. */
|
|
17
|
+
const ENS_RAINBOW = "https://api.ensrainbow.io/v1/heal/";
|
|
18
|
+
|
|
19
|
+
const nullableString = Sury.union([Sury.string, null]);
|
|
20
|
+
|
|
21
|
+
/** A stalled gateway would hold the whole batch, which waits on the mapping. */
|
|
22
|
+
const GATEWAY_TIMEOUT_MS = 30_000;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Only "the gateway doesn't have it" is an answer, and a cached one; anything
|
|
26
|
+
* else — a timeout, a 5xx, a rate limit — throws, so envio retries the batch
|
|
27
|
+
* instead of caching a null for good.
|
|
28
|
+
*/
|
|
29
|
+
async function fetchBase64(url: string): Promise<string | null> {
|
|
30
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(GATEWAY_TIMEOUT_MS) });
|
|
31
|
+
if (response.status === 404) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Envio Subgraph's fetch of ${url} failed: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
38
|
+
return Buffer.from(buffer).toString("base64");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type HostEffects = ReturnType<typeof makeHostEffects>;
|
|
42
|
+
|
|
43
|
+
export function makeHostEffects(rpcUrls: string[]) {
|
|
44
|
+
configureBlockTimestamps(rpcUrls);
|
|
45
|
+
|
|
46
|
+
const clientOrThrow = (callSite: string) => {
|
|
47
|
+
if (rpcUrls.length === 0) {
|
|
48
|
+
throw new Error(missingRpcMessage(callSite));
|
|
49
|
+
}
|
|
50
|
+
return rpcClient(rpcUrls);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const ipfsCat = createEffect(
|
|
54
|
+
{
|
|
55
|
+
name: "envio_subgraph_ipfs_cat",
|
|
56
|
+
input: Sury.string,
|
|
57
|
+
output: nullableString,
|
|
58
|
+
rateLimit: false,
|
|
59
|
+
cache: true,
|
|
60
|
+
},
|
|
61
|
+
async ({ input }: { input: string }) => fetchBase64(IPFS_GATEWAY + input),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const arweaveData = createEffect(
|
|
65
|
+
{
|
|
66
|
+
name: "envio_subgraph_arweave",
|
|
67
|
+
input: Sury.string,
|
|
68
|
+
output: nullableString,
|
|
69
|
+
rateLimit: false,
|
|
70
|
+
cache: true,
|
|
71
|
+
},
|
|
72
|
+
async ({ input }: { input: string }) => fetchBase64(ARWEAVE_GATEWAY + input),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// graph-node returns null when its rainbow table doesn't hold the hash.
|
|
76
|
+
// ENSRainbow answers that as a 404, and a hash that isn't one as a 400;
|
|
77
|
+
// anything else is the service failing, which must not be cached as a miss.
|
|
78
|
+
const ensName = createEffect(
|
|
79
|
+
{
|
|
80
|
+
name: "envio_subgraph_ens_name",
|
|
81
|
+
input: Sury.string,
|
|
82
|
+
output: nullableString,
|
|
83
|
+
rateLimit: false,
|
|
84
|
+
cache: true,
|
|
85
|
+
},
|
|
86
|
+
async ({ input }: { input: string }) => {
|
|
87
|
+
const url = ENS_RAINBOW + input;
|
|
88
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(GATEWAY_TIMEOUT_MS) });
|
|
89
|
+
if (response.status === 404 || response.status === 400) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`Envio Subgraph's lookup of ${url} failed: ${response.status} ${response.statusText}`);
|
|
94
|
+
}
|
|
95
|
+
const body = (await response.json()) as { label?: string };
|
|
96
|
+
return body.label ?? null;
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const getBalance = createEffect(
|
|
101
|
+
{
|
|
102
|
+
name: "envio_subgraph_eth_balance",
|
|
103
|
+
input: Sury.string,
|
|
104
|
+
output: Sury.string,
|
|
105
|
+
rateLimit: false,
|
|
106
|
+
cache: true,
|
|
107
|
+
crossChain: false,
|
|
108
|
+
},
|
|
109
|
+
async ({ input }: { input: string }) => {
|
|
110
|
+
const { address, blockNumber } = JSON.parse(input);
|
|
111
|
+
const balance = await clientOrThrow("ethereum.getBalance").getBalance({
|
|
112
|
+
address,
|
|
113
|
+
blockNumber: BigInt(blockNumber),
|
|
114
|
+
});
|
|
115
|
+
return balance.toString();
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const hasCode = createEffect(
|
|
120
|
+
{
|
|
121
|
+
name: "envio_subgraph_has_code",
|
|
122
|
+
input: Sury.string,
|
|
123
|
+
output: Sury.boolean,
|
|
124
|
+
rateLimit: false,
|
|
125
|
+
cache: true,
|
|
126
|
+
crossChain: false,
|
|
127
|
+
},
|
|
128
|
+
async ({ input }: { input: string }) => {
|
|
129
|
+
const { address, blockNumber } = JSON.parse(input);
|
|
130
|
+
const code = await clientOrThrow("ethereum.hasCode").getCode({
|
|
131
|
+
address,
|
|
132
|
+
blockNumber: BigInt(blockNumber),
|
|
133
|
+
});
|
|
134
|
+
return code !== undefined && code !== "0x";
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// Uncached on purpose: a block's timestamp is read exactly once, by that
|
|
139
|
+
// block's own handler invocation, so a persisted row per indexed block would
|
|
140
|
+
// be bloat with no reuse. The in-memory memo still covers replay rounds and
|
|
141
|
+
// the preload -> execute transition.
|
|
142
|
+
const blockTimestamp = createEffect(
|
|
143
|
+
{
|
|
144
|
+
name: "envio_subgraph_block_timestamp",
|
|
145
|
+
input: Sury.number,
|
|
146
|
+
output: Sury.string,
|
|
147
|
+
rateLimit: false,
|
|
148
|
+
cache: false,
|
|
149
|
+
crossChain: false,
|
|
150
|
+
},
|
|
151
|
+
async ({ input, context }: { input: number; context: { chain: { id: number } } }) => {
|
|
152
|
+
const timestamp = await requestBlockTimestamp(context.chain.id, input);
|
|
153
|
+
return timestamp.toString();
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return { ipfsCat, arweaveData, ensName, getBalance, hasCode, blockTimestamp };
|
|
158
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one client every RPC read of the subgraph runtime goes through: contract
|
|
3
|
+
* calls, `getBalance`/`hasCode` and block timestamps.
|
|
4
|
+
*
|
|
5
|
+
* Preload runs a batch's handlers at once, and with them every read they make.
|
|
6
|
+
* Unbounded, that is one open connection per read — thousands on a factory's
|
|
7
|
+
* backfill, until the endpoint stops answering and the batch never completes.
|
|
8
|
+
* So requests beyond a fixed number wait for one in flight to finish; each is
|
|
9
|
+
* short, and a queue drains far faster than a refused connection retries.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createPublicClient, fallback, http, type Transport } from "viem";
|
|
13
|
+
|
|
14
|
+
const MAX_IN_FLIGHT = 16;
|
|
15
|
+
|
|
16
|
+
/** Runs at most `MAX_IN_FLIGHT` requests at once, queueing the rest. */
|
|
17
|
+
function gate() {
|
|
18
|
+
let inFlight = 0;
|
|
19
|
+
const queued: (() => void)[] = [];
|
|
20
|
+
return async <T>(request: () => Promise<T>): Promise<T> => {
|
|
21
|
+
if (inFlight < MAX_IN_FLIGHT) inFlight++;
|
|
22
|
+
// A finishing request hands its slot straight over.
|
|
23
|
+
else await new Promise<void>((resolve) => queued.push(resolve));
|
|
24
|
+
try {
|
|
25
|
+
return await request();
|
|
26
|
+
} finally {
|
|
27
|
+
const next = queued.shift();
|
|
28
|
+
if (next) next();
|
|
29
|
+
else inFlight--;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Bounded per set of endpoints, so one chain's slow RPC can't stall another's. */
|
|
35
|
+
function boundedTransport(transport: Transport): Transport {
|
|
36
|
+
const bounded = gate();
|
|
37
|
+
return (options) => {
|
|
38
|
+
const inner = transport(options);
|
|
39
|
+
return {
|
|
40
|
+
...inner,
|
|
41
|
+
request: ((args) => bounded(() => inner.request(args))) as typeof inner.request,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const clients = new Map<string, ReturnType<typeof createPublicClient>>();
|
|
47
|
+
|
|
48
|
+
export function rpcClient(rpcUrls: string[]) {
|
|
49
|
+
const key = rpcUrls.join("|");
|
|
50
|
+
let client = clients.get(key);
|
|
51
|
+
if (!client) {
|
|
52
|
+
client = createPublicClient({
|
|
53
|
+
// Retrying is envio's job: a failed read becomes a handler error and
|
|
54
|
+
// the batch is retried with the effect's dedup still in place.
|
|
55
|
+
transport: boundedTransport(fallback(rpcUrls.map((url) => http(url, { retryCount: 0 })))),
|
|
56
|
+
});
|
|
57
|
+
clients.set(key, client);
|
|
58
|
+
}
|
|
59
|
+
return client;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Reset between test indexers, which each bring their own endpoints. */
|
|
63
|
+
export function resetRpcClients() {
|
|
64
|
+
clients.clear();
|
|
65
|
+
}
|