envio 3.7.0 → 3.9.0-resolvers.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.
Files changed (118) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +7 -0
  3. package/fuel.schema.json +7 -0
  4. package/index.d.ts +674 -161
  5. package/index.js +10 -0
  6. package/package.json +6 -7
  7. package/src/AddressRows.res +121 -0
  8. package/src/AddressRows.res.mjs +143 -0
  9. package/src/Batch.res +11 -0
  10. package/src/Batch.res.mjs +2 -1
  11. package/src/Bin.res +47 -0
  12. package/src/Bin.res.mjs +34 -1
  13. package/src/ChainState.res +108 -98
  14. package/src/ChainState.res.mjs +86 -67
  15. package/src/ChainState.resi +28 -15
  16. package/src/Config.res +61 -131
  17. package/src/Config.res.mjs +47 -79
  18. package/src/ContractMapping.res +66 -0
  19. package/src/ContractMapping.res.mjs +73 -0
  20. package/src/Core.res +24 -0
  21. package/src/Core.res.mjs +4 -0
  22. package/src/Ecosystem.res +7 -2
  23. package/src/Env.res +128 -1
  24. package/src/Env.res.mjs +123 -1
  25. package/src/Envio.res +54 -76
  26. package/src/EventConfigBuilder.res +316 -46
  27. package/src/EventConfigBuilder.res.mjs +231 -28
  28. package/src/FetchState.res +59 -67
  29. package/src/FetchState.res.mjs +34 -44
  30. package/src/HandlerRegister.res +26 -15
  31. package/src/HandlerRegister.res.mjs +27 -7
  32. package/src/Hasura.res +30 -22
  33. package/src/Hasura.res.mjs +11 -5
  34. package/src/InMemoryStore.res +23 -38
  35. package/src/InMemoryStore.res.mjs +13 -27
  36. package/src/IndexerState.res +40 -3
  37. package/src/IndexerState.res.mjs +30 -4
  38. package/src/IndexerState.resi +4 -1
  39. package/src/Internal.res +49 -30
  40. package/src/Internal.res.mjs +12 -16
  41. package/src/Main.res +27 -20
  42. package/src/Main.res.mjs +19 -14
  43. package/src/Metrics.res +15 -1
  44. package/src/Metrics.res.mjs +5 -1
  45. package/src/Persistence.res +46 -21
  46. package/src/Persistence.res.mjs +8 -5
  47. package/src/PgStorage.res +238 -79
  48. package/src/PgStorage.res.mjs +115 -73
  49. package/src/PruneStaleHistory.res +1 -1
  50. package/src/PruneStaleHistory.res.mjs +1 -1
  51. package/src/Rollback.res +62 -41
  52. package/src/Rollback.res.mjs +61 -19
  53. package/src/RollbackCommit.res +7 -9
  54. package/src/RollbackCommit.res.mjs +5 -6
  55. package/src/SimulateItems.res +254 -9
  56. package/src/SimulateItems.res.mjs +214 -47
  57. package/src/Sink.res +35 -26
  58. package/src/Sink.res.mjs +20 -16
  59. package/src/TestIndexer.res +121 -123
  60. package/src/TestIndexer.res.mjs +97 -102
  61. package/src/Utils.res +38 -0
  62. package/src/Utils.res.mjs +39 -2
  63. package/src/Writing.res +4 -2
  64. package/src/Writing.res.mjs +3 -2
  65. package/src/bindings/ClickHouse.res +311 -656
  66. package/src/bindings/ClickHouse.res.mjs +294 -395
  67. package/src/bindings/ClickHouseSink.res +303 -0
  68. package/src/bindings/ClickHouseSink.res.mjs +216 -0
  69. package/src/bindings/NodeJs.res +9 -0
  70. package/src/bindings/NodeJs.res.mjs +8 -1
  71. package/src/bindings/Postgres.res +9 -0
  72. package/src/bindings/Postgres.res.mjs +3 -0
  73. package/src/db/EntityHistory.res +29 -24
  74. package/src/db/EntityHistory.res.mjs +11 -19
  75. package/src/db/InternalTable.res +258 -83
  76. package/src/db/InternalTable.res.mjs +223 -85
  77. package/src/db/RollbackScope.res +29 -0
  78. package/src/db/RollbackScope.res.mjs +31 -0
  79. package/src/db/Table.res +28 -1
  80. package/src/db/Table.res.mjs +26 -2
  81. package/src/resolvers/ResolverProcess.res +809 -0
  82. package/src/resolvers/ResolverProcess.res.mjs +667 -0
  83. package/src/resolvers/ResolverQuery.res +317 -0
  84. package/src/resolvers/ResolverQuery.res.mjs +220 -0
  85. package/src/resolvers/collisions.js +108 -0
  86. package/src/resolvers/db.js +363 -0
  87. package/src/resolvers/dispatch.js +165 -0
  88. package/src/resolvers/errors.js +30 -0
  89. package/src/resolvers/graphqlSelection.js +292 -0
  90. package/src/resolvers/hasuraAction.js +84 -0
  91. package/src/resolvers/hasuraApply.js +323 -0
  92. package/src/resolvers/hasuraMetadata.js +119 -0
  93. package/src/resolvers/index.js +95 -0
  94. package/src/resolvers/manifest.js +370 -0
  95. package/src/resolvers/server.js +270 -0
  96. package/src/sources/AddressSet.res +0 -22
  97. package/src/sources/AddressStore.res +48 -88
  98. package/src/sources/AddressStore.res.mjs +11 -22
  99. package/src/sources/Evm.res +2 -0
  100. package/src/sources/Evm.res.mjs +2 -0
  101. package/src/sources/EvmHyperSyncSource.res +3 -2
  102. package/src/sources/Fuel.res +2 -0
  103. package/src/sources/Fuel.res.mjs +2 -0
  104. package/src/sources/SimulateSource.res +8 -4
  105. package/src/sources/SimulateSource.res.mjs +7 -3
  106. package/src/sources/Svm.res +36 -7
  107. package/src/sources/Svm.res.mjs +34 -4
  108. package/src/sources/SvmHyperSyncClient.res +20 -116
  109. package/src/sources/SvmHyperSyncClient.res.mjs +5 -7
  110. package/src/sources/SvmHyperSyncSource.res +89 -37
  111. package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
  112. package/src/sources/TransactionStore.res +38 -0
  113. package/src/sources/TransactionStore.res.mjs +5 -0
  114. package/src/tui/Tui.res +1 -1
  115. package/src/tui/Tui.res.mjs +1 -1
  116. package/svm.schema.json +44 -156
  117. package/src/MemoryStorage.res +0 -724
  118. package/src/MemoryStorage.res.mjs +0 -601
package/index.d.ts CHANGED
@@ -1160,152 +1160,392 @@ export type SvmOnSlotOptions<Config extends IndexerConfigTypes = GlobalConfig> =
1160
1160
 
