@wowok/agent-mcp 3.3.8 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/dist/chain-semantics/field-capability.js +1 -1
  2. package/dist/chain-semantics/freeze-map.js +1 -1
  3. package/dist/chain-semantics/fund-flow.js +1 -1
  4. package/dist/chain-semantics/guard-verbs.js +1 -1
  5. package/dist/chain-semantics/object-graph.js +1 -1
  6. package/dist/composition/audit.js +1 -1
  7. package/dist/composition/compile.d.ts +3 -2
  8. package/dist/composition/compile.js +1 -1
  9. package/dist/composition/inflight.d.ts +6 -0
  10. package/dist/composition/inflight.js +1 -1
  11. package/dist/composition/materialize.d.ts +4 -0
  12. package/dist/composition/materialize.js +1 -1
  13. package/dist/composition/param-disclosure.d.ts +61 -0
  14. package/dist/composition/param-disclosure.js +1 -0
  15. package/dist/composition/plan.d.ts +11 -1
  16. package/dist/composition/plan.js +1 -1
  17. package/dist/customer/account-events.js +1 -1
  18. package/dist/data/api/api.spec.js +1 -1
  19. package/dist/data/api/cli.js +1 -1
  20. package/dist/data/api/server.d.ts +1 -0
  21. package/dist/data/api/server.js +1 -1
  22. package/dist/data/projection/store.d.ts +2 -1
  23. package/dist/data/projection/store.js +1 -1
  24. package/dist/data/projection/types.d.ts +10 -0
  25. package/dist/data/sync/cdc.js +1 -1
  26. package/dist/data/sync/cdc.spec.js +1 -1
  27. package/dist/data/sync/store.d.ts +5 -0
  28. package/dist/data/sync/store.js +1 -1
  29. package/dist/data/sync/types.d.ts +2 -0
  30. package/dist/evaluation/builtins/graph-service.spec.js +1 -1
  31. package/dist/evaluation/engine.js +1 -1
  32. package/dist/evaluation/guard-scan.js +1 -1
  33. package/dist/experience/realtime-feedback.js +1 -1
  34. package/dist/extensions/business-modules.js +1 -1
  35. package/dist/extensions/industry-pack.js +1 -1
  36. package/dist/extensions/modes.js +1 -1
  37. package/dist/graph/onchain/expand.js +1 -1
  38. package/dist/graph/onchain/exposure.js +1 -1
  39. package/dist/harness/recover.js +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/knowledge/allocation-risk.js +1 -1
  42. package/dist/knowledge/allocation-templates.js +1 -1
  43. package/dist/knowledge/allocator-rail-verifier.js +1 -1
  44. package/dist/knowledge/arb-fund-facts.d.ts +1 -0
  45. package/dist/knowledge/arb-fund-facts.js +1 -1
  46. package/dist/knowledge/arbitration-ledger.js +1 -1
  47. package/dist/knowledge/arbitration-risk.d.ts +1 -0
  48. package/dist/knowledge/arbitration-risk.js +1 -1
  49. package/dist/knowledge/audit-rules.js +1 -1
  50. package/dist/knowledge/baselines/rules/allocation.json +6 -6
  51. package/dist/knowledge/baselines/rules/arb.json +2 -2
  52. package/dist/knowledge/baselines/rules/guard.json +11 -11
  53. package/dist/knowledge/baselines/rules/order.json +1 -1
  54. package/dist/knowledge/baselines/rules/plan.json +1 -1
  55. package/dist/knowledge/baselines/semantic-facts.js +1 -1
  56. package/dist/knowledge/builtin-templates.d.ts +14 -1
  57. package/dist/knowledge/builtin-templates.js +1 -1
  58. package/dist/knowledge/catalog-facts.d.ts +4 -0
  59. package/dist/knowledge/catalog-facts.js +1 -0
  60. package/dist/knowledge/commission-landing.js +1 -1
  61. package/dist/knowledge/component-schema.d.ts +64 -0
  62. package/dist/knowledge/component-schema.js +1 -0
  63. package/dist/knowledge/entity-recipient-guard.js +1 -1
  64. package/dist/knowledge/event-semantics.js +1 -1
  65. package/dist/knowledge/fee-param-bindings.d.ts +26 -0
  66. package/dist/knowledge/fee-param-bindings.js +1 -0
  67. package/dist/knowledge/fund-layer.js +1 -1
  68. package/dist/knowledge/getting-started.d.ts +2 -2
  69. package/dist/knowledge/getting-started.js +1 -1
  70. package/dist/knowledge/guard-anchor-reach.js +1 -1
  71. package/dist/knowledge/guard-design-patterns.js +1 -1
  72. package/dist/knowledge/guard-ledger.js +1 -1
  73. package/dist/knowledge/guard-lint.d.ts +1 -0
  74. package/dist/knowledge/guard-lint.js +1 -1
  75. package/dist/knowledge/guard-puzzle.js +1 -1
  76. package/dist/knowledge/guard-risk.js +1 -1
  77. package/dist/knowledge/guard-templates.d.ts +1 -1
  78. package/dist/knowledge/guard-templates.js +1 -1
  79. package/dist/knowledge/guard-translation.js +1 -1
  80. package/dist/knowledge/index.js +1 -1
  81. package/dist/knowledge/industry-registry.js +1 -1
  82. package/dist/knowledge/industry-strategy.js +1 -1
  83. package/dist/knowledge/jsonrpc-enum.d.ts +14 -3
  84. package/dist/knowledge/jsonrpc-enum.js +1 -1
  85. package/dist/knowledge/knob-docs.d.ts +5 -0
  86. package/dist/knowledge/knob-docs.js +1 -0
  87. package/dist/knowledge/machine-templates.js +1 -1
  88. package/dist/knowledge/machine-topology.js +1 -1
  89. package/dist/knowledge/machine-translation.js +1 -1
  90. package/dist/knowledge/onchain-constants.d.ts +2 -0
  91. package/dist/knowledge/onchain-constants.js +1 -1
  92. package/dist/knowledge/order-ledger.js +1 -1
  93. package/dist/knowledge/param-schema.d.ts +70 -0
  94. package/dist/knowledge/param-schema.js +1 -0
  95. package/dist/knowledge/param-tiers.d.ts +25 -0
  96. package/dist/knowledge/param-tiers.js +1 -0
  97. package/dist/knowledge/passport-ledger.d.ts +1 -1
  98. package/dist/knowledge/passport-ledger.js +1 -1
  99. package/dist/knowledge/pattern-resolutions.d.ts +106 -0
  100. package/dist/knowledge/pattern-resolutions.js +1 -0
  101. package/dist/knowledge/projection.spec.js +1 -1
  102. package/dist/knowledge/safety-rules.js +1 -1
  103. package/dist/knowledge/scenario-modes.d.ts +1 -0
  104. package/dist/knowledge/scenario-modes.js +1 -1
  105. package/dist/knowledge/scenario-topology.js +1 -1
  106. package/dist/knowledge/service-allocation-semantics.js +1 -1
  107. package/dist/knowledge/service-ledger.js +1 -1
  108. package/dist/knowledge/service-templates.js +1 -1
  109. package/dist/knowledge/strategy-manuals.d.ts +1 -1
  110. package/dist/knowledge/strategy-manuals.js +1 -1
  111. package/dist/knowledge/template-loader.d.ts +101 -1
  112. package/dist/knowledge/template-loader.js +1 -1
  113. package/dist/knowledge/template-nav.d.ts +7 -0
  114. package/dist/knowledge/template-nav.js +1 -0
  115. package/dist/knowledge/template-registry.js +1 -1
  116. package/dist/knowledge/template-scanner.d.ts +33 -0
  117. package/dist/knowledge/template-scanner.js +1 -1
  118. package/dist/knowledge/template-test-profiles.d.ts +17 -0
  119. package/dist/knowledge/template-test-profiles.js +1 -0
  120. package/dist/knowledge/template-validation.d.ts +1 -0
  121. package/dist/knowledge/template-validation.js +1 -1
  122. package/dist/knowledge/tools-reference.js +1 -1
  123. package/dist/knowledge/treasury-templates.js +1 -1
  124. package/dist/knowledge/workflow-guidance.js +1 -1
  125. package/dist/monitor/MonitorLoop.js +1 -1
  126. package/dist/participation/time-window.d.ts +37 -0
  127. package/dist/participation/time-window.js +1 -0
  128. package/dist/playbooks/service-build/business-puzzle.js +1 -1
  129. package/dist/playbooks/service-build/machine-panorama.d.ts +1 -0
  130. package/dist/playbooks/service-build/machine-panorama.js +1 -1
  131. package/dist/playbooks/service-build/merchant-guide.d.ts +4 -1
  132. package/dist/playbooks/service-build/merchant-guide.js +1 -1
  133. package/dist/playbooks/service-build/migration-planner.js +1 -1
  134. package/dist/playbooks/service-build/object-panorama.js +1 -1
  135. package/dist/playbooks/service-build/participation-radar.d.ts +1 -0
  136. package/dist/playbooks/service-build/participation-radar.js +1 -1
  137. package/dist/playbooks/service-build/relationship-profile.js +1 -1
  138. package/dist/playbooks/service-build/service-panorama.d.ts +1 -0
  139. package/dist/playbooks/service-build/service-panorama.js +1 -1
  140. package/dist/playbooks/service-build/service-quote.js +1 -1
  141. package/dist/playbooks/service-build/service-quote.spec.js +1 -1
  142. package/dist/playbooks/service-build/workflow-design-assessment.js +1 -1
  143. package/dist/relationship/registry.js +1 -1
  144. package/dist/review/index.js +1 -1
  145. package/dist/runtime/instance-registry.d.ts +7 -1
  146. package/dist/runtime/instance-registry.js +1 -1
  147. package/dist/safety/confirm-gate.js +1 -1
  148. package/dist/schema/benchmark-migration/index.d.ts +2 -0
  149. package/dist/schema/benchmark-migration/index.js +1 -1
  150. package/dist/schema/call/allocation.js +1 -1
  151. package/dist/schema/call/arbitration.js +1 -1
  152. package/dist/schema/call/base.d.ts +8 -0
  153. package/dist/schema/call/base.js +1 -1
  154. package/dist/schema/call/bridge.d.ts +2 -0
  155. package/dist/schema/call/error-codes.d.ts +1 -1
  156. package/dist/schema/call/error-codes.js +1 -1
  157. package/dist/schema/call/guard.js +1 -1
  158. package/dist/schema/call/handler.js +1 -1
  159. package/dist/schema/call/machine.js +1 -1
  160. package/dist/schema/call/semantic.js +1 -1
  161. package/dist/schema/call/service.d.ts +3 -3
  162. package/dist/schema/call/service.js +1 -1
  163. package/dist/schema/common/index.js +1 -1
  164. package/dist/schema/evaluation/index.d.ts +8 -0
  165. package/dist/schema/evaluation/index.js +1 -1
  166. package/dist/schema/goal/planning.d.ts +1 -0
  167. package/dist/schema/goal/planning.js +1 -1
  168. package/dist/schema/industry-pack/index.d.ts +29 -0
  169. package/dist/schema/industry-pack/index.js +1 -1
  170. package/dist/schema/local/index.d.ts +20 -0
  171. package/dist/schema/local/index.js +1 -1
  172. package/dist/schema/messenger/index.d.ts +2 -0
  173. package/dist/schema/messenger/index.js +1 -1
  174. package/dist/schema/operations.d.ts +1 -1
  175. package/dist/schema/operations.js +1 -1
  176. package/dist/schema/query/bi.d.ts +106 -0
  177. package/dist/schema/query/bi.js +1 -1
  178. package/dist/schema/query/index.d.ts +5 -5
  179. package/dist/schema/query/index.js +1 -1
  180. package/dist/schema/schema-version.js +1 -1
  181. package/dist/schema/watch/index.js +1 -1
  182. package/dist/schema-query-impl/index.js +1 -1
  183. package/dist/schemas/account_operation.output.json +4 -2
  184. package/dist/schemas/benchmark_migration_operation.output.json +3 -3
  185. package/dist/schemas/benchmark_migration_operation.schema.json +16 -2
  186. package/dist/schemas/bridge_operation.output.json +4 -2
  187. package/dist/schemas/bridge_operation.schema.json +5 -5
  188. package/dist/schemas/evaluation_operation.output.json +16 -0
  189. package/dist/schemas/guard2file.schema.json +1 -1
  190. package/dist/schemas/index.json +1 -1
  191. package/dist/schemas/industry_pack_operation.output.json +150 -1
  192. package/dist/schemas/industry_pack_operation.schema.json +9 -3
  193. package/dist/schemas/keeper_operation.output.json +2 -2
  194. package/dist/schemas/local_cache_operation.output.json +4 -2
  195. package/dist/schemas/local_history_operation.output.json +4 -2
  196. package/dist/schemas/local_info_operation.output.json +4 -2
  197. package/dist/schemas/local_mark_operation.output.json +4 -2
  198. package/dist/schemas/machineNode2file.schema.json +1 -1
  199. package/dist/schemas/messenger_operation.output.json +13 -2
  200. package/dist/schemas/messenger_operation.schema.json +41 -34
  201. package/dist/schemas/monitor_events.output.json +2 -2
  202. package/dist/schemas/monitor_subscription.output.json +2 -2
  203. package/dist/schemas/onchain_events.output.json +14 -14
  204. package/dist/schemas/onchain_operations.output.json +13 -10
  205. package/dist/schemas/onchain_operations.schema.json +124 -99
  206. package/dist/schemas/onchain_operations_allocation.schema.json +7 -6
  207. package/dist/schemas/onchain_operations_arbitration.schema.json +7 -6
  208. package/dist/schemas/onchain_operations_contact.schema.json +4 -3
  209. package/dist/schemas/onchain_operations_demand.schema.json +4 -3
  210. package/dist/schemas/onchain_operations_gen_passport.schema.json +4 -3
  211. package/dist/schemas/onchain_operations_gen_proof.schema.json +1 -1
  212. package/dist/schemas/onchain_operations_guard.schema.json +7 -6
  213. package/dist/schemas/onchain_operations_machine.schema.json +9 -7
  214. package/dist/schemas/onchain_operations_order.schema.json +6 -4
  215. package/dist/schemas/onchain_operations_payment.schema.json +2 -2
  216. package/dist/schemas/onchain_operations_permission.schema.json +19 -15
  217. package/dist/schemas/onchain_operations_personal.schema.json +17 -14
  218. package/dist/schemas/onchain_operations_progress.schema.json +6 -4
  219. package/dist/schemas/onchain_operations_proof.schema.json +4 -3
  220. package/dist/schemas/onchain_operations_repository.schema.json +9 -7
  221. package/dist/schemas/onchain_operations_reward.schema.json +5 -4
  222. package/dist/schemas/onchain_operations_service.schema.json +15 -12
  223. package/dist/schemas/onchain_operations_treasury.schema.json +4 -3
  224. package/dist/schemas/onchain_table_data.output.json +18 -13
  225. package/dist/schemas/onchain_table_data.schema.json +13 -13
  226. package/dist/schemas/query_toolkit.output.json +301 -33
  227. package/dist/schemas/query_toolkit.schema.json +6 -6
  228. package/dist/schemas/watch_operation.output.json +3 -3
  229. package/dist/schemas/workflow_operation.schema.json +3 -2
  230. package/dist/schemas/wowok_buildin_info.schema.json +1 -1
  231. package/dist/task/playbook.js +1 -1
  232. package/dist/tools/handlers/benchmark-migration.d.ts +1 -0
  233. package/dist/tools/handlers/benchmark-migration.js +1 -1
  234. package/dist/tools/handlers/config.js +1 -1
  235. package/dist/tools/handlers/evaluation.js +1 -1
  236. package/dist/tools/handlers/evaluation.spec.js +1 -1
  237. package/dist/tools/handlers/industry-pack.js +1 -1
  238. package/dist/tools/handlers/messenger.js +1 -1
  239. package/dist/tools/handlers/onchain.d.ts +4 -0
  240. package/dist/tools/handlers/onchain.js +1 -1
  241. package/dist/tools/index.js +1 -1
  242. package/dist/tools/registry/business.js +1 -1
  243. package/dist/tools/registry/onchain.js +1 -1
  244. package/dist/tools/registry/query.js +1 -1
  245. package/dist/tools/sanitize-output.js +1 -1
  246. package/dist/tools/sanitize-output.spec.js +1 -1
  247. package/dist/tools/types.d.ts +1 -0
  248. package/dist/tools/upgrade-check.d.ts +22 -0
  249. package/dist/tools/upgrade-check.js +1 -1
  250. package/dist/tools/wrap.d.ts +1 -1
  251. package/dist/tools/wrap.js +1 -1
  252. package/package.json +7 -6
