@kedem/okdb 1.8.17 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/bin/okdb.js +1 -1
  2. package/docs/change-log.md +16 -16
  3. package/docs/embeddings.md +1 -1
  4. package/docs/functions.md +26 -25
  5. package/docs/http-cluster.md +157 -0
  6. package/docs/index.md +1 -0
  7. package/docs/manifest.json +5 -1
  8. package/docs/process-registry.md +185 -0
  9. package/docs/processors.md +61 -65
  10. package/docs/queue.md +23 -13
  11. package/docs/subscriptions.md +230 -0
  12. package/docs/worker-fleet.md +139 -0
  13. package/okdb-functions-runner-child.js +1 -1
  14. package/okdb-functions-sandbox-worker.js +1 -0
  15. package/okdb-http-worker-child.js +1 -0
  16. package/okdb-queue-load-handler.js +1 -0
  17. package/okdb-queue-spawn-child.js +1 -1
  18. package/okdb-views-bootstrap-worker.js +1 -1
  19. package/okdb-worker-child.js +1 -0
  20. package/okdb.js +1 -1
  21. package/package.json +1 -1
  22. package/public/sections/db/parts/db-overview.ok.js +1 -1
  23. package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -1
  24. package/public/sections/queue/parts/queue-jobs.ok.js +1 -1
  25. package/public/sections/system/index.ok.html +1 -1
  26. package/public/sections/system/modals/data-ops-modal.ok.js +1 -1
  27. package/public/sections/system/parts/system-process-panel.ok.js +1 -0
  28. package/public/sections/system/parts/system-processing-panel.ok.js +1 -0
  29. package/public/sections/system/parts/system-runtime-overview.ok.js +1 -0
  30. package/public/sections/system/parts/system-workers-panel.ok.js +1 -0
  31. package/types/environment.d.ts +21 -4
  32. package/types/features/embeddings.d.ts +11 -2
  33. package/types/features/queue.d.ts +27 -5
  34. package/types/features/views.d.ts +10 -10
  35. package/types/index.d.ts +54 -6
  36. package/types/options.d.ts +12 -0
  37. package/okdb-fts-handler.js +0 -1
  38. package/okdb-processor-worker.js +0 -1
  39. package/public/sections/processors/index.ok.html +0 -1
@@ -24,6 +24,18 @@ export interface OKDBOptions {
24
24
  runtimeDeclarations?: boolean;
25
25
  log?: { retainDays?: number };
26
26
  shutdownTimeout?: number;
27
+ /** Lifecycle role flags — gate which background work this instance runs.
28
+ * Defaults preserve full-role behavior; passive instances serve reads/writes
29
+ * but skip engines / async processors / compaction scheduling. */
30
+ engines?: boolean;
31
+ asyncProcessors?: boolean;
32
+ compaction?: 'active' | 'passive';
33
+ http?: boolean;
34
+ /** Which registered envs open() eagerly opens: 'all' (default), 'core'
35
+ * (~system/~log/default only), or an array of names (core + listed —
36
+ * an unknown listed name makes open() throw). Use openEnv(name) to open
37
+ * more on demand. */
38
+ envs?: 'all' | 'core' | string[];
27
39
  }
28
40
 
