@wowok/agent-mcp 3.3.3 → 3.3.6

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 (202) hide show
  1. package/dist/chain-semantics/eval-order.d.ts +17 -0
  2. package/dist/chain-semantics/eval-order.js +1 -0
  3. package/dist/chain-semantics/freeze-map.js +1 -1
  4. package/dist/chain-semantics/fund-flow.js +1 -1
  5. package/dist/chain-semantics/index.d.ts +1 -0
  6. package/dist/chain-semantics/index.js +1 -1
  7. package/dist/chain-semantics/object-graph.js +1 -1
  8. package/dist/composition/audit.js +1 -1
  9. package/dist/composition/compile.d.ts +4 -1
  10. package/dist/composition/compile.js +1 -1
  11. package/dist/data/api/api.spec.d.ts +1 -0
  12. package/dist/data/api/api.spec.js +1 -0
  13. package/dist/data/api/cli.d.ts +1 -0
  14. package/dist/data/api/cli.js +1 -0
  15. package/dist/data/api/head.d.ts +16 -0
  16. package/dist/data/api/head.js +1 -0
  17. package/dist/data/api/head.spec.d.ts +1 -0
  18. package/dist/data/api/head.spec.js +1 -0
  19. package/dist/data/api/index.d.ts +2 -0
  20. package/dist/data/api/index.js +1 -0
  21. package/dist/data/api/match.d.ts +69 -0
  22. package/dist/data/api/match.js +1 -0
  23. package/dist/data/api/match.spec.d.ts +1 -0
  24. package/dist/data/api/match.spec.js +1 -0
  25. package/dist/data/api/server.d.ts +12 -0
  26. package/dist/data/api/server.js +1 -0
  27. package/dist/data/projection/cli.d.ts +1 -0
  28. package/dist/data/projection/cli.js +1 -0
  29. package/dist/data/projection/edges.d.ts +8 -0
  30. package/dist/data/projection/edges.js +1 -0
  31. package/dist/data/projection/edges.spec.d.ts +1 -0
  32. package/dist/data/projection/edges.spec.js +1 -0
  33. package/dist/data/projection/facets.d.ts +18 -0
  34. package/dist/data/projection/facets.js +1 -0
  35. package/dist/data/projection/facets.spec.d.ts +1 -0
  36. package/dist/data/projection/facets.spec.js +1 -0
  37. package/dist/data/projection/facts.d.ts +40 -0
  38. package/dist/data/projection/facts.js +1 -0
  39. package/dist/data/projection/index.d.ts +6 -0
  40. package/dist/data/projection/index.js +1 -0
  41. package/dist/data/projection/project.d.ts +10 -0
  42. package/dist/data/projection/project.js +1 -0
  43. package/dist/data/projection/projection.spec.d.ts +1 -0
  44. package/dist/data/projection/projection.spec.js +1 -0
  45. package/dist/data/projection/schema.d.ts +1 -0
  46. package/dist/data/projection/schema.js +1 -0
  47. package/dist/data/projection/store.d.ts +49 -0
  48. package/dist/data/projection/store.js +1 -0
  49. package/dist/data/projection/types.d.ts +137 -0
  50. package/dist/data/projection/types.js +1 -0
  51. package/dist/data/sync/cdc.d.ts +34 -0
  52. package/dist/data/sync/cdc.js +1 -0
  53. package/dist/data/sync/cdc.spec.d.ts +1 -0
  54. package/dist/data/sync/cdc.spec.js +1 -0
  55. package/dist/data/sync/graphql-source.d.ts +16 -0
  56. package/dist/data/sync/graphql-source.js +1 -0
  57. package/dist/data/sync/index.d.ts +5 -0
  58. package/dist/data/sync/index.js +1 -0
  59. package/dist/data/sync/reconciler.d.ts +14 -0
  60. package/dist/data/sync/reconciler.js +1 -0
  61. package/dist/data/sync/reconciler.spec.d.ts +1 -0
  62. package/dist/data/sync/reconciler.spec.js +1 -0
  63. package/dist/data/sync/schema.d.ts +1 -0
  64. package/dist/data/sync/schema.js +1 -0
  65. package/dist/data/sync/store.d.ts +19 -0
  66. package/dist/data/sync/store.js +1 -0
  67. package/dist/data/sync/sync.spec.d.ts +1 -0
  68. package/dist/data/sync/sync.spec.js +1 -0
  69. package/dist/data/sync/synchronizer.d.ts +10 -0
  70. package/dist/data/sync/synchronizer.js +1 -0
  71. package/dist/data/sync/types.d.ts +162 -0
  72. package/dist/data/sync/types.js +1 -0
  73. package/dist/evaluation/builtins/demand-match.js +1 -1
  74. package/dist/evaluation/builtins/graph-service.spec.js +1 -1
  75. package/dist/evaluation/capability.d.ts +1 -0
  76. package/dist/evaluation/engine.js +1 -1
  77. package/dist/evaluation/extract.d.ts +7 -1
  78. package/dist/evaluation/extract.js +1 -1
  79. package/dist/evaluation/match-policy.d.ts +118 -0
  80. package/dist/evaluation/match-policy.js +1 -0
  81. package/dist/evaluation/match-policy.spec.d.ts +1 -0
  82. package/dist/evaluation/match-policy.spec.js +1 -0
  83. package/dist/evaluation/node-game.d.ts +3 -0
  84. package/dist/evaluation/node-game.js +1 -1
  85. package/dist/experience/realtime-feedback.js +1 -1
  86. package/dist/graph/onchain/expand.js +1 -1
  87. package/dist/graph/onchain/exposure.js +1 -1
  88. package/dist/harness/recover.js +1 -1
  89. package/dist/knowledge/arbitration-ledger.js +1 -1
  90. package/dist/knowledge/baselines/rules/plan.json +16 -1
  91. package/dist/knowledge/builtin-templates.d.ts +1 -1
  92. package/dist/knowledge/builtin-templates.js +1 -1
  93. package/dist/knowledge/getting-started.js +1 -1
  94. package/dist/knowledge/guard-design-patterns.d.ts +1 -1
  95. package/dist/knowledge/guard-design-patterns.js +1 -1
  96. package/dist/knowledge/guard-ledger.js +1 -1
  97. package/dist/knowledge/guard-puzzle.js +1 -1
  98. package/dist/knowledge/guard-render.js +1 -1
  99. package/dist/knowledge/guard-risk.js +1 -1
  100. package/dist/knowledge/guard-templates.d.ts +1 -1
  101. package/dist/knowledge/guard-templates.js +1 -1
  102. package/dist/knowledge/guard-translation.js +1 -1
  103. package/dist/knowledge/index.js +1 -1
  104. package/dist/knowledge/industry-registry.js +1 -1
  105. package/dist/knowledge/jsonrpc-enum.d.ts +26 -10
  106. package/dist/knowledge/jsonrpc-enum.js +1 -1
  107. package/dist/knowledge/projection.d.ts +54 -0
  108. package/dist/knowledge/projection.js +1 -0
  109. package/dist/knowledge/projection.spec.d.ts +1 -0
  110. package/dist/knowledge/projection.spec.js +1 -0
  111. package/dist/knowledge/recipient-constraint.d.ts +9 -0
  112. package/dist/knowledge/recipient-constraint.js +1 -1
  113. package/dist/knowledge/scenario-modes.d.ts +1 -0
  114. package/dist/knowledge/service-ledger.d.ts +1 -1
  115. package/dist/knowledge/service-ledger.js +1 -1
  116. package/dist/knowledge/template-loader.d.ts +1 -0
  117. package/dist/knowledge/template-loader.js +1 -1
  118. package/dist/knowledge/template-registry.js +1 -1
  119. package/dist/knowledge/template-scanner.js +1 -1
  120. package/dist/monitor/MonitorLoop.js +1 -1
  121. package/dist/participation/node-action-advisor.js +1 -1
  122. package/dist/playbooks/service-build/business-puzzle.js +1 -1
  123. package/dist/playbooks/service-build/machine-panorama.js +1 -1
  124. package/dist/playbooks/service-build/object-panorama.js +1 -1
  125. package/dist/playbooks/service-build/participation-radar.js +1 -1
  126. package/dist/playbooks/service-build/relationship-profile.js +1 -1
  127. package/dist/playbooks/service-build/service-panorama.js +1 -1
  128. package/dist/playbooks/service-build/service-quote.js +1 -1
  129. package/dist/playbooks/service-build/service-quote.spec.js +1 -1
  130. package/dist/review/index.js +1 -1
  131. package/dist/role/profiles.js +1 -1
  132. package/dist/safety/confirm-gate.js +1 -1
  133. package/dist/schema/call/allocation.js +1 -1
  134. package/dist/schema/call/base.d.ts +25 -0
  135. package/dist/schema/call/base.js +1 -1
  136. package/dist/schema/call/bridge.d.ts +1 -0
  137. package/dist/schema/call/error-codes.d.ts +1 -1
  138. package/dist/schema/call/error-codes.js +1 -1
  139. package/dist/schema/call/handler.js +1 -1
  140. package/dist/schema/call/order.d.ts +12 -0
  141. package/dist/schema/call/order.js +1 -1
  142. package/dist/schema/call/progress.js +1 -1
  143. package/dist/schema/call/proof.js +1 -1
  144. package/dist/schema/call/semantic.js +1 -1
  145. package/dist/schema/call/service.js +1 -1
  146. package/dist/schema/common/index.js +1 -1
  147. package/dist/schema/evaluation/index.d.ts +189 -0
  148. package/dist/schema/evaluation/index.js +1 -1
  149. package/dist/schema/local/index.d.ts +10 -0
  150. package/dist/schema/local/index.js +1 -1
  151. package/dist/schema/operations.d.ts +4 -0
  152. package/dist/schema/query/bi.d.ts +8 -0
  153. package/dist/schema/query/bi.js +1 -1
  154. package/dist/schema/query/index.d.ts +147 -0
  155. package/dist/schema/query/index.js +1 -1
  156. package/dist/schema/schema-version.js +1 -1
  157. package/dist/schema-query-impl/index.js +1 -1
  158. package/dist/schemas/account_operation.output.json +2 -1
  159. package/dist/schemas/bridge_operation.output.json +2 -1
  160. package/dist/schemas/evaluation_operation.output.json +384 -2
  161. package/dist/schemas/evaluation_operation.schema.json +202 -4
  162. package/dist/schemas/index.json +1 -1
  163. package/dist/schemas/keeper_operation.output.json +1 -1
  164. package/dist/schemas/local_cache_operation.output.json +2 -1
  165. package/dist/schemas/local_history_operation.output.json +2 -1
  166. package/dist/schemas/local_info_operation.output.json +2 -1
  167. package/dist/schemas/local_mark_operation.output.json +2 -1
  168. package/dist/schemas/messenger_operation.output.json +1 -1
  169. package/dist/schemas/monitor_events.output.json +1 -1
  170. package/dist/schemas/monitor_subscription.output.json +1 -1
  171. package/dist/schemas/onchain_events.output.json +1 -1
  172. package/dist/schemas/onchain_operations.output.json +35 -4
  173. package/dist/schemas/onchain_operations.schema.json +687 -103
  174. package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
  175. package/dist/schemas/onchain_operations_gen_proof.schema.json +1 -1
  176. package/dist/schemas/onchain_operations_guard.schema.json +660 -94
  177. package/dist/schemas/onchain_operations_order.schema.json +19 -1
  178. package/dist/schemas/onchain_operations_progress.schema.json +2 -2
  179. package/dist/schemas/onchain_operations_service.schema.json +4 -4
  180. package/dist/schemas/onchain_table_data.output.json +2 -2
  181. package/dist/schemas/query_toolkit.output.json +316 -1
  182. package/dist/schemas/query_toolkit.schema.json +1 -1
  183. package/dist/schemas/wowok_buildin_info.output.json +259 -0
  184. package/dist/schemas/wowok_buildin_info.schema.json +121 -0
  185. package/dist/tools/build-fingerprint.d.ts +28 -0
  186. package/dist/tools/build-fingerprint.js +1 -0
  187. package/dist/tools/handlers/benchmark-migration.d.ts +4 -2
  188. package/dist/tools/handlers/benchmark-migration.js +1 -1
  189. package/dist/tools/handlers/config.js +1 -1
  190. package/dist/tools/handlers/evaluation.js +1 -1
  191. package/dist/tools/handlers/evaluation.spec.js +1 -1
  192. package/dist/tools/handlers/onchain.d.ts +7 -0
  193. package/dist/tools/handlers/onchain.js +1 -1
  194. package/dist/tools/handlers/query.js +1 -1
  195. package/dist/tools/handlers/review-chain.d.ts +9 -13
  196. package/dist/tools/handlers/review-chain.js +1 -1
  197. package/dist/tools/index.js +1 -1
  198. package/dist/tools/registry/business.js +1 -1
  199. package/dist/tools/upgrade-check.d.ts +1 -0
  200. package/dist/tools/upgrade-check.js +1 -1
  201. package/dist/tools/wrap.js +1 -1
  202. package/package.json +7 -2
