web_plsql 1.6.0 → 1.7.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.
- package/README.md +13 -1
- package/dist/frontend/assets/{main-DG_2Z-rA.js → main-DurwHchn.js} +1 -1
- package/dist/frontend/assets/main-DurwHchn.js.br +0 -0
- package/dist/frontend/assets/{main-DG_2Z-rA.js.gz → main-DurwHchn.js.gz} +0 -0
- package/dist/frontend/index.html +1 -1
- package/dist/frontend/index.html.br +0 -0
- package/dist/frontend/index.html.gz +0 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +4 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/frontend/assets/main-DG_2Z-rA.js.br +0 -0
package/README.md
CHANGED
|
@@ -218,7 +218,19 @@ The following mod_plsql DAD configuration translates to the configuration option
|
|
|
218
218
|
"rollback" this automatically rolls back any open transaction after each request.
|
|
219
219
|
"transactionCallbackType" this allows defining a custom handler as a JavaScript function.
|
|
220
220
|
- The option `auth` allows for custom authentication strategies.
|
|
221
|
-
|
|
221
|
+
- The option `setupExtensions` allows for injecting custom Express routes and middleware.
|
|
222
|
+
This hook is executed after the database connection pools are initialized but before the static file routes and SPA fallback are mounted.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
setupExtensions: async (app, pools) => {
|
|
226
|
+
// app is the Express application
|
|
227
|
+
// pools is an array of initialized Oracle connection pools
|
|
228
|
+
app.get('/api-ext/test', (req, res) => {
|
|
229
|
+
res.json({ status: 'ok', poolsCount: pools.length });
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
222
234
|
**Basic Authentication**:
|
|
223
235
|
```typescript
|
|
224
236
|
auth: {
|
|
@@ -144,4 +144,4 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
144
144
|
<td class="text-right font-mono">${r}</td>
|
|
145
145
|
</tr>
|
|
146
146
|
`}).join(``)}catch(e){console.error(`Failed to load stats history:`,e),t&&(t.textContent=`Failed to load stats`)}}async function AC(){let e=document.getElementById(`access-filter`),t=document.getElementById(`access-limit`),n=e?.value??``,r=t?Number.parseInt(t.value):100,i=await Qp.getAccessLogs(r,n),a=document.getElementById(`access-log-view`),o=document.getElementById(`access-log-range`);if(!a)return;let s=0;Array.isArray(i)?(a.textContent=i.join(`
|
|
147
|
-
`),s=i.length):i&&typeof i==`object`&&`message`in i?(a.textContent=i.message,s=0):(a.textContent=`No logs available`,s=0),o&&(o.textContent=s>0?`Showing last ${s} log entries`:`No logs available`),a.parentElement&&(a.parentElement.scrollTop=a.parentElement.scrollHeight)}async function jC(){let e=document.getElementById(`trace-filter`),t=document.getElementById(`trace-limit`),n=document.getElementById(`trace-status-toggle`),r=e?.value??``,i=t?Number.parseInt(t.value):100;try{let{enabled:e}=await Qp.getTraceStatus();n&&(n.textContent=e?`Tracing: ON`:`Tracing: OFF`,n.dataset.enabled=String(e),n.className=`px-4 py-2 rounded-lg text-sm font-bold transition-colors ${e?`bg-success text-black hover:bg-success/80`:`bg-white/10 text-white hover:bg-white/20`}`)}catch(e){console.error(`Failed to get trace status`,e)}let a=await Qp.getTraceLogs(i,r);new DC(`trace-table`,{columns:[{id:`timestamp`,header:`Timestamp`,headerTitle:`Time of request`,width:`1%`,accessor:e=>new Date(e.timestamp).toLocaleString(),className:`font-mono text-xs text-dim whitespace-nowrap`},{id:`source`,header:`Source`,headerTitle:`Request source (IP/User)`,width:`1%`,accessor:e=>e.source,className:`text-dim text-xs truncate max-w-[150px]`,cellTitle:e=>e.source},{id:`method`,header:`Method`,headerTitle:`HTTP Method`,width:`1%`,accessor:e=>e.method,className:`font-mono text-xs whitespace-nowrap`},{id:`url`,header:`Request URL`,headerTitle:`Request URL`,accessor:e=>e.url,className:`text-bright font-mono text-xs truncate max-w-[800px]`,cellTitle:e=>e.url},{id:`status`,header:`Status`,headerTitle:`HTTP Status Code`,width:`1%`,accessor:e=>e.status,className:e=>`font-bold text-xs uppercase whitespace-nowrap ${e.status===`success`?`text-success`:`text-danger`}`},{id:`duration`,header:`Duration`,headerTitle:`Execution time in ms`,width:`1%`,align:`right`,accessor:e=>gC(e.duration),className:`font-mono text-xs text-dim whitespace-nowrap`}],dense:!0,tableLayout:`auto`,onRowClick:e=>{let t=document.getElementById(`trace-modal`),n=document.getElementById(`trace-detail-content`);t&&n&&(n.textContent=JSON.stringify(e,null,2),t.style.display=`flex`)}}).render(a)}function MC(e){let t=document.getElementById(`pools-container`);!t||!e.pools||(t.innerHTML=e.pools.map(e=>SC(e)).join(``))}function NC(e){let t=e.status.config;if(!t)return;let n=document.getElementById(`config-view`);n&&(n.innerHTML=EC(t))}function PC(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**+r).toFixed(2))} ${n[r]}`}function FC(e){return gC(e/1e3)}function IC(e,t){let n=document.getElementById(`middleware-version`);n&&e.version&&(n.textContent=`${e.version} (4/8/2026, 11:31:42 AM)`,n.title=`The version of the web_plsql gateway and admin console build time`);let r=document.getElementById(`node-version`);r&&e.system&&(r.textContent=e.system.nodeVersion,r.title=`The version of the Node.js runtime`);let i=document.getElementById(`platform-info`);i&&e.system&&(i.textContent=`${e.system.platform} (${e.system.arch})`,i.title=`The operating system and architecture`);let a=document.getElementById(`system-uptime`);a&&e.uptime&&(a.textContent=hC(e.uptime));let o=document.getElementById(`system-start-time`);o&&e.startTime&&(o.textContent=_C(e.startTime));let s=document.getElementById(`system-status-text`);s&&(s.textContent=e.status?.toUpperCase()??`-`);let c=document.getElementById(`total-requests`);c&&e.metrics&&(c.textContent=e.metrics.requestCount.toLocaleString(),c.title=`Cumulative number of requests handled by the server`);let l=document.getElementById(`total-errors`);l&&e.metrics&&(l.textContent=e.metrics.errorCount.toLocaleString(),l.title=`Cumulative number of failed requests`);let u=document.getElementById(`active-pools`);if(u&&e.pools&&(u.textContent=e.pools.length.toString(),u.title=`Number of database connection pools currently active`),e.system){let t=e.system,n={heapUsed:t.memory.heapUsed,heapTotal:t.memory.heapTotal,rss:t.memory.rss,external:t.memory.external,cpuUser:t.cpu.user,cpuSystem:t.cpu.system},r=(e,r,i)=>{let a=n[r],o=t.memory[i],s=document.getElementById(e),c=document.getElementById(`${e}-max`);s&&(s.textContent=PC(a)),c&&typeof o==`number`&&(c.textContent=PC(o))},i=(e,r,i)=>{let a=n[r],o=document.getElementById(e);if(o&&(o.textContent=FC(a)),i){let n=t.cpu[i],r=document.getElementById(`${e}-max`);r&&typeof n==`number`&&(r.textContent=FC(n))}};r(`memory-heap-used`,`heapUsed`,`heapUsedMax`),r(`memory-heap-total`,`heapTotal`,`heapTotalMax`),r(`memory-rss`,`rss`,`rssMax`),r(`memory-external`,`external`,`externalMax`),i(`cpu-user`,`cpuUser`,`userMax`),i(`cpu-system`,`cpuSystem`,`systemMax`);let a=document.getElementById(`cpu-percent`);a&&t.cpu.max!==void 0&&(a.textContent=`${t.cpu.max.toFixed(1)}%`,a.title=`Max System CPU usage`);let o=document.getElementById(`memory-percent`);o&&t.memory.totalMemory&&(o.textContent=`${(t.memory.rss/t.memory.totalMemory*100).toFixed(1)}%`,o.title=`System Memory Used relative to Total (${PC(t.memory.totalMemory)})`);let s=document.getElementById(`cpu-cores-info`);s&&t.cpuCores&&(s.textContent=`${t.cpuCores} Cores`)}}async function LC(e,t){let n=e.querySelector(`.material-symbols-rounded`),r=n?.textContent;e.disabled=!0,e.classList.add(`loading`),n&&(n.textContent=`sync`,n.classList.add(`animate-spin`));try{return await t()}finally{e.disabled=!1,e.classList.remove(`loading`),n&&(n.textContent=r??``,n.classList.remove(`animate-spin`))}}function RC(e,t){let n=document.getElementById(e);return n&&n.addEventListener(`click`,()=>void LC(n,t)),n}var zC={overview:`dashboard`,trace:`bolt`,errors:`error`,access:`list_alt`,pools:`database`,stats:`query_stats`,config:`settings`,system:`terminal`},$={currentView:`overview`,status:{},maxHistoryPoints:30,lastRequestCount:0,lastErrorCount:0,lastUpdateTime:Date.now(),lastBucketTimestamp:0,nextRefreshTimeout:null,nextRefreshTime:0,countdownInterval:null,history:{labels:[],requests:[],avgResponseTimes:[],p95ResponseTimes:[],p99ResponseTimes:[],cpuUsage:[],memoryUsage:[],poolUsage:{}},charts:{},metricsMin:{},metricsMax:{}},BC={REFRESH_INTERVAL:`admin_refresh_interval`,HISTORY_DURATION:`admin_history_duration`,AUTO_REFRESH:`admin_auto_refresh`,THEME:`theme`,LAST_VIEW:`admin_last_view`};function VC(e){console.error(`Connection lost:`,e);let t=document.getElementById(`server-status-dot`),n=document.getElementById(`server-status-text`);t&&(t.className=`dot offline`),n&&(n.textContent=`OFFLINE`);let r=document.getElementById(`btn-pause`);r&&(r.style.display=`none`);let i=document.getElementById(`btn-resume`);i&&(i.style.display=`none`);let a=document.querySelector(`#system-status .dot`),o=document.getElementById(`system-status-text`);a&&(a.className=`dot offline`),o&&(o.textContent=`OFFLINE`);let s=document.getElementById(`offline-modal`);s&&s.style.display!==`flex`&&(s.style.display=`flex`),GC(6e4),HC(6e4)}function HC(e){$.countdownInterval&&clearInterval($.countdownInterval);let t=Date.now()+e,n=document.getElementById(`offline-countdown`),r=document.getElementById(`reconnect-text`);r&&(r.textContent=`Try Reconnect`);let i=()=>{if(!n)return;let e=Math.max(0,Math.ceil((t-Date.now())/1e3));n.textContent=`Retrying in ${e}s...`,e<=0&&$.countdownInterval&&(clearInterval($.countdownInterval),$.countdownInterval=null)};i(),$.countdownInterval=setInterval(i,1e3)}function UC(){$.countdownInterval&&=(clearInterval($.countdownInterval),null);let e=document.getElementById(`offline-countdown`);e&&(e.textContent=``)}async function WC(e=!1,t=!1){let n=document.getElementById(`reconnect-spinner`),r=document.getElementById(`reconnect-icon`),i=document.getElementById(`reconnect-text`);n&&(n.style.display=`inline-block`),r&&(r.style.display=`none`),i&&(i.textContent=`Connecting...`);try{let a=Date.now(),o=await Qp.getStatus(e,t),s=document.getElementById(`offline-modal`);if(s?.style.display===`flex`&&s&&(s.style.display=`none`,UC()),n&&(n.style.display=`none`),r&&(r.style.display=`inline-block`),i&&(i.textContent=`Try Reconnect`),o.history&&$.history.labels.length===0&&pC($,o.history),!o.config&&$.status.config&&(o.config=$.status.config),$.status=o,!o.metrics||!o.pools)return;let c=o.history?.at(-1),l=(o.intervalMs??5e3)/1e3,u=c?c.requests/l:0,d=c?c.durationAvg:o.metrics.avgResponseTime;if($.lastRequestCount=o.metrics.requestCount,$.lastErrorCount=o.metrics.errorCount,$.lastUpdateTime=a,o.system){let e=o.system;vC({heapUsed:e.memory.heapUsed,heapTotal:e.memory.heapTotal,rss:e.memory.rss,external:e.memory.external,cpuUser:e.cpu.user,cpuSystem:e.cpu.system},$.metricsMin,$.metricsMax)}c&&c.timestamp>$.lastBucketTimestamp?($.lastBucketTimestamp=c.timestamp,mC($,new Date(c.timestamp).toLocaleTimeString(),u,d,o.pools)):!c&&$.history.labels.length===0&&mC($,new Date().toLocaleTimeString(),0,0,o.pools);let f=document.getElementById(`sidebar-version`);f&&(f.textContent=`v${o.version}`);let p=document.getElementById(`uptime-val`);p&&(p.textContent=hC(o.uptime));let m=document.getElementById(`start-time-val`);m&&(m.textContent=`Started: ${_C(o.startTime)}`);let h=document.getElementById(`req-per-sec`);h&&(h.textContent=u.toFixed(2));let g=document.getElementById(`max-req-per-sec`);g&&(g.textContent=o.metrics.maxRequestsPerSecond.toFixed(2));let _=document.getElementById(`avg-resp-time`);_&&(_.textContent=`${o.metrics.avgResponseTime.toFixed(1)}ms`);let v=document.getElementById(`max-resp-time`);v&&(v.textContent=`${o.metrics.maxResponseTime.toFixed(1)}ms`);let y=document.getElementById(`err-count`);y&&(y.textContent=o.metrics.errorCount.toLocaleString());let b=0,x=0;o.pools.forEach(e=>{e.cache&&(b+=e.cache.procedureName.hits+e.cache.argument.hits,x+=e.cache.procedureName.misses+e.cache.argument.misses)});let S=b+x,C=S>0?Math.round(b/S*100):0,w=document.getElementById(`cache-hit-rate-val`);w&&(w.textContent=`${C}%`,w.style.color=C>80?`var(--success)`:C>50?`var(--warning)`:`var(--danger)`);let T=document.getElementById(`cache-hits-val`);T&&(T.textContent=b.toLocaleString());let E=document.getElementById(`cache-misses-val`);E&&(E.textContent=x.toLocaleString());let ee=document.getElementById(`server-status-dot`),te=document.getElementById(`server-status-text`);ee&&(ee.className=`dot `+o.status),te&&(te.textContent=o.status.toUpperCase());let ne=document.getElementById(`btn-pause`);ne&&(ne.style.display=o.status===`running`?`flex`:`none`);let re=document.getElementById(`btn-resume`);re&&(re.style.display=o.status===`paused`?`flex`:`none`),$.currentView===`errors`&&await OC(),$.currentView===`trace`&&await jC(),$.currentView===`pools`&&MC(o),$.currentView===`config`&&NC($),$.currentView===`system`&&IC(o,$),YC?.checked&&XC&&GC(Number.parseInt(XC.value,10))}catch(e){document.getElementById(`offline-modal`)?.style.display===`flex`?(GC(6e4),HC(6e4),n&&(n.style.display=`none`),r&&(r.style.display=`inline-block`),i&&(i.textContent=`Try Reconnect`)):VC(e)}}function GC(e){$.nextRefreshTimeout&&=(clearTimeout($.nextRefreshTimeout),null),$.nextRefreshTime=Date.now()+e,$.nextRefreshTimeout=setTimeout(()=>{WC()},e)}function KC(){let e=document.getElementById(`refresh-interval`);e&&GC(Number.parseInt(e.value))}function qC(){$.nextRefreshTimeout&&=(clearTimeout($.nextRefreshTimeout),null)}function JC(){let e=document.getElementById(`chart-history-points`);e&&Array.from(e.options).forEach(e=>{let t=Number.parseInt(e.value),n=``;if(t<60)n=`${t}s`;else if(t<3600)n=`${Math.round(t/60)} min`;else{let e=t/3600;n=e===Math.round(e)?`${e} hour${e>1?`s`:``}`:`${e.toFixed(1)} hours`}e.textContent=`Last ${n}`})}document.querySelectorAll(`nav button`).forEach(e=>{let t=e;t.addEventListener(`click`,async()=>{try{let e=t.dataset.view;if(!e)return;$.currentView=e,localStorage.setItem(BC.LAST_VIEW,e),document.querySelectorAll(`.view`).forEach(e=>{let t=e;t.style.display=`none`});let n=document.getElementById(`view-`+e);n&&(n.style.display=`block`),document.querySelectorAll(`nav button`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`);let r=document.getElementById(`view-title`);if(r){let n=Array.from(t.childNodes).filter(e=>e.nodeType===Node.TEXT_NODE).map(e=>e.textContent?.trim()).join(``);r.innerHTML=`<span class="material-symbols-rounded">${zC[e]??`chevron_right`}</span>${n}`}e===`errors`&&await OC(),e===`trace`&&await jC(),e===`pools`&&MC($.status),e===`stats`&&await kC(),e===`config`&&NC($),e===`system`&&IC($.status,$)}catch(e){VC(e)}})});var YC=document.getElementById(`auto-refresh-toggle`);YC&&YC.addEventListener(`change`,e=>{let t=e.target;localStorage.setItem(BC.AUTO_REFRESH,String(t.checked)),t.checked?KC():qC()});var XC=document.getElementById(`refresh-interval`);XC&&XC.addEventListener(`change`,()=>{localStorage.setItem(BC.REFRESH_INTERVAL,XC.value);let e=Number.parseInt(XC.value),t=Number.parseInt(ZC?.value??`60`);$.maxHistoryPoints=Math.max(1,Math.floor(t/(e/1e3))),$.history.labels=[],$.history.requests=[],$.history.avgResponseTimes=[],$.history.cpuUsage=[],$.history.memoryUsage=[],$.history.poolUsage={},JC(),IC($.status,$),WC()});var ZC=document.getElementById(`chart-history-points`);ZC&&ZC.addEventListener(`change`,()=>{localStorage.setItem(BC.HISTORY_DURATION,ZC.value);let e=document.getElementById(`refresh-interval`);if(!e)return;let t=Number.parseInt(e.value),n=Number.parseInt(ZC.value);$.maxHistoryPoints=Math.max(1,Math.floor(n/(t/1e3))),$.history.labels=[],$.history.requests=[],$.history.avgResponseTimes=[],$.history.cpuUsage=[],$.history.memoryUsage=[],$.history.poolUsage={},WC()});var QC=document.getElementById(`manual-refresh`);QC&&QC.addEventListener(`click`,()=>{LC(QC,WC)});var $C=document.getElementById(`error-filter`);$C&&$C.addEventListener(`keydown`,e=>{e.key===`Enter`&&OC()}),RC(`error-load-btn`,OC),RC(`trace-load-btn`,jC),RC(`access-load-btn`,AC),RC(`stats-load-btn`,kC);var ew=document.getElementById(`trace-filter`);ew&&ew.addEventListener(`keydown`,e=>{e.key===`Enter`&&jC()});var tw=document.getElementById(`trace-clear-btn`);tw&&tw.addEventListener(`click`,async()=>{confirm(`Are you sure you want to clear all traces?`)&&await LC(tw,async()=>{await Qp.clearTraces(),await jC()})});var nw=document.getElementById(`trace-status-toggle`);nw&&nw.addEventListener(`click`,async()=>{await LC(nw,async()=>{let{enabled:e}=await Qp.getTraceStatus();await Qp.toggleTrace(!e),await jC()})});var rw=document.getElementById(`access-filter`);rw&&rw.addEventListener(`keydown`,e=>{e.key===`Enter`&&AC()});var iw=document.getElementById(`stats-limit`);iw&&iw.addEventListener(`keydown`,e=>{e.key===`Enter`&&kC()}),RC(`btn-pause`,async()=>{confirm(`Are you sure you want to pause the server?`)&&(await Qp.post(`api/server/pause`),await WC())}),RC(`btn-resume`,async()=>{await Qp.post(`api/server/resume`),await WC()}),RC(`btn-stop`,async()=>{confirm(`Are you sure you want to STOP the server? This action cannot be undone from the web interface.`)&&(await Qp.post(`api/server/stop`),alert(`Server stop requested. The interface will now become unresponsive.`))}),RC(`btn-clear-all-cache`,async()=>{confirm(`Are you sure you want to clear ALL caches?`)&&(await Qp.post(`api/cache/clear`),await WC())});var aw=document.getElementById(`btn-reconnect`);aw&&aw.addEventListener(`click`,()=>{LC(aw,WC)}),globalThis.addEventListener(`keydown`,e=>{if(e.key===`Escape`){let e=document.getElementById(`error-modal`);e&&(e.style.display=`none`);let t=document.getElementById(`trace-modal`);t&&(t.style.display=`none`)}});var ow=localStorage.getItem(BC.REFRESH_INTERVAL);ow&&XC&&(XC.value=ow);var sw=localStorage.getItem(BC.HISTORY_DURATION);sw&&ZC&&(ZC.value=sw);var cw=localStorage.getItem(BC.AUTO_REFRESH);if(cw!==null&&YC&&(YC.checked=cw===`true`),xC($),fC($),JC(),XC&&ZC){let e=Number.parseInt(XC.value),t=Number.parseInt(ZC.value);$.maxHistoryPoints=Math.max(1,Math.floor(t/(e/1e3)))}var lw=localStorage.getItem(BC.LAST_VIEW);if(lw){let e=document.querySelector(`nav button[data-view="${lw}"]`);e&&e.click()}WC(!0,!0).then(()=>{YC?.checked&&KC()}).catch(console.error);
|
|
147
|
+
`),s=i.length):i&&typeof i==`object`&&`message`in i?(a.textContent=i.message,s=0):(a.textContent=`No logs available`,s=0),o&&(o.textContent=s>0?`Showing last ${s} log entries`:`No logs available`),a.parentElement&&(a.parentElement.scrollTop=a.parentElement.scrollHeight)}async function jC(){let e=document.getElementById(`trace-filter`),t=document.getElementById(`trace-limit`),n=document.getElementById(`trace-status-toggle`),r=e?.value??``,i=t?Number.parseInt(t.value):100;try{let{enabled:e}=await Qp.getTraceStatus();n&&(n.textContent=e?`Tracing: ON`:`Tracing: OFF`,n.dataset.enabled=String(e),n.className=`px-4 py-2 rounded-lg text-sm font-bold transition-colors ${e?`bg-success text-black hover:bg-success/80`:`bg-white/10 text-white hover:bg-white/20`}`)}catch(e){console.error(`Failed to get trace status`,e)}let a=await Qp.getTraceLogs(i,r);new DC(`trace-table`,{columns:[{id:`timestamp`,header:`Timestamp`,headerTitle:`Time of request`,width:`1%`,accessor:e=>new Date(e.timestamp).toLocaleString(),className:`font-mono text-xs text-dim whitespace-nowrap`},{id:`source`,header:`Source`,headerTitle:`Request source (IP/User)`,width:`1%`,accessor:e=>e.source,className:`text-dim text-xs truncate max-w-[150px]`,cellTitle:e=>e.source},{id:`method`,header:`Method`,headerTitle:`HTTP Method`,width:`1%`,accessor:e=>e.method,className:`font-mono text-xs whitespace-nowrap`},{id:`url`,header:`Request URL`,headerTitle:`Request URL`,accessor:e=>e.url,className:`text-bright font-mono text-xs truncate max-w-[800px]`,cellTitle:e=>e.url},{id:`status`,header:`Status`,headerTitle:`HTTP Status Code`,width:`1%`,accessor:e=>e.status,className:e=>`font-bold text-xs uppercase whitespace-nowrap ${e.status===`success`?`text-success`:`text-danger`}`},{id:`duration`,header:`Duration`,headerTitle:`Execution time in ms`,width:`1%`,align:`right`,accessor:e=>gC(e.duration),className:`font-mono text-xs text-dim whitespace-nowrap`}],dense:!0,tableLayout:`auto`,onRowClick:e=>{let t=document.getElementById(`trace-modal`),n=document.getElementById(`trace-detail-content`);t&&n&&(n.textContent=JSON.stringify(e,null,2),t.style.display=`flex`)}}).render(a)}function MC(e){let t=document.getElementById(`pools-container`);!t||!e.pools||(t.innerHTML=e.pools.map(e=>SC(e)).join(``))}function NC(e){let t=e.status.config;if(!t)return;let n=document.getElementById(`config-view`);n&&(n.innerHTML=EC(t))}function PC(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**+r).toFixed(2))} ${n[r]}`}function FC(e){return gC(e/1e3)}function IC(e,t){let n=document.getElementById(`middleware-version`);n&&e.version&&(n.textContent=`${e.version} (4/8/2026, 11:51:20 AM)`,n.title=`The version of the web_plsql gateway and admin console build time`);let r=document.getElementById(`node-version`);r&&e.system&&(r.textContent=e.system.nodeVersion,r.title=`The version of the Node.js runtime`);let i=document.getElementById(`platform-info`);i&&e.system&&(i.textContent=`${e.system.platform} (${e.system.arch})`,i.title=`The operating system and architecture`);let a=document.getElementById(`system-uptime`);a&&e.uptime&&(a.textContent=hC(e.uptime));let o=document.getElementById(`system-start-time`);o&&e.startTime&&(o.textContent=_C(e.startTime));let s=document.getElementById(`system-status-text`);s&&(s.textContent=e.status?.toUpperCase()??`-`);let c=document.getElementById(`total-requests`);c&&e.metrics&&(c.textContent=e.metrics.requestCount.toLocaleString(),c.title=`Cumulative number of requests handled by the server`);let l=document.getElementById(`total-errors`);l&&e.metrics&&(l.textContent=e.metrics.errorCount.toLocaleString(),l.title=`Cumulative number of failed requests`);let u=document.getElementById(`active-pools`);if(u&&e.pools&&(u.textContent=e.pools.length.toString(),u.title=`Number of database connection pools currently active`),e.system){let t=e.system,n={heapUsed:t.memory.heapUsed,heapTotal:t.memory.heapTotal,rss:t.memory.rss,external:t.memory.external,cpuUser:t.cpu.user,cpuSystem:t.cpu.system},r=(e,r,i)=>{let a=n[r],o=t.memory[i],s=document.getElementById(e),c=document.getElementById(`${e}-max`);s&&(s.textContent=PC(a)),c&&typeof o==`number`&&(c.textContent=PC(o))},i=(e,r,i)=>{let a=n[r],o=document.getElementById(e);if(o&&(o.textContent=FC(a)),i){let n=t.cpu[i],r=document.getElementById(`${e}-max`);r&&typeof n==`number`&&(r.textContent=FC(n))}};r(`memory-heap-used`,`heapUsed`,`heapUsedMax`),r(`memory-heap-total`,`heapTotal`,`heapTotalMax`),r(`memory-rss`,`rss`,`rssMax`),r(`memory-external`,`external`,`externalMax`),i(`cpu-user`,`cpuUser`,`userMax`),i(`cpu-system`,`cpuSystem`,`systemMax`);let a=document.getElementById(`cpu-percent`);a&&t.cpu.max!==void 0&&(a.textContent=`${t.cpu.max.toFixed(1)}%`,a.title=`Max System CPU usage`);let o=document.getElementById(`memory-percent`);o&&t.memory.totalMemory&&(o.textContent=`${(t.memory.rss/t.memory.totalMemory*100).toFixed(1)}%`,o.title=`System Memory Used relative to Total (${PC(t.memory.totalMemory)})`);let s=document.getElementById(`cpu-cores-info`);s&&t.cpuCores&&(s.textContent=`${t.cpuCores} Cores`)}}async function LC(e,t){let n=e.querySelector(`.material-symbols-rounded`),r=n?.textContent;e.disabled=!0,e.classList.add(`loading`),n&&(n.textContent=`sync`,n.classList.add(`animate-spin`));try{return await t()}finally{e.disabled=!1,e.classList.remove(`loading`),n&&(n.textContent=r??``,n.classList.remove(`animate-spin`))}}function RC(e,t){let n=document.getElementById(e);return n&&n.addEventListener(`click`,()=>void LC(n,t)),n}var zC={overview:`dashboard`,trace:`bolt`,errors:`error`,access:`list_alt`,pools:`database`,stats:`query_stats`,config:`settings`,system:`terminal`},$={currentView:`overview`,status:{},maxHistoryPoints:30,lastRequestCount:0,lastErrorCount:0,lastUpdateTime:Date.now(),lastBucketTimestamp:0,nextRefreshTimeout:null,nextRefreshTime:0,countdownInterval:null,history:{labels:[],requests:[],avgResponseTimes:[],p95ResponseTimes:[],p99ResponseTimes:[],cpuUsage:[],memoryUsage:[],poolUsage:{}},charts:{},metricsMin:{},metricsMax:{}},BC={REFRESH_INTERVAL:`admin_refresh_interval`,HISTORY_DURATION:`admin_history_duration`,AUTO_REFRESH:`admin_auto_refresh`,THEME:`theme`,LAST_VIEW:`admin_last_view`};function VC(e){console.error(`Connection lost:`,e);let t=document.getElementById(`server-status-dot`),n=document.getElementById(`server-status-text`);t&&(t.className=`dot offline`),n&&(n.textContent=`OFFLINE`);let r=document.getElementById(`btn-pause`);r&&(r.style.display=`none`);let i=document.getElementById(`btn-resume`);i&&(i.style.display=`none`);let a=document.querySelector(`#system-status .dot`),o=document.getElementById(`system-status-text`);a&&(a.className=`dot offline`),o&&(o.textContent=`OFFLINE`);let s=document.getElementById(`offline-modal`);s&&s.style.display!==`flex`&&(s.style.display=`flex`),GC(6e4),HC(6e4)}function HC(e){$.countdownInterval&&clearInterval($.countdownInterval);let t=Date.now()+e,n=document.getElementById(`offline-countdown`),r=document.getElementById(`reconnect-text`);r&&(r.textContent=`Try Reconnect`);let i=()=>{if(!n)return;let e=Math.max(0,Math.ceil((t-Date.now())/1e3));n.textContent=`Retrying in ${e}s...`,e<=0&&$.countdownInterval&&(clearInterval($.countdownInterval),$.countdownInterval=null)};i(),$.countdownInterval=setInterval(i,1e3)}function UC(){$.countdownInterval&&=(clearInterval($.countdownInterval),null);let e=document.getElementById(`offline-countdown`);e&&(e.textContent=``)}async function WC(e=!1,t=!1){let n=document.getElementById(`reconnect-spinner`),r=document.getElementById(`reconnect-icon`),i=document.getElementById(`reconnect-text`);n&&(n.style.display=`inline-block`),r&&(r.style.display=`none`),i&&(i.textContent=`Connecting...`);try{let a=Date.now(),o=await Qp.getStatus(e,t),s=document.getElementById(`offline-modal`);if(s?.style.display===`flex`&&s&&(s.style.display=`none`,UC()),n&&(n.style.display=`none`),r&&(r.style.display=`inline-block`),i&&(i.textContent=`Try Reconnect`),o.history&&$.history.labels.length===0&&pC($,o.history),!o.config&&$.status.config&&(o.config=$.status.config),$.status=o,!o.metrics||!o.pools)return;let c=o.history?.at(-1),l=(o.intervalMs??5e3)/1e3,u=c?c.requests/l:0,d=c?c.durationAvg:o.metrics.avgResponseTime;if($.lastRequestCount=o.metrics.requestCount,$.lastErrorCount=o.metrics.errorCount,$.lastUpdateTime=a,o.system){let e=o.system;vC({heapUsed:e.memory.heapUsed,heapTotal:e.memory.heapTotal,rss:e.memory.rss,external:e.memory.external,cpuUser:e.cpu.user,cpuSystem:e.cpu.system},$.metricsMin,$.metricsMax)}c&&c.timestamp>$.lastBucketTimestamp?($.lastBucketTimestamp=c.timestamp,mC($,new Date(c.timestamp).toLocaleTimeString(),u,d,o.pools)):!c&&$.history.labels.length===0&&mC($,new Date().toLocaleTimeString(),0,0,o.pools);let f=document.getElementById(`sidebar-version`);f&&(f.textContent=`v${o.version}`);let p=document.getElementById(`uptime-val`);p&&(p.textContent=hC(o.uptime));let m=document.getElementById(`start-time-val`);m&&(m.textContent=`Started: ${_C(o.startTime)}`);let h=document.getElementById(`req-per-sec`);h&&(h.textContent=u.toFixed(2));let g=document.getElementById(`max-req-per-sec`);g&&(g.textContent=o.metrics.maxRequestsPerSecond.toFixed(2));let _=document.getElementById(`avg-resp-time`);_&&(_.textContent=`${o.metrics.avgResponseTime.toFixed(1)}ms`);let v=document.getElementById(`max-resp-time`);v&&(v.textContent=`${o.metrics.maxResponseTime.toFixed(1)}ms`);let y=document.getElementById(`err-count`);y&&(y.textContent=o.metrics.errorCount.toLocaleString());let b=0,x=0;o.pools.forEach(e=>{e.cache&&(b+=e.cache.procedureName.hits+e.cache.argument.hits,x+=e.cache.procedureName.misses+e.cache.argument.misses)});let S=b+x,C=S>0?Math.round(b/S*100):0,w=document.getElementById(`cache-hit-rate-val`);w&&(w.textContent=`${C}%`,w.style.color=C>80?`var(--success)`:C>50?`var(--warning)`:`var(--danger)`);let T=document.getElementById(`cache-hits-val`);T&&(T.textContent=b.toLocaleString());let E=document.getElementById(`cache-misses-val`);E&&(E.textContent=x.toLocaleString());let ee=document.getElementById(`server-status-dot`),te=document.getElementById(`server-status-text`);ee&&(ee.className=`dot `+o.status),te&&(te.textContent=o.status.toUpperCase());let ne=document.getElementById(`btn-pause`);ne&&(ne.style.display=o.status===`running`?`flex`:`none`);let re=document.getElementById(`btn-resume`);re&&(re.style.display=o.status===`paused`?`flex`:`none`),$.currentView===`errors`&&await OC(),$.currentView===`trace`&&await jC(),$.currentView===`pools`&&MC(o),$.currentView===`config`&&NC($),$.currentView===`system`&&IC(o,$),YC?.checked&&XC&&GC(Number.parseInt(XC.value,10))}catch(e){document.getElementById(`offline-modal`)?.style.display===`flex`?(GC(6e4),HC(6e4),n&&(n.style.display=`none`),r&&(r.style.display=`inline-block`),i&&(i.textContent=`Try Reconnect`)):VC(e)}}function GC(e){$.nextRefreshTimeout&&=(clearTimeout($.nextRefreshTimeout),null),$.nextRefreshTime=Date.now()+e,$.nextRefreshTimeout=setTimeout(()=>{WC()},e)}function KC(){let e=document.getElementById(`refresh-interval`);e&&GC(Number.parseInt(e.value))}function qC(){$.nextRefreshTimeout&&=(clearTimeout($.nextRefreshTimeout),null)}function JC(){let e=document.getElementById(`chart-history-points`);e&&Array.from(e.options).forEach(e=>{let t=Number.parseInt(e.value),n=``;if(t<60)n=`${t}s`;else if(t<3600)n=`${Math.round(t/60)} min`;else{let e=t/3600;n=e===Math.round(e)?`${e} hour${e>1?`s`:``}`:`${e.toFixed(1)} hours`}e.textContent=`Last ${n}`})}document.querySelectorAll(`nav button`).forEach(e=>{let t=e;t.addEventListener(`click`,async()=>{try{let e=t.dataset.view;if(!e)return;$.currentView=e,localStorage.setItem(BC.LAST_VIEW,e),document.querySelectorAll(`.view`).forEach(e=>{let t=e;t.style.display=`none`});let n=document.getElementById(`view-`+e);n&&(n.style.display=`block`),document.querySelectorAll(`nav button`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`);let r=document.getElementById(`view-title`);if(r){let n=Array.from(t.childNodes).filter(e=>e.nodeType===Node.TEXT_NODE).map(e=>e.textContent?.trim()).join(``);r.innerHTML=`<span class="material-symbols-rounded">${zC[e]??`chevron_right`}</span>${n}`}e===`errors`&&await OC(),e===`trace`&&await jC(),e===`pools`&&MC($.status),e===`stats`&&await kC(),e===`config`&&NC($),e===`system`&&IC($.status,$)}catch(e){VC(e)}})});var YC=document.getElementById(`auto-refresh-toggle`);YC&&YC.addEventListener(`change`,e=>{let t=e.target;localStorage.setItem(BC.AUTO_REFRESH,String(t.checked)),t.checked?KC():qC()});var XC=document.getElementById(`refresh-interval`);XC&&XC.addEventListener(`change`,()=>{localStorage.setItem(BC.REFRESH_INTERVAL,XC.value);let e=Number.parseInt(XC.value),t=Number.parseInt(ZC?.value??`60`);$.maxHistoryPoints=Math.max(1,Math.floor(t/(e/1e3))),$.history.labels=[],$.history.requests=[],$.history.avgResponseTimes=[],$.history.cpuUsage=[],$.history.memoryUsage=[],$.history.poolUsage={},JC(),IC($.status,$),WC()});var ZC=document.getElementById(`chart-history-points`);ZC&&ZC.addEventListener(`change`,()=>{localStorage.setItem(BC.HISTORY_DURATION,ZC.value);let e=document.getElementById(`refresh-interval`);if(!e)return;let t=Number.parseInt(e.value),n=Number.parseInt(ZC.value);$.maxHistoryPoints=Math.max(1,Math.floor(n/(t/1e3))),$.history.labels=[],$.history.requests=[],$.history.avgResponseTimes=[],$.history.cpuUsage=[],$.history.memoryUsage=[],$.history.poolUsage={},WC()});var QC=document.getElementById(`manual-refresh`);QC&&QC.addEventListener(`click`,()=>{LC(QC,WC)});var $C=document.getElementById(`error-filter`);$C&&$C.addEventListener(`keydown`,e=>{e.key===`Enter`&&OC()}),RC(`error-load-btn`,OC),RC(`trace-load-btn`,jC),RC(`access-load-btn`,AC),RC(`stats-load-btn`,kC);var ew=document.getElementById(`trace-filter`);ew&&ew.addEventListener(`keydown`,e=>{e.key===`Enter`&&jC()});var tw=document.getElementById(`trace-clear-btn`);tw&&tw.addEventListener(`click`,async()=>{confirm(`Are you sure you want to clear all traces?`)&&await LC(tw,async()=>{await Qp.clearTraces(),await jC()})});var nw=document.getElementById(`trace-status-toggle`);nw&&nw.addEventListener(`click`,async()=>{await LC(nw,async()=>{let{enabled:e}=await Qp.getTraceStatus();await Qp.toggleTrace(!e),await jC()})});var rw=document.getElementById(`access-filter`);rw&&rw.addEventListener(`keydown`,e=>{e.key===`Enter`&&AC()});var iw=document.getElementById(`stats-limit`);iw&&iw.addEventListener(`keydown`,e=>{e.key===`Enter`&&kC()}),RC(`btn-pause`,async()=>{confirm(`Are you sure you want to pause the server?`)&&(await Qp.post(`api/server/pause`),await WC())}),RC(`btn-resume`,async()=>{await Qp.post(`api/server/resume`),await WC()}),RC(`btn-stop`,async()=>{confirm(`Are you sure you want to STOP the server? This action cannot be undone from the web interface.`)&&(await Qp.post(`api/server/stop`),alert(`Server stop requested. The interface will now become unresponsive.`))}),RC(`btn-clear-all-cache`,async()=>{confirm(`Are you sure you want to clear ALL caches?`)&&(await Qp.post(`api/cache/clear`),await WC())});var aw=document.getElementById(`btn-reconnect`);aw&&aw.addEventListener(`click`,()=>{LC(aw,WC)}),globalThis.addEventListener(`keydown`,e=>{if(e.key===`Escape`){let e=document.getElementById(`error-modal`);e&&(e.style.display=`none`);let t=document.getElementById(`trace-modal`);t&&(t.style.display=`none`)}});var ow=localStorage.getItem(BC.REFRESH_INTERVAL);ow&&XC&&(XC.value=ow);var sw=localStorage.getItem(BC.HISTORY_DURATION);sw&&ZC&&(ZC.value=sw);var cw=localStorage.getItem(BC.AUTO_REFRESH);if(cw!==null&&YC&&(YC.checked=cw===`true`),xC($),fC($),JC(),XC&&ZC){let e=Number.parseInt(XC.value),t=Number.parseInt(ZC.value);$.maxHistoryPoints=Math.max(1,Math.floor(t/(e/1e3)))}var lw=localStorage.getItem(BC.LAST_VIEW);if(lw){let e=document.querySelector(`nav button[data-view="${lw}"]`);e&&e.click()}WC(!0,!0).then(()=>{YC?.checked&&KC()}).catch(console.error);
|
|
Binary file
|
|
Binary file
|
package/dist/frontend/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>web_plsql Admin Console</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="/admin/assets/favicon-mQAM4tVu.svg" />
|
|
8
8
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
|
9
|
-
<script type="module" crossorigin src="/admin/assets/main-
|
|
9
|
+
<script type="module" crossorigin src="/admin/assets/main-DurwHchn.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/admin/assets/main-CoERzZAr.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body class="dark">
|
|
Binary file
|
|
Binary file
|
package/dist/index.d.mts
CHANGED
|
@@ -177,7 +177,8 @@ declare const z$configType: z$1.ZodObject<{
|
|
|
177
177
|
adminRoute: z$1.ZodOptional<z$1.ZodString>; /** Username for admin console authentication */
|
|
178
178
|
adminUser: z$1.ZodOptional<z$1.ZodString>; /** Password for admin console authentication */
|
|
179
179
|
adminPassword: z$1.ZodOptional<z$1.ZodString>; /** Developer mode (skips frontend build check, enables CORS) */
|
|
180
|
-
devMode: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
180
|
+
devMode: z$1.ZodOptional<z$1.ZodBoolean>; /** Callback function to setup custom Express extensions */
|
|
181
|
+
setupExtensions: z$1.ZodOptional<z$1.ZodCustom<(app: Express, pools: Pool[]) => void | Promise<void>, (app: Express, pools: Pool[]) => void | Promise<void>>>;
|
|
181
182
|
}, z$1.core.$strict>;
|
|
182
183
|
type configType = z$1.infer<typeof z$configType>;
|
|
183
184
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -155,7 +155,8 @@ const z$configType = z$1.strictObject({
|
|
|
155
155
|
adminRoute: z$1.string().optional(),
|
|
156
156
|
adminUser: z$1.string().optional(),
|
|
157
157
|
adminPassword: z$1.string().optional(),
|
|
158
|
-
devMode: z$1.boolean().optional()
|
|
158
|
+
devMode: z$1.boolean().optional(),
|
|
159
|
+
setupExtensions: z$1.custom((val) => typeof val === "function", { message: "Invalid setupExtensions callback" }).optional()
|
|
159
160
|
});
|
|
160
161
|
//#endregion
|
|
161
162
|
//#region src/backend/util/oracledb-provider.ts
|
|
@@ -208,7 +209,7 @@ globalThis.__VERSION__ ??= "**development**";
|
|
|
208
209
|
* Returns the current library version
|
|
209
210
|
* @returns {string} - Version.
|
|
210
211
|
*/
|
|
211
|
-
const getVersion = () => "1.
|
|
212
|
+
const getVersion = () => "1.7.0";
|
|
212
213
|
//#endregion
|
|
213
214
|
//#region src/backend/server/config.ts
|
|
214
215
|
const paddedLine = (title, value) => {
|
|
@@ -334,6 +335,7 @@ const startServer = async (config, ssl) => {
|
|
|
334
335
|
});
|
|
335
336
|
}
|
|
336
337
|
if (internalConfig.loggerFilename.length > 0) app.use(handlerLogger(internalConfig.loggerFilename));
|
|
338
|
+
if (internalConfig.setupExtensions) await internalConfig.setupExtensions(app, adminContext.pools);
|
|
337
339
|
for (const i of internalConfig.routeStatic) {
|
|
338
340
|
app.use(i.route, expressStaticGzip(i.directoryPath, {
|
|
339
341
|
enableBrotli: true,
|