@wowok/agent-mcp 3.3.9 → 3.4.1

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 (480) hide show
  1. package/README.md +8 -0
  2. package/dist/chain-semantics/composition-truth.d.ts +102 -0
  3. package/dist/chain-semantics/composition-truth.js +1 -0
  4. package/dist/chain-semantics/eval-order.js +1 -1
  5. package/dist/chain-semantics/field-capability.js +1 -1
  6. package/dist/chain-semantics/freeze-map.js +1 -1
  7. package/dist/chain-semantics/fund-flow.js +1 -1
  8. package/dist/chain-semantics/guard-verbs.js +1 -1
  9. package/dist/chain-semantics/index.d.ts +1 -0
  10. package/dist/chain-semantics/index.js +1 -1
  11. package/dist/chain-semantics/object-graph.js +1 -1
  12. package/dist/composition/audit.js +1 -1
  13. package/dist/composition/blueprint-view.d.ts +3 -3
  14. package/dist/composition/blueprint-view.js +1 -1
  15. package/dist/composition/compile.d.ts +26 -4
  16. package/dist/composition/compile.js +1 -1
  17. package/dist/composition/emit-phases.d.ts +206 -0
  18. package/dist/composition/emit-phases.js +1 -0
  19. package/dist/composition/generate.d.ts +40 -0
  20. package/dist/composition/generate.js +1 -0
  21. package/dist/composition/guard-fill.d.ts +44 -0
  22. package/dist/composition/guard-fill.js +1 -0
  23. package/dist/composition/inflight.d.ts +26 -2
  24. package/dist/composition/inflight.js +1 -1
  25. package/dist/composition/input-normalize.d.ts +15 -0
  26. package/dist/composition/input-normalize.js +1 -0
  27. package/dist/composition/materialize.d.ts +22 -13
  28. package/dist/composition/materialize.js +1 -1
  29. package/dist/composition/mode-gates.d.ts +35 -0
  30. package/dist/composition/mode-gates.js +1 -0
  31. package/dist/composition/param-disclosure.d.ts +61 -0
  32. package/dist/composition/param-disclosure.js +1 -0
  33. package/dist/composition/plan-retry-ledger.d.ts +21 -0
  34. package/dist/composition/plan-retry-ledger.js +1 -0
  35. package/dist/composition/plan.d.ts +17 -2
  36. package/dist/composition/plan.js +1 -1
  37. package/dist/composition/product-card.d.ts +94 -0
  38. package/dist/composition/product-card.js +1 -0
  39. package/dist/composition/supply-chain-emit.d.ts +46 -0
  40. package/dist/composition/supply-chain-emit.js +1 -0
  41. package/dist/config/config-audit.spec.js +1 -1
  42. package/dist/config/config-warnings.d.ts +2 -0
  43. package/dist/config/config-warnings.js +1 -0
  44. package/dist/config/exposure.d.ts +2 -2
  45. package/dist/config/judgment.d.ts +31 -5
  46. package/dist/config/judgment.js +1 -1
  47. package/dist/config/judgment.spec.js +1 -1
  48. package/dist/config/match-policy-file.d.ts +34 -0
  49. package/dist/config/match-policy-file.js +1 -0
  50. package/dist/config/match-policy-file.spec.d.ts +1 -0
  51. package/dist/config/match-policy-file.spec.js +1 -0
  52. package/dist/config/rule-engine.d.ts +5 -5
  53. package/dist/config/rule-engine.js +1 -1
  54. package/dist/config/runtime.d.ts +0 -1
  55. package/dist/config/runtime.js +1 -1
  56. package/dist/config/severity.d.ts +0 -2
  57. package/dist/config/severity.js +1 -1
  58. package/dist/config/store-policy.spec.js +1 -1
  59. package/dist/config/template-params.d.ts +42 -0
  60. package/dist/config/template-params.js +1 -0
  61. package/dist/config/template-params.spec.d.ts +1 -0
  62. package/dist/config/template-params.spec.js +1 -0
  63. package/dist/customer/account-events.js +1 -1
  64. package/dist/data/api/api.spec.js +1 -1
  65. package/dist/data/api/cli.js +1 -1
  66. package/dist/data/api/server.d.ts +1 -0
  67. package/dist/data/api/server.js +1 -1
  68. package/dist/data/projection/store.d.ts +3 -1
  69. package/dist/data/projection/store.js +1 -1
  70. package/dist/data/projection/types.d.ts +32 -0
  71. package/dist/data/sync/cdc.d.ts +1 -2
  72. package/dist/data/sync/cdc.js +1 -1
  73. package/dist/data/sync/cdc.spec.js +1 -1
  74. package/dist/data/sync/store.d.ts +5 -0
  75. package/dist/data/sync/store.js +1 -1
  76. package/dist/data/sync/types.d.ts +2 -0
  77. package/dist/evaluation/acceptance.d.ts +8 -0
  78. package/dist/evaluation/acceptance.js +1 -1
  79. package/dist/evaluation/builtins/demand-match.js +1 -1
  80. package/dist/evaluation/builtins/graph-service.spec.js +1 -1
  81. package/dist/evaluation/capability.d.ts +2 -0
  82. package/dist/evaluation/category-match-rules.d.ts +0 -1
  83. package/dist/evaluation/category-match-rules.js +1 -1
  84. package/dist/evaluation/composer.d.ts +25 -0
  85. package/dist/evaluation/composer.js +1 -1
  86. package/dist/evaluation/engine.js +1 -1
  87. package/dist/evaluation/extract.d.ts +7 -0
  88. package/dist/evaluation/extract.js +1 -1
  89. package/dist/evaluation/game-strategy.d.ts +0 -3
  90. package/dist/evaluation/game-strategy.js +1 -1
  91. package/dist/evaluation/guard-scan.js +1 -1
  92. package/dist/evaluation/match-operation.d.ts +9 -0
  93. package/dist/evaluation/match-operation.js +1 -1
  94. package/dist/evaluation/match-policy-resolver.d.ts +9 -0
  95. package/dist/evaluation/match-policy-resolver.js +1 -0
  96. package/dist/evaluation/match-policy.d.ts +3 -1
  97. package/dist/evaluation/match-policy.js +1 -1
  98. package/dist/evaluation/region.d.ts +0 -6
  99. package/dist/evaluation/region.js +1 -1
  100. package/dist/evaluation/standards.d.ts +2 -1
  101. package/dist/evaluation/standards.js +1 -1
  102. package/dist/evaluation/structured-lines.d.ts +8 -0
  103. package/dist/evaluation/structured-lines.js +1 -0
  104. package/dist/evaluation/types.d.ts +6 -0
  105. package/dist/experience/realtime-feedback.js +1 -1
  106. package/dist/extensions/capability-manifest.d.ts +1 -0
  107. package/dist/extensions/capability-manifest.js +1 -1
  108. package/dist/extensions/capability.d.ts +91 -0
  109. package/dist/extensions/capability.js +1 -0
  110. package/dist/extensions/industry-audit.spec.js +1 -1
  111. package/dist/extensions/industry-pack.d.ts +13 -0
  112. package/dist/extensions/industry-pack.js +1 -1
  113. package/dist/extensions/modes.js +1 -1
  114. package/dist/extensions/registry.d.ts +0 -2
  115. package/dist/extensions/registry.js +1 -1
  116. package/dist/goal/GoalEngine.js +1 -1
  117. package/dist/graph/onchain/analyze.js +1 -1
  118. package/dist/graph/onchain/expand.js +1 -1
  119. package/dist/graph/onchain/exposure.js +1 -1
  120. package/dist/graph/onchain/facts.js +1 -1
  121. package/dist/graph/onchain/order-status.d.ts +0 -1
  122. package/dist/graph/onchain/order-status.js +1 -1
  123. package/dist/harness/recover.js +1 -1
  124. package/dist/harness/verify.d.ts +0 -3
  125. package/dist/harness/verify.js +1 -1
  126. package/dist/index.js +1 -1
  127. package/dist/intent/types.d.ts +0 -1
  128. package/dist/intent/types.js +1 -1
  129. package/dist/keeper/detectors.js +1 -1
  130. package/dist/keeper/types.d.ts +0 -1
  131. package/dist/keeper/types.js +1 -1
  132. package/dist/knowledge/allocation-risk.d.ts +1 -0
  133. package/dist/knowledge/allocation-risk.js +1 -1
  134. package/dist/knowledge/allocation-templates.js +1 -1
  135. package/dist/knowledge/allocator-rail-verifier.d.ts +6 -1
  136. package/dist/knowledge/allocator-rail-verifier.js +1 -1
  137. package/dist/knowledge/arb-fund-facts.d.ts +1 -0
  138. package/dist/knowledge/arb-fund-facts.js +1 -1
  139. package/dist/knowledge/arbitration-ledger.js +1 -1
  140. package/dist/knowledge/arbitration-puzzle.js +1 -1
  141. package/dist/knowledge/arbitration-risk.d.ts +1 -0
  142. package/dist/knowledge/arbitration-risk.js +1 -1
  143. package/dist/knowledge/audit-rules.d.ts +2 -2
  144. package/dist/knowledge/audit-rules.js +1 -1
  145. package/dist/knowledge/baselines/judgment-baselines.json +21 -2
  146. package/dist/knowledge/baselines/rules/allocation.json +6 -6
  147. package/dist/knowledge/baselines/rules/arb.json +2 -2
  148. package/dist/knowledge/baselines/rules/guard.json +11 -11
  149. package/dist/knowledge/baselines/rules/oracle.json +120 -0
  150. package/dist/knowledge/baselines/rules/order.json +1 -1
  151. package/dist/knowledge/baselines/rules/plan.json +385 -18
  152. package/dist/knowledge/baselines/rules/progress.json +20 -2
  153. package/dist/knowledge/baselines/semantic-facts.js +1 -1
  154. package/dist/knowledge/builtin-templates.d.ts +25 -1
  155. package/dist/knowledge/builtin-templates.js +1 -1
  156. package/dist/knowledge/catalog-facts.d.ts +4 -0
  157. package/dist/knowledge/catalog-facts.js +1 -0
  158. package/dist/knowledge/commission-landing.js +1 -1
  159. package/dist/knowledge/component-schema.d.ts +64 -0
  160. package/dist/knowledge/component-schema.js +1 -0
  161. package/dist/knowledge/contact-templates.d.ts +0 -1
  162. package/dist/knowledge/contact-templates.js +1 -1
  163. package/dist/knowledge/dynamic-pricing.js +1 -1
  164. package/dist/knowledge/entity-recipient-guard.js +1 -1
  165. package/dist/knowledge/event-semantics.js +1 -1
  166. package/dist/knowledge/fee-param-bindings.d.ts +26 -0
  167. package/dist/knowledge/fee-param-bindings.js +1 -0
  168. package/dist/knowledge/fund-layer.d.ts +1 -0
  169. package/dist/knowledge/fund-layer.js +1 -1
  170. package/dist/knowledge/game-scenarios.js +1 -1
  171. package/dist/knowledge/getting-started.d.ts +2 -2
  172. package/dist/knowledge/getting-started.js +1 -1
  173. package/dist/knowledge/guard-anchor-reach.js +1 -1
  174. package/dist/knowledge/guard-binding-table.d.ts +52 -0
  175. package/dist/knowledge/guard-binding-table.js +1 -0
  176. package/dist/knowledge/guard-binding-verifier.d.ts +30 -0
  177. package/dist/knowledge/guard-binding-verifier.js +1 -0
  178. package/dist/knowledge/guard-bindings.js +1 -1
  179. package/dist/knowledge/guard-blueprint.d.ts +68 -0
  180. package/dist/knowledge/guard-blueprint.js +1 -0
  181. package/dist/knowledge/guard-design-patterns.d.ts +1 -1
  182. package/dist/knowledge/guard-design-patterns.js +1 -1
  183. package/dist/knowledge/guard-field-cognition.js +1 -1
  184. package/dist/knowledge/guard-host-context.d.ts +24 -0
  185. package/dist/knowledge/guard-host-context.js +1 -0
  186. package/dist/knowledge/guard-ledger.js +1 -1
  187. package/dist/knowledge/guard-lint.d.ts +1 -0
  188. package/dist/knowledge/guard-lint.js +1 -1
  189. package/dist/knowledge/guard-node-gates.d.ts +3 -0
  190. package/dist/knowledge/guard-node-gates.js +1 -1
  191. package/dist/knowledge/guard-puzzle.js +1 -1
  192. package/dist/knowledge/guard-render.js +1 -1
  193. package/dist/knowledge/guard-risk.js +1 -1
  194. package/dist/knowledge/guard-submission-prompt.d.ts +11 -0
  195. package/dist/knowledge/guard-submission-prompt.js +1 -1
  196. package/dist/knowledge/guard-templates.d.ts +1 -1
  197. package/dist/knowledge/guard-templates.js +1 -1
  198. package/dist/knowledge/guard-translation.js +1 -1
  199. package/dist/knowledge/index.d.ts +1 -1
  200. package/dist/knowledge/index.js +1 -1
  201. package/dist/knowledge/industry-generalizer.d.ts +6 -1
  202. package/dist/knowledge/industry-generalizer.js +1 -1
  203. package/dist/knowledge/industry-registry.js +1 -1
  204. package/dist/knowledge/industry-strategy.js +1 -1
  205. package/dist/knowledge/jsonrpc-enum.d.ts +52 -3
  206. package/dist/knowledge/jsonrpc-enum.js +1 -1
  207. package/dist/knowledge/knob-docs.d.ts +5 -0
  208. package/dist/knowledge/knob-docs.js +1 -0
  209. package/dist/knowledge/machine-templates.js +1 -1
  210. package/dist/knowledge/machine-topology.js +1 -1
  211. package/dist/knowledge/machine-translation.js +1 -1
  212. package/dist/knowledge/object-dependency.d.ts +31 -0
  213. package/dist/knowledge/object-dependency.js +1 -0
  214. package/dist/knowledge/onchain-constants.d.ts +4 -0
  215. package/dist/knowledge/onchain-constants.js +1 -1
  216. package/dist/knowledge/order-ledger.js +1 -1
  217. package/dist/knowledge/param-schema.d.ts +93 -0
  218. package/dist/knowledge/param-schema.js +1 -0
  219. package/dist/knowledge/param-tiers.d.ts +25 -0
  220. package/dist/knowledge/param-tiers.js +1 -0
  221. package/dist/knowledge/passport-ledger.d.ts +1 -1
  222. package/dist/knowledge/passport-ledger.js +1 -1
  223. package/dist/knowledge/path-oracle/coverage.d.ts +16 -0
  224. package/dist/knowledge/path-oracle/coverage.js +1 -0
  225. package/dist/knowledge/path-oracle/index.d.ts +5 -0
  226. package/dist/knowledge/path-oracle/index.js +1 -0
  227. package/dist/knowledge/path-oracle/products/food-delivery.d.ts +2 -0
  228. package/dist/knowledge/path-oracle/products/food-delivery.js +1 -0
  229. package/dist/knowledge/path-oracle/schema.d.ts +188 -0
  230. package/dist/knowledge/path-oracle/schema.js +1 -0
  231. package/dist/knowledge/pattern-resolutions.d.ts +108 -0
  232. package/dist/knowledge/pattern-resolutions.js +1 -0
  233. package/dist/knowledge/progress-ledger.js +1 -1
  234. package/dist/knowledge/progress-risk.js +1 -1
  235. package/dist/knowledge/projection.spec.js +1 -1
  236. package/dist/knowledge/protocol-facts.js +1 -1
  237. package/dist/knowledge/requirement-families.d.ts +13 -0
  238. package/dist/knowledge/requirement-families.js +1 -0
  239. package/dist/knowledge/reward-ledger.js +1 -1
  240. package/dist/knowledge/safety-rules.js +1 -1
  241. package/dist/knowledge/scenario-modes.d.ts +2 -0
  242. package/dist/knowledge/scenario-modes.js +1 -1
  243. package/dist/knowledge/scenario-topology.js +1 -1
  244. package/dist/knowledge/semantic-ir.d.ts +4 -0
  245. package/dist/knowledge/semantic-ir.js +1 -1
  246. package/dist/knowledge/service-allocation-semantics.js +1 -1
  247. package/dist/knowledge/service-ledger.d.ts +1 -1
  248. package/dist/knowledge/service-ledger.js +1 -1
  249. package/dist/knowledge/service-templates.js +1 -1
  250. package/dist/knowledge/sku-name-gate.d.ts +17 -0
  251. package/dist/knowledge/sku-name-gate.js +1 -0
  252. package/dist/knowledge/strategy-manuals.d.ts +1 -1
  253. package/dist/knowledge/strategy-manuals.js +1 -1
  254. package/dist/knowledge/supply-chain.d.ts +9 -0
  255. package/dist/knowledge/supply-chain.js +1 -1
  256. package/dist/knowledge/template-loader.d.ts +114 -6
  257. package/dist/knowledge/template-loader.js +1 -1
  258. package/dist/knowledge/template-nav.d.ts +9 -0
  259. package/dist/knowledge/template-nav.js +1 -0
  260. package/dist/knowledge/template-prose.d.ts +1 -1
  261. package/dist/knowledge/template-registry.js +1 -1
  262. package/dist/knowledge/template-scanner.d.ts +95 -0
  263. package/dist/knowledge/template-scanner.js +1 -1
  264. package/dist/knowledge/template-test-profiles.d.ts +17 -0
  265. package/dist/knowledge/template-test-profiles.js +1 -0
  266. package/dist/knowledge/template-validation.d.ts +1 -0
  267. package/dist/knowledge/template-validation.js +1 -1
  268. package/dist/knowledge/tools-reference.js +1 -1
  269. package/dist/knowledge/treasury-templates.js +1 -1
  270. package/dist/knowledge/workflow-guidance.d.ts +5 -0
  271. package/dist/knowledge/workflow-guidance.js +1 -1
  272. package/dist/monitor/MonitorLoop.js +1 -1
  273. package/dist/participation/radar-core.js +1 -1
  274. package/dist/participation/time-window.d.ts +37 -0
  275. package/dist/participation/time-window.js +1 -0
  276. package/dist/persona/address-format.d.ts +0 -1
  277. package/dist/persona/address-format.js +1 -1
  278. package/dist/persona/bridge.js +1 -1
  279. package/dist/persona/index.d.ts +0 -2
  280. package/dist/persona/index.js +1 -1
  281. package/dist/persona/model.js +1 -1
  282. package/dist/persona/persona-audit.spec.js +1 -1
  283. package/dist/persona/types.d.ts +6 -0
  284. package/dist/playbooks/service-build/business-puzzle.js +1 -1
  285. package/dist/playbooks/service-build/game-theory.d.ts +2 -2
  286. package/dist/playbooks/service-build/intent-analyzer.js +1 -1
  287. package/dist/playbooks/service-build/machine-panorama.d.ts +1 -0
  288. package/dist/playbooks/service-build/machine-panorama.js +1 -1
  289. package/dist/playbooks/service-build/merchant-guide.d.ts +52 -22
  290. package/dist/playbooks/service-build/merchant-guide.js +1 -1
  291. package/dist/playbooks/service-build/migration-planner.d.ts +2 -0
  292. package/dist/playbooks/service-build/migration-planner.js +1 -1
  293. package/dist/playbooks/service-build/mode-actions.js +1 -1
  294. package/dist/playbooks/service-build/object-panorama.d.ts +8 -0
  295. package/dist/playbooks/service-build/object-panorama.js +1 -1
  296. package/dist/playbooks/service-build/participation-radar.d.ts +1 -0
  297. package/dist/playbooks/service-build/participation-radar.js +1 -1
  298. package/dist/playbooks/service-build/relationship-profile.js +1 -1
  299. package/dist/playbooks/service-build/reverse-mapping.d.ts +6 -0
  300. package/dist/playbooks/service-build/reverse-mapping.js +1 -1
  301. package/dist/playbooks/service-build/service-panorama.d.ts +2 -0
  302. package/dist/playbooks/service-build/service-panorama.js +1 -1
  303. package/dist/playbooks/service-build/service-quote.js +1 -1
  304. package/dist/playbooks/service-build/service-quote.spec.js +1 -1
  305. package/dist/playbooks/service-build/workflow-design-assessment.d.ts +10 -1
  306. package/dist/playbooks/service-build/workflow-design-assessment.js +1 -1
  307. package/dist/relationship/registry.js +1 -1
  308. package/dist/review/index.js +1 -1
  309. package/dist/review/repository.js +1 -1
  310. package/dist/runtime/instance-registry.d.ts +7 -1
  311. package/dist/runtime/instance-registry.js +1 -1
  312. package/dist/safety/confirm-gate.js +1 -1
  313. package/dist/schema/benchmark-migration/index.d.ts +106 -0
  314. package/dist/schema/benchmark-migration/index.js +1 -1
  315. package/dist/schema/call/allocation.d.ts +15 -6
  316. package/dist/schema/call/allocation.js +1 -1
  317. package/dist/schema/call/arbitration.js +1 -1
  318. package/dist/schema/call/base.d.ts +264 -0
  319. package/dist/schema/call/base.js +1 -1
  320. package/dist/schema/call/bridge.d.ts +34 -6
  321. package/dist/schema/call/demand.d.ts +15 -6
  322. package/dist/schema/call/demand.js +1 -1
  323. package/dist/schema/call/error-codes.d.ts +1 -1
  324. package/dist/schema/call/error-codes.js +1 -1
  325. package/dist/schema/call/guard.d.ts +8 -8
  326. package/dist/schema/call/guard.js +1 -1
  327. package/dist/schema/call/handler.d.ts +3 -0
  328. package/dist/schema/call/handler.js +1 -1
  329. package/dist/schema/call/machine.d.ts +32 -8
  330. package/dist/schema/call/machine.js +1 -1
  331. package/dist/schema/call/order.d.ts +26 -8
  332. package/dist/schema/call/order.js +1 -1
  333. package/dist/schema/call/payment.d.ts +20 -8
  334. package/dist/schema/call/payment.js +1 -1
  335. package/dist/schema/call/permission-handler.js +1 -1
  336. package/dist/schema/call/permission.d.ts +330 -114
  337. package/dist/schema/call/permission.js +1 -1
  338. package/dist/schema/call/personal.d.ts +10 -4
  339. package/dist/schema/call/personal.js +1 -1
  340. package/dist/schema/call/progress.d.ts +16 -4
  341. package/dist/schema/call/reward.d.ts +10 -4
  342. package/dist/schema/call/reward.js +1 -1
  343. package/dist/schema/call/semantic.d.ts +1 -0
  344. package/dist/schema/call/semantic.js +1 -1
  345. package/dist/schema/call/service.d.ts +131 -43
  346. package/dist/schema/call/service.js +1 -1
  347. package/dist/schema/call/treasury.d.ts +15 -6
  348. package/dist/schema/call/treasury.js +1 -1
  349. package/dist/schema/common/index.js +1 -1
  350. package/dist/schema/config/index.d.ts +61 -0
  351. package/dist/schema/config/index.js +1 -1
  352. package/dist/schema/envelope-unify.d.ts +4 -0
  353. package/dist/schema/envelope-unify.js +1 -0
  354. package/dist/schema/evaluation/index.d.ts +224 -19
  355. package/dist/schema/evaluation/index.js +1 -1
  356. package/dist/schema/goal/index.d.ts +47 -0
  357. package/dist/schema/goal/planning.d.ts +116 -1
  358. package/dist/schema/goal/planning.js +1 -1
  359. package/dist/schema/industry-pack/index.d.ts +166 -6
  360. package/dist/schema/industry-pack/index.js +1 -1
  361. package/dist/schema/industry-pack/modes.d.ts +6 -6
  362. package/dist/schema/keeper/index.d.ts +26 -0
  363. package/dist/schema/local/index.d.ts +157 -0
  364. package/dist/schema/local/index.js +1 -1
  365. package/dist/schema/local/wip.d.ts +6 -0
  366. package/dist/schema/local/wip.js +1 -1
  367. package/dist/schema/messenger/index.d.ts +28 -0
  368. package/dist/schema/messenger/index.js +1 -1
  369. package/dist/schema/operations.d.ts +343 -84
  370. package/dist/schema/operations.js +1 -1
  371. package/dist/schema/persona/index.d.ts +2907 -640
  372. package/dist/schema/persona/index.js +1 -1
  373. package/dist/schema/query/bi.d.ts +251 -4
  374. package/dist/schema/query/bi.js +1 -1
  375. package/dist/schema/query/index.d.ts +271 -78
  376. package/dist/schema/query/index.js +1 -1
  377. package/dist/schema/schema-query/index.d.ts +1 -1
  378. package/dist/schema/schema-query/index.js +1 -1
  379. package/dist/schema/schema-version.js +1 -1
  380. package/dist/schema/utils/permission-machine-check.d.ts +2 -0
  381. package/dist/schema/utils/permission-machine-check.js +1 -1
  382. package/dist/schema/watch/index.d.ts +16 -0
  383. package/dist/schema/watch/index.js +1 -1
  384. package/dist/schema/workflow/index.d.ts +2 -2
  385. package/dist/schema/workflow/index.js +1 -1
  386. package/dist/schema-query-impl/index.d.ts +1 -1
  387. package/dist/schema-query-impl/index.js +1 -1
  388. package/dist/schemas/account_operation.output.json +98 -2
  389. package/dist/schemas/benchmark_migration_operation.output.json +341 -12
  390. package/dist/schemas/benchmark_migration_operation.schema.json +42 -3
  391. package/dist/schemas/bridge_operation.output.json +98 -2
  392. package/dist/schemas/bridge_operation.schema.json +5 -5
  393. package/dist/schemas/config_operation.output.json +352 -0
  394. package/dist/schemas/config_operation.schema.json +20 -2
  395. package/dist/schemas/evaluation_operation.output.json +586 -4
  396. package/dist/schemas/evaluation_operation.schema.json +194 -3
  397. package/dist/schemas/goal_operation.schema.json +183 -0
  398. package/dist/schemas/guard2file.schema.json +1 -1
  399. package/dist/schemas/index.json +1 -1
  400. package/dist/schemas/industry_pack_operation.output.json +771 -1
  401. package/dist/schemas/industry_pack_operation.schema.json +28 -4
  402. package/dist/schemas/keeper_operation.output.json +96 -2
  403. package/dist/schemas/local_cache_operation.output.json +98 -2
  404. package/dist/schemas/local_history_operation.output.json +98 -2
  405. package/dist/schemas/local_info_operation.output.json +98 -2
  406. package/dist/schemas/local_mark_operation.output.json +98 -2
  407. package/dist/schemas/machineNode2file.schema.json +1 -1
  408. package/dist/schemas/messenger_operation.output.json +107 -2
  409. package/dist/schemas/messenger_operation.schema.json +41 -34
  410. package/dist/schemas/monitor_events.output.json +96 -2
  411. package/dist/schemas/monitor_subscription.output.json +96 -2
  412. package/dist/schemas/onchain_events.output.json +108 -14
  413. package/dist/schemas/onchain_operations.output.json +326 -11
  414. package/dist/schemas/onchain_operations.schema.json +1343 -734
  415. package/dist/schemas/onchain_operations_allocation.schema.json +35 -19
  416. package/dist/schemas/onchain_operations_arbitration.schema.json +16 -8
  417. package/dist/schemas/onchain_operations_contact.schema.json +12 -4
  418. package/dist/schemas/onchain_operations_demand.schema.json +33 -17
  419. package/dist/schemas/onchain_operations_gen_passport.schema.json +12 -4
  420. package/dist/schemas/onchain_operations_gen_proof.schema.json +1 -1
  421. package/dist/schemas/onchain_operations_guard.schema.json +297 -111
  422. package/dist/schemas/onchain_operations_machine.schema.json +56 -39
  423. package/dist/schemas/onchain_operations_order.schema.json +67 -42
  424. package/dist/schemas/onchain_operations_payment.schema.json +27 -12
  425. package/dist/schemas/onchain_operations_permission.schema.json +363 -232
  426. package/dist/schemas/onchain_operations_personal.schema.json +43 -28
  427. package/dist/schemas/onchain_operations_progress.schema.json +49 -32
  428. package/dist/schemas/onchain_operations_proof.schema.json +12 -4
  429. package/dist/schemas/onchain_operations_repository.schema.json +17 -8
  430. package/dist/schemas/onchain_operations_reward.schema.json +36 -20
  431. package/dist/schemas/onchain_operations_service.schema.json +230 -130
  432. package/dist/schemas/onchain_operations_treasury.schema.json +36 -20
  433. package/dist/schemas/onchain_table_data.output.json +276 -19
  434. package/dist/schemas/onchain_table_data.schema.json +104 -64
  435. package/dist/schemas/persona_operation.output.json +7752 -0
  436. package/dist/schemas/persona_operation.schema.json +1232 -4
  437. package/dist/schemas/query_toolkit.output.json +1054 -146
  438. package/dist/schemas/query_toolkit.schema.json +144 -13
  439. package/dist/schemas/schema_query.schema.json +1 -1
  440. package/dist/schemas/watch_operation.output.json +86 -3
  441. package/dist/schemas/wip_file.output.json +8 -0
  442. package/dist/schemas/workflow_operation.schema.json +5 -4
  443. package/dist/schemas/wowok_buildin_info.schema.json +1 -1
  444. package/dist/task/playbook.js +1 -1
  445. package/dist/tools/handlers/benchmark-migration.d.ts +12 -3
  446. package/dist/tools/handlers/benchmark-migration.js +1 -1
  447. package/dist/tools/handlers/config.js +1 -1
  448. package/dist/tools/handlers/evaluation.js +1 -1
  449. package/dist/tools/handlers/evaluation.spec.js +1 -1
  450. package/dist/tools/handlers/industry-pack.js +1 -1
  451. package/dist/tools/handlers/messenger.js +1 -1
  452. package/dist/tools/handlers/onchain.d.ts +24 -0
  453. package/dist/tools/handlers/onchain.js +1 -1
  454. package/dist/tools/handlers/persona.js +1 -1
  455. package/dist/tools/handlers/query.d.ts +8 -0
  456. package/dist/tools/handlers/query.js +1 -1
  457. package/dist/tools/handlers/winner-derivation.d.ts +20 -0
  458. package/dist/tools/handlers/winner-derivation.js +1 -0
  459. package/dist/tools/handlers/wip-upload.js +1 -1
  460. package/dist/tools/index.d.ts +1 -0
  461. package/dist/tools/index.js +1 -1
  462. package/dist/tools/registry/business.js +1 -1
  463. package/dist/tools/registry/config.js +1 -1
  464. package/dist/tools/registry/evaluation.js +1 -1
  465. package/dist/tools/registry/identity.js +1 -1
  466. package/dist/tools/registry/onchain.js +1 -1
  467. package/dist/tools/registry/query.js +1 -1
  468. package/dist/tools/sanitize-output.js +1 -1
  469. package/dist/tools/sanitize-output.spec.js +1 -1
  470. package/dist/tools/transport-integrity.d.ts +7 -0
  471. package/dist/tools/transport-integrity.js +1 -0
  472. package/dist/tools/types.d.ts +1 -0
  473. package/dist/tools/upgrade-check.d.ts +22 -0
  474. package/dist/tools/upgrade-check.js +1 -1
  475. package/dist/tools/wrap.d.ts +6 -1
  476. package/dist/tools/wrap.js +1 -1
  477. package/package.json +7 -6
  478. package/dist/extensions/business-modules.d.ts +0 -54
  479. package/dist/extensions/business-modules.js +0 -1
  480. package/dist/schemas/guard-templates.json +0 -379