@@ -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['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;
@@ -94,6 +103,7 @@ export interface ProjectionStatus {
94
103
  active_objects: number;
95
104
  quarantined_versions: number;
96
105
  max_checkpoint: string | null;
106
+ observed_at: string | null;
97
107
  coverage: ProjectionCoverage;
98
108
  reconciliations: ReconciliationGeneration[];
99
109
  }
@@ -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'];['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);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;
@@ -1 +1 @@
1
- import{describe,expect,it}from'vitest';import{ENTRYPOINT}from'@wowok/wowok';import{FakeDataPlane}from'../../graph/onchain/dataplane.js';import{expandTopology}from'../../graph/onchain/expand.js';import{FULL,GAP,fullServiceState,gapServiceState,truncatedServiceState}from'../../graph/onchain/fixtures.js';import{buildViewport}from'../../graph/onchain/viewport.js';import{runAnalyzers}from'../../graph/onchain/analyze.js';import{EVALUATION_SERVICE_INTENTS,resolveExpansionStrategy,withEvaluationBundle}from'../../graph/onchain/strategy.js';import{projectEvaluationFacts as a72a}from'../../graph/onchain/facts.js';import{evaluateGraphServiceFacts,GRAPH_RULE_INPUT_FACTS,registerGraphServiceEvaluations}from'./graph-service.js';async function evalState(a,b){registerGraphServiceEvaluations();const c=withEvaluationBundle(resolveExpansionStrategy({'intents':[...EVALUATION_SERVICE_INTENTS]})),d=await expandTopology(new FakeDataPlane(a),{'network':ENTRYPOINT['Mainnet'],'seed':b,'edges':c['edges'],'budget':c['budget']}),e=buildViewport(d,b,'neutral'),f=a72a(e,b,runAnalyzers(e));return{'projected':f,'r':await evaluateGraphServiceFacts(f)};}const scoreOf=(a,b,c)=>a[b]['breakdown']['find'](d=>d['rule_id']===c);describe('graph\x20service\x20evaluation\x20—\x20fully\x20hooked\x20shop\x20(TR-14.1)',()=>{it('scores\x20all\x20nine\x20dimensions\x20from\x20material\x20facts\x20with\x20no\x20default-low\x20deductions',async()=>{const {r:a}=await evalState(fullServiceState(),FULL['svc']);expect(a['unverified'])['toEqual']([]),expect(a['completeness'])['toBe'](0x64);const c=scoreOf(a,'trust','trust_arbitration');expect(c['score'])['toBe'](0x64),expect(c['matched'])['toEqual'](expect['arrayContaining'](['arbitrator\x20roster\x20configured','arbitration\x20fee\x20funded','arbitration\x20active'])),expect(c['reason'])['toContain']('Arbitration\x2020/20'),expect(scoreOf(a,'trust','trust_reviews')['score'])['toBe'](0x28),expect(scoreOf(a,'trust','trust_fulfillment')['score'])['toBe'](0x19);const d=scoreOf(a,'trust','trust_fund_safety');expect(d['score'])['toBe'](0x0),expect(d['mismatched'])['toContain']('compensation\x20fund\x20below\x20the\x20statutory\x203x\x20largest-order\x20exposure\x20ceiling'),expect(scoreOf(a,'trust','trust_transparency')['score'])['toBe'](0x64),expect(a['trust']['total'])['toBe'](0x31);const e=scoreOf(a,'risk','risk_fund');expect(e['score'])['toBeLessThan'](0x64),expect(e['mismatched'])['toContain']('Payout\x20exposure:\x20compensation\x20fund\x20cannot\x20cover\x20a\x20maximum-multiple\x20award\x20on\x20the\x20largest\x20windowed\x20order'),expect(e['mismatched']?.['some'](h=>h['startsWith']('R2:')))['toBe'](![]),expect(e['finding_refs']?.['map'](h=>h['id']))['toContain']('R2:'+FULL['svc']['toLowerCase']());const f=scoreOf(a,'risk','risk_trust');expect(f['score'])['toBeLessThan'](0x64),expect(f['mismatched']?.['some'](h=>h['startsWith']('R1:')))['toBe'](![]),expect(f['mismatched']?.['length'])['toBeGreaterThan'](0x0),expect(f['finding_refs']?.['some'](h=>h['id']['startsWith']('R1:')))['toBe'](!![]);for(const h of[...a['trust']['breakdown'],...a['risk']['breakdown']]){for(const i of h['mismatched']??[])expect(i)['not']['toContain']('::node::');}expect(scoreOf(a,'risk','risk_workflow')['score'])['toBe'](0x64),expect(scoreOf(a,'risk','risk_behavior')['score'])['toBe'](0x64);for(const j of[...a['trust']['breakdown'],...a['risk']['breakdown']]){const k=(j['reason']??'')['toLowerCase']();expect(k)['not']['toContain']('no\x20data'),expect(k)['not']['toContain']('default\x20low');}const g=a['trust']['trace']['filter'](l=>l['kind']==='rule'&&l['detail']['startsWith']('score='));expect(g['map'](l=>l['id']))['toEqual'](expect['arrayContaining'](Object['keys'](GRAPH_RULE_INPUT_FACTS)['filter'](l=>l['startsWith']('trust_'))));}),it('keeps\x20the\x20injection\x20+\x20requirement\x20mechanisms\x20working',async()=>{const {projected:a}=await evalState(fullServiceState(),FULL['svc']),b=await evaluateGraphServiceFacts(a,{'overrides':{'rules':{'trust_arbitration':{'weight':0x28}}}});expect(b['trust']['total'])['toBe'](0x3a);const c=await evaluateGraphServiceFacts(a,{'requirements':[{'rule_id':'trust_fund_safety','condition':'require'}]});expect(c['trust']['blocked'])['toBe'](!![]),expect(c['trust']['red_flags']['length'])['toBeGreaterThan'](0x0);});}),describe('graph\x20service\x20evaluation\x20—\x20configured-empty\x20shell\x20(TR-14.1)',()=>{it('scores\x20verified\x20absence\x20as\x20a\x20configured\x20fact\x20and\x20excludes\x20only\x20the\x20gap\x20dimension',async()=>{const {r:a}=await evalState(gapServiceState(),GAP['svc']),b=scoreOf(a,'trust','trust_arbitration');expect(b['score'])['toBe'](0x0),expect(b['reason'])['toContain']('verified\x20absence'),expect(scoreOf(a,'trust','trust_reviews')['score'])['toBe'](0x32),expect(a['unverified'])['toEqual'](['risk_workflow']),expect(scoreOf(a,'risk','risk_workflow'))['toBeUndefined'](),expect(a['risk']['unverified'])['toEqual'](['risk_workflow']),expect(a['trust']['unverified'])['toEqual'](['risk_workflow']);const c=a['risk']['trace']['find'](d=>d['kind']==='rule'&&d['id']==='risk_workflow');expect(c?.['detail'])['toContain']('not\x20applicable'),expect(scoreOf(a,'trust','trust_transparency')['score'])['toBe'](0x28),expect(scoreOf(a,'trust','trust_fund_safety')['score'])['toBe'](0x0);});}),describe('graph\x20service\x20evaluation\x20—\x20truncated\x20order\x20window\x20(TR-14.1)',()=>{it('excludes\x20the\x20unverifiable\x20dimensions\x20and\x20renormalizes\x20the\x20weighted\x20total',async()=>{const {r:a}=await evalState(truncatedServiceState(),FULL['svc']);expect(a['unverified'])['toEqual'](expect['arrayContaining'](['trust_fulfillment','trust_fund_safety','risk_fund','risk_behavior'])),expect(scoreOf(a,'trust','trust_fulfillment'))['toBeUndefined'](),expect(scoreOf(a,'trust','trust_fund_safety'))['toBeUndefined'](),expect(scoreOf(a,'risk','risk_fund'))['toBeUndefined'](),expect(scoreOf(a,'risk','risk_behavior'))['toBeUndefined'](),expect(a['trust']['total'])['toBe'](0x44);for(const b of['trust_fulfillment','trust_fund_safety']){expect(a['trust']['trace']['find'](c=>c['kind']==='rule'&&c['id']===b)?.['detail'])['toContain']('not\x20applicable');}for(const c of['risk_fund','risk_behavior']){expect(a['risk']['trace']['find'](d=>d['kind']==='rule'&&d['id']===c)?.['detail'])['toContain']('not\x20applicable');}});}),describe('graph\x20service\x20evaluation\x20—\x20scoring\x20report\x20(TR-14.2)',()=>{it('renders\x20a\x20per-dimension\x20report\x20with\x20score,\x20weight,\x20state,\x20confidence\x20and\x20evidence',async()=>{const {projected:a,r:c}=await evalState(fullServiceState(),FULL['svc']),d=new Map(a['facts']['map'](g=>[g['key'],g])),e=[];for(const g of['trust','risk']){const h=c[g];e['push'](g['toUpperCase']()+'\x20'+h['total']+'/100\x20('+h['level']+')\x20—\x20'+h['summary']);for(const i of h['breakdown']){const j=GRAPH_RULE_INPUT_FACTS[i['rule_id']]??[],k=j['map'](o=>o+':state='+(d['get'](o)?.['state']??'missing')),l=j['map'](o=>d['get'](o)?.['provenance']['confidence']??'missing'),n=j['map'](o=>d['get'](o)?.['evidence']??'missing')['join']('\x20');e['push'](i['rule_id']+':\x20score='+i['score']+'\x20weight='+i['weight']+'\x20'+k['join'](',')+'\x20confidence='+[...new Set(l)]['join']('+')+'\x20evidence=\x22'+n+'\x22');}}expect(e)['toHaveLength'](0xb);const f=e['filter'](o=>o['includes']('score='));expect(f)['toHaveLength'](0x9);for(const o of f){expect(o)['toMatch'](/weight=\d+/),expect(o)['toContain']('state=present'),expect(o)['toMatch'](/confidence=(exact|bounded|windowed|derived)/);const p=o['match'](/evidence="(.*)"/);expect(p,o)['not']['toBeNull'](),expect(p[0x1]['length'],o)['toBeGreaterThan'](0x0);}expect(c['trust']['summary'])['toContain']('weakest\x20Fund\x20safety'),expect(c['trust']['summary'])['not']['toContain']('trust_fund_safety'),expect(c['trust']['summary'])['toMatch'](/grade: (strong|fair|weak)/),expect(c['trust']['summary'])['toContain']('Compensation\x20fund');});});
1
+ import{describe,expect,it}from'vitest';import{ENTRYPOINT}from'@wowok/wowok';import{FakeDataPlane}from'../../graph/onchain/dataplane.js';import{expandTopology}from'../../graph/onchain/expand.js';import{FULL,GAP,fullServiceState,gapServiceState,truncatedServiceState}from'../../graph/onchain/fixtures.js';import{buildViewport}from'../../graph/onchain/viewport.js';import{runAnalyzers}from'../../graph/onchain/analyze.js';import{EVALUATION_SERVICE_INTENTS,resolveExpansionStrategy,withEvaluationBundle}from'../../graph/onchain/strategy.js';import{projectEvaluationFacts as a73a}from'../../graph/onchain/facts.js';import{evaluateGraphServiceFacts,GRAPH_RULE_INPUT_FACTS,registerGraphServiceEvaluations}from'./graph-service.js';async function evalState(a,b){registerGraphServiceEvaluations();const c=withEvaluationBundle(resolveExpansionStrategy({'intents':[...EVALUATION_SERVICE_INTENTS]})),d=await expandTopology(new FakeDataPlane(a),{'network':ENTRYPOINT['Mainnet'],'seed':b,'edges':c['edges'],'budget':c['budget']}),e=buildViewport(d,b,'neutral'),f=a73a(e,b,runAnalyzers(e));return{'projected':f,'r':await evaluateGraphServiceFacts(f)};}const scoreOf=(a,b,c)=>a[b]['breakdown']['find'](d=>d['rule_id']===c);describe('graph\x20service\x20evaluation\x20—\x20fully\x20hooked\x20shop\x20(TR-14.1)',()=>{it('scores\x20all\x20nine\x20dimensions\x20from\x20material\x20facts\x20with\x20no\x20default-low\x20deductions',async()=>{const {r:a}=await evalState(fullServiceState(),FULL['svc']);expect(a['unverified'])['toEqual']([]),expect(a['completeness'])['toBe'](0x64);const c=scoreOf(a,'trust','trust_arbitration');expect(c['score'])['toBe'](0x64),expect(c['matched'])['toEqual'](expect['arrayContaining'](['arbitrator\x20roster\x20configured','arbitration\x20fee\x20funded','arbitration\x20active'])),expect(c['reason'])['toContain']('Arbitration\x2020/20'),expect(scoreOf(a,'trust','trust_reviews')['score'])['toBe'](0x28),expect(scoreOf(a,'trust','trust_fulfillment')['score'])['toBe'](0x19);const d=scoreOf(a,'trust','trust_fund_safety');expect(d['score'])['toBe'](0x0),expect(d['mismatched'])['toContain']('compensation\x20fund\x20below\x20the\x20statutory\x203x\x20largest-order\x20exposure\x20ceiling'),expect(scoreOf(a,'trust','trust_transparency')['score'])['toBe'](0x64),expect(a['trust']['total'])['toBe'](0x31);const e=scoreOf(a,'risk','risk_fund');expect(e['score'])['toBeLessThan'](0x64),expect(e['mismatched'])['toContain']('Payout\x20exposure:\x20compensation\x20fund\x20cannot\x20cover\x20a\x20maximum-multiple\x20award\x20on\x20the\x20largest\x20windowed\x20order'),expect(e['mismatched']?.['some'](h=>h['startsWith']('R2:')))['toBe'](![]),expect(e['finding_refs']?.['map'](h=>h['id']))['toContain']('R2:'+FULL['svc']['toLowerCase']());const f=scoreOf(a,'risk','risk_trust');expect(f['score'])['toBeLessThan'](0x64),expect(f['mismatched']?.['some'](h=>h['startsWith']('R1:')))['toBe'](![]),expect(f['mismatched']?.['length'])['toBeGreaterThan'](0x0),expect(f['finding_refs']?.['some'](h=>h['id']['startsWith']('R1:')))['toBe'](!![]);for(const h of[...a['trust']['breakdown'],...a['risk']['breakdown']]){for(const i of h['mismatched']??[])expect(i)['not']['toContain']('::node::');}expect(scoreOf(a,'risk','risk_workflow')['score'])['toBe'](0x64),expect(scoreOf(a,'risk','risk_behavior')['score'])['toBe'](0x64);for(const j of[...a['trust']['breakdown'],...a['risk']['breakdown']]){const k=(j['reason']??'')['toLowerCase']();expect(k)['not']['toContain']('no\x20data'),expect(k)['not']['toContain']('default\x20low');}const g=a['trust']['trace']['filter'](l=>l['kind']==='rule'&&l['detail']['startsWith']('score='));expect(g['map'](l=>l['id']))['toEqual'](expect['arrayContaining'](Object['keys'](GRAPH_RULE_INPUT_FACTS)['filter'](l=>l['startsWith']('trust_'))));}),it('keeps\x20the\x20injection\x20+\x20requirement\x20mechanisms\x20working',async()=>{const {projected:a}=await evalState(fullServiceState(),FULL['svc']),b=await evaluateGraphServiceFacts(a,{'overrides':{'rules':{'trust_arbitration':{'weight':0x28}}}});expect(b['trust']['total'])['toBe'](0x3a);const c=await evaluateGraphServiceFacts(a,{'requirements':[{'rule_id':'trust_fund_safety','condition':'require'}]});expect(c['trust']['blocked'])['toBe'](!![]),expect(c['trust']['red_flags']['length'])['toBeGreaterThan'](0x0);});}),describe('graph\x20service\x20evaluation\x20—\x20configured-empty\x20shell\x20(TR-14.1)',()=>{it('scores\x20verified\x20absence\x20as\x20a\x20configured\x20fact\x20and\x20excludes\x20only\x20the\x20gap\x20dimension',async()=>{const {r:a}=await evalState(gapServiceState(),GAP['svc']),b=scoreOf(a,'trust','trust_arbitration');expect(b['score'])['toBe'](0x0),expect(b['reason'])['toContain']('verified\x20absence'),expect(scoreOf(a,'trust','trust_reviews')['score'])['toBe'](0x32),expect(a['unverified'])['toEqual'](['risk_workflow']),expect(scoreOf(a,'risk','risk_workflow'))['toBeUndefined'](),expect(a['risk']['unverified'])['toEqual'](['risk_workflow']),expect(a['trust']['unverified'])['toEqual'](['risk_workflow']);const c=a['risk']['trace']['find'](d=>d['kind']==='rule'&&d['id']==='risk_workflow');expect(c?.['detail'])['toContain']('not\x20applicable'),expect(scoreOf(a,'trust','trust_transparency')['score'])['toBe'](0x28),expect(scoreOf(a,'trust','trust_fund_safety')['score'])['toBe'](0x0);});}),describe('graph\x20service\x20evaluation\x20—\x20truncated\x20order\x20window\x20(TR-14.1)',()=>{it('excludes\x20the\x20unverifiable\x20dimensions\x20and\x20renormalizes\x20the\x20weighted\x20total',async()=>{const {r:a}=await evalState(truncatedServiceState(),FULL['svc']);expect(a['unverified'])['toEqual'](expect['arrayContaining'](['trust_fulfillment','trust_fund_safety','risk_fund','risk_behavior'])),expect(scoreOf(a,'trust','trust_fulfillment'))['toBeUndefined'](),expect(scoreOf(a,'trust','trust_fund_safety'))['toBeUndefined'](),expect(scoreOf(a,'risk','risk_fund'))['toBeUndefined'](),expect(scoreOf(a,'risk','risk_behavior'))['toBeUndefined'](),expect(a['trust']['total'])['toBe'](0x44);for(const b of['trust_fulfillment','trust_fund_safety']){expect(a['trust']['trace']['find'](c=>c['kind']==='rule'&&c['id']===b)?.['detail'])['toContain']('not\x20applicable');}for(const c of['risk_fund','risk_behavior']){expect(a['risk']['trace']['find'](d=>d['kind']==='rule'&&d['id']===c)?.['detail'])['toContain']('not\x20applicable');}});}),describe('graph\x20service\x20evaluation\x20—\x20scoring\x20report\x20(TR-14.2)',()=>{it('renders\x20a\x20per-dimension\x20report\x20with\x20score,\x20weight,\x20state,\x20confidence\x20and\x20evidence',async()=>{const {projected:a,r:c}=await evalState(fullServiceState(),FULL['svc']),d=new Map(a['facts']['map'](g=>[g['key'],g])),e=[];for(const g of['trust','risk']){const h=c[g];e['push'](g['toUpperCase']()+'\x20'+h['total']+'/100\x20('+h['level']+')\x20—\x20'+h['summary']);for(const i of h['breakdown']){const j=GRAPH_RULE_INPUT_FACTS[i['rule_id']]??[],k=j['map'](o=>o+':state='+(d['get'](o)?.['state']??'missing')),l=j['map'](o=>d['get'](o)?.['provenance']['confidence']??'missing'),n=j['map'](o=>d['get'](o)?.['evidence']??'missing')['join']('\x20');e['push'](i['rule_id']+':\x20score='+i['score']+'\x20weight='+i['weight']+'\x20'+k['join'](',')+'\x20confidence='+[...new Set(l)]['join']('+')+'\x20evidence=\x22'+n+'\x22');}}expect(e)['toHaveLength'](0xb);const f=e['filter'](o=>o['includes']('score='));expect(f)['toHaveLength'](0x9);for(const o of f){expect(o)['toMatch'](/weight=\d+/),expect(o)['toContain']('state=present'),expect(o)['toMatch'](/confidence=(exact|bounded|windowed|derived)/);const p=o['match'](/evidence="(.*)"/);expect(p,o)['not']['toBeNull'](),expect(p[0x1]['length'],o)['toBeGreaterThan'](0x0);}expect(c['trust']['summary'])['toContain']('weakest\x20Fund\x20safety'),expect(c['trust']['summary'])['not']['toContain']('trust_fund_safety'),expect(c['trust']['summary'])['toMatch'](/grade: (strong|fair|weak)/),expect(c['trust']['summary'])['toContain']('Compensation\x20fund');});});
@@ -1 +1 @@
1
- import{REQUIREMENT_PASS_THRESHOLD,effectiveWeight,isDataSourceEnabled,isRuleEnabled,normalizeInjection}from'./user-injection.js';import{levelFromScore as a78a}from'./standards.js';export function levelFromScore(a){return a78a(a);}function appliesTo(a,b){if(!a||a['length']===0x0)return!![];return a['includes'](b);}export class EvaluationEngine{static ['instance']=null;['dataSources']=new Map();['rules']=new Map();static['Instance'](){return!EvaluationEngine['instance']&&(EvaluationEngine['instance']=new EvaluationEngine()),EvaluationEngine['instance'];}['registerDataSource'](a){if(!a['id']||this['dataSources']['has'](a['id']))return![];return this['dataSources']['set'](a['id'],a),!![];}['unregisterDataSource'](a){return this['dataSources']['delete'](a);}['registerRule'](a){if(!a['id']||this['rules']['has'](a['id']))return![];return this['rules']['set'](a['id'],a),!![];}['unregisterRule'](a){return this['rules']['delete'](a);}['getRule'](a){return this['rules']['get'](a);}['listRules'](){return Array['from'](this['rules']['values']());}['getDataSource'](a){return this['dataSources']['get'](a);}['listDataSources'](){return Array['from'](this['dataSources']['values']());}async['evaluate'](a,b,c){const d=normalizeInjection(c),e={'evaluation_id':a,'entities':b,'facts':{},'injection':d,'now':Date['now']()},f=[],g=Array['from'](this['dataSources']['values']())['filter'](m=>appliesTo(m['evaluation_ids'],a))['sort']((m,n)=>(m['priority']??0x0)-(n['priority']??0x0));for(const m of g){if(!isDataSourceEnabled(m['id'],d)){f['push']({'kind':'override','id':m['id'],'detail':'data\x20source\x20disabled\x20by\x20user\x20override'});continue;}if(m['isEnabled']&&!m['isEnabled'](e))continue;const n=await m['extract'](e);Object['assign'](e['facts'],n),f['push']({'kind':'data_source','id':m['id'],'detail':'extracted\x20'+Object['keys'](n)['length']+'\x20fact(s)'});}const h=[],i=[];for(const o of this['rules']['values']()){if(!appliesTo(o['evaluation_ids'],a))continue;if(!isRuleEnabled(o['id'],d)){f['push']({'kind':'override','id':o['id'],'detail':'rule\x20disabled\x20by\x20user\x20override'});continue;}if(o['isEnabled']&&!o['isEnabled'](e))continue;const p=o['evaluate'](e);if(!p){f['push']({'kind':'rule','id':o['id'],'detail':'not\x20applicable\x20—\x20excluded\x20from\x20weighted\x20aggregation'});continue;}const q=effectiveWeight(o,d);h['push']({'rule_id':o['id'],'dimension':o['dimension'],'score':p['score'],'weight':q,'weight_source':q!==o['weight']?'override':'default','reason':p['reason'],'matched':p['matched'],'mismatched':p['mismatched'],'finding_refs':p['finding_refs'],'red_flag':p['red_flag']}),p['red_flag']&&i['push'](p['reason']??o['id']+'\x20triggered\x20a\x20hard\x20block'),f['push']({'kind':'rule','id':o['id'],'detail':'score='+p['score']+'\x20weight='+q});}const j=aggregateScore(h);let k=i['length']>0x0;for(const r of d['requirements']??[]){const s=h['find'](t=>t['rule_id']===r['rule_id']);if(r['condition']==='require')(!s||s['score']<REQUIREMENT_PASS_THRESHOLD||s['red_flag'])&&(k=!![],i['push'](r['note']??'Requirement\x20requires\x20rule\x20\x27'+r['rule_id']+'\x27\x20to\x20pass'));else r['condition']==='forbid'&&(s&&s['red_flag']&&(k=!![],i['push'](r['note']??'Requirement\x20forbids\x20rule\x20\x27'+r['rule_id']+'\x27\x20from\x20triggering')));}const l=e['facts']['summary']??buildSummary(a,j,h,i,k);return{'evaluation_id':a,'total':j,'level':levelFromScore(j),'breakdown':h,'red_flags':i,'blocked':k,'trace':f,'summary':l,'criterionScores':e['facts']['criterionScores'],'findings':e['facts']['findings'],'strengths':e['facts']['strengths'],'needsLlm':e['facts']['needsLlm'],'llmPrompt':e['facts']['llmPrompt']};}}function aggregateScore(a){if(a['length']===0x0)return 0x0;let c=0x0,d=0x0;for(const e of a){c+=e['score']*e['weight'],d+=e['weight'];}if(d<=0x0)return 0x0;return clamp(Math['round'](c/d),0x0,0x64);}function clamp(a,b,c){return Math['max'](b,Math['min'](c,a));}function buildSummary(a,b,c,d,e){const f=['Evaluation\x20\x27'+a+'\x27:\x20score\x20'+b+'/100'];return e?f['push']('BLOCKED\x20('+d['length']+'\x20red\x20flag(s))'):f['push'](c['length']+'\x20rule(s)\x20evaluated'),f['join']('\x20—\x20');}export function getEvaluationEngine(){return EvaluationEngine['Instance']();}
1
+ import{REQUIREMENT_PASS_THRESHOLD,effectiveWeight,isDataSourceEnabled,isRuleEnabled,normalizeInjection}from'./user-injection.js';import{levelFromScore as a79a}from'./standards.js';export function levelFromScore(a){return a79a(a);}function appliesTo(a,b){if(!a||a['length']===0x0)return!![];return a['includes'](b);}export class EvaluationEngine{static ['instance']=null;['dataSources']=new Map();['rules']=new Map();static['Instance'](){return!EvaluationEngine['instance']&&(EvaluationEngine['instance']=new EvaluationEngine()),EvaluationEngine['instance'];}['registerDataSource'](a){if(!a['id']||this['dataSources']['has'](a['id']))return![];return this['dataSources']['set'](a['id'],a),!![];}['unregisterDataSource'](a){return this['dataSources']['delete'](a);}['registerRule'](a){if(!a['id']||this['rules']['has'](a['id']))return![];return this['rules']['set'](a['id'],a),!![];}['unregisterRule'](a){return this['rules']['delete'](a);}['getRule'](a){return this['rules']['get'](a);}['listRules'](){return Array['from'](this['rules']['values']());}['getDataSource'](a){return this['dataSources']['get'](a);}['listDataSources'](){return Array['from'](this['dataSources']['values']());}async['evaluate'](a,b,c){const d=normalizeInjection(c),e={'evaluation_id':a,'entities':b,'facts':{},'injection':d,'now':Date['now']()},f=[],g=Array['from'](this['dataSources']['values']())['filter'](m=>appliesTo(m['evaluation_ids'],a))['sort']((m,n)=>(m['priority']??0x0)-(n['priority']??0x0));for(const m of g){if(!isDataSourceEnabled(m['id'],d)){f['push']({'kind':'override','id':m['id'],'detail':'data\x20source\x20disabled\x20by\x20user\x20override'});continue;}if(m['isEnabled']&&!m['isEnabled'](e))continue;const n=await m['extract'](e);Object['assign'](e['facts'],n),f['push']({'kind':'data_source','id':m['id'],'detail':'extracted\x20'+Object['keys'](n)['length']+'\x20fact(s)'});}const h=[],i=[];for(const o of this['rules']['values']()){if(!appliesTo(o['evaluation_ids'],a))continue;if(!isRuleEnabled(o['id'],d)){f['push']({'kind':'override','id':o['id'],'detail':'rule\x20disabled\x20by\x20user\x20override'});continue;}if(o['isEnabled']&&!o['isEnabled'](e))continue;const p=o['evaluate'](e);if(!p){f['push']({'kind':'rule','id':o['id'],'detail':'not\x20applicable\x20—\x20excluded\x20from\x20weighted\x20aggregation'});continue;}const q=effectiveWeight(o,d);h['push']({'rule_id':o['id'],'dimension':o['dimension'],'score':p['score'],'weight':q,'weight_source':q!==o['weight']?'override':'default','reason':p['reason'],'matched':p['matched'],'mismatched':p['mismatched'],'finding_refs':p['finding_refs'],'red_flag':p['red_flag']}),p['red_flag']&&i['push'](p['reason']??o['id']+'\x20triggered\x20a\x20hard\x20block'),f['push']({'kind':'rule','id':o['id'],'detail':'score='+p['score']+'\x20weight='+q});}const j=aggregateScore(h);let k=i['length']>0x0;for(const r of d['requirements']??[]){const s=h['find'](t=>t['rule_id']===r['rule_id']);if(r['condition']==='require')(!s||s['score']<REQUIREMENT_PASS_THRESHOLD||s['red_flag'])&&(k=!![],i['push'](r['note']??'Requirement\x20requires\x20rule\x20\x27'+r['rule_id']+'\x27\x20to\x20pass'));else r['condition']==='forbid'&&(s&&s['red_flag']&&(k=!![],i['push'](r['note']??'Requirement\x20forbids\x20rule\x20\x27'+r['rule_id']+'\x27\x20from\x20triggering')));}const l=e['facts']['summary']??buildSummary(a,j,h,i,k);return{'evaluation_id':a,'total':j,'level':levelFromScore(j),'breakdown':h,'red_flags':i,'blocked':k,'trace':f,'summary':l,'criterionScores':e['facts']['criterionScores'],'findings':e['facts']['findings'],'strengths':e['facts']['strengths'],'needsLlm':e['facts']['needsLlm'],'llmPrompt':e['facts']['llmPrompt']};}}function aggregateScore(a){if(a['length']===0x0)return 0x0;let c=0x0,d=0x0;for(const e of a){c+=e['score']*e['weight'],d+=e['weight'];}if(d<=0x0)return 0x0;return clamp(Math['round'](c/d),0x0,0x64);}function clamp(a,b,c){return Math['max'](b,Math['min'](c,a));}function buildSummary(a,b,c,d,e){const f=['Evaluation\x20\x27'+a+'\x27:\x20score\x20'+b+'/100'];return e?f['push']('BLOCKED\x20('+d['length']+'\x20red\x20flag(s))'):f['push'](c['length']+'\x20rule(s)\x20evaluated'),f['join']('\x20—\x20');}export function getEvaluationEngine(){return EvaluationEngine['Instance']();}
@@ -1 +1 @@
1
- import{readdirSync,readFileSync}from'node:fs';import{join}from'node:path';export function stripComments(a){return a['replace'](/\/\*[\s\S]*?\*\//g,'\x20')['replace'](/(^|[^:])\/\/[^\n]*/g,'$1\x20');}export function importSourcesOf(a){const b=[];for(const c of a['matchAll'](/\bimport\s+(?:type\s+)?\{[^}]*\}\s*from\s*["']([^"']+)["']/g))b['push'](c[0x1]);for(const d of a['matchAll'](/\bimport\s+(?:type\s+)?(?:\*\s+as\s+\w+|\w+)(?:\s*,\s*\{[^}]*\})?\s*from\s*["']([^"']+)["']/g))b['push'](d[0x1]);for(const e of a['matchAll'](/\bexport\s+(?:\*\s*|\{[^}]*\}\s*)from\s*["']([^"']+)["']/g))b['push'](e[0x1]);for(const f of a['matchAll'](/^\s*import\s+["']([^"']+)["']/gm))b['push'](f[0x1]);return b;}export function namedSdkImportsOf(a){const b=[];for(const c of a['matchAll'](/import\s+(?:type\s+)?\{([^}]*)\}\s+from\s+["']@wowok\/wowok["']/g)){for(const d of c[0x1]['split'](',')){const e=d['replace'](/\btype\s+/g,'')['trim']()['split'](/\s+as\s+/)[0x0]['trim']();if(e)b['push'](e);}}return b;}export const SDK_CONSTANT_ALLOWLIST=new Set(['MAX_VOTING_GUARD_COUNT']);export const ONCHAIN_IO_CALLS=[[/\bnew\s+SdkDataPlane\b/,'SdkDataPlane\x20construction'],[/\b(?:query_objects|query_table|query_services|query_arbs|query_events)\s*\(/,'SDK\x20query\x20call'],[/\bLocalMark\.Instance\s*\(\)/,'LocalMark\x20store\x20access'],[/\bget_many_address\s*\(/,'LocalMark\x20name\x20resolution'],[/\bfetchObjectLinker\s*\(/,'linker\x20chain\x20IO'],[/\bnetwork_get\s*\(/,'authority\x20network\x20read']];export function onchainIoCalls(a){return ONCHAIN_IO_CALLS['filter'](([b])=>b['test'](a))['map'](([,b])=>b);}export function listRuntimeSources(a){const b=[];for(const c of readdirSync(a,{'withFileTypes':!![]})){const d=join(a,c['name']);if(c['isDirectory']())b['push'](...listRuntimeSources(d));else c['name']['endsWith']('.ts')&&!c['name']['endsWith']('.spec.ts')&&b['push']({'file':c['name'],'text':stripComments(readFileSync(d,'utf8'))});}return b['sort']((e,f)=>e['file']['localeCompare'](f['file']));}
1
+ import{readdirSync,readFileSync}from'node:fs';import{join}from'node:path';export function stripComments(a){return a['replace'](/\/\*[\s\S]*?\*\//g,'\x20')['replace'](/(^|[^:])\/\/[^\n]*/g,'$1\x20');}export function importSourcesOf(a){const b=[];for(const c of a['matchAll'](/\bimport\s+(?:type\s+)?\{[^}]*\}\s*from\s*["']([^"']+)["']/g))b['push'](c[0x1]);for(const d of a['matchAll'](/\bimport\s+(?:type\s+)?(?:\*\s+as\s+\w+|\w+)(?:\s*,\s*\{[^}]*\})?\s*from\s*["']([^"']+)["']/g))b['push'](d[0x1]);for(const e of a['matchAll'](/\bexport\s+(?:\*\s*|\{[^}]*\}\s*)from\s*["']([^"']+)["']/g))b['push'](e[0x1]);for(const f of a['matchAll'](/^\s*import\s+["']([^"']+)["']/gm))b['push'](f[0x1]);return b;}export function namedSdkImportsOf(a){const b=[];for(const c of a['matchAll'](/import\s+(?:type\s+)?\{([^}]*)\}\s+from\s+["']@wowok\/wowok["']/g)){for(const d of c[0x1]['split'](',')){const e=d['replace'](/\btype\s+/g,'')['trim']()['split'](/\s+as\s+/)[0x0]['trim']();if(e)b['push'](e);}}return b;}export const SDK_CONSTANT_ALLOWLIST=new Set(['MAX_VOTING_GUARD_COUNT']);export const ONCHAIN_IO_CALLS=[[/\bnew\s+SdkDataPlane\b/,'SdkDataPlane\x20construction'],[/\b(?:query_objects|query_table|query_services|query_arbs|query_events)\s*\(/,'SDK\x20query\x20call'],[/\bLocalMark\.Instance\s*\(\)/,'LocalMark\x20store\x20access'],[/\bget_many_address\s*\(/,'LocalMark\x20name\x20resolution'],[/\bfetchObjectLinker\s*\(/,'linker\x20chain\x20IO'],[/\bnetwork_get\s*\(/,'authority\x20network\x20read']];export function onchainIoCalls(a){return ONCHAIN_IO_CALLS['filter'](([b])=>b['test'](a))['map'](([,b])=>b);}export function listRuntimeSources(a){const b=[];for(const c of readdirSync(a,{'withFileTypes':!![]})){const d=join(a,c['name']);if(c['isDirectory']())b['push'](...listRuntimeSources(d));else c['name']['endsWith']('.ts')&&!c['name']['endsWith']('.spec'+'.ts')&&b['push']({'file':c['name'],'text':stripComments(readFileSync(d,'utf8'))});}return b['sort']((e,f)=>e['file']['localeCompare'](f['file']));}
@@ -1 +1 @@
1
- import{distillIntent,extractSignals}from'./intent-distill.js';import{getProfile,updateFromOperation}from'./user-profile.js';import{findMatches,recordSignature}from'./experience-reuse.js';import{EXPERIENCE_LAYER_VERSION}from'./types.js';import{isEnabled as a103a}from'../config/index.js';import{recordIndustrySignal}from'../knowledge/flywheel-loop.js';export{EXPERIENCE_LAYER_VERSION};export function getExperienceFeedback(a,b,c){try{const d=distillIntent(a,b,c),e=findMatches(d['primary_intent'],a,b,0x3);if(e['length']===0x0)return undefined;const f=e[0x0],g=getProfile();return formatFeedback(f,e,d['scenario'],g);}catch{return undefined;}}export function recordOperationOutcome(a,b,c,d,e,f=[]){try{const g=distillIntent(a,b,c),h=extractSignals(a,b);recordSignature({'intent':g['primary_intent'],'scenario':g['scenario'],'signals':h,'timestamp':Date['now'](),'outcome':d,'error_code':e}),updateFromOperation(g['primary_intent'],g['scenario'],d,e,f);try{if(a103a('industry_evolution')){const i=typeof b?.['industry']==='string'&&b['industry']['trim']()?b['industry']['trim']():undefined;if(i){const j=d==='success'?{'success':!![]}:{'success':![],'error_code':e};recordIndustrySignal(i,{'type':a,'data':b},j);}}}catch{}}catch{}}function formatFeedback(a,b,c,d){const e=buildAdviceText(a,b,d),f=collectAvoidList(b,d),g=a['relevance'],h=c??a['signature']['scenario'],i={};if(e)i['advice']=e;if(f['length']>0x0)i['avoid']=f;if(g>0x0)i['relevance']=Math['round'](g*0x64)/0x64;if(h)i['matched_scenario']=h;return i;}function buildAdviceText(a,b,c){const d=[];if(a['signature']['outcome']==='success')d['push']('Historically,\x20'+a['signature']['intent']+'\x20operation\x20succeeded');else a['signature']['outcome']==='failed'&&d['push']('Historically,\x20'+a['signature']['intent']+'\x20operation\x20failed\x20('+(a['signature']['error_code']??'unknown\x20error')+'),\x20pay\x20special\x20attention\x20to\x20parameters');return c['expertise_tier']==='novice'&&b['length']>0x0&&d['push']('It\x20is\x20recommended\x20to\x20carefully\x20check\x20parameters\x20before\x20executing'),d['join'](';\x20')||a['advice'];}function collectAvoidList(b,c){const d=new Set();for(const e of b){for(const f of e['avoid']){d['add'](f);}}for(const g of c['frequent_pitfalls']){d['add']('You\x20often\x20make\x20mistakes\x20at\x20the\x20'+g+'\x20step,\x20please\x20be\x20especially\x20careful');}return Array['from'](d)['slice'](0x0,0x5);}
1
+ import{distillIntent,extractSignals}from'./intent-distill.js';import{getProfile,updateFromOperation}from'./user-profile.js';import{findMatches,recordSignature}from'./experience-reuse.js';import{EXPERIENCE_LAYER_VERSION}from'./types.js';import{isEnabled as a104a}from'../config/index.js';import{recordIndustrySignal}from'../knowledge/flywheel-loop.js';export{EXPERIENCE_LAYER_VERSION};export function getExperienceFeedback(a,b,c){try{const d=distillIntent(a,b,c),e=findMatches(d['primary_intent'],a,b,0x3);if(e['length']===0x0)return undefined;const f=e[0x0],g=getProfile();return formatFeedback(f,e,d['scenario'],g);}catch{return undefined;}}export function recordOperationOutcome(a,b,c,d,e,f=[]){try{const g=distillIntent(a,b,c),h=extractSignals(a,b);recordSignature({'intent':g['primary_intent'],'scenario':g['scenario'],'signals':h,'timestamp':Date['now'](),'outcome':d,'error_code':e}),updateFromOperation(g['primary_intent'],g['scenario'],d,e,f);try{if(a104a('industry_evolution')){const i=typeof b?.['industry']==='string'&&b['industry']['trim']()?b['industry']['trim']():undefined;if(i){const j=d==='success'?{'success':!![]}:{'success':![],'error_code':e};recordIndustrySignal(i,{'type':a,'data':b},j);}}}catch{}}catch{}}function formatFeedback(a,b,c,d){const e=buildAdviceText(a,b,d),f=collectAvoidList(b,d),g=a['relevance'],h=c??a['signature']['scenario'],i={};if(e)i['advice']=e;if(f['length']>0x0)i['avoid']=f;if(g>0x0)i['relevance']=Math['round'](g*0x64)/0x64;if(h)i['matched_scenario']=h;return i;}function buildAdviceText(a,b,c){const d=[];if(a['signature']['outcome']==='success')d['push']('Historically,\x20'+a['signature']['intent']+'\x20operation\x20succeeded');else a['signature']['outcome']==='failed'&&d['push']('Historically,\x20'+a['signature']['intent']+'\x20operation\x20failed\x20('+(a['signature']['error_code']??'unknown\x20error')+'),\x20pay\x20special\x20attention\x20to\x20parameters');return c['expertise_tier']==='novice'&&b['length']>0x0&&d['push']('It\x20is\x20recommended\x20to\x20carefully\x20check\x20parameters\x20before\x20executing'),d['join'](';\x20')||a['advice'];}function collectAvoidList(b,c){const d=new Set();for(const e of b){for(const f of e['avoid']){d['add'](f);}}for(const g of c['frequent_pitfalls']){d['add']('You\x20often\x20make\x20mistakes\x20at\x20the\x20'+g+'\x20step,\x20please\x20be\x20especially\x20careful');}return Array['from'](d)['slice'](0x0,0x5);}