@@ -0,0 +1 @@
1
+ import{createServer}from'node:http';import{WOW_OBJECT_TYPE_TAGS,wowAddressToBytes}from'@wowok/wowok';import{KNOWN_CAPABILITIES,runMatch}from'./match.js';function json(a,b,c){a['writeHead'](b,{'Content-Type':'application/json;\x20charset=utf-8','Cache-Control':'no-store','X-Content-Type-Options':'nosniff'}),a['end'](JSON['stringify'](c));}function badRequest(a,b){json(a,0x190,{'error':{'code':'BAD_REQUEST','message':b}});}const WOW_DECIMALS=0x9;function parseWowToWei(a){const b=/^(\d+)(?:\.(\d{1,9}))?$/['exec'](a['trim']());if(!b)return null;const c=(b[0x2]??'')['padEnd'](WOW_DECIMALS,'0');return(BigInt(b[0x1])*BigInt(0xa**WOW_DECIMALS)+BigInt(c))['toString']();}function parsePositiveInt(a){return/^\d+$/['test'](a['trim']())?Number(a['trim']()):null;}export function createProjectionApi(a){if(!a['chainId'])throw new Error('chainId\x20is\x20required');const b=a['staleLag']??0x0;if(!Number['isInteger'](b)||b<0x0)throw new Error('Invalid\x20staleLag');return createServer(async(c,d)=>{try{if(c['method']!=='GET'){d['setHeader']('Allow','GET'),json(d,0x195,{'error':{'code':'METHOD_NOT_ALLOWED','message':'GET\x20required'}});return;}const e=new URL(c['url']??'/','http://localhost');if(e['pathname']==='/v1/status'){const [f,g,h,i]=await Promise['all']([a['projection']['status'](a['chainId']),a['sync']['status'](a['chainId']),a['projection']['watermarks'](a['chainId']),a['head']?a['head']['read']():Promise['resolve'](null)]);let j=null;if(i?.['checkpoint']!==null&&i?.['checkpoint']!==undefined&&f['max_checkpoint']!==null){const k=BigInt(i['checkpoint'])-BigInt(f['max_checkpoint']);j={'head_checkpoint':i['checkpoint'],'projection_checkpoint':f['max_checkpoint'],'head_lag':(k>0x0n?k:0x0n)['toString'](),'stale':b>0x0&&k>BigInt(b)};}json(d,0xc8,{'chain_id':a['chainId'],'read_only':!![],'generated_at':new Date()['toISOString'](),'projection':f,'sync':g,'watermarks':h,'head':i,'freshness':j});return;}if(e['pathname']==='/v1/objects'){const l=e['searchParams']['get']('kind')??undefined;if(l&&!(l in WOW_OBJECT_TYPE_TAGS)){badRequest(d,'Unknown\x20object\x20kind:\x20'+l);return;}const m=e['searchParams']['get']('cursor')??undefined;if(m)try{wowAddressToBytes(m);}catch{badRequest(d,'Invalid\x20object\x20cursor');return;}const n=e['searchParams']['get']('limit'),o=n===null?undefined:Number(n);if(o!==undefined&&(!Number['isInteger'](o)||o<0x1||o>0x3e8)){badRequest(d,'limit\x20must\x20be\x20an\x20integer\x20between\x201\x20and\x201000');return;}const p=e['searchParams']['get']('shard_count'),r=e['searchParams']['get']('shard_index');if(p===null!==(r===null)){badRequest(d,'shard_count\x20and\x20shard_index\x20must\x20be\x20provided\x20together');return;}const s=p===null||r===null?undefined:{'count':Number(p),'index':Number(r)};if(s&&(!Number['isInteger'](s['count'])||s['count']<0x1||!Number['isInteger'](s['index'])||s['index']<0x0||s['index']>=s['count'])){badRequest(d,'Invalid\x20shard\x20selector');return;}const t=await a['projection']['listCurrent']({'chainId':a['chainId'],'kind':l,'cursor':m,'limit':o,'shard':s});json(d,0xc8,{'chain_id':a['chainId'],'generated_at':new Date()['toISOString'](),...t});return;}if(e['pathname']==='/v1/edges'){const u=e['searchParams']['get']('src'),v=e['searchParams']['get']('dst');if(u===null===(v===null)){badRequest(d,'Provide\x20exactly\x20one\x20of\x20src\x20or\x20dst');return;}const w=u??v;try{wowAddressToBytes(w);}catch{badRequest(d,'Invalid\x20object\x20address');return;}const x=u!==null?await a['projection']['edgesFrom'](a['chainId'],w):await a['projection']['edgesTo'](a['chainId'],w);json(d,0xc8,{'chain_id':a['chainId'],'generated_at':new Date()['toISOString'](),'direction':u!==null?'out':'in','object_id':w['toLowerCase'](),'edges':x,'orphan_count':x['filter'](y=>!y['dstProjected'])['length']});return;}if(e['pathname']==='/v1/match'){const y=e['searchParams']['get']('kind');if(y!=='Service'&&y!=='Demand'){badRequest(d,'kind\x20must\x20be\x20\x27Service\x27\x20or\x20\x27Demand\x27');return;}const z=e['searchParams']['get']('q')??undefined,A=e['searchParams']['get']('location')??undefined,B=e['searchParams']['get']('industry')??undefined;let C;const D=e['searchParams']['get']('budget');if(D!==null){C=parseWowToWei(D)??undefined;if(C===undefined){badRequest(d,'budget\x20must\x20be\x20a\x20non-negative\x20decimal\x20WOW\x20amount\x20(max\x209\x20fractional\x20digits)');return;}}let E;const F=e['searchParams']['get']('capabilities');if(F!==null){E=F['split'](',')['map'](S=>S['trim']())['filter'](S=>S['length']>0x0);const R=E['filter'](S=>!KNOWN_CAPABILITIES['includes'](S));if(R['length']>0x0){badRequest(d,'Unknown\x20capability:\x20'+R['join'](',\x20')+'\x20(known:\x20'+KNOWN_CAPABILITIES['join'](',\x20')+')');return;}}let G=0x14;const H=e['searchParams']['get']('limit');if(H!==null){G=parsePositiveInt(H)??-0x1;if(!Number['isInteger'](G)||G<0x1||G>0x64){badRequest(d,'limit\x20must\x20be\x20an\x20integer\x20between\x201\x20and\x20100');return;}}let I=0xc8;const J=e['searchParams']['get']('recall_limit');if(J!==null){I=parsePositiveInt(J)??-0x1;if(!Number['isInteger'](I)||I<0x1||I>0x3e8){badRequest(d,'recall_limit\x20must\x20be\x20an\x20integer\x20between\x201\x20and\x201000');return;}}const K=e['searchParams']['get']('include_payload');let L=![];if(K!==null){if(K==='1'||K==='true')L=!![];else{if(K!=='0'&&K!=='false'){badRequest(d,'include_payload\x20must\x20be\x20one\x20of\x201,\x20true,\x200,\x20false');return;}}}const M={'kind':y,'q':z,'location':A,'industry':B,'budgetWei':C,'capabilities':E,'limit':G,'recallLimit':I},[N,O]=await Promise['all']([a['projection']['activeFacets'](a['chainId'],y),a['projection']['status'](a['chainId'])]),P=runMatch(N,M);let Q=P['candidates'];if(L&&Q['length']>0x0){const S=await a['projection']['currentPayloads'](a['chainId'],Q['map'](T=>T['object_id']));Q=Q['map'](T=>({...T,'payload_json':S['get'](T['object_id'])??null}));}json(d,0xc8,{'chain_id':a['chainId'],'generated_at':new Date()['toISOString'](),'coverage':O['coverage'],...P,'candidates':Q});return;}json(d,0x194,{'error':{'code':'NOT_FOUND','message':'Unknown\x20endpoint'}});}catch{json(d,0x1f4,{'error':{'code':'INTERNAL_ERROR','message':'Index\x20query\x20failed'}});}});}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ import{createReadStream}from'node:fs';import{createInterface}from'node:readline';import{ENTRYPOINT,PackageAddress,WOW_OBJECT_TYPE_TAGS}from'@wowok/wowok';import{CdcSynchronizer,GraphQLCdcSource}from'../sync/cdc.js';import{canonicalChainIdentifier,GraphQLSnapshotSource}from'../sync/graphql-source.js';import{LiveSetReconciler}from'../sync/reconciler.js';import{PostgresSyncStore}from'../sync/store.js';import{SnapshotSynchronizer}from'../sync/synchronizer.js';import{PostgresProjectionStore}from'./store.js';function usage(){console['log']('Usage:\x0a\x20\x20projection\x20migrate\x0a\x20\x20projection\x20ingest\x20[ndjson-file]\x0a\x20\x20projection\x20sync\x20<network>\x20<expected-chain-id>\x20[kind]\x20[limit]\x0a\x20\x20projection\x20reconcile\x20<network>\x20<expected-chain-id>\x20<kind>\x20[limit]\x0a\x20\x20projection\x20cdc\x20<network>\x20<expected-chain-id>\x20<kind>\x20[max-span]\x0a\x20\x20projection\x20edges-backfill\x20<chain-id>\x0a\x20\x20projection\x20facets-backfill\x20<chain-id>\x0a\x20\x20projection\x20status\x20<chain-id>\x0a\x20\x20projection\x20sync-status\x20<chain-id>\x0a\x20\x20projection\x20list\x20<chain-id>\x20[kind]\x20[limit]\x0a\x0aEnvironment:\x20DATABASE_URL\x20is\x20required;\x20WOWOK_INDEX_SHARD_COUNT\x20defaults\x20to\x20256.');}async function main(){const [a,...b]=process['argv']['slice'](0x2);if(!a||a==='help'||a==='--help'){usage();return;}const c=a==='migrate'&&b['length']===0x0||a==='ingest'&&b['length']<=0x1||a==='sync'&&b['length']>=0x2&&b['length']<=0x4||a==='reconcile'&&b['length']>=0x3&&b['length']<=0x4||a==='cdc'&&b['length']>=0x3&&b['length']<=0x4||a==='edges-backfill'&&b['length']===0x1||a==='facets-backfill'&&b['length']===0x1||a==='status'&&b['length']===0x1||a==='sync-status'&&b['length']===0x1||a==='list'&&b['length']>=0x1&&b['length']<=0x3;if(!c){usage(),process['exitCode']=0x2;return;}const d=process['env']['DATABASE_URL'];if(!d)throw new Error('DATABASE_URL\x20is\x20required');const e=Number(process['env']['WOWOK_INDEX_SHARD_COUNT']??0x100),f=PostgresProjectionStore['fromDatabaseUrl'](d,e),g=PostgresSyncStore['fromDatabaseUrl'](d);try{if(a==='migrate'){await f['migrate'](),await g['migrate'](),console['log'](JSON['stringify']({'status':'migrated'}));return;}if(a==='ingest'){const h=b[0x0]?createReadStream(b[0x0],{'encoding':'utf8'}):process['stdin'],i=createInterface({'input':h,'crlfDelay':Infinity}),j={'applied':0x0,'duplicate':0x0,'stale':0x0,'quarantined':0x0,'conflict':0x0};for await(const k of i){if(!k['trim']())continue;const l=await f['apply'](JSON['parse'](k));j[l['status']]+=0x1;}console['log'](JSON['stringify'](j));return;}if(a==='sync'&&b[0x0]&&b[0x1]){if(!Object['values'](ENTRYPOINT)['includes'](b[0x0]))throw new Error('Unknown\x20network:\x20'+b[0x0]);const m=b[0x2]??'Service';if(!(m in WOW_OBJECT_TYPE_TAGS))throw new Error('Unknown\x20object\x20kind:\x20'+m);const n=b[0x0],o=canonicalChainIdentifier(b[0x1]),p=GraphQLSnapshotSource['forNetwork'](n,o),q=new SnapshotSynchronizer(f,g,p),r=m==='Discount'?'service':m['toLowerCase'](),s=await q['run']({'expectedChainId':o,'stream':'graphql-shared:'+m,'type':PackageAddress+'::'+r,'scope':{'kind':m},'limit':b[0x3]?Number(b[0x3]):undefined});console['log'](JSON['stringify'](s,null,0x2));return;}if(a==='reconcile'&&b[0x0]&&b[0x1]&&b[0x2]){if(!Object['values'](ENTRYPOINT)['includes'](b[0x0]))throw new Error('Unknown\x20network:\x20'+b[0x0]);const t=b[0x2];if(!(t in WOW_OBJECT_TYPE_TAGS))throw new Error('Unknown\x20object\x20kind:\x20'+t);const u=b[0x0],v=canonicalChainIdentifier(b[0x1]),w=GraphQLSnapshotSource['forNetwork'](u,v),x=new LiveSetReconciler(f,w),y=t==='Discount'?'service':t['toLowerCase'](),z=await x['run']({'expectedChainId':v,'type':PackageAddress+'::'+y,'kind':t,'limit':b[0x3]?Number(b[0x3]):undefined});console['log'](JSON['stringify'](z,null,0x2));return;}if(a==='edges-backfill'&&b[0x0]){const A=await f['backfillGraphEdges'](b[0x0]);console['log'](JSON['stringify']({'status':'backfilled',...A}));return;}if(a==='facets-backfill'&&b[0x0]){const B=await f['backfillFacets'](b[0x0]);console['log'](JSON['stringify']({'status':'backfilled',...B}));return;}if(a==='cdc'&&b[0x0]&&b[0x1]&&b[0x2]){if(!Object['values'](ENTRYPOINT)['includes'](b[0x0]))throw new Error('Unknown\x20network:\x20'+b[0x0]);const C=b[0x2];if(!(C in WOW_OBJECT_TYPE_TAGS))throw new Error('Unknown\x20object\x20kind:\x20'+C);const D=b[0x0],E=canonicalChainIdentifier(b[0x1]),F=GraphQLCdcSource['forNetwork'](D,E),G=new CdcSynchronizer(f,F,g),H=await G['run']({'expectedChainId':E,'kind':C,'maxSpan':b[0x3]?Number(b[0x3]):undefined});console['log'](JSON['stringify'](H,null,0x2));return;}if(a==='status'&&b[0x0]){console['log'](JSON['stringify'](await f['status'](b[0x0]),null,0x2));return;}if(a==='sync-status'&&b[0x0]){console['log'](JSON['stringify'](await g['status'](b[0x0]),null,0x2));return;}if(a==='list'&&b[0x0]){const I=await f['listCurrent']({'chainId':b[0x0],'kind':b[0x1],'limit':b[0x2]?Number(b[0x2]):undefined});console['log'](JSON['stringify'](I,null,0x2));return;}usage(),process['exitCode']=0x2;}finally{await f['close'](),await g['close']();}}await main();
@@ -0,0 +1,8 @@
1
+ export interface GraphEdgeRef {
2
+ src: string;
3
+ srcKind: string;
4
+ edge: string;
5
+ dst: string;
6
+ dstKind: string;
7
+ }
8
+ export declare function extractGraphEdges(verifiedKind: string, objectId: string, payloadJson: Record<string, unknown> | null | undefined): GraphEdgeRef[];
@@ -0,0 +1 @@
1
+ const ADDRESS_RE=/^0x[0-9a-fA-F]{64}$/,SCALAR_EDGES={'um':'UM','machine':'Machine','permission':'Permission','buy_guard':'Guard'},VECTOR_EDGES={'rewards':'Reward','arbitrations':'Arbitration','repositories':'Repository'},ARB_EDGES={'arbitration':'Arbitration','order':'Order'};export function extractGraphEdges(a,b,c){if(!c)return[];const d=a==='Service'?{...SCALAR_EDGES,...VECTOR_EDGES}:a==='Arb'?ARB_EDGES:null;if(!d)return[];const e=[];for(const [f,g]of Object['entries'](d)){const h=c[f],i=Array['isArray'](h)?h:[h];for(const j of i){if(typeof j!=='string'||!ADDRESS_RE['test'](j))continue;const k=j['toLowerCase']();if(k===b['toLowerCase']())continue;e['push']({'src':b['toLowerCase'](),'srcKind':a,'edge':f,'dst':k,'dstKind':g});}}return e;}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ import{toBase58}from'@wowok/wowok';import{DataType,newDb}from'pg-mem';import{afterEach,beforeEach,describe,expect,it}from'vitest';import{extractGraphEdges}from'./edges.js';import{PostgresProjectionStore}from'./store.js';const digest=toBase58(new Uint8Array(0x20)['fill'](0x7));function objectId(a,b){return'0x'+a['toString'](0x10)['padStart'](0x2,'0')+b['toString'](0x10)['padStart'](0x2,'0')['repeat'](0x1f);}const SERVICE_ID=objectId(0x14,0x1),MACHINE_ID=objectId(0x15,0x2),UM_ID=objectId(0x24,0x3),PERM_ID=objectId(0x40,0x4),GUARD_ID=objectId(0x41,0x5),REWARD_ID=objectId(0x42,0x6),ARB_ID=objectId(0x12,0x7),ARB_TARGET=objectId(0x12,0xb),REPO_ID=objectId(0x11,0x8),ORDER_ID=objectId(0x30,0x9),SERVICE_PAYLOAD={'id':{'id':SERVICE_ID},'um':UM_ID,'machine':MACHINE_ID,'permission':PERM_ID,'buy_guard':GUARD_ID,'rewards':[REWARD_ID,'not-an-address'],'arbitrations':[ARB_ID],'repositories':[REPO_ID],'sales':[{'fields':{'wip':'https://wip.example/f/hash'}}]};function fact(a={}){return{'chain_id':'chain_a','object_id':SERVICE_ID,'object_version':'1','move_type':'0x2::service::Service<0x2::wow::WOW>','owner_kind':'Shared','payload_uri':'test://raw/service-1','payload_hash':'0x'+'41'['repeat'](0x20),'payload_format':'rpc-content-v1','checkpoint':'100','tx_digest':digest,'state':'active','observed_at':'2026-10-24T00:00:00.000Z',...a};}describe('extractGraphEdges',()=>{it('extracts\x20Service\x20static\x20references\x20from\x20real\x20payload\x20shape',()=>{const a=extractGraphEdges('Service',SERVICE_ID,SERVICE_PAYLOAD);expect(a)['toEqual']([{'src':SERVICE_ID,'srcKind':'Service','edge':'um','dst':UM_ID,'dstKind':'UM'},{'src':SERVICE_ID,'srcKind':'Service','edge':'machine','dst':MACHINE_ID,'dstKind':'Machine'},{'src':SERVICE_ID,'srcKind':'Service','edge':'permission','dst':PERM_ID,'dstKind':'Permission'},{'src':SERVICE_ID,'srcKind':'Service','edge':'buy_guard','dst':GUARD_ID,'dstKind':'Guard'},{'src':SERVICE_ID,'srcKind':'Service','edge':'rewards','dst':REWARD_ID,'dstKind':'Reward'},{'src':SERVICE_ID,'srcKind':'Service','edge':'arbitrations','dst':ARB_ID,'dstKind':'Arbitration'},{'src':SERVICE_ID,'srcKind':'Service','edge':'repositories','dst':REPO_ID,'dstKind':'Repository'}]);}),it('extracts\x20Arb\x20arbitration\x20and\x20order\x20references',()=>{const a=objectId(0x12,0x7),b=extractGraphEdges('Arb',a,{'order':ORDER_ID,'arbitration':ARB_TARGET,'voted':[{'fields':{'voter':GUARD_ID}}]});expect(b)['toEqual']([{'src':a,'srcKind':'Arb','edge':'arbitration','dst':ARB_TARGET,'dstKind':'Arbitration'},{'src':a,'srcKind':'Arb','edge':'order','dst':ORDER_ID,'dstKind':'Order'}]);}),it('skips\x20self-references,\x20null\x20guards\x20and\x20unprojected\x20kinds',()=>{expect(extractGraphEdges('Service',SERVICE_ID,{'buy_guard':null,'machine':SERVICE_ID}))['toEqual']([]),expect(extractGraphEdges('Demand',SERVICE_ID,{'machine':MACHINE_ID}))['toEqual']([]),expect(extractGraphEdges('Service',SERVICE_ID,null))['toEqual']([]);});}),describe('PostgresProjectionStore\x20graph\x20edges',()=>{let a;beforeEach(async()=>{const b=newDb();b['public']['registerFunction']({'name':'pg_advisory_xact_lock','args':[DataType['integer'],DataType['integer']],'returns':DataType['integer'],'implementation':()=>0x0});const {Pool:c}=b['adapters']['createPg'](),d=new c();a=new PostgresProjectionStore(d,0x10),await a['migrate']();}),afterEach(async()=>{await a?.['close']();}),it('syncs\x20edges\x20on\x20apply\x20and\x20annotates\x20unprojected\x20destinations',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD}));const b=await a['edgesFrom']('chain_a',SERVICE_ID);expect(b)['toHaveLength'](0x7),expect(b['filter'](d=>!d['dstProjected']))['toHaveLength'](0x7),expect(b['every'](d=>d['objectVersion']==='1'))['toBe'](!![]);const c=await a['edgesTo']('chain_a',MACHINE_ID);expect(c)['toEqual']([{'src':SERVICE_ID,'srcKind':'Service','edge':'machine','dst':MACHINE_ID,'dstKind':'Machine','objectVersion':'1','dstProjected':!![]}]);}),it('replaces\x20edges\x20when\x20a\x20newer\x20version\x20changes\x20its\x20references',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD})),await a['apply'](fact({'object_version':'2','payload_hash':'0x'+'43'['repeat'](0x20),'payload_uri':'test://raw/service-2','payload_json':{...SERVICE_PAYLOAD,'machine':GUARD_ID,'arbitrations':[]}}));const b=await a['edgesFrom']('chain_a',SERVICE_ID);expect(b['filter'](c=>c['edge']==='machine'))['toEqual']([{'src':SERVICE_ID,'srcKind':'Service','edge':'machine','dst':GUARD_ID,'dstKind':'Machine','objectVersion':'2','dstProjected':![]}]),expect(b['filter'](c=>c['edge']==='arbitrations'))['toEqual']([]),expect(b)['toHaveLength'](0x6);}),it('leaves\x20edges\x20untouched\x20for\x20duplicate\x20replays\x20and\x20removes\x20them\x20on\x20tombstone',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD})),expect((await a['apply'](fact({'payload_json':SERVICE_PAYLOAD})))['status'])['toBe']('duplicate'),expect(await a['edgesFrom']('chain_a',SERVICE_ID))['toHaveLength'](0x7),await a['markTombstone']('chain_a',SERVICE_ID),expect(await a['edgesFrom']('chain_a',SERVICE_ID))['toEqual']([]);}),it('backfills\x20edges\x20for\x20active\x20objects\x20from\x20their\x20current\x20version\x20payloads',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD})),await a['apply'](fact({'object_id':objectId(0x12,0x7),'move_type':'0x2::arb::Arb<0x2::wow::WOW>','payload_uri':'test://raw/arb-1','payload_json':{'order':ORDER_ID,'arbitration':ARB_TARGET}}));const b=await a['backfillGraphEdges']('chain_a');expect(b)['toEqual']({'objects':0x2,'edges':0x9}),expect(await a['edgesFrom']('chain_a',SERVICE_ID))['toHaveLength'](0x7),expect(await a['edgesFrom']('chain_a',objectId(0x12,0x7)))['toHaveLength'](0x2);});});
@@ -0,0 +1,18 @@
1
+ export declare const FACET_VERSION = "facets-1";
2
+ export interface ObjectFacet {
3
+ verifiedKind: string;
4
+ objectId: string;
5
+ industry: string | null;
6
+ industryConfidence: number;
7
+ location: string | null;
8
+ priceMin: string | null;
9
+ priceMax: string | null;
10
+ capabilities: string[];
11
+ published: boolean;
12
+ paused: boolean;
13
+ nameTokens: string[];
14
+ textTokens: string[];
15
+ keywords: string[];
16
+ }
17
+ export declare function tokenize(text: string): string[];
18
+ export declare function extractFacets(verifiedKind: string, objectId: string, payloadJson: unknown): ObjectFacet | null;
@@ -0,0 +1 @@
1
+ import{enrichFromDescription}from'../../evaluation/extract.js';export const FACET_VERSION='facets-1';const STOPWORDS=new Set(['the','a','an','and','or','of','for','to','in','on','with','is','are','be','as','at','by','it','its','this','that','from','we','you','our','your','will','can','all','has','have','not','but']),LATIN_WORD=/[a-z0-9]+/g,CJK_RUN=/[\u4e00-\u9fff]+/g;export function tokenize(a){const b=a['toLowerCase'](),c=[];for(const d of b['match'](LATIN_WORD)??[]){if(d['length']>=0x2&&!STOPWORDS['has'](d))c['push'](d);}for(const e of b['match'](CJK_RUN)??[]){for(const f of e)c['push'](f);for(let g=0x0;g+0x1<e['length'];g+=0x1)c['push'](e['slice'](g,g+0x2));}return c;}function str(a){return typeof a==='string'?a:undefined;}function strOrNull(a){return typeof a==='string'&&a?a:null;}function weiOrUndefined(a){const b=typeof a==='string'?a:typeof a==='number'?String(a):undefined;if(b===undefined||!/^\d+$/['test'](b))return undefined;try{return BigInt(b);}catch{return undefined;}}function parseSales(a){if(!Array['isArray'](a))return[];return a['map'](b=>{const c=b&&typeof b==='object'&&'fields'in b?b['fields']:b;return{'name':str(c?.['name']),'price':weiOrUndefined(c?.['price']),'wipHash':!!str(c?.['wip_hash'])};});}function addressVector(a){return Array['isArray'](a)?a['filter'](b=>typeof b==='string'):[];}function serviceFacet(a,b){const c=str(b['description'])??'',d=strOrNull(b['location']),e=parseSales(b['sales']),f=e['map'](n=>n['price'])['filter'](n=>n!==undefined),g=addressVector(b['arbitrations']),h=weiOrUndefined(b['compensation_fund'])??0x0n,i=enrichFromDescription(c),j=[];if(g['length']>0x0)j['push']('has_arbitration');if(g['length']>0x0&&h>0x0n)j['push']('has_refund_path');if(strOrNull(b['machine']))j['push']('has_milestone_nodes');if(h>0x0n)j['push']('has_compensation_fund');if(e['some'](n=>n['wipHash']))j['push']('has_wip_verification');if(strOrNull(b['um']))j['push']('has_messenger');if(strOrNull(b['buy_guard']))j['push']('has_buy_guard');const k=e['map'](n=>n['name']??'')['filter'](o=>o['length']>0x0),l=tokenize(k['join']('\x20')),m=[...tokenize(c),...tokenize(d??''),...l,...i['keywords']['map'](n=>n['toLowerCase']())];return{'verifiedKind':'Service','objectId':a['toLowerCase'](),'industry':i['industry']==='general'?null:i['industry'],'industryConfidence':i['industry_confidence'],'location':d,'priceMin':f['length']>0x0?f['reduce']((n,o)=>n<o?n:o)['toString']():null,'priceMax':f['length']>0x0?f['reduce']((n,o)=>n>o?n:o)['toString']():null,'capabilities':j,'published':b['bPublished']===!![],'paused':b['bPaused']===!![],'nameTokens':l,'textTokens':m,'keywords':i['keywords']};}function demandFacet(a,b){const c=str(b['description'])??'',d=strOrNull(b['location']),e=enrichFromDescription(c),f=[];if(strOrNull(b['um']))f['push']('has_messenger');return{'verifiedKind':'Demand','objectId':a['toLowerCase'](),'industry':e['industry']==='general'?null:e['industry'],'industryConfidence':e['industry_confidence'],'location':d,'priceMin':null,'priceMax':null,'capabilities':f,'published':!![],'paused':![],'nameTokens':[],'textTokens':[...tokenize(c),...tokenize(d??''),...e['keywords']['map'](g=>g['toLowerCase']())],'keywords':e['keywords']};}export function extractFacets(a,b,c){if(a!=='Service'&&a!=='Demand')return null;if(!c||typeof c!=='object'||Array['isArray'](c))return null;const d=c;return a==='Service'?serviceFacet(b,d):demandFacet(b,d);}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ import{toBase58}from'@wowok/wowok';import{DataType,newDb}from'pg-mem';import{afterEach,beforeEach,describe,expect,it}from'vitest';import{extractFacets,FACET_VERSION,tokenize}from'./facets.js';import{PostgresProjectionStore}from'./store.js';const digest=toBase58(new Uint8Array(0x20)['fill'](0x7));function objectId(a,b){return'0x'+a['toString'](0x10)['padStart'](0x2,'0')+b['toString'](0x10)['padStart'](0x2,'0')['repeat'](0x1f);}const SERVICE_ID=objectId(0x14,0x1),DEMAND_ID=objectId(0x1b,0x2),MACHINE_ID=objectId(0x15,0x3),UM_ID=objectId(0x24,0x4),PERM_ID=objectId(0x40,0x5),ARB_TARGET=objectId(0x12,0x6),REWARD_ID=objectId(0x42,0x7),SERVICE_PAYLOAD={'id':SERVICE_ID,'description':'NanoBrew\x20One\x20—\x20threshold-funded\x20reward\x20campaign\x20with\x20escrow\x20and\x20refunds','location':'Shenzhen,\x20CN\x20(ships\x20worldwide)','sales':[{'name':'Early\x20Bird','price':'6000000000','stock':'20','wip_hash':'aa'['repeat'](0x20)},{'name':'Standard','price':'7500000000','stock':'20'}],'buy_guard':null,'machine':MACHINE_ID,'bPublished':!![],'bPaused':![],'arbitrations':[ARB_TARGET],'compensation_fund':'15000000000','rewards':[REWARD_ID],'um':UM_ID,'permission':PERM_ID};function fact(a={}){return{'chain_id':'chain_a','object_id':SERVICE_ID,'object_version':'1','move_type':'0x2::service::Service<0x2::wow::WOW>','owner_kind':'Shared','payload_uri':'test://raw/service-1','payload_hash':'0x'+'41'['repeat'](0x20),'payload_format':'rpc-content-v1','checkpoint':'100','tx_digest':digest,'state':'active','observed_at':'2026-10-24T00:00:00.000Z',...a};}describe('tokenize\x20(facets-1)',()=>{it('lowercases,\x20drops\x20stopwords\x20and\x20short\x20latin\x20words',()=>{expect(tokenize('The\x20BEAT\x20License\x20for\x20a\x20Video!'))['toEqual'](['beat','license','video']);}),it('emits\x20CJK\x20unigrams\x20and\x20bigrams',()=>{expect(tokenize('音乐授权'))['toEqual'](['音','乐','授','权','音乐','乐授','授权']);}),it('keeps\x20duplicates\x20so\x20BM25\x20sees\x20term\x20frequency',()=>{expect(tokenize('beat\x20beat'))['toEqual'](['beat','beat']);});}),describe('extractFacets',()=>{it('extracts\x20evidence-backed\x20Service\x20facets\x20from\x20the\x20real\x20payload\x20shape',()=>{const a=extractFacets('Service',SERVICE_ID,SERVICE_PAYLOAD);expect(a)['not']['toBeNull'](),expect(a['verifiedKind'])['toBe']('Service'),expect(a['objectId'])['toBe'](SERVICE_ID['toLowerCase']()),expect(a['priceMin'])['toBe']('6000000000'),expect(a['priceMax'])['toBe']('7500000000'),expect(a['published'])['toBe'](!![]),expect(a['paused'])['toBe'](![]),expect(a['location'])['toBe']('Shenzhen,\x20CN\x20(ships\x20worldwide)'),expect(a['capabilities'])['toEqual'](['has_arbitration','has_refund_path','has_milestone_nodes','has_compensation_fund','has_wip_verification','has_messenger']),expect(a['nameTokens'])['toContain']('early'),expect(a['textTokens'])['toContain']('escrow'),expect(a['textTokens'])['toContain']('shenzhen');}),it('never\x20fabricates\x20industry:\x20no\x20signal\x20→\x20null\x20(unknown)',()=>{const a=extractFacets('Service',SERVICE_ID,{...SERVICE_PAYLOAD,'description':''});expect(a['industry'])['toBeNull'](),expect(a['industryConfidence'])['toBe'](0x0);}),it('is\x20deterministic\x20for\x20identical\x20input',()=>{const c=extractFacets('Service',SERVICE_ID,SERVICE_PAYLOAD),d=extractFacets('Service',SERVICE_ID,SERVICE_PAYLOAD);expect(c)['toEqual'](d);}),it('derives\x20refund\x20path\x20only\x20from\x20arbitration\x20AND\x20funded\x20compensation',()=>{const a=extractFacets('Service',SERVICE_ID,{...SERVICE_PAYLOAD,'compensation_fund':'0'});expect(a['capabilities'])['toContain']('has_arbitration'),expect(a['capabilities'])['not']['toContain']('has_refund_path'),expect(a['capabilities'])['not']['toContain']('has_compensation_fund');const b=extractFacets('Service',SERVICE_ID,{...SERVICE_PAYLOAD,'arbitrations':[]});expect(b['capabilities'])['not']['toContain']('has_refund_path');}),it('extracts\x20Demand\x20facets\x20and\x20skips\x20kinds\x20without\x20facet\x20support',()=>{const a=extractFacets('Demand',DEMAND_ID,{'description':'Looking\x20for\x20a\x20licensed\x20beat','location':'Remote','um':UM_ID});expect(a['verifiedKind'])['toBe']('Demand'),expect(a['capabilities'])['toEqual'](['has_messenger']),expect(a['priceMin'])['toBeNull'](),expect(extractFacets('Arb',objectId(0x12,0x9),{'order':SERVICE_ID}))['toBeNull'](),expect(extractFacets('Service',SERVICE_ID,null))['toBeNull']();});}),describe('PostgresProjectionStore\x20facets',()=>{let a;beforeEach(async()=>{const b=newDb();b['public']['registerFunction']({'name':'pg_advisory_xact_lock','args':[DataType['integer'],DataType['integer']],'returns':DataType['integer'],'implementation':()=>0x0});const {Pool:c}=b['adapters']['createPg']();a=new PostgresProjectionStore(new c(),0x10),await a['migrate']();}),afterEach(async()=>{await a?.['close']();}),it('materializes\x20the\x20facet\x20row\x20on\x20apply\x20with\x20version\x20and\x20facet\x20generation',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD}));const b=await a['activeFacets']('chain_a','Service');expect(b)['toHaveLength'](0x1),expect(b[0x0])['toMatchObject']({'objectId':SERVICE_ID['toLowerCase'](),'verifiedKind':'Service','objectVersion':'1','facetVersion':FACET_VERSION,'priceMin':'6000000000','priceMax':'7500000000','published':!![],'paused':![]}),expect(b[0x0]['capabilities'])['toContain']('has_refund_path');}),it('computes\x20facets\x20when\x20the\x20JSON\x20payload\x20attaches\x20to\x20an\x20existing\x20raw\x20version',async()=>{await a['apply'](fact()),expect(await a['activeFacets']('chain_a','Service'))['toEqual']([]);const b=await a['apply'](fact({'payload_json':SERVICE_PAYLOAD}));expect(b['status'])['toBe']('duplicate'),expect(await a['activeFacets']('chain_a','Service'))['toHaveLength'](0x1);}),it('replaces\x20facets\x20on\x20a\x20newer\x20version\x20and\x20ignores\x20tombstoned\x20objects',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD})),await a['apply'](fact({'object_version':'2','payload_hash':'0x'+'43'['repeat'](0x20),'payload_uri':'test://raw/service-2','payload_json':{...SERVICE_PAYLOAD,'bPaused':!![],'compensation_fund':'0'}}));const b=await a['activeFacets']('chain_a','Service');expect(b)['toHaveLength'](0x1),expect(b[0x0]['objectVersion'])['toBe']('2'),expect(b[0x0]['paused'])['toBe'](!![]),expect(b[0x0]['capabilities'])['not']['toContain']('has_compensation_fund'),await a['markTombstone']('chain_a',SERVICE_ID),expect(await a['activeFacets']('chain_a','Service'))['toEqual']([]);}),it('backfills\x20facets\x20for\x20active\x20objects\x20from\x20current\x20version\x20payloads',async()=>{await a['apply'](fact({'payload_json':SERVICE_PAYLOAD})),await a['apply'](fact({'object_id':DEMAND_ID,'move_type':'0x2::demand::Demand<0x2::wow::WOW>','payload_uri':'test://raw/demand-1','payload_json':{'description':'Need\x20a\x20beat','location':'Remote','um':UM_ID}}));const b=await a['backfillFacets']('chain_a');expect(b)['toEqual']({'objects':0x2,'facets':0x2}),expect(await a['activeFacets']('chain_a'))['toHaveLength'](0x2),expect(await a['activeFacets']('chain_a','Demand'))['toHaveLength'](0x1);});});
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import type { ObjectVersionFact } from "./types.js";
3
+ export declare const ObjectVersionFactSchema: z.ZodPipe<z.ZodObject<{
4
+ chain_id: z.ZodString;
5
+ object_id: z.ZodString;
6
+ object_version: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBigInt]>, z.ZodTransform<bigint, string | number | bigint>>;
7
+ move_type: z.ZodString;
8
+ owner_kind: z.ZodString;
9
+ owner_address: z.ZodOptional<z.ZodString>;
10
+ payload_uri: z.ZodString;
11
+ payload_hash: z.ZodString;
12
+ payload_format: z.ZodString;
13
+ payload_json: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
14
+ checkpoint: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBigInt]>, z.ZodTransform<bigint, string | number | bigint>>;
15
+ tx_digest: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
16
+ previous_version: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBigInt]>, z.ZodTransform<bigint, string | number | bigint>>>;
17
+ state: z.ZodEnum<{
18
+ deleted: "deleted";
19
+ active: "active";
20
+ wrapped: "wrapped";
21
+ }>;
22
+ observed_at: z.ZodString;
23
+ }, z.core.$strict>, z.ZodTransform<ObjectVersionFact, {
24
+ chain_id: string;
25
+ object_id: string;
26
+ object_version: bigint;
27
+ move_type: string;
28
+ owner_kind: string;
29
+ payload_uri: string;
30
+ payload_hash: string;
31
+ payload_format: string;
32
+ checkpoint: bigint;
33
+ tx_digest: string;
34
+ state: "deleted" | "active" | "wrapped";
35
+ observed_at: string;
36
+ owner_address?: string | undefined;
37
+ payload_json?: Record<string, unknown> | null | undefined;
38
+ previous_version?: bigint | undefined;
39
+ }>>;
40
+ export declare function parseObjectVersionFact(input: unknown): ObjectVersionFact;
@@ -0,0 +1 @@
1
+ import{isValidTransactionDigest,normalizeWowAddress,wowAddressToBytes}from'@wowok/wowok';import{z}from'zod';const uint64=z['union']([z['string']()['regex'](/^\d+$/),z['number']()['int']()['nonnegative']()['refine'](Number['isSafeInteger']),z['bigint']()['nonnegative']()])['transform'](a=>BigInt(a))['refine'](a=>a<=0x7fffffffffffffffn,'Integer\x20exceeds\x20PostgreSQL\x20BIGINT'),address=z['string']()['refine'](a=>{try{return wowAddressToBytes(a),!![];}catch{return![];}},'Invalid\x2032-byte\x20Wow\x20address'),hash32=z['string']()['regex'](/^(0x)?[0-9a-fA-F]{64}$/);export const ObjectVersionFactSchema=z['object']({'chain_id':z['string']()['min'](0x1)['max'](0x80),'object_id':address,'object_version':uint64,'move_type':z['string']()['min'](0x3)['max'](0x800),'owner_kind':z['string']()['min'](0x1)['max'](0x40),'owner_address':address['optional'](),'payload_uri':z['string']()['min'](0x1)['max'](0x1000),'payload_hash':hash32,'payload_format':z['string']()['min'](0x1)['max'](0x80),'payload_json':z['record'](z['string'](),z['unknown']())['nullable']()['optional'](),'checkpoint':uint64,'tx_digest':z['string']()['refine'](isValidTransactionDigest,'Invalid\x20transaction\x20digest'),'previous_version':uint64['optional'](),'state':z['enum'](['active','deleted','wrapped']),'observed_at':z['string']()['datetime']({'offset':!![]})})['strict']()['transform'](a=>({'chainId':a['chain_id'],'objectId':normalizeWowAddress(a['object_id']),'objectVersion':a['object_version'],'moveType':a['move_type'],'ownerKind':a['owner_kind'],'ownerAddress':a['owner_address']?normalizeWowAddress(a['owner_address']):undefined,'payloadUri':a['payload_uri'],'payloadHash':a['payload_hash'],'payloadFormat':a['payload_format'],'payloadJson':a['payload_json'],'checkpoint':a['checkpoint'],'txDigest':a['tx_digest'],'previousVersion':a['previous_version'],'state':a['state'],'observedAt':new Date(a['observed_at'])}));export function parseObjectVersionFact(a){return ObjectVersionFactSchema['parse'](a);}
@@ -0,0 +1,6 @@
1
+ export { ObjectVersionFactSchema, parseObjectVersionFact } from "./facts.js";
2
+ export { projectObjectVersion } from "./project.js";
3
+ export { PROJECTION_SCHEMA_SQL } from "./schema.js";
4
+ export { PostgresProjectionStore } from "./store.js";
5
+ export type { ListCurrentObjectsOptions } from "./store.js";
6
+ export type { ApplyProjectionResult, ApplyProjectionStatus, CurrentObject, CurrentObjectPage, ObjectVersionFact, ObjectVersionState, ProjectionCoverage, ProjectionStatus, } from "./types.js";
@@ -0,0 +1 @@
1
+ export{ObjectVersionFactSchema,parseObjectVersionFact}from'./facts.js';export{projectObjectVersion}from'./project.js';export{PROJECTION_SCHEMA_SQL}from'./schema.js';export{PostgresProjectionStore}from'./store.js';
@@ -0,0 +1,10 @@
1
+ import { type WowTypedObjectKind } from "@wowok/wowok";
2
+ import type { ObjectVersionFact } from "./types.js";
3
+ export interface ObjectProjection {
4
+ kindHint: number;
5
+ verifiedKind: WowTypedObjectKind | null;
6
+ shardCount: number;
7
+ shardIndex: number | null;
8
+ quarantineReason?: string;
9
+ }
10
+ export declare function projectObjectVersion(fact: ObjectVersionFact, shardCount: number): ObjectProjection;
@@ -0,0 +1 @@
1
+ import{classifyWowAddress,isWowTypedObjectTypeMatch,wowAddressShard,wowTypedKindFromMoveType}from'@wowok/wowok';export function projectObjectVersion(a,b){if(!Number['isInteger'](b)||b<0x1||b>0xffff)throw new Error('Invalid\x20shard\x20count:\x20'+b);const c=classifyWowAddress(a['objectId']),d=wowTypedKindFromMoveType(a['moveType']),e={'kindHint':c['tag'],'verifiedKind':d,'shardCount':b};if(!d)return{...e,'shardIndex':null,'quarantineReason':'UNSUPPORTED_OR_INVALID_MOVE_TYPE'};if(!isWowTypedObjectTypeMatch(a['objectId'],a['moveType']))return{...e,'shardIndex':null,'quarantineReason':'TYPED_ACTUAL_KIND_MISMATCH'};return{...e,'shardIndex':wowAddressShard(a['objectId'],d,b)};}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ import{toBase58,wowAddressShard}from'@wowok/wowok';import{DataType,newDb}from'pg-mem';import{afterEach,beforeEach,describe,expect,it}from'vitest';import{parseObjectVersionFact}from'./facts.js';import{PostgresProjectionStore}from'./store.js';const digest=toBase58(new Uint8Array(0x20)['fill'](0x7));function objectId(a=0x14,b=0x1){return'0x'+a['toString'](0x10)['padStart'](0x2,'0')+b['toString'](0x10)['padStart'](0x2,'0')['repeat'](0x1f);}function fact(a={}){return{'chain_id':'chain_a','object_id':objectId(),'object_version':'1','move_type':'0x2::service::Service<0x2::wow::WOW>','owner_kind':'Shared','payload_uri':'test://raw/service-1','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',...a};}describe('PostgresProjectionStore',()=>{let a;beforeEach(async()=>{const b=newDb();b['public']['registerFunction']({'name':'pg_advisory_xact_lock','args':[DataType['integer'],DataType['integer']],'returns':DataType['integer'],'implementation':()=>0x0});const {Pool:c}=b['adapters']['createPg'](),d=new c();a=new PostgresProjectionStore(d,0x10),await a['migrate']();}),afterEach(async()=>{await a?.['close']();}),it('applies\x20a\x20typed\x20object\x20once\x20and\x20preserves\x20raw\x20history\x20on\x20replay',async()=>{expect((await a['apply'](fact()))['status'])['toBe']('applied'),expect((await a['apply'](fact()))['status'])['toBe']('duplicate');const b=await a['status']('chain_a');expect(b)['toMatchObject']({'raw_versions':0x1,'current_objects':0x1,'active_objects':0x1,'quarantined_versions':0x0,'max_checkpoint':'100'});const c=await a['listCurrent']({'chainId':'chain_a'});expect(c['objects'])['toHaveLength'](0x1),expect(c['coverage'])['toMatchObject']({'mode':'known_objects','complete':![],'truncated':![],'degraded_reasons':['RECONCILIATION_REQUIRED']});}),it('allows\x20the\x20same\x20immutable\x20version\x20at\x20a\x20later\x20observation\x20checkpoint',async()=>{expect((await a['apply'](fact()))['status'])['toBe']('applied'),expect((await a['apply'](fact({'checkpoint':'101'})))['status'])['toBe']('duplicate'),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x1,'quarantined_versions':0x0});}),it('enriches\x20legacy\x20raw\x20rows\x20and\x20detects\x20JSON\x20content\x20conflicts\x20independently\x20of\x20key\x20order',async()=>{await a['apply'](fact()),expect((await a['apply'](fact({'payload_json':{'name':'one','stock':0x2}})))['status'])['toBe']('duplicate'),expect((await a['apply'](fact({'payload_json':{'stock':0x2,'name':'one'}})))['status'])['toBe']('duplicate'),expect((await a['apply'](fact()))['status'])['toBe']('duplicate'),expect((await a['listCurrent']({'chainId':'chain_a'}))['objects'][0x0]['payloadJson'])['toEqual']({'name':'one','stock':0x2});const b=await a['apply'](fact({'payload_json':{'name':'changed','stock':0x2}}));expect(b)['toMatchObject']({'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'});}),it('rejects\x20a\x20different\x20payload\x20hash\x20for\x20an\x20existing\x20immutable\x20version',async()=>{await a['apply'](fact());const b=await a['apply'](fact({'payload_hash':'0x'+'42'['repeat'](0x20)}));expect(b)['toMatchObject']({'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'}),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x1,'current_objects':0x1,'quarantined_versions':0x1});}),it('rejects\x20a\x20changed\x20payload\x20URI\x20for\x20an\x20existing\x20immutable\x20version',async()=>{await a['apply'](fact());const b=await a['apply'](fact({'payload_uri':'test://raw/service-1-conflict'}));expect(b)['toMatchObject']({'status':'conflict','reasonCode':'CONFLICTING_OBJECT_VERSION'}),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x1,'current_objects':0x1,'quarantined_versions':0x1});}),it('rejects\x20values\x20above\x20PostgreSQL\x20BIGINT',()=>{expect(()=>parseObjectVersionFact(fact({'object_version':'9223372036854775808'})))['toThrow']('Integer\x20exceeds\x20PostgreSQL\x20BIGINT');}),it('never\x20rolls\x20current\x20back\x20when\x20an\x20older\x20delta\x20arrives\x20late',async()=>{await a['apply'](fact({'object_version':'2','checkpoint':'101'}));const b=await a['apply'](fact());expect(b)['toMatchObject']({'status':'stale','currentVersion':'2'});const c=await a['listCurrent']({'chainId':'chain_a'});expect(c['objects'][0x0])['toMatchObject']({'objectVersion':'2','checkpoint':'101'}),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x2,'quarantined_versions':0x1});}),it('does\x20not\x20install\x20an\x20older\x20valid\x20version\x20after\x20a\x20newer\x20quarantined\x20version',async()=>{await a['apply'](fact({'object_version':'2','move_type':'0x2::demand::Demand','checkpoint':'101'})),expect((await a['apply'](fact()))['status'])['toBe']('stale'),expect((await a['listCurrent']({'chainId':'chain_a'}))['objects'])['toEqual']([]),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x2,'current_objects':0x0,'quarantined_versions':0x2});}),it('keeps\x20typed/actual\x20mismatches\x20out\x20of\x20normal\x20candidates',async()=>{const b=await a['apply'](fact({'move_type':'0x2::demand::Demand'}));expect(b)['toMatchObject']({'status':'quarantined','reasonCode':'TYPED_ACTUAL_KIND_MISMATCH'}),expect((await a['listCurrent']({'chainId':'chain_a'}))['objects'])['toEqual']([]),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x1,'current_objects':0x0,'quarantined_versions':0x1});}),it('retains\x20deletion\x20tombstones\x20while\x20withdrawing\x20active\x20candidates',async()=>{await a['apply'](fact()),await a['apply'](fact({'object_version':'2','state':'deleted','checkpoint':'101'})),expect((await a['listCurrent']({'chainId':'chain_a'}))['objects'])['toEqual']([]),expect(await a['status']('chain_a'))['toMatchObject']({'raw_versions':0x2,'current_objects':0x1,'active_objects':0x0});}),it('isolates\x20identical\x20object\x20ids\x20on\x20replacement\x20chains',async()=>{await a['apply'](fact()),await a['apply'](fact({'chain_id':'chain_b','checkpoint':'1'})),expect((await a['listCurrent']({'chainId':'chain_a'}))['objects'][0x0]['checkpoint'])['toBe']('100'),expect((await a['listCurrent']({'chainId':'chain_b'}))['objects'][0x0]['checkpoint'])['toBe']('1');}),it('uses\x20a\x20lookahead\x20row\x20for\x20pagination\x20and\x20kind+hash\x20shard\x20filters',async()=>{await a['apply'](fact({'object_id':objectId(0x14,0x1)})),await a['apply'](fact({'object_id':objectId(0x14,0x2)})),await a['apply'](fact({'object_id':objectId(0x14,0x3)}));const b=await a['listCurrent']({'chainId':'chain_a','kind':'Service','limit':0x2});expect(b['objects'])['toHaveLength'](0x2),expect(b['coverage']['truncated'])['toBe'](!![]),expect(b['next_cursor'])['toBe'](b['objects'][0x1]['objectId']);const c=await a['listCurrent']({'chainId':'chain_a','kind':'Service','cursor':b['next_cursor']??undefined,'limit':0x2});expect(c['objects'])['toHaveLength'](0x1),expect(c['coverage']['truncated'])['toBe'](![]);const d=b['objects'][0x0];expect(d['shardIndex'])['toBe'](wowAddressShard(d['objectId'],'Service',0x10));const e=await a['listCurrent']({'chainId':'chain_a','kind':'Service','shard':{'count':0x10,'index':d['shardIndex']}});expect(e['objects']['some'](g=>g['objectId']===d['objectId']))['toBe'](!![]);const f=await a['listCurrent']({'chainId':'chain_a','kind':'Service','shard':{'count':0x10,'index':(d['shardIndex']+0x1)%0x10}});expect(f['objects']['some'](g=>g['objectId']===d['objectId']))['toBe'](![]);});});
@@ -0,0 +1 @@
1
+ export declare const PROJECTION_SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS object_version (\n chain_id TEXT NOT NULL,\n object_id BYTEA NOT NULL,\n kind_hint SMALLINT NOT NULL,\n object_version BIGINT NOT NULL,\n move_type TEXT NOT NULL,\n owner_kind TEXT NOT NULL,\n owner_address BYTEA,\n payload_uri TEXT NOT NULL,\n payload_hash BYTEA NOT NULL,\n payload_format TEXT NOT NULL,\n payload_json JSONB,\n payload_json_present BOOLEAN NOT NULL DEFAULT FALSE,\n checkpoint BIGINT NOT NULL,\n tx_digest BYTEA NOT NULL,\n previous_version BIGINT,\n state TEXT NOT NULL CHECK (state IN ('active', 'deleted', 'wrapped')),\n observed_at TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (chain_id, object_id, object_version)\n);\nALTER TABLE object_version ADD COLUMN IF NOT EXISTS payload_json JSONB;\nALTER TABLE object_version ADD COLUMN IF NOT EXISTS payload_json_present BOOLEAN NOT NULL DEFAULT FALSE;\n\nCREATE TABLE IF NOT EXISTS object_current (\n chain_id TEXT NOT NULL,\n object_id BYTEA NOT NULL,\n kind_hint SMALLINT NOT NULL,\n object_version BIGINT NOT NULL,\n move_type TEXT NOT NULL,\n verified_kind TEXT NOT NULL,\n shard_count INTEGER NOT NULL,\n shard_index INTEGER NOT NULL,\n checkpoint BIGINT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('active', 'deleted', 'wrapped')),\n payload_hash BYTEA NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (chain_id, object_id)\n);\n\nCREATE INDEX IF NOT EXISTS object_current_kind_shard\n ON object_current (chain_id, verified_kind, shard_count, shard_index, object_id)\n WHERE state = 'active';\nCREATE INDEX IF NOT EXISTS object_current_kind_version\n ON object_current (chain_id, kind_hint, object_version DESC);\n\nCREATE TABLE IF NOT EXISTS quarantine (\n chain_id TEXT NOT NULL,\n object_id BYTEA NOT NULL,\n object_version BIGINT NOT NULL,\n reason_code TEXT NOT NULL,\n raw_ref TEXT NOT NULL,\n first_seen TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (chain_id, object_id, object_version, reason_code)\n);\n\n-- W2 live-set reconciliation. Evidence arrays are post-repair RESIDUALS\n-- (fail-closed: a pass verdict means all three residual sets are empty);\n-- pre-repair diff sizes are kept in the repaired_*/counts columns.\nCREATE TABLE IF NOT EXISTS reconciliation_run (\n chain_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n run_id TEXT NOT NULL,\n live_set_checkpoint BIGINT NOT NULL,\n missing TEXT[] NOT NULL DEFAULT '{}',\n extra TEXT[] NOT NULL DEFAULT '{}',\n version_drift TEXT[] NOT NULL DEFAULT '{}',\n missing_count INTEGER NOT NULL DEFAULT 0,\n extra_count INTEGER NOT NULL DEFAULT 0,\n version_drift_count INTEGER NOT NULL DEFAULT 0,\n repaired_missing INTEGER NOT NULL DEFAULT 0,\n repaired_drift INTEGER NOT NULL DEFAULT 0,\n tombstoned INTEGER NOT NULL DEFAULT 0,\n verdict TEXT NOT NULL CHECK (verdict IN ('pass', 'fail')),\n live_count INTEGER NOT NULL,\n projection_active INTEGER NOT NULL,\n generation INTEGER,\n reconciled_through BIGINT,\n started_at TIMESTAMPTZ NOT NULL,\n completed_at TIMESTAMPTZ NOT NULL,\n error TEXT,\n PRIMARY KEY (chain_id, kind, run_id)\n);\n\n-- Generation atomic publish: bumped ONLY inside the same transaction that\n-- records a verdict='pass' reconciliation run. Consumers read this table to\n-- decide whether coverage may drop RECONCILIATION_REQUIRED.\nCREATE TABLE IF NOT EXISTS projection_generation (\n chain_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n generation INTEGER NOT NULL,\n reconciled_through BIGINT NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (chain_id, kind)\n);\n\n-- W4 minimal graph materialization: static reference edges extracted from the\n-- applied version payload, synced in the same transaction as object_current.\n-- Out-degree lookup uses the PK prefix (chain_id, src); in-degree uses graph_edge_in.\nCREATE TABLE IF NOT EXISTS graph_edge (\n chain_id TEXT NOT NULL,\n src BYTEA NOT NULL,\n src_kind TEXT NOT NULL,\n edge TEXT NOT NULL,\n dst BYTEA NOT NULL,\n dst_kind TEXT NOT NULL,\n object_version BIGINT NOT NULL,\n PRIMARY KEY (chain_id, src, edge, dst)\n);\n\nCREATE INDEX IF NOT EXISTS graph_edge_in\n ON graph_edge (chain_id, dst, edge);\n\n-- R3-W1 public facet materialization (K5-10 \u00A72.4): versioned, evidence-backed\n-- retrieval/scoring facets extracted from the applied payload in the SAME\n-- transaction as object_current. Prices stay decimal TEXT (wei) \u2014 v1 filters\n-- run in the API layer for determinism and pg-mem testability; push down to\n-- NUMERIC + GIN when the corpus outgrows an in-memory facet scan.\nCREATE TABLE IF NOT EXISTS object_facet (\n chain_id TEXT NOT NULL,\n object_id BYTEA NOT NULL,\n verified_kind TEXT NOT NULL,\n facet_version TEXT NOT NULL,\n object_version BIGINT NOT NULL,\n industry TEXT,\n industry_confidence REAL NOT NULL DEFAULT 0,\n location TEXT,\n price_min TEXT,\n price_max TEXT,\n capabilities TEXT[] NOT NULL DEFAULT '{}',\n published BOOLEAN NOT NULL DEFAULT FALSE,\n paused BOOLEAN NOT NULL DEFAULT FALSE,\n name_tokens TEXT[] NOT NULL DEFAULT '{}',\n text_tokens TEXT[] NOT NULL DEFAULT '{}',\n keywords TEXT[] NOT NULL DEFAULT '{}',\n computed_at TEXT NOT NULL,\n PRIMARY KEY (chain_id, object_id)\n);\n\nCREATE INDEX IF NOT EXISTS object_facet_kind\n ON object_facet (chain_id, verified_kind);\n";
@@ -0,0 +1 @@
1
+ export const PROJECTION_SCHEMA_SQL='\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20object_version\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_id\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20kind_hint\x20SMALLINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_version\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20move_type\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20owner_kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20owner_address\x20BYTEA,\x0a\x20\x20\x20\x20payload_uri\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20payload_hash\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20payload_format\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20payload_json\x20JSONB,\x0a\x20\x20\x20\x20payload_json_present\x20BOOLEAN\x20NOT\x20NULL\x20DEFAULT\x20FALSE,\x0a\x20\x20\x20\x20checkpoint\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20tx_digest\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20previous_version\x20BIGINT,\x0a\x20\x20\x20\x20state\x20TEXT\x20NOT\x20NULL\x20CHECK\x20(state\x20IN\x20(\x27active\x27,\x20\x27deleted\x27,\x20\x27wrapped\x27)),\x0a\x20\x20\x20\x20observed_at\x20TIMESTAMPTZ\x20NOT\x20NULL,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20object_id,\x20object_version)\x0a);\x0aALTER\x20TABLE\x20object_version\x20ADD\x20COLUMN\x20IF\x20NOT\x20EXISTS\x20payload_json\x20JSONB;\x0aALTER\x20TABLE\x20object_version\x20ADD\x20COLUMN\x20IF\x20NOT\x20EXISTS\x20payload_json_present\x20BOOLEAN\x20NOT\x20NULL\x20DEFAULT\x20FALSE;\x0a\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20object_current\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_id\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20kind_hint\x20SMALLINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_version\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20move_type\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20verified_kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20shard_count\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20shard_index\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20checkpoint\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20state\x20TEXT\x20NOT\x20NULL\x20CHECK\x20(state\x20IN\x20(\x27active\x27,\x20\x27deleted\x27,\x20\x27wrapped\x27)),\x0a\x20\x20\x20\x20payload_hash\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20updated_at\x20TIMESTAMPTZ\x20NOT\x20NULL,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20object_id)\x0a);\x0a\x0aCREATE\x20INDEX\x20IF\x20NOT\x20EXISTS\x20object_current_kind_shard\x0a\x20\x20\x20\x20ON\x20object_current\x20(chain_id,\x20verified_kind,\x20shard_count,\x20shard_index,\x20object_id)\x0a\x20\x20\x20\x20WHERE\x20state\x20=\x20\x27active\x27;\x0aCREATE\x20INDEX\x20IF\x20NOT\x20EXISTS\x20object_current_kind_version\x0a\x20\x20\x20\x20ON\x20object_current\x20(chain_id,\x20kind_hint,\x20object_version\x20DESC);\x0a\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20quarantine\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_id\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_version\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20reason_code\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20raw_ref\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20first_seen\x20TIMESTAMPTZ\x20NOT\x20NULL,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20object_id,\x20object_version,\x20reason_code)\x0a);\x0a\x0a--\x20W2\x20live-set\x20reconciliation.\x20Evidence\x20arrays\x20are\x20post-repair\x20RESIDUALS\x0a--\x20(fail-closed:\x20a\x20pass\x20verdict\x20means\x20all\x20three\x20residual\x20sets\x20are\x20empty);\x0a--\x20pre-repair\x20diff\x20sizes\x20are\x20kept\x20in\x20the\x20repaired_*/counts\x20columns.\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20reconciliation_run\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20run_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20live_set_checkpoint\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20missing\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20extra\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20version_drift\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20missing_count\x20INTEGER\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20extra_count\x20INTEGER\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20version_drift_count\x20INTEGER\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20repaired_missing\x20INTEGER\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20repaired_drift\x20INTEGER\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20tombstoned\x20INTEGER\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20verdict\x20TEXT\x20NOT\x20NULL\x20CHECK\x20(verdict\x20IN\x20(\x27pass\x27,\x20\x27fail\x27)),\x0a\x20\x20\x20\x20live_count\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20projection_active\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20generation\x20INTEGER,\x0a\x20\x20\x20\x20reconciled_through\x20BIGINT,\x0a\x20\x20\x20\x20started_at\x20TIMESTAMPTZ\x20NOT\x20NULL,\x0a\x20\x20\x20\x20completed_at\x20TIMESTAMPTZ\x20NOT\x20NULL,\x0a\x20\x20\x20\x20error\x20TEXT,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20kind,\x20run_id)\x0a);\x0a\x0a--\x20Generation\x20atomic\x20publish:\x20bumped\x20ONLY\x20inside\x20the\x20same\x20transaction\x20that\x0a--\x20records\x20a\x20verdict=\x27pass\x27\x20reconciliation\x20run.\x20Consumers\x20read\x20this\x20table\x20to\x0a--\x20decide\x20whether\x20coverage\x20may\x20drop\x20RECONCILIATION_REQUIRED.\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20projection_generation\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20generation\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20reconciled_through\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20updated_at\x20TIMESTAMPTZ\x20NOT\x20NULL,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20kind)\x0a);\x0a\x0a--\x20W4\x20minimal\x20graph\x20materialization:\x20static\x20reference\x20edges\x20extracted\x20from\x20the\x0a--\x20applied\x20version\x20payload,\x20synced\x20in\x20the\x20same\x20transaction\x20as\x20object_current.\x0a--\x20Out-degree\x20lookup\x20uses\x20the\x20PK\x20prefix\x20(chain_id,\x20src);\x20in-degree\x20uses\x20graph_edge_in.\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20graph_edge\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20src\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20src_kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20edge\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20dst\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20dst_kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_version\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20src,\x20edge,\x20dst)\x0a);\x0a\x0aCREATE\x20INDEX\x20IF\x20NOT\x20EXISTS\x20graph_edge_in\x0a\x20\x20\x20\x20ON\x20graph_edge\x20(chain_id,\x20dst,\x20edge);\x0a\x0a--\x20R3-W1\x20public\x20facet\x20materialization\x20(K5-10\x20§2.4):\x20versioned,\x20evidence-backed\x0a--\x20retrieval/scoring\x20facets\x20extracted\x20from\x20the\x20applied\x20payload\x20in\x20the\x20SAME\x0a--\x20transaction\x20as\x20object_current.\x20Prices\x20stay\x20decimal\x20TEXT\x20(wei)\x20—\x20v1\x20filters\x0a--\x20run\x20in\x20the\x20API\x20layer\x20for\x20determinism\x20and\x20pg-mem\x20testability;\x20push\x20down\x20to\x0a--\x20NUMERIC\x20+\x20GIN\x20when\x20the\x20corpus\x20outgrows\x20an\x20in-memory\x20facet\x20scan.\x0aCREATE\x20TABLE\x20IF\x20NOT\x20EXISTS\x20object_facet\x20(\x0a\x20\x20\x20\x20chain_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_id\x20BYTEA\x20NOT\x20NULL,\x0a\x20\x20\x20\x20verified_kind\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20facet_version\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20object_version\x20BIGINT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20industry\x20TEXT,\x0a\x20\x20\x20\x20industry_confidence\x20REAL\x20NOT\x20NULL\x20DEFAULT\x200,\x0a\x20\x20\x20\x20location\x20TEXT,\x0a\x20\x20\x20\x20price_min\x20TEXT,\x0a\x20\x20\x20\x20price_max\x20TEXT,\x0a\x20\x20\x20\x20capabilities\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20published\x20BOOLEAN\x20NOT\x20NULL\x20DEFAULT\x20FALSE,\x0a\x20\x20\x20\x20paused\x20BOOLEAN\x20NOT\x20NULL\x20DEFAULT\x20FALSE,\x0a\x20\x20\x20\x20name_tokens\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20text_tokens\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20keywords\x20TEXT[]\x20NOT\x20NULL\x20DEFAULT\x20\x27{}\x27,\x0a\x20\x20\x20\x20computed_at\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20PRIMARY\x20KEY\x20(chain_id,\x20object_id)\x0a);\x0a\x0aCREATE\x20INDEX\x20IF\x20NOT\x20EXISTS\x20object_facet_kind\x0a\x20\x20\x20\x20ON\x20object_facet\x20(chain_id,\x20verified_kind);\x0a';
@@ -0,0 +1,49 @@
1
+ import { type WowTypedObjectKind } from "@wowok/wowok";
2
+ import { Pool } from "pg";
3
+ import type { ApplyProjectionResult, CurrentObjectPage, GraphEdgeView, ObjectFacetRow, ObjectVersionFact, ProjectionStatus, ProjectionWatermark, RecordReconciliationOptions, RecordReconciliationResult, ReconciliationGeneration } from "./types.js";
4
+ export interface ListCurrentObjectsOptions {
5
+ chainId: string;
6
+ kind?: WowTypedObjectKind;
7
+ shard?: {
8
+ count: number;
9
+ index: number;
10
+ };
11
+ cursor?: string;
12
+ limit?: number;
13
+ }
14
+ export declare class PostgresProjectionStore {
15
+ private readonly pool;
16
+ private readonly shardCount;
17
+ constructor(pool: Pool, shardCount?: number);
18
+ static fromDatabaseUrl(databaseUrl: string, shardCount?: number): PostgresProjectionStore;
19
+ migrate(): Promise<void>;
20
+ close(): Promise<void>;
21
+ apply(input: unknown): Promise<ApplyProjectionResult>;
22
+ applyFact(fact: ObjectVersionFact): Promise<ApplyProjectionResult>;
23
+ private applyWithClient;
24
+ private syncGraphEdges;
25
+ private syncFacets;
26
+ private attachJson;
27
+ private quarantine;
28
+ liveSetVersions(chainId: string, kind: string): Promise<Map<string, string>>;
29
+ markTombstone(chainId: string, objectId: string): Promise<boolean>;
30
+ markTombstoneIfKind(chainId: string, objectId: string, kind: string): Promise<boolean>;
31
+ edgesFrom(chainId: string, objectId: string): Promise<GraphEdgeView[]>;
32
+ edgesTo(chainId: string, objectId: string): Promise<GraphEdgeView[]>;
33
+ backfillGraphEdges(chainId: string): Promise<{
34
+ objects: number;
35
+ edges: number;
36
+ }>;
37
+ backfillFacets(chainId: string): Promise<{
38
+ objects: number;
39
+ facets: number;
40
+ }>;
41
+ activeFacets(chainId: string, kind?: string): Promise<ObjectFacetRow[]>;
42
+ currentPayloads(chainId: string, objectIds: string[]): Promise<Map<string, Record<string, unknown> | null>>;
43
+ recordReconciliation(options: RecordReconciliationOptions): Promise<RecordReconciliationResult>;
44
+ reconciliationSummary(chainId: string): Promise<ReconciliationGeneration[]>;
45
+ private reconciledThrough;
46
+ status(chainId: string): Promise<ProjectionStatus>;
47
+ watermarks(chainId: string): Promise<ProjectionWatermark[]>;
48
+ listCurrent(options: ListCurrentObjectsOptions): Promise<CurrentObjectPage>;
49
+ }
@@ -0,0 +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)};}}
@@ -0,0 +1,137 @@
1
+ import type { WowTypedObjectKind } from "@wowok/wowok";
2
+ export type ObjectVersionState = "active" | "deleted" | "wrapped";
3
+ export interface ObjectVersionFact {
4
+ chainId: string;
5
+ objectId: string;
6
+ objectVersion: bigint;
7
+ moveType: string;
8
+ ownerKind: string;
9
+ ownerAddress?: string;
10
+ payloadUri: string;
11
+ payloadHash: string;
12
+ payloadFormat: string;
13
+ payloadJson?: Record<string, unknown> | null;
14
+ checkpoint: bigint;
15
+ txDigest: string;
16
+ previousVersion?: bigint;
17
+ state: ObjectVersionState;
18
+ observedAt: Date;
19
+ }
20
+ export type ApplyProjectionStatus = "applied" | "duplicate" | "stale" | "quarantined" | "conflict";
21
+ export interface ApplyProjectionResult {
22
+ status: ApplyProjectionStatus;
23
+ currentVersion?: string;
24
+ reasonCode?: string;
25
+ }
26
+ export interface CurrentObject {
27
+ objectId: string;
28
+ objectVersion: string;
29
+ kindHint: number;
30
+ verifiedKind: WowTypedObjectKind;
31
+ shardCount: number;
32
+ shardIndex: number;
33
+ moveType: string;
34
+ checkpoint: string;
35
+ state: ObjectVersionState;
36
+ payloadHash: string;
37
+ payloadUri: string;
38
+ payloadFormat: string;
39
+ payloadJson: Record<string, unknown> | null;
40
+ ownerKind: string;
41
+ ownerAddress?: string;
42
+ updatedAt: string;
43
+ }
44
+ export interface ProjectionCoverage {
45
+ mode: "known_objects";
46
+ complete: false;
47
+ truncated: boolean;
48
+ total_enumerated: number;
49
+ chain_id: string;
50
+ reconciled_through: string | null;
51
+ degraded_reasons: string[];
52
+ }
53
+ export interface CurrentObjectPage {
54
+ objects: CurrentObject[];
55
+ next_cursor: string | null;
56
+ coverage: ProjectionCoverage;
57
+ }
58
+ export interface ProjectionWatermark {
59
+ verified_kind: WowTypedObjectKind;
60
+ max_checkpoint: string | null;
61
+ active_objects: number;
62
+ }
63
+ export interface GraphEdgeView {
64
+ src: string;
65
+ srcKind: string;
66
+ edge: string;
67
+ dst: string;
68
+ dstKind: string;
69
+ objectVersion: string;
70
+ dstProjected: boolean;
71
+ }
72
+ export interface ObjectFacetRow {
73
+ objectId: string;
74
+ verifiedKind: string;
75
+ objectVersion: string;
76
+ facetVersion: string;
77
+ industry: string | null;
78
+ industryConfidence: number;
79
+ location: string | null;
80
+ priceMin: string | null;
81
+ priceMax: string | null;
82
+ capabilities: string[];
83
+ published: boolean;
84
+ paused: boolean;
85
+ nameTokens: string[];
86
+ textTokens: string[];
87
+ keywords: string[];
88
+ checkpoint: string;
89
+ }
90
+ export interface ProjectionStatus {
91
+ chain_id: string;
92
+ raw_versions: number;
93
+ current_objects: number;
94
+ active_objects: number;
95
+ quarantined_versions: number;
96
+ max_checkpoint: string | null;
97
+ coverage: ProjectionCoverage;
98
+ reconciliations: ReconciliationGeneration[];
99
+ }
100
+ export interface ReconciliationGeneration {
101
+ kind: string;
102
+ generation: number;
103
+ reconciled_through: string;
104
+ verdict: string;
105
+ completed_at: string;
106
+ missing_count: number;
107
+ extra_count: number;
108
+ version_drift_count: number;
109
+ }
110
+ export interface RecordReconciliationOptions {
111
+ chainId: string;
112
+ kind: string;
113
+ runId: string;
114
+ liveSetCheckpoint: string;
115
+ missing: string[];
116
+ extra: string[];
117
+ versionDrift: string[];
118
+ preDiff: {
119
+ missing: number;
120
+ extra: number;
121
+ versionDrift: number;
122
+ };
123
+ repairs: {
124
+ missing: number;
125
+ drift: number;
126
+ tombstoned: number;
127
+ };
128
+ liveCount: number;
129
+ projectionActive: number;
130
+ error?: string;
131
+ }
132
+ export interface RecordReconciliationResult {
133
+ runId: string;
134
+ verdict: "pass" | "fail";
135
+ generation: number | null;
136
+ reconciledThrough: string | null;
137
+ }
@@ -0,0 +1 @@
1
+ export{};