envio 3.8.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 (109) 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 +433 -109
  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 +102 -100
  14. package/src/ChainState.res.mjs +81 -67
  15. package/src/ChainState.resi +28 -15
  16. package/src/Config.res +43 -122
  17. package/src/Config.res.mjs +33 -75
  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/EventConfigBuilder.res +169 -28
  26. package/src/EventConfigBuilder.res.mjs +124 -17
  27. package/src/FetchState.res +59 -67
  28. package/src/FetchState.res.mjs +34 -44
  29. package/src/HandlerRegister.res +6 -4
  30. package/src/HandlerRegister.res.mjs +8 -5
  31. package/src/InMemoryStore.res +22 -32
  32. package/src/InMemoryStore.res.mjs +12 -24
  33. package/src/IndexerState.res +40 -3
  34. package/src/IndexerState.res.mjs +30 -4
  35. package/src/IndexerState.resi +4 -1
  36. package/src/Internal.res +16 -17
  37. package/src/Main.res +25 -15
  38. package/src/Main.res.mjs +19 -14
  39. package/src/Metrics.res +15 -1
  40. package/src/Metrics.res.mjs +5 -1
  41. package/src/Persistence.res +42 -19
  42. package/src/Persistence.res.mjs +8 -5
  43. package/src/PgStorage.res +232 -78
  44. package/src/PgStorage.res.mjs +114 -72
  45. package/src/PruneStaleHistory.res +1 -1
  46. package/src/PruneStaleHistory.res.mjs +1 -1
  47. package/src/Rollback.res +62 -41
  48. package/src/Rollback.res.mjs +61 -19
  49. package/src/RollbackCommit.res +7 -9
  50. package/src/RollbackCommit.res.mjs +5 -6
  51. package/src/SimulateItems.res +5 -12
  52. package/src/SimulateItems.res.mjs +6 -10
  53. package/src/Sink.res +35 -26
  54. package/src/Sink.res.mjs +20 -16
  55. package/src/TestIndexer.res +95 -113
  56. package/src/TestIndexer.res.mjs +63 -90
  57. package/src/Utils.res +38 -0
  58. package/src/Utils.res.mjs +39 -2
  59. package/src/Writing.res +4 -2
  60. package/src/Writing.res.mjs +3 -2
  61. package/src/bindings/ClickHouse.res +311 -683
  62. package/src/bindings/ClickHouse.res.mjs +294 -416
  63. package/src/bindings/ClickHouseSink.res +303 -0
  64. package/src/bindings/ClickHouseSink.res.mjs +216 -0
  65. package/src/bindings/NodeJs.res +9 -0
  66. package/src/bindings/NodeJs.res.mjs +8 -1
  67. package/src/bindings/Postgres.res +9 -0
  68. package/src/bindings/Postgres.res.mjs +3 -0
  69. package/src/db/EntityHistory.res +29 -24
  70. package/src/db/EntityHistory.res.mjs +11 -19
  71. package/src/db/InternalTable.res +247 -83
  72. package/src/db/InternalTable.res.mjs +216 -85
  73. package/src/db/RollbackScope.res +29 -0
  74. package/src/db/RollbackScope.res.mjs +31 -0
  75. package/src/db/Table.res +28 -1
  76. package/src/db/Table.res.mjs +26 -2
  77. package/src/resolvers/ResolverProcess.res +809 -0
  78. package/src/resolvers/ResolverProcess.res.mjs +667 -0
  79. package/src/resolvers/ResolverQuery.res +317 -0
  80. package/src/resolvers/ResolverQuery.res.mjs +220 -0
  81. package/src/resolvers/collisions.js +108 -0
  82. package/src/resolvers/db.js +363 -0
  83. package/src/resolvers/dispatch.js +165 -0
  84. package/src/resolvers/errors.js +30 -0
  85. package/src/resolvers/graphqlSelection.js +292 -0
  86. package/src/resolvers/hasuraAction.js +84 -0
  87. package/src/resolvers/hasuraApply.js +323 -0
  88. package/src/resolvers/hasuraMetadata.js +119 -0
  89. package/src/resolvers/index.js +95 -0
  90. package/src/resolvers/manifest.js +370 -0
  91. package/src/resolvers/server.js +270 -0
  92. package/src/sources/AddressSet.res +0 -22
  93. package/src/sources/AddressStore.res +48 -88
  94. package/src/sources/AddressStore.res.mjs +11 -22
  95. package/src/sources/Evm.res +2 -0
  96. package/src/sources/Evm.res.mjs +2 -0
  97. package/src/sources/Fuel.res +2 -0
  98. package/src/sources/Fuel.res.mjs +2 -0
  99. package/src/sources/Svm.res +2 -0
  100. package/src/sources/Svm.res.mjs +2 -0
  101. package/src/sources/SvmHyperSyncClient.res +13 -107
  102. package/src/sources/SvmHyperSyncClient.res.mjs +2 -5
  103. package/src/sources/SvmHyperSyncSource.res +5 -10
  104. package/src/sources/SvmHyperSyncSource.res.mjs +5 -13
  105. package/src/tui/Tui.res +1 -1
  106. package/src/tui/Tui.res.mjs +1 -1
  107. package/svm.schema.json +17 -78
  108. package/src/MemoryStorage.res +0 -756
  109. package/src/MemoryStorage.res.mjs +0 -623
