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
@@ -1 +1 @@
1
- {"version":3,"file":"abi.d.ts","sourceRoot":"","sources":["../../../src/utils/abi.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,GAAG,EACR,KAAK,QAAQ,EACb,KAAK,WAAW,EAEjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,KAAK,GAAG,EAMT,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;GAGG;AACH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,gBAAgB;QACxB,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;KACnE;CACF;AAED,KAAK,YAAY,GAAG;IAGlB,QAAQ,EAAE,MAAM,CAAC;IAEjB,SAAS,EAAE,MAAM,CAAC;IAElB,QAAQ,EAAE,GAAG,CAAC;IAEd,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IAGrB,QAAQ,EAAE,MAAM,CAAC;IAEjB,SAAS,EAAE,MAAM,CAAC;IAElB,QAAQ,EAAE,GAAG,CAAC;IAEd,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;KAAE,CAAC;IACxD,UAAU,EAAE;QAAE,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,GAAG,SAAS,CAAA;KAAE,CAAC;CACtD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;IAC3D,UAAU,EAAE;QAAE,CAAC,GAAG,EAAE,GAAG,GAAG,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;CACzD,CAAC;AAEF,eAAO,MAAM,cAAc;;eA0B1B,CAAC;AAEF,wBAAgB,WAAW,CACzB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,GACzD;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;CAC5B,EAAE,CAmBF;AAgBD,eAAO,MAAM,iBAAiB;;kBA0B7B,CAAC"}
1
+ {"version":3,"file":"abi.d.ts","sourceRoot":"","sources":["../../../src/utils/abi.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,GAAG,EACR,KAAK,QAAQ,EACb,KAAK,WAAW,EAEjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,KAAK,GAAG,EAIT,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;GAGG;AACH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,gBAAgB;QACxB,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;KACnE;CACF;AAED,eAAO,MAAM,UAAU;;UAGF,QAAQ,GAAG,WAAW;YA8B1C,CAAC;AAEF,wBAAgB,WAAW,CACzB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,GACzD;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;CAC5B,EAAE,CAmBF"}
@@ -0,0 +1,2 @@
1
+ export declare const chunk: <T>(array: T[], size: number) => T[][];
2
+ //# sourceMappingURL=chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../../../src/utils/chunk.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,wBAAyB,MAAM,UAMhD,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Like `Promise.allSettled` but throws if any of the promises reject.
3
+ *
4
+ * @dev This is very useful when dealing with multiple concurrent promises
5
+ * in a database transaction.
6
+ */
7
+ export declare function promiseAllSettledWithThrow<T>(promises: Promise<T>[]): Promise<T[]>;
8
+ //# sourceMappingURL=promiseAllSettledWithThrow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promiseAllSettledWithThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/promiseAllSettledWithThrow.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAAC,CAAC,EAChD,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GACrB,OAAO,CAAC,CAAC,EAAE,CAAC,CAkBd"}
@@ -0,0 +1,21 @@
1
+ import type { Node } from "@pgsql/types";
2
+ export declare const parseSQLQuery: (sql: string) => Promise<Node>;
3
+ /**
4
+ * Validate a SQL query.
5
+ *
6
+ * @param sql - SQL query
7
+ */
8
+ export declare const validateAllowableSQLQuery: (sql: string) => Promise<void>;
9
+ /**
10
+ * Return `true` if the SQL query is readonly, else `false`.
11
+ *
12
+ * @param sql - SQL query
13
+ */
14
+ export declare const isReadonlySQLQuery: (sql: string) => Promise<boolean>;
15
+ /**
16
+ * Find all referenced relations in a SQL query.
17
+ *
18
+ * @param sql - SQL query
19
+ */
20
+ export declare const getSQLQueryRelations: (sql: string) => Promise<Set<string>>;
21
+ //# sourceMappingURL=sql-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-parse.d.ts","sourceRoot":"","sources":["../../../src/utils/sql-parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAqB,MAAM,cAAc,CAAC;AAe5D,eAAO,MAAM,aAAa,QAAe,MAAM,KAAG,QAAQ,IAAI,CAiC7D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAAe,MAAM,kBAuD1D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAe,MAAM,KAAG,QAAQ,OAAO,CA2BrE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAC1B,MAAM,KACV,QAAQ,IAAI,MAAM,CAAC,CAoDrB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ponder",
3
- "version": "0.14.13",
3
+ "version": "0.15.0",
4
4
  "description": "An open-source framework for crypto application backends",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -99,7 +99,7 @@
99
99
  "rimraf": "^5.0.5",
100
100
  "tsx": "^4.19.2",
101
101
  "vitest": "^1.0.2",
102
- "@ponder/client": "0.14.13"
102
+ "@ponder/client": "0.15.0"
103
103
  },
104
104
  "engines": {
105
105
  "node": ">=18.14"
@@ -10,6 +10,11 @@ import {
10
10
  createDatabase,
11
11
  getPonderMetaTable,
12
12
  } from "@/database/index.js";
13
+ import {
14
+ getLiveQueryChannelName,
15
+ getLiveQueryNotifyProcedureName,
16
+ getViewsLiveQueryNotifyTriggerName,
17
+ } from "@/drizzle/onchain.js";
13
18
  import { sql } from "@/index.js";
14
19
  import { createLogger } from "@/internal/logger.js";
15
20
  import { MetricsService } from "@/internal/metrics.js";
@@ -257,25 +262,40 @@ export async function createViews({
257
262
  ),
258
263
  );
259
264
 
260
- const trigger = `status_${cliOptions.viewsSchema}_trigger`;
261
- const notification = "status_notify()";
262
- const channel = `${cliOptions.viewsSchema}_status_channel`;
265
+ const notifyProcedure = getLiveQueryNotifyProcedureName();
266
+ const channel = getLiveQueryChannelName(cliOptions.viewsSchema);
263
267
 
264
268
  await database.adminQB.wrap((db) =>
265
- db.execute(
266
- `
267
- CREATE OR REPLACE FUNCTION "${cliOptions.viewsSchema}".${notification}
268
- RETURNS TRIGGER
269
- LANGUAGE plpgsql
269
+ db.execute(`
270
+ CREATE OR REPLACE FUNCTION "${cliOptions.viewsSchema}".${notifyProcedure}
271
+ RETURNS TRIGGER LANGUAGE plpgsql
270
272
  AS $$
271
- BEGIN
272
- NOTIFY "${channel}";
273
- RETURN NULL;
274
- END;
275
- $$;`,
276
- ),
273
+ DECLARE
274
+ table_names json;
275
+ table_exists boolean := false;
276
+ BEGIN
277
+ SELECT EXISTS (
278
+ SELECT 1
279
+ FROM information_schema.tables
280
+ WHERE table_name = 'live_query_tables'
281
+ AND table_type = 'LOCAL TEMPORARY'
282
+ ) INTO table_exists;
283
+
284
+ IF table_exists THEN
285
+ SELECT json_agg(table_name) INTO table_names
286
+ FROM live_query_tables;
287
+
288
+ table_names := COALESCE(table_names, '[]'::json);
289
+ PERFORM pg_notify('${channel}', table_names::text);
290
+ END IF;
291
+
292
+ RETURN NULL;
293
+ END;
294
+ $$;`),
277
295
  );
278
296
 
297
+ const trigger = getViewsLiveQueryNotifyTriggerName(cliOptions.viewsSchema);
298
+
279
299
  await database.adminQB.wrap((db) =>
280
300
  db.execute(
281
301
  `
@@ -283,7 +303,7 @@ CREATE OR REPLACE TRIGGER "${trigger}"
283
303
  AFTER INSERT OR UPDATE OR DELETE
284
304
  ON "${cliOptions.schema!}"._ponder_checkpoint
285
305
  FOR EACH STATEMENT
286
- EXECUTE PROCEDURE "${cliOptions.viewsSchema}".${notification};`,
306
+ EXECUTE PROCEDURE "${cliOptions.viewsSchema}".${notifyProcedure};`,
287
307
  ),
288
308
  );
289
309
 
@@ -19,7 +19,9 @@ import { createServer } from "@/server/index.js";
19
19
  import { createUi } from "@/ui/index.js";
20
20
  import { createQueue } from "@/utils/queue.js";
21
21
  import type { Result } from "@/utils/result.js";
22
+ import { isolatedController } from "../isolatedController.js";
22
23
  import type { CliOptions } from "../ponder.js";
24
+ import { runCodegen } from "../utils/codegen.js";
23
25
  import { createExit } from "../utils/exit.js";
24
26
 
25
27
  export async function dev({ cliOptions }: { cliOptions: CliOptions }) {
@@ -73,6 +75,8 @@ export async function dev({ cliOptions }: { cliOptions: CliOptions }) {
73
75
  );
74
76
  }
75
77
 
78
+ runCodegen({ common });
79
+
76
80
  const build = await createBuild({ common, cliOptions });
77
81
 
78
82
  if (cliOptions.disableUi !== true) {
@@ -174,7 +178,10 @@ export async function dev({ cliOptions }: { cliOptions: CliOptions }) {
174
178
  return;
175
179
  }
176
180
 
177
- const compileSchemaResult = build.compileSchema(schemaResult.result);
181
+ const compileSchemaResult = build.compileSchema({
182
+ ...schemaResult.result,
183
+ preBuild: preCompileResult.result,
184
+ });
178
185
 
179
186
  if (compileSchemaResult.status === "error") {
180
187
  common.logger.error({
@@ -344,26 +351,41 @@ export async function dev({ cliOptions }: { cliOptions: CliOptions }) {
344
351
  schemaBuild: compileSchemaResult.result,
345
352
  });
346
353
 
347
- if (preCompileResult.result.ordering === "omnichain") {
348
- runOmnichain({
349
- common,
350
- database,
351
- preBuild: preCompileResult.result,
352
- namespaceBuild: { schema, viewsSchema: undefined },
353
- schemaBuild: compileSchemaResult.result,
354
- indexingBuild: indexingBuildResult.result,
355
- crashRecoveryCheckpoint,
356
- });
357
- } else {
358
- runMultichain({
359
- common,
360
- database,
361
- preBuild: preCompileResult.result,
362
- namespaceBuild: { schema, viewsSchema: undefined },
363
- schemaBuild: compileSchemaResult.result,
364
- indexingBuild: indexingBuildResult.result,
365
- crashRecoveryCheckpoint,
366
- });
354
+ switch (preCompileResult.result.ordering) {
355
+ case "omnichain":
356
+ runOmnichain({
357
+ common,
358
+ database,
359
+ preBuild: preCompileResult.result,
360
+ namespaceBuild: { schema, viewsSchema: undefined },
361
+ schemaBuild: compileSchemaResult.result,
362
+ indexingBuild: indexingBuildResult.result,
363
+ crashRecoveryCheckpoint,
364
+ });
365
+ break;
366
+ case "multichain":
367
+ runMultichain({
368
+ common,
369
+ database,
370
+ preBuild: preCompileResult.result,
371
+ namespaceBuild: { schema, viewsSchema: undefined },
372
+ schemaBuild: compileSchemaResult.result,
373
+ indexingBuild: indexingBuildResult.result,
374
+ crashRecoveryCheckpoint,
375
+ });
376
+ break;
377
+ case "experimental_isolated": {
378
+ isolatedController({
379
+ common,
380
+ database,
381
+ preBuild: preCompileResult.result,
382
+ namespaceBuild: { schema, viewsSchema: undefined },
383
+ schemaBuild: compileSchemaResult.result,
384
+ indexingBuild: indexingBuildResult.result,
385
+ crashRecoveryCheckpoint,
386
+ });
387
+ break;
388
+ }
367
389
  }
368
390
  } else {
369
391
  metrics.resetApiMetrics();
@@ -12,6 +12,10 @@ import {
12
12
  } from "@/database/index.js";
13
13
  import { TABLES } from "@/database/index.js";
14
14
  import { sqlToReorgTableName } from "@/drizzle/kit/index.js";
15
+ import {
16
+ getLiveQueryNotifyProcedureName,
17
+ getLiveQueryProcedureName,
18
+ } from "@/drizzle/onchain.js";
15
19
  import { createLogger } from "@/internal/logger.js";
16
20
  import { MetricsService } from "@/internal/metrics.js";
17
21
  import { buildOptions } from "@/internal/options.js";
@@ -215,6 +219,8 @@ export async function prune({ cliOptions }: { cliOptions: CliOptions }) {
215
219
  tablesToDrop.push(`"${schema}"."${sqlToReorgTableName(table)}"`);
216
220
  functionsToDrop.push(`"${schema}"."operation_reorg__${table}"`);
217
221
  }
222
+ functionsToDrop.push(`"${schema}".${getLiveQueryProcedureName()}`);
223
+ functionsToDrop.push(`"${schema}".${getLiveQueryNotifyProcedureName()}`);
218
224
  if ("view_names" in value) {
219
225
  for (const view of value.view_names) {
220
226
  viewsToDrop.push(`"${schema}"."${view}"`);
@@ -126,7 +126,10 @@ export async function serve({ cliOptions }: { cliOptions: CliOptions }) {
126
126
  return;
127
127
  }
128
128
 
129
- const compileSchemaResult = build.compileSchema(schemaResult.result);
129
+ const compileSchemaResult = build.compileSchema({
130
+ ...schemaResult.result,
131
+ preBuild: preCompileResult.result,
132
+ });
130
133
 
131
134
  if (compileSchemaResult.status === "error") {
132
135
  common.logger.error({
@@ -1,3 +1,4 @@
1
+ import { runCodegen } from "@/bin/utils/codegen.js";
1
2
  import { createBuild } from "@/build/index.js";
2
3
  import { type Database, createDatabase } from "@/database/index.js";
3
4
  import type { Common } from "@/internal/common.js";
@@ -17,6 +18,7 @@ import type {
17
18
  import { runMultichain } from "@/runtime/multichain.js";
18
19
  import { runOmnichain } from "@/runtime/omnichain.js";
19
20
  import { createServer } from "@/server/index.js";
21
+ import { isolatedController } from "../isolatedController.js";
20
22
  import type { CliOptions } from "../ponder.js";
21
23
  import { createExit } from "../utils/exit.js";
22
24
 
@@ -83,6 +85,8 @@ export async function start({
83
85
  );
84
86
  }
85
87
 
88
+ runCodegen({ common });
89
+
86
90
  const build = await createBuild({ common, cliOptions });
87
91
 
88
92
  // biome-ignore lint/style/useConst: <explanation>
@@ -146,7 +150,10 @@ export async function start({
146
150
  return;
147
151
  }
148
152
 
149
- const compileSchemaResult = build.compileSchema(schemaResult.result);
153
+ const compileSchemaResult = build.compileSchema({
154
+ ...schemaResult.result,
155
+ preBuild: preCompileResult.result,
156
+ });
150
157
 
151
158
  if (compileSchemaResult.status === "error") {
152
159
  common.logger.error({
@@ -292,11 +299,19 @@ export async function start({
292
299
 
293
300
  metrics.initializeIndexingMetrics(app);
294
301
 
295
- if (preCompileResult.result.ordering === "omnichain") {
296
- runOmnichain(app);
297
- } else {
298
- runMultichain(app);
302
+ switch (preCompileResult.result.ordering) {
303
+ case "omnichain":
304
+ runOmnichain(app);
305
+ break;
306
+ case "multichain":
307
+ runMultichain(app);
308
+ break;
309
+ case "experimental_isolated": {
310
+ isolatedController(app);
311
+ break;
312
+ }
299
313
  }
314
+
300
315
  createServer(app);
301
316
 
302
317
  return shutdown.kill;
@@ -0,0 +1,300 @@
1
+ import path from "node:path";
2
+ import url from "node:url";
3
+ import v8 from "node:v8";
4
+ import { Worker } from "node:worker_threads";
5
+ import { createIndexes, createViews } from "@/database/actions.js";
6
+ import { type Database, getPonderMetaTable } from "@/database/index.js";
7
+ import type { Common } from "@/internal/common.js";
8
+ import {
9
+ NonRetryableUserError,
10
+ nonRetryableUserErrorNames,
11
+ } from "@/internal/errors.js";
12
+ import { AggregateMetricsService, getAppProgress } from "@/internal/metrics.js";
13
+ import type {
14
+ CrashRecoveryCheckpoint,
15
+ IndexingBuild,
16
+ NamespaceBuild,
17
+ PreBuild,
18
+ SchemaBuild,
19
+ } from "@/internal/types.js";
20
+ import { runIsolated } from "@/runtime/isolated.js";
21
+ import { chunk } from "@/utils/chunk.js";
22
+ import { formatEta, formatPercentage } from "@/utils/format.js";
23
+ import { startClock } from "@/utils/timer.js";
24
+ import { isTable, isView, sql } from "drizzle-orm";
25
+ import type { isolatedWorker } from "./isolatedWorker.js";
26
+
27
+ const __filename = url.fileURLToPath(import.meta.url);
28
+ const __dirname = path.dirname(__filename);
29
+
30
+ type WorkerState = "backfill" | "live" | "complete";
31
+
32
+ export async function isolatedController({
33
+ common,
34
+ preBuild,
35
+ namespaceBuild,
36
+ schemaBuild,
37
+ indexingBuild,
38
+ crashRecoveryCheckpoint,
39
+ database,
40
+ }: {
41
+ common: Common;
42
+ preBuild: PreBuild;
43
+ namespaceBuild: NamespaceBuild;
44
+ schemaBuild: SchemaBuild;
45
+ indexingBuild: IndexingBuild;
46
+ crashRecoveryCheckpoint: CrashRecoveryCheckpoint;
47
+ database: Database;
48
+ }) {
49
+ const backfillEndClock = startClock();
50
+ const perChainState = new Map<number, WorkerState>();
51
+
52
+ const etaInterval = setInterval(async () => {
53
+ const { eta, progress } = await getAppProgress(common.metrics);
54
+
55
+ if (eta === undefined && progress === undefined) {
56
+ return;
57
+ }
58
+
59
+ common.logger.info({
60
+ msg: "Updated backfill indexing progress",
61
+ progress: progress === undefined ? undefined : formatPercentage(progress),
62
+ estimate: eta === undefined ? undefined : formatEta(eta * 1_000),
63
+ });
64
+ }, 5_000);
65
+
66
+ common.shutdown.add(() => {
67
+ clearInterval(etaInterval);
68
+ });
69
+
70
+ let isAllReady = false;
71
+ let isAllComplete = false;
72
+ const callback = async () => {
73
+ if (
74
+ isAllReady === false &&
75
+ indexingBuild.chains.every(
76
+ (chain) => perChainState.get(chain.id) !== "backfill",
77
+ )
78
+ ) {
79
+ isAllReady = true;
80
+
81
+ common.logger.info({
82
+ msg: "Completed backfill indexing across all chains",
83
+ duration: backfillEndClock(),
84
+ });
85
+ clearInterval(etaInterval);
86
+
87
+ let endClock = startClock();
88
+ await createIndexes(database.adminQB, {
89
+ statements: schemaBuild.statements,
90
+ });
91
+
92
+ if (schemaBuild.statements.indexes.sql.length > 0) {
93
+ common.logger.info({
94
+ msg: "Created database indexes",
95
+ count: schemaBuild.statements.indexes.sql.length,
96
+ duration: endClock(),
97
+ });
98
+ }
99
+
100
+ if (namespaceBuild.viewsSchema !== undefined) {
101
+ endClock = startClock();
102
+
103
+ const tables = Object.values(schemaBuild.schema).filter(isTable);
104
+ const views = Object.values(schemaBuild.schema).filter(isView);
105
+ await createViews(database.adminQB, { tables, views, namespaceBuild });
106
+
107
+ common.logger.info({
108
+ msg: "Created database views",
109
+ schema: namespaceBuild.viewsSchema,
110
+ count: tables.length,
111
+ duration: endClock(),
112
+ });
113
+
114
+ endClock = startClock();
115
+ }
116
+
117
+ await database.adminQB.wrap({ label: "update_ready" }, (db) =>
118
+ db
119
+ .update(getPonderMetaTable(namespaceBuild.schema))
120
+ .set({ value: sql`jsonb_set(value, '{is_ready}', to_jsonb(1))` }),
121
+ );
122
+
123
+ common.logger.info({
124
+ msg: "Started returning 200 responses",
125
+ endpoint: "/ready",
126
+ });
127
+ }
128
+
129
+ if (
130
+ isAllComplete === false &&
131
+ indexingBuild.chains.every(
132
+ (chain) => perChainState.get(chain.id) === "complete",
133
+ )
134
+ ) {
135
+ isAllComplete = true;
136
+ }
137
+ };
138
+
139
+ if (
140
+ common.options.command === "dev" ||
141
+ indexingBuild.chains.length === 1 ||
142
+ database.driver.dialect === "pglite" ||
143
+ common.options.maxThreads === 1
144
+ ) {
145
+ common.options.indexingCacheMaxBytes = Math.floor(
146
+ common.options.indexingCacheMaxBytes / indexingBuild.chains.length,
147
+ );
148
+ common.options.rpcMaxConcurrency = Math.floor(
149
+ common.options.rpcMaxConcurrency / indexingBuild.chains.length,
150
+ );
151
+ common.options.syncEventsQuerySize = Math.floor(
152
+ common.options.syncEventsQuerySize / indexingBuild.chains.length,
153
+ );
154
+
155
+ await Promise.all(
156
+ indexingBuild.chains.map(async (chain) => {
157
+ const chainIndex = indexingBuild.chains.findIndex(
158
+ (c) => c.id === chain.id,
159
+ );
160
+ const _indexingBuild = {
161
+ ...indexingBuild,
162
+ chains: [indexingBuild.chains[chainIndex]!],
163
+ rpcs: [indexingBuild.rpcs[chainIndex]!],
164
+ finalizedBlocks: [indexingBuild.finalizedBlocks[chainIndex]!],
165
+ eventCallbacks: [indexingBuild.eventCallbacks[chainIndex]!],
166
+ setupCallbacks: [indexingBuild.setupCallbacks[chainIndex]!],
167
+ contracts: [indexingBuild.contracts[chainIndex]!],
168
+ };
169
+
170
+ perChainState.set(chain.id, "backfill");
171
+
172
+ await runIsolated({
173
+ common,
174
+ preBuild,
175
+ namespaceBuild,
176
+ schemaBuild,
177
+ indexingBuild: _indexingBuild,
178
+ crashRecoveryCheckpoint,
179
+ database,
180
+ onReady: () => {
181
+ perChainState.set(chain.id, "live");
182
+ callback();
183
+ },
184
+ });
185
+
186
+ perChainState.set(chain.id, "complete");
187
+ callback();
188
+ }),
189
+ );
190
+ } else {
191
+ const workerPath = path.join(__dirname, "isolatedWorker.js");
192
+
193
+ const perThreadChains = chunk(
194
+ indexingBuild.chains,
195
+ Math.ceil(indexingBuild.chains.length / common.options.maxThreads),
196
+ );
197
+
198
+ const perThreadWorkers: Worker[] = [];
199
+ for (const chains of perThreadChains) {
200
+ const chainIds = chains.map((chain) => chain.id);
201
+
202
+ // Note: This is a hack to force color support in the worker threads
203
+ if (process.stdout.isTTY) {
204
+ process.env.FORCE_COLOR = "1";
205
+ }
206
+
207
+ const heapSizeLimit = v8.getHeapStatistics().heap_size_limit;
208
+ const perThreadHeapSizeLimit = Math.floor(
209
+ heapSizeLimit / (common.options.maxThreads + 1) / 1024 / 1024,
210
+ );
211
+
212
+ // Note: This sets `--max-old-space-size` for the worker thread.
213
+ // `resourceLimits` does not work because it gets overridden by
214
+ // CLI flags or environment variables. It does not change the heap
215
+ // size limit for the current main thread
216
+ v8.setFlagsFromString(`--max-old-space-size=${perThreadHeapSizeLimit}`);
217
+
218
+ const worker = new Worker(workerPath, {
219
+ workerData: {
220
+ options: common.options,
221
+ chainIds,
222
+ namespaceBuild,
223
+ crashRecoveryCheckpoint,
224
+ } satisfies Parameters<typeof isolatedWorker>[0],
225
+ });
226
+
227
+ for (const chainId of chainIds) {
228
+ perChainState.set(chainId, "backfill");
229
+ }
230
+
231
+ worker.on(
232
+ "message",
233
+ (
234
+ message:
235
+ | { type: "ready"; chainId: number }
236
+ | { type: "done"; chainId: number }
237
+ | { type: "error"; error: Error },
238
+ ) => {
239
+ switch (message.type) {
240
+ case "ready": {
241
+ perChainState.set(message.chainId, "live");
242
+ callback();
243
+ break;
244
+ }
245
+ case "done": {
246
+ perChainState.set(message.chainId, "complete");
247
+ callback();
248
+ break;
249
+ }
250
+ case "error": {
251
+ let error: Error;
252
+ if (nonRetryableUserErrorNames.includes(message.error.name)) {
253
+ error = new NonRetryableUserError(message.error.message);
254
+ } else {
255
+ error = new Error(message.error.message);
256
+ }
257
+ error.name = message.error.name;
258
+ error.stack = message.error.stack;
259
+ throw error;
260
+ }
261
+ }
262
+ },
263
+ );
264
+
265
+ worker.on("error", (error: Error) => {
266
+ if (nonRetryableUserErrorNames.includes(error.name)) {
267
+ error = new NonRetryableUserError(error.message);
268
+ } else {
269
+ error = new Error(error.message);
270
+ }
271
+ throw error;
272
+ });
273
+
274
+ worker.on("exit", (code: number) => {
275
+ const error = new Error(`Worker thread exited with code ${code}.`);
276
+ error.stack = undefined;
277
+ throw error;
278
+ });
279
+
280
+ perThreadWorkers.push(worker);
281
+ }
282
+
283
+ common.logger.debug({
284
+ msg: "Created worker threads",
285
+ count: perThreadWorkers.length,
286
+ duration: backfillEndClock(),
287
+ });
288
+
289
+ common.metrics = new AggregateMetricsService(
290
+ common.metrics,
291
+ perThreadWorkers,
292
+ );
293
+
294
+ common.shutdown.add(() => {
295
+ for (const worker of perThreadWorkers) {
296
+ worker.postMessage({ type: "kill" });
297
+ }
298
+ });
299
+ }
300
+ }