envio 3.1.2 → 3.2.0
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/evm.schema.json +83 -11
- package/fuel.schema.json +83 -11
- package/index.d.ts +184 -3
- package/package.json +6 -6
- package/src/Batch.res +2 -2
- package/src/ChainFetcher.res +27 -3
- package/src/ChainFetcher.res.mjs +17 -3
- package/src/ChainManager.res +163 -0
- package/src/ChainManager.res.mjs +136 -0
- package/src/Config.res +213 -30
- package/src/Config.res.mjs +102 -41
- package/src/Core.res +16 -10
- package/src/Ecosystem.res +0 -3
- package/src/Env.res +2 -2
- package/src/Env.res.mjs +2 -2
- package/src/Envio.res +101 -2
- package/src/Envio.res.mjs +2 -3
- package/src/EventConfigBuilder.res +52 -0
- package/src/EventConfigBuilder.res.mjs +32 -0
- package/src/EventUtils.res +2 -2
- package/src/FetchState.res +23 -14
- package/src/FetchState.res.mjs +21 -15
- package/src/GlobalState.res +219 -363
- package/src/GlobalState.res.mjs +314 -491
- package/src/GlobalStateManager.res +49 -59
- package/src/GlobalStateManager.res.mjs +5 -4
- package/src/GlobalStateManager.resi +1 -1
- package/src/HandlerLoader.res +12 -1
- package/src/HandlerLoader.res.mjs +6 -1
- package/src/HandlerRegister.res +9 -9
- package/src/HandlerRegister.res.mjs +9 -9
- package/src/Hasura.res +102 -32
- package/src/Hasura.res.mjs +88 -34
- package/src/InMemoryStore.res +10 -1
- package/src/InMemoryStore.res.mjs +4 -1
- package/src/InMemoryTable.res +83 -136
- package/src/InMemoryTable.res.mjs +57 -86
- package/src/Internal.res +54 -5
- package/src/Internal.res.mjs +2 -8
- package/src/LazyLoader.res +2 -2
- package/src/LazyLoader.res.mjs +3 -3
- package/src/LoadLayer.res +47 -60
- package/src/LoadLayer.res.mjs +28 -50
- package/src/LoadLayer.resi +2 -5
- package/src/LogSelection.res +4 -4
- package/src/LogSelection.res.mjs +5 -7
- package/src/Logging.res +1 -1
- package/src/Main.res +61 -2
- package/src/Main.res.mjs +37 -1
- package/src/Persistence.res +3 -16
- package/src/PgStorage.res +125 -114
- package/src/PgStorage.res.mjs +112 -95
- package/src/Ports.res +5 -0
- package/src/Ports.res.mjs +9 -0
- package/src/Prometheus.res +3 -3
- package/src/Prometheus.res.mjs +4 -4
- package/src/ReorgDetection.res +4 -4
- package/src/ReorgDetection.res.mjs +4 -5
- package/src/SafeCheckpointTracking.res +16 -16
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/SimulateItems.res +10 -14
- package/src/SimulateItems.res.mjs +5 -2
- package/src/Sink.res +1 -1
- package/src/Sink.res.mjs +1 -2
- package/src/SvmTypes.res +9 -0
- package/src/SvmTypes.res.mjs +14 -0
- package/src/TestIndexer.res +17 -57
- package/src/TestIndexer.res.mjs +14 -48
- package/src/TestIndexerProxyStorage.res +23 -23
- package/src/TestIndexerProxyStorage.res.mjs +12 -15
- package/src/Throttler.res +2 -2
- package/src/Time.res +2 -2
- package/src/Time.res.mjs +2 -2
- package/src/UserContext.res +19 -118
- package/src/UserContext.res.mjs +10 -66
- package/src/Utils.res +15 -15
- package/src/Utils.res.mjs +7 -8
- package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
- package/src/bindings/BigDecimal.res +1 -1
- package/src/bindings/BigDecimal.res.mjs +2 -2
- package/src/bindings/ClickHouse.res +8 -6
- package/src/bindings/ClickHouse.res.mjs +5 -5
- package/src/bindings/Hrtime.res +1 -1
- package/src/bindings/Pino.res +2 -2
- package/src/bindings/Pino.res.mjs +3 -4
- package/src/db/EntityFilter.res +410 -0
- package/src/db/EntityFilter.res.mjs +424 -0
- package/src/db/EntityHistory.res +1 -1
- package/src/db/EntityHistory.res.mjs +1 -1
- package/src/db/InternalTable.res +10 -10
- package/src/db/InternalTable.res.mjs +41 -45
- package/src/db/Schema.res +2 -2
- package/src/db/Schema.res.mjs +3 -3
- package/src/db/Table.res +106 -22
- package/src/db/Table.res.mjs +84 -35
- package/src/sources/EventRouter.res +67 -2
- package/src/sources/EventRouter.res.mjs +45 -3
- package/src/sources/Evm.res +0 -7
- package/src/sources/Evm.res.mjs +0 -15
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +1 -2
- package/src/sources/EvmRpcClient.res +42 -0
- package/src/sources/EvmRpcClient.res.mjs +64 -0
- package/src/sources/Fuel.res +0 -7
- package/src/sources/Fuel.res.mjs +0 -15
- package/src/sources/HyperFuelSource.res +5 -4
- package/src/sources/HyperFuelSource.res.mjs +2 -2
- package/src/sources/HyperSyncClient.res +9 -5
- package/src/sources/HyperSyncClient.res.mjs +2 -2
- package/src/sources/HyperSyncHeightStream.res +2 -2
- package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
- package/src/sources/HyperSyncSource.res +10 -9
- package/src/sources/HyperSyncSource.res.mjs +4 -4
- package/src/sources/Rpc.res +1 -5
- package/src/sources/Rpc.res.mjs +1 -9
- package/src/sources/RpcSource.res +57 -21
- package/src/sources/RpcSource.res.mjs +47 -20
- package/src/sources/RpcWebSocketHeightStream.res +1 -1
- package/src/sources/SourceManager.res +3 -2
- package/src/sources/SourceManager.res.mjs +1 -1
- package/src/sources/Svm.res +3 -10
- package/src/sources/Svm.res.mjs +4 -18
- package/src/sources/SvmHyperSyncClient.res +265 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
- package/src/sources/SvmHyperSyncSource.res +638 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
- package/src/tui/Tui.res +9 -2
- package/src/tui/Tui.res.mjs +18 -3
- package/src/tui/components/BufferedProgressBar.res +2 -2
- package/src/tui/components/TuiData.res +3 -0
- package/svm.schema.json +523 -14
- package/src/TableIndices.res +0 -115
- package/src/TableIndices.res.mjs +0 -144
package/evm.schema.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"minimum": 0
|
|
40
40
|
},
|
|
41
41
|
"storage": {
|
|
42
|
-
"description": "
|
|
42
|
+
"description": "Storage backends the indexer writes data to. Defaults to Postgres when omitted. Set `clickhouse: true` to additionally sync the indexed data to ClickHouse. Mark a backend with `default: true` to store entities that don't have an @storage directive in the schema, e.g. `clickhouse: {default: true}`.",
|
|
43
43
|
"anyOf": [
|
|
44
44
|
{
|
|
45
45
|
"$ref": "#/$defs/StorageConfig"
|
|
@@ -131,17 +131,75 @@
|
|
|
131
131
|
"type": "object",
|
|
132
132
|
"properties": {
|
|
133
133
|
"postgres": {
|
|
134
|
-
"description": "Whether to use Postgres as a storage backend (default: true).",
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
"description": "Whether to use Postgres as a storage backend (default: true). Accepts a boolean or an options object (the object form implies the backend is enabled).",
|
|
135
|
+
"anyOf": [
|
|
136
|
+
{
|
|
137
|
+
"type": [
|
|
138
|
+
"boolean",
|
|
139
|
+
"null"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"type": "object",
|
|
144
|
+
"properties": {
|
|
145
|
+
"default": {
|
|
146
|
+
"description": "Whether entities without an @storage directive are stored in this backend (default: true when Postgres is the only enabled backend, false otherwise).",
|
|
147
|
+
"type": [
|
|
148
|
+
"boolean",
|
|
149
|
+
"null"
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
"column_name_format": {
|
|
153
|
+
"description": "How entity fields are reflected in the storage column names. `original` keeps the schema.graphql field names as is, `snake_case` converts them to snake_case in the database while keeping the original casing in the exposed APIs. (default: original)",
|
|
154
|
+
"type": [
|
|
155
|
+
"string",
|
|
156
|
+
"null"
|
|
157
|
+
],
|
|
158
|
+
"enum": [
|
|
159
|
+
"original",
|
|
160
|
+
"snake_case",
|
|
161
|
+
null
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"additionalProperties": false
|
|
166
|
+
}
|
|
138
167
|
]
|
|
139
168
|
},
|
|
140
169
|
"clickhouse": {
|
|
141
|
-
"description": "Whether to additionally sync the indexed data to ClickHouse. Requires Postgres to be enabled (default: false).",
|
|
142
|
-
"
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
"description": "Whether to additionally sync the indexed data to ClickHouse. Requires Postgres to be enabled (default: false). Accepts a boolean or an options object (the object form implies the backend is enabled).",
|
|
171
|
+
"anyOf": [
|
|
172
|
+
{
|
|
173
|
+
"type": [
|
|
174
|
+
"boolean",
|
|
175
|
+
"null"
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"type": "object",
|
|
180
|
+
"properties": {
|
|
181
|
+
"default": {
|
|
182
|
+
"description": "Whether entities without an @storage directive are stored in this backend (default: false).",
|
|
183
|
+
"type": [
|
|
184
|
+
"boolean",
|
|
185
|
+
"null"
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
"column_name_format": {
|
|
189
|
+
"description": "How entity fields are reflected in the storage column names. `original` keeps the schema.graphql field names as is, `snake_case` converts them to snake_case in the database while keeping the original casing in the exposed APIs. (default: original)",
|
|
190
|
+
"type": [
|
|
191
|
+
"string",
|
|
192
|
+
"null"
|
|
193
|
+
],
|
|
194
|
+
"enum": [
|
|
195
|
+
"original",
|
|
196
|
+
"snake_case",
|
|
197
|
+
null
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"additionalProperties": false
|
|
202
|
+
}
|
|
145
203
|
]
|
|
146
204
|
}
|
|
147
205
|
},
|
|
@@ -163,7 +221,14 @@
|
|
|
163
221
|
"if": {
|
|
164
222
|
"properties": {
|
|
165
223
|
"clickhouse": {
|
|
166
|
-
"
|
|
224
|
+
"anyOf": [
|
|
225
|
+
{
|
|
226
|
+
"const": true
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"type": "object"
|
|
230
|
+
}
|
|
231
|
+
]
|
|
167
232
|
}
|
|
168
233
|
},
|
|
169
234
|
"required": [
|
|
@@ -173,7 +238,14 @@
|
|
|
173
238
|
"then": {
|
|
174
239
|
"properties": {
|
|
175
240
|
"postgres": {
|
|
176
|
-
"
|
|
241
|
+
"anyOf": [
|
|
242
|
+
{
|
|
243
|
+
"const": true
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"type": "object"
|
|
247
|
+
}
|
|
248
|
+
]
|
|
177
249
|
}
|
|
178
250
|
},
|
|
179
251
|
"required": [
|
package/fuel.schema.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"minimum": 0
|
|
40
40
|
},
|
|
41
41
|
"storage": {
|
|
42
|
-
"description": "
|
|
42
|
+
"description": "Storage backends the indexer writes data to. Defaults to Postgres when omitted. Set `clickhouse: true` to additionally sync the indexed data to ClickHouse. Mark a backend with `default: true` to store entities that don't have an @storage directive in the schema, e.g. `clickhouse: {default: true}`.",
|
|
43
43
|
"anyOf": [
|
|
44
44
|
{
|
|
45
45
|
"$ref": "#/$defs/StorageConfig"
|
|
@@ -89,17 +89,75 @@
|
|
|
89
89
|
"type": "object",
|
|
90
90
|
"properties": {
|
|
91
91
|
"postgres": {
|
|
92
|
-
"description": "Whether to use Postgres as a storage backend (default: true).",
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
"description": "Whether to use Postgres as a storage backend (default: true). Accepts a boolean or an options object (the object form implies the backend is enabled).",
|
|
93
|
+
"anyOf": [
|
|
94
|
+
{
|
|
95
|
+
"type": [
|
|
96
|
+
"boolean",
|
|
97
|
+
"null"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"default": {
|
|
104
|
+
"description": "Whether entities without an @storage directive are stored in this backend (default: true when Postgres is the only enabled backend, false otherwise).",
|
|
105
|
+
"type": [
|
|
106
|
+
"boolean",
|
|
107
|
+
"null"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"column_name_format": {
|
|
111
|
+
"description": "How entity fields are reflected in the storage column names. `original` keeps the schema.graphql field names as is, `snake_case` converts them to snake_case in the database while keeping the original casing in the exposed APIs. (default: original)",
|
|
112
|
+
"type": [
|
|
113
|
+
"string",
|
|
114
|
+
"null"
|
|
115
|
+
],
|
|
116
|
+
"enum": [
|
|
117
|
+
"original",
|
|
118
|
+
"snake_case",
|
|
119
|
+
null
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"additionalProperties": false
|
|
124
|
+
}
|
|
96
125
|
]
|
|
97
126
|
},
|
|
98
127
|
"clickhouse": {
|
|
99
|
-
"description": "Whether to additionally sync the indexed data to ClickHouse. Requires Postgres to be enabled (default: false).",
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
128
|
+
"description": "Whether to additionally sync the indexed data to ClickHouse. Requires Postgres to be enabled (default: false). Accepts a boolean or an options object (the object form implies the backend is enabled).",
|
|
129
|
+
"anyOf": [
|
|
130
|
+
{
|
|
131
|
+
"type": [
|
|
132
|
+
"boolean",
|
|
133
|
+
"null"
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"type": "object",
|
|
138
|
+
"properties": {
|
|
139
|
+
"default": {
|
|
140
|
+
"description": "Whether entities without an @storage directive are stored in this backend (default: false).",
|
|
141
|
+
"type": [
|
|
142
|
+
"boolean",
|
|
143
|
+
"null"
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"column_name_format": {
|
|
147
|
+
"description": "How entity fields are reflected in the storage column names. `original` keeps the schema.graphql field names as is, `snake_case` converts them to snake_case in the database while keeping the original casing in the exposed APIs. (default: original)",
|
|
148
|
+
"type": [
|
|
149
|
+
"string",
|
|
150
|
+
"null"
|
|
151
|
+
],
|
|
152
|
+
"enum": [
|
|
153
|
+
"original",
|
|
154
|
+
"snake_case",
|
|
155
|
+
null
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"additionalProperties": false
|
|
160
|
+
}
|
|
103
161
|
]
|
|
104
162
|
}
|
|
105
163
|
},
|
|
@@ -121,7 +179,14 @@
|
|
|
121
179
|
"if": {
|
|
122
180
|
"properties": {
|
|
123
181
|
"clickhouse": {
|
|
124
|
-
"
|
|
182
|
+
"anyOf": [
|
|
183
|
+
{
|
|
184
|
+
"const": true
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"type": "object"
|
|
188
|
+
}
|
|
189
|
+
]
|
|
125
190
|
}
|
|
126
191
|
},
|
|
127
192
|
"required": [
|
|
@@ -131,7 +196,14 @@
|
|
|
131
196
|
"then": {
|
|
132
197
|
"properties": {
|
|
133
198
|
"postgres": {
|
|
134
|
-
"
|
|
199
|
+
"anyOf": [
|
|
200
|
+
{
|
|
201
|
+
"const": true
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"type": "object"
|
|
205
|
+
}
|
|
206
|
+
]
|
|
135
207
|
}
|
|
136
208
|
},
|
|
137
209
|
"required": [
|
package/index.d.ts
CHANGED
|
@@ -107,7 +107,7 @@ export type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Operator for filtering entity fields in getWhere queries.
|
|
110
|
-
* Only fields with `@index` in the schema can be queried at runtime.
|
|
110
|
+
* Only `id` and fields with `@index` in the schema can be queried at runtime.
|
|
111
111
|
*/
|
|
112
112
|
export type GetWhereOperator<T> = {
|
|
113
113
|
/** Matches entities where the field equals the given value. */
|
|
@@ -128,7 +128,7 @@ export type GetWhereOperator<T> = {
|
|
|
128
128
|
* Constructs a getWhere filter type from an entity type.
|
|
129
129
|
* Each field can be filtered using {@link GetWhereOperator} (`_eq`, `_gt`, `_lt`, `_gte`, `_lte`, `_in`).
|
|
130
130
|
*
|
|
131
|
-
* Note: only fields with `@index` in the schema can be queried at runtime.
|
|
131
|
+
* Note: only `id` and fields with `@index` in the schema can be queried at runtime.
|
|
132
132
|
* Attempting to filter on a non-indexed field will throw a descriptive error.
|
|
133
133
|
*/
|
|
134
134
|
export type GetWhereFilter<E> = {
|
|
@@ -959,6 +959,144 @@ export type SvmOnSlotOptions<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
|
959
959
|
readonly where?: (args: SvmOnSlotWhereArgs<Config>) => SvmOnSlotWhereResult;
|
|
960
960
|
};
|
|
961
961
|
|
|
962
|
+
// ============== SVM onInstruction types ==============
|
|
963
|
+
|
|
964
|
+
/** Borsh-decoded params view of an instruction. Present whenever a
|
|
965
|
+
* `ProgramSchema` was attached to the program (bundled, Anchor IDL, or
|
|
966
|
+
* hand-written `accounts`/`args` in YAML). Absent when no schema applies or
|
|
967
|
+
* the discriminator didn't match any registered instruction. */
|
|
968
|
+
export type SvmInstructionParams = {
|
|
969
|
+
/** Schema-declared instruction name. */
|
|
970
|
+
readonly name: string;
|
|
971
|
+
/** Borsh-decoded args object. POC types this as `unknown`; narrow with a
|
|
972
|
+
* locally-declared type until the typed-args codegen lands. */
|
|
973
|
+
readonly args: unknown;
|
|
974
|
+
/** Named accounts in schema order. Keys are exactly the schema-declared
|
|
975
|
+
* names; values are base58 pubkeys. */
|
|
976
|
+
readonly accounts: Readonly<Record<string, string>>;
|
|
977
|
+
/** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
|
|
978
|
+
* IDL drift). Empty when counts match the schema. */
|
|
979
|
+
readonly extraAccounts: readonly string[];
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
/** Block context for a matched instruction. */
|
|
983
|
+
export type SvmInstructionBlock = {
|
|
984
|
+
/** Slot this instruction's block was matched in. */
|
|
985
|
+
readonly slot: number;
|
|
986
|
+
readonly time: number;
|
|
987
|
+
/** Always empty for now — reserved for the future reorg-guard route. */
|
|
988
|
+
readonly hash: string;
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
export type SvmTokenBalance = {
|
|
992
|
+
readonly account?: string;
|
|
993
|
+
readonly mint?: string;
|
|
994
|
+
readonly owner?: string;
|
|
995
|
+
/** u64 decimal string. Cast with BigInt(...) for arithmetic. */
|
|
996
|
+
readonly preAmount?: string;
|
|
997
|
+
readonly postAmount?: string;
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
/** Parent transaction surfaced when an instruction's
|
|
1001
|
+
* `include_transaction` flag is `true`. */
|
|
1002
|
+
export type SvmTransaction = {
|
|
1003
|
+
readonly signatures: readonly string[];
|
|
1004
|
+
readonly feePayer?: string;
|
|
1005
|
+
readonly success?: boolean;
|
|
1006
|
+
readonly err?: string;
|
|
1007
|
+
/** Lamports. */
|
|
1008
|
+
readonly fee?: bigint;
|
|
1009
|
+
readonly computeUnitsConsumed?: bigint;
|
|
1010
|
+
readonly accountKeys: readonly string[];
|
|
1011
|
+
readonly recentBlockhash?: string;
|
|
1012
|
+
readonly version?: string;
|
|
1013
|
+
/** SPL Token / Token-2022 balance snapshots for this transaction.
|
|
1014
|
+
* Present when `include_token_balances` is `true`. */
|
|
1015
|
+
readonly tokenBalances?: readonly SvmTokenBalance[];
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
export type SvmLog = {
|
|
1019
|
+
readonly kind: string;
|
|
1020
|
+
readonly message: string;
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
/** A single Solana instruction delivered to an `onInstruction` handler.
|
|
1024
|
+
*
|
|
1025
|
+
* Carries the matched instruction's own fields (`programId`, `data`,
|
|
1026
|
+
* `accounts`, discriminator prefixes, `params`) plus the program/instruction
|
|
1027
|
+
* names, parent transaction, scoped logs, and block context. Parameterised
|
|
1028
|
+
* over `Params` so the per-(program, instruction) overload of
|
|
1029
|
+
* `onInstruction` can narrow `instruction.params` to the codegen-generated
|
|
1030
|
+
* `{ args, accounts }` shape.
|
|
1031
|
+
*
|
|
1032
|
+
* `data` and discriminator prefixes are `0x`-prefixed hex strings; accounts
|
|
1033
|
+
* are base58 strings. */
|
|
1034
|
+
export type SvmInstruction<
|
|
1035
|
+
Params extends SvmInstructionParams = SvmInstructionParams,
|
|
1036
|
+
> = {
|
|
1037
|
+
/** Program name as declared under `programs[].name` in `config.yaml`. */
|
|
1038
|
+
readonly programName: string;
|
|
1039
|
+
/** Instruction name as declared under `instructions[].name` in
|
|
1040
|
+
* `config.yaml`. */
|
|
1041
|
+
readonly instructionName: string;
|
|
1042
|
+
readonly programId: string;
|
|
1043
|
+
readonly data: string;
|
|
1044
|
+
readonly accounts: readonly string[];
|
|
1045
|
+
readonly instructionAddress: readonly number[];
|
|
1046
|
+
readonly isInner: boolean;
|
|
1047
|
+
readonly d1?: string;
|
|
1048
|
+
readonly d2?: string;
|
|
1049
|
+
readonly d4?: string;
|
|
1050
|
+
readonly d8?: string;
|
|
1051
|
+
/** Borsh-decoded params. Present when a schema is configured and matched. */
|
|
1052
|
+
readonly params?: Params;
|
|
1053
|
+
/** Present when the instruction's `include_transaction` is `true`. */
|
|
1054
|
+
readonly transaction?: SvmTransaction;
|
|
1055
|
+
/** Present when the instruction's `include_logs` is `true`; only logs
|
|
1056
|
+
* scoped to this exact instruction (matching `instruction_address`). */
|
|
1057
|
+
readonly logs?: readonly SvmLog[];
|
|
1058
|
+
readonly block: SvmInstructionBlock;
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
/** Arguments passed to handlers registered via `indexer.onInstruction`. */
|
|
1062
|
+
export type SvmOnInstructionHandlerArgs<
|
|
1063
|
+
Config extends IndexerConfigTypes = GlobalConfig,
|
|
1064
|
+
Instr extends SvmInstruction = SvmInstruction,
|
|
1065
|
+
> = {
|
|
1066
|
+
readonly instruction: Instr;
|
|
1067
|
+
readonly context: SvmOnSlotContext<Config>;
|
|
1068
|
+
};
|
|
1069
|
+
|
|
1070
|
+
/** Shape extracted from `Global.config.svm.programs[P][I]`. The codegen
|
|
1071
|
+
* emits `{ args: ...; accounts: ... }` per (program, instruction); this
|
|
1072
|
+
* helper turns that into a `SvmInstructionParams`-compatible record. */
|
|
1073
|
+
type SvmParamsFromProgramTable<TInstr> = TInstr extends {
|
|
1074
|
+
args: infer A;
|
|
1075
|
+
accounts: infer Acc extends Readonly<Record<string, string>>;
|
|
1076
|
+
}
|
|
1077
|
+
? {
|
|
1078
|
+
readonly name: string;
|
|
1079
|
+
readonly args: A;
|
|
1080
|
+
readonly accounts: Acc;
|
|
1081
|
+
readonly extraAccounts: readonly string[];
|
|
1082
|
+
}
|
|
1083
|
+
: SvmInstructionParams;
|
|
1084
|
+
|
|
1085
|
+
/** Options for an SVM `indexer.onInstruction` registration. */
|
|
1086
|
+
export type SvmOnInstructionOptions<P extends string = string, I extends string = string> = {
|
|
1087
|
+
/** Program name as declared under `chains[].programs[].name` in
|
|
1088
|
+
* `config.yaml`. */
|
|
1089
|
+
readonly program: P;
|
|
1090
|
+
/** Instruction name as declared under
|
|
1091
|
+
* `chains[].programs[].instructions[].name` in `config.yaml`. */
|
|
1092
|
+
readonly instruction: I;
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1095
|
+
/** Handler function for an SVM `indexer.onInstruction` registration. */
|
|
1096
|
+
export type SvmOnInstructionHandler<
|
|
1097
|
+
Config extends IndexerConfigTypes = GlobalConfig,
|
|
1098
|
+
> = (args: SvmOnInstructionHandlerArgs<Config>) => Promise<void>;
|
|
1099
|
+
|
|
962
1100
|
// ============== Indexer Types ==============
|
|
963
1101
|
|
|
964
1102
|
// Helper: Check if an ecosystem is configured. Single-ecosystem indexers only
|
|
@@ -1136,7 +1274,14 @@ type FuelEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
|
1136
1274
|
: never
|
|
1137
1275
|
: never;
|
|
1138
1276
|
|
|
1139
|
-
//
|
|
1277
|
+
// Surfaced when an SVM indexer configures no `programs`, so there's no
|
|
1278
|
+
// instruction to register a handler for. Mirrors `CodegenRequiredHint`: the
|
|
1279
|
+
// string literal becomes the argument type, so any `onInstruction` call fails
|
|
1280
|
+
// with this text naming the fix.
|
|
1281
|
+
type SvmNoProgramsHint =
|
|
1282
|
+
"Add at least one entry under `svm.programs` in config.yaml to register instruction handlers with onInstruction.";
|
|
1283
|
+
|
|
1284
|
+
// SVM ecosystem type — chains plus instruction + slot handler methods.
|
|
1140
1285
|
type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
1141
1286
|
"svm" extends keyof Config
|
|
1142
1287
|
? Config["svm"] extends { chains: infer Chains }
|
|
@@ -1160,7 +1305,42 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
|
|
|
1160
1305
|
options: SvmOnSlotOptions<Config>,
|
|
1161
1306
|
handler: SvmOnSlotHandler<Config>,
|
|
1162
1307
|
) => void;
|
|
1308
|
+
} & (Config["svm"] extends {
|
|
1309
|
+
programs: infer Programs extends Record<string, Record<string, any>>;
|
|
1163
1310
|
}
|
|
1311
|
+
? {
|
|
1312
|
+
/**
|
|
1313
|
+
* Register an instruction handler. Dispatch matches on
|
|
1314
|
+
* `(programId, discriminator)` from the YAML config.
|
|
1315
|
+
* `instruction.params.args` and
|
|
1316
|
+
* `instruction.params.accounts` are typed from the
|
|
1317
|
+
* program's Borsh schema (Anchor IDL, bundled, or
|
|
1318
|
+
* hand-written `accounts`/`args` in YAML). `params` stays
|
|
1319
|
+
* optional at runtime because schema-matching can fail on
|
|
1320
|
+
* IDL drift or unknown discriminators.
|
|
1321
|
+
*/
|
|
1322
|
+
readonly onInstruction: <
|
|
1323
|
+
P extends keyof Programs & string,
|
|
1324
|
+
I extends keyof Programs[P] & string,
|
|
1325
|
+
>(
|
|
1326
|
+
options: SvmOnInstructionOptions<P, I>,
|
|
1327
|
+
handler: (
|
|
1328
|
+
args: SvmOnInstructionHandlerArgs<
|
|
1329
|
+
Config,
|
|
1330
|
+
SvmInstruction<SvmParamsFromProgramTable<Programs[P][I]>>
|
|
1331
|
+
>,
|
|
1332
|
+
) => Promise<void>,
|
|
1333
|
+
) => void;
|
|
1334
|
+
}
|
|
1335
|
+
: {
|
|
1336
|
+
/** No `programs` configured under `svm` in config.yaml, so
|
|
1337
|
+
* there's nothing to register an instruction handler for. The
|
|
1338
|
+
* rest parameter is typed as a string-literal hint so any call
|
|
1339
|
+
* site fails with a message naming the fix. */
|
|
1340
|
+
readonly onInstruction: (
|
|
1341
|
+
...hint: SvmNoProgramsHint[]
|
|
1342
|
+
) => void;
|
|
1343
|
+
})
|
|
1164
1344
|
: never
|
|
1165
1345
|
: never
|
|
1166
1346
|
: never;
|
|
@@ -1176,6 +1356,7 @@ type CodegenRequiredHint =
|
|
|
1176
1356
|
"Run 'envio codegen' to generate handler types from config.yaml. Without codegen, the indexer has no contracts, chains, or events to register handlers for.";
|
|
1177
1357
|
type CodegenRequiredFallback = {
|
|
1178
1358
|
readonly onEvent: (...hint: CodegenRequiredHint[]) => void;
|
|
1359
|
+
readonly onInstruction: (...hint: CodegenRequiredHint[]) => void;
|
|
1179
1360
|
readonly onBlock: (...hint: CodegenRequiredHint[]) => void;
|
|
1180
1361
|
readonly onSlot: (...hint: CodegenRequiredHint[]) => void;
|
|
1181
1362
|
readonly contractRegister: (...hint: CodegenRequiredHint[]) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
6
6
|
"bin": "./bin.mjs",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"tsx": "4.21.0"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
|
-
"envio-linux-x64": "3.
|
|
74
|
-
"envio-linux-x64-musl": "3.
|
|
75
|
-
"envio-linux-arm64": "3.
|
|
76
|
-
"envio-darwin-x64": "3.
|
|
77
|
-
"envio-darwin-arm64": "3.
|
|
73
|
+
"envio-linux-x64": "3.2.0",
|
|
74
|
+
"envio-linux-x64-musl": "3.2.0",
|
|
75
|
+
"envio-linux-arm64": "3.2.0",
|
|
76
|
+
"envio-darwin-x64": "3.2.0",
|
|
77
|
+
"envio-darwin-arm64": "3.2.0"
|
|
78
78
|
}
|
|
79
79
|
}
|
package/src/Batch.res
CHANGED
|
@@ -207,7 +207,7 @@ let prepareBatch = (
|
|
|
207
207
|
let prevBlockNumber = ref(chainBeforeBatch.progressBlockNumber)
|
|
208
208
|
if chainBatchSize > 0 {
|
|
209
209
|
for idx in 0 to chainBatchSize - 1 {
|
|
210
|
-
let item = fetchState.buffer->
|
|
210
|
+
let item = fetchState.buffer->Array.getUnsafe(idx)
|
|
211
211
|
let blockNumber = item->Internal.getItemBlockNumber
|
|
212
212
|
|
|
213
213
|
// Every new block we should create a new checkpoint
|
|
@@ -243,7 +243,7 @@ let prepareBatch = (
|
|
|
243
243
|
} else {
|
|
244
244
|
let lastIndex = checkpointEventsProcessed->Array.length - 1
|
|
245
245
|
checkpointEventsProcessed
|
|
246
|
-
->
|
|
246
|
+
->Array.setUnsafe(
|
|
247
247
|
lastIndex,
|
|
248
248
|
checkpointEventsProcessed->Array.getUnsafe(lastIndex) + 1,
|
|
249
249
|
)
|
package/src/ChainFetcher.res
CHANGED
|
@@ -153,14 +153,14 @@ let make = (
|
|
|
153
153
|
onBlockConfigs->Array.forEach(onBlockConfig => {
|
|
154
154
|
if onBlockConfig.startBlock->Option.getOr(startBlock) < startBlock {
|
|
155
155
|
JsError.throwWithMessage(
|
|
156
|
-
`The start block for onBlock handler "${onBlockConfig.name}" is less than the chain start block (${startBlock->
|
|
156
|
+
`The start block for onBlock handler "${onBlockConfig.name}" is less than the chain start block (${startBlock->Int.toString}). This is not supported yet.`,
|
|
157
157
|
)
|
|
158
158
|
}
|
|
159
159
|
switch endBlock {
|
|
160
160
|
| Some(chainEndBlock) =>
|
|
161
161
|
if onBlockConfig.endBlock->Option.getOr(chainEndBlock) > chainEndBlock {
|
|
162
162
|
JsError.throwWithMessage(
|
|
163
|
-
`The end block for onBlock handler "${onBlockConfig.name}" is greater than the chain end block (${chainEndBlock->
|
|
163
|
+
`The end block for onBlock handler "${onBlockConfig.name}" is greater than the chain end block (${chainEndBlock->Int.toString}). This is not supported yet.`,
|
|
164
164
|
)
|
|
165
165
|
}
|
|
166
166
|
| None => ()
|
|
@@ -229,7 +229,31 @@ let make = (
|
|
|
229
229
|
~lowercaseAddresses,
|
|
230
230
|
)
|
|
231
231
|
| Config.FuelSourceConfig({hypersync}) => [HyperFuelSource.make({chain, endpointUrl: hypersync})]
|
|
232
|
-
| Config.SvmSourceConfig({rpc}) =>
|
|
232
|
+
| Config.SvmSourceConfig({hypersync, rpc}) =>
|
|
233
|
+
switch (hypersync, rpc) {
|
|
234
|
+
| (None, None) =>
|
|
235
|
+
JsError.throwWithMessage(
|
|
236
|
+
`Chain ${chain->ChainMap.Chain.toChainId->Int.toString} has no SVM data source`,
|
|
237
|
+
)
|
|
238
|
+
| (None, Some(rpc)) => [Svm.makeRPCSource(~chain, ~rpc)]
|
|
239
|
+
| (Some(hypersyncUrl), _) =>
|
|
240
|
+
// HyperSync drives instruction sync. A configured RPC is ignored for now
|
|
241
|
+
// (RPC fallback isn't wired up yet).
|
|
242
|
+
let svmEventConfigs =
|
|
243
|
+
chainConfig.contracts
|
|
244
|
+
->Array.flatMap(contract => contract.events)
|
|
245
|
+
->(Utils.magic: array<Internal.eventConfig> => array<Internal.svmInstructionEventConfig>)
|
|
246
|
+
let apiToken = Env.envioApiToken
|
|
247
|
+
[
|
|
248
|
+
SvmHyperSyncSource.make({
|
|
249
|
+
chain,
|
|
250
|
+
endpointUrl: hypersyncUrl,
|
|
251
|
+
apiToken,
|
|
252
|
+
eventConfigs: svmEventConfigs,
|
|
253
|
+
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
|
|
254
|
+
}),
|
|
255
|
+
]
|
|
256
|
+
}
|
|
233
257
|
// For tests: use ready-to-use sources directly
|
|
234
258
|
| Config.CustomSources(sources) => sources
|
|
235
259
|
}
|
package/src/ChainFetcher.res.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
|
20
20
|
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
21
21
|
import * as HyperFuelSource from "./sources/HyperFuelSource.res.mjs";
|
|
22
22
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
23
|
+
import * as SvmHyperSyncSource from "./sources/SvmHyperSyncSource.res.mjs";
|
|
23
24
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
24
25
|
import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
|
|
25
26
|
|
|
@@ -89,10 +90,10 @@ function make(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBl
|
|
|
89
90
|
if (onBlockConfigs !== undefined) {
|
|
90
91
|
onBlockConfigs.forEach(onBlockConfig => {
|
|
91
92
|
if (Stdlib_Option.getOr(onBlockConfig.startBlock, startBlock) < startBlock) {
|
|
92
|
-
Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + onBlockConfig.name + `" is less than the chain start block (` +
|
|
93
|
+
Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + onBlockConfig.name + `" is less than the chain start block (` + startBlock.toString() + `). This is not supported yet.`);
|
|
93
94
|
}
|
|
94
95
|
if (endBlock !== undefined && Stdlib_Option.getOr(onBlockConfig.endBlock, endBlock) > endBlock) {
|
|
95
|
-
return Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + onBlockConfig.name + `" is greater than the chain end block (` +
|
|
96
|
+
return Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + onBlockConfig.name + `" is greater than the chain end block (` + endBlock.toString() + `). This is not supported yet.`);
|
|
96
97
|
}
|
|
97
98
|
});
|
|
98
99
|
}
|
|
@@ -132,7 +133,20 @@ function make(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBl
|
|
|
132
133
|
})];
|
|
133
134
|
break;
|
|
134
135
|
case "SvmSourceConfig" :
|
|
135
|
-
|
|
136
|
+
let rpc = sources.rpc;
|
|
137
|
+
let hypersync = sources.hypersync;
|
|
138
|
+
if (hypersync !== undefined) {
|
|
139
|
+
let svmEventConfigs = chainConfig.contracts.flatMap(contract => contract.events);
|
|
140
|
+
sources$1 = [SvmHyperSyncSource.make({
|
|
141
|
+
chain: chain,
|
|
142
|
+
endpointUrl: hypersync,
|
|
143
|
+
apiToken: Env.envioApiToken,
|
|
144
|
+
eventConfigs: svmEventConfigs,
|
|
145
|
+
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis
|
|
146
|
+
})];
|
|
147
|
+
} else {
|
|
148
|
+
sources$1 = rpc !== undefined ? [Svm.makeRPCSource(chain, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + chain.toString() + ` has no SVM data source`);
|
|
149
|
+
}
|
|
136
150
|
break;
|
|
137
151
|
case "CustomSources" :
|
|
138
152
|
sources$1 = sources._0;
|