1161
1161
  // ============== SVM onInstruction types ==============
1162
1162
 
1163
- /** Borsh-decoded params view of an instruction. Present whenever a
1164
- * `ProgramSchema` was attached to the program (bundled, Anchor IDL, or
1165
- * hand-written `accounts`/`args` in YAML). Absent when no schema applies or
1166
- * the discriminator didn't match any registered instruction. */
1167
- export type SvmInstructionParams = {
1168
- /** Schema-declared instruction name. */
1169
- readonly name: string;
1170
- /** Borsh-decoded args object. POC types this as `unknown`; narrow with a
1171
- * locally-declared type until the typed-args codegen lands. */
1172
- readonly args: unknown;
1173
- /** Named accounts in schema order. Keys are exactly the schema-declared
1174
- * names; values are base58 pubkeys. */
1175
- readonly accounts: Readonly<Record<string, string>>;
1176
- /** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
1177
- * IDL drift). Empty when counts match the schema. */
1178
- readonly extraAccounts: readonly string[];
1163
+ export type SvmLogKind =
1164
+ | "invoke"
1165
+ | "success"
1166
+ | "failed"
1167
+ | "consumed"
1168
+ | "log"
1169
+ | "data"
1170
+ | (string & {});
1171
+
1172
+ export type SvmAllLogFields = {
1173
+ readonly kind: SvmLogKind;
1174
+ readonly message: string;
1179
1175
  };
1180
1176
 
1181
- /** Permissive fallback shape for an instruction's `block`. The generated
1182
- * per-instruction type narrows this to `slot`/`hash` (always present) and
1183
- * `time` (always present but possibly `undefined`), plus the selected
1184
- * `field_selection.block_fields`. */
1185
- export type SvmInstructionBlock = {
1186
- /** Slot this instruction's block was matched in. */
1177
+ export type SvmAllAccountLamportsFields = {
1178
+ readonly pre: bigint;
1179
+ readonly post: bigint;
1180
+ };
1181
+
1182
+ export type SvmAllAccountTokenActivityFields = {
1183
+ readonly mint: string;
1184
+ readonly owner: string;
1185
+ readonly decimals: number;
1186
+ readonly preAmount: bigint | undefined;
1187
+ readonly postAmount: bigint | undefined;
1188
+ };
1189
+
1190
+ export type SvmAllAccountActivityFields = {
1191
+ readonly address: string;
1192
+ readonly transactionAccountIndex: number;
1193
+ readonly isSigner: boolean;
1194
+ readonly isWritable: boolean;
1195
+ readonly lamports: SvmAllAccountLamportsFields | undefined;
1196
+ readonly token: SvmAllAccountTokenActivityFields | undefined;
1197
+ };
1198
+
1199
+ export type SvmAllBlockFields = {
1187
1200
  readonly slot: number;
1188
- /** Unix block time (seconds). Absent when HyperSync/Solana doesn't report a
1189
- * block time for this slot. */
1190
- readonly time?: number;
1191
- /** Block hash. */
1201
+ readonly time: number;
1192
1202
  readonly hash: string;
1193
- /** Block height. Select via `field_selection.block_fields`. */
1194
- readonly height?: number;
1195
- /** Parent slot. Select via `field_selection.block_fields`. */
1196
- readonly parentSlot?: number;
1197
- /** Parent block hash. Select via `field_selection.block_fields`. */
1198
- readonly parentHash?: string;
1199
- };
1200
-
1201
- export type SvmTokenBalance = {
1202
- readonly account?: string;
1203
- readonly mint?: string;
1204
- /** Owner at the end of the transaction, falling back to the owner on entry
1205
- * when the account was closed during it. Pre and post owners differ only
1206
- * when a `SetAuthority(AccountOwner)` runs mid-transaction. */
1207
- readonly owner?: string;
1208
- /** Mint decimals, for scaling the raw amounts below. */
1209
- readonly decimals?: number;
1210
- /** Raw amount in base units before the transaction. Absent when the token
1211
- * account was created during it. */
1212
- readonly preAmount?: bigint;
1213
- /** Raw amount in base units after the transaction. Absent when the token
1214
- * account was closed during it. */
1215
- readonly postAmount?: bigint;
1216
- };
1217
-
1218
- export type SvmLog = {
1219
- readonly kind: string;
1220
- readonly message: string;
1203
+ readonly height: number;
1204
+ readonly parentSlot: number;
1205
+ readonly parentHash: string;
1221
1206
  };
1222
1207
 
1223
- /** A single Solana instruction delivered to an `onInstruction` handler.
1224
- *
1225
- * Carries the matched instruction's own fields (`programId`, `data`,
1226
- * `accounts`, discriminator prefixes, `params`) plus the program/instruction
1227
- * names, parent transaction, scoped logs, and block context. Parameterised
1228
- * over `Params` so the per-(program, instruction) overload of
1229
- * `onInstruction` can narrow `instruction.params` to the codegen-generated
1230
- * `{ args, accounts }` shape.
1208
+ /** All SVM parent-transaction fields. Handler `fields.transaction` narrows
1209
+ * this via {@link SvmTransaction}; `accountActivities` is implied by
1210
+ * `fields.accountActivity`. */
1211
+ export type SvmAllTransactionFields = {
1212
+ readonly transactionIndex: number;
1213
+ readonly signature: string;
1214
+ readonly feePayer: string;
1215
+ readonly success: boolean;
1216
+ readonly err: string | undefined;
1217
+ readonly fee: bigint;
1218
+ readonly computeUnitsConsumed: bigint | undefined;
1219
+ readonly accountKeys: readonly string[];
1220
+ readonly recentBlockhash: string;
1221
+ readonly version: string | undefined;
1222
+ readonly allSignatures: readonly string[];
1223
+ };
1224
+
1225
+ export type SvmInstructionFieldName =
1226
+ | "args"
1227
+ | "accounts"
1228
+ | "accountArguments"
1229
+ | "programId"
1230
+ | "data"
1231
+ | "path"
1232
+ | "isInner";
1233
+ export type SvmTransactionFieldName =
1234
+ | "transactionIndex"
1235
+ | "signature"
1236
+ | "feePayer"
1237
+ | "success"
1238
+ | "err"
1239
+ | "fee"
1240
+ | "computeUnitsConsumed"
1241
+ | "accountKeys"
1242
+ | "recentBlockhash"
1243
+ | "version"
1244
+ | "allSignatures";
1245
+ export type SvmAccountActivityFieldName =
1246
+ | "address"
1247
+ | "transactionAccountIndex"
1248
+ | "isSigner"
1249
+ | "isWritable"
1250
+ | "lamports.pre"
1251
+ | "lamports.post"
1252
+ | "token.mint"
1253
+ | "token.owner"
1254
+ | "token.decimals"
1255
+ | "token.preAmount"
1256
+ | "token.postAmount";
1257
+ export type SvmBlockFieldName =
1258
+ | "slot"
1259
+ | "time"
1260
+ | "hash"
1261
+ | "height"
1262
+ | "parentSlot"
1263
+ | "parentHash";
1264
+ export type SvmLogFieldName = "kind" | "message";
1265
+
1266
+ export type SvmFieldsSelection = {
1267
+ readonly instruction?: readonly SvmInstructionFieldName[];
1268
+ readonly transaction?: readonly SvmTransactionFieldName[];
1269
+ readonly accountActivity?: readonly SvmAccountActivityFieldName[];
1270
+ readonly block?: readonly SvmBlockFieldName[];
1271
+ readonly log?: readonly SvmLogFieldName[];
1272
+ };
1273
+
1274
+ /** A {@link SvmFieldsSelection} with every field selected.
1231
1275
  *
1232
- * `data` and discriminator prefixes are `0x`-prefixed hex strings; accounts
1233
- * are base58 strings. */
1234
- export type SvmInstruction<
1235
- Params extends SvmInstructionParams = SvmInstructionParams,
1236
- Tx = SvmTransaction,
1237
- Block = SvmInstructionBlock,
1276
+ * Type-level only — its knobs are field-name arrays rather than literals, so it
1277
+ * describes a payload (`SvmInstruction<SvmAllFieldsSelection>`) but can't be
1278
+ * passed as a registration's `fields` value. */
1279
+ export type SvmAllFieldsSelection = {
1280
+ readonly instruction: readonly SvmInstructionFieldName[];
1281
+ readonly transaction: readonly SvmTransactionFieldName[];
1282
+ readonly accountActivity: readonly SvmAccountActivityFieldName[];
1283
+ readonly block: readonly SvmBlockFieldName[];
1284
+ readonly log: readonly SvmLogFieldName[];
1285
+ };
1286
+
1287
+ type SvmListedArray<Fields, Knob extends keyof SvmFieldsSelection> = Fields[Knob &
1288
+ keyof Fields];
1289
+ type SvmListedFields<Fields, Knob extends keyof SvmFieldsSelection> = NonNullable<
1290
+ SvmListedArray<Fields, Knob>
1291
+ >[number] &
1292
+ string;
1293
+
1294
+ type SvmFieldsLiteralCheck<Fields> = [Fields] extends [undefined]
1295
+ ? unknown
1296
+ : IsWidenedArray<SvmListedArray<Fields, "instruction">> extends true
1297
+ ? EvmFieldsMustBeLiteral<"instruction">
1298
+ : IsWidenedArray<SvmListedArray<Fields, "transaction">> extends true
1299
+ ? EvmFieldsMustBeLiteral<"transaction">
1300
+ : IsWidenedArray<SvmListedArray<Fields, "accountActivity">> extends true
1301
+ ? EvmFieldsMustBeLiteral<"accountActivity">
1302
+ : IsWidenedArray<SvmListedArray<Fields, "block">> extends true
1303
+ ? EvmFieldsMustBeLiteral<"block">
1304
+ : IsWidenedArray<SvmListedArray<Fields, "log">> extends true
1305
+ ? EvmFieldsMustBeLiteral<"log">
1306
+ : unknown;
1307
+
1308
+ type SvmActivityListed<Fields> = SvmListedFields<Fields, "accountActivity">;
1309
+ type SvmActivityHas<Fields, Name extends string> = [SvmActivityListed<Fields>] extends [never]
1310
+ ? false
1311
+ : Name extends SvmActivityListed<Fields>
1312
+ ? true
1313
+ : false;
1314
+
1315
+ type SvmActivityField<Fields, Name extends string, T> = SvmActivityHas<
1316
+ Fields,
1317
+ Name
1318
+ > extends true
1319
+ ? T
1320
+ : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1321
+
1322
+ /** The pre/post lamport balances of a {@link SvmAccountActivity}, narrowed to
1323
+ * the registration's fields selection. */
1324
+ export type SvmAccountLamports<Fields extends SvmFieldsSelection> = [
1325
+ SvmActivityListed<Fields> & `lamports.${string}`,
1326
+ ] extends [never]
1327
+ ? FieldNotSelected<`Field 'lamports' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>
1328
+ : {
1329
+ readonly [K in keyof SvmAllAccountLamportsFields]: SvmActivityHas<Fields, `lamports.${K & string}`> extends true
1330
+ ? SvmAllAccountLamportsFields[K]
1331
+ : FieldNotSelected<`Field 'lamports.${K & string}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1332
+ } | undefined;
1333
+
1334
+ /** The token activity of a {@link SvmAccountActivity}, narrowed to the
1335
+ * registration's fields selection. */
1336
+ export type SvmAccountTokenActivity<Fields extends SvmFieldsSelection> = [SvmActivityListed<Fields> & `token.${string}`] extends [never]
1337
+ ? FieldNotSelected<`Field 'token' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>
1338
+ : {
1339
+ readonly [K in keyof SvmAllAccountTokenActivityFields]: SvmActivityHas<Fields, `token.${K & string}`> extends true
1340
+ ? SvmAllAccountTokenActivityFields[K]
1341
+ : FieldNotSelected<`Field 'token.${K & string}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1342
+ } | undefined;
1343
+
1344
+ /** An account activity of a {@link SvmTransaction}, narrowed to the
1345
+ * registration's fields selection. */
1346
+ export type SvmAccountActivity<Fields extends SvmFieldsSelection> = {
1347
+ readonly address: string;
1348
+ readonly transactionAccountIndex: SvmActivityField<Fields, "transactionAccountIndex", number>;
1349
+ readonly isSigner: SvmActivityField<Fields, "isSigner", boolean>;
1350
+ readonly isWritable: SvmActivityField<Fields, "isWritable", boolean>;
1351
+ readonly lamports: SvmAccountLamports<Fields>;
1352
+ readonly token: SvmAccountTokenActivity<Fields>;
1353
+ };
1354
+
1355
+ type SvmInstrListed<Fields> = SvmListedFields<Fields, "instruction">;
1356
+ type SvmInstrField<Fields, Name extends SvmInstructionFieldName, T> = Name extends SvmInstrListed<Fields>
1357
+ ? T
1358
+ : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.instruction in the registration options.`>;
1359
+
1360
+ /** A named account of a {@link SvmInstruction}. Its `activity` narrows to the
1361
+ * registration's fields selection. */
1362
+ export type SvmInstructionAccount<
1363
+ Fields extends SvmFieldsSelection,
1364
+ Name extends string = string,
1238
1365
  > = {
1239
- /** Program name as declared under `programs[].name` in `config.yaml`. */
1366
+ readonly address: string;
1367
+ readonly accountName: Name;
1368
+ readonly instructionAccountIndex: number;
1369
+ readonly activity:
1370
+ | ([SvmActivityListed<Fields>] extends [never]
1371
+ ? FieldNotSelected<`Field 'activity' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1372
+ : SvmAccountActivity<Fields>)
1373
+ | undefined;
1374
+ };
1375
+
1376
+ type SvmNamedAccounts<
1377
+ Acc extends Readonly<Record<string, unknown>>,
1378
+ Fields extends SvmFieldsSelection,
1379
+ > = {
1380
+ readonly [K in keyof Acc & string]: SvmInstructionAccount<Fields, K>;
1381
+ };
1382
+
1383
+ /** The parent transaction of a {@link SvmInstruction}, narrowed to the
1384
+ * registration's fields selection. */
1385
+ export type SvmTransaction<Fields extends SvmFieldsSelection> = {
1386
+ readonly [K in keyof SvmAllTransactionFields]: K extends SvmListedFields<Fields, "transaction">
1387
+ ? SvmAllTransactionFields[K]
1388
+ : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.transaction in the registration options.`>;
1389
+ } & {
1390
+ readonly accountActivities: [SvmActivityListed<Fields>] extends [never]
1391
+ ? FieldNotSelected<`Field 'accountActivities' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1392
+ : readonly SvmAccountActivity<Fields>[];
1393
+ };
1394
+
1395
+ /** The block of a {@link SvmInstruction}, narrowed to the registration's
1396
+ * fields selection. `slot` is always selected. */
1397
+ export type SvmBlock<Fields extends SvmFieldsSelection> = {
1398
+ readonly [K in keyof SvmAllBlockFields]: K extends "slot"
1399
+ ? SvmAllBlockFields[K]
1400
+ : K extends SvmListedFields<Fields, "block">
1401
+ ? SvmAllBlockFields[K]
1402
+ : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.block in the registration options.`>;
1403
+ };
1404
+
1405
+ /** A log of a {@link SvmInstruction}, narrowed to the registration's fields
1406
+ * selection. */
1407
+ export type SvmLog<Fields extends SvmFieldsSelection> = {
1408
+ readonly kind: "kind" extends SvmListedFields<Fields, "log">
1409
+ ? SvmLogKind
1410
+ : FieldNotSelected<`Field 'kind' is not selected for this handler. Add it to fields.log in the registration options.`>;
1411
+ readonly message: "message" extends SvmListedFields<Fields, "log">
1412
+ ? string
1413
+ : FieldNotSelected<`Field 'message' is not selected for this handler. Add it to fields.log in the registration options.`>;
1414
+ };
1415
+
1416
+ type SvmAnyProgramInstruction = {
1417
+ readonly args: unknown;
1418
+ readonly accounts: Readonly<Record<string, string>>;
1419
+ };
1420
+
1421
+ type SvmSelectedInstruction<Fields extends SvmFieldsSelection, ProgInstr> = {
1240
1422
  readonly programName: string;
1241
- /** Instruction name as declared under `instructions[].name` in
1242
- * `config.yaml`. */
1243
1423
  readonly instructionName: string;
1244
- readonly programId: string;
1245
- readonly data: string;
1246
- readonly accounts: readonly string[];
1247
- readonly instructionAddress: readonly number[];
1248
- readonly isInner: boolean;
1249
- readonly d1?: string;
1250
- readonly d2?: string;
1251
- readonly d4?: string;
1252
- readonly d8?: string;
1253
- /** Borsh-decoded params. Present when a schema is configured and matched. */
1254
- readonly params?: Params;
1255
- /** Parent transaction. Carries only the fields selected via this
1256
- * instruction's `field_selection`; unselected fields are typed as
1257
- * `FieldNotSelected<...>` so reading them is a compile error. Always present
1258
- * (`{}` when no fields are selected). */
1259
- readonly transaction: Tx;
1260
- /** Present when the instruction's `include_logs` is `true`; only logs
1261
- * scoped to this exact instruction (matching `instruction_address`). */
1262
- readonly logs?: readonly SvmLog[];
1263
- /** The block this instruction's slot belongs to. Carries `slot`/`hash`
1264
- * (always present) and `time` (always present but possibly `undefined`),
1265
- * plus the fields selected via this instruction's
1266
- * `field_selection.block_fields`; unselected fields are typed as
1267
- * `FieldNotSelected<...>`. */
1268
- readonly block: Block;
1269
- };
1270
-
1271
- /** Arguments passed to handlers registered via `indexer.onInstruction`. */
1272
- export type SvmOnInstructionHandlerArgs<
1273
- Config extends IndexerConfigTypes = GlobalConfig,
1274
- Instr extends SvmInstruction = SvmInstruction,
1275
- > = {
1424
+ readonly discriminator: string;
1425
+ readonly programId: SvmInstrField<Fields, "programId", string>;
1426
+ readonly data: SvmInstrField<Fields, "data", string>;
1427
+ readonly path: SvmInstrField<Fields, "path", readonly number[]>;
1428
+ readonly isInner: SvmInstrField<Fields, "isInner", boolean>;
1429
+ readonly args: SvmInstrField<
1430
+ Fields,
1431
+ "args",
1432
+ ProgInstr extends { readonly args: infer A } ? A : unknown
1433
+ >;
1434
+ readonly accounts: SvmInstrField<
1435
+ Fields,
1436
+ "accounts",
1437
+ ProgInstr extends { readonly accounts: infer Acc extends Readonly<Record<string, unknown>> }
1438
+ ? SvmNamedAccounts<Acc, Fields>
1439
+ : SvmNamedAccounts<Readonly<Record<string, string>>, Fields>
1440
+ >;
1441
+ readonly accountArguments: SvmInstrField<Fields, "accountArguments", readonly string[]>;
1442
+ readonly logs: [SvmListedFields<Fields, "log">] extends [never]
1443
+ ? FieldNotSelected<`Field 'logs' is not selected for this handler. Add fields.log in the registration options.`>
1444
+ : readonly SvmLog<Fields>[];
1445
+ readonly transaction: SvmTransaction<Fields>;
1446
+ readonly block: SvmBlock<Fields>;
1447
+ };
1448
+
1449
+ type SvmConfiguredInstruction<Program extends string, Instruction extends string> = [
1450
+ Program,
1451
+ ] extends [never]
1452
+ ? SvmAnyProgramInstruction
1453
+ : Program extends keyof SvmProgramsT
1454
+ ? Instruction extends keyof SvmProgramsT[Program]
1455
+ ? SvmProgramsT[Program][Instruction]
1456
+ : SvmAnyProgramInstruction
1457
+ : SvmAnyProgramInstruction;
1458
+
1459
+ /** The `instruction` payload of an `indexer.onInstruction` handler. `Fields`
1460
+ * must be the registration's fields selection (use `typeof fields` on a
1461
+ * `const fields = {...} as const satisfies SvmFieldsSelection`, or
1462
+ * {@link SvmAllFieldsSelection}). Pass the config-declared program and
1463
+ * instruction names to type `args` and `accounts`. */
1464
+ export type SvmInstruction<
1465
+ Fields extends SvmFieldsSelection,
1466
+ Program extends keyof SvmProgramsT & string = never,
1467
+ Instruction extends keyof SvmProgramsT[Program] & string = never,
1468
+ > = SvmSelectedInstruction<Fields, SvmConfiguredInstruction<Program, Instruction>>;
1469
+
1470
+ type SvmOnInstructionArgsFor<Instr, Config extends IndexerConfigTypes> = {
1276
1471
  readonly instruction: Instr;
1277
1472
  readonly context: SvmOnSlotContext<Config>;
1278
1473
  };
1279
1474
 
1280
- /** Shape extracted from `Global.config.svm.programs[P][I]`. The codegen
1281
- * emits `{ args: ...; accounts: ... }` per (program, instruction); this
1282
- * helper turns that into a `SvmInstructionParams`-compatible record. */
1283
- type SvmParamsFromProgramTable<TInstr> = TInstr extends {
1284
- args: infer A;
1285
- accounts: infer Acc extends Readonly<Record<string, string>>;
1286
- }
1287
- ? {
1288
- readonly name: string;
1289
- readonly args: A;
1290
- readonly accounts: Acc;
1291
- readonly extraAccounts: readonly string[];
1292
- }
1293
- : SvmInstructionParams;
1475
+ type SvmOnInstructionHandlerFor<Instr, Config extends IndexerConfigTypes> = (
1476
+ args: SvmOnInstructionArgsFor<Instr, Config>,
1477
+ ) => Promise<void>;
1478
+
1479
+ /** Arguments passed to handlers registered via `indexer.onInstruction`.
1480
+ * Takes the same type arguments as {@link SvmInstruction}. */
1481
+ export type SvmOnInstructionHandlerArgs<
1482
+ Fields extends SvmFieldsSelection,
1483
+ Program extends keyof SvmProgramsT & string = never,
1484
+ Instruction extends keyof SvmProgramsT[Program] & string = never,
1485
+ > = SvmOnInstructionArgsFor<SvmInstruction<Fields, Program, Instruction>, GlobalConfig>;
1486
+
1487
+ /** The named accounts of a configured instruction. Falls back to an open
1488
+ * record when the instruction carries no resolved schema, so its filter keys
1489
+ * are unconstrained rather than unusable. */
1490
+ type SvmAccountsOf<Program extends string, Instruction extends string> =
1491
+ SvmConfiguredInstruction<Program, Instruction>["accounts"];
1492
+
1493
+ /** One AND-group of account narrowings: every named account must match one of
1494
+ * its listed pubkeys. Names are the instruction's own account names. */
1495
+ export type SvmAccountsFilter<Accounts> = {
1496
+ readonly [K in keyof Accounts]?: string | readonly string[];
1497
+ };
1498
+
1499
+ /** The `where` option value of `indexer.onInstruction`.
1500
+ *
1501
+ * `accounts` accepts either a single AND-group of account narrowings, or an
1502
+ * array of them (OR semantics). `block.slot._gte` promotes to the
1503
+ * registration's startBlock and overrides the chain-level `start_block` — use
1504
+ * it to restrict per-instruction processing without touching `config.yaml`.
1505
+ * Only `_gte` is supported here; use `indexer.onSlot` for `_lte` / `_every`. */
1506
+ export type SvmOnInstructionWhere<Accounts> = {
1507
+ /** Match only inner (CPI-invoked) or only outer instructions. Absent
1508
+ * matches both. */
1509
+ readonly isInner?: boolean;
1510
+ readonly accounts?: SvmAccountsFilter<Accounts> | readonly SvmAccountsFilter<Accounts>[];
1511
+ readonly block?: {
1512
+ readonly slot?: {
1513
+ readonly _gte?: number;
1514
+ };
1515
+ };
1516
+ };
1294
1517
 
1295
1518
  /** Options for an SVM `indexer.onInstruction` registration. */
1296
- export type SvmOnInstructionOptions<P extends string = string, I extends string = string> = {
1519
+ export type SvmOnInstructionOptions<
1520
+ P extends string = string,
1521
+ I extends string = string,
1522
+ Fields extends SvmFieldsSelection = {},
1523
+ > = {
1297
1524
  /** Program name as declared under `chains[].programs[].name` in
1298
1525
  * `config.yaml`. */
1299
1526
  readonly program: P;
1300
1527
  /** Instruction name as declared under
1301
1528
  * `chains[].programs[].instructions[].name` in `config.yaml`. */
1302
1529
  readonly instruction: I;
1530
+ readonly fields?: Fields & SvmFieldsLiteralCheck<Fields>;
1531
+ readonly where?: SvmOnInstructionWhere<SvmAccountsOf<P, I>>;
1303
1532
  };
1304
1533
 
1305
- /** Handler function for an SVM `indexer.onInstruction` registration. */
1534
+ /** Handler function for an SVM `indexer.onInstruction` registration. Takes
1535
+ * the same type arguments as {@link SvmInstruction}, so a standalone handler
1536
+ * needs a single annotation:
1537
+ *
1538
+ * const handleSwap: SvmOnInstructionHandler<typeof fields, "Swapper", "swap"> =
1539
+ * async ({ instruction, context }) => { ... };
1540
+ */
1306
1541
  export type SvmOnInstructionHandler<
1307
- Config extends IndexerConfigTypes = GlobalConfig,
1308
- > = (args: SvmOnInstructionHandlerArgs<Config>) => Promise<void>;
1542
+ Fields extends SvmFieldsSelection,
1543
+ Program extends keyof SvmProgramsT & string = never,
1544
+ Instruction extends keyof SvmProgramsT[Program] & string = never,
1545
+ > = SvmOnInstructionHandlerFor<
1546
+ SvmInstruction<Fields, Program, Instruction>,
1547
+ GlobalConfig
1548
+ >;
1309
1549
 
1310
1550
  // ============== Indexer Types ==============
1311
1551
 
@@ -1530,28 +1770,18 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1530
1770
  /**
1531
1771
  * Register an instruction handler. Dispatch matches on
1532
1772
  * `(programId, discriminator)` from the YAML config.
1533
- * `instruction.params.args` and
1534
- * `instruction.params.accounts` are typed from the
1535
- * program's Borsh schema (Anchor IDL, bundled, or
1536
- * hand-written `accounts`/`args` in YAML). `params` stays
1537
- * optional at runtime because schema-matching can fail on
1538
- * IDL drift or unknown discriminators.
1773
+ * Handler `fields` is the only source of payload selection.
1539
1774
  */
1540
1775
  readonly onInstruction: <
1541
1776
  P extends keyof Programs & string,
1542
1777
  I extends keyof Programs[P] & string,
1778
+ const F extends SvmFieldsSelection = {},
1543
1779
  >(
1544
- options: SvmOnInstructionOptions<P, I>,
1545
- handler: (
1546
- args: SvmOnInstructionHandlerArgs<
1547
- Config,
1548
- SvmInstruction<
1549
- SvmParamsFromProgramTable<Programs[P][I]>,
1550
- Programs[P][I]["transaction"],
1551
- Programs[P][I]["block"]
1552
- >
1553
- >,
1554
- ) => Promise<void>,
1780
+ options: SvmOnInstructionOptions<P, I, F>,
1781
+ handler: SvmOnInstructionHandlerFor<
1782
+ SvmSelectedInstruction<F, Programs[P][I]>,
1783
+ Config
1784
+ >,
1555
1785
  ) => void;
1556
1786
  }
1557
1787
  : {
@@ -1691,14 +1921,71 @@ type FuelTestIndexerChainConfig<Config extends IndexerConfigTypes = GlobalConfig
1691
1921
  simulate?: FuelSimulateItem<Config>[];
1692
1922
  };
1693
1923
 
1694
- /** Configuration for a single SVM chain in the test indexer. SVM has no
1695
- * `onEvent` handlers yet, so simulate items aren't supported — only slot
1696
- * range overrides for driving `indexer.onSlot` block handlers under test. */
1697
- type SvmTestIndexerChainConfig = {
1924
+ /** Simulate item type for SVM ecosystem. */
1925
+ type SvmSimulateItem<Config extends IndexerConfigTypes = GlobalConfig> =
1926
+ Config["svm"] extends { programs: infer Programs extends Record<string, Record<string, any>> }
1927
+ ? {
1928
+ [P in keyof Programs]: {
1929
+ [I in keyof Programs[P]]: {
1930
+ /** Program name as declared under `chains[].programs[].name`. */
1931
+ program: P;
1932
+ /** Instruction name as declared under the program. */
1933
+ instruction: I;
1934
+ /** Override the slot. Auto-increments by default. */
1935
+ slot?: number;
1936
+ /** Instruction path in the CPI tree. Defaults to `[0]`. */
1937
+ path?: readonly number[];
1938
+ /** Override the program id. Defaults to the configured `program_id`. */
1939
+ programId?: string;
1940
+ /** Raw instruction data, `0x`-prefixed hex. */
1941
+ data?: string;
1942
+ /** Whether this is a CPI-invoked inner instruction. */
1943
+ isInner?: boolean;
1944
+ /** Decoded args. Keys match the instruction's arg names. */
1945
+ args?: Programs[P][I] extends { args: infer A } ? A : unknown;
1946
+ /** Named accounts. Keys match the instruction's account names. */
1947
+ accounts?: Programs[P][I] extends { accounts: infer Acc extends Record<string, unknown> }
1948
+ ? { readonly [K in keyof Acc]?: { readonly address: string } }
1949
+ : Record<string, { readonly address: string }>;
1950
+ /** Positional account addresses, zipped onto IDL names when `accounts` is omitted. */
1951
+ accountArguments?: readonly string[];
1952
+ /** Logs scoped to this instruction. */
1953
+ logs?: readonly { readonly kind?: string; readonly message?: string }[];
1954
+ /** Override block fields. */
1955
+ block?: Partial<SvmAllBlockFields>;
1956
+ /** Override transaction fields. `accountActivities` are joined onto named accounts at process time. */
1957
+ transaction?: Partial<SvmAllTransactionFields> & {
1958
+ readonly accountActivities?: readonly {
1959
+ readonly address: string;
1960
+ readonly transactionAccountIndex?: number;
1961
+ readonly isSigner?: boolean;
1962
+ readonly isWritable?: boolean;
1963
+ readonly lamports?: {
1964
+ readonly pre?: bigint;
1965
+ readonly post?: bigint;
1966
+ };
1967
+ readonly token?: {
1968
+ readonly mint?: string;
1969
+ readonly owner?: string;
1970
+ readonly decimals?: number;
1971
+ readonly preAmount?: bigint;
1972
+ readonly postAmount?: bigint;
1973
+ };
1974
+ }[];
1975
+ };
1976
+ };
1977
+ }[keyof Programs[P]];
1978
+ }[keyof Programs]
1979
+ : never;
1980
+
1981
+ /** Configuration for a single SVM chain in the test indexer. */
1982
+ type SvmTestIndexerChainConfig<Config extends IndexerConfigTypes = GlobalConfig> = {
1698
1983
  /** The slot number to start processing from. Defaults to config startBlock or progressBlock+1. */
1699
1984
  startBlock?: number;
1700
- /** The slot number to stop processing at. */
1985
+ /** The slot number to stop processing at. Defaults to max simulate slot when simulate is provided. */
1701
1986
  endBlock?: number;
1987
+ /** Simulate items to process instead of fetching from real sources. */
1988
+ simulate?: SvmSimulateItem<Config>[];
1702
1989
  };
1703
1990
 
1704
1991
  /** Entity change value containing sets and/or deleted IDs. */
@@ -1725,10 +2012,10 @@ type ConfigEntities<Config extends IndexerConfigTypes = GlobalConfig> =
1725
2012
  type PerChainEntityNames<Config extends IndexerConfigTypes = GlobalConfig> =
1726
2013
  Config extends { perChainEntities: infer Names extends string } ? Names : never;
1727
2014
 
1728
- /** The row shape the chain-agnostic test-indexer operations exchange. A
1729
- * per-chain entity's row is only identified together with its chain, so the
1730
- * chain id travels alongside the entity fields. */
1731
- type TestIndexerEntityRow<
2015
+ /** The row shape chain-agnostic APIs exchange. A per-chain entity's row is
2016
+ * only identified together with its chain, so the chain id travels alongside
2017
+ * the entity fields. */
2018
+ type ChainScopedEntityRow<
1732
2019
  Config extends IndexerConfigTypes,
1733
2020
  Name,
1734
2021
  Entity
@@ -1806,7 +2093,7 @@ type FuelTestChains<Config extends IndexerConfigTypes = GlobalConfig> =
1806
2093
 
1807
2094
  type SvmTestChains<Config extends IndexerConfigTypes = GlobalConfig> =
1808
2095
  HasSvm<Config> extends true
1809
- ? { [K in SvmChainIds<Config>]?: SvmTestIndexerChainConfig }
2096
+ ? { [K in SvmChainIds<Config>]?: SvmTestIndexerChainConfig<Config> }
1810
2097
  : {};
1811
2098
 
1812
2099
  /** Process configuration for the test indexer, with chains keyed by chain ID. */
@@ -1922,7 +2209,7 @@ export type TestIndexerFromConfig<Config extends IndexerConfigTypes = GlobalConf
1922
2209
  } & SingleEcosystemTestChains<Config> & {
1923
2210
  /** Entity operations for direct manipulation outside of handlers. */
1924
2211
  readonly [K in keyof ConfigEntities<Config>]: TestIndexerEntityOperations<
1925
- TestIndexerEntityRow<Config, K, ConfigEntities<Config>[K]>
2212
+ ChainScopedEntityRow<Config, K, ConfigEntities<Config>[K]>
1926
2213
  >;
1927
2214
  };
1928
2215
 
@@ -1958,18 +2245,6 @@ export type FuelChainId = IsEmptyObject<FuelChainsT> extends true ? NotConfigure
1958
2245
  /** Union of all configured SVM chain IDs. */
1959
2246
  export type SvmChainId = IsEmptyObject<SvmChainsT> extends true ? NotConfigured<"SvmChainId", "Configure SVM chains"> : SvmChainsT [keyof SvmChainsT ]["id"];
1960
2247
 
1961
- /** The SVM parent-transaction type generated from this project's
1962
- * `field_selection`: the union of every instruction's `transaction` shape,
1963
- * with unselected fields typed as `FieldNotSelected<...>`. Resolves to a
1964
- * `NotConfigured` hint until `envio codegen` augments {@link Global}. */
1965
- export type SvmTransaction = IsEmptyObject<SvmProgramsT> extends true
1966
- ? NotConfigured<"SvmTransaction", "Configure SVM programs">
1967
- : {
1968
- [P in keyof SvmProgramsT]: {
1969
- [I in keyof SvmProgramsT[P]]: SvmProgramsT[P][I]["transaction"];
1970
- }[keyof SvmProgramsT[P]];
1971
- }[keyof SvmProgramsT];
1972
-
1973
2248
  /** Lookup an EVM event type by contract and event name. Without generics,
1974
2249
  * resolves to the discriminated union of every EVM event in the project. */
1975
2250
  export type EvmEvent<
@@ -2008,6 +2283,244 @@ export type EnumName = keyof EnumsT & string;
2008
2283
  /** Lookup an enum value type by name (e.g. `Enum<"AccountType">`). */
2009
2284
  export type Enum<TName extends EnumName> = EnumsT[TName];
2010
2285
 
2286
+ // ============== Custom Resolver Types ==============
2287
+
2288
+ /** Handle for a custom GraphQL resolver created via {@link createResolver}. */
2289
+ export declare abstract class Resolver<Args, Output> {
2290
+ protected opaque: Args | Output;
2291
+ }
2292
+
2293
+ /** The selection the caller asked for: field names and their nesting, with
2294
+ * aliases and fragments already resolved away. A resolver may use it to skip
2295
+ * work it wasn't asked for — the response is projected against the declared
2296
+ * schema either way, so correctness never depends on honouring it. */
2297
+ export type ResolverSelection = { readonly [field: string]: ResolverSelection };
2298
+
2299
+ /** Request metadata, forwarded by envio-serve. */
2300
+ export type ResolverContext = {
2301
+ /** The role the operation was executed under. `admin: true` resolvers are
2302
+ * only reachable as `"admin"`. */
2303
+ readonly role: "public" | "admin";
2304
+ /** Correlates this field's work with the operation it belongs to. */
2305
+ readonly requestId: string;
2306
+ /** W3C trace context of the incoming request, when the caller sent one. */
2307
+ readonly traceparent?: string;
2308
+ };
2309
+
2310
+ /** How far a chain has been indexed. Read it to refuse to answer from a stale
2311
+ * index — `sourceBlock - progressBlock` is how far behind the head the
2312
+ * indexer is. */
2313
+ export type ChainHeight = {
2314
+ readonly chainId: number;
2315
+ /** `"evm"`, `"fuel"` or `"svm"`. Chain ids are only unique within one. */
2316
+ readonly ecosystem: string;
2317
+ readonly startBlock: number;
2318
+ readonly endBlock: number | null;
2319
+ /** The latest block seen on the chain. */
2320
+ readonly sourceBlock: number;
2321
+ /** The latest block fetched from the source. */
2322
+ readonly bufferBlock: number;
2323
+ /** The latest block whose events have been processed and committed. */
2324
+ readonly progressBlock: number;
2325
+ /** When the chain first caught up to the head, or null while it hasn't. */
2326
+ readonly readyAt: Date | null;
2327
+ readonly isReady: boolean;
2328
+ };
2329
+
2330
+ /** Raw SQL, run under the resolver's `statement_timeout` and against its
2331
+ * bounded pool. */
2332
+ export type ResolverSql = {
2333
+ /** ``db.sql`select 1` `` */
2334
+ <Row = Record<string, unknown>>(
2335
+ strings: TemplateStringsArray,
2336
+ ...values: readonly unknown[]
2337
+ ): Promise<Row[]>;
2338
+ /** `db.sql.unsafe(text, params)` — the direct lift for a query built as a
2339
+ * string with positional parameters. */
2340
+ unsafe<Row = Record<string, unknown>>(
2341
+ text: string,
2342
+ params?: readonly unknown[],
2343
+ options?: { readonly prepare?: boolean }
2344
+ ): Promise<Row[]>;
2345
+ };
2346
+
2347
+ /** Options accepted by `db.find`. */
2348
+ export type ResolverFindOptions<Entity> = {
2349
+ /** Filter by field, with the same operators as `context.<Entity>.getWhere`.
2350
+ * Unlike `getWhere`, any field can be filtered on here — it is a query
2351
+ * against the table, so an unindexed field is a slow one, not an error. */
2352
+ readonly where?: GetWhereFilter<Entity>;
2353
+ readonly orderBy?: readonly {
2354
+ readonly field: keyof Entity & string;
2355
+ readonly direction: "asc" | "desc";
2356
+ }[];
2357
+ readonly limit?: number;
2358
+ readonly offset?: number;
2359
+ };
2360
+
2361
+ /** The database a resolver reads through. Every query it runs carries the
2362
+ * resolver's `timeoutMs` as a `statement_timeout` and takes one of the
2363
+ * process's bounded connections. */
2364
+ export type ResolverDb<Config extends IndexerConfigTypes = GlobalConfig> = {
2365
+ /** Entities matching `where`, decoded exactly as a handler sees them. */
2366
+ readonly find: <Name extends keyof ConfigEntities<Config> & string>(
2367
+ entityName: Name,
2368
+ options?: ResolverFindOptions<
2369
+ ChainScopedEntityRow<Config, Name, ConfigEntities<Config>[Name]>
2370
+ >
2371
+ ) => Promise<
2372
+ ChainScopedEntityRow<Config, Name, ConfigEntities<Config>[Name]>[]
2373
+ >;
2374
+ /** One entity by id, or null. Not available for per-chain entities, whose
2375
+ * key is the id together with a chain — use {@link ResolverDb.find}. */
2376
+ readonly get: <
2377
+ Name extends Exclude<
2378
+ keyof ConfigEntities<Config> & string,
2379
+ PerChainEntityNames<Config>
2380
+ >
2381
+ >(
2382
+ entityName: Name,
2383
+ id: EntityId<ConfigEntities<Config>[Name]>
2384
+ ) => Promise<ConfigEntities<Config>[Name] | null>;
2385
+ /** Raw SQL, for what the loaders don't express. */
2386
+ readonly sql: ResolverSql;
2387
+ /** The Postgres schema the indexer's tables live in. Raw SQL has to qualify
2388
+ * table names with it — it is not `"public"` on a hosted deployment. */
2389
+ readonly pgSchema: string;
2390
+ /** Several queries on one connection, under one timeout. */
2391
+ readonly transaction: <T>(work: (sql: ResolverSql) => Promise<T>) => Promise<T>;
2392
+ /** How far each chain has been indexed, keyed by chain id. */
2393
+ readonly chainHeights: () => Promise<Record<string, ChainHeight>>;
2394
+ };
2395
+
2396
+ /** Arguments passed to a {@link Resolver}'s handler. */
2397
+ export type ResolverHandlerArgs<
2398
+ Args,
2399
+ Config extends IndexerConfigTypes = GlobalConfig
2400
+ > = {
2401
+ /** Coerced and validated against the declared arg schemas before the
2402
+ * resolver is reached. */
2403
+ readonly args: Args;
2404
+ readonly db: ResolverDb<Config>;
2405
+ readonly selection: ResolverSelection;
2406
+ readonly ctx: ResolverContext;
2407
+ };
2408
+
2409
+ /**
2410
+ * Declares a custom GraphQL resolver: a root query field served alongside the
2411
+ * generated entity fields, backed by TypeScript in this project.
2412
+ *
2413
+ * Arguments and result are declared with the same `S` schemas effects use, and
2414
+ * the GraphQL types are derived from them. A field is non-null unless its
2415
+ * schema is optional. Object types must be named with {@link defineType} —
2416
+ * GraphQL has no anonymous types.
2417
+ *
2418
+ * ```ts
2419
+ * export const marketsAprByPeriod = createResolver({
2420
+ * name: "marketsAprByPeriod",
2421
+ * args: { periodStart: S.int32, periodEnd: S.int32 },
2422
+ * output: S.array(defineType("MarketApr", { marketAddress: S.string })),
2423
+ * timeoutMs: 30_000,
2424
+ * handler: async ({ args, db }) => db.find("MarketInfo"),
2425
+ * });
2426
+ * ```
2427
+ */
2428
+ export function createResolver<
2429
+ // Both are schemas at runtime: `createResolver` reads `output.t` and walks
2430
+ // every argument with `toGraphQLType` while the module is being imported, so
2431
+ // anything else fails at indexer startup rather than in the editor.
2432
+ AS extends Record<string, Sury.Schema<unknown>>,
2433
+ OS extends Sury.Schema<unknown>,
2434
+ A = UnknownToOutput<AS>,
2435
+ O = UnknownToOutput<OS>,
2436
+ // A hack to enforce that the inferred return type matches the output schema.
2437
+ R extends O = O
2438
+ >(options: {
2439
+ /** The GraphQL field name. Must not collide with a generated one. */
2440
+ readonly name: string;
2441
+ /** Shown in the schema, for the people querying it. */
2442
+ readonly description?: string;
2443
+ /** Argument schemas, keyed by argument name. */
2444
+ readonly args?: AS;
2445
+ /** The result schema. Determines the field's GraphQL type. */
2446
+ readonly output: OS;
2447
+ /** Register the field on the admin schema only: it stays out of public
2448
+ * introspection and is unexecutable without the admin secret. */
2449
+ readonly admin?: boolean;
2450
+ /** The `statement_timeout` every query this resolver runs is bounded by.
2451
+ * Required: it is the only thing bounding a runaway query. */
2452
+ readonly timeoutMs: number;
2453
+ readonly handler: (args: ResolverHandlerArgs<A>) => Promise<R>;
2454
+ }): Resolver<A, O>;
2455
+
2456
+ /**
2457
+ * Thrown by a resolver to put a specific error on the client's response.
2458
+ *
2459
+ * Anything else a handler throws is reported as an internal failure with its
2460
+ * message withheld — a driver error can carry a connection string, and the
2461
+ * caller is the public internet — so this is how a resolver says more than
2462
+ * that. envio-serve carries the extensions through unchanged.
2463
+ *
2464
+ * ```ts
2465
+ * throw new ResolverError("Service is syncing", {
2466
+ * code: "SERVICE_UNAVAILABLE",
2467
+ * httpStatus: 503,
2468
+ * });
2469
+ * ```
2470
+ */
2471
+ export declare class ResolverError extends Error {
2472
+ constructor(
2473
+ message: string,
2474
+ options?: {
2475
+ /** Becomes `extensions.code`. Defaults to `"INTERNAL_SERVER_ERROR"`. */
2476
+ readonly code?: string;
2477
+ /** Becomes `extensions.http.status`. */
2478
+ readonly httpStatus?: number;
2479
+ /** Merged into `extensions` alongside `code`. */
2480
+ readonly extensions?: Record<string, unknown>;
2481
+ }
2482
+ );
2483
+ readonly code: string;
2484
+ readonly httpStatus?: number;
2485
+ readonly extensions?: Record<string, unknown>;
2486
+ }
2487
+
2488
+ /** Names a schema so it can appear in the GraphQL schema as an object type. */
2489
+ export function defineType<F extends Record<string, unknown>>(
2490
+ name: string,
2491
+ fields: F
2492
+ ): Sury.Schema<UnknownToOutput<F>>;
2493
+
2494
+ /**
2495
+ * Names a schema that appears in an argument.
2496
+ *
2497
+ * GraphQL keeps input and output types in a separate namespace from object
2498
+ * types, so a `where` argument is declared with this rather than with
2499
+ * {@link defineType}.
2500
+ */
2501
+ export function defineInput<F extends Record<string, unknown>>(
2502
+ name: string,
2503
+ fields: F
2504
+ ): Sury.Schema<UnknownToOutput<F>>;
2505
+
2506
+ /** Every resolver declared so far, in declaration order. */
2507
+ export function getRegisteredResolvers(): readonly Resolver<unknown, unknown>[];
2508
+
2509
+ /** The manifest and SDL for everything declared so far. */
2510
+ export function buildRegisteredManifest(): { manifest: unknown; sdl: string };
2511
+
2512
+ /** Names a schema representing a GraphQL enum. */
2513
+ export function defineEnum<const V extends readonly string[]>(
2514
+ name: string,
2515
+ values: V
2516
+ ): Sury.Schema<V[number]>;
2517
+
2518
+ /** Names a schema representing a custom GraphQL scalar, such as `BigInt`. */
2519
+ export function defineScalar<T>(
2520
+ name: string,
2521
+ schema: Sury.Schema<T>
2522
+ ): Sury.Schema<T>;
2523
+
2011
2524
  // ============== Runtime values ==============
2012
2525
 
2013
2526
  /** The indexer instance. Register handlers with `indexer.onEvent`,