@hugomrdias/foxer 0.1.3 → 0.1.11

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 (343) hide show
  1. package/CHANGELOG.md +71 -17
  2. package/README.md +77 -10
  3. package/dist/{src/api/runner.d.ts → api/create-api.d.ts} +2 -2
  4. package/dist/api/create-api.d.ts.map +1 -0
  5. package/dist/{src/api/runner.js → api/create-api.js} +2 -2
  6. package/dist/api/create-api.js.map +1 -0
  7. package/dist/api/index.d.ts.map +1 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/server.d.ts.map +1 -0
  10. package/dist/api/server.js.map +1 -0
  11. package/dist/api/sql-middleware.d.ts.map +1 -0
  12. package/dist/{src/api → api}/sql-middleware.js +3 -3
  13. package/dist/api/sql-middleware.js.map +1 -0
  14. package/dist/api/sql.d.ts.map +1 -0
  15. package/dist/api/sql.js.map +1 -0
  16. package/dist/api/sse.d.ts.map +1 -0
  17. package/dist/api/sse.js.map +1 -0
  18. package/dist/bin/create.d.ts.map +1 -0
  19. package/dist/{src/bin → bin}/create.js +4 -4
  20. package/dist/bin/create.js.map +1 -0
  21. package/dist/bin/dev.d.ts.map +1 -0
  22. package/dist/{src/bin → bin}/dev.js +9 -11
  23. package/dist/bin/dev.js.map +1 -0
  24. package/dist/bin/flags.d.ts.map +1 -0
  25. package/dist/{src/bin → bin}/flags.js +1 -1
  26. package/dist/bin/flags.js.map +1 -0
  27. package/dist/{src/bin → bin}/index.d.ts.map +1 -1
  28. package/dist/{src/bin → bin}/index.js +4 -2
  29. package/dist/bin/index.js.map +1 -0
  30. package/dist/bin/serve.d.ts +3 -0
  31. package/dist/bin/serve.d.ts.map +1 -0
  32. package/dist/bin/serve.js +53 -0
  33. package/dist/bin/serve.js.map +1 -0
  34. package/dist/bin/start.d.ts +3 -0
  35. package/dist/bin/start.d.ts.map +1 -0
  36. package/dist/bin/start.js +72 -0
  37. package/dist/bin/start.js.map +1 -0
  38. package/dist/bin/utils.d.ts.map +1 -0
  39. package/dist/bin/utils.js +39 -0
  40. package/dist/bin/utils.js.map +1 -0
  41. package/dist/config/config.d.ts.map +1 -0
  42. package/dist/config/config.js.map +1 -0
  43. package/dist/{src/config → config}/env.d.ts +1 -1
  44. package/dist/config/env.d.ts.map +1 -0
  45. package/dist/{src/config → config}/env.js +4 -3
  46. package/dist/config/env.js.map +1 -0
  47. package/dist/contants.d.ts.map +1 -0
  48. package/dist/contants.js.map +1 -0
  49. package/dist/{src/db → db}/actions/blocks.d.ts +9 -6
  50. package/dist/db/actions/blocks.d.ts.map +1 -0
  51. package/dist/{src/db → db}/actions/blocks.js +40 -44
  52. package/dist/db/actions/blocks.js.map +1 -0
  53. package/dist/db/actions/index.d.ts.map +1 -0
  54. package/dist/db/actions/index.js.map +1 -0
  55. package/dist/db/actions/transactions.d.ts.map +1 -0
  56. package/dist/db/actions/transactions.js.map +1 -0
  57. package/dist/{src/db → db}/client.d.ts +3 -3
  58. package/dist/db/client.d.ts.map +1 -0
  59. package/dist/{src/db → db}/client.js +9 -3
  60. package/dist/db/client.js.map +1 -0
  61. package/dist/{src/db → db}/column-types.d.ts +2 -2
  62. package/dist/db/column-types.d.ts.map +1 -0
  63. package/dist/{src/db → db}/column-types.js +11 -3
  64. package/dist/db/column-types.js.map +1 -0
  65. package/dist/db/encode.d.ts.map +1 -0
  66. package/dist/db/encode.js.map +1 -0
  67. package/dist/db/migrate.d.ts.map +1 -0
  68. package/dist/db/migrate.js.map +1 -0
  69. package/dist/{src/db → db}/schema/blocks.d.ts +16 -16
  70. package/dist/{src/db → db}/schema/blocks.d.ts.map +1 -1
  71. package/dist/db/schema/blocks.js.map +1 -0
  72. package/dist/{src/db → db}/schema/index.d.ts +44 -44
  73. package/dist/{src/db → db}/schema/index.d.ts.map +1 -1
  74. package/dist/db/schema/index.js.map +1 -0
  75. package/dist/{src/db → db}/schema/transactions.d.ts +6 -6
  76. package/dist/{src/db → db}/schema/transactions.d.ts.map +1 -1
  77. package/dist/{src/db → db}/schema/transactions.js +3 -1
  78. package/dist/db/schema/transactions.js.map +1 -0
  79. package/dist/db/transaction.d.ts.map +1 -0
  80. package/dist/db/transaction.js.map +1 -0
  81. package/dist/{src/hooks → hooks}/registry.d.ts +7 -3
  82. package/dist/hooks/registry.d.ts.map +1 -0
  83. package/dist/{src/hooks → hooks}/registry.js +5 -0
  84. package/dist/hooks/registry.js.map +1 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/indexer/backfill.d.ts.map +1 -0
  88. package/dist/{src/indexer → indexer}/backfill.js +22 -19
  89. package/dist/indexer/backfill.js.map +1 -0
  90. package/dist/{src/indexer/runner.d.ts → indexer/create-indexer.d.ts} +2 -2
  91. package/dist/indexer/create-indexer.d.ts.map +1 -0
  92. package/dist/{src/indexer/runner.js → indexer/create-indexer.js} +2 -2
  93. package/dist/indexer/create-indexer.js.map +1 -0
  94. package/dist/indexer/live.d.ts.map +1 -0
  95. package/dist/{src/indexer → indexer}/live.js +3 -3
  96. package/dist/indexer/live.js.map +1 -0
  97. package/dist/{src/indexer → indexer}/process-block.d.ts +4 -4
  98. package/dist/indexer/process-block.d.ts.map +1 -0
  99. package/dist/{src/indexer → indexer}/process-block.js +6 -31
  100. package/dist/indexer/process-block.js.map +1 -0
  101. package/dist/indexer/queue-block.d.ts.map +1 -0
  102. package/dist/{src/indexer → indexer}/queue-block.js +19 -1
  103. package/dist/indexer/queue-block.js.map +1 -0
  104. package/dist/{src/indexer → indexer}/reorg.d.ts +2 -2
  105. package/dist/indexer/reorg.d.ts.map +1 -0
  106. package/dist/indexer/reorg.js.map +1 -0
  107. package/dist/rpc/client.d.ts.map +1 -0
  108. package/dist/rpc/client.js.map +1 -0
  109. package/dist/rpc/get-block.d.ts.map +1 -0
  110. package/dist/rpc/get-block.js.map +1 -0
  111. package/dist/rpc/get-logs.d.ts.map +1 -0
  112. package/dist/{src/rpc → rpc}/get-logs.js +2 -2
  113. package/dist/rpc/get-logs.js.map +1 -0
  114. package/dist/schema.d.ts.map +1 -0
  115. package/dist/schema.js.map +1 -0
  116. package/dist/{src/types.d.ts → types.d.ts} +2 -0
  117. package/dist/types.d.ts.map +1 -0
  118. package/dist/types.js.map +1 -0
  119. package/dist/utils/bloom.d.ts.map +1 -0
  120. package/dist/utils/bloom.js.map +1 -0
  121. package/dist/utils/build-conflict-columns.d.ts.map +1 -0
  122. package/dist/utils/build-conflict-columns.js.map +1 -0
  123. package/dist/utils/common.d.ts.map +1 -0
  124. package/dist/utils/common.js.map +1 -0
  125. package/dist/utils/cursor.d.ts.map +1 -0
  126. package/dist/utils/cursor.js.map +1 -0
  127. package/dist/utils/format.d.ts.map +1 -0
  128. package/dist/utils/format.js.map +1 -0
  129. package/dist/utils/hash.d.ts.map +1 -0
  130. package/dist/utils/hash.js.map +1 -0
  131. package/dist/utils/json.d.ts.map +1 -0
  132. package/dist/utils/json.js.map +1 -0
  133. package/dist/utils/logger.d.ts.map +1 -0
  134. package/dist/{src/utils → utils}/logger.js +0 -3
  135. package/dist/utils/logger.js.map +1 -0
  136. package/dist/utils/shutdown.d.ts.map +1 -0
  137. package/dist/{src/utils → utils}/shutdown.js +3 -2
  138. package/dist/utils/shutdown.js.map +1 -0
  139. package/dist/utils/timer.d.ts.map +1 -0
  140. package/dist/utils/timer.js.map +1 -0
  141. package/dist/utils/types.d.ts.map +1 -0
  142. package/dist/{src → utils}/types.js.map +1 -1
  143. package/package.json +45 -41
  144. package/src/api/{runner.ts → create-api.ts} +2 -1
  145. package/src/api/server.ts +1 -0
  146. package/src/api/sql-middleware.ts +4 -3
  147. package/src/api/sql.ts +2 -1
  148. package/src/bin/create.ts +7 -8
  149. package/src/bin/dev.ts +11 -13
  150. package/src/bin/flags.ts +1 -1
  151. package/src/bin/index.ts +6 -2
  152. package/src/bin/serve.ts +65 -0
  153. package/src/bin/start.ts +87 -0
  154. package/src/bin/utils.ts +22 -25
  155. package/src/config/config.ts +1 -0
  156. package/src/config/env.ts +5 -3
  157. package/src/db/actions/blocks.ts +53 -52
  158. package/src/db/actions/transactions.ts +1 -0
  159. package/src/db/client.ts +12 -5
  160. package/src/db/column-types.ts +17 -6
  161. package/src/db/encode.ts +1 -0
  162. package/src/db/migrate.ts +1 -0
  163. package/src/db/schema/blocks.ts +1 -0
  164. package/src/db/schema/transactions.ts +4 -1
  165. package/src/hooks/registry.ts +15 -3
  166. package/src/indexer/backfill.ts +31 -20
  167. package/src/indexer/{runner.ts → create-indexer.ts} +1 -1
  168. package/src/indexer/live.ts +4 -3
  169. package/src/indexer/process-block.ts +13 -41
  170. package/src/indexer/queue-block.ts +25 -1
  171. package/src/indexer/reorg.ts +3 -2
  172. package/src/rpc/client.ts +1 -0
  173. package/src/rpc/get-block.ts +1 -0
  174. package/src/rpc/get-logs.ts +3 -2
  175. package/src/types.ts +3 -0
  176. package/src/utils/logger.ts +1 -3
  177. package/src/utils/shutdown.ts +3 -2
  178. package/src/utils/types.ts +1 -0
  179. package/template/{package.json → package.json.tpl} +10 -8
  180. package/template/{pnpm-workspace.yaml → pnpm-workspace.yaml.tpl} +1 -1
  181. package/template/{tsconfig.json → tsconfig.json.tpl} +1 -2
  182. package/template/turbo.json.tpl +22 -0
  183. package/tsconfig.json +3 -1
  184. package/dist/src/api/index.d.ts.map +0 -1
  185. package/dist/src/api/index.js.map +0 -1
  186. package/dist/src/api/runner.d.ts.map +0 -1
  187. package/dist/src/api/runner.js.map +0 -1
  188. package/dist/src/api/server.d.ts.map +0 -1
  189. package/dist/src/api/server.js.map +0 -1
  190. package/dist/src/api/sql-middleware.d.ts.map +0 -1
  191. package/dist/src/api/sql-middleware.js.map +0 -1
  192. package/dist/src/api/sql.d.ts.map +0 -1
  193. package/dist/src/api/sql.js.map +0 -1
  194. package/dist/src/api/sse.d.ts.map +0 -1
  195. package/dist/src/api/sse.js.map +0 -1
  196. package/dist/src/bin/create.d.ts.map +0 -1
  197. package/dist/src/bin/create.js.map +0 -1
  198. package/dist/src/bin/dev.d.ts.map +0 -1
  199. package/dist/src/bin/dev.js.map +0 -1
  200. package/dist/src/bin/flags.d.ts.map +0 -1
  201. package/dist/src/bin/flags.js.map +0 -1
  202. package/dist/src/bin/index.js.map +0 -1
  203. package/dist/src/bin/utils.d.ts.map +0 -1
  204. package/dist/src/bin/utils.js +0 -52
  205. package/dist/src/bin/utils.js.map +0 -1
  206. package/dist/src/config/config.d.ts.map +0 -1
  207. package/dist/src/config/config.js.map +0 -1
  208. package/dist/src/config/env.d.ts.map +0 -1
  209. package/dist/src/config/env.js.map +0 -1
  210. package/dist/src/contants.d.ts.map +0 -1
  211. package/dist/src/contants.js.map +0 -1
  212. package/dist/src/db/actions/blocks.d.ts.map +0 -1
  213. package/dist/src/db/actions/blocks.js.map +0 -1
  214. package/dist/src/db/actions/index.d.ts.map +0 -1
  215. package/dist/src/db/actions/index.js.map +0 -1
  216. package/dist/src/db/actions/transactions.d.ts.map +0 -1
  217. package/dist/src/db/actions/transactions.js.map +0 -1
  218. package/dist/src/db/client.d.ts.map +0 -1
  219. package/dist/src/db/client.js.map +0 -1
  220. package/dist/src/db/column-types.d.ts.map +0 -1
  221. package/dist/src/db/column-types.js.map +0 -1
  222. package/dist/src/db/encode.d.ts.map +0 -1
  223. package/dist/src/db/encode.js.map +0 -1
  224. package/dist/src/db/migrate.d.ts.map +0 -1
  225. package/dist/src/db/migrate.js.map +0 -1
  226. package/dist/src/db/schema/blocks.js.map +0 -1
  227. package/dist/src/db/schema/index.js.map +0 -1
  228. package/dist/src/db/schema/transactions.js.map +0 -1
  229. package/dist/src/db/transaction.d.ts.map +0 -1
  230. package/dist/src/db/transaction.js.map +0 -1
  231. package/dist/src/hooks/registry.d.ts.map +0 -1
  232. package/dist/src/hooks/registry.js.map +0 -1
  233. package/dist/src/index.d.ts.map +0 -1
  234. package/dist/src/index.js.map +0 -1
  235. package/dist/src/indexer/backfill.d.ts.map +0 -1
  236. package/dist/src/indexer/backfill.js.map +0 -1
  237. package/dist/src/indexer/live.d.ts.map +0 -1
  238. package/dist/src/indexer/live.js.map +0 -1
  239. package/dist/src/indexer/process-block.d.ts.map +0 -1
  240. package/dist/src/indexer/process-block.js.map +0 -1
  241. package/dist/src/indexer/queue-block.d.ts.map +0 -1
  242. package/dist/src/indexer/queue-block.js.map +0 -1
  243. package/dist/src/indexer/reorg.d.ts.map +0 -1
  244. package/dist/src/indexer/reorg.js.map +0 -1
  245. package/dist/src/indexer/runner.d.ts.map +0 -1
  246. package/dist/src/indexer/runner.js.map +0 -1
  247. package/dist/src/rpc/client.d.ts.map +0 -1
  248. package/dist/src/rpc/client.js.map +0 -1
  249. package/dist/src/rpc/get-block.d.ts.map +0 -1
  250. package/dist/src/rpc/get-block.js.map +0 -1
  251. package/dist/src/rpc/get-logs.d.ts.map +0 -1
  252. package/dist/src/rpc/get-logs.js.map +0 -1
  253. package/dist/src/schema.d.ts.map +0 -1
  254. package/dist/src/schema.js.map +0 -1
  255. package/dist/src/types.d.ts.map +0 -1
  256. package/dist/src/utils/bloom.d.ts.map +0 -1
  257. package/dist/src/utils/bloom.js.map +0 -1
  258. package/dist/src/utils/build-conflict-columns.d.ts.map +0 -1
  259. package/dist/src/utils/build-conflict-columns.js.map +0 -1
  260. package/dist/src/utils/common.d.ts.map +0 -1
  261. package/dist/src/utils/common.js.map +0 -1
  262. package/dist/src/utils/cursor.d.ts.map +0 -1
  263. package/dist/src/utils/cursor.js.map +0 -1
  264. package/dist/src/utils/format.d.ts.map +0 -1
  265. package/dist/src/utils/format.js.map +0 -1
  266. package/dist/src/utils/hash.d.ts.map +0 -1
  267. package/dist/src/utils/hash.js.map +0 -1
  268. package/dist/src/utils/json.d.ts.map +0 -1
  269. package/dist/src/utils/json.js.map +0 -1
  270. package/dist/src/utils/logger.d.ts.map +0 -1
  271. package/dist/src/utils/logger.js.map +0 -1
  272. package/dist/src/utils/shutdown.d.ts.map +0 -1
  273. package/dist/src/utils/shutdown.js.map +0 -1
  274. package/dist/src/utils/timer.d.ts.map +0 -1
  275. package/dist/src/utils/timer.js.map +0 -1
  276. package/dist/src/utils/types.d.ts.map +0 -1
  277. package/dist/src/utils/types.js.map +0 -1
  278. package/dist/tsconfig.tsbuildinfo +0 -1
  279. package/template/biome.template.json +0 -50
  280. /package/dist/{src/api → api}/index.d.ts +0 -0
  281. /package/dist/{src/api → api}/index.js +0 -0
  282. /package/dist/{src/api → api}/server.d.ts +0 -0
  283. /package/dist/{src/api → api}/server.js +0 -0
  284. /package/dist/{src/api → api}/sql-middleware.d.ts +0 -0
  285. /package/dist/{src/api → api}/sql.d.ts +0 -0
  286. /package/dist/{src/api → api}/sql.js +0 -0
  287. /package/dist/{src/api → api}/sse.d.ts +0 -0
  288. /package/dist/{src/api → api}/sse.js +0 -0
  289. /package/dist/{src/bin → bin}/create.d.ts +0 -0
  290. /package/dist/{src/bin → bin}/dev.d.ts +0 -0
  291. /package/dist/{src/bin → bin}/flags.d.ts +0 -0
  292. /package/dist/{src/bin → bin}/index.d.ts +0 -0
  293. /package/dist/{src/bin → bin}/utils.d.ts +0 -0
  294. /package/dist/{src/config → config}/config.d.ts +0 -0
  295. /package/dist/{src/config → config}/config.js +0 -0
  296. /package/dist/{src/contants.d.ts → contants.d.ts} +0 -0
  297. /package/dist/{src/contants.js → contants.js} +0 -0
  298. /package/dist/{src/db → db}/actions/index.d.ts +0 -0
  299. /package/dist/{src/db → db}/actions/index.js +0 -0
  300. /package/dist/{src/db → db}/actions/transactions.d.ts +0 -0
  301. /package/dist/{src/db → db}/actions/transactions.js +0 -0
  302. /package/dist/{src/db → db}/encode.d.ts +0 -0
  303. /package/dist/{src/db → db}/encode.js +0 -0
  304. /package/dist/{src/db → db}/migrate.d.ts +0 -0
  305. /package/dist/{src/db → db}/migrate.js +0 -0
  306. /package/dist/{src/db → db}/schema/blocks.js +0 -0
  307. /package/dist/{src/db → db}/schema/index.js +0 -0
  308. /package/dist/{src/db → db}/transaction.d.ts +0 -0
  309. /package/dist/{src/db → db}/transaction.js +0 -0
  310. /package/dist/{src/index.d.ts → index.d.ts} +0 -0
  311. /package/dist/{src/index.js → index.js} +0 -0
  312. /package/dist/{src/indexer → indexer}/backfill.d.ts +0 -0
  313. /package/dist/{src/indexer → indexer}/live.d.ts +0 -0
  314. /package/dist/{src/indexer → indexer}/queue-block.d.ts +0 -0
  315. /package/dist/{src/indexer → indexer}/reorg.js +0 -0
  316. /package/dist/{src/rpc → rpc}/client.d.ts +0 -0
  317. /package/dist/{src/rpc → rpc}/client.js +0 -0
  318. /package/dist/{src/rpc → rpc}/get-block.d.ts +0 -0
  319. /package/dist/{src/rpc → rpc}/get-block.js +0 -0
  320. /package/dist/{src/rpc → rpc}/get-logs.d.ts +0 -0
  321. /package/dist/{src/schema.d.ts → schema.d.ts} +0 -0
  322. /package/dist/{src/schema.js → schema.js} +0 -0
  323. /package/dist/{src/types.js → types.js} +0 -0
  324. /package/dist/{src/utils → utils}/bloom.d.ts +0 -0
  325. /package/dist/{src/utils → utils}/bloom.js +0 -0
  326. /package/dist/{src/utils → utils}/build-conflict-columns.d.ts +0 -0
  327. /package/dist/{src/utils → utils}/build-conflict-columns.js +0 -0
  328. /package/dist/{src/utils → utils}/common.d.ts +0 -0
  329. /package/dist/{src/utils → utils}/common.js +0 -0
  330. /package/dist/{src/utils → utils}/cursor.d.ts +0 -0
  331. /package/dist/{src/utils → utils}/cursor.js +0 -0
  332. /package/dist/{src/utils → utils}/format.d.ts +0 -0
  333. /package/dist/{src/utils → utils}/format.js +0 -0
  334. /package/dist/{src/utils → utils}/hash.d.ts +0 -0
  335. /package/dist/{src/utils → utils}/hash.js +0 -0
  336. /package/dist/{src/utils → utils}/json.d.ts +0 -0
  337. /package/dist/{src/utils → utils}/json.js +0 -0
  338. /package/dist/{src/utils → utils}/logger.d.ts +0 -0
  339. /package/dist/{src/utils → utils}/shutdown.d.ts +0 -0
  340. /package/dist/{src/utils → utils}/timer.d.ts +0 -0
  341. /package/dist/{src/utils → utils}/timer.js +0 -0
  342. /package/dist/{src/utils → utils}/types.d.ts +0 -0
  343. /package/dist/{src/utils → utils}/types.js +0 -0
