ponder 0.14.13 → 0.15.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 (237) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/esm/bin/commands/createViews.js +28 -11
  3. package/dist/esm/bin/commands/createViews.js.map +1 -1
  4. package/dist/esm/bin/commands/dev.js +42 -22
  5. package/dist/esm/bin/commands/dev.js.map +1 -1
  6. package/dist/esm/bin/commands/prune.js +3 -0
  7. package/dist/esm/bin/commands/prune.js.map +1 -1
  8. package/dist/esm/bin/commands/serve.js +4 -1
  9. package/dist/esm/bin/commands/serve.js.map +1 -1
  10. package/dist/esm/bin/commands/start.js +18 -6
  11. package/dist/esm/bin/commands/start.js.map +1 -1
  12. package/dist/esm/bin/isolatedController.js +200 -0
  13. package/dist/esm/bin/isolatedController.js.map +1 -0
  14. package/dist/esm/bin/isolatedWorker.js +146 -0
  15. package/dist/esm/bin/isolatedWorker.js.map +1 -0
  16. package/dist/esm/build/config.js +322 -402
  17. package/dist/esm/build/config.js.map +1 -1
  18. package/dist/esm/build/index.js +8 -11
  19. package/dist/esm/build/index.js.map +1 -1
  20. package/dist/esm/build/pre.js +1 -4
  21. package/dist/esm/build/pre.js.map +1 -1
  22. package/dist/esm/build/schema.js +25 -3
  23. package/dist/esm/build/schema.js.map +1 -1
  24. package/dist/esm/client/index.js +306 -42
  25. package/dist/esm/client/index.js.map +1 -1
  26. package/dist/esm/database/actions.js +264 -104
  27. package/dist/esm/database/actions.js.map +1 -1
  28. package/dist/esm/database/index.js +39 -33
  29. package/dist/esm/database/index.js.map +1 -1
  30. package/dist/esm/database/queryBuilder.js +1 -0
  31. package/dist/esm/database/queryBuilder.js.map +1 -1
  32. package/dist/esm/drizzle/index.js +11 -7
  33. package/dist/esm/drizzle/index.js.map +1 -1
  34. package/dist/esm/drizzle/onchain.js +18 -0
  35. package/dist/esm/drizzle/onchain.js.map +1 -1
  36. package/dist/esm/indexing/client.js +32 -25
  37. package/dist/esm/indexing/client.js.map +1 -1
  38. package/dist/esm/indexing/index.js +110 -178
  39. package/dist/esm/indexing/index.js.map +1 -1
  40. package/dist/esm/indexing/profile.js +1 -1
  41. package/dist/esm/indexing/profile.js.map +1 -1
  42. package/dist/esm/indexing-store/cache.js +196 -274
  43. package/dist/esm/indexing-store/cache.js.map +1 -1
  44. package/dist/esm/indexing-store/historical.js +17 -13
  45. package/dist/esm/indexing-store/historical.js.map +1 -1
  46. package/dist/esm/indexing-store/index.js +10 -1
  47. package/dist/esm/indexing-store/index.js.map +1 -1
  48. package/dist/esm/indexing-store/profile.js +3 -3
  49. package/dist/esm/indexing-store/profile.js.map +1 -1
  50. package/dist/esm/indexing-store/realtime.js +27 -2
  51. package/dist/esm/indexing-store/realtime.js.map +1 -1
  52. package/dist/esm/internal/errors.js +28 -0
  53. package/dist/esm/internal/errors.js.map +1 -1
  54. package/dist/esm/internal/metrics.js +279 -82
  55. package/dist/esm/internal/metrics.js.map +1 -1
  56. package/dist/esm/internal/options.js +1 -0
  57. package/dist/esm/internal/options.js.map +1 -1
  58. package/dist/esm/internal/telemetry.js +1 -1
  59. package/dist/esm/internal/telemetry.js.map +1 -1
  60. package/dist/esm/rpc/http.js +130 -0
  61. package/dist/esm/rpc/http.js.map +1 -0
  62. package/dist/esm/rpc/index.js +38 -7
  63. package/dist/esm/rpc/index.js.map +1 -1
  64. package/dist/esm/runtime/events.js +179 -212
  65. package/dist/esm/runtime/events.js.map +1 -1
  66. package/dist/esm/runtime/filter.js +71 -0
  67. package/dist/esm/runtime/filter.js.map +1 -1
  68. package/dist/esm/runtime/fragments.js +78 -73
  69. package/dist/esm/runtime/fragments.js.map +1 -1
  70. package/dist/esm/runtime/historical.js +306 -130
  71. package/dist/esm/runtime/historical.js.map +1 -1
  72. package/dist/esm/runtime/index.js +183 -58
  73. package/dist/esm/runtime/index.js.map +1 -1
  74. package/dist/esm/runtime/isolated.js +462 -0
  75. package/dist/esm/runtime/isolated.js.map +1 -0
  76. package/dist/esm/runtime/multichain.js +80 -73
  77. package/dist/esm/runtime/multichain.js.map +1 -1
  78. package/dist/esm/runtime/omnichain.js +82 -75
  79. package/dist/esm/runtime/omnichain.js.map +1 -1
  80. package/dist/esm/runtime/realtime.js +198 -66
  81. package/dist/esm/runtime/realtime.js.map +1 -1
  82. package/dist/esm/sync-historical/index.js +416 -457
  83. package/dist/esm/sync-historical/index.js.map +1 -1
  84. package/dist/esm/sync-realtime/bloom.js +3 -3
  85. package/dist/esm/sync-realtime/bloom.js.map +1 -1
  86. package/dist/esm/sync-realtime/index.js +27 -46
  87. package/dist/esm/sync-realtime/index.js.map +1 -1
  88. package/dist/esm/sync-store/index.js +112 -63
  89. package/dist/esm/sync-store/index.js.map +1 -1
  90. package/dist/esm/utils/abi.js +20 -32
  91. package/dist/esm/utils/abi.js.map +1 -1
  92. package/dist/esm/utils/chunk.js +8 -0
  93. package/dist/esm/utils/chunk.js.map +1 -0
  94. package/dist/esm/utils/promiseAllSettledWithThrow.js +19 -0
  95. package/dist/esm/utils/promiseAllSettledWithThrow.js.map +1 -0
  96. package/dist/esm/{client/parse.js → utils/sql-parse.js} +94 -80
  97. package/dist/esm/utils/sql-parse.js.map +1 -0
  98. package/dist/types/bin/commands/createViews.d.ts.map +1 -1
  99. package/dist/types/bin/commands/dev.d.ts.map +1 -1
  100. package/dist/types/bin/commands/prune.d.ts.map +1 -1
  101. package/dist/types/bin/commands/serve.d.ts.map +1 -1
  102. package/dist/types/bin/commands/start.d.ts.map +1 -1
  103. package/dist/types/bin/isolatedController.d.ts +13 -0
  104. package/dist/types/bin/isolatedController.d.ts.map +1 -0
  105. package/dist/types/bin/isolatedWorker.d.ts +9 -0
  106. package/dist/types/bin/isolatedWorker.d.ts.map +1 -0
  107. package/dist/types/build/config.d.ts +29 -11
  108. package/dist/types/build/config.d.ts.map +1 -1
  109. package/dist/types/build/index.d.ts +3 -2
  110. package/dist/types/build/index.d.ts.map +1 -1
  111. package/dist/types/build/pre.d.ts +1 -1
  112. package/dist/types/build/pre.d.ts.map +1 -1
  113. package/dist/types/build/schema.d.ts +5 -3
  114. package/dist/types/build/schema.d.ts.map +1 -1
  115. package/dist/types/client/index.d.ts +1 -1
  116. package/dist/types/client/index.d.ts.map +1 -1
  117. package/dist/types/config/index.d.ts +3 -3
  118. package/dist/types/config/index.d.ts.map +1 -1
  119. package/dist/types/database/actions.d.ts +53 -7
  120. package/dist/types/database/actions.d.ts.map +1 -1
  121. package/dist/types/database/index.d.ts +21 -21
  122. package/dist/types/database/index.d.ts.map +1 -1
  123. package/dist/types/database/queryBuilder.d.ts.map +1 -1
  124. package/dist/types/drizzle/index.d.ts +4 -5
  125. package/dist/types/drizzle/index.d.ts.map +1 -1
  126. package/dist/types/drizzle/onchain.d.ts +6 -0
  127. package/dist/types/drizzle/onchain.d.ts.map +1 -1
  128. package/dist/types/indexing/client.d.ts.map +1 -1
  129. package/dist/types/indexing/index.d.ts +2 -5
  130. package/dist/types/indexing/index.d.ts.map +1 -1
  131. package/dist/types/indexing-store/cache.d.ts +3 -2
  132. package/dist/types/indexing-store/cache.d.ts.map +1 -1
  133. package/dist/types/indexing-store/historical.d.ts +2 -1
  134. package/dist/types/indexing-store/historical.d.ts.map +1 -1
  135. package/dist/types/indexing-store/index.d.ts +1 -0
  136. package/dist/types/indexing-store/index.d.ts.map +1 -1
  137. package/dist/types/indexing-store/realtime.d.ts +2 -1
  138. package/dist/types/indexing-store/realtime.d.ts.map +1 -1
  139. package/dist/types/internal/errors.d.ts +5 -0
  140. package/dist/types/internal/errors.d.ts.map +1 -1
  141. package/dist/types/internal/metrics.d.ts +21 -0
  142. package/dist/types/internal/metrics.d.ts.map +1 -1
  143. package/dist/types/internal/options.d.ts +2 -0
  144. package/dist/types/internal/options.d.ts.map +1 -1
  145. package/dist/types/internal/types.d.ts +66 -58
  146. package/dist/types/internal/types.d.ts.map +1 -1
  147. package/dist/types/rpc/http.d.ts +17 -0
  148. package/dist/types/rpc/http.d.ts.map +1 -0
  149. package/dist/types/rpc/index.d.ts.map +1 -1
  150. package/dist/types/runtime/events.d.ts +4 -4
  151. package/dist/types/runtime/events.d.ts.map +1 -1
  152. package/dist/types/runtime/filter.d.ts +5 -1
  153. package/dist/types/runtime/filter.d.ts.map +1 -1
  154. package/dist/types/runtime/fragments.d.ts +4 -3
  155. package/dist/types/runtime/fragments.d.ts.map +1 -1
  156. package/dist/types/runtime/historical.d.ts +29 -13
  157. package/dist/types/runtime/historical.d.ts.map +1 -1
  158. package/dist/types/runtime/index.d.ts +49 -6
  159. package/dist/types/runtime/index.d.ts.map +1 -1
  160. package/dist/types/runtime/init.d.ts +5 -5
  161. package/dist/types/runtime/init.d.ts.map +1 -1
  162. package/dist/types/runtime/isolated.d.ts +14 -0
  163. package/dist/types/runtime/isolated.d.ts.map +1 -0
  164. package/dist/types/runtime/multichain.d.ts.map +1 -1
  165. package/dist/types/runtime/omnichain.d.ts.map +1 -1
  166. package/dist/types/runtime/realtime.d.ts +21 -10
  167. package/dist/types/runtime/realtime.d.ts.map +1 -1
  168. package/dist/types/sync-historical/index.d.ts +18 -8
  169. package/dist/types/sync-historical/index.d.ts.map +1 -1
  170. package/dist/types/sync-realtime/bloom.d.ts.map +1 -1
  171. package/dist/types/sync-realtime/index.d.ts +2 -2
  172. package/dist/types/sync-realtime/index.d.ts.map +1 -1
  173. package/dist/types/sync-store/index.d.ts +9 -9
  174. package/dist/types/sync-store/index.d.ts.map +1 -1
  175. package/dist/types/utils/abi.d.ts +3 -34
  176. package/dist/types/utils/abi.d.ts.map +1 -1
  177. package/dist/types/utils/chunk.d.ts +2 -0
  178. package/dist/types/utils/chunk.d.ts.map +1 -0
  179. package/dist/types/utils/promiseAllSettledWithThrow.d.ts +8 -0
  180. package/dist/types/utils/promiseAllSettledWithThrow.d.ts.map +1 -0
  181. package/dist/types/utils/sql-parse.d.ts +21 -0
  182. package/dist/types/utils/sql-parse.d.ts.map +1 -0
  183. package/package.json +2 -2
  184. package/src/bin/commands/createViews.ts +35 -15
  185. package/src/bin/commands/dev.ts +43 -21
  186. package/src/bin/commands/prune.ts +6 -0
  187. package/src/bin/commands/serve.ts +4 -1
  188. package/src/bin/commands/start.ts +20 -5
  189. package/src/bin/isolatedController.ts +300 -0
  190. package/src/bin/isolatedWorker.ts +192 -0
  191. package/src/build/config.ts +570 -632
  192. package/src/build/index.ts +14 -14
  193. package/src/build/pre.ts +1 -4
  194. package/src/build/schema.ts +49 -4
  195. package/src/client/index.ts +386 -48
  196. package/src/config/index.ts +3 -3
  197. package/src/database/actions.ts +469 -120
  198. package/src/database/index.ts +85 -58
  199. package/src/database/queryBuilder.ts +1 -0
  200. package/src/drizzle/index.ts +15 -7
  201. package/src/drizzle/onchain.ts +19 -0
  202. package/src/indexing/client.ts +38 -25
  203. package/src/indexing/index.ts +137 -230
  204. package/src/indexing/profile.ts +1 -1
  205. package/src/indexing-store/cache.ts +285 -414
  206. package/src/indexing-store/historical.ts +20 -10
  207. package/src/indexing-store/index.ts +16 -0
  208. package/src/indexing-store/profile.ts +3 -3
  209. package/src/indexing-store/realtime.ts +28 -0
  210. package/src/internal/errors.ts +26 -0
  211. package/src/internal/metrics.ts +341 -111
  212. package/src/internal/options.ts +4 -0
  213. package/src/internal/telemetry.ts +1 -1
  214. package/src/internal/types.ts +70 -87
  215. package/src/rpc/http.ts +164 -0
  216. package/src/rpc/index.ts +39 -7
  217. package/src/runtime/events.ts +195 -240
  218. package/src/runtime/filter.ts +85 -1
  219. package/src/runtime/fragments.ts +109 -113
  220. package/src/runtime/historical.ts +467 -189
  221. package/src/runtime/index.ts +337 -69
  222. package/src/runtime/init.ts +5 -5
  223. package/src/runtime/isolated.ts +768 -0
  224. package/src/runtime/multichain.ts +137 -102
  225. package/src/runtime/omnichain.ts +138 -106
  226. package/src/runtime/realtime.ts +322 -123
  227. package/src/sync-historical/index.ts +556 -692
  228. package/src/sync-realtime/bloom.ts +7 -3
  229. package/src/sync-realtime/index.ts +31 -46
  230. package/src/sync-store/index.ts +189 -95
  231. package/src/utils/abi.ts +33 -90
  232. package/src/utils/chunk.ts +7 -0
  233. package/src/utils/promiseAllSettledWithThrow.ts +27 -0
  234. package/src/{client/parse.ts → utils/sql-parse.ts} +100 -90
  235. package/dist/esm/client/parse.js.map +0 -1
  236. package/dist/types/client/parse.d.ts +0 -14
  237. package/dist/types/client/parse.d.ts.map +0 -1