package/index.d.ts CHANGED
@@ -1169,37 +1169,34 @@ export type SvmLogKind =
1169
1169
  | "data"
1170
1170
  | (string & {});
1171
1171
 
1172
- export type SvmLog = {
1172
+ export type SvmAllLogFields = {
1173
1173
  readonly kind: SvmLogKind;
1174
1174
  readonly message: string;
1175
1175
  };
1176
1176
 
1177
- export type SvmAccountActivity = {
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 = {
1178
1191
  readonly address: string;
1179
1192
  readonly transactionAccountIndex: number;
1180
1193
  readonly isSigner: boolean;
1181
1194
  readonly isWritable: boolean;
1182
- readonly lamports: { readonly pre: bigint; readonly post: bigint } | undefined;
1183
- readonly token: {
1184
- readonly mint: string;
1185
- readonly owner: string;
1186
- readonly decimals: number;
1187
- readonly preAmount: bigint | undefined;
1188
- readonly postAmount: bigint | undefined;
1189
- } | undefined;
1195
+ readonly lamports: SvmAllAccountLamportsFields | undefined;
1196
+ readonly token: SvmAllAccountTokenActivityFields | undefined;
1190
1197
  };
1191
1198
 
1192
- export type SvmInstructionAccount<
1193
- Activity = SvmAccountActivity,
1194
- Name extends string = string,
1195
- > = {
1196
- readonly address: string;
1197
- readonly accountName: Name;
1198
- readonly instructionAccountIndex: number;
1199
- readonly activity: Activity | undefined;
1200
- };
1201
-
1202
- export type SvmBlock = {
1199
+ export type SvmAllBlockFields = {
1203
1200
  readonly slot: number;
1204
1201
  readonly time: number;
1205
1202
  readonly hash: string;
@@ -1208,10 +1205,10 @@ export type SvmBlock = {
1208
1205
  readonly parentHash: string;
1209
1206
  };
1210
1207
 
1211
- /** All SVM parent-transaction fields when selected. Handler
1212
- * `fields.transaction` narrows this; `accountActivities` is implied by
1208
+ /** All SVM parent-transaction fields. Handler `fields.transaction` narrows
1209
+ * this via {@link SvmTransaction}; `accountActivities` is implied by
1213
1210
  * `fields.accountActivity`. */
1214
- export type SvmTransaction = {
1211
+ export type SvmAllTransactionFields = {
1215
1212
  readonly transactionIndex: number;
1216
1213
  readonly signature: string;
1217
1214
  readonly feePayer: string;
@@ -1250,10 +1247,8 @@ export type SvmAccountActivityFieldName =
1250
1247
  | "transactionAccountIndex"
1251
1248
  | "isSigner"
1252
1249
  | "isWritable"
1253
- | "lamports"
1254
1250
  | "lamports.pre"
1255
1251
  | "lamports.post"
1256
- | "token"
1257
1252
  | "token.mint"
1258
1253
  | "token.owner"
1259
1254
  | "token.decimals"
@@ -1276,6 +1271,19 @@ export type SvmFieldsSelection = {
1276
1271
  readonly log?: readonly SvmLogFieldName[];
1277
1272
  };
1278
1273
 
1274
+ /** A {@link SvmFieldsSelection} with every field selected.
1275
+ *
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
+
1279
1287
  type SvmListedArray<Fields, Knob extends keyof SvmFieldsSelection> = Fields[Knob &
1280
1288
  keyof Fields];
1281
1289
  type SvmListedFields<Fields, Knob extends keyof SvmFieldsSelection> = NonNullable<
@@ -1302,15 +1310,7 @@ type SvmActivityHas<Fields, Name extends string> = [SvmActivityListed<Fields>] e
1302
1310
  ? false
1303
1311
  : Name extends SvmActivityListed<Fields>
1304
1312
  ? true
1305
- : Name extends `lamports.${string}`
1306
- ? "lamports" extends SvmActivityListed<Fields>
1307
- ? true
1308
- : false
1309
- : Name extends `token.${string}`
1310
- ? "token" extends SvmActivityListed<Fields>
1311
- ? true
1312
- : false
1313
- : false;
1313
+ : false;
1314
1314
 
1315
1315
  type SvmActivityField<Fields, Name extends string, T> = SvmActivityHas<
1316
1316
  Fields,
@@ -1319,38 +1319,37 @@ type SvmActivityField<Fields, Name extends string, T> = SvmActivityHas<
1319
1319
  ? T
1320
1320
  : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1321
1321
 
1322
- type SvmSelectedLamports<Fields> =
1323
- SvmActivityHas<Fields, "lamports.pre"> extends true
1324
- ? SvmActivityHas<Fields, "lamports.post"> extends true
1325
- ? { readonly pre: bigint; readonly post: bigint } | undefined
1326
- : { readonly pre: bigint } | undefined
1327
- : SvmActivityHas<Fields, "lamports.post"> extends true
1328
- ? { readonly post: bigint } | undefined
1329
- : FieldNotSelected<`Field 'lamports' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1330
-
1331
- export type SvmAccountTokenActivity = {
1332
- readonly mint: string;
1333
- readonly owner: string;
1334
- readonly decimals: number;
1335
- readonly preAmount: bigint | undefined;
1336
- readonly postAmount: bigint | undefined;
1337
- };
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;
1338
1333
 
1339
- type SvmSelectedToken<Fields> = [SvmActivityListed<Fields> & (`token` | `token.${string}`)] extends [never]
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]
1340
1337
  ? FieldNotSelected<`Field 'token' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>
1341
1338
  : {
1342
- readonly [K in keyof SvmAccountTokenActivity as SvmActivityHas<Fields, `token.${K & string}`> extends true
1343
- ? K
1344
- : never]: SvmAccountTokenActivity[K];
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.`>;
1345
1342
  } | undefined;
1346
1343
 
1347
- type SvmSelectedAccountActivity<Fields> = {
1344
+ /** An account activity of a {@link SvmTransaction}, narrowed to the
1345
+ * registration's fields selection. */
1346
+ export type SvmAccountActivity<Fields extends SvmFieldsSelection> = {
1348
1347
  readonly address: string;
1349
1348
  readonly transactionAccountIndex: SvmActivityField<Fields, "transactionAccountIndex", number>;
1350
1349
  readonly isSigner: SvmActivityField<Fields, "isSigner", boolean>;
1351
1350
  readonly isWritable: SvmActivityField<Fields, "isWritable", boolean>;
1352
- readonly lamports: SvmSelectedLamports<Fields>;
1353
- readonly token: SvmSelectedToken<Fields>;
1351
+ readonly lamports: SvmAccountLamports<Fields>;
1352
+ readonly token: SvmAccountTokenActivity<Fields>;
1354
1353
  };
1355
1354
 
1356
1355
  type SvmInstrListed<Fields> = SvmListedFields<Fields, "instruction">;
@@ -1358,37 +1357,54 @@ type SvmInstrField<Fields, Name extends SvmInstructionFieldName, T> = Name exten
1358
1357
  ? T
1359
1358
  : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.instruction in the registration options.`>;
1360
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,
1365
+ > = {
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
+
1361
1376
  type SvmNamedAccounts<
1362
1377
  Acc extends Readonly<Record<string, unknown>>,
1363
- Fields,
1378
+ Fields extends SvmFieldsSelection,
1364
1379
  > = {
1365
- readonly [K in keyof Acc & string]: SvmInstructionAccount<
1366
- [SvmActivityListed<Fields>] extends [never]
1367
- ? FieldNotSelected<`Field 'activity' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1368
- : SvmSelectedAccountActivity<Fields> | undefined,
1369
- K
1370
- >;
1380
+ readonly [K in keyof Acc & string]: SvmInstructionAccount<Fields, K>;
1371
1381
  };
1372
1382
 
1373
- type SvmSelectedTransaction<Fields> = {
1374
- readonly [K in keyof SvmTransaction]: K extends SvmListedFields<Fields, "transaction">
1375
- ? SvmTransaction[K]
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]
1376
1388
  : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.transaction in the registration options.`>;
1377
1389
  } & {
1378
1390
  readonly accountActivities: [SvmActivityListed<Fields>] extends [never]
1379
1391
  ? FieldNotSelected<`Field 'accountActivities' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1380
- : readonly SvmSelectedAccountActivity<Fields>[];
1392
+ : readonly SvmAccountActivity<Fields>[];
1381
1393
  };
1382
1394
 
1383
- type SvmSelectedBlock<Fields> = {
1384
- readonly [K in keyof SvmBlock]: K extends "slot"
1385
- ? SvmBlock[K]
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]
1386
1400
  : K extends SvmListedFields<Fields, "block">
1387
- ? SvmBlock[K]
1401
+ ? SvmAllBlockFields[K]
1388
1402
  : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.block in the registration options.`>;
1389
1403
  };
1390
1404
 
1391
- type SvmSelectedLog<Fields> = {
1405
+ /** A log of a {@link SvmInstruction}, narrowed to the registration's fields
1406
+ * selection. */
1407
+ export type SvmLog<Fields extends SvmFieldsSelection> = {
1392
1408
  readonly kind: "kind" extends SvmListedFields<Fields, "log">
1393
1409
  ? SvmLogKind
1394
1410
  : FieldNotSelected<`Field 'kind' is not selected for this handler. Add it to fields.log in the registration options.`>;
@@ -1397,10 +1413,12 @@ type SvmSelectedLog<Fields> = {
1397
1413
  : FieldNotSelected<`Field 'message' is not selected for this handler. Add it to fields.log in the registration options.`>;
1398
1414
  };
1399
1415
 
1400
- export type SvmInstruction<
1401
- ProgInstr = { readonly args: unknown; readonly accounts: Readonly<Record<string, string>> },
1402
- Fields = {},
1403
- > = {
1416
+ type SvmAnyProgramInstruction = {
1417
+ readonly args: unknown;
1418
+ readonly accounts: Readonly<Record<string, string>>;
1419
+ };
1420
+
1421
+ type SvmSelectedInstruction<Fields extends SvmFieldsSelection, ProgInstr> = {
1404
1422
  readonly programName: string;
1405
1423
  readonly instructionName: string;
1406
1424
  readonly discriminator: string;
@@ -1411,7 +1429,7 @@ export type SvmInstruction<
1411
1429
  readonly args: SvmInstrField<
1412
1430
  Fields,
1413
1431
  "args",
1414
- ProgInstr extends { readonly args: infer A } ? A | undefined : unknown | undefined
1432
+ ProgInstr extends { readonly args: infer A } ? A : unknown
1415
1433
  >;
1416
1434
  readonly accounts: SvmInstrField<
1417
1435
  Fields,
@@ -1423,25 +1441,85 @@ export type SvmInstruction<
1423
1441
  readonly accountArguments: SvmInstrField<Fields, "accountArguments", readonly string[]>;
1424
1442
  readonly logs: [SvmListedFields<Fields, "log">] extends [never]
1425
1443
  ? FieldNotSelected<`Field 'logs' is not selected for this handler. Add fields.log in the registration options.`>
1426
- : readonly SvmSelectedLog<Fields>[];
1427
- readonly transaction: SvmSelectedTransaction<Fields>;
1428
- readonly block: SvmSelectedBlock<Fields>;
1429
- };
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>>;
1430
1469
 
1431
- /** Arguments passed to handlers registered via `indexer.onInstruction`. */
1432
- export type SvmOnInstructionHandlerArgs<
1433
- Config extends IndexerConfigTypes = GlobalConfig,
1434
- Instr = SvmInstruction,
1435
- > = {
1470
+ type SvmOnInstructionArgsFor<Instr, Config extends IndexerConfigTypes> = {
1436
1471
  readonly instruction: Instr;
1437
1472
  readonly context: SvmOnSlotContext<Config>;
1438
1473
  };
1439
1474
 
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
+ };
1517
+
1440
1518
  /** Options for an SVM `indexer.onInstruction` registration. */
1441
1519
  export type SvmOnInstructionOptions<
1442
1520
  P extends string = string,
1443
1521
  I extends string = string,
1444
- Fields extends SvmFieldsSelection | undefined = undefined,
1522
+ Fields extends SvmFieldsSelection = {},
1445
1523
  > = {
1446
1524
  /** Program name as declared under `chains[].programs[].name` in
1447
1525
  * `config.yaml`. */
@@ -1450,12 +1528,24 @@ export type SvmOnInstructionOptions<
1450
1528
  * `chains[].programs[].instructions[].name` in `config.yaml`. */
1451
1529
  readonly instruction: I;
1452
1530
  readonly fields?: Fields & SvmFieldsLiteralCheck<Fields>;
1531
+ readonly where?: SvmOnInstructionWhere<SvmAccountsOf<P, I>>;
1453
1532
  };
1454
1533
 
1455
- /** 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
+ */
1456
1541
  export type SvmOnInstructionHandler<
1457
- Config extends IndexerConfigTypes = GlobalConfig,
1458
- > = (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
+ >;
1459
1549
 
1460
1550
  // ============== Indexer Types ==============
1461
1551
 
@@ -1685,18 +1775,13 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1685
1775
  readonly onInstruction: <
1686
1776
  P extends keyof Programs & string,
1687
1777
  I extends keyof Programs[P] & string,
1688
- const F extends SvmFieldsSelection | undefined,
1778
+ const F extends SvmFieldsSelection = {},
1689
1779
  >(
1690
1780
  options: SvmOnInstructionOptions<P, I, F>,
1691
- handler: (
1692
- args: SvmOnInstructionHandlerArgs<
1693
- Config,
1694
- SvmInstruction<
1695
- Programs[P][I],
1696
- [F] extends [undefined] ? {} : F
1697
- >
1698
- >,
1699
- ) => Promise<void>,
1781
+ handler: SvmOnInstructionHandlerFor<
1782
+ SvmSelectedInstruction<F, Programs[P][I]>,
1783
+ Config
1784
+ >,
1700
1785
  ) => void;
1701
1786
  }
1702
1787
  : {
@@ -1867,9 +1952,9 @@ type SvmSimulateItem<Config extends IndexerConfigTypes = GlobalConfig> =
1867
1952
  /** Logs scoped to this instruction. */
1868
1953
  logs?: readonly { readonly kind?: string; readonly message?: string }[];
1869
1954
  /** Override block fields. */
1870
- block?: Partial<SvmBlock>;
1955
+ block?: Partial<SvmAllBlockFields>;
1871
1956
  /** Override transaction fields. `accountActivities` are joined onto named accounts at process time. */
1872
- transaction?: Partial<SvmTransaction> & {
1957
+ transaction?: Partial<SvmAllTransactionFields> & {
1873
1958
  readonly accountActivities?: readonly {
1874
1959
  readonly address: string;
1875
1960
  readonly transactionAccountIndex?: number;
@@ -1927,10 +2012,10 @@ type ConfigEntities<Config extends IndexerConfigTypes = GlobalConfig> =
1927
2012
  type PerChainEntityNames<Config extends IndexerConfigTypes = GlobalConfig> =
1928
2013
  Config extends { perChainEntities: infer Names extends string } ? Names : never;
1929
2014
 
1930
- /** The row shape the chain-agnostic test-indexer operations exchange. A
1931
- * per-chain entity's row is only identified together with its chain, so the
1932
- * chain id travels alongside the entity fields. */
1933
- 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<
1934
2019
  Config extends IndexerConfigTypes,
1935
2020
  Name,
1936
2021
  Entity
@@ -2124,7 +2209,7 @@ export type TestIndexerFromConfig<Config extends IndexerConfigTypes = GlobalConf
2124
2209
  } & SingleEcosystemTestChains<Config> & {
2125
2210
  /** Entity operations for direct manipulation outside of handlers. */
2126
2211
  readonly [K in keyof ConfigEntities<Config>]: TestIndexerEntityOperations<
2127
- TestIndexerEntityRow<Config, K, ConfigEntities<Config>[K]>
2212
+ ChainScopedEntityRow<Config, K, ConfigEntities<Config>[K]>
2128
2213
  >;
2129
2214
  };
2130
2215
 
@@ -2138,6 +2223,7 @@ type EvmContractsT = GlobalConfig extends { evm: { contracts: infer X extends
2138
2223
  type FuelChainsT = GlobalConfig extends { fuel: { chains: infer X extends Record<string, { id: number }> } } ? X : {};
2139
2224
  type FuelContractsT = GlobalConfig extends { fuel: { contracts: infer X extends Record<string, Record<string, any>> } } ? X : {};
2140
2225
  type SvmChainsT = GlobalConfig extends { svm: { chains: infer X extends Record<string, { id: number }> } } ? X : {};
2226
+ type SvmProgramsT = GlobalConfig extends { svm: { programs: infer X extends Record<string, Record<string, any>> } } ? X : {};
2141
2227
  type EntitiesT = GlobalConfig extends { entities: infer X extends Record<string, object> } ? X : {};
2142
2228
  type EnumsT = GlobalConfig extends { enums: infer X extends Record<string, any> } ? X : {};
2143
2229
 
@@ -2197,6 +2283,244 @@ export type EnumName = keyof EnumsT & string;
2197
2283
  /** Lookup an enum value type by name (e.g. `Enum<"AccountType">`). */
2198
2284
  export type Enum<TName extends EnumName> = EnumsT[TName];
2199
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
+
2200
2524
  // ============== Runtime values ==============
2201
2525
 
2202
2526
  /** The indexer instance. Register handlers with `indexer.onEvent`,