@@ -1,6 +1,6 @@
1
1
  /** biome-ignore-all lint/style/noNonNullAssertion: its ok */
2
2
 
3
- import { gte } from 'drizzle-orm'
3
+ import { and, gte, inArray } from 'drizzle-orm'
4
4
  import {
5
5
  getTableConfig,
6
6
  type PgAsyncTransaction,
@@ -8,13 +8,15 @@ import {
8
8
  type PgQueryResultHKT,
9
9
  type PgTable,
10
10
  } from 'drizzle-orm/pg-core'
11
- import type { PublicClient } from 'viem'
12
- import type { FilteredContracts } from '../../config/config.ts'
11
+ import type { Hash, PublicClient } from 'viem'
12
+
13
13
  import { MAX_QUERY_PARAMS } from '../../contants.ts'
14
14
  import { safeGetBlock } from '../../rpc/get-block.ts'
15
15
  import type {
16
- EncodedBlockWithTransactions,
16
+ BlocksMap,
17
+ EncodedBlock,
17
18
  EncodedTransaction,
19
+ TransactionsMap,
18
20
  } from '../../types.ts'
19
21
  import type { Logger } from '../../utils/logger.ts'
20
22
  import { startClock } from '../../utils/timer.ts'
@@ -72,19 +74,20 @@ function getTablesWithBlockNumberColumn(fullSchema: Record<string, unknown>) {
72
74
  */
73
75
  export async function cacheBlockAndTransactions(args: {
74
76
  db: Database<typeof schema, typeof relations>
75
- block: EncodedBlockWithTransactions
77
+ blocks: EncodedBlock[]
78
+ transactions: EncodedTransaction[]
76
79
  logger: Logger
77
80
  }): Promise<void> {
78
- const { db, block } = args
81
+ const { db, blocks, transactions } = args
79
82
 
80
83
  await db.transaction(async (tx) => {
81
84
  await insertBlocksInChunks({
82
85
  db: tx,
83
- blocks: [block],
86
+ blocks,
84
87
  })
85
88
  await insertTransactionsInChunks({
86
89
  db: tx,
87
- transactions: block.transactions,
90
+ transactions,
88
91
  })
89
92
  })
90
93
  }
@@ -104,8 +107,8 @@ export async function getBlocksInRange(
104
107
  db: Database<typeof schema, typeof relations>,
105
108
  blockNumbers: bigint[],
106
109
  client: PublicClient,
107
- contracts: FilteredContracts
108
- ): Promise<Map<bigint, EncodedBlockWithTransactions>> {
110
+ logsTxs: Hash[]
111
+ ): Promise<{ blocks: BlocksMap; transactions: TransactionsMap }> {
109
112
  const endClock = startClock()
110
113
  const firstBlockNumber = blockNumbers[0]!
111
114
  const lastBlockNumber = blockNumbers[blockNumbers.length - 1]!
@@ -116,74 +119,72 @@ export async function getBlocksInRange(
116
119
  // contractAddresses: contracts.addresses,
117
120
  // })
118
121
 
119
- const r = await db.query.blocks.findMany({
120
- with: {
121
- transactions: {
122
- where: {
123
- AND: [
124
- { blockNumber: { gte: firstBlockNumber } },
125
- { blockNumber: { lte: lastBlockNumber } },
126
- {
127
- to: {
128
- in: contracts.addresses,
129
- },
130
- },
131
- ],
132
- },
122
+ const [blocks, txs] = await Promise.all([
123
+ db.query.blocks.findMany({
124
+ where: {
125
+ AND: [
126
+ { number: { gte: firstBlockNumber } },
127
+ { number: { lte: lastBlockNumber } },
128
+ ],
133
129
  },
134
- },
135
- where: {
136
- AND: [
137
- { number: { gte: firstBlockNumber } },
138
- { number: { lte: lastBlockNumber } },
139
- ],
140
- },
141
- })
130
+ }),
131
+ db
132
+ .select()
133
+ .from(schema.transactions)
134
+ .where(and(inArray(schema.transactions.hash, logsTxs))),
135
+ ])
136
+
137
+ const transactionByHash = new Map<`0x${string}`, EncodedTransaction>()
138
+ for (const tx of txs) {
139
+ transactionByHash.set(tx.hash, tx)
140
+ }
142
141
 
143
- const blocksByNumber = new Map<bigint, EncodedBlockWithTransactions>()
142
+ const blocksByNumber = new Map<bigint, EncodedBlock>()
144
143
  const missing = new Set(blockNumbers)
145
144
 
146
- for (const block of r) {
145
+ for (const block of blocks) {
147
146
  blocksByNumber.set(block.number, block)
148
147
  missing.delete(block.number)
149
148
  }
150
149
 
151
150
  const missingBlockNumbers = [...missing]
152
- const newBlocks: EncodedBlockWithTransactions[] = []
151
+ const newBlocks: EncodedBlock[] = []
153
152
  const newTransactions: EncodedTransaction[] = []
154
153
 
155
154
  await Promise.all(
156
155
  missingBlockNumbers.map(async (blockNumber) => {
157
156
  const block = await safeGetBlock({ client, blockNumber, db })
158
- const transactions = block.transactions
159
157
  blocksByNumber.set(blockNumber, block)
160
- newBlocks.push(block)
158
+ const { transactions, ..._block } = block
159
+ newBlocks.push(_block)
160
+
161
161
  if (transactions.length > 0) {
162
162
  newTransactions.push(...transactions)
163
163
  }
164
+ for (const tx of transactions) {
165
+ transactionByHash.set(tx.hash, tx)
166
+ }
164
167
  })
165
168
  )
166
169
 
167
- await db.transaction(async (tx) => {
168
- await insertBlocksInChunks({
169
- db: tx,
170
- blocks: newBlocks,
171
- })
172
- await insertTransactionsInChunks({
173
- db: tx,
174
- transactions: newTransactions,
175
- })
170
+ await cacheBlockAndTransactions({
171
+ db,
172
+ blocks: newBlocks,
173
+ transactions: newTransactions,
174
+ logger,
176
175
  })
177
176
 
178
- logger.info(
177
+ logger.trace(
179
178
  {
180
- blocks: blocksByNumber.size,
181
- missing: missingBlockNumbers.length,
179
+ blocks: blocks.length,
180
+ txs: txs.length,
181
+ newBlocks: newBlocks.length,
182
+ newTxs: newTransactions.length,
182
183
  duration: endClock(),
183
184
  },
184
- 'get blocks'
185
+ 'get blocks and txs'
185
186
  )
186
- return blocksByNumber
187
+ return { blocks: blocksByNumber, transactions: transactionByHash }
187
188
  }
188
189
 
189
190
  /**
@@ -191,7 +192,7 @@ export async function getBlocksInRange(
191
192
  */
192
193
  export async function insertBlocksInChunks(args: {
193
194
  db: PgAsyncTransaction<PgQueryResultHKT, typeof schema>
194
- blocks: EncodedBlockWithTransactions[]
195
+ blocks: EncodedBlock[]
195
196
  }): Promise<void> {
196
197
  const { db, blocks } = args
197
198
  if (blocks.length === 0) return
@@ -1,4 +1,5 @@
1
1
  import type { PgAsyncTransaction, PgQueryResultHKT } from 'drizzle-orm/pg-core'
2
+
2
3
  import { MAX_QUERY_PARAMS } from '../../contants.ts'
3
4
  import type { EncodedTransaction } from '../../types.ts'
4
5
  import { schema } from '../schema/index.ts'
package/src/db/client.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  } from 'drizzle-orm/pglite'
11
11
  import type { AnyRelations, EmptyRelations } from 'drizzle-orm/relations'
12
12
  import { Pool, type PoolConfig } from 'pg'
13
+
13
14
  import type { DatabaseConfig } from '../config/config.ts'
14
15
  import type { Env } from '../config/env.ts'
15
16
  import { type relations, schema } from './schema/index.ts'
@@ -39,7 +40,7 @@ export type DatabaseContext<
39
40
  $prepared: ReturnType<typeof generatePrepared>
40
41
  }
41
42
  driver: 'postgres'
42
- close: () => Promise<void>
43
+ stop: () => Promise<void>
43
44
  }
44
45
  | {
45
46
  db: PgliteDatabase<TSchema, TRelations> & {
@@ -47,7 +48,7 @@ export type DatabaseContext<
47
48
  $prepared: ReturnType<typeof generatePrepared>
48
49
  }
49
50
  driver: 'pglite'
50
- close: () => Promise<void>
51
+ stop: () => Promise<void>
51
52
  }
52
53
 
53
54
  /**
@@ -80,10 +81,15 @@ export function createDatabase<
80
81
  options = config.options
81
82
  }
82
83
 
84
+ // Postgres
83
85
  if (driver === 'postgres' && url) {
84
86
  const pool = new Pool({
85
- ...options,
87
+ application_name: 'foxer',
88
+ connectionTimeoutMillis: 5_000,
89
+ idleTimeoutMillis: 30_000,
90
+ max: 10,
86
91
  connectionString: url,
92
+ ...options,
87
93
  })
88
94
  const db = drizzleNodePostgres({
89
95
  client: pool,
@@ -101,12 +107,13 @@ export function createDatabase<
101
107
  return {
102
108
  db,
103
109
  driver: 'postgres',
104
- close: async () => {
110
+ stop: async () => {
105
111
  await pool.end()
106
112
  },
107
113
  }
108
114
  }
109
115
 
116
+ // PGlite
110
117
  const client = new PGlite(
111
118
  config?.driver === 'pglite' && config.directory
112
119
  ? config.directory
@@ -128,7 +135,7 @@ export function createDatabase<
128
135
  return {
129
136
  db,
130
137
  driver: 'pglite',
131
- close: async () => {
138
+ stop: async () => {
132
139
  await client.close()
133
140
  },
134
141
  }
@@ -1,4 +1,5 @@
1
1
  import { customType } from 'drizzle-orm/pg-core'
2
+ import { hex as hexCodec } from 'iso-base/rfc4648'
2
3
  import { type Address, type Hash, type Hex, stringify } from 'viem'
3
4
 
4
5
  export const numeric78 = customType<{ data: bigint; driverData: string }>({
@@ -90,16 +91,26 @@ export const jsonb = customType<{ data: unknown; driverData: string }>({
90
91
  },
91
92
  })
92
93
 
93
- export const bytea = customType<{ data: Hex; driverData: Buffer }>({
94
+ export const bytea = customType<{ data: Hex; driverData: Uint8Array }>({
94
95
  dataType() {
95
96
  return 'bytea'
96
97
  },
97
- toDriver(value: string): Buffer {
98
+ toDriver(value: string): Uint8Array {
98
99
  return Buffer.from(value.slice(2), 'hex')
99
100
  },
100
- fromDriver(value: Buffer): Hex {
101
- const hex = value.toString('hex')
102
- const _value = hex.startsWith('\\x') ? hex.slice(2) : hex
103
- return `0x${_value}` as Hex
101
+ fromDriver(value: unknown): Hex {
102
+ if (typeof value === 'string') {
103
+ return `0x${value.slice(2)}` as Hex
104
+ }
105
+
106
+ if (value instanceof Buffer) {
107
+ return `0x${value.toString('hex')}` as Hex
108
+ }
109
+
110
+ if (value instanceof Uint8Array) {
111
+ return `0x${hexCodec.encode(value)}` as Hex
112
+ }
113
+
114
+ throw new Error('Invalid value')
104
115
  },
105
116
  })
package/src/db/encode.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Hash } from 'viem'
2
+
2
3
  import type {
3
4
  ChainBlock,
4
5
  ChainTransaction,
package/src/db/migrate.ts CHANGED
@@ -2,6 +2,7 @@ import { migrate as migratePostgresJs } from 'drizzle-orm/node-postgres/migrator
2
2
  import { getTableConfig, type PgTable } from 'drizzle-orm/pg-core'
3
3
  import { IndexedColumn } from 'drizzle-orm/pg-core/columns/common'
4
4
  import { migrate as migratePglite } from 'drizzle-orm/pglite/migrator'
5
+
5
6
  import { FOXER_TABLES, PUBLICATION_NAME } from '../contants.ts'
6
7
  import type { Logger } from '../utils/logger.ts'
7
8
  import { startClock } from '../utils/timer.ts'
@@ -1,4 +1,5 @@
1
1
  import { pgTable } from 'drizzle-orm/pg-core'
2
+
2
3
  import { address, bigint, bytea, hash, numeric78 } from '../column-types.ts'
3
4
 
4
5
  export const blocks = pgTable('blocks', {
@@ -1,5 +1,6 @@
1
1
  import { index, integer, jsonb, pgEnum, pgTable } from 'drizzle-orm/pg-core'
2
2
  import type { AccessList } from 'viem'
3
+
3
4
  import { address, bigint, bytea, hash, numeric78 } from '../column-types.ts'
4
5
 
5
6
  export const transactionTypeEnum = pgEnum('transaction_type', [
@@ -34,6 +35,8 @@ export const transactions = pgTable(
34
35
  },
35
36
  (table) => [
36
37
  index('transactions_block_number_index').on(table.blockNumber),
37
- index('transactions_to_index').on(table.to),
38
+ index('transactions_to_block_number_index')
39
+ .on(table.to, table.blockNumber)
40
+ .concurrently(),
38
41
  ]
39
42
  )
@@ -1,7 +1,9 @@
1
1
  import type { AnyRelations, EmptyRelations } from 'drizzle-orm/relations'
2
2
  import type { GetEventArgs, Log } from 'viem'
3
+
4
+ import type { InternalConfig } from '../config/config'
3
5
  import type { Database } from '../db/client'
4
- import type { EncodedBlockWithTransactions, EncodedTransaction } from '../types'
6
+ import type { EncodedBlock, EncodedTransaction } from '../types'
5
7
  import type { Logger } from '../utils/logger'
6
8
  import type {
7
9
  ContractAbiByEventKey,
@@ -32,7 +34,7 @@ export type DecodedEvent<
32
34
  { EnableUnion: false; IndexedOnly: false; Required: true }
33
35
  >
34
36
  log: Log<bigint, number, false, ContractAbiEventByEventKey<C, Event>>
35
- block: EncodedBlockWithTransactions
37
+ block: EncodedBlock
36
38
  transaction: EncodedTransaction
37
39
  }
38
40
 
@@ -79,7 +81,7 @@ export class HookRegistry<
79
81
  { EnableUnion: false; IndexedOnly: false; Required: true }
80
82
  >
81
83
  log: Log<bigint, number, false, ContractAbiEventByEventKey<C, K>>
82
- block: EncodedBlockWithTransactions
84
+ block: EncodedBlock
83
85
  transaction: EncodedTransaction
84
86
  context: HookContext<TSchema, TRelations>
85
87
  }): Promise<void> {
@@ -105,3 +107,13 @@ export class HookRegistry<
105
107
  })
106
108
  }
107
109
  }
110
+
111
+ export function createRegistry({
112
+ config,
113
+ }: {
114
+ config: InternalConfig
115
+ }): HookRegistry {
116
+ const registry = new HookRegistry()
117
+ config.hooks({ registry })
118
+ return registry
119
+ }
@@ -1,3 +1,4 @@
1
+ import type { Hash } from 'viem'
1
2
  import { filterContracts, type InternalConfig } from '../config/config.ts'
2
3
  import { getBlocksInRange } from '../db/actions/blocks.ts'
3
4
  import type { Database } from '../db/client.ts'
@@ -40,7 +41,7 @@ export async function runBackfill(args: {
40
41
  }
41
42
 
42
43
  const batchSize = config.batchSize
43
- logger.debug(
44
+ logger.info(
44
45
  {
45
46
  fromBlock: cursor.toString(),
46
47
  toBlock: safeHead.toString(),
@@ -54,14 +55,6 @@ export async function runBackfill(args: {
54
55
  const toBlock = windowEnd(cursor, batchSize, safeHead)
55
56
  const windowContracts = filterContracts(config, cursor, toBlock)
56
57
 
57
- logger.debug(
58
- {
59
- batchFromBlock: cursor.toString(),
60
- batchToBlock: toBlock.toString(),
61
- streamCount: windowContracts.addresses.length,
62
- },
63
- 'processing backfill batch'
64
- )
65
58
  const batchBlockNumbers: bigint[] = []
66
59
  let blockNumber = cursor
67
60
  while (blockNumber <= toBlock) {
@@ -69,17 +62,30 @@ export async function runBackfill(args: {
69
62
  blockNumber += 1n
70
63
  }
71
64
 
72
- const [blocksByNumber, logsByBlock] = await Promise.all([
73
- getBlocksInRange(logger, db, batchBlockNumbers, client, windowContracts),
74
- getLogsInRange({
65
+ const logsByBlock = await getLogsInRange({
66
+ logger,
67
+ client,
68
+ addresses: windowContracts.addresses,
69
+ events: windowContracts.eventAbis,
70
+ fromBlock: cursor,
71
+ toBlock,
72
+ })
73
+
74
+ const logsTxsSet = new Set<Hash>()
75
+ for (const logs of logsByBlock.values()) {
76
+ for (const log of logs) {
77
+ logsTxsSet.add(log.transactionHash)
78
+ }
79
+ }
80
+
81
+ const { blocks: blocksByNumber, transactions: transactionsMap } =
82
+ await getBlocksInRange(
75
83
  logger,
84
+ db,
85
+ batchBlockNumbers,
76
86
  client,
77
- addresses: windowContracts.addresses,
78
- events: windowContracts.eventAbis,
79
- fromBlock: cursor,
80
- toBlock,
81
- }),
82
- ])
87
+ Array.from(logsTxsSet)
88
+ )
83
89
 
84
90
  let blockIndex = 0
85
91
 
@@ -89,22 +95,26 @@ export async function runBackfill(args: {
89
95
  const blockNumber = batchBlockNumbers[blockIndex]
90
96
  const prefetchedBlock = blocksByNumber.get(blockNumber)
91
97
 
98
+ if (!prefetchedBlock) {
99
+ throw new Error(`Block ${blockNumber} not found`)
100
+ }
101
+
92
102
  await processBlock({
93
103
  logger,
94
104
  config,
95
105
  db: tx,
96
106
  client,
97
107
  registry,
98
- blockNumber,
99
108
  logs: logsByBlock.get(blockNumber) ?? [],
100
109
  block: prefetchedBlock,
110
+ transactionsMap,
101
111
  type: 'backfill',
102
112
  contracts: windowContracts,
103
113
  })
104
114
  blockIndex += 1
105
115
  }
106
116
  })
107
- logger.info(
117
+ logger.debug(
108
118
  { duration: endClockBatch() },
109
119
  'batch block and events processed'
110
120
  )
@@ -118,6 +128,7 @@ export async function runBackfill(args: {
118
128
  {
119
129
  indexedUpTo: toBlock.toString(),
120
130
  duration: batchElapsedMs,
131
+ contracts: windowContracts.addresses.length,
121
132
  throughput: Number(blocksPerSecond.toFixed(2)),
122
133
  },
123
134
  'backfill batch completed'
@@ -7,7 +7,7 @@ import { runBackfill } from './backfill.ts'
7
7
  import { startLiveSync } from './live.ts'
8
8
  import { verifyRecentBlocks } from './reorg.ts'
9
9
 
10
- export async function bootstrapIndexer(options: {
10
+ export async function createIndexer(options: {
11
11
  logger: Logger
12
12
  db: Database<typeof schema, typeof relations>
13
13
  registry: HookRegistry
@@ -1,5 +1,6 @@
1
1
  import PQueue from 'p-queue'
2
2
  import type { PublicClient } from 'viem'
3
+
3
4
  import type { InternalConfig } from '../config/config.ts'
4
5
  import type { Database } from '../db/client.ts'
5
6
  import type { relations, schema } from '../db/schema/index.ts'
@@ -25,7 +26,7 @@ export function startLiveSync(args: {
25
26
  const contracts = config.contractsForLive
26
27
 
27
28
  if (contracts.length === 0) {
28
- logger.debug(
29
+ logger.info(
29
30
  'all configured contracts have endBlock set; live sync disabled'
30
31
  )
31
32
  return { stop: noop }
@@ -44,7 +45,7 @@ export function startLiveSync(args: {
44
45
  onBlockNumber: (head) => {
45
46
  while (nextBlockToQueue <= head) {
46
47
  const blockNumber = nextBlockToQueue
47
- pqueue.add(async () => {
48
+ void pqueue.add(async () => {
48
49
  await queueBlock({
49
50
  logger,
50
51
  blockNumber,
@@ -67,7 +68,7 @@ export function startLiveSync(args: {
67
68
  },
68
69
  })
69
70
 
70
- logger.debug(
71
+ logger.info(
71
72
  { startBlock: nextBlockToQueue.toString() },
72
73
  'watching latest chain head'
73
74
  )
@@ -1,12 +1,12 @@
1
1
  import type { AbiEvent, Log, PublicClient } from 'viem'
2
+
2
3
  import type { FilteredContracts, InternalConfig } from '../config/config.ts'
3
4
  import { cacheBlockAndTransactions } from '../db/actions/blocks.ts'
4
5
  import type { Database } from '../db/client.ts'
5
6
  import type { relations, schema } from '../db/schema/index.ts'
6
7
  import { withTransaction } from '../db/transaction.ts'
7
8
  import type { HookRegistry } from '../hooks/registry.ts'
8
- import { safeGetBlock } from '../rpc/get-block.ts'
9
- import type { EncodedBlockWithTransactions, EncodedTransaction } from '../types'
9
+ import type { EncodedBlock, TransactionsMap } from '../types'
10
10
  import type { Logger } from '../utils/logger.ts'
11
11
  import { ensureParentContinuity } from './reorg.ts'
12
12
 
@@ -23,9 +23,9 @@ export async function processBlock(args: {
23
23
  db: Database<typeof schema, typeof relations>
24
24
  client: PublicClient
25
25
  registry: HookRegistry<NonNullable<unknown>>
26
- blockNumber: bigint
27
- logs?: Log<bigint, number, false, AbiEvent>[]
28
- block?: EncodedBlockWithTransactions
26
+ logs: Log<bigint, number, false, AbiEvent>[]
27
+ block: EncodedBlock
28
+ transactionsMap: TransactionsMap
29
29
  type: 'backfill' | 'live'
30
30
  contracts: FilteredContracts
31
31
  }): Promise<ProcessBlockResult> {
@@ -35,41 +35,12 @@ export async function processBlock(args: {
35
35
  db,
36
36
  client,
37
37
  registry,
38
- blockNumber,
39
- block: prefetchedBlock,
40
- logs: prefetchedLogs,
38
+ block,
39
+ transactionsMap,
40
+ logs,
41
41
  type,
42
42
  contracts,
43
43
  } = args
44
- const transactionByHash = new Map<`0x${string}`, EncodedTransaction>()
45
-
46
- let block: EncodedBlockWithTransactions | undefined
47
- let logs: Log<bigint, number, false, AbiEvent>[] | undefined
48
-
49
- if (prefetchedBlock) {
50
- block = prefetchedBlock
51
- }
52
- if (prefetchedLogs) {
53
- logs = prefetchedLogs
54
- }
55
- if (!block || !logs) {
56
- const [blockResult, logsResult] = await Promise.all([
57
- safeGetBlock({ client, blockNumber, db }),
58
- client.getLogs({
59
- address: contracts.addresses,
60
- events: contracts.eventAbis,
61
- fromBlock: blockNumber,
62
- toBlock: blockNumber,
63
- }),
64
- ])
65
-
66
- block = blockResult
67
- logs = logsResult
68
- }
69
-
70
- for (const tx of block.transactions) {
71
- transactionByHash.set(tx.hash, tx)
72
- }
73
44
 
74
45
  if (type === 'live') {
75
46
  const rewindTo = await ensureParentContinuity({
@@ -87,7 +58,8 @@ export async function processBlock(args: {
87
58
  if (type === 'live') {
88
59
  await cacheBlockAndTransactions({
89
60
  db: tx,
90
- block,
61
+ blocks: [block],
62
+ transactions: Array.from(transactionsMap.values()),
91
63
  logger,
92
64
  })
93
65
  }
@@ -96,7 +68,7 @@ export async function processBlock(args: {
96
68
  const contractName = contracts.contractNameByAddress[log.address]
97
69
 
98
70
  if (!contractName) {
99
- logger.trace(
71
+ logger.debug(
100
72
  { address: log.address },
101
73
  'contract not found in contract name by address'
102
74
  )
@@ -107,10 +79,10 @@ export async function processBlock(args: {
107
79
  if (!contracts.eventNames.has(eventName)) {
108
80
  continue
109
81
  }
110
- const transaction = transactionByHash.get(log.transactionHash)
82
+ const transaction = transactionsMap.get(log.transactionHash)
111
83
 
112
84
  if (!transaction) {
113
- logger.trace(
85
+ logger.debug(
114
86
  { transactionHash: log.transactionHash },
115
87
 
116
88
  'transaction not found in block transaction list'
@@ -1,9 +1,12 @@
1
1
  import type { Logger } from 'pino'
2
2
  import type { PublicClient } from 'viem'
3
+
3
4
  import { filterContracts, type InternalConfig } from '../config/config.ts'
4
5
  import type { Database } from '../db/client.ts'
5
6
  import type { relations, schema } from '../db/schema/index.ts'
6
7
  import type { HookRegistry } from '../hooks/registry.ts'
8
+ import { safeGetBlock } from '../rpc/get-block.ts'
9
+ import type { EncodedBlock, EncodedTransaction } from '../types.ts'
7
10
  import { startClock } from '../utils/timer.ts'
8
11
  import { processBlock } from './process-block.ts'
9
12
 
@@ -33,15 +36,36 @@ export async function queueBlock(args: QueueBlockArgs): Promise<void> {
33
36
  const endClock = startClock()
34
37
  try {
35
38
  const contracts = filterContracts(config, blockNumber, blockNumber)
39
+
40
+ const [blockResult, logsResult] = await Promise.all([
41
+ safeGetBlock({ client, blockNumber, db }),
42
+ client.getLogs({
43
+ address: contracts.addresses,
44
+ events: contracts.eventAbis,
45
+ fromBlock: blockNumber,
46
+ toBlock: blockNumber,
47
+ }),
48
+ ])
49
+
50
+ const { transactions, ..._block } = blockResult
51
+ const block: EncodedBlock = _block
52
+ const transactionsMap = new Map<`0x${string}`, EncodedTransaction>()
53
+
54
+ for (const tx of transactions) {
55
+ transactionsMap.set(tx.hash, tx)
56
+ }
57
+
36
58
  const result = await processBlock({
37
59
  logger,
38
60
  config,
39
61
  db,
40
62
  client,
41
63
  registry,
42
- blockNumber,
43
64
  type: 'live',
44
65
  contracts,
66
+ block,
67
+ transactionsMap,
68
+ logs: logsResult,
45
69
  })
46
70
 
47
71
  if (result.status === 'reorg') {