@@ -1 +1 @@
1
- import{createHash}from'node:crypto';import{isDeepStrictEqual}from'node:util';import{WOW_OBJECT_TYPE_TAGS,fromBase58,fromHex,toHex,wowAddressToBytes}from'@wowok/wowok';import{Pool}from'pg';import{extractGraphEdges}from'./edges.js';import{extractFacets,FACET_VERSION}from'./facets.js';import{parseObjectVersionFact}from'./facts.js';import{projectObjectVersion}from'./project.js';import{PROJECTION_SCHEMA_SQL}from'./schema.js';function addressBytes(a){return Buffer['from'](wowAddressToBytes(a));}function hashBytes(a){return Buffer['from'](fromHex(a['replace'](/^0x/,'')));}function digestBytes(a){return Buffer['from'](fromBase58(a));}function hexBytes(a){return'0x'+toHex(a);}function numberValue(a){return Number(a);}function coverage(a,b,c,d){return{'mode':'known_objects','complete':![],'truncated':c,'total_enumerated':b,'chain_id':a,'reconciled_through':d,'degraded_reasons':[...d===null?['RECONCILIATION_REQUIRED']:[],...c?['ENUMERATION_TRUNCATED']:[]]};}function sameRawVersion(a,b){const c=a['owner_address']?hexBytes(a['owner_address']):undefined,d=a['previous_version']===null||a['previous_version']===undefined?undefined:BigInt(String(a['previous_version']));return a['move_type']===b['moveType']&&a['owner_kind']===b['ownerKind']&&c===b['ownerAddress']&&a['payload_uri']===b['payloadUri']&&a['payload_format']===b['payloadFormat']&&(b['payloadJson']===undefined||a['payload_json_present']===!![]&&isDeepStrictEqual(a['payload_json']??null,b['payloadJson']))&&hexBytes(a['payload_hash'])==='0x'+b['payloadHash']['replace'](/^0x/,'')['toLowerCase']()&&Buffer['from'](a['tx_digest'])['equals'](digestBytes(b['txDigest']))&&d===b['previousVersion']&&a['state']===b['state'];}function canAttachJson(a,b){return b['payloadJson']!==undefined&&a['payload_json_present']!==!![]&&sameRawVersion(a,{...b,'payloadJson':undefined});}export class PostgresProjectionStore{['pool'];['shardCount'];constructor(a,b=0x100){this['pool']=a,this['shardCount']=b;if(!Number['isInteger'](b)||b<0x1||b>0xffff)throw new Error('Invalid\x20shard\x20count:\x20'+b);}static['fromDatabaseUrl'](a,b=0x100){return new PostgresProjectionStore(new Pool({'connectionString':a}),b);}async['migrate'](){await this['pool']['query'](PROJECTION_SCHEMA_SQL);}async['close'](){await this['pool']['end']();}async['apply'](a){return this['applyFact'](parseObjectVersionFact(a));}async['applyFact'](a){const b=await this['pool']['connect']();try{await b['query']('BEGIN');const c=await this['applyWithClient'](b,a);return await b['query']('COMMIT'),c;}catch(d){await b['query']('ROLLBACK');throw d;}finally{b['release']();}}async['applyWithClient'](a,b){const c=projectObjectVersion(b,this['shardCount']),d=createHash('sha256')['update'](b['chainId']+':'+b['objectId'])['digest']();await a['query']('SELECT\x20pg_advisory_xact_lock($1,\x20$2)',[d['readInt32BE'](0x0),d['readInt32BE'](0x4)]);const e=[b['chainId'],addressBytes(b['objectId']),b['objectVersion']['toString']()],f=await a['query']('SELECT\x20*\x20FROM\x20object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20object_version=$3',e);if(f['rows']['length']>0x0){if(!sameRawVersion(f['rows'][0x0],b)){if(canAttachJson(f['rows'][0x0],b)){await this['attachJson'](a,e,b);const k=await a['query']('SELECT\x20verified_kind,\x20object_version::TEXT\x20AS\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20state=\x27active\x27',[b['chainId'],addressBytes(b['objectId'])]);return k['rows'][0x0]?.['verified_kind']&&BigInt(k['rows'][0x0]['object_version'])<=b['objectVersion']&&(await this['syncGraphEdges'](a,b,k['rows'][0x0]['verified_kind']),await this['syncFacets'](a,b,k['rows'][0x0]['verified_kind'])),{'status':'duplicate','currentVersion':b['objectVersion']['toString']()};}return await this['quarantine'](a,b,'CONFLICTING_OBJECT_VERSION'),{'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'};}return{'status':'duplicate','currentVersion':b['objectVersion']['toString']()};}await a['query']('INSERT\x20INTO\x20object_version\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20kind_hint,\x20object_version,\x20move_type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20owner_kind,\x20owner_address,\x20payload_uri,\x20payload_hash,\x20payload_format,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json,\x20payload_json_present,\x20checkpoint,\x20tx_digest,\x20previous_version,\x20state,\x20observed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id,\x20object_version)\x20DO\x20NOTHING',[b['chainId'],addressBytes(b['objectId']),c['kindHint'],b['objectVersion']['toString'](),b['moveType'],b['ownerKind'],b['ownerAddress']?addressBytes(b['ownerAddress']):null,b['payloadUri'],hashBytes(b['payloadHash']),b['payloadFormat'],b['payloadJson']===undefined?null:JSON['stringify'](b['payloadJson']),b['payloadJson']!==undefined,b['checkpoint']['toString'](),digestBytes(b['txDigest']),b['previousVersion']?.['toString']()??null,b['state'],b['observedAt']['toISOString']()]);const g=await a['query']('SELECT\x20*\x20FROM\x20object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20object_version=$3',e);if(!sameRawVersion(g['rows'][0x0],b))return await this['quarantine'](a,b,'CONFLICTING_OBJECT_VERSION'),{'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'};if(c['quarantineReason']||c['verifiedKind']===null||c['shardIndex']===null){const l=c['quarantineReason']??'INVALID_OBJECT_PROJECTION';return await this['quarantine'](a,b,l),{'status':'quarantined','reasonCode':l};}const h=await a['query']('SELECT\x20MAX(object_version)::TEXT\x20AS\x20max\x20FROM\x20object_version\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],addressBytes(b['objectId'])]);if(h['rows'][0x0]['max']!==null&&BigInt(h['rows'][0x0]['max'])>b['objectVersion']){const m=await a['query']('SELECT\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],addressBytes(b['objectId'])]);return await this['quarantine'](a,b,'OUT_OF_ORDER_OBJECT_VERSION'),{'status':'stale','currentVersion':m['rows'][0x0]?.['object_version']===undefined?undefined:String(m['rows'][0x0]['object_version']),'reasonCode':'OUT_OF_ORDER_OBJECT_VERSION'};}await a['query']('INSERT\x20INTO\x20object_current\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20kind_hint,\x20object_version,\x20move_type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind,\x20shard_count,\x20shard_index,\x20checkpoint,\x20state,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_hash,\x20updated_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20kind_hint=EXCLUDED.kind_hint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20move_type=EXCLUDED.move_type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind=EXCLUDED.verified_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_count=EXCLUDED.shard_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_index=EXCLUDED.shard_index,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=EXCLUDED.checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20state=EXCLUDED.state,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_hash=EXCLUDED.payload_hash,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20EXCLUDED.object_version\x20>\x20object_current.object_version',[b['chainId'],addressBytes(b['objectId']),c['kindHint'],b['objectVersion']['toString'](),b['moveType'],c['verifiedKind'],c['shardCount'],c['shardIndex'],b['checkpoint']['toString'](),b['state'],hashBytes(b['payloadHash']),b['observedAt']['toISOString']()]);const i=await a['query']('SELECT\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],addressBytes(b['objectId'])]),j=i['rows'][0x0]?.['object_version'];if(j===undefined)throw new Error('Current\x20object\x20projection\x20missing\x20after\x20conditional\x20upsert');if(BigInt(j)>b['objectVersion'])return await this['quarantine'](a,b,'OUT_OF_ORDER_OBJECT_VERSION'),{'status':'stale','currentVersion':String(j),'reasonCode':'OUT_OF_ORDER_OBJECT_VERSION'};if(BigInt(j)===b['objectVersion'])return await this['syncGraphEdges'](a,b,c['verifiedKind']),await this['syncFacets'](a,b,c['verifiedKind']),{'status':'applied','currentVersion':String(j)};throw new Error('Current\x20object\x20version\x20is\x20behind\x20the\x20applied\x20raw\x20version');}async['syncGraphEdges'](a,b,c){if(!c)return;const d=extractGraphEdges(c,b['objectId'],b['payloadJson']),e=addressBytes(b['objectId']);await a['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[b['chainId'],e]);for(const f of d){await a['query']('INSERT\x20INTO\x20graph_edge\x20(chain_id,\x20src,\x20src_kind,\x20edge,\x20dst,\x20dst_kind,\x20object_version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20src,\x20edge,\x20dst)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20src_kind=EXCLUDED.src_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20dst_kind=EXCLUDED.dst_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version',[b['chainId'],e,f['srcKind'],f['edge'],addressBytes(f['dst']),f['dstKind'],b['objectVersion']['toString']()]);}}async['syncFacets'](a,b,c){if(!c)return;const d=addressBytes(b['objectId']),e=extractFacets(c,b['objectId'],b['payloadJson']);if(!e){await a['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],d]);return;}await a['query']('INSERT\x20INTO\x20object_facet\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20verified_kind,\x20facet_version,\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry,\x20industry_confidence,\x20location,\x20price_min,\x20price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities,\x20published,\x20paused,\x20name_tokens,\x20text_tokens,\x20keywords,\x20computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind=EXCLUDED.verified_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20facet_version=EXCLUDED.facet_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry=EXCLUDED.industry,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry_confidence=EXCLUDED.industry_confidence,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20location=EXCLUDED.location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_min=EXCLUDED.price_min,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_max=EXCLUDED.price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities=EXCLUDED.capabilities,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20published=EXCLUDED.published,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20paused=EXCLUDED.paused,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20name_tokens=EXCLUDED.name_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20text_tokens=EXCLUDED.text_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20keywords=EXCLUDED.keywords,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20computed_at=EXCLUDED.computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20EXCLUDED.object_version\x20>=\x20object_facet.object_version',[b['chainId'],d,e['verifiedKind'],FACET_VERSION,b['objectVersion']['toString'](),e['industry'],e['industryConfidence'],e['location'],e['priceMin'],e['priceMax'],e['capabilities'],e['published'],e['paused'],e['nameTokens'],e['textTokens'],e['keywords'],new Date()['toISOString']()]);}async['attachJson'](a,b,c){await a['query']('UPDATE\x20object_version\x20SET\x20payload_json=$4,\x20payload_json_present=TRUE\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20object_version=$3\x20AND\x20payload_json_present=FALSE',[...b,c['payloadJson']===null?'null':JSON['stringify'](c['payloadJson'])]);}async['quarantine'](a,b,c){await a['query']('INSERT\x20INTO\x20quarantine\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20object_version,\x20reason_code,\x20raw_ref,\x20first_seen\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id,\x20object_version,\x20reason_code)\x20DO\x20NOTHING',[b['chainId'],addressBytes(b['objectId']),b['objectVersion']['toString'](),c,b['payloadUri'],b['observedAt']['toISOString']()]);}async['liveSetVersions'](a,b){const c=await this['pool']['query']('SELECT\x20object_id,\x20object_version::TEXT\x20AS\x20object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20verified_kind=$2\x20AND\x20state=\x27active\x27',[a,b]),d=new Map();for(const e of c['rows']){d['set'](hexBytes(e['object_id']),String(e['object_version']));}return d;}async['markTombstone'](a,b){const c=await this['pool']['connect']();try{await c['query']('BEGIN');const d=await c['query']('UPDATE\x20object_current\x20SET\x20state=\x27deleted\x27,\x20updated_at=$3\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20state=\x27active\x27',[a,addressBytes(b),new Date()['toISOString']()]);return await c['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[a,addressBytes(b)]),await c['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[a,addressBytes(b)]),await c['query']('COMMIT'),(d['rowCount']??0x0)>0x0;}catch(e){await c['query']('ROLLBACK');throw e;}finally{c['release']();}}async['markTombstoneIfKind'](a,b,c){const d=await this['pool']['connect']();try{await d['query']('BEGIN');const e=await d['query']('UPDATE\x20object_current\x20SET\x20state=\x27deleted\x27,\x20updated_at=$4\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20state=\x27active\x27\x20AND\x20verified_kind=$3',[a,addressBytes(b),c,new Date()['toISOString']()]);return(e['rowCount']??0x0)>0x0&&(await d['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[a,addressBytes(b)]),await d['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[a,addressBytes(b)])),await d['query']('COMMIT'),(e['rowCount']??0x0)>0x0;}catch(f){await d['query']('ROLLBACK');throw f;}finally{d['release']();}}async['edgesFrom'](a,b){const c=await this['pool']['query']('SELECT\x20g.src_kind,\x20g.edge,\x20g.dst,\x20g.dst_kind,\x20g.object_version::TEXT\x20AS\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(c.object_id\x20IS\x20NOT\x20NULL)\x20AS\x20dst_projected\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20graph_edge\x20g\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=g.chain_id\x20AND\x20c.object_id=g.dst\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20g.chain_id=$1\x20AND\x20g.src=$2\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20g.edge,\x20g.dst',[a,addressBytes(b)]);return c['rows']['map'](d=>({'src':b['toLowerCase'](),'srcKind':d['src_kind'],'edge':d['edge'],'dst':hexBytes(d['dst']),'dstKind':d['dst_kind'],'objectVersion':d['object_version'],'dstProjected':d['dst_projected']}));}async['edgesTo'](a,b){const c=await this['pool']['query']('SELECT\x20g.src,\x20g.src_kind,\x20g.edge,\x20g.dst_kind,\x20g.object_version::TEXT\x20AS\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(c.object_id\x20IS\x20NOT\x20NULL)\x20AS\x20src_projected\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20graph_edge\x20g\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=g.chain_id\x20AND\x20c.object_id=g.src\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20g.chain_id=$1\x20AND\x20g.dst=$2\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20g.src_kind,\x20g.src',[a,addressBytes(b)]);return c['rows']['map'](d=>({'src':hexBytes(d['src']),'srcKind':d['src_kind'],'edge':d['edge'],'dst':b['toLowerCase'](),'dstKind':d['dst_kind'],'objectVersion':d['object_version'],'dstProjected':d['src_projected']}));}async['backfillGraphEdges'](a){const b=await this['pool']['query']('SELECT\x20c.object_id,\x20c.verified_kind,\x20v.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20v.chain_id=c.chain_id\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20c.chain_id=$1\x20AND\x20c.state=\x27active\x27\x20AND\x20v.payload_json\x20IS\x20NOT\x20NULL',[a]),c=await this['pool']['connect']();let d=0x0;try{await c['query']('BEGIN');for(const e of b['rows']){const f=hexBytes(e['object_id']),g=extractGraphEdges(e['verified_kind'],f,e['payload_json']);await c['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[a,e['object_id']]);for(const h of g){await c['query']('INSERT\x20INTO\x20graph_edge\x20(chain_id,\x20src,\x20src_kind,\x20edge,\x20dst,\x20dst_kind,\x20object_version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4,$5,$6,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(SELECT\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2))',[a,e['object_id'],h['srcKind'],h['edge'],addressBytes(h['dst']),h['dstKind']]);}d+=g['length'];}await c['query']('COMMIT');}catch(i){await c['query']('ROLLBACK');throw i;}finally{c['release']();}return{'objects':b['rows']['length'],'edges':d};}async['backfillFacets'](a){const b=await this['pool']['query']('SELECT\x20c.object_id,\x20c.verified_kind,\x20c.object_version::TEXT\x20AS\x20object_version,\x20v.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20v.chain_id=c.chain_id\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20c.chain_id=$1\x20AND\x20c.state=\x27active\x27\x20AND\x20v.payload_json\x20IS\x20NOT\x20NULL',[a]),c=await this['pool']['connect']();let d=0x0;try{await c['query']('BEGIN');for(const e of b['rows']){const f=hexBytes(e['object_id']),g=extractFacets(e['verified_kind'],f,e['payload_json']);if(!g){await c['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[a,e['object_id']]);continue;}await c['query']('INSERT\x20INTO\x20object_facet\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20verified_kind,\x20facet_version,\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry,\x20industry_confidence,\x20location,\x20price_min,\x20price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities,\x20published,\x20paused,\x20name_tokens,\x20text_tokens,\x20keywords,\x20computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind=EXCLUDED.verified_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20facet_version=EXCLUDED.facet_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry=EXCLUDED.industry,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry_confidence=EXCLUDED.industry_confidence,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20location=EXCLUDED.location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_min=EXCLUDED.price_min,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_max=EXCLUDED.price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities=EXCLUDED.capabilities,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20published=EXCLUDED.published,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20paused=EXCLUDED.paused,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20name_tokens=EXCLUDED.name_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20text_tokens=EXCLUDED.text_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20keywords=EXCLUDED.keywords,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20computed_at=EXCLUDED.computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20EXCLUDED.object_version\x20>=\x20object_facet.object_version',[a,e['object_id'],g['verifiedKind'],FACET_VERSION,e['object_version'],g['industry'],g['industryConfidence'],g['location'],g['priceMin'],g['priceMax'],g['capabilities'],g['published'],g['paused'],g['nameTokens'],g['textTokens'],g['keywords'],new Date()['toISOString']()]),d+=0x1;}await c['query']('COMMIT');}catch(h){await c['query']('ROLLBACK');throw h;}finally{c['release']();}return{'objects':b['rows']['length'],'facets':d};}async['activeFacets'](a,b){const c=[a];let d='';b&&(c['push'](b),d='\x20AND\x20c.verified_kind=$'+c['length']);const e=await this['pool']['query']('SELECT\x20f.object_id,\x20f.verified_kind,\x20f.object_version::TEXT\x20AS\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20f.facet_version,\x20f.industry,\x20f.industry_confidence,\x20f.location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20f.price_min,\x20f.price_max,\x20f.capabilities,\x20f.published,\x20f.paused,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20f.name_tokens,\x20f.text_tokens,\x20f.keywords,\x20c.checkpoint::TEXT\x20AS\x20checkpoint\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_facet\x20f\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=f.chain_id\x20AND\x20c.object_id=f.object_id\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20f.chain_id=$1'+d+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20f.object_id',c);return e['rows']['map'](f=>({'objectId':hexBytes(f['object_id']),'verifiedKind':f['verified_kind'],'objectVersion':f['object_version'],'facetVersion':f['facet_version'],'industry':f['industry'],'industryConfidence':Number(f['industry_confidence']),'location':f['location'],'priceMin':f['price_min'],'priceMax':f['price_max'],'capabilities':f['capabilities']??[],'published':f['published'],'paused':f['paused'],'nameTokens':f['name_tokens']??[],'textTokens':f['text_tokens']??[],'keywords':f['keywords']??[],'checkpoint':f['checkpoint']}));}async['currentPayloads'](a,b){const c=new Map();if(b['length']===0x0)return c;const d=[a],e=b['map'](g=>{return d['push'](addressBytes(g)),'$'+d['length'];}),f=await this['pool']['query']('SELECT\x20c.object_id,\x20v.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20v.chain_id=c.chain_id\x20AND\x20v.object_id=c.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20c.chain_id=$1\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20c.object_id\x20IN\x20('+e['join'](',\x20')+')',d);for(const g of f['rows']){c['set'](hexBytes(g['object_id']),g['payload_json']??null);}return c;}async['recordReconciliation'](a){const b=a['missing']['length'],c=a['extra']['length'],d=a['versionDrift']['length'],e=a['error']||b>0x0||c>0x0||d>0x0?'fail':'pass',f=new Date()['toISOString'](),g=await this['pool']['connect']();try{await g['query']('BEGIN'),await g['query']('INSERT\x20INTO\x20reconciliation_run\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20kind,\x20run_id,\x20live_set_checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20missing,\x20extra,\x20version_drift,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20missing_count,\x20extra_count,\x20version_drift_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20repaired_missing,\x20repaired_drift,\x20tombstoned,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verdict,\x20live_count,\x20projection_active,\x20generation,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20reconciled_through,\x20started_at,\x20completed_at,\x20error\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4::bigint,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14::text,$15,$16,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(SELECT\x20generation\x20FROM\x20projection_generation\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20CASE\x20WHEN\x20$14::text=\x27pass\x27\x20THEN\x20$4::bigint\x20ELSE\x20NULL\x20END,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20$17,$18,$19)',[a['chainId'],a['kind'],a['runId'],a['liveSetCheckpoint'],a['missing'],a['extra'],a['versionDrift'],a['preDiff']['missing'],a['preDiff']['extra'],a['preDiff']['versionDrift'],a['repairs']['missing'],a['repairs']['drift'],a['repairs']['tombstoned'],e,a['liveCount'],a['projectionActive'],f,f,a['error']??null]);let h=null,i=null;if(e==='pass'){const j=await g['query']('INSERT\x20INTO\x20projection_generation\x20(chain_id,\x20kind,\x20generation,\x20reconciled_through,\x20updated_at)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,1,$3,$4)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20kind)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20generation=projection_generation.generation+1,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20reconciled_through=EXCLUDED.reconciled_through,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20RETURNING\x20generation',[a['chainId'],a['kind'],a['liveSetCheckpoint'],new Date()['toISOString']()]);h=Number(j['rows'][0x0]['generation']),i=a['liveSetCheckpoint'];}return await g['query']('UPDATE\x20reconciliation_run\x20SET\x20generation=$4,\x20reconciled_through=$5\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2\x20AND\x20run_id=$3',[a['chainId'],a['kind'],a['runId'],h,i]),await g['query']('COMMIT'),{'runId':a['runId'],'verdict':e,'generation':h,'reconciledThrough':i};}catch(k){await g['query']('ROLLBACK');throw k;}finally{g['release']();}}async['reconciliationSummary'](a){if(!a)throw new Error('chainId\x20is\x20required');const b=await this['pool']['query']('SELECT\x20kind,\x20generation,\x20reconciled_through::TEXT\x20AS\x20reconciled_through,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verdict,\x20completed_at,\x20missing_count,\x20extra_count,\x20version_drift_count\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20reconciliation_run\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20completed_at\x20IS\x20NOT\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20completed_at\x20DESC,\x20run_id\x20DESC',[a]),c=new Map();for(const d of b['rows']){if(c['has'](d['kind']))continue;c['set'](d['kind'],{'kind':d['kind'],'generation':Number(d['generation']??0x0),'reconciled_through':d['reconciled_through'],'verdict':d['verdict'],'completed_at':new Date(d['completed_at'])['toISOString'](),'missing_count':Number(d['missing_count']),'extra_count':Number(d['extra_count']),'version_drift_count':Number(d['version_drift_count'])});}return[...c['values']()]['sort']((e,f)=>e['kind']['localeCompare'](f['kind']));}async['reconciledThrough'](a,b){const c=b?await this['pool']['query']('SELECT\x20MIN(reconciled_through)::TEXT\x20AS\x20reconciled_through\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20projection_generation\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2',[a,b]):await this['pool']['query']('SELECT\x20MIN(reconciled_through)::TEXT\x20AS\x20reconciled_through\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20projection_generation\x20WHERE\x20chain_id=$1',[a]);return c['rows'][0x0]?.['reconciled_through']??null;}async['status'](a){if(!a)throw new Error('chainId\x20is\x20required');const [b,c,d,e,f,g,h]=await Promise['all']([this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_version\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_current\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20state=\x27active\x27',[a]),this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20quarantine\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20MAX(checkpoint)::TEXT\x20AS\x20max\x20FROM\x20object_current\x20WHERE\x20chain_id=$1',[a]),this['reconciliationSummary'](a),this['reconciledThrough'](a)]),i=numberValue(d['rows'][0x0]['count']);return{'chain_id':a,'raw_versions':numberValue(b['rows'][0x0]['count']),'current_objects':numberValue(c['rows'][0x0]['count']),'active_objects':i,'quarantined_versions':numberValue(e['rows'][0x0]['count']),'max_checkpoint':f['rows'][0x0]['max'],'coverage':coverage(a,i,![],h),'reconciliations':g};}async['watermarks'](a){if(!a)throw new Error('chainId\x20is\x20required');const b=await this['pool']['query']('SELECT\x20verified_kind,\x20MAX(checkpoint)::TEXT\x20AS\x20max,\x20COUNT(*)::TEXT\x20AS\x20count\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20GROUP\x20BY\x20verified_kind\x20ORDER\x20BY\x20verified_kind',[a]);return b['rows']['map'](c=>({'verified_kind':c['verified_kind'],'max_checkpoint':c['max'],'active_objects':numberValue(c['count'])}));}async['listCurrent'](a){if(!a['chainId'])throw new Error('chainId\x20is\x20required');if(a['kind']&&!(a['kind']in WOW_OBJECT_TYPE_TAGS))throw new Error('Unknown\x20object\x20kind:\x20'+a['kind']);const b=a['limit']??0x64;if(!Number['isInteger'](b)||b<0x1||b>0x3e8)throw new Error('Invalid\x20list\x20limit:\x20'+b);if(a['shard']){const {count:i,index:j}=a['shard'];if(!Number['isInteger'](i)||i<0x1||!Number['isInteger'](j)||j<0x0||j>=i)throw new Error('Invalid\x20shard\x20selector');}const c=[a['chainId']],d=['c.chain_id=$1','c.state=\x27active\x27'];a['kind']&&(c['push'](a['kind']),d['push']('c.verified_kind=$'+c['length']));a['shard']&&(c['push'](a['shard']['count'],a['shard']['index']),d['push']('c.shard_count=$'+(c['length']-0x1)),d['push']('c.shard_index=$'+c['length']));a['cursor']&&(c['push'](addressBytes(a['cursor'])),d['push']('c.object_id>$'+c['length']));c['push'](b+0x1);const e=await this['pool']['query']('SELECT\x20c.*,\x20v.payload_uri,\x20v.payload_format,\x20v.payload_json,\x20v.owner_kind,\x20v.owner_address\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x20ON\x20v.chain_id=c.chain_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20'+d['join']('\x20AND\x20')+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20c.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LIMIT\x20$'+c['length'],c),f=e['rows']['length']>b,g=e['rows']['slice'](0x0,b),h=await this['reconciledThrough'](a['chainId'],a['kind']);return{'objects':g['map'](k=>({'objectId':hexBytes(k['object_id']),'objectVersion':String(k['object_version']),'kindHint':k['kind_hint'],'verifiedKind':k['verified_kind'],'shardCount':k['shard_count'],'shardIndex':k['shard_index'],'moveType':k['move_type'],'checkpoint':String(k['checkpoint']),'state':k['state'],'payloadHash':hexBytes(k['payload_hash']),'payloadUri':k['payload_uri'],'payloadFormat':k['payload_format'],'payloadJson':k['payload_json']??null,'ownerKind':k['owner_kind'],'ownerAddress':k['owner_address']?hexBytes(k['owner_address']):undefined,'updatedAt':new Date(k['updated_at'])['toISOString']()})),'next_cursor':f?hexBytes(g[g['length']-0x1]['object_id']):null,'coverage':coverage(a['chainId'],g['length'],f,h)};}}
1
+ import{createHash}from'node:crypto';import{isDeepStrictEqual}from'node:util';import{WOW_OBJECT_TYPE_TAGS,fromBase58,fromHex,toHex,wowAddressToBytes}from'@wowok/wowok';import{Pool}from'pg';import{extractGraphEdges}from'./edges.js';import{extractFacets,FACET_VERSION}from'./facets.js';import{parseObjectVersionFact}from'./facts.js';import{projectObjectVersion}from'./project.js';import{PROJECTION_SCHEMA_SQL}from'./schema.js';function addressBytes(a){return Buffer['from'](wowAddressToBytes(a));}function hashBytes(a){return Buffer['from'](fromHex(a['replace'](/^0x/,'')));}function digestBytes(a){return Buffer['from'](fromBase58(a));}function hexBytes(a){return'0x'+toHex(a);}function numberValue(a){return Number(a);}function isoValue(a){if(a===null||a===undefined)return null;const b=a instanceof Date?a:new Date(String(a));return Number['isNaN'](b['getTime']())?null:b['toISOString']();}function coverage(a,b,c,d){return{'mode':'known_objects','complete':![],'truncated':c,'total_enumerated':b,'chain_id':a,'reconciled_through':d,'degraded_reasons':[...d===null?['RECONCILIATION_REQUIRED']:[],...c?['ENUMERATION_TRUNCATED']:[]]};}function sameRawVersion(a,b){const c=a['owner_address']?hexBytes(a['owner_address']):undefined,d=a['previous_version']===null||a['previous_version']===undefined?undefined:BigInt(String(a['previous_version']));return a['move_type']===b['moveType']&&a['owner_kind']===b['ownerKind']&&c===b['ownerAddress']&&a['payload_uri']===b['payloadUri']&&a['payload_format']===b['payloadFormat']&&(b['payloadJson']===undefined||a['payload_json_present']===!![]&&isDeepStrictEqual(a['payload_json']??null,b['payloadJson']))&&hexBytes(a['payload_hash'])==='0x'+b['payloadHash']['replace'](/^0x/,'')['toLowerCase']()&&Buffer['from'](a['tx_digest'])['equals'](digestBytes(b['txDigest']))&&d===b['previousVersion']&&a['state']===b['state'];}function canAttachJson(a,b){return b['payloadJson']!==undefined&&a['payload_json_present']!==!![]&&sameRawVersion(a,{...b,'payloadJson':undefined});}export class PostgresProjectionStore{['pool'];['shardCount'];constructor(a,b=0x100){this['pool']=a,this['shardCount']=b;if(!Number['isInteger'](b)||b<0x1||b>0xffff)throw new Error('Invalid\x20shard\x20count:\x20'+b);}static['fromDatabaseUrl'](a,b=0x100){return new PostgresProjectionStore(new Pool({'connectionString':a}),b);}async['migrate'](){await this['pool']['query'](PROJECTION_SCHEMA_SQL);}async['close'](){await this['pool']['end']();}async['apply'](a){return this['applyFact'](parseObjectVersionFact(a));}async['applyFact'](a){const b=await this['pool']['connect']();try{await b['query']('BEGIN');const c=await this['applyWithClient'](b,a);return await b['query']('COMMIT'),c;}catch(d){await b['query']('ROLLBACK');throw d;}finally{b['release']();}}async['applyWithClient'](a,b){const c=projectObjectVersion(b,this['shardCount']),d=createHash('sha256')['update'](b['chainId']+':'+b['objectId'])['digest']();await a['query']('SELECT\x20pg_advisory_xact_lock($1,\x20$2)',[d['readInt32BE'](0x0),d['readInt32BE'](0x4)]);const e=[b['chainId'],addressBytes(b['objectId']),b['objectVersion']['toString']()],f=await a['query']('SELECT\x20*\x20FROM\x20object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20object_version=$3',e);if(f['rows']['length']>0x0){if(!sameRawVersion(f['rows'][0x0],b)){if(canAttachJson(f['rows'][0x0],b)){await this['attachJson'](a,e,b);const k=await a['query']('SELECT\x20verified_kind,\x20object_version::TEXT\x20AS\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20state=\x27active\x27',[b['chainId'],addressBytes(b['objectId'])]);return k['rows'][0x0]?.['verified_kind']&&BigInt(k['rows'][0x0]['object_version'])<=b['objectVersion']&&(await this['syncGraphEdges'](a,b,k['rows'][0x0]['verified_kind']),await this['syncFacets'](a,b,k['rows'][0x0]['verified_kind'])),{'status':'duplicate','currentVersion':b['objectVersion']['toString']()};}return await this['quarantine'](a,b,'CONFLICTING_OBJECT_VERSION'),{'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'};}return{'status':'duplicate','currentVersion':b['objectVersion']['toString']()};}await a['query']('INSERT\x20INTO\x20object_version\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20kind_hint,\x20object_version,\x20move_type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20owner_kind,\x20owner_address,\x20payload_uri,\x20payload_hash,\x20payload_format,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json,\x20payload_json_present,\x20checkpoint,\x20tx_digest,\x20previous_version,\x20state,\x20observed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id,\x20object_version)\x20DO\x20NOTHING',[b['chainId'],addressBytes(b['objectId']),c['kindHint'],b['objectVersion']['toString'](),b['moveType'],b['ownerKind'],b['ownerAddress']?addressBytes(b['ownerAddress']):null,b['payloadUri'],hashBytes(b['payloadHash']),b['payloadFormat'],b['payloadJson']===undefined?null:JSON['stringify'](b['payloadJson']),b['payloadJson']!==undefined,b['checkpoint']['toString'](),digestBytes(b['txDigest']),b['previousVersion']?.['toString']()??null,b['state'],b['observedAt']['toISOString']()]);const g=await a['query']('SELECT\x20*\x20FROM\x20object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20object_version=$3',e);if(!sameRawVersion(g['rows'][0x0],b))return await this['quarantine'](a,b,'CONFLICTING_OBJECT_VERSION'),{'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'};if(c['quarantineReason']||c['verifiedKind']===null||c['shardIndex']===null){const l=c['quarantineReason']??'INVALID_OBJECT_PROJECTION';return await this['quarantine'](a,b,l),{'status':'quarantined','reasonCode':l};}const h=await a['query']('SELECT\x20MAX(object_version)::TEXT\x20AS\x20max\x20FROM\x20object_version\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],addressBytes(b['objectId'])]);if(h['rows'][0x0]['max']!==null&&BigInt(h['rows'][0x0]['max'])>b['objectVersion']){const m=await a['query']('SELECT\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],addressBytes(b['objectId'])]);return await this['quarantine'](a,b,'OUT_OF_ORDER_OBJECT_VERSION'),{'status':'stale','currentVersion':m['rows'][0x0]?.['object_version']===undefined?undefined:String(m['rows'][0x0]['object_version']),'reasonCode':'OUT_OF_ORDER_OBJECT_VERSION'};}await a['query']('INSERT\x20INTO\x20object_current\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20kind_hint,\x20object_version,\x20move_type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind,\x20shard_count,\x20shard_index,\x20checkpoint,\x20state,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_hash,\x20updated_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20kind_hint=EXCLUDED.kind_hint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20move_type='+'EXCLUDED.'+'move_type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind=EXCLUDED.verified_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_count=EXCLUDED.shard_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_index=EXCLUDED.shard_index,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=EXCLUDED.checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20state=EXCLUDED.state,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_hash=EXCLUDED.payload_hash,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20EXCLUDED.object_version\x20>\x20object_current.object_version',[b['chainId'],addressBytes(b['objectId']),c['kindHint'],b['objectVersion']['toString'](),b['moveType'],c['verifiedKind'],c['shardCount'],c['shardIndex'],b['checkpoint']['toString'](),b['state'],hashBytes(b['payloadHash']),b['observedAt']['toISOString']()]);const i=await a['query']('SELECT\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],addressBytes(b['objectId'])]),j=i['rows'][0x0]?.['object_version'];if(j===undefined)throw new Error('Current\x20object\x20projection\x20missing\x20after\x20conditional\x20upsert');if(BigInt(j)>b['objectVersion'])return await this['quarantine'](a,b,'OUT_OF_ORDER_OBJECT_VERSION'),{'status':'stale','currentVersion':String(j),'reasonCode':'OUT_OF_ORDER_OBJECT_VERSION'};if(BigInt(j)===b['objectVersion'])return await this['syncGraphEdges'](a,b,c['verifiedKind']),await this['syncFacets'](a,b,c['verifiedKind']),{'status':'applied','currentVersion':String(j)};throw new Error('Current\x20object\x20version\x20is\x20behind\x20the\x20applied\x20raw\x20version');}async['syncGraphEdges'](a,b,c){if(!c)return;const d=extractGraphEdges(c,b['objectId'],b['payloadJson']),e=addressBytes(b['objectId']);await a['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[b['chainId'],e]);for(const f of d){await a['query']('INSERT\x20INTO\x20graph_edge\x20(chain_id,\x20src,\x20src_kind,\x20edge,\x20dst,\x20dst_kind,\x20object_version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20src,\x20edge,\x20dst)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20src_kind=EXCLUDED.src_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20dst_kind=EXCLUDED.dst_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version',[b['chainId'],e,f['srcKind'],f['edge'],addressBytes(f['dst']),f['dstKind'],b['objectVersion']['toString']()]);}}async['syncFacets'](a,b,c){if(!c)return;const d=addressBytes(b['objectId']),e=extractFacets(c,b['objectId'],b['payloadJson']);if(!e){await a['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[b['chainId'],d]);return;}await a['query']('INSERT\x20INTO\x20object_facet\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20verified_kind,\x20facet_version,\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry,\x20industry_confidence,\x20location,\x20price_min,\x20price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities,\x20published,\x20paused,\x20name_tokens,\x20text_tokens,\x20keywords,\x20computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind=EXCLUDED.verified_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20facet_version=EXCLUDED.facet_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry=EXCLUDED.industry,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry_confidence=EXCLUDED.industry_confidence,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20location=EXCLUDED.location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_min=EXCLUDED.price_min,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_max=EXCLUDED.price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities=EXCLUDED.capabilities,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20published=EXCLUDED.published,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20paused=EXCLUDED.paused,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20name_tokens=EXCLUDED.name_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20text_tokens=EXCLUDED.text_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20keywords=EXCLUDED.keywords,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20computed_at=EXCLUDED.computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20EXCLUDED.object_version\x20>=\x20object_facet.object_version',[b['chainId'],d,e['verifiedKind'],FACET_VERSION,b['objectVersion']['toString'](),e['industry'],e['industryConfidence'],e['location'],e['priceMin'],e['priceMax'],e['capabilities'],e['published'],e['paused'],e['nameTokens'],e['textTokens'],e['keywords'],new Date()['toISOString']()]);}async['attachJson'](a,b,c){await a['query']('UPDATE\x20object_version\x20SET\x20payload_json=$4,\x20payload_json_present=TRUE\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20object_version=$3\x20AND\x20payload_json_present=FALSE',[...b,c['payloadJson']===null?'null':JSON['stringify'](c['payloadJson'])]);}async['quarantine'](a,b,c){await a['query']('INSERT\x20INTO\x20quarantine\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20object_version,\x20reason_code,\x20raw_ref,\x20first_seen\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id,\x20object_version,\x20reason_code)\x20DO\x20NOTHING',[b['chainId'],addressBytes(b['objectId']),b['objectVersion']['toString'](),c,b['payloadUri'],b['observedAt']['toISOString']()]);}async['liveSetVersions'](a,b){const c=await this['pool']['query']('SELECT\x20object_id,\x20object_version::TEXT\x20AS\x20object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20verified_kind=$2\x20AND\x20state=\x27active\x27',[a,b]),d=new Map();for(const e of c['rows']){d['set'](hexBytes(e['object_id']),String(e['object_version']));}return d;}async['markTombstone'](a,b){const c=await this['pool']['connect']();try{await c['query']('BEGIN');const d=await c['query']('UPDATE\x20object_current\x20SET\x20state=\x27deleted\x27,\x20updated_at=$3\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20state=\x27active\x27',[a,addressBytes(b),new Date()['toISOString']()]);return await c['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[a,addressBytes(b)]),await c['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[a,addressBytes(b)]),await c['query']('COMMIT'),(d['rowCount']??0x0)>0x0;}catch(e){await c['query']('ROLLBACK');throw e;}finally{c['release']();}}async['markTombstoneIfKind'](a,b,c){const d=await this['pool']['connect']();try{await d['query']('BEGIN');const e=await d['query']('UPDATE\x20object_current\x20SET\x20state=\x27deleted\x27,\x20updated_at=$4\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2\x20AND\x20state=\x27active\x27\x20AND\x20verified_kind=$3',[a,addressBytes(b),c,new Date()['toISOString']()]);return(e['rowCount']??0x0)>0x0&&(await d['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[a,addressBytes(b)]),await d['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[a,addressBytes(b)])),await d['query']('COMMIT'),(e['rowCount']??0x0)>0x0;}catch(f){await d['query']('ROLLBACK');throw f;}finally{d['release']();}}async['edgesFrom'](a,b){const c=await this['pool']['query']('SELECT\x20g.src_kind,\x20g.edge,\x20g.dst,\x20g.dst_kind,\x20g.object_version::TEXT\x20AS\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(c.object_id\x20IS\x20NOT\x20NULL)\x20AS\x20dst_projected\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20graph_edge\x20g\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=g.chain_id\x20AND\x20c.object_id=g.dst\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20g.chain_id=$1\x20AND\x20g.src=$2\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20g.edge,\x20g.dst',[a,addressBytes(b)]);return c['rows']['map'](d=>({'src':b['toLowerCase'](),'srcKind':d['src_kind'],'edge':d['edge'],'dst':hexBytes(d['dst']),'dstKind':d['dst_kind'],'objectVersion':d['object_version'],'dstProjected':d['dst_projected']}));}async['edgesTo'](a,b){const c=await this['pool']['query']('SELECT\x20g.src,\x20g.src_kind,\x20g.edge,\x20g.dst_kind,\x20g.object_version::TEXT\x20AS\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(c.object_id\x20IS\x20NOT\x20NULL)\x20AS\x20src_projected\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20graph_edge\x20g\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=g.chain_id\x20AND\x20c.object_id=g.src\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20g.chain_id=$1\x20AND\x20g.dst=$2\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20g.src_kind,\x20g.src',[a,addressBytes(b)]);return c['rows']['map'](d=>({'src':hexBytes(d['src']),'srcKind':d['src_kind'],'edge':d['edge'],'dst':b['toLowerCase'](),'dstKind':d['dst_kind'],'objectVersion':d['object_version'],'dstProjected':d['src_projected']}));}async['backfillGraphEdges'](a){const b=await this['pool']['query']('SELECT\x20c.object_id,\x20c.verified_kind,\x20v.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20v.chain_id=c.chain_id\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20c.chain_id=$1\x20AND\x20c.state=\x27active\x27\x20AND\x20v.payload_json\x20IS\x20NOT\x20NULL',[a]),c=await this['pool']['connect']();let d=0x0;try{await c['query']('BEGIN');for(const e of b['rows']){const f=hexBytes(e['object_id']),g=extractGraphEdges(e['verified_kind'],f,e['payload_json']);await c['query']('DELETE\x20FROM\x20graph_edge\x20WHERE\x20chain_id=$1\x20AND\x20src=$2',[a,e['object_id']]);for(const h of g){await c['query']('INSERT\x20INTO\x20graph_edge\x20(chain_id,\x20src,\x20src_kind,\x20edge,\x20dst,\x20dst_kind,\x20object_version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4,$5,$6,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(SELECT\x20object_version\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2))',[a,e['object_id'],h['srcKind'],h['edge'],addressBytes(h['dst']),h['dstKind']]);}d+=g['length'];}await c['query']('COMMIT');}catch(i){await c['query']('ROLLBACK');throw i;}finally{c['release']();}return{'objects':b['rows']['length'],'edges':d};}async['backfillFacets'](a){const b=await this['pool']['query']('SELECT\x20c.object_id,\x20c.verified_kind,\x20c.object_version::TEXT\x20AS\x20object_version,\x20v.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20v.chain_id=c.chain_id\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20c.chain_id=$1\x20AND\x20c.state=\x27active\x27\x20AND\x20v.payload_json\x20IS\x20NOT\x20NULL',[a]),c=await this['pool']['connect']();let d=0x0;try{await c['query']('BEGIN');for(const e of b['rows']){const f=hexBytes(e['object_id']),g=extractFacets(e['verified_kind'],f,e['payload_json']);if(!g){await c['query']('DELETE\x20FROM\x20object_facet\x20WHERE\x20chain_id=$1\x20AND\x20object_id=$2',[a,e['object_id']]);continue;}await c['query']('INSERT\x20INTO\x20object_facet\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20object_id,\x20verified_kind,\x20facet_version,\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry,\x20industry_confidence,\x20location,\x20price_min,\x20price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities,\x20published,\x20paused,\x20name_tokens,\x20text_tokens,\x20keywords,\x20computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20object_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verified_kind=EXCLUDED.verified_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20facet_version=EXCLUDED.facet_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20object_version=EXCLUDED.object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry=EXCLUDED.industry,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20industry_confidence=EXCLUDED.industry_confidence,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20location=EXCLUDED.location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_min=EXCLUDED.price_min,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20price_max=EXCLUDED.price_max,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20capabilities=EXCLUDED.capabilities,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20published=EXCLUDED.published,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20paused=EXCLUDED.paused,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20name_tokens=EXCLUDED.name_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20text_tokens=EXCLUDED.text_tokens,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20keywords=EXCLUDED.keywords,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20computed_at=EXCLUDED.computed_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20EXCLUDED.object_version\x20>=\x20object_facet.object_version',[a,e['object_id'],g['verifiedKind'],FACET_VERSION,e['object_version'],g['industry'],g['industryConfidence'],g['location'],g['priceMin'],g['priceMax'],g['capabilities'],g['published'],g['paused'],g['nameTokens'],g['textTokens'],g['keywords'],new Date()['toISOString']()]),d+=0x1;}await c['query']('COMMIT');}catch(h){await c['query']('ROLLBACK');throw h;}finally{c['release']();}return{'objects':b['rows']['length'],'facets':d};}async['activeFacets'](a,b){const c=[a];let d='';b&&(c['push'](b),d='\x20AND\x20c.verified_kind=$'+c['length']);const e=await this['pool']['query']('SELECT\x20f.object_id,\x20f.verified_kind,\x20f.object_version::TEXT\x20AS\x20object_version,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20f.facet_version,\x20f.industry,\x20f.industry_confidence,\x20f.location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20f.price_min,\x20f.price_max,\x20f.capabilities,\x20f.published,\x20f.paused,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20f.name_tokens,\x20f.text_tokens,\x20f.keywords,\x20c.checkpoint::TEXT\x20AS\x20checkpoint\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_facet\x20f\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=f.chain_id\x20AND\x20c.object_id=f.object_id\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20f.chain_id=$1'+d+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20f.object_id',c);return e['rows']['map'](f=>({'objectId':hexBytes(f['object_id']),'verifiedKind':f['verified_kind'],'objectVersion':f['object_version'],'facetVersion':f['facet_version'],'industry':f['industry'],'industryConfidence':Number(f['industry_confidence']),'location':f['location'],'priceMin':f['price_min'],'priceMax':f['price_max'],'capabilities':f['capabilities']??[],'published':f['published'],'paused':f['paused'],'nameTokens':f['name_tokens']??[],'textTokens':f['text_tokens']??[],'keywords':f['keywords']??[],'checkpoint':f['checkpoint']}));}async['currentPayloads'](a,b){const c=new Map();if(b['length']===0x0)return c;const d=[a],e=b['map'](g=>{return d['push'](addressBytes(g)),'$'+d['length'];}),f=await this['pool']['query']('SELECT\x20c.object_id,\x20v.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20v.chain_id=c.chain_id\x20AND\x20v.object_id=c.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20c.chain_id=$1\x20AND\x20c.state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20c.object_id\x20IN\x20('+e['join'](',\x20')+')',d);for(const g of f['rows']){c['set'](hexBytes(g['object_id']),g['payload_json']??null);}return c;}async['aggregate'](a,b){if(!a)throw new Error('chainId\x20is\x20required');const c=[a,b['group'],b['metric']],d='(v.payload_json->>$2)',e='(v.payload_json->>$3)::numeric',f=['c.chain_id=$1','c.state=\x27active\x27',d+'\x20IS\x20NOT\x20NULL'];b['groupId']!==undefined&&(c['push'](b['groupId']),f['push'](d+'\x20=\x20$'+c['length']));b['excludeClaimed']&&f['push']('(v.payload_json->>\x27claimed_by\x27)\x20IS\x20NULL');const g=f['join']('\x20AND\x20'),h='\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x20ON\x20v.chain_id=c.chain_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version',i=await this['pool']['query']('SELECT\x20'+d+'\x20AS\x20group_id,\x20COUNT(*)::TEXT\x20AS\x20count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20COALESCE(SUM('+e+'),\x200)::TEXT\x20AS\x20metric_sum,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20MAX(c.checkpoint)::TEXT\x20AS\x20max_checkpoint\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20'+h+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20'+g+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20GROUP\x20BY\x20'+d+'\x20ORDER\x20BY\x20'+d+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LIMIT\x20$'+(c['length']+0x1),[...c,b['limit']+0x1]),j=await this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20total_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20COALESCE(SUM('+e+'),\x200)::TEXT\x20AS\x20metric_sum\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20'+h+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20'+g,c),k=i['rows']['length']>b['limit'];return{'rows':i['rows']['slice'](0x0,b['limit'])['map'](l=>({'group_id':l['group_id'],'count':Number(l['count']),'metric_sum':l['metric_sum'],'max_checkpoint':l['max_checkpoint']})),'totals':{'count':Number(j['rows'][0x0]?.['total_count']??'0'),'metric_sum':j['rows'][0x0]?.['metric_sum']??'0'},'truncated':k};}async['recordReconciliation'](a){const b=a['missing']['length'],c=a['extra']['length'],d=a['versionDrift']['length'],e=a['error']||b>0x0||c>0x0||d>0x0?'fail':'pass',f=new Date()['toISOString'](),g=await this['pool']['connect']();try{await g['query']('BEGIN'),await g['query']('INSERT\x20INTO\x20reconciliation_run\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20kind,\x20run_id,\x20live_set_checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20missing,\x20extra,\x20version_drift,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20missing_count,\x20extra_count,\x20version_drift_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20repaired_missing,\x20repaired_drift,\x20tombstoned,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verdict,\x20live_count,\x20projection_active,\x20generation,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20reconciled_through,\x20started_at,\x20completed_at,\x20error\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4::bigint,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14::text,$15,$16,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(SELECT\x20generation\x20FROM\x20projection_generation\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20CASE\x20WHEN\x20$14::text=\x27pass\x27\x20THEN\x20$4::bigint\x20ELSE\x20NULL\x20END,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20$17,$18,$19)',[a['chainId'],a['kind'],a['runId'],a['liveSetCheckpoint'],a['missing'],a['extra'],a['versionDrift'],a['preDiff']['missing'],a['preDiff']['extra'],a['preDiff']['versionDrift'],a['repairs']['missing'],a['repairs']['drift'],a['repairs']['tombstoned'],e,a['liveCount'],a['projectionActive'],f,f,a['error']??null]);let h=null,i=null;if(e==='pass'){const j=await g['query']('INSERT\x20INTO\x20projection_generation\x20(chain_id,\x20kind,\x20generation,\x20reconciled_through,\x20updated_at)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,1,$3,$4)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20kind)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20generation=projection_generation.generation+1,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20reconciled_through=EXCLUDED.reconciled_through,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20RETURNING\x20generation',[a['chainId'],a['kind'],a['liveSetCheckpoint'],new Date()['toISOString']()]);h=Number(j['rows'][0x0]['generation']),i=a['liveSetCheckpoint'];}return await g['query']('UPDATE\x20reconciliation_run\x20SET\x20generation=$4,\x20reconciled_through=$5\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2\x20AND\x20run_id=$3',[a['chainId'],a['kind'],a['runId'],h,i]),await g['query']('COMMIT'),{'runId':a['runId'],'verdict':e,'generation':h,'reconciledThrough':i};}catch(k){await g['query']('ROLLBACK');throw k;}finally{g['release']();}}async['reconciliationSummary'](a){if(!a)throw new Error('chainId\x20is\x20required');const b=await this['pool']['query']('SELECT\x20kind,\x20generation,\x20reconciled_through::TEXT\x20AS\x20reconciled_through,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20verdict,\x20completed_at,\x20missing_count,\x20extra_count,\x20version_drift_count\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20reconciliation_run\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20completed_at\x20IS\x20NOT\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20completed_at\x20DESC,\x20run_id\x20DESC',[a]),c=new Map();for(const d of b['rows']){if(c['has'](d['kind']))continue;c['set'](d['kind'],{'kind':d['kind'],'generation':Number(d['generation']??0x0),'reconciled_through':d['reconciled_through'],'verdict':d['verdict'],'completed_at':new Date(d['completed_at'])['toISOString'](),'missing_count':Number(d['missing_count']),'extra_count':Number(d['extra_count']),'version_drift_count':Number(d['version_drift_count'])});}return[...c['values']()]['sort']((e,f)=>e['kind']['localeCompare'](f['kind']));}async['reconciledThrough'](a,b){const c=b?await this['pool']['query']('SELECT\x20MIN(reconciled_through)::TEXT\x20AS\x20reconciled_through\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20projection_generation\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2',[a,b]):await this['pool']['query']('SELECT\x20MIN(reconciled_through)::TEXT\x20AS\x20reconciled_through\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20projection_generation\x20WHERE\x20chain_id=$1',[a]);return c['rows'][0x0]?.['reconciled_through']??null;}async['status'](a){if(!a)throw new Error('chainId\x20is\x20required');const [b,c,d,e,f,g,h,i]=await Promise['all']([this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_version\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_current\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_current\x20WHERE\x20chain_id=$1\x20AND\x20state=\x27active\x27',[a]),this['pool']['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20quarantine\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20MAX(checkpoint)::TEXT\x20AS\x20max\x20FROM\x20object_current\x20WHERE\x20chain_id=$1',[a]),this['pool']['query']('SELECT\x20MAX(updated_at)\x20AS\x20max\x20FROM\x20object_current\x20WHERE\x20chain_id=$1',[a]),this['reconciliationSummary'](a),this['reconciledThrough'](a)]),j=numberValue(d['rows'][0x0]['count']);return{'chain_id':a,'raw_versions':numberValue(b['rows'][0x0]['count']),'current_objects':numberValue(c['rows'][0x0]['count']),'active_objects':j,'quarantined_versions':numberValue(e['rows'][0x0]['count']),'max_checkpoint':f['rows'][0x0]['max'],'observed_at':isoValue(g['rows'][0x0]['max']),'coverage':coverage(a,j,![],i),'reconciliations':h};}async['watermarks'](a){if(!a)throw new Error('chainId\x20is\x20required');const b=await this['pool']['query']('SELECT\x20verified_kind,\x20MAX(checkpoint)::TEXT\x20AS\x20max,\x20COUNT(*)::TEXT\x20AS\x20count\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20state=\x27active\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20GROUP\x20BY\x20verified_kind\x20ORDER\x20BY\x20verified_kind',[a]);return b['rows']['map'](c=>({'verified_kind':c['verified_kind'],'max_checkpoint':c['max'],'active_objects':numberValue(c['count'])}));}async['quarantineQueue'](a,b=0x32){if(!a)throw new Error('chainId\x20is\x20required');if(!Number['isInteger'](b)||b<0x1||b>0x1f4)throw new Error('Invalid\x20quarantine\x20limit:\x20'+b);const c=await this['pool']['query']('SELECT\x20q.object_id,\x20q.object_version::TEXT\x20AS\x20object_version,\x20q.reason_code,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20q.first_seen,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20c.object_version::TEXT\x20AS\x20current_version,\x20c.verified_kind\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20quarantine\x20q\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20c.chain_id=q.chain_id\x20AND\x20c.object_id=q.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20q.chain_id=$1\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20q.first_seen\x20DESC\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LIMIT\x20$2',[a,String(b)]),d=c['rows']['map'](e=>{return{'object_id':e['object_id']instanceof Uint8Array?hexBytes(e['object_id'])['toLowerCase']():null,'object_version':e['object_version'],'reason_code':e['reason_code'],'first_seen':isoValue(e['first_seen']),'current_version':e['current_version'],'verified_kind':e['verified_kind'],'blocking':e['current_version']===null||BigInt(e['object_version'])>BigInt(e['current_version'])};});return d['sort']((e,f)=>e['blocking']===f['blocking']?0x0:e['blocking']?-0x1:0x1)['slice'](0x0,b);}async['listCurrent'](a){if(!a['chainId'])throw new Error('chainId\x20is\x20required');if(a['kind']&&!(a['kind']in WOW_OBJECT_TYPE_TAGS))throw new Error('Unknown\x20object\x20kind:\x20'+a['kind']);const b=a['limit']??0x64;if(!Number['isInteger'](b)||b<0x1||b>0x3e8)throw new Error('Invalid\x20list\x20limit:\x20'+b);if(a['shard']){const {count:i,index:j}=a['shard'];if(!Number['isInteger'](i)||i<0x1||!Number['isInteger'](j)||j<0x0||j>=i)throw new Error('Invalid\x20shard\x20selector');}const c=[a['chainId']],d=['c.chain_id=$1','c.state=\x27active\x27'];a['kind']&&(c['push'](a['kind']),d['push']('c.verified_kind=$'+c['length']));a['shard']&&(c['push'](a['shard']['count'],a['shard']['index']),d['push']('c.shard_count=$'+(c['length']-0x1)),d['push']('c.shard_index=$'+c['length']));a['cursor']&&(c['push'](addressBytes(a['cursor'])),d['push']('c.object_id>$'+c['length']));c['push'](b+0x1);const e=await this['pool']['query']('SELECT\x20c.*,\x20v.payload_uri,\x20v.payload_format,\x20v.payload_json,\x20v.owner_kind,\x20v.owner_address\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20object_version\x20v\x20ON\x20v.chain_id=c.chain_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20v.object_id=c.object_id\x20AND\x20v.object_version=c.object_version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20'+d['join']('\x20AND\x20')+'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20c.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LIMIT\x20$'+c['length'],c),f=e['rows']['length']>b,g=e['rows']['slice'](0x0,b),h=await this['reconciledThrough'](a['chainId'],a['kind']);return{'objects':g['map'](k=>({'objectId':hexBytes(k['object_id']),'objectVersion':String(k['object_version']),'kindHint':k['kind_hint'],'verifiedKind':k['verified_kind'],'shardCount':k['shard_count'],'shardIndex':k['shard_index'],'moveType':k['move_type'],'checkpoint':String(k['checkpoint']),'state':k['state'],'payloadHash':hexBytes(k['payload_hash']),'payloadUri':k['payload_uri'],'payloadFormat':k['payload_format'],'payloadJson':k['payload_json']??null,'ownerKind':k['owner_kind'],'ownerAddress':k['owner_address']?hexBytes(k['owner_address']):undefined,'updatedAt':new Date(k['updated_at'])['toISOString']()})),'next_cursor':f?hexBytes(g[g['length']-0x1]['object_id']):null,'coverage':coverage(a['chainId'],g['length'],f,h)};}}
@@ -60,6 +60,15 @@ export interface ProjectionWatermark {
60
60
  max_checkpoint: string | null;
61
61
  active_objects: number;
62
62
  }