@@ -31,6 +31,8 @@ export type Options = {
31
31
  databaseHeartbeatTimeout: number;
32
32
  databaseMaxQueryParameters: number;
33
33
 
34
+ maxThreads: number;
35
+
34
36
  factoryAddressCountThreshold: number;
35
37
 
36
38
  indexingCacheMaxBytes: number;
@@ -103,6 +105,8 @@ export const buildOptions = ({ cliOptions }: { cliOptions: CliOptions }) => {
103
105
  // Half of the max query parameters for PGlite
104
106
  databaseMaxQueryParameters: 16_000,
105
107
 
108
+ maxThreads: 4,
109
+
106
110
  factoryAddressCountThreshold: 1_000,
107
111
 
108
112
  rpcMaxConcurrency: 256,
@@ -295,7 +295,7 @@ export function buildPayload({
295
295
 
296
296
  return {
297
297
  database_kind: preBuild?.databaseConfig.kind,
298
- contract_count: indexingBuild?.sources.length ?? 0,
298
+ contract_count: 0,
299
299
  network_count: indexingBuild?.chains.length ?? 0,
300
300
  table_count,
301
301
  indexing_function_count,
@@ -9,7 +9,6 @@ import type {
9
9
  Transfer,
10
10
  } from "@/types/eth.js";
11
11
  import type { PartialExcept, Prettify } from "@/types/utils.js";
12
- import type { AbiEvents, AbiFunctions } from "@/utils/abi.js";
13
12
  import type { Trace as DebugTrace } from "@/utils/debug.js";
14
13
  import type { PGliteOptions } from "@/utils/pglite.js";
15
14
  import type { PGlite } from "@electric-sql/pglite";
@@ -17,6 +16,8 @@ import type { Hono } from "hono";
17
16
  import type { PoolConfig } from "pg";
18
17
  import type {
19
18
  Abi,
19
+ AbiEvent,
20
+ AbiFunction,
20
21
  Address,
21
22
  BlockTag,
22
23
  Hex,
@@ -40,18 +41,13 @@ export type DatabaseConfig =
40
41
  // Indexing
41
42
 
42
43
  /** Indexing functions as defined in `ponder.on()` */
43
- export type RawIndexingFunctions = {
44
+ export type IndexingFunctions = {
44
45
  /** Name of the event */
45
46
  name: string;
46
47
  /** Callback function */
47
48
  fn: (...args: any) => any;
48
49
  }[];
49
50
 
50
- /** Indexing functions for event callbacks */
51
- export type IndexingFunctions = {
52
- [eventName: string]: (...args: any) => any;
53
- };
54
-
55
51
  // Filters
56
52
 
57
53
  /** Filter definition based on the fundamental data model of the Ethereum blockchain. */
@@ -61,12 +57,6 @@ export type Filter =
61
57
  | TransferFilter
62
58
  | TransactionFilter
63
59
  | TraceFilter;
64
- export type FilterWithoutBlocks =
65
- | Omit<BlockFilter, "fromBlock" | "toBlock">
66
- | Omit<TransactionFilter, "fromBlock" | "toBlock">
67
- | Omit<TraceFilter, "fromBlock" | "toBlock">
68
- | Omit<LogFilter, "fromBlock" | "toBlock">
69
- | Omit<TransferFilter, "fromBlock" | "toBlock">;
70
60
 
71
61
  /** Filter that matches addresses. */
72
62
  export type Factory = LogFactory;
@@ -77,6 +67,7 @@ export type FilterAddress<
77
67
  export type BlockFilter = {
78
68
  type: "block";
79
69
  chainId: number;
70
+ sourceId: string;
80
71
  interval: number;
81
72
  offset: number;
82
73
  fromBlock: number | undefined;
@@ -91,6 +82,7 @@ export type TransactionFilter<
91
82
  > = {
92
83
  type: "transaction";
93
84
  chainId: number;
85
+ sourceId: string;
94
86
  fromAddress: FilterAddress<fromFactory>;
95
87
  toAddress: FilterAddress<toFactory>;
96
88
  includeReverted: boolean;
@@ -110,9 +102,10 @@ export type TraceFilter<
110
102
  > = {
111
103
  type: "trace";
112
104
  chainId: number;
105
+ sourceId: string;
113
106
  fromAddress: FilterAddress<fromFactory>;
114
107
  toAddress: FilterAddress<toFactory>;
115
- functionSelector: Hex | Hex[] | undefined;
108
+ functionSelector: Hex;
116
109
  callType: Trace["type"] | undefined;
117
110
  includeReverted: boolean;
118
111
  fromBlock: number | undefined;
@@ -131,8 +124,9 @@ export type LogFilter<
131
124
  > = {
132
125
  type: "log";
133
126
  chainId: number;
127
+ sourceId: string;
134
128
  address: FilterAddress<factory>;
135
- topic0: LogTopic;
129
+ topic0: Hex;
136
130
  topic1: LogTopic;
137
131
  topic2: LogTopic;
138
132
  topic3: LogTopic;
@@ -153,6 +147,7 @@ export type TransferFilter<
153
147
  > = {
154
148
  type: "transfer";
155
149
  chainId: number;
150
+ sourceId: string;
156
151
  fromAddress: FilterAddress<fromFactory>;
157
152
  toAddress: FilterAddress<toFactory>;
158
153
  includeReverted: boolean;
@@ -215,14 +210,14 @@ export type Fragment =
215
210
  chainId: number;
216
211
  fromAddress: FragmentAddress;
217
212
  toAddress: FragmentAddress;
218
- functionSelector: Hex | null;
213
+ functionSelector: Hex;
219
214
  includeTransactionReceipts: boolean;
220
215
  }
221
216
  | {
222
217
  type: "log";
223
218
  chainId: number;
224
219
  address: FragmentAddress;
225
- topic0: FragmentTopic;
220
+ topic0: Hex;
226
221
  topic1: FragmentTopic;
227
222
  topic2: FragmentTopic;
228
223
  topic3: FragmentTopic;
@@ -234,6 +229,13 @@ export type Fragment =
234
229
  fromAddress: FragmentAddress;
235
230
  toAddress: FragmentAddress;
236
231
  includeTransactionReceipts: boolean;
232
+ }
233
+ | {
234
+ type: "factory_log";
235
+ chainId: number;
236
+ address: Address;
237
+ eventSelector: Factory["eventSelector"];
238
+ childAddressLocation: Factory["childAddressLocation"];
237
239
  };
238
240
 
239
241
  /** Minimum slice of a {@link Filter} */
@@ -247,53 +249,40 @@ export type FragmentId =
247
249
  /** log_{chainId}_{address}_{topic0}_{topic1}_{topic2}_{topic3}_{includeReceipts} */
248
250
  | `log_${number}_${FragmentAddressId}_${FragmentTopic}_${FragmentTopic}_${FragmentTopic}_${FragmentTopic}_${0 | 1}`
249
251
  /** transfer_{chainId}_{fromAddress}_{toAddress}_{includeReceipts} */
250
- | `transfer_${number}_${FragmentAddressId}_${FragmentAddressId}_${0 | 1}`;
251
-
252
- // Sources
253
-
254
- /** Event source that matches {@link Event}s containing an underlying filter and metadata. */
255
- export type Source = ContractSource | AccountSource | BlockSource;
256
-
257
- export type ContractSource<
258
- filter extends "log" | "trace" = "log" | "trace",
259
- factory extends Factory | undefined = Factory | undefined,
260
- fromFactory extends Factory | undefined = Factory | undefined,
261
- toFactory extends Factory | undefined = Factory | undefined,
262
- > = {
263
- filter: filter extends "log"
264
- ? LogFilter<factory>
265
- : TraceFilter<fromFactory, toFactory>;
266
- } & ContractMetadata;
267
-
268
- export type AccountSource<
269
- filter extends "transaction" | "transfer" = "transaction" | "transfer",
270
- fromFactory extends Factory | undefined = Factory | undefined,
271
- toFactory extends Factory | undefined = Factory | undefined,
272
- > = {
273
- filter: filter extends "transaction"
274
- ? TransactionFilter<fromFactory, toFactory>
275
- : TransferFilter<fromFactory, toFactory>;
276
- } & AccountMetadata;
252
+ | `transfer_${number}_${FragmentAddressId}_${FragmentAddressId}_${0 | 1}`
253
+ /** factory_log_{chainId}_{address}_{eventSelector}_{childAddressLocation} */
254
+ | `factory_log_${number}_${Address}_${Factory["eventSelector"]}_${Factory["childAddressLocation"]}`;
277
255
 
278
- export type BlockSource = { filter: BlockFilter } & BlockMetadata;
279
-
280
- export type ContractMetadata = {
281
- type: "contract";
256
+ // Contract
257
+ export type Contract = {
282
258
  abi: Abi;
283
- abiEvents: AbiEvents;
284
- abiFunctions: AbiFunctions;
285
- name: string;
286
- chain: Chain;
259
+ address?: Address | readonly Address[];
260
+ startBlock?: number;
261
+ endBlock?: number;
287
262
  };
288
- export type AccountMetadata = {
289
- type: "account";
263
+
264
+ // Event Callback
265
+
266
+ export type EventCallback = {
267
+ filter: Filter;
290
268
  name: string;
269
+ fn: (...args: any) => any;
291
270
  chain: Chain;
292
- };
293
- export type BlockMetadata = {
294
- type: "block";
271
+ } & (
272
+ | {
273
+ type: "contract";
274
+ abiItem: AbiEvent | AbiFunction;
275
+ metadata: { safeName: string; abi: Abi };
276
+ }
277
+ | { type: "account"; direction: "from" | "to" }
278
+ | { type: "block" }
279
+ );
280
+
281
+ export type SetupCallback = {
295
282
  name: string;
283
+ fn: (...args: any) => any;
296
284
  chain: Chain;
285
+ block: number | undefined;
297
286
  };
298
287
 
299
288
  // Chain
@@ -327,7 +316,7 @@ export type PreBuild = {
327
316
  /** Database type and configuration */
328
317
  databaseConfig: DatabaseConfig;
329
318
  /** Ordering of events */
330
- ordering: "omnichain" | "multichain";
319
+ ordering: "omnichain" | "multichain" | "experimental_isolated";
331
320
  };
332
321
 
333
322
  export type SchemaBuild = {
@@ -339,16 +328,22 @@ export type SchemaBuild = {
339
328
  export type IndexingBuild = {
340
329
  /** Ten character hex string identifier. */
341
330
  buildId: string;
342
- /** Sources to index. */
343
- sources: Source[];
344
331
  /** Chains to index. */
345
332
  chains: Chain[];
346
333
  /** RPCs for all `chains`. */
347
334
  rpcs: Rpc[];
348
335
  /** Finalized blocks for all `chains`. */
349
336
  finalizedBlocks: LightBlock[];
350
- /** Event callbacks for all `sources`. */
337
+ /** Event callbacks for all `chains`. */
338
+ eventCallbacks: EventCallback[][];
339
+ /** Setup callbacks for all `chains`. */
340
+ setupCallbacks: SetupCallback[][];
341
+ /** Indexing functions registered with `ponder.on()`. */
351
342
  indexingFunctions: IndexingFunctions;
343
+ /** Contracts for all `chains`. */
344
+ contracts: {
345
+ [name: string]: Contract;
346
+ }[];
352
347
  };
353
348
 
354
349
  export type ApiBuild = {
@@ -489,9 +484,9 @@ export type UserLog = Log;
489
484
  // Events
490
485
 
491
486
  export type RawEvent = {
492
- chainId: number;
493
- sourceIndex: number;
494
487
  checkpoint: string;
488
+ chainId: number;
489
+ eventCallbackIndex: number;
495
490
  log?: UserLog;
496
491
  block: UserBlock;
497
492
  transaction?: UserTransaction;
@@ -508,22 +503,18 @@ export type Event =
508
503
 
509
504
  export type SetupEvent = {
510
505
  type: "setup";
511
- chainId: number;
512
506
  checkpoint: string;
513
-
514
- /** `${source.name}:setup` */
515
- name: string;
507
+ chain: Chain;
508
+ setupCallback: SetupCallback;
516
509
 
517
510
  block: bigint;
518
511
  };
519
512
 
520
513
  export type BlockEvent = {
521
514
  type: "block";
522
- chainId: number;
523
515
  checkpoint: string;
524
-
525
- /** `${source.name}:block` */
526
- name: string;
516
+ chain: Chain;
517
+ eventCallback: EventCallback;
527
518
 
528
519
  event: {
529
520
  id: string;
@@ -533,11 +524,9 @@ export type BlockEvent = {
533
524
 
534
525
  export type TransactionEvent = {
535
526
  type: "transaction";
536
- chainId: number;
537
527
  checkpoint: string;
538
-
539
- /** `${source.name}.{safeName}()` */
540
- name: string;
528
+ chain: Chain;
529
+ eventCallback: EventCallback;
541
530
 
542
531
  event: {
543
532
  id: string;
@@ -549,11 +538,9 @@ export type TransactionEvent = {
549
538
 
550
539
  export type TraceEvent = {
551
540
  type: "trace";
552
- chainId: number;
553
541
  checkpoint: string;
554
-
555
- /** `${source.name}:transfer:from` | `${source.name}:transfer:to` */
556
- name: string;
542
+ chain: Chain;
543
+ eventCallback: EventCallback;
557
544
 
558
545
  event: {
559
546
  id: string;
@@ -568,11 +555,9 @@ export type TraceEvent = {
568
555
 
569
556
  export type LogEvent = {
570
557
  type: "log";
571
- chainId: number;
572
558
  checkpoint: string;
573
-
574
- /** `${source.name}:${safeName}` */
575
- name: string;
559
+ chain: Chain;
560
+ eventCallback: EventCallback;
576
561
 
577
562
  event: {
578
563
  id: string;
@@ -586,11 +571,9 @@ export type LogEvent = {
586
571
 
587
572
  export type TransferEvent = {
588
573
  type: "transfer";
589
- chainId: number;
590
574
  checkpoint: string;
591
-
592
- /** `${source.name}:transfer:from` | `${source.name}:transfer:to` */
593
- name: string;
575
+ chain: Chain;
576
+ eventCallback: EventCallback;
594
577
 
595
578
  event: {
596
579
  id: string;
@@ -0,0 +1,164 @@
1
+ import { URL } from "node:url";
2
+ import type { Common } from "@/internal/common.js";
3
+ import type { Chain } from "@/internal/types.js";
4
+ import { HttpRequestError, RpcRequestError, TimeoutError } from "viem";
5
+ import {
6
+ type HttpRequestParameters,
7
+ type HttpRequestReturnType,
8
+ type HttpRpcClientOptions,
9
+ stringify,
10
+ } from "viem/utils";
11
+
12
+ export type RpcRequest = {
13
+ jsonrpc?: "2.0" | undefined;
14
+ method: string;
15
+ params?: any | undefined;
16
+ id?: number | undefined;
17
+ };
18
+
19
+ export type HttpRpcClient = {
20
+ request<body extends RpcRequest>(
21
+ params: HttpRequestParameters<body>,
22
+ ): Promise<HttpRequestReturnType<body>>;
23
+ };
24
+
25
+ export function getHttpRpcClient(
26
+ url: string,
27
+ options: HttpRpcClientOptions & { common: Common; chain: Chain },
28
+ ): HttpRpcClient {
29
+ const { common, chain } = options;
30
+ const timeoutMs = options?.timeout ?? 10_000;
31
+ let id = 1;
32
+ return {
33
+ async request(params) {
34
+ // biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation>
35
+ return new Promise(async (resolve, reject) => {
36
+ let isTimeoutRejected = false;
37
+ const { body } = params;
38
+
39
+ const fetchOptions = {
40
+ ...(params.fetchOptions ?? {}),
41
+ };
42
+
43
+ const { headers, method } = fetchOptions;
44
+
45
+ let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;
46
+ const controller = new AbortController();
47
+ const timeoutId = setTimeout(async () => {
48
+ isTimeoutRejected = true;
49
+ controller.abort();
50
+
51
+ reject(new TimeoutError({ body, url }));
52
+
53
+ if (reader) {
54
+ common.logger.warn({
55
+ msg: "JSON-RPC request timed out reading response body",
56
+ chain: chain.name,
57
+ chain_id: chain.id,
58
+ hostname: new URL(url).hostname,
59
+ // @ts-ignore
60
+ request_id: headers ? headers["X-Request-ID"] : undefined,
61
+ method: body.method,
62
+ request: JSON.stringify(body),
63
+ duration: timeoutMs,
64
+ });
65
+ try {
66
+ await reader.cancel("Timeout");
67
+ } catch {}
68
+ }
69
+ }, timeoutMs);
70
+
71
+ try {
72
+ const init: RequestInit = {
73
+ body: stringify({
74
+ jsonrpc: "2.0",
75
+ id: body.id ?? id++,
76
+ ...body,
77
+ }),
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ ...headers,
81
+ },
82
+ method: method || "POST",
83
+ signal: controller.signal,
84
+ };
85
+ const request = new Request(url, init);
86
+ const response = await fetch(request);
87
+
88
+ reader = response.body?.getReader()!;
89
+ const chunks: Uint8Array[] = [];
90
+ let totalLength = 0;
91
+
92
+ try {
93
+ while (true) {
94
+ const { done, value } = await reader.read();
95
+ if (done) break;
96
+ chunks.push(value);
97
+ totalLength += value.length;
98
+ }
99
+ } finally {
100
+ reader.releaseLock();
101
+ reader = undefined;
102
+ }
103
+
104
+ if (isTimeoutRejected) return;
105
+
106
+ let offset = 0;
107
+ const fullData = new Uint8Array(totalLength);
108
+ for (const chunk of chunks) {
109
+ fullData.set(chunk, offset);
110
+ offset += chunk.length;
111
+ }
112
+
113
+ const text = new TextDecoder().decode(fullData);
114
+
115
+ let data: any = text;
116
+ try {
117
+ data = JSON.parse(data || "{}");
118
+ } catch (err) {
119
+ if (response.ok) throw err;
120
+ data = { error: data };
121
+ }
122
+
123
+ clearTimeout(timeoutId);
124
+
125
+ if (!response.ok) {
126
+ reject(
127
+ new HttpRequestError({
128
+ body,
129
+ details: stringify(data.error) || response.statusText,
130
+ headers: response.headers,
131
+ status: response.status,
132
+ url,
133
+ }),
134
+ );
135
+ return;
136
+ }
137
+
138
+ if (data.error) {
139
+ reject(
140
+ new RpcRequestError({
141
+ body,
142
+ error: data.error,
143
+ url: url,
144
+ }),
145
+ );
146
+ } else {
147
+ resolve(data.result);
148
+ }
149
+ } catch (_error) {
150
+ const error = _error as Error;
151
+ clearTimeout(timeoutId);
152
+
153
+ if (isTimeoutRejected) return;
154
+
155
+ if (error.name === "AbortError") {
156
+ reject(new TimeoutError({ body, url }));
157
+ }
158
+ if (error instanceof HttpRequestError) reject(error);
159
+ reject(new HttpRequestError({ body, cause: error, url }));
160
+ }
161
+ });
162
+ },
163
+ };
164
+ }
package/src/rpc/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import crypto from "node:crypto";
1
+ import crypto, { type UUID } from "node:crypto";
2
2
  import url from "node:url";
3
3
  import type { Common } from "@/internal/common.js";
4
4
  import type { Logger } from "@/internal/logger.js";
@@ -16,7 +16,6 @@ import {
16
16
  getLogsRetryHelper,
17
17
  } from "@ponder/utils";
18
18
  import {
19
- http,
20
19
  BlockNotFoundError,
21
20
  type EIP1193Parameters,
22
21
  type EIP1193RequestFn,
@@ -30,12 +29,14 @@ import {
30
29
  type RpcError,
31
30
  type RpcTransactionReceipt,
32
31
  TimeoutError,
32
+ custom,
33
33
  hexToNumber,
34
34
  isHex,
35
35
  webSocket,
36
36
  } from "viem";
37
37
  import { WebSocket } from "ws";
38
38
  import type { DebugRpcSchema } from "../utils/debug.js";
39
+ import { getHttpRpcClient } from "./http.js";
39
40
 
40
41
  export type RpcSchema = [
41
42
  ...PublicRpcSchema,
@@ -176,16 +177,32 @@ export const createRpc = ({
176
177
  }: { common: Common; chain: Chain; concurrency?: number }): Rpc => {
177
178
  let backends: { request: EIP1193RequestFn<RpcSchema>; hostname: string }[];
178
179
 
180
+ let requestId: UUID | undefined;
181
+
179
182
  if (typeof chain.rpc === "string") {
180
183
  const protocol = new url.URL(chain.rpc).protocol;
181
184
  const hostname = new url.URL(chain.rpc).hostname;
182
185
  if (protocol === "https:" || protocol === "http:") {
186
+ const httpRpcClient = getHttpRpcClient(chain.rpc, {
187
+ common,
188
+ chain,
189
+ timeout: 10_000,
190
+ });
183
191
  backends = [
184
192
  {
185
- request: http(chain.rpc)({
193
+ request: custom({
194
+ request(body) {
195
+ if (requestId) {
196
+ return httpRpcClient.request({
197
+ body,
198
+ fetchOptions: { headers: { "X-Request-ID": requestId } },
199
+ });
200
+ }
201
+ return httpRpcClient.request({ body });
202
+ },
203
+ })({
186
204
  chain: chain.viemChain,
187
205
  retryCount: 0,
188
- timeout: 10_000,
189
206
  }).request,
190
207
  hostname,
191
208
  },
@@ -210,11 +227,25 @@ export const createRpc = ({
210
227
  const hostname = new url.URL(chain.rpc).hostname;
211
228
 
212
229
  if (protocol === "https:" || protocol === "http:") {
230
+ const httpRpcClient = getHttpRpcClient(rpc, {
231
+ common,
232
+ chain,
233
+ timeout: 10_000,
234
+ });
213
235
  return {
214
- request: http(rpc)({
236
+ request: custom({
237
+ request(body) {
238
+ if (requestId) {
239
+ return httpRpcClient.request({
240
+ body,
241
+ fetchOptions: { headers: { "X-Request-ID": requestId } },
242
+ });
243
+ }
244
+ return httpRpcClient.request({ body });
245
+ },
246
+ })({
215
247
  chain: chain.viemChain,
216
248
  retryCount: 0,
217
- timeout: 10_000,
218
249
  }).request,
219
250
  hostname,
220
251
  };
@@ -433,7 +464,7 @@ export const createRpc = ({
433
464
  clearTimeout(t);
434
465
  const getBucketDuration = endClock();
435
466
  endClock = startClock();
436
- const id = crypto.randomUUID().slice(0, 8);
467
+ const id = crypto.randomUUID();
437
468
 
438
469
  const surpassTimeout = setTimeout(() => {
439
470
  logger.warn({
@@ -469,6 +500,7 @@ export const createRpc = ({
469
500
  bucket.rps[bucket.rps.length - 1]!.count++;
470
501
  }
471
502
 
503
+ requestId = id;
472
504
  const response = await bucket.request(body);
473
505
 
474
506
  if (response === undefined) {