29
41
  export interface OKDBAuthOptions {
@@ -1 +0,0 @@
1
- "use strict";async function ftsApply(t,s){const p=s&&s.env;p&&p.okdb&&p.okdb.fts&&await p.okdb.fts._applyChanges(t,p)}module.exports={ftsApply:ftsApply},module.exports.default=ftsApply;
@@ -1 +0,0 @@
1
- 'use strict';const _0x516c2b=_0x45f0;(function(_0x4cd82a,_0x560c24){const _0xfb1404=_0x45f0,_0x104f0a=_0x4cd82a();while(!![]){try{const _0x5bd466=parseInt(_0xfb1404(0xea))/0x1+-parseInt(_0xfb1404(0xc9))/0x2*(-parseInt(_0xfb1404(0xe4))/0x3)+parseInt(_0xfb1404(0xdd))/0x4+parseInt(_0xfb1404(0xd8))/0x5+-parseInt(_0xfb1404(0x112))/0x6+-parseInt(_0xfb1404(0x110))/0x7+parseInt(_0xfb1404(0x109))/0x8;if(_0x5bd466===_0x560c24)break;else _0x104f0a['push'](_0x104f0a['shift']());}catch(_0x23c59f){_0x104f0a['push'](_0x104f0a['shift']());}}}(_0x28b4,0xd1db7));var require$$0=require(_0x516c2b(0xcb)),require$$1=require('lmdb'),require$$4=require(_0x516c2b(0xd5));function getDefaultExportFromCjs(_0xbf985e){const _0x484327=_0x516c2b;return _0xbf985e&&_0xbf985e[_0x484327(0xd7)]&&Object[_0x484327(0xe9)]['hasOwnProperty'][_0x484327(0xdb)](_0xbf985e,_0x484327(0x102))?_0xbf985e[_0x484327(0x102)]:_0xbf985e;}var okdbProcessorWorker$1={},okdbEnums,hasRequiredOkdbEnums;function requireOkdbEnums(){const _0xd4be3a=_0x516c2b;if(hasRequiredOkdbEnums)return okdbEnums;hasRequiredOkdbEnums=0x1;const _0x4c20b4={'PUT':'put','REMOVE':'remove','INDEX_DROP':_0xd4be3a(0xff),'INDEX_REGISTER':_0xd4be3a(0xde),'INDEX_RESET':_0xd4be3a(0xe7),'TYPE_REGISTER':_0xd4be3a(0x123),'TYPE_DROP':_0xd4be3a(0xe5),'FTS_REGISTER':_0xd4be3a(0xe3),'FTS_DROP':'dropFts','FTS_RESET':_0xd4be3a(0x125),'SCHEMA_SET':'setSchema','SCHEMA_DROP':_0xd4be3a(0x118),'TTL_SET':_0xd4be3a(0x124),'TTL_CLEAR':_0xd4be3a(0xf9)},_0x2f3ecc={'SYSTEM_READY':_0xd4be3a(0xe1),'SYSTEM_STOPPED':'system:stopped','SYSTEM_CLOCK_CHANGE':_0xd4be3a(0x121),'SYSTEM_POKE':_0xd4be3a(0xce),'SYSTEM_DRAIN':_0xd4be3a(0x100),'SYSTEM_TYPE_DROP':'system:type_drop','SYSTEM_BUS_STATE_CHANGE':'system:bus_state_change','ITEM_CREATE':_0xd4be3a(0x11b),'ITEM_UPDATE':'item:update','ITEM_REMOVE':_0xd4be3a(0x108),'INDEX_RESET':_0xd4be3a(0x10f),'INDEX_READY':_0xd4be3a(0xee),'INDEX_PROGRESS':_0xd4be3a(0x12a),'VIEW_PROGRESS':_0xd4be3a(0x117),'INDEX_DROP':_0xd4be3a(0xd9),'INDEX_REGISTERED':_0xd4be3a(0x12f),'FTS_REGISTERED':_0xd4be3a(0xd4),'FTS_DROP':_0xd4be3a(0x105),'FTS_RESET':_0xd4be3a(0x127),'SCHEMA_SET':_0xd4be3a(0xec),'SCHEMA_DROP':_0xd4be3a(0x131),'UNIQUE_VIOLATION':_0xd4be3a(0xd1),'UNIQUE_VIOLATION_RESOLVED':_0xd4be3a(0x10d),'REF_VIOLATION':'ref:violation','REF_VIOLATION_RESOLVED':_0xd4be3a(0xf0),'SYNC_APPLY':_0xd4be3a(0xf1),'TXN_START':_0xd4be3a(0x103),'TXN_END':_0xd4be3a(0xed),'TXN_ROLLBACK':'txn:rollback','TYPE_REGISTERED':'type:registered','TYPE_DROP':'type:drop','ENV_OPENED':_0xd4be3a(0x111),'ENV_REMOVED':_0xd4be3a(0x122),'TTL_EXPIRED':_0xd4be3a(0x12c),'TTL_SET':_0xd4be3a(0xf3),'TTL_CLEAR':'ttl:clear','LICENSE_INVALID':_0xd4be3a(0x104),'LICENSE_ADDED':_0xd4be3a(0xe0),'LICENSE_ACTIVATED':_0xd4be3a(0x10b),'LICENSE_REMOVED':_0xd4be3a(0x101)},_0x31b78f={'CREATING':_0xd4be3a(0xdf),'RESETTING':_0xd4be3a(0xfe),'READY':'ready','DROPPING':_0xd4be3a(0x128),'WAITING':_0xd4be3a(0xd3)},_0x39cef1={'CREATED':_0xd4be3a(0x10e),'STARTING':_0xd4be3a(0xcf),'STARTED':'started','STOPPING':'stopping','STOPPED':'stopped'},_0x14fc27={'CREATING':_0xd4be3a(0xdf),'READY':_0xd4be3a(0xda),'HALTED':_0xd4be3a(0x10a),'STOPPED':_0xd4be3a(0xd6),'RESETTING':_0xd4be3a(0xfe)},_0x2c0021=Object[_0xd4be3a(0xd0)]({'POKE':_0xd4be3a(0x132),'DRAIN':'bus:drain','TYPE_DROP':'bus:type_drop'});return okdbEnums={'BUS_EVENTS':_0x2c0021,'CHANGE_ACTIONS':_0x4c20b4,'EVENTS':_0x2f3ecc,'INDEX_STATE':_0x31b78f,'OKDB_STATE':_0x39cef1,'VIEW_STATE':_0x14fc27},okdbEnums;}function _0x28b4(){const _0x2f15e1=['resetFts','exports','fts:reset','dropping','export','index:progress','push','ttl:expired','error','remote','index:registered','live','schema:drop','bus:poke','41398DSvCxz','stop','worker_threads','originMode','ack','system:poke','starting','freeze','unique:violation','catch','waiting','fts:registered','./okdb','stopped','__esModule','551065NYHHQd','index:drop','ready','call','message','2465312RkhXeX','registerIndex','creating','license:added','system:ready','all','registerFts','159dqHoIk','dropType','origin','resetIndex','object','prototype','433620ghdNEV','drain','schema:set','txn:end','index:ready','self','ref:violation_resolved','sync:apply','getChanges','ttl:set','init','module','reqId','type:','from','clearTtl','batch','getRange','length','handle','resetting','dropIndex','system:drain','license:removed','default','txn:start','license:invalid','fts:drop','postMessage','action','item:remove','1617360wasyGF','halted','license:activated','drained','unique:violation_resolved','created','index:reset','502565qFEudw','env:opened','9168048HNRptx','filter','resolve','pong','exit','view:progress','dropSchema','open','function','item:create','close','type','PUT','ping','scanType','system:clock_change','env:removed','registerType','setTtl'];_0x28b4=function(){return _0x2f15e1;};return _0x28b4();}function _0x45f0(_0x4a03a7,_0x4f5f9){_0x4a03a7=_0x4a03a7-0xc9;const _0x28b4aa=_0x28b4();let _0x45f0f8=_0x28b4aa[_0x4a03a7];return _0x45f0f8;}var okdbProcessorOrigin,hasRequiredOkdbProcessorOrigin;function requireOkdbProcessorOrigin(){if(hasRequiredOkdbProcessorOrigin)return okdbProcessorOrigin;hasRequiredOkdbProcessorOrigin=0x1;function _0x1e0641(_0x4f8977,_0x1b6802,_0x117880){const _0x26262f=_0x45f0;if(_0x1b6802===_0x26262f(0xe2))return _0x4f8977;if(_0x1b6802===_0x26262f(0xef))return _0x4f8977[_0x26262f(0x113)](_0x129f76=>_0x129f76[_0x26262f(0xe6)]===_0x117880);if(_0x1b6802===_0x26262f(0x12e))return _0x4f8977[_0x26262f(0x113)](_0x4b05f7=>_0x4b05f7[_0x26262f(0xe6)]!==_0x117880);return _0x4f8977;}function _0x547f5f(_0x1057c2,_0x4295c6,_0x203a34){const _0x47e7eb=_0x45f0;if(_0x4295c6===_0x47e7eb(0xe2))return!![];if(_0x4295c6===_0x47e7eb(0xef))return _0x1057c2===_0x203a34;if(_0x4295c6===_0x47e7eb(0x12e))return _0x1057c2!==_0x203a34;return!![];}return okdbProcessorOrigin={'filterByOrigin':_0x1e0641,'passesOriginFilter':_0x547f5f},okdbProcessorOrigin;}var hasRequiredOkdbProcessorWorker;function requireOkdbProcessorWorker(){const _0x3cbbdf=_0x516c2b;if(hasRequiredOkdbProcessorWorker)return okdbProcessorWorker$1;hasRequiredOkdbProcessorWorker=0x1;const {parentPort:_0x531063,workerData:_0x41db27}=require$$0,_0x48b5a7=require$$1,_0x1feb76=_0x41db27['mode']??'snapshot';_0x1feb76==='live'?_0x304135()['catch'](_0x3b85bf=>{const _0x18156b=_0x45f0;_0x531063[_0x18156b(0x106)]({'type':_0x18156b(0x12d),'error':_0x3b85bf[_0x18156b(0xdc)]??String(_0x3b85bf)}),process[_0x18156b(0x116)](0x1);}):_0xe2ead1()[_0x3cbbdf(0xd2)](_0x41da36=>{const _0x2f7471=_0x3cbbdf;_0x531063[_0x2f7471(0x106)]({'type':_0x2f7471(0x12d),'error':_0x41da36[_0x2f7471(0xdc)]??String(_0x41da36)}),process['exit'](0x1);});async function _0xe2ead1(){const _0x2a8f72=_0x3cbbdf,{envPath:_0x16d467,type:_0x1c72c6,batchSize:_0x26c4c5,mapSize:_0x10de0a,compression:_0x2fa13e}=_0x41db27,_0x41c0aa=_0x48b5a7[_0x2a8f72(0x119)](_0x16d467,{'readOnly':!![],'maxDbs':0x80,'mapSize':_0x10de0a??0x100*0x400*0x400,'compression':_0x2fa13e??!![]}),_0x142d51=_0x41c0aa['openDB'](_0x2a8f72(0xf7)+_0x1c72c6+':data',{'dupSort':![],'useVersions':!![]}),_0x4d7660=_0x142d51[_0x2a8f72(0xfb)]({'snapshot':!![]});let _0x350240=null;const _0x471703=()=>new Promise(_0x98b3b0=>{_0x350240=_0x98b3b0;});_0x531063['on'](_0x2a8f72(0xdc),_0x32a6b1=>{const _0xdecd5d=_0x2a8f72;if(_0x32a6b1[_0xdecd5d(0x11d)]===_0xdecd5d(0xcd)&&_0x350240){const _0x13b594=_0x350240;_0x350240=null,_0x13b594();}});let _0x47a364=[],_0x4a1351=0x0;for(const {key:_0xc08881,value:_0x7306bb,version:_0x9246c6}of _0x4d7660){_0x47a364[_0x2a8f72(0x12b)]({'key':_0xc08881,'value':_0x7306bb,'version':_0x9246c6});if(_0x47a364[_0x2a8f72(0xfc)]>=_0x26c4c5){const _0x901a3e=_0x47a364['length'];_0x531063[_0x2a8f72(0x106)]({'type':_0x2a8f72(0xfa),'entries':_0x47a364,'processed':_0x4a1351}),await _0x471703(),_0x4a1351+=_0x901a3e,_0x47a364=[];}}_0x47a364['length']>0x0&&(_0x531063['postMessage']({'type':'batch','entries':_0x47a364,'processed':_0x4a1351}),await _0x471703(),_0x4a1351+=_0x47a364[_0x2a8f72(0xfc)]),await _0x41c0aa['close'](),_0x531063[_0x2a8f72(0x106)]({'type':'done','total':_0x4a1351}),process['exit'](0x0);}async function _0x304135(){const _0x50211c=_0x3cbbdf,{handlerModule:_0x53e40b,rootPath:_0x343bfb,envName:_0x782022,bus:_0xce7467}=_0x41db27,{CHANGE_ACTIONS:_0x53b566}=requireOkdbEnums(),{filterByOrigin:_0x28de08}=requireOkdbProcessorOrigin(),_0x2d700c=require$$4,_0x214064=new _0x2d700c(_0x343bfb,{'admin':![],'mcp':![],'http':![],'timeMachine':![],'engines':![],'asyncProcessors':![],'compaction':'passive','_skipBootRuntime':!![],..._0xce7467===![]?{'bus':![]}:{}});await _0x214064[_0x50211c(0x119)]();const _0x21d73a=_0x214064['env'](_0x782022),_0x1cab04=require(_0x53e40b[_0x50211c(0xf5)]);let _0x5d4953=_0x1cab04[_0x53e40b[_0x50211c(0x129)]]??_0x1cab04[_0x50211c(0x102)]??_0x1cab04;if(_0x5d4953&&typeof _0x5d4953===_0x50211c(0xe8)&&typeof _0x5d4953['handle']===_0x50211c(0x11a)){if(typeof _0x5d4953[_0x50211c(0xf4)]===_0x50211c(0x11a))await _0x5d4953[_0x50211c(0xf4)]({'env':_0x21d73a});_0x5d4953=_0x5d4953[_0x50211c(0xfd)]['bind'](_0x5d4953);}if(typeof _0x5d4953!==_0x50211c(0x11a))throw new Error('live\x20worker:\x20'+_0x53e40b['export']+'\x20is\x20not\x20a\x20function\x20in\x20'+_0x53e40b[_0x50211c(0xf5)]);let _0x4d9bab=Promise[_0x50211c(0x114)]();const _0x401d9e=_0x591be4=>{const _0x11b203=_0x50211c;return _0x4d9bab=_0x4d9bab['then'](_0x591be4)[_0x11b203(0xd2)](()=>{}),_0x4d9bab;};await new Promise(_0xac3b0f=>{const _0x21a710=_0x50211c;_0x531063['on'](_0x21a710(0xdc),_0x1b01ef=>{const _0x2b451a=_0x21a710;if(_0x1b01ef['type']===_0x2b451a(0xeb))_0x401d9e(async()=>{const _0x46e7b2=_0x2b451a;try{const _0x49e1d7=Array['from'](_0x21d73a[_0x46e7b2(0xf2)](_0x1b01ef[_0x46e7b2(0x120)],_0x1b01ef[_0x46e7b2(0xf8)],_0x1b01ef['to'])),_0x46a07f=_0x49e1d7[_0x46e7b2(0x113)](_0x1f876e=>_0x1f876e[_0x46e7b2(0x107)]===_0x53b566[_0x46e7b2(0x11e)]||_0x1f876e['action']===_0x53b566['REMOVE']),_0x3c2afb=_0x28de08(_0x46a07f,_0x1b01ef[_0x46e7b2(0xcc)],_0x1b01ef[_0x46e7b2(0xe6)]);await _0x5d4953(_0x3c2afb,{'mode':_0x46e7b2(0x130),'type':_0x1b01ef[_0x46e7b2(0x120)],'env':_0x21d73a}),_0x531063[_0x46e7b2(0x106)]({'type':_0x46e7b2(0x10c),'reqId':_0x1b01ef[_0x46e7b2(0xf6)],'lastClock':_0x1b01ef['to']});}catch(_0x2f519f){_0x531063[_0x46e7b2(0x106)]({'type':'drainError','reqId':_0x1b01ef['reqId'],'error':_0x2f519f[_0x46e7b2(0xdc)]??String(_0x2f519f)});}});else{if(_0x1b01ef[_0x2b451a(0x11d)]===_0x2b451a(0x11f))_0x531063[_0x2b451a(0x106)]({'type':_0x2b451a(0x115)});else _0x1b01ef['type']===_0x2b451a(0xca)&&_0xac3b0f();}});}),await _0x214064[_0x50211c(0x11c)](),process[_0x50211c(0x116)](0x0);}return okdbProcessorWorker$1;}var okdbProcessorWorkerExports=requireOkdbProcessorWorker(),okdbProcessorWorker=getDefaultExportFromCjs(okdbProcessorWorkerExports);module[_0x516c2b(0x126)]=okdbProcessorWorker;
@@ -1 +0,0 @@
1
- <script type="module">import s from"../../stores/events-store.js";export default{tag:"processors-index",unwrap:!0,context:s=>({processors:[],busy:!1,_unsubs:[],async load(){this.busy=!0;try{const s=await fetch(__ENV__.API+"/processors");s.ok&&(this.processors=(await s.json()).data??[])}catch{}finally{this.busy=!1}},async doPause(s){await fetch(__ENV__.API+"/processors/"+encodeURIComponent(s)+"/pause",{method:"POST"}),await this.load()},async doResume(s){await fetch(__ENV__.API+"/processors/"+encodeURIComponent(s)+"/resume",{method:"POST"}),await this.load()},async doRetry(s){await fetch(__ENV__.API+"/processors/"+encodeURIComponent(s)+"/retry",{method:"POST"}),await this.load()},async doResetCursor(s){s&&(await fetch(__ENV__.API+"/processors/cursor/reset",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cursorKey:s})}),await this.load())},stateColor(s){switch(s){case"online":return"var(--okdb-success)";case"building":return"var(--okdb-warning)";case"error":return"var(--okdb-danger)";case"waiting":return"var(--okdb-method-default)";case"paused":return"#818cf8";default:return"var(--okdb-app-fg-subtle)"}},lagLabel:s=>0===s.lag?"caught up":s.lag+" behind",progressPct:s=>s.progress?Math.round(100*(s.progress.percent??0)):null}),async init(o){await this.load();const e=()=>this.load();this._unsubs=[s.on("processor:ready",e),s.on("processor:error",e),s.on("processor:paused",e),s.on("processor:resumed",e),s.on("processor:retry",e)]},unmount(){for(const s of this._unsubs)s();this._unsubs=[]}};</script><style>.proc-grid{display:grid;grid-template-columns:1fr;gap:12px;padding:16px}.proc-card{background:var(--okdb-app-bg);border:1px solid var(--okdb-app-border);border-radius:8px;padding:14px 16px;font-size:13px}.proc-card__header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.proc-card__dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.proc-card__name{font-weight:600;color:var(--okdb-app-fg-strong);flex:1}.proc-card__state{font-size:11px;padding:2px 8px;border-radius:4px;text-transform:uppercase;letter-spacing:.5px}.proc-card__row{display:flex;gap:16px;margin-top:6px;font-size:12px;color:var(--okdb-method-default)}.proc-card__row strong{color:var(--okdb-app-fg)}.proc-card__actions{display:flex;gap:6px;margin-top:10px}.proc-card__actions button{font-size:11px;padding:3px 10px;border-radius:4px;border:1px solid var(--okdb-app-border-strong);background:var(--okdb-app-surface);color:var(--okdb-method-default);cursor:pointer}.proc-card__actions button:hover{background:var(--okdb-app-border);color:var(--okdb-app-fg-strong)}.proc-card__error{margin-top:6px;padding:6px 8px;background:var(--okdb-danger-soft-bg);border:1px solid #7f1d1d;border-radius:4px;color:var(--okdb-danger);font-size:12px;word-break:break-all}.proc-card__progress{margin-top:6px;height:4px;background:var(--okdb-app-border);border-radius:2px;overflow:hidden}.proc-card__progress-bar{height:100%;background:var(--okdb-accent);transition:width .3s ease;border-radius:2px}.proc-empty{color:var(--okdb-app-fg-subtle);text-align:center;padding:40px 16px;font-size:14px}</style><template><component import="../../layouts/_default.ok.html"><template name="sidebar"><div style="padding:8px 8px;font-size:12px;color:var(--okdb-method-default)"><strong style="color:var(--okdb-app-fg-strong)">Processors</strong><div style="margin-top:4px;opacity:.6">{{ processors.length }} registered</div></div></template><template name="header"><h2 style="margin:0;font-size:16px;color:var(--okdb-app-fg-strong)">Change Processors</h2></template><template name="default"><if :="processors.length === 0 && !busy"><div class="proc-empty">No processors registered.<br><span style="font-size:12px;opacity:.6">Processors are registered by subsystems (FTS, embeddings) or via <code>okdb.processor.register()</code>.</span></div></if><div class="proc-grid"><for :of="processors" let:p><div class="proc-card"><div class="proc-card__header"><span class="proc-card__dot" :style="'background:' + stateColor(p.paused ? 'paused' : p.state)"></span> <span class="proc-card__name">{{ p.meta?.name || p.id.slice(0, 8) }} </span><span class="proc-card__state" :style="'color:' + stateColor(p.paused ? 'paused' : p.state)">{{ p.paused ? 'paused' : p.state }}</span></div><div class="proc-card__row"><span>Type: <strong>{{ p.type }}</strong></span> <span>Mode: <strong>{{ p.mode }}</strong></span> <span>Lag: <strong>{{ lagLabel(p) }}</strong></span></div><div class="proc-card__row"><span>Clock: <strong>{{ p.lastClock }}</strong> / {{ p.headClock }}</span><if :="p.bootstrap"><span>Bootstrap: <strong>{{ p.bootstrap }}</strong></span></if></div><if :="progressPct(p) !== null && p.state === 'building'"><div class="proc-card__progress"><div class="proc-card__progress-bar" :style="'width:' + progressPct(p) + '%'"></div></div><div style="font-size:11px;color:var(--okdb-app-fg-subtle);margin-top:2px">{{ p.progress?.phase }} — {{ progressPct(p) }}%</div></if><if :="p.error"><div class="proc-card__error">{{ p.error }}</div></if><div class="proc-card__actions"><if :="!p.paused && p.state === 'online'"><button @click="doPause(p.id)">⏸ Pause</button></if><if :="p.paused"><button @click="doResume(p.id)">▶ Resume</button></if><if :="p.state === 'error'"><button @click="doRetry(p.id)">↻ Retry</button></if><if :="p.cursorKey"><button @click="doResetCursor(p.cursorKey)" title="Reset cursor for this processor — forces full reprocess on next start">⟲ Reset Cursor</button></if></div></div></for></div></template></component></template>