63
+ export interface QuarantineEntry {
64
+ object_id: string | null;
65
+ object_version: string;
66
+ reason_code: string;
67
+ first_seen: string | null;
68
+ current_version: string | null;
69
+ verified_kind: WowTypedObjectKind | null;
70
+ blocking: boolean;
71
+ }
63
72
  export interface GraphEdgeView {
64
73
  src: string;
65
74
  srcKind: string;
@@ -69,6 +78,28 @@ export interface GraphEdgeView {
69
78
  objectVersion: string;
70
79
  dstProjected: boolean;
71
80
  }
81
+ export interface AggregateOptions {
82
+ chainId: string;
83
+ group: string;
84
+ groupId?: string;
85
+ metric: string;
86
+ excludeClaimed: boolean;
87
+ limit: number;
88
+ }
89
+ export interface AggregateRow {
90
+ group_id: string;
91
+ count: number;
92
+ metric_sum: string;
93
+ max_checkpoint: string;
94
+ }
95
+ export interface AggregateAnswer {
96
+ rows: AggregateRow[];
97
+ totals: {
98
+ count: number;
99
+ metric_sum: string;
100
+ };
101
+ truncated: boolean;
102
+ }
72
103
  export interface ObjectFacetRow {
73
104
  objectId: string;
74
105
  verifiedKind: string;
@@ -94,6 +125,7 @@ export interface ProjectionStatus {
94
125
  active_objects: number;
95
126
  quarantined_versions: number;
96
127
  max_checkpoint: string | null;
128
+ observed_at: string | null;
97
129
  coverage: ProjectionCoverage;
98
130
  reconciliations: ReconciliationGeneration[];
99
131
  }
@@ -6,9 +6,8 @@ export declare class GraphQLCdcSource implements CdcSource {
6
6
  private readonly graphql;
7
7
  private readonly snapshot;
8
8
  private readonly rpc;
9
- private readonly network;
10
9
  private readonly expectedChainId;
11
- constructor(graphql: WowGraphQLClient, snapshot: GraphQLSnapshotSource, rpc: WowClient, network: ENTRYPOINT, expectedChainId: string);
10
+ constructor(graphql: WowGraphQLClient, snapshot: GraphQLSnapshotSource, rpc: WowClient, expectedChainId: string);
12
11
  static forNetwork(network: ENTRYPOINT, expectedChainId: string): GraphQLCdcSource;
13
12
  head(): Promise<CdcHead>;
14
13
  readChanges(after: string, before: string, kind: string): Promise<CdcChangeBatch>;
@@ -1 +1 @@
1
- import{WowClient,WowGraphQLClient,getFullnodeUrl,getGraphqlUrl,normalizeWowAddress,wowTypedKindFromMoveType}from'@wowok/wowok';import{canonicalChainIdentifier,GraphQLSnapshotSource}from'./graphql-source.js';const CDC_PAGE_QUERY='\x0aquery\x20CdcPage($after:\x20UInt53!,\x20$before:\x20UInt53!,\x20$cursor:\x20String)\x20{\x0a\x20\x20\x20\x20transactions(\x0a\x20\x20\x20\x20\x20\x20\x20\x20filter:\x20{\x20afterCheckpoint:\x20$after,\x20beforeCheckpoint:\x20$before\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20first:\x2050\x0a\x20\x20\x20\x20\x20\x20\x20\x20after:\x20$cursor\x0a\x20\x20\x20\x20)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20pageInfo\x20{\x20hasNextPage\x20endCursor\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20nodes\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20digest\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20effects\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint\x20{\x20sequenceNumber\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objectChanges\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20nodes\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20address\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20idCreated\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20idDeleted\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20outputState\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20asMoveObject\x20{\x20contents\x20{\x20type\x20{\x20repr\x20}\x20}\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20}\x0a}',MAX_TX_PAGES=0xc8;export class GraphQLCdcSource{['graphql'];['snapshot'];['rpc'];['network'];['expectedChainId'];constructor(a,b,c,d,e){this['graphql']=a,this['snapshot']=b,this['rpc']=c,this['network']=d,this['expectedChainId']=e;}static['forNetwork'](a,b){const c=getGraphqlUrl(a);if(!c)throw new Error('No\x20GraphQL\x20endpoint\x20configured\x20for\x20'+a);return new GraphQLCdcSource(new WowGraphQLClient({'url':c,'network':a}),GraphQLSnapshotSource['forNetwork'](a,b),new WowClient({'url':getFullnodeUrl(a),'network':a}),a,b);}async['head'](){const [a,b,c]=await Promise['all']([this['graphql']['core']['getChainIdentifier'](),this['rpc']['getChainIdentifier'](),this['rpc']['getLatestCheckpointSequenceNumber']()]),d=canonicalChainIdentifier(a['chainIdentifier']),e=canonicalChainIdentifier(b),f=canonicalChainIdentifier(this['expectedChainId']);if(d!==e||e!==f)throw new Error('CHAIN_IDENTITY_MISMATCH');return{'chainId':e,'checkpoint':c};}async['readChanges'](a,b,c){const d=BigInt(a),e=BigInt(b);if(e<=d)return{'facts':[],'deletedIds':[],'observedThrough':a,'pages':0x0};const f=canonicalChainIdentifier(this['expectedChainId']),g=new Set(),h=new Set();let i=null,j=0x0,k=a;do{const m=await this['graphql']['query']({'query':CDC_PAGE_QUERY,'variables':{'after':Number(d),'before':Number(e),'cursor':i}});if(m['errors']?.['length'])throw new Error('CDC\x20GraphQL\x20error:\x20'+JSON['stringify'](m['errors'])['slice'](0x0,0x1f4));const n=m['data']?.['transactions'];if(!n)throw new Error('CDC\x20GraphQL\x20returned\x20no\x20transactions\x20connection');for(const o of n['nodes']??[]){const p=o?.['effects']?.['checkpoint']?.['sequenceNumber'];if(p===undefined||p===null)continue;const q=BigInt(p);if(q<=d||q>=e)throw new Error('CDC_INTERVAL_VIOLATION:\x20tx\x20checkpoint\x20'+p+'\x20outside\x20('+d+',\x20'+e+')');if(q>BigInt(k))k=String(q);for(const r of o?.['effects']?.['objectChanges']?.['nodes']??[]){const s=normalizeWowAddress(r['address']);if(r['idDeleted']){h['add'](s);continue;}const t=r['outputState']?.['asMoveObject']?.['contents']?.['type']?.['repr'];if(!t)continue;if(wowTypedKindFromMoveType(t)!==c)continue;g['add'](s);}}j+=0x1,i=n['pageInfo']?.['hasNextPage']?n['pageInfo']['endCursor']:null;}while(i!==null&&j<MAX_TX_PAGES);if(i!==null)throw new Error('CDC_PAGE_CAP:\x20exceeded\x20'+MAX_TX_PAGES+'\x20pages\x20for\x20('+a+',\x20'+b+')');for(const u of h)g['delete'](u);const l=await this['snapshot']['hydrateFacts']([...g],f,k);return{'facts':l,'deletedIds':[...h],'observedThrough':k,'pages':j};}}export class CdcSynchronizer{['projection'];['source'];['cursors'];constructor(a,b,c){this['projection']=a,this['source']=b,this['cursors']=c;}async['run'](a){if(!a['expectedChainId'])throw new Error('expectedChainId\x20is\x20required');if(!a['kind'])throw new Error('kind\x20is\x20required');const b=a['maxSpan']??0x1f4;if(!Number['isInteger'](b)||b<0x1)throw new Error('Invalid\x20maxSpan:\x20'+b);return this['cursors']['withCdcLock'](a['expectedChainId'],a['kind'],()=>this['poll'](a,b));}async['poll'](a,b){const c=a['expectedChainId'],d=await this['source']['head']();if(d['chainId']!==c)throw new Error('CHAIN_IDENTITY_MISMATCH:\x20source\x20reported\x20'+d['chainId']);const e=await this['cursors']['cdcCheckpoint'](c,a['kind']),f={'applied':0x0,'duplicate':0x0,'stale':0x0,'quarantined':0x0,'conflict':0x0,'tombstoned':0x0,'skipped_facts':0x0};if(e===null)return await this['cursors']['setCdcCheckpoint'](c,a['kind'],d['checkpoint']),{'chainId':c,'kind':a['kind'],'anchored':!![],'from':null,'to':d['checkpoint'],'head':d['checkpoint'],'pages':0x0,...f};const g=BigInt(e),h=BigInt(d['checkpoint']);if(h<=g)return{'chainId':c,'kind':a['kind'],'anchored':![],'from':e,'to':e,'head':d['checkpoint'],'pages':0x0,...f};const i=h<g+BigInt(b)?h:g+BigInt(b),j=await this['source']['readChanges'](e,(i+0x1n)['toString'](),a['kind']);for(const l of j['facts']){const m=l;if(!m['object_id']){f['skipped_facts']+=0x1;continue;}const n=await this['projection']['apply'](l);n['status']in f&&(f[n['status']]+=0x1);}for(const o of j['deletedIds']){await this['projection']['markTombstoneIfKind'](c,o,a['kind'])&&(f['tombstoned']+=0x1);}const k=j['observedThrough'];return BigInt(k)>g&&await this['cursors']['setCdcCheckpoint'](c,a['kind'],k),{'chainId':c,'kind':a['kind'],'anchored':![],'from':e,'to':BigInt(k)>g?k:e,'head':d['checkpoint'],'pages':j['pages'],...f};}}
1
+ import{WowClient,WowGraphQLClient,getFullnodeUrl,getGraphqlUrl,normalizeWowAddress,wowTypedKindFromMoveType}from'@wowok/wowok';import{canonicalChainIdentifier,GraphQLSnapshotSource}from'./graphql-source.js';const CDC_PAGE_QUERY='\x0aquery\x20CdcPage($after:\x20UInt53!,\x20$before:\x20UInt53!,\x20$cursor:\x20String)\x20{\x0a\x20\x20\x20\x20transactions(\x0a\x20\x20\x20\x20\x20\x20\x20\x20filter:\x20{\x20afterCheckpoint:\x20$after,\x20beforeCheckpoint:\x20$before\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20first:\x2050\x0a\x20\x20\x20\x20\x20\x20\x20\x20after:\x20$cursor\x0a\x20\x20\x20\x20)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20pageInfo\x20{\x20hasNextPage\x20endCursor\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20nodes\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20digest\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20effects\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint\x20{\x20sequenceNumber\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objectChanges\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20nodes\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20address\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20idCreated\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20idDeleted\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20outputState\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20asMoveObject\x20{\x20contents\x20{\x20type\x20{\x20repr\x20}\x20}\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20}\x0a}',MAX_TX_PAGES=0xc8;function stalledLagCheckpoints(){const a=process['env']['WOWOK_CDC_STALLED_LAG_CHECKPOINTS'];if(a===undefined||a['trim']()==='')return 0x186a0n;const b=Number(a);if(!Number['isInteger'](b)||b<0x0)throw new Error('Invalid\x20WOWOK_CDC_STALLED_LAG_CHECKPOINTS:\x20'+a);return BigInt(b);}export class GraphQLCdcSource{['graphql'];['snapshot'];['rpc'];['expectedChainId'];constructor(a,b,c,d){this['graphql']=a,this['snapshot']=b,this['rpc']=c,this['expectedChainId']=d;}static['forNetwork'](a,b){const c=getGraphqlUrl(a);if(!c)throw new Error('No\x20GraphQL\x20endpoint\x20configured\x20for\x20'+a);return new GraphQLCdcSource(new WowGraphQLClient({'url':c,'network':a}),GraphQLSnapshotSource['forNetwork'](a,b),new WowClient({'url':getFullnodeUrl(a),'network':a}),b);}async['head'](){const [a,b,c]=await Promise['all']([this['graphql']['core']['getChainIdentifier'](),this['rpc']['getChainIdentifier'](),this['rpc']['getLatestCheckpointSequenceNumber']()]),d=canonicalChainIdentifier(a['chainIdentifier']),e=canonicalChainIdentifier(b),f=canonicalChainIdentifier(this['expectedChainId']);if(d!==e||e!==f)throw new Error('CHAIN_IDENTITY_MISMATCH');return{'chainId':e,'checkpoint':c};}async['readChanges'](a,b,c){const d=BigInt(a),e=BigInt(b);if(e<=d)return{'facts':[],'deletedIds':[],'observedThrough':a,'pages':0x0};const f=canonicalChainIdentifier(this['expectedChainId']),g=new Set(),h=new Set();let i=null,j=0x0,k=a;do{const m=await this['graphql']['query']({'query':CDC_PAGE_QUERY,'variables':{'after':Number(d),'before':Number(e),'cursor':i}});if(m['errors']?.['length'])throw new Error('CDC\x20GraphQL\x20error:\x20'+JSON['stringify'](m['errors'])['slice'](0x0,0x1f4));const n=m['data']?.['transactions'];if(!n)throw new Error('CDC\x20GraphQL\x20returned\x20no\x20transactions\x20connection');for(const o of n['nodes']??[]){const p=o?.['effects']?.['checkpoint']?.['sequenceNumber'];if(p===undefined||p===null)continue;const q=BigInt(p);if(q<=d||q>=e)throw new Error('CDC_INTERVAL_VIOLATION:\x20tx\x20checkpoint\x20'+p+'\x20outside\x20('+d+',\x20'+e+')');if(q>BigInt(k))k=String(q);for(const r of o?.['effects']?.['objectChanges']?.['nodes']??[]){const s=normalizeWowAddress(r['address']);if(r['idDeleted']){h['add'](s);continue;}const t=r['outputState']?.['asMoveObject']?.['contents']?.['type']?.['repr'];if(!t)continue;if(wowTypedKindFromMoveType(t)!==c)continue;g['add'](s);}}j+=0x1,i=n['pageInfo']?.['hasNextPage']?n['pageInfo']['endCursor']:null;}while(i!==null&&j<MAX_TX_PAGES);if(i!==null)throw new Error('CDC_PAGE_CAP:\x20exceeded\x20'+MAX_TX_PAGES+'\x20pages\x20for\x20('+a+',\x20'+b+')');for(const u of h)g['delete'](u);const l=await this['snapshot']['hydrateFacts']([...g],f,k);return{'facts':l,'deletedIds':[...h],'observedThrough':k,'pages':j};}}export class CdcSynchronizer{['projection'];['source'];['cursors'];constructor(a,b,c){this['projection']=a,this['source']=b,this['cursors']=c;}async['run'](a){if(!a['expectedChainId'])throw new Error('expectedChainId\x20is\x20required');if(!a['kind'])throw new Error('kind\x20is\x20required');const b=a['maxSpan']??0x1f4;if(!Number['isInteger'](b)||b<0x1)throw new Error('Invalid\x20maxSpan:\x20'+b);if(a['stalledLag']!==undefined&&(!Number['isInteger'](a['stalledLag'])||a['stalledLag']<0x0))throw new Error('Invalid\x20stalledLag:\x20'+a['stalledLag']);const c=a['stalledLag']===undefined?stalledLagCheckpoints():BigInt(a['stalledLag']);return this['cursors']['withCdcLock'](a['expectedChainId'],a['kind'],()=>this['poll'](a,b,c));}async['poll'](a,b,c){const d=a['expectedChainId'],e=await this['source']['head']();if(e['chainId']!==d)throw new Error('CHAIN_IDENTITY_MISMATCH:\x20source\x20reported\x20'+e['chainId']);const f=await this['cursors']['cdcCheckpoint'](d,a['kind']),g={'applied':0x0,'duplicate':0x0,'stale':0x0,'quarantined':0x0,'conflict':0x0,'tombstoned':0x0,'skipped_facts':0x0};if(f===null)return await this['cursors']['setCdcCheckpoint'](d,a['kind'],e['checkpoint']),{'chainId':d,'kind':a['kind'],'anchored':!![],'reanchored_from':null,'from':null,'to':e['checkpoint'],'head':e['checkpoint'],'pages':0x0,...g};const h=BigInt(f),i=BigInt(e['checkpoint']);if(i<=h)return{'chainId':d,'kind':a['kind'],'anchored':![],'reanchored_from':null,'from':f,'to':f,'head':e['checkpoint'],'pages':0x0,...g};if(c>0x0n&&i-h>c)return await this['cursors']['setCdcCheckpoint'](d,a['kind'],e['checkpoint']),{'chainId':d,'kind':a['kind'],'anchored':![],'reanchored_from':f,'from':f,'to':e['checkpoint'],'head':e['checkpoint'],'pages':0x0,...g};const j=i<h+BigInt(b)?i:h+BigInt(b),k=await this['source']['readChanges'](f,(j+0x1n)['toString'](),a['kind']);for(const m of k['facts']){const n=m;if(!n['object_id']){g['skipped_facts']+=0x1;continue;}const o=await this['projection']['apply'](m);o['status']in g&&(g[o['status']]+=0x1);}for(const p of k['deletedIds']){await this['projection']['markTombstoneIfKind'](d,p,a['kind'])&&(g['tombstoned']+=0x1);}const l=k['observedThrough'];return BigInt(l)>h&&await this['cursors']['setCdcCheckpoint'](d,a['kind'],l),{'chainId':d,'kind':a['kind'],'anchored':![],'reanchored_from':null,'from':f,'to':BigInt(l)>h?l:f,'head':e['checkpoint'],'pages':k['pages'],...g};}}
@@ -1 +1 @@
1
- import{toBase58}from'@wowok/wowok';import{DataType,newDb}from'pg-mem';import{afterEach,beforeEach,describe,expect,it,vi}from'vitest';import{PostgresProjectionStore}from'../projection/store.js';import{CdcSynchronizer}from'./cdc.js';import{PostgresSyncStore}from'./store.js';const digest=toBase58(new Uint8Array(0x20)['fill'](0x7));function objectId(a){return'0x14'+a['toString'](0x10)['padStart'](0x2,'0')['repeat'](0x1f);}function fact(a,b={}){return{'chain_id':'chain_a','object_id':objectId(a),'object_version':'1','move_type':'0x2::service::Service<0x2::wow::WOW>','owner_kind':'Shared','payload_uri':'test://raw/service-'+a,'payload_hash':'0x'+'41'['repeat'](0x20),'payload_format':'json+bcs-v1','checkpoint':'100','tx_digest':digest,'state':'active','observed_at':'2026-10-24T00:00:00.000Z',...b};}class FakeCdcSource{['headCheckpoint'];['batches'];['chainId'];['calls']=[];constructor(a,b,c='chain_a'){this['headCheckpoint']=a,this['batches']=b,this['chainId']=c;}async['head'](){return{'chainId':this['chainId'],'checkpoint':this['headCheckpoint']};}async['readChanges'](a,b){this['calls']['push']({'after':a,'before':b});const c=this['batches']['get'](a+':'+b);if(!c)return{'facts':[],'deletedIds':[],'observedThrough':a,'pages':0x0};return c;}}function options(a,b={}){return{'expectedChainId':a['chainId'],'kind':'Service',...b};}describe('CdcSynchronizer',()=>{let a,b,c;beforeEach(async()=>{const e=newDb();e['public']['registerFunction']({'name':'pg_advisory_xact_lock','args':[DataType['integer'],DataType['integer']],'returns':DataType['integer'],'implementation':()=>0x0});const {Pool:f}=e['adapters']['createPg']();c=new f(),a=new PostgresProjectionStore(c,0x10),b=new PostgresSyncStore(c),await a['migrate'](),await b['migrate']();}),afterEach(async()=>{await a?.['close'](),await b?.['close'](),vi['restoreAllMocks']();});function d(e,f){return new FakeCdcSource(e,f??new Map());}it('anchors\x20at\x20head\x20on\x20the\x20first\x20run\x20without\x20applying\x20anything',async()=>{const e=d('120'),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'anchored':!![],'from':null,'to':'120','applied':0x0}),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('120'),expect(await a['status']('chain_a'))['toMatchObject']({'active_objects':0x0});}),it('applies\x20facts\x20in\x20the\x20interval\x20and\x20advances\x20to\x20observedThrough',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('150',new Map([['100:151',{'facts':[fact(0x1),fact(0x2,{'object_version':'2','checkpoint':'140'})],'deletedIds':[],'observedThrough':'140','pages':0x2}]])),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'anchored':![],'from':'100','to':'140','head':'150','applied':0x2,'pages':0x2}),expect(e['calls'])['toEqual']([{'after':'100','before':'151'}]),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('140'),expect(await a['status']('chain_a'))['toMatchObject']({'active_objects':0x2});}),it('clamps\x20the\x20interval\x20to\x20maxSpan\x20and\x20requests\x20the\x20half-open\x20bound',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('1000');await new CdcSynchronizer(a,e,b)['run'](options(e,{'maxSpan':0x32})),expect(e['calls'])['toEqual']([{'after':'100','before':'151'}]),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('100');}),it('is\x20a\x20no-op\x20when\x20head\x20has\x20not\x20advanced',async()=>{await b['setCdcCheckpoint']('chain_a','Service','150');const e=d('150'),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'from':'150','to':'150','applied':0x0}),expect(e['calls'])['toEqual']([]);}),it('replays\x20idempotently\x20after\x20a\x20crash\x20between\x20apply\x20and\x20cursor\x20advance',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=new Map([['100:102',{'facts':[fact(0x1)],'deletedIds':[],'observedThrough':'101','pages':0x1}]]),f=new FakeCdcSource('101',e),g=new CdcSynchronizer(a,f,b),h=await g['run'](options(f));expect(h['applied'])['toBe'](0x1),await c['query']('UPDATE\x20cdc_cursor\x20SET\x20checkpoint=100\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2',['chain_a','Service']);const i=await g['run'](options(f));expect(i)['toMatchObject']({'applied':0x0,'duplicate':0x1,'to':'101'}),expect(await a['status']('chain_a'))['toMatchObject']({'active_objects':0x1,'raw_versions':0x1});}),it('tombstones\x20kind-matched\x20deletions\x20only',async()=>{await a['apply'](fact(0x1));const e='0x12'+'02'['repeat'](0x1f);await a['apply'](fact(0x2,{'object_id':e,'move_type':'0x2::arb::Arb','payload_uri':'test://raw/arb-2'})),await b['setCdcCheckpoint']('chain_a','Service','100');const f=d('120',new Map([['100:121',{'facts':[],'deletedIds':[objectId(0x1),e,objectId(0x3)],'observedThrough':'120','pages':0x1}]])),g=await new CdcSynchronizer(a,f,b)['run'](options(f));expect(g['tombstoned'])['toBe'](0x1);const h=await a['listCurrent']({'chainId':'chain_a','kind':'Service'});expect(h['objects'])['toHaveLength'](0x0);const i=await a['listCurrent']({'chainId':'chain_a','kind':'Arb'});expect(i['objects'])['toHaveLength'](0x1);}),it('keeps\x20the\x20cursor\x20forward-only\x20when\x20the\x20source\x20reports\x20stale\x20intervals',async()=>{await b['setCdcCheckpoint']('chain_a','Service','150');const e=d('120'),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'from':'150','to':'150','head':'120'}),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('150');}),it('does\x20not\x20advance\x20past\x20what\x20the\x20source\x20returned',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('150',new Map([['100:151',{'facts':[],'deletedIds':[],'observedThrough':'130','pages':0x1}]])),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f['to'])['toBe']('130'),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('130');});});
1
+ import{toBase58}from'@wowok/wowok';import{DataType,newDb}from'pg-mem';import{afterEach,beforeEach,describe,expect,it,vi}from'vitest';import{PostgresProjectionStore}from'../projection/store.js';import{CdcSynchronizer}from'./cdc.js';import{PostgresSyncStore}from'./store.js';const digest=toBase58(new Uint8Array(0x20)['fill'](0x7));function objectId(a){return'0x14'+a['toString'](0x10)['padStart'](0x2,'0')['repeat'](0x1f);}function fact(a,b={}){return{'chain_id':'chain_a','object_id':objectId(a),'object_version':'1','move_type':'0x2::service::Service<0x2::wow::WOW>','owner_kind':'Shared','payload_uri':'test://raw/service-'+a,'payload_hash':'0x'+'41'['repeat'](0x20),'payload_format':'json+bcs-v1','checkpoint':'100','tx_digest':digest,'state':'active','observed_at':'2026-10-24T00:00:00.000Z',...b};}class FakeCdcSource{['headCheckpoint'];['batches'];['chainId'];['calls']=[];constructor(a,b,c='chain_a'){this['headCheckpoint']=a,this['batches']=b,this['chainId']=c;}async['head'](){return{'chainId':this['chainId'],'checkpoint':this['headCheckpoint']};}async['readChanges'](a,b){this['calls']['push']({'after':a,'before':b});const c=this['batches']['get'](a+':'+b);if(!c)return{'facts':[],'deletedIds':[],'observedThrough':a,'pages':0x0};return c;}}function options(a,b={}){return{'expectedChainId':a['chainId'],'kind':'Service',...b};}describe('CdcSynchronizer',()=>{let a,b,c;beforeEach(async()=>{const e=newDb();e['public']['registerFunction']({'name':'pg_advisory_xact_lock','args':[DataType['integer'],DataType['integer']],'returns':DataType['integer'],'implementation':()=>0x0});const {Pool:f}=e['adapters']['createPg']();c=new f(),a=new PostgresProjectionStore(c,0x10),b=new PostgresSyncStore(c),await a['migrate'](),await b['migrate']();}),afterEach(async()=>{await a?.['close'](),await b?.['close'](),vi['restoreAllMocks']();});function d(e,f){return new FakeCdcSource(e,f??new Map());}it('anchors\x20at\x20head\x20on\x20the\x20first\x20run\x20without\x20applying\x20anything',async()=>{const e=d('120'),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'anchored':!![],'from':null,'to':'120','applied':0x0}),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('120'),expect(await a['status']('chain_a'))['toMatchObject']({'active_objects':0x0});}),it('re-anchors\x20a\x20stranded\x20cursor\x20instead\x20of\x20grinding\x20empty\x20intervals',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('2000'),f=await new CdcSynchronizer(a,e,b)['run'](options(e,{'stalledLag':0x1f4}));expect(f)['toMatchObject']({'anchored':![],'reanchored_from':'100','from':'100','to':'2000','applied':0x0}),expect(e['calls'])['toEqual']([]),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('2000');}),it('grinds\x20a\x20lagged\x20cursor\x20when\x20the\x20stall\x20threshold\x20is\x20disabled',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('2000'),f=await new CdcSynchronizer(a,e,b)['run'](options(e,{'stalledLag':0x0,'maxSpan':0x32}));expect(f)['toMatchObject']({'reanchored_from':null,'to':'100'}),expect(e['calls'])['toEqual']([{'after':'100','before':'151'}]);}),it('applies\x20facts\x20in\x20the\x20interval\x20and\x20advances\x20to\x20observedThrough',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('150',new Map([['100:151',{'facts':[fact(0x1),fact(0x2,{'object_version':'2','checkpoint':'140'})],'deletedIds':[],'observedThrough':'140','pages':0x2}]])),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'anchored':![],'from':'100','to':'140','head':'150','applied':0x2,'pages':0x2}),expect(e['calls'])['toEqual']([{'after':'100','before':'151'}]),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('140'),expect(await a['status']('chain_a'))['toMatchObject']({'active_objects':0x2});}),it('clamps\x20the\x20interval\x20to\x20maxSpan\x20and\x20requests\x20the\x20half-open\x20bound',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('1000');await new CdcSynchronizer(a,e,b)['run'](options(e,{'maxSpan':0x32})),expect(e['calls'])['toEqual']([{'after':'100','before':'151'}]),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('100');}),it('is\x20a\x20no-op\x20when\x20head\x20has\x20not\x20advanced',async()=>{await b['setCdcCheckpoint']('chain_a','Service','150');const e=d('150'),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'from':'150','to':'150','applied':0x0}),expect(e['calls'])['toEqual']([]);}),it('replays\x20idempotently\x20after\x20a\x20crash\x20between\x20apply\x20and\x20cursor\x20advance',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=new Map([['100:102',{'facts':[fact(0x1)],'deletedIds':[],'observedThrough':'101','pages':0x1}]]),f=new FakeCdcSource('101',e),g=new CdcSynchronizer(a,f,b),h=await g['run'](options(f));expect(h['applied'])['toBe'](0x1),await c['query']('UPDATE\x20cdc_cursor\x20SET\x20checkpoint=100\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2',['chain_a','Service']);const i=await g['run'](options(f));expect(i)['toMatchObject']({'applied':0x0,'duplicate':0x1,'to':'101'}),expect(await a['status']('chain_a'))['toMatchObject']({'active_objects':0x1,'raw_versions':0x1});}),it('tombstones\x20kind-matched\x20deletions\x20only',async()=>{await a['apply'](fact(0x1));const e='0x12'+'02'['repeat'](0x1f);await a['apply'](fact(0x2,{'object_id':e,'move_type':'0x2::arb::Arb','payload_uri':'test://raw/arb-2'})),await b['setCdcCheckpoint']('chain_a','Service','100');const f=d('120',new Map([['100:121',{'facts':[],'deletedIds':[objectId(0x1),e,objectId(0x3)],'observedThrough':'120','pages':0x1}]])),g=await new CdcSynchronizer(a,f,b)['run'](options(f));expect(g['tombstoned'])['toBe'](0x1);const h=await a['listCurrent']({'chainId':'chain_a','kind':'Service'});expect(h['objects'])['toHaveLength'](0x0);const i=await a['listCurrent']({'chainId':'chain_a','kind':'Arb'});expect(i['objects'])['toHaveLength'](0x1);}),it('keeps\x20the\x20cursor\x20forward-only\x20when\x20the\x20source\x20reports\x20stale\x20intervals',async()=>{await b['setCdcCheckpoint']('chain_a','Service','150');const e=d('120'),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f)['toMatchObject']({'from':'150','to':'150','head':'120'}),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('150');}),it('does\x20not\x20advance\x20past\x20what\x20the\x20source\x20returned',async()=>{await b['setCdcCheckpoint']('chain_a','Service','100');const e=d('150',new Map([['100:151',{'facts':[],'deletedIds':[],'observedThrough':'130','pages':0x1}]])),f=await new CdcSynchronizer(a,e,b)['run'](options(e));expect(f['to'])['toBe']('130'),expect(await b['cdcCheckpoint']('chain_a','Service'))['toBe']('130');});});
@@ -13,6 +13,11 @@ export declare class PostgresSyncStore {
13
13
  private verifyPageLedger;
14
14
  fail(chainId: string, stream: string, runId: string, error: unknown): Promise<void>;
15
15
  status(chainId: string): Promise<SyncRun[]>;
16
+ cdcCursors(chainId: string): Promise<Array<{
17
+ kind: string;
18
+ checkpoint: string;
19
+ updated_at: string;
20
+ }>>;
16
21
  cdcCheckpoint(chainId: string, kind: string): Promise<string | null>;
17
22
  setCdcCheckpoint(chainId: string, kind: string, checkpoint: string): Promise<void>;
18
23
  withCdcLock<T>(chainId: string, kind: string, work: () => Promise<T>): Promise<T>;
@@ -1 +1 @@
1
- import{createHash,randomUUID}from'node:crypto';import{toHex,wowAddressToBytes}from'@wowok/wowok';import{Pool}from'pg';import{SYNC_SCHEMA_SQL}from'./schema.js';function addressBytes(a){return Buffer['from'](wowAddressToBytes(a));}function hexBytes(a){return'0x'+toHex(a);}function checkpointValue(a){if(!/^\d+$/['test'](a))throw new Error('Invalid\x20checkpoint:\x20'+a);const b=BigInt(a);if(b>0x7fffffffffffffffn)throw new Error('Checkpoint\x20exceeds\x20PostgreSQL\x20BIGINT');return b;}function validateScope(a){if(!a['shard'])return;const {count:b,index:c}=a['shard'];if(!Number['isInteger'](b)||b<0x1||!Number['isInteger'](c)||c<0x0||c>=b)throw new Error('Invalid\x20shard\x20selector');}function sameScope(a,b){return a['kind']===b['kind']&&a['shard']?.['count']===b['shard']?.['count']&&a['shard']?.['index']===b['shard']?.['index'];}function mapRun(a,b=![]){return{'chainId':a['chain_id'],'stream':a['stream'],'runId':a['run_id'],'state':a['state'],'scope':{'kind':a['scope_kind']??undefined,'shard':a['shard_count']===null||a['shard_count']===undefined?undefined:{'count':Number(a['shard_count']),'index':Number(a['shard_index'])}},'cursor':a['cursor'],'checkpoint':a['checkpoint']===null||a['checkpoint']===undefined?null:String(a['checkpoint']),'pages':Number(a['pages']),'objects':Number(a['objects']),'startedAt':new Date(a['started_at'])['toISOString'](),'updatedAt':new Date(a['updated_at'])['toISOString'](),'completedAt':a['completed_at']?new Date(a['completed_at'])['toISOString']():null,'error':a['error'],'resumed':b};}export class PostgresSyncStore{['pool'];constructor(a){this['pool']=a;}static['fromDatabaseUrl'](a){return new PostgresSyncStore(new Pool({'connectionString':a}));}async['migrate'](){await this['pool']['query'](SYNC_SCHEMA_SQL);}async['close'](){await this['pool']['end']();}async['locked'](a,b,c){const d=await this['pool']['connect']();try{await d['query']('BEGIN');const e=createHash('sha256')['update'](a+':'+b)['digest']();await d['query']('SELECT\x20pg_advisory_xact_lock($1,\x20$2)',[e['readInt32BE'](0x0),e['readInt32BE'](0x4)]);const f=await c(d);return await d['query']('COMMIT'),f;}catch(g){await d['query']('ROLLBACK');throw g;}finally{d['release']();}}async['start'](a){if(!a['chainId']||!a['stream'])throw new Error('chainId\x20and\x20stream\x20are\x20required');return validateScope(a['scope']),checkpointValue(a['checkpoint']),this['locked'](a['chainId'],a['stream'],async b=>{const c=await b['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),d=c['rows'][0x0];if(d?.['checkpoint']!==null&&d?.['checkpoint']!==undefined&&checkpointValue(String(d['checkpoint']))>checkpointValue(a['checkpoint']))throw new Error('CHAIN_CHECKPOINT_REGRESSION');const e=d?.['state']==='failed'&&typeof d['error']==='string'&&d['error']['startsWith']('NON_STABLE_SNAPSHOT');if(d&&d['state']!=='complete'&&!e){const h=mapRun(d)['scope'];if(!sameScope(h,a['scope']))throw new Error('Cannot\x20resume\x20a\x20sync\x20run\x20with\x20a\x20different\x20scope');const i=await b['query']('UPDATE\x20sync_run\x20SET\x20state=\x27running\x27,\x20error=NULL,\x20updated_at=$3\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20RETURNING\x20*',[a['chainId'],a['stream'],new Date()['toISOString']()]);return mapRun(i['rows'][0x0],!![]);}d&&(await b['query']('DELETE\x20FROM\x20sync_seen\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),await b['query']('DELETE\x20FROM\x20sync_page\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]));const f=new Date()['toISOString'](),g=await b['query']('INSERT\x20INTO\x20sync_run\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20stream,\x20run_id,\x20state,\x20scope_kind,\x20shard_count,\x20shard_index,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor,\x20checkpoint,\x20pages,\x20objects,\x20started_at,\x20updated_at,\x20completed_at,\x20error\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,\x27running\x27,$4,$5,$6,NULL,$7,0,0,$8,$8,NULL,NULL)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20stream)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20run_id=EXCLUDED.run_id,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20state=EXCLUDED.state,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20scope_kind=EXCLUDED.scope_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_count=EXCLUDED.shard_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_index=EXCLUDED.shard_index,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor=EXCLUDED.cursor,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=EXCLUDED.checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20pages=EXCLUDED.pages,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objects=EXCLUDED.objects,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20started_at=EXCLUDED.started_at,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20completed_at=EXCLUDED.completed_at,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20error=EXCLUDED.error\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20RETURNING\x20*',[a['chainId'],a['stream'],randomUUID(),a['scope']['kind']??null,a['scope']['shard']?.['count']??null,a['scope']['shard']?.['index']??null,a['checkpoint'],f]);return mapRun(g['rows'][0x0]);});}async['savePage'](a){return checkpointValue(a['checkpoint']),this['locked'](a['chainId'],a['stream'],async b=>{const c=await b['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),d=c['rows'][0x0];if(!d||d['run_id']!==a['runId']||d['state']!=='running')throw new Error('Sync\x20run\x20is\x20not\x20active');if(d['checkpoint']!==null&&checkpointValue(String(d['checkpoint']))>checkpointValue(a['checkpoint']))throw new Error('CHAIN_CHECKPOINT_REGRESSION');for(const f of a['objects']){const g=addressBytes(f['objectId']);await b['query']('INSERT\x20INTO\x20sync_seen\x20(chain_id,\x20stream,\x20run_id,\x20object_id,\x20object_version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4,$5)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20stream,\x20object_id)\x20DO\x20NOTHING',[a['chainId'],a['stream'],a['runId'],g,f['objectVersion']['toString']()]);const h=await b['query']('SELECT\x20object_version\x20FROM\x20sync_seen\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20object_id=$3',[a['chainId'],a['stream'],g]);if(BigInt(String(h['rows'][0x0]['object_version']))!==f['objectVersion'])throw new Error('NON_STABLE_SNAPSHOT:\x20'+f['objectId']);}const e=await b['query']('UPDATE\x20sync_run\x20SET\x20cursor=$4,\x20checkpoint=$5,\x20pages=pages+1,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objects=objects+$6,\x20updated_at=$7\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3\x20RETURNING\x20*',[a['chainId'],a['stream'],a['runId'],a['cursor'],a['checkpoint'],a['objects']['length'],new Date()['toISOString']()]);return await b['query']('INSERT\x20INTO\x20sync_page\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20stream,\x20run_id,\x20page_seq,\x20checkpoint,\x20objects,\x20cursor,\x20created_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20stream,\x20run_id,\x20page_seq)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=EXCLUDED.checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objects=EXCLUDED.objects,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor=EXCLUDED.cursor,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20created_at=EXCLUDED.created_at',[a['chainId'],a['stream'],a['runId'],Number(d['pages'])+0x1,a['checkpoint'],a['objects']['length'],a['cursor'],new Date()['toISOString']()]),mapRun(e['rows'][0x0],!![]);});}async['complete'](a){return this['locked'](a['chainId'],a['stream'],async b=>{const c=await b['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),d=c['rows'][0x0];if(!d||d['run_id']!==a['runId']||d['state']!=='running')throw new Error('Sync\x20run\x20is\x20not\x20active');const e=mapRun(d);await this['verifyPageLedger'](b,a['chainId'],a['stream'],e);const f=[a['chainId'],a['stream'],a['runId']],g=['c.chain_id=$1','c.state=\x27active\x27','s.object_id\x20IS\x20NULL'];e['scope']['kind']&&(f['push'](e['scope']['kind']),g['push']('c.verified_kind=$'+f['length']));e['scope']['shard']&&(f['push'](e['scope']['shard']['count'],e['scope']['shard']['index']),g['push']('c.shard_count=$'+(f['length']-0x1)),g['push']('c.shard_index=$'+f['length']));const h='FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20sync_seen\x20s\x20ON\x20s.chain_id=c.chain_id\x20AND\x20s.stream=$2\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20s.run_id=$3\x20AND\x20s.object_id=c.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20'+g['join']('\x20AND\x20'),i=await b['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20'+h,f),j=await b['query']('SELECT\x20c.object_id\x20'+h+'\x20ORDER\x20BY\x20c.object_id\x20LIMIT\x201000',f),k=[a['chainId']],l=['chain_id=$1','state=\x27active\x27'];e['scope']['kind']&&(k['push'](e['scope']['kind']),l['push']('verified_kind=$'+k['length']));e['scope']['shard']&&(k['push'](e['scope']['shard']['count'],e['scope']['shard']['index']),l['push']('shard_count=$'+(k['length']-0x1)),l['push']('shard_index=$'+k['length']));const m=await b['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_current\x20WHERE\x20'+l['join']('\x20AND\x20'),k),n=await b['query']('UPDATE\x20sync_run\x20SET\x20state=\x27complete\x27,\x20completed_at=$4,\x20updated_at=$4,\x20error=NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3\x20RETURNING\x20*',[a['chainId'],a['stream'],a['runId'],new Date()['toISOString']()]),o=j['rows']['slice'](0x0,0x3e8),p=new Set(a['degradedReasons']??[]);p['add']('SNAPSHOT_NOT_CHECKPOINT_PINNED'),p['add']('INCREMENTAL_CDC_REQUIRED');const q=Number(i['rows'][0x0]['count']);if(q>0x0)p['add']('LIVE_SET_MISSING');return{'run':mapRun(n['rows'][0x0],!![]),'enumeration_complete':!![],'current_active':Number(m['rows'][0x0]['count']),'missing_objects':q,'missing_object_ids':o['map'](r=>hexBytes(r['object_id'])),'missing_truncated':q>o['length'],'coverage':{'mode':'known_objects','complete':![],'truncated':![],'total_enumerated':e['objects'],'chain_id':a['chainId'],'reconciled_through':null,'degraded_reasons':[...p]}};});}async['verifyPageLedger'](a,b,c,d){const e=await a['query']('SELECT\x20page_seq,\x20checkpoint\x20FROM\x20sync_page\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3\x20ORDER\x20BY\x20page_seq',[b,c,d['runId']]),f=e['rows'];if(f['length']!==d['pages'])throw new Error('CHECKPOINT_GAP_DETECTED:\x20page\x20ledger\x20has\x20'+f['length']+'\x20rows\x20but\x20run\x20recorded\x20'+d['pages']+'\x20pages');let g=null;for(let h=0x0;h<f['length'];h+=0x1){const i=Number(f[h]['page_seq']);if(i!==h+0x1)throw new Error('CHECKPOINT_GAP_DETECTED:\x20page\x20ledger\x20sequence\x20break\x20at\x20position\x20'+(h+0x1)+'\x20(found\x20'+i+')');const j=checkpointValue(String(f[h]['checkpoint']));if(g!==null&&j<g)throw new Error('CHECKPOINT_GAP_DETECTED:\x20page\x20'+i+'\x20checkpoint\x20'+j+'\x20regressed\x20below\x20'+g);g=j;}}async['fail'](a,b,c,d){const e=(d instanceof Error?d['message']:String(d))['slice'](0x0,0xfa0);await this['locked'](a,b,async f=>{await f['query']('UPDATE\x20sync_run\x20SET\x20state=\x27failed\x27,\x20error=$4,\x20updated_at=$5\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3',[a,b,c,e,new Date()['toISOString']()]);});}async['status'](a){const b=await this['pool']['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20ORDER\x20BY\x20stream',[a]);return b['rows']['map'](c=>mapRun(c));}async['cdcCheckpoint'](a,b){const c=await this['pool']['query']('SELECT\x20checkpoint::TEXT\x20AS\x20checkpoint\x20FROM\x20cdc_cursor\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2',[a,b]);return c['rows'][0x0]?.['checkpoint']??null;}async['setCdcCheckpoint'](a,b,c){await this['pool']['query']('INSERT\x20INTO\x20cdc_cursor\x20(chain_id,\x20kind,\x20checkpoint,\x20updated_at)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20kind)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=GREATEST(cdc_cursor.checkpoint,\x20EXCLUDED.checkpoint),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at',[a,b,checkpointValue(c),new Date()['toISOString']()]);}async['withCdcLock'](a,b,c){return this['locked'](a,'cdc:'+b,async()=>c());}}
1
+ import{createHash,randomUUID}from'node:crypto';import{toHex,wowAddressToBytes}from'@wowok/wowok';import{Pool}from'pg';import{SYNC_SCHEMA_SQL}from'./schema.js';function addressBytes(a){return Buffer['from'](wowAddressToBytes(a));}function hexBytes(a){return'0x'+toHex(a);}function checkpointValue(a){if(!/^\d+$/['test'](a))throw new Error('Invalid\x20checkpoint:\x20'+a);const b=BigInt(a);if(b>0x7fffffffffffffffn)throw new Error('Checkpoint\x20exceeds\x20PostgreSQL\x20BIGINT');return b;}function validateScope(a){if(!a['shard'])return;const {count:b,index:c}=a['shard'];if(!Number['isInteger'](b)||b<0x1||!Number['isInteger'](c)||c<0x0||c>=b)throw new Error('Invalid\x20shard\x20selector');}function sameScope(a,b){return a['kind']===b['kind']&&a['shard']?.['count']===b['shard']?.['count']&&a['shard']?.['index']===b['shard']?.['index'];}function mapRun(a,b=![]){return{'chainId':a['chain_id'],'stream':a['stream'],'runId':a['run_id'],'state':a['state'],'scope':{'kind':a['scope_kind']??undefined,'shard':a['shard_count']===null||a['shard_count']===undefined?undefined:{'count':Number(a['shard_count']),'index':Number(a['shard_index'])}},'cursor':a['cursor'],'checkpoint':a['checkpoint']===null||a['checkpoint']===undefined?null:String(a['checkpoint']),'pages':Number(a['pages']),'objects':Number(a['objects']),'startedAt':new Date(a['started_at'])['toISOString'](),'updatedAt':new Date(a['updated_at'])['toISOString'](),'completedAt':a['completed_at']?new Date(a['completed_at'])['toISOString']():null,'error':a['error'],'resumed':b};}export class PostgresSyncStore{['pool'];constructor(a){this['pool']=a;}static['fromDatabaseUrl'](a){return new PostgresSyncStore(new Pool({'connectionString':a}));}async['migrate'](){await this['pool']['query'](SYNC_SCHEMA_SQL);}async['close'](){await this['pool']['end']();}async['locked'](a,b,c){const d=await this['pool']['connect']();try{await d['query']('BEGIN');const e=createHash('sha256')['update'](a+':'+b)['digest']();await d['query']('SELECT\x20pg_advisory_xact_lock($1,\x20$2)',[e['readInt32BE'](0x0),e['readInt32BE'](0x4)]);const f=await c(d);return await d['query']('COMMIT'),f;}catch(g){await d['query']('ROLLBACK');throw g;}finally{d['release']();}}async['start'](a){if(!a['chainId']||!a['stream'])throw new Error('chainId\x20and\x20stream\x20are\x20required');return validateScope(a['scope']),checkpointValue(a['checkpoint']),this['locked'](a['chainId'],a['stream'],async b=>{const c=await b['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),d=c['rows'][0x0];if(d?.['checkpoint']!==null&&d?.['checkpoint']!==undefined&&checkpointValue(String(d['checkpoint']))>checkpointValue(a['checkpoint']))throw new Error('CHAIN_CHECKPOINT_REGRESSION');const e=d?.['state']==='failed'&&typeof d['error']==='string'&&d['error']['startsWith']('NON_STABLE_SNAPSHOT');if(d&&d['state']!=='complete'&&!e){const h=mapRun(d)['scope'];if(!sameScope(h,a['scope']))throw new Error('Cannot\x20resume\x20a\x20sync\x20run\x20with\x20a\x20different\x20scope');const i=await b['query']('UPDATE\x20sync_run\x20SET\x20state=\x27running\x27,\x20error=NULL,\x20updated_at=$3\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20RETURNING\x20*',[a['chainId'],a['stream'],new Date()['toISOString']()]);return mapRun(i['rows'][0x0],!![]);}d&&(await b['query']('DELETE\x20FROM\x20sync_seen\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),await b['query']('DELETE\x20FROM\x20sync_page\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]));const f=new Date()['toISOString'](),g=await b['query']('INSERT\x20INTO\x20sync_run\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20stream,\x20run_id,\x20state,\x20scope_kind,\x20shard_count,\x20shard_index,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor,\x20checkpoint,\x20pages,\x20objects,\x20started_at,\x20updated_at,\x20completed_at,\x20error\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,\x27running\x27,$4,$5,$6,NULL,$7,0,0,$8,$8,NULL,NULL)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20stream)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20run_id=EXCLUDED.run_id,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20state=EXCLUDED.state,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20scope_kind=EXCLUDED.scope_kind,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_count=EXCLUDED.shard_count,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shard_index=EXCLUDED.shard_index,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor=EXCLUDED.cursor,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=EXCLUDED.checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20pages=EXCLUDED.pages,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objects=EXCLUDED.objects,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20started_at=EXCLUDED.started_at,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20completed_at=EXCLUDED.completed_at,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20error=EXCLUDED.error\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20RETURNING\x20*',[a['chainId'],a['stream'],randomUUID(),a['scope']['kind']??null,a['scope']['shard']?.['count']??null,a['scope']['shard']?.['index']??null,a['checkpoint'],f]);return mapRun(g['rows'][0x0]);});}async['savePage'](a){return checkpointValue(a['checkpoint']),this['locked'](a['chainId'],a['stream'],async b=>{const c=await b['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),d=c['rows'][0x0];if(!d||d['run_id']!==a['runId']||d['state']!=='running')throw new Error('Sync\x20run\x20is\x20not\x20active');if(d['checkpoint']!==null&&checkpointValue(String(d['checkpoint']))>checkpointValue(a['checkpoint']))throw new Error('CHAIN_CHECKPOINT_REGRESSION');for(const f of a['objects']){const g=addressBytes(f['objectId']);await b['query']('INSERT\x20INTO\x20sync_seen\x20(chain_id,\x20stream,\x20run_id,\x20object_id,\x20object_version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4,$5)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20stream,\x20object_id)\x20DO\x20NOTHING',[a['chainId'],a['stream'],a['runId'],g,f['objectVersion']['toString']()]);const h=await b['query']('SELECT\x20object_version\x20FROM\x20sync_seen\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20object_id=$3',[a['chainId'],a['stream'],g]);if(BigInt(String(h['rows'][0x0]['object_version']))!==f['objectVersion'])throw new Error('NON_STABLE_SNAPSHOT:\x20'+f['objectId']);}const e=await b['query']('UPDATE\x20sync_run\x20SET\x20cursor=$4,\x20checkpoint=$5,\x20pages=pages+1,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objects=objects+$6,\x20updated_at=$7\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3\x20RETURNING\x20*',[a['chainId'],a['stream'],a['runId'],a['cursor'],a['checkpoint'],a['objects']['length'],new Date()['toISOString']()]);return await b['query']('INSERT\x20INTO\x20sync_page\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20chain_id,\x20stream,\x20run_id,\x20page_seq,\x20checkpoint,\x20objects,\x20cursor,\x20created_at\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x20VALUES\x20($1,$2,$3,$4,$5,$6,$7,$8)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20stream,\x20run_id,\x20page_seq)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=EXCLUDED.checkpoint,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20objects=EXCLUDED.objects,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor=EXCLUDED.cursor,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20created_at=EXCLUDED.created_at',[a['chainId'],a['stream'],a['runId'],Number(d['pages'])+0x1,a['checkpoint'],a['objects']['length'],a['cursor'],new Date()['toISOString']()]),mapRun(e['rows'][0x0],!![]);});}async['complete'](a){return this['locked'](a['chainId'],a['stream'],async b=>{const c=await b['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2',[a['chainId'],a['stream']]),d=c['rows'][0x0];if(!d||d['run_id']!==a['runId']||d['state']!=='running')throw new Error('Sync\x20run\x20is\x20not\x20active');const e=mapRun(d);await this['verifyPageLedger'](b,a['chainId'],a['stream'],e);const f=[a['chainId'],a['stream'],a['runId']],g=['c.chain_id=$1','c.state=\x27active\x27','s.object_id\x20IS\x20NULL'];e['scope']['kind']&&(f['push'](e['scope']['kind']),g['push']('c.verified_kind=$'+f['length']));e['scope']['shard']&&(f['push'](e['scope']['shard']['count'],e['scope']['shard']['index']),g['push']('c.shard_count=$'+(f['length']-0x1)),g['push']('c.shard_index=$'+f['length']));const h='FROM\x20object_current\x20c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20sync_seen\x20s\x20ON\x20s.chain_id=c.chain_id\x20AND\x20s.stream=$2\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20s.run_id=$3\x20AND\x20s.object_id=c.object_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20'+g['join']('\x20AND\x20'),i=await b['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20'+h,f),j=await b['query']('SELECT\x20c.object_id\x20'+h+'\x20ORDER\x20BY\x20c.object_id\x20LIMIT\x201000',f),k=[a['chainId']],l=['chain_id=$1','state=\x27active\x27'];e['scope']['kind']&&(k['push'](e['scope']['kind']),l['push']('verified_kind=$'+k['length']));e['scope']['shard']&&(k['push'](e['scope']['shard']['count'],e['scope']['shard']['index']),l['push']('shard_count=$'+(k['length']-0x1)),l['push']('shard_index=$'+k['length']));const m=await b['query']('SELECT\x20COUNT(*)::TEXT\x20AS\x20count\x20FROM\x20object_current\x20WHERE\x20'+l['join']('\x20AND\x20'),k),n=await b['query']('UPDATE\x20sync_run\x20SET\x20state=\x27complete\x27,\x20completed_at=$4,\x20updated_at=$4,\x20error=NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3\x20RETURNING\x20*',[a['chainId'],a['stream'],a['runId'],new Date()['toISOString']()]),o=j['rows']['slice'](0x0,0x3e8),p=new Set(a['degradedReasons']??[]);p['add']('SNAPSHOT_NOT_CHECKPOINT_PINNED'),p['add']('INCREMENTAL_CDC_REQUIRED');const q=Number(i['rows'][0x0]['count']);if(q>0x0)p['add']('LIVE_SET_MISSING');return{'run':mapRun(n['rows'][0x0],!![]),'enumeration_complete':!![],'current_active':Number(m['rows'][0x0]['count']),'missing_objects':q,'missing_object_ids':o['map'](r=>hexBytes(r['object_id'])),'missing_truncated':q>o['length'],'coverage':{'mode':'known_objects','complete':![],'truncated':![],'total_enumerated':e['objects'],'chain_id':a['chainId'],'reconciled_through':null,'degraded_reasons':[...p]}};});}async['verifyPageLedger'](a,b,c,d){const e=await a['query']('SELECT\x20page_seq,\x20checkpoint\x20FROM\x20sync_page\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3\x20ORDER\x20BY\x20page_seq',[b,c,d['runId']]),f=e['rows'];if(f['length']!==d['pages'])throw new Error('CHECKPOINT_GAP_DETECTED:\x20page\x20ledger\x20has\x20'+f['length']+'\x20rows\x20but\x20run\x20recorded\x20'+d['pages']+'\x20pages');let g=null;for(let h=0x0;h<f['length'];h+=0x1){const i=Number(f[h]['page_seq']);if(i!==h+0x1)throw new Error('CHECKPOINT_GAP_DETECTED:\x20page\x20ledger\x20sequence\x20break\x20at\x20position\x20'+(h+0x1)+'\x20(found\x20'+i+')');const j=checkpointValue(String(f[h]['checkpoint']));if(g!==null&&j<g)throw new Error('CHECKPOINT_GAP_DETECTED:\x20page\x20'+i+'\x20checkpoint\x20'+j+'\x20regressed\x20below\x20'+g);g=j;}}async['fail'](a,b,c,d){const e=(d instanceof Error?d['message']:String(d))['slice'](0x0,0xfa0);await this['locked'](a,b,async f=>{await f['query']('UPDATE\x20sync_run\x20SET\x20state=\x27failed\x27,\x20error=$4,\x20updated_at=$5\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20chain_id=$1\x20AND\x20stream=$2\x20AND\x20run_id=$3',[a,b,c,e,new Date()['toISOString']()]);});}async['status'](a){const b=await this['pool']['query']('SELECT\x20*\x20FROM\x20sync_run\x20WHERE\x20chain_id=$1\x20ORDER\x20BY\x20stream',[a]);return b['rows']['map'](c=>mapRun(c));}async['cdcCursors'](a){const b=await this['pool']['query']('SELECT\x20kind,\x20checkpoint::TEXT\x20AS\x20checkpoint,\x20updated_at\x20FROM\x20cdc_cursor\x20WHERE\x20chain_id=$1\x20ORDER\x20BY\x20kind',[a]);return b['rows'];}async['cdcCheckpoint'](a,b){const c=await this['pool']['query']('SELECT\x20checkpoint::TEXT\x20AS\x20checkpoint\x20FROM\x20cdc_cursor\x20WHERE\x20chain_id=$1\x20AND\x20kind=$2',[a,b]);return c['rows'][0x0]?.['checkpoint']??null;}async['setCdcCheckpoint'](a,b,c){await this['pool']['query']('INSERT\x20INTO\x20cdc_cursor\x20(chain_id,\x20kind,\x20checkpoint,\x20updated_at)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20($1,$2,$3,$4)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT\x20(chain_id,\x20kind)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20checkpoint=GREATEST(cdc_cursor.checkpoint,\x20EXCLUDED.checkpoint),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20updated_at=EXCLUDED.updated_at',[a,b,checkpointValue(c),new Date()['toISOString']()]);}async['withCdcLock'](a,b,c){return this['locked'](a,'cdc:'+b,async()=>c());}}
@@ -143,11 +143,13 @@ export interface RunCdcOptions {
143
143
  expectedChainId: string;
144
144
  kind: string;
145
145
  maxSpan?: number;
146
+ stalledLag?: number;
146
147
  }
147
148
  export interface CdcRoundResult {
148
149
  chainId: string;
149
150
  kind: string;
150
151
  anchored: boolean;
152
+ reanchored_from: string | null;
151
153
  from: string | null;
152
154
  to: string | null;
153
155
  head: string;
@@ -2,17 +2,25 @@ import type { EvaluationRule } from "./types.js";
2
2
  export declare const PRESENTER_HISTORY_KEY = "presenter_history";
3
3
  export interface PresenterAcceptanceRecord {
4
4
  demand_id?: string;
5
+ presenter?: string;
6
+ presenter_service?: string;
5
7
  acceptance_score: number | null;
6
8
  feedback_time?: number;
7
9
  }
10
+ export declare const COUNTERPARTY_LIKE_THRESHOLD = 60;
8
11
  export interface AcceptanceSummary {
9
12
  score: number | null;
10
13
  rated: number;
11
14
  total: number;
12
15
  average: number | null;
16
+ clamped: number;
13
17
  }
14
18
  export declare function summarizeAcceptance(records: PresenterAcceptanceRecord[]): AcceptanceSummary;
15
19
  export declare function presenterHistoryFromEntities(entities: Record<string, unknown>): PresenterAcceptanceRecord[];
20
+ export declare function applyCounterpartyFeedback<T extends {
21
+ object: string;
22
+ }>(services: T[], records: PresenterAcceptanceRecord[]): T[];
23
+ export declare function recordsForService(records: PresenterAcceptanceRecord[], serviceObject: string | undefined | null): PresenterAcceptanceRecord[];
16
24
  export interface AcceptanceRuleOptions {
17
25
  weight: number;
18
26
  weightOf?: () => number;
@@ -1 +1 @@
1
- export const PRESENTER_HISTORY_KEY='presenter_history';export function summarizeAcceptance(a){const b=a['map'](d=>d['acceptance_score'])['filter'](d=>typeof d==='number'&&Number['isFinite'](d))['map'](d=>Math['max'](0x0,Math['min'](0x64,d)));if(b['length']===0x0)return{'score':null,'rated':0x0,'total':a['length'],'average':null};const c=b['reduce']((d,e)=>d+e,0x0)/b['length'];return{'score':Math['round'](c),'rated':b['length'],'total':a['length'],'average':Math['round'](c*0x64)/0x64};}export function presenterHistoryFromEntities(a){const b=a[PRESENTER_HISTORY_KEY];if(!Array['isArray'](b))return[];return b['filter'](c=>typeof c==='object'&&c!==null&&c['acceptance_score']!==undefined);}export function createAcceptanceRule(a,b){return{'id':'acceptance','description':'Presenter\x20historical\x20acceptance\x20score\x20backflow\x20(demand-side\x20feedback)','dimension':b['dimension']??'acceptance',get 'weight'(){return b['weightOf']?.()??b['weight'];},'evaluation_ids':[a],'evaluate':c=>{const d=b['weightOf']?.()??b['weight'],e=summarizeAcceptance(presenterHistoryFromEntities(c['entities']));if(e['score']===null)return{'score':0x32,'weight':d,'reason':e['total']>0x0?'acceptance:\x20'+e['total']+'\x20presentation(s),\x20none\x20rated\x20(neutral)':'acceptance:\x20no\x20history\x20(neutral)'};const f=b['redFlag']!==undefined&&e['rated']>=b['redFlag']['minRated']&&e['average']!==null&&e['average']<b['redFlag']['below'];return{'score':e['score'],'weight':d,'reason':'acceptance\x20avg\x20'+e['average']+'\x20over\x20'+e['rated']+'\x20rated\x20presentation(s)','red_flag':f||undefined};}};}
1
+ export const PRESENTER_HISTORY_KEY='presenter_history';export const COUNTERPARTY_LIKE_THRESHOLD=0x3c;export function summarizeAcceptance(a){let b=0x0;const c=a['map'](f=>f['acceptance_score'])['filter'](f=>typeof f==='number'&&Number['isFinite'](f)),d=c['map'](f=>{const g=Math['max'](0x0,Math['min'](0x64,f));if(g!==f)b+=0x1;return g;});if(d['length']===0x0)return{'score':null,'rated':0x0,'total':a['length'],'average':null,'clamped':0x0};const e=d['reduce']((f,g)=>f+g,0x0)/d['length'];return{'score':Math['round'](e),'rated':d['length'],'total':a['length'],'average':Math['round'](e*0x64)/0x64,'clamped':b};}function clampNote(a){return a['clamped']>0x0?';\x20'+a['clamped']+'\x20raw\x20score(s)\x20outside\x20the\x20documented\x200-100\x20scale\x20were\x20clamped\x20(the\x20chain\x20does\x20not\x20range-check\x20acceptance_score\x20—\x20raw\x20data\x20degraded)':'';}export function presenterHistoryFromEntities(a){const b=a[PRESENTER_HISTORY_KEY];if(!Array['isArray'](b))return[];return b['filter'](c=>typeof c==='object'&&c!==null&&c['acceptance_score']!==undefined);}export function applyCounterpartyFeedback(a,b){const c=new Map(),d=(e,f)=>{if(typeof e!=='string'||e==='')return;const g=e['toLowerCase'](),h=c['get'](g);if(h)h['push'](f);else c['set'](g,[f]);};for(const e of b){d(e['presenter_service'],e),d(e['presenter'],e);}if(c['size']===0x0)return a;return a['map'](f=>{const g=c['get'](f['object']['toLowerCase']());if(!g||g['length']===0x0)return f;const h=g['map'](j=>j['acceptance_score'])['filter'](j=>typeof j==='number'&&Number['isFinite'](j))['map'](j=>Math['max'](0x0,Math['min'](0x64,j)));if(h['length']===0x0)return f;const i=h['filter'](j=>j>=COUNTERPARTY_LIKE_THRESHOLD)['length'];return{...f,'buyer_feedback':{'total':h['length'],'likes':i}};});}export function recordsForService(a,b){if(typeof b!=='string'||b==='')return[];const c=b['toLowerCase']();return a['filter'](d=>typeof d['presenter_service']==='string'&&d['presenter_service']['toLowerCase']()===c||typeof d['presenter']==='string'&&d['presenter']['toLowerCase']()===c);}export function createAcceptanceRule(a,b){return{'id':'acceptance','description':'Presenter\x20historical\x20acceptance\x20score\x20backflow\x20(demand-side\x20feedback)','dimension':b['dimension']??'acceptance',get 'weight'(){return b['weightOf']?.()??b['weight'];},'evaluation_ids':[a],'evaluate':c=>{const d=b['weightOf']?.()??b['weight'],e=c['entities']?.['service'],f=presenterHistoryFromEntities(c['entities']);let g=e?recordsForService(f,e['object']):f;e&&g['length']===0x0&&!f['some'](k=>typeof k['presenter']==='string'||typeof k['presenter_service']==='string')&&(g=f);const h=summarizeAcceptance(g);if(e&&h['rated']===0x0&&h['total']===0x0){const k=f['filter'](l=>typeof l['presenter']==='string'||typeof l['presenter_service']==='string')['length'];return{'score':0x32,'weight':d,'reason':h['total']===0x0?'acceptance:\x20no\x20history\x20for\x20this\x20candidate\x20(neutral'+(k>0x0?'\x20—\x20'+k+'\x20batch\x20record(s)\x20belong\x20to\x20other\x20presenters,\x20matched\x20'+g['length']:';\x20no\x20history')+')':'acceptance:\x20'+h['total']+'\x20presentation(s)\x20for\x20this\x20candidate,\x20none\x20rated\x20(neutral)'};}if(h['score']===null)return{'score':0x32,'weight':d,'reason':h['total']>0x0?'acceptance:\x20'+h['total']+'\x20presentation(s),\x20none\x20rated\x20(neutral)'+clampNote(h):'acceptance:\x20no\x20history\x20(neutral)'};const i=b['redFlag']!==undefined&&h['rated']>=b['redFlag']['minRated']&&h['average']!==null&&h['average']<b['redFlag']['below'],j=e?'':'\x20(global\x20baseline\x20—\x20no\x20candidate\x20identity\x20in\x20context)';return{'score':h['score'],'weight':d,'reason':'acceptance\x20avg\x20'+h['average']+'\x20over\x20'+h['rated']+'\x20rated\x20presentation(s)'+j+clampNote(h),'red_flag':i||undefined};}};}
@@ -1 +1 @@
1
- import{createAcceptanceRule}from'../acceptance.js';import{requiredCapabilities}from'../capability.js';import{getEvaluationEngine}from'../engine.js';import{extractDemandCapability,extractServiceCapability}from'../extract.js';import{relateRegion}from'../region.js';import{getJudgmentDoc}from'../../config/judgment.js';export const DEMAND_MATCH_EVALUATION='demand_match';function matchParams(){return getJudgmentDoc()['match'];}const dsCaps={'id':'ds_caps','description':'Extract\x20demand\x20+\x20service\x20capability\x20vectors\x20(either\x20may\x20be\x20pre-computed\x20or\x20raw)','evaluation_ids':[DEMAND_MATCH_EVALUATION],'extract':a=>({'demand_cap':a['entities']['demand_cap']??extractDemandCapability(a['entities']['demand']),'service_cap':a['entities']['service_cap']??extractServiceCapability(a['entities']['service'])})},regionRule={'id':'region','description':'Geographic\x20region\x20relation\x20between\x20demand\x20and\x20service','dimension':'region',get 'weight'(){return matchParams()['weights']['region'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'],f=relateRegion(c['region'],e['region']);return{'score':b['region_scores'][f],'weight':b['weights']['region'],'reason':'region\x20'+f};}},industryRule={'id':'industry','description':'Industry\x20scenario\x20match','dimension':'industry',get 'weight'(){return matchParams()['weights']['industry'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'];if(c['industry']==='general'||e['industry']==='general')return{'score':b['neutral_score'],'weight':b['weights']['industry'],'reason':'industry\x20unknown\x20(neutral)'};const f=c['industry']===e['industry']?0x64:0x0;return{'score':f,'weight':b['weights']['industry'],'reason':c['industry']+'\x20vs\x20'+e['industry']};}},priceRule={'id':'price','description':'Service\x20price\x20within\x20demand\x20budget','dimension':'price',get 'weight'(){return matchParams()['weights']['price'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'];if(c['price_max']===undefined||e['price_min']===undefined)return{'score':b['neutral_score'],'weight':b['weights']['price'],'reason':'price\x20unknown\x20(neutral)'};if(e['price_min']<=c['price_max'])return{'score':0x64,'weight':b['weights']['price'],'reason':'within\x20budget'};const f=c['price_max']*BigInt(Math['round'](0x64+b['price_over_budget_tolerance_pct']))/0x64n;if(e['price_min']<=f)return{'score':b['neutral_score'],'weight':b['weights']['price'],'reason':'slightly\x20over\x20budget'};return{'score':0x0,'weight':b['weights']['price'],'reason':'over\x20budget'};}},trustRule={'id':'trust','description':'Service\x20trust\x20score','dimension':'trust',get 'weight'(){return matchParams()['weights']['trust'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['service_cap'],d=c['trust_score'],e=b['trust_bands']['find'](h=>d>=h['min']),f=e?e['score']:0x0,g=c['trust_provenance']==='cold_start_prior'?'trust\x20'+d+'\x20(cold-start\x20prior\x20—\x20no\x20verified\x20reputation\x20yet)':'trust\x20'+d;return{'score':f,'weight':b['weights']['trust'],'reason':g};}},capabilitiesRule={'id':'capabilities','description':'Demand\x20capability\x20requirements\x20covered\x20by\x20the\x20service','dimension':'capabilities',get 'weight'(){return matchParams()['weights']['capabilities'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'],f=requiredCapabilities(c['capabilities']);if(f['length']===0x0)return{'score':b['neutral_score'],'weight':b['weights']['capabilities'],'reason':'no\x20capability\x20requirement\x20(neutral)'};const g=f['filter'](h=>e['capabilities'][h]);return{'score':Math['round'](g['length']/f['length']*0x64),'weight':b['weights']['capabilities'],'matched':g,'mismatched':f['filter'](h=>!e['capabilities'][h]),'reason':g['length']+'/'+f['length']+'\x20required\x20capabilities\x20covered'};}},tagsRule={'id':'tags','description':'Keyword/tag\x20overlap','dimension':'tags',get 'weight'(){return matchParams()['weights']['tags'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'],f=new Set((c['keywords']??[])['map'](i=>i['toLowerCase']())),g=new Set([...e['tags']??[],...e['keywords']??[]]['map'](i=>i['toLowerCase']()));if(f['size']===0x0)return{'score':b['neutral_score'],'weight':b['weights']['tags'],'reason':'no\x20keywords\x20(neutral)'};const h=[...f]['filter'](i=>g['has'](i))['length'];return{'score':Math['round'](h/f['size']*0x64),'weight':b['weights']['tags'],'reason':h+'/'+f['size']+'\x20keywords'};}},acceptanceRule=createAcceptanceRule(DEMAND_MATCH_EVALUATION,{'weight':matchParams()['weights']['acceptance'],'weightOf':()=>matchParams()['weights']['acceptance']});export function registerDemandMatchEvaluation(a=getEvaluationEngine()){a['registerDataSource'](dsCaps);for(const b of[regionRule,industryRule,priceRule,trustRule,capabilitiesRule,tagsRule,acceptanceRule]){a['registerRule'](b);}}export async function matchDemandToServices(a,b,c,d,e){const f=d??matchParams()['top_n'],g=getEvaluationEngine(),h=await Promise['all'](b['map'](async i=>({'service':i,'result':await g['evaluate'](DEMAND_MATCH_EVALUATION,{'demand_cap':a,'service':i,'presenter_history':e??[]},c)})));return h['sort']((i,j)=>j['result']['total']-i['result']['total']||i['service']['object']['localeCompare'](j['service']['object'])),h['slice'](0x0,f);}export async function matchServiceToDemands(a,b,c,d,e){const f=d??matchParams()['top_n'],g=getEvaluationEngine(),h=await Promise['all'](b['map'](async i=>({'demand':i,'result':await g['evaluate'](DEMAND_MATCH_EVALUATION,{'service_cap':a,'demand':i,'presenter_history':e??[]},c)})));return h['sort']((i,j)=>j['result']['total']-i['result']['total']||i['demand']['object']['localeCompare'](j['demand']['object'])),h['slice'](0x0,f);}
1
+ import{createAcceptanceRule,applyCounterpartyFeedback}from'../acceptance.js';import{requiredCapabilities}from'../capability.js';import{getEvaluationEngine}from'../engine.js';import{extractDemandCapability,extractServiceCapability}from'../extract.js';import{relateRegion}from'../region.js';import{findSimilarIndustries}from'../../knowledge/industry-generalizer.js';import{getIndustryProfile}from'../../knowledge/industry-registry.js';import{getJudgmentDoc}from'../../config/judgment.js';export const DEMAND_MATCH_EVALUATION='demand_match';function matchParams(){return getJudgmentDoc()['match'];}const dsCaps={'id':'ds_caps','description':'Extract\x20demand\x20+\x20service\x20capability\x20vectors\x20(either\x20may\x20be\x20pre-computed\x20or\x20raw)','evaluation_ids':[DEMAND_MATCH_EVALUATION],'extract':a=>({'demand_cap':a['entities']['demand_cap']??extractDemandCapability(a['entities']['demand']),'service_cap':a['entities']['service_cap']??extractServiceCapability(a['entities']['service'])})},regionRule={'id':'region','description':'Geographic\x20region\x20relation\x20between\x20demand\x20and\x20service','dimension':'region',get 'weight'(){return matchParams()['weights']['region'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'],f=relateRegion(c['region'],e['region']);return{'score':b['region_scores'][f],'weight':b['weights']['region'],'reason':'region\x20'+f};}},industryRule={'id':'industry','description':'Industry\x20scenario\x20match','dimension':'industry',get 'weight'(){return matchParams()['weights']['industry'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'];if(c['industry']==='general'||e['industry']==='general')return{'score':b['neutral_score'],'weight':b['weights']['industry'],'reason':'industry\x20unknown\x20(neutral)'};if(c['industry']===e['industry'])return{'score':0x64,'weight':b['weights']['industry'],'reason':c['industry']+'\x20exact\x20match'};const f=getIndustryProfile(c['industry'])?.['traits'],g=getIndustryProfile(e['industry'])?.['traits'];if(!f||!g)return{'score':b['neutral_score'],'weight':b['weights']['industry'],'reason':c['industry']+'\x20vs\x20'+e['industry']+'\x20(unregistered\x20industry\x20profile\x20—\x20neutral)'};const h=findSimilarIndustries(f,0x80)['find'](k=>k['industry']===e['industry']),i=h?.['similarity']??0x0,j=i>=0.8?0x55:i>=0.5?b['neutral_score']:0x0;return{'score':j,'weight':b['weights']['industry'],'reason':c['industry']+'\x20vs\x20'+e['industry']+':\x20trait\x20similarity\x20'+i['toFixed'](0x2)};}},priceRule={'id':'price','description':'Service\x20price\x20within\x20demand\x20budget','dimension':'price',get 'weight'(){return matchParams()['weights']['price'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'];if(c['price_max']===undefined||e['price_min']===undefined)return{'score':b['neutral_score'],'weight':b['weights']['price'],'reason':'price\x20unknown\x20(neutral)'};const f=c['price_max'],g=e['price_min'];if(g*0x5n<=f*0x4n)return{'score':0x64,'weight':b['weights']['price'],'reason':'within\x20budget\x20('+g+'\x20≤\x2080%\x20of\x20the\x20'+f+'\x20cap)'};if(g<=f)return{'score':0x55,'weight':b['weights']['price'],'reason':'within\x20budget\x20('+g+'\x20in\x20the\x2080–100%\x20band\x20of\x20the\x20'+f+'\x20cap)'};const h=f*BigInt(Math['round'](0x64+b['price_over_budget_tolerance_pct']))/0x64n;if(g<=h)return{'score':b['neutral_score'],'weight':b['weights']['price'],'reason':'slightly\x20over\x20budget\x20(tolerance\x20band)'};return{'score':0x0,'weight':b['weights']['price'],'reason':'over\x20budget'};}},trustRule={'id':'trust','description':'Service\x20trust\x20score','dimension':'trust',get 'weight'(){return matchParams()['weights']['trust'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['service_cap'],d=c['trust_score'],e=b['trust_bands']['find'](h=>d>=h['min']),f=e?e['score']:0x0,g=c['trust_provenance']==='cold_start_prior'?'trust\x20'+d+'\x20(cold-start\x20prior\x20—\x20no\x20verified\x20reputation\x20yet)':'trust\x20'+d;return{'score':f,'weight':b['weights']['trust'],'reason':g};}},capabilitiesRule={'id':'capabilities','description':'Demand\x20capability\x20requirements\x20covered\x20by\x20the\x20service','dimension':'capabilities',get 'weight'(){return matchParams()['weights']['capabilities'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'],f=requiredCapabilities(c['capabilities']);if(f['length']===0x0)return{'score':b['neutral_score'],'weight':b['weights']['capabilities'],'reason':'no\x20capability\x20requirement\x20(neutral)'};const g=f['filter'](h=>e['capabilities'][h]);return{'score':Math['round'](g['length']/f['length']*0x64),'weight':b['weights']['capabilities'],'matched':g,'mismatched':f['filter'](h=>!e['capabilities'][h]),'reason':g['length']+'/'+f['length']+'\x20required\x20capabilities\x20covered'};}},buyableRule={'id':'buyable','description':'Catalog\x20buyability\x20—\x20the\x20F-RQ-01\x20dead-SKU\x20gate\x20(64-byte\x20on-chain\x20quote\x20limit)','dimension':'buyable',get 'weight'(){return matchParams()['weights']['buyable']??0xf;},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const c=matchParams(),d=a['facts']['service_cap'],e=d['buyable'];if(!e||e['total_skus']===0x0)return{'score':c['neutral_score'],'weight':c['weights']['buyable']??0xf,'reason':'SKU\x20buyability\x20unknown\x20(no\x20catalog\x20read)\x20—\x20neutral'};if(e['purchasable_skus']===0x0)return{'score':0x0,'weight':c['weights']['buyable']??0xf,'reason':'NO\x20purchasable\x20SKU:\x20'+e['dead_skus']+'/'+e['total_skus']+'\x20name(s)\x20exceed\x20the\x20on-chain\x20'+'64-byte\x20buy\x20limit\x20—\x20the\x20Service\x20quotes\x20fine\x20but\x20EVERY\x20order\x20aborts\x20'+'E_NAME_LENGTH_EXCEEDED\x20(abort\x201,\x20F-RQ-01);\x20dead\x20storefront'};return{'score':0x64,'weight':c['weights']['buyable']??0xf,'reason':e['purchasable_skus']+'/'+e['total_skus']+'\x20SKU(s)\x20pass\x20the\x2064-byte\x20buy\x20gate'+(e['dead_skus']>0x0?'\x20('+e['dead_skus']+'\x20dead\x20over-limit\x20SKU(s)\x20excluded)':'')};}},tagsRule={'id':'tags','description':'Keyword/tag\x20overlap','dimension':'tags',get 'weight'(){return matchParams()['weights']['tags'];},'evaluation_ids':[DEMAND_MATCH_EVALUATION],'evaluate':a=>{const b=matchParams(),c=a['facts']['demand_cap'],e=a['facts']['service_cap'],f=new Set((c['keywords']??[])['map'](i=>i['toLowerCase']())),g=new Set([...e['tags']??[],...e['keywords']??[]]['map'](i=>i['toLowerCase']()));if(f['size']===0x0)return{'score':b['neutral_score'],'weight':b['weights']['tags'],'reason':'no\x20keywords\x20(neutral)'};const h=[...f]['filter'](i=>g['has'](i))['length'];return{'score':Math['round'](h/f['size']*0x64),'weight':b['weights']['tags'],'reason':h+'/'+f['size']+'\x20keywords'};}},acceptanceRule=createAcceptanceRule(DEMAND_MATCH_EVALUATION,{'weight':matchParams()['weights']['acceptance'],'weightOf':()=>matchParams()['weights']['acceptance']});export function registerDemandMatchEvaluation(a=getEvaluationEngine()){a['registerDataSource'](dsCaps);for(const b of[regionRule,industryRule,priceRule,trustRule,capabilitiesRule,buyableRule,tagsRule,acceptanceRule]){a['registerRule'](b);}}export async function matchDemandToServices(a,b,c,d,e){const f=d??matchParams()['top_n'],g=applyCounterpartyFeedback(b,e??[]),h=getEvaluationEngine(),i=await Promise['all'](g['map'](async k=>({'service':k,'result':await h['evaluate'](DEMAND_MATCH_EVALUATION,{'demand_cap':a,'service':k,'presenter_history':e??[]},c)}))),j=k=>Number(k['result']['blocked']||k['service']['bPublished']===![]);return i['sort']((k,l)=>j(k)-j(l)||l['result']['total']-k['result']['total']||k['service']['object']['localeCompare'](l['service']['object'])),i['slice'](0x0,f);}export async function matchServiceToDemands(a,b,c,d,e){const f=d??matchParams()['top_n'],g=getEvaluationEngine(),h=await Promise['all'](b['map'](async i=>({'demand':i,'result':await g['evaluate'](DEMAND_MATCH_EVALUATION,{'service_cap':a,'demand':i,'presenter_history':e??[]},c)})));return h['sort']((i,j)=>Number(i['result']['blocked'])-Number(j['result']['blocked'])||j['result']['total']-i['result']['total']||i['demand']['object']['localeCompare'](j['demand']['object'])),h['slice'](0x0,f);}