diff --git a/api/routes.ts b/api/routes.ts
index 74c874a..9b12fcd 100644
--- a/api/routes.ts
+++ b/api/routes.ts
@@ -788,6 +788,43 @@ const defs = {
output: ARR(MetricSchema, 'Collected query metrics'),
description: 'Get SQL metrics from the deployment',
}),
+ 'GET/api/deployment/metrics-router': route({
+ authorize: withUserSession,
+ fn: async (ctx, { deployment }) => {
+ const dep = await withDeploymentTableAccess(ctx, deployment)
+ try {
+ const urlStr = dep.url.startsWith('http')
+ ? dep.url
+ : `${isLocal ? 'http' : 'https'}://${dep.url}`
+ return await fetchJson(`${urlStr}/api/router/metrics`, {
+ method: 'GET',
+ })
+ } catch (err) {
+ log.error('fetch-router-metrics-error', { error: err })
+ throw new respond.InternalServerErrorError({
+ message: err instanceof Error
+ ? err.message
+ : 'Failed to fetch router metrics',
+ })
+ }
+ },
+ input: OBJ({ deployment: STR("The deployment's URL") }),
+ output: ARR(
+ OBJ({
+ key: STR('Route key (method:path) allow to identify which route'),
+ duration: NUM(
+ 'Total time the route handler take to respond, in milliseconds',
+ ),
+ count: NUM('How many times the route was called'),
+ error: NUM('Number of time it responded with a status 400 or above'),
+ success: NUM(
+ 'Number of time it responded with a status under 399 (Success, Redirect and Info)',
+ ),
+ }, 'Route metrics'),
+ 'Collected route metrics',
+ ),
+ description: 'Get router metrics from the deployment',
+ }),
'GET/api/deployment/doc': route({
authorize: withUserSession,
fn: async (_ctx, { deployment }) => {
diff --git a/deno.json b/deno.json
index ffc89a6..63e30fd 100644
--- a/deno.json
+++ b/deno.json
@@ -31,7 +31,7 @@
"imports": {
"./": "./",
"/": "./",
- "@01edu/api": "jsr:@01edu/api@^0.2.7",
+ "@01edu/api": "jsr:@01edu/api@^0.2.11",
"@01edu/api-client": "jsr:@01edu/api-client@^0.2.6",
"@01edu/api-proxy": "jsr:@01edu/api-proxy@^0.2.1",
"@01edu/signal-router": "npm:@01edu/signal-router@^0.2.3",
@@ -47,15 +47,15 @@
"@std/streams": "jsr:@std/streams@^1.1.1",
"@std/testing": "jsr:@std/testing@^1.0.19",
"chdb": "npm:chdb@^2.0.1",
- "vite": "npm:vite@^8.0.16",
+ "vite": "npm:vite@^8.1.0",
"preact": "npm:preact@^10.29.2",
"@preact/preset-vite": "npm:@preact/preset-vite@^2.10.5",
- "@preact/signals": "npm:@preact/signals@^2.9.1",
- "@clickhouse/client": "npm:@clickhouse/client@^1.19.0",
- "@tailwindcss/vite": "npm:@tailwindcss/vite@^4.3.0",
- "tailwindcss": "npm:tailwindcss@^4.3.0",
- "daisyui": "npm:daisyui@^5.5.20",
- "lucide-preact": "npm:lucide-preact@^1.17.0",
+ "@preact/signals": "npm:@preact/signals@^2.9.2",
+ "@clickhouse/client": "npm:@clickhouse/client@^1.22.0",
+ "@tailwindcss/vite": "npm:@tailwindcss/vite@^4.3.1",
+ "tailwindcss": "npm:tailwindcss@^4.3.1",
+ "daisyui": "npm:daisyui@^5.5.23",
+ "lucide-preact": "npm:lucide-preact@^1.21.0",
"@deno/gfm": "jsr:@deno/gfm@0.12.0"
},
"fmt": {
diff --git a/deno.lock b/deno.lock
index 79b4376..df9918b 100644
--- a/deno.lock
+++ b/deno.lock
@@ -3,7 +3,7 @@
"specifiers": {
"jsr:@01edu/api-client@~0.2.6": "0.2.6",
"jsr:@01edu/api-proxy@~0.2.1": "0.2.1",
- "jsr:@01edu/api@~0.2.7": "0.2.8",
+ "jsr:@01edu/api@~0.2.11": "0.2.11",
"jsr:@01edu/time@0.1": "0.1.0",
"jsr:@01edu/types@~0.2.6": "0.2.6",
"jsr:@cd/sqlite@~0.13.1": "0.13.1",
@@ -11,7 +11,6 @@
"jsr:@denosaurs/emoji@~0.3.1": "0.3.1",
"jsr:@denosaurs/plug@1": "1.1.0",
"jsr:@std/assert@^1.0.19": "1.0.19",
- "jsr:@std/async@^1.4.0": "1.4.0",
"jsr:@std/bytes@^1.0.6": "1.0.6",
"jsr:@std/cli@^1.0.30": "1.0.30",
"jsr:@std/crypto@^1.1.0": "1.1.0",
@@ -35,19 +34,19 @@
"jsr:@std/path@^1.1.5": "1.1.5",
"jsr:@std/streams@^1.1.1": "1.1.1",
"jsr:@std/testing@^1.0.19": "1.0.19",
- "npm:@01edu/signal-router@~0.2.3": "0.2.3_@preact+signals@2.9.1__preact@10.29.2_preact@10.29.2",
- "npm:@clickhouse/client@^1.19.0": "1.19.0",
- "npm:@deno/vite-plugin@^2.0.2": "2.0.2_vite@8.0.16",
- "npm:@preact/preset-vite@^2.10.5": "2.10.5_@babel+core@7.29.7_vite@8.0.16_preact@10.29.2",
- "npm:@preact/signals@^2.9.0": "2.9.1_preact@10.29.2",
- "npm:@preact/signals@^2.9.1": "2.9.1_preact@10.29.2",
- "npm:@tailwindcss/vite@^4.3.0": "4.3.0_vite@8.0.16",
+ "npm:@01edu/signal-router@~0.2.3": "0.2.3_@preact+signals@2.9.2__preact@10.29.2_preact@10.29.2",
+ "npm:@clickhouse/client@^1.22.0": "1.22.0",
+ "npm:@deno/vite-plugin@^2.0.2": "2.0.2_vite@8.1.0",
+ "npm:@preact/preset-vite@^2.10.5": "2.10.5_vite@8.1.0",
+ "npm:@preact/signals@^2.9.0": "2.9.2_preact@10.29.2",
+ "npm:@preact/signals@^2.9.2": "2.9.2_preact@10.29.2",
+ "npm:@tailwindcss/vite@^4.3.1": "4.3.1_vite@8.1.0",
"npm:chdb@^2.0.1": "2.0.1",
- "npm:daisyui@^5.5.20": "5.5.20",
+ "npm:daisyui@^5.5.23": "5.5.23",
"npm:github-slugger@2": "2.0.0",
"npm:he@^1.2.0": "1.2.0",
"npm:katex@0.16": "0.16.47",
- "npm:lucide-preact@^1.17.0": "1.17.0_preact@10.29.2",
+ "npm:lucide-preact@^1.21.0": "1.21.0_preact@10.29.2",
"npm:marked-alert@^2.1.2": "2.1.2_marked@17.0.6",
"npm:marked-footnote@^1.4.0": "1.4.0_marked@17.0.6",
"npm:marked-gfm-heading-id@^4.1.3": "4.1.4_marked@17.0.6",
@@ -55,13 +54,13 @@
"npm:preact@^10.29.2": "10.29.2",
"npm:prismjs@^1.30.0": "1.30.0",
"npm:sanitize-html@^2.17.0": "2.17.4",
- "npm:tailwindcss@^4.3.0": "4.3.0",
- "npm:vite@^8.0.16": "8.0.16",
- "npm:vite@^8.0.3": "8.0.16"
+ "npm:tailwindcss@^4.3.1": "4.3.1",
+ "npm:vite@^8.0.3": "8.1.0",
+ "npm:vite@^8.1.0": "8.1.0"
},
"jsr": {
- "@01edu/api@0.2.8": {
- "integrity": "b49fa2db91cef165d0bf819efdc72c690332ec4bd73403ce6db96c8a016ab7d2",
+ "@01edu/api@0.2.11": {
+ "integrity": "a0483f14681ab5c67bb66c5b95ba7520a80ccb734c94b79cb8b9908526fa13e8",
"dependencies": [
"jsr:@01edu/time",
"jsr:@01edu/types",
@@ -132,9 +131,6 @@
"jsr:@std/internal@^1.0.12"
]
},
- "@std/async@1.4.0": {
- "integrity": "4d70b008634f571cff9b554090d628c76141c32613aae0ff283fd5fa23d0c379"
- },
"@std/bytes@1.0.6": {
"integrity": "f6ac6adbd8ccd99314045f5703e23af0a68d7f7e58364b47d2c7f408aeb5820a"
},
@@ -205,7 +201,6 @@
"integrity": "f4236172365b216728dc3cc8b5e80a9f4c33083d1e4ede7613d5b25b4014898e",
"dependencies": [
"jsr:@std/assert",
- "jsr:@std/async",
"jsr:@std/data-structures",
"jsr:@std/fs@^1.0.24",
"jsr:@std/internal@^1.0.14",
@@ -214,7 +209,7 @@
}
},
"npm": {
- "@01edu/signal-router@0.2.3_@preact+signals@2.9.1__preact@10.29.2_preact@10.29.2": {
+ "@01edu/signal-router@0.2.3_@preact+signals@2.9.2__preact@10.29.2_preact@10.29.2": {
"integrity": "sha512-Eg2ORuigaA8i3vM+Lr4k0P7+A53vZ3mKb2wsVnbBslkItaebEFwPUDxXiz2zDCJYHd06wLdvd64r/VRQQw6XFw==",
"dependencies": [
"@preact/signals",
@@ -375,16 +370,16 @@
"@babel/helper-validator-identifier"
]
},
- "@clickhouse/client-common@1.19.0": {
- "integrity": "sha512-HHQw7MUt1aFquSlnoQhlRO8e7zhRw7rJZFNSYiHP2wxzEVeoI0cX8kKoTp+xlVySvFi8s0mAC3bi8D031xmIQg=="
+ "@clickhouse/client-common@1.22.0": {
+ "integrity": "sha512-MQgXRhoYXut6GhRrTJlub42bnPX7+5Vm+5gHNR0zZXU5+EwZKsBgMXiWXPOerAmQd3weGKm8hzoeZJCfU3Cw2w=="
},
- "@clickhouse/client@1.19.0": {
- "integrity": "sha512-R/35tIFZjwRyqtTN0cnlvd45zU+YREuQ/cnfi6c+KGGkVSCF+1cl8mZ9kkxshqHx2U4YjcmPVElJaRn2bEqJ4g==",
+ "@clickhouse/client@1.22.0": {
+ "integrity": "sha512-iQAAM4VT9fO7mYVOkGB/Ul9Xxuf0atKn+GFceZqfE8xFakV8KOAQxR3tfNrXFMlJ8T+Q3gbrpfLFyj7/TbOwyA==",
"dependencies": [
"@clickhouse/client-common"
]
},
- "@deno/vite-plugin@2.0.2_vite@8.0.16": {
+ "@deno/vite-plugin@2.0.2_vite@8.1.0": {
"integrity": "sha512-bzuKApn9Jr2x1jSrbuJEJzy++8LUwjFVOAopAbepcE3RgYzdcPEWd36PSp7P5dNMQlNnQlgtm3MeNbcKZ/Eh/Q==",
"dependencies": [
"@deno/loader@npm:@jsr/deno__loader@0.5.0",
@@ -392,21 +387,21 @@
"vite"
]
},
- "@emnapi/core@1.10.0": {
- "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "@emnapi/core@1.11.1": {
+ "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
"dependencies": [
"@emnapi/wasi-threads",
"tslib"
]
},
- "@emnapi/runtime@1.10.0": {
- "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "@emnapi/runtime@1.11.1": {
+ "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
"dependencies": [
"tslib"
]
},
- "@emnapi/wasi-threads@1.2.1": {
- "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "@emnapi/wasi-threads@1.2.2": {
+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
"dependencies": [
"tslib"
]
@@ -467,18 +462,18 @@
],
"tarball": "https://npm.jsr.io/~/11/@jsr/std__streams/1.1.1.tgz"
},
- "@napi-rs/wasm-runtime@1.1.4_@emnapi+core@1.10.0_@emnapi+runtime@1.10.0": {
- "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+ "@napi-rs/wasm-runtime@1.1.6_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {
+ "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
"dependencies": [
"@emnapi/core",
"@emnapi/runtime",
"@tybys/wasm-util"
]
},
- "@oxc-project/types@0.133.0": {
- "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA=="
+ "@oxc-project/types@0.137.0": {
+ "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA=="
},
- "@preact/preset-vite@2.10.5_@babel+core@7.29.7_vite@8.0.16_preact@10.29.2": {
+ "@preact/preset-vite@2.10.5_vite@8.1.0": {
"integrity": "sha512-p0vJpxiVO7KWWazWny3LUZ+saXyZKWv6Ju0bYMWNJRp2YveufRPgSUB1C4MTqGJfz07EehMgfN+AJNwQy+w6Iw==",
"dependencies": [
"@babel/core",
@@ -495,11 +490,11 @@
"zimmerframe"
]
},
- "@preact/signals-core@1.14.2": {
- "integrity": "sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A=="
+ "@preact/signals-core@1.14.3": {
+ "integrity": "sha512-m0K3vnbSLC5rHs2ZVfeAMvBtT1zIyq4mxx5OlNncSgMj5Iz6W5Rn3kPrDxAC+iIKmiVe0lSl6U37t5ZkEWoVAw=="
},
- "@preact/signals@2.9.1_preact@10.29.2": {
- "integrity": "sha512-xVqN8mJjbSN5IB/8Ubmd9NN+Ew6zJswoRxrjZbH3YsgkMshFeO6d8zxEFpHRTq9GJZx7cnPs2CnCpFqtGXGNsw==",
+ "@preact/signals@2.9.2_preact@10.29.2": {
+ "integrity": "sha512-DvFPISNMSh3vPqRwPa1tAVAHl85aDq4pTyNu1bTGfrKr64F3EOCHjdUl9aUdohKBf1v9PRGLYuGFcJpfztkdoQ==",
"dependencies": [
"@preact/signals-core",
"preact"
@@ -517,7 +512,7 @@
"@prefresh/utils@1.2.1": {
"integrity": "sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw=="
},
- "@prefresh/vite@2.4.12_preact@10.29.2_vite@8.0.16": {
+ "@prefresh/vite@2.4.12_preact@10.29.2_vite@8.1.0": {
"integrity": "sha512-FY1fzXpUjiuosznMV0YM7XAOPZjB5FIdWS0W24+XnlxYkt9hNAwwsiKYn+cuTEoMtD/ZVazS5QVssBr9YhpCQA==",
"dependencies": [
"@babel/core",
@@ -529,68 +524,68 @@
"vite"
]
},
- "@rolldown/binding-android-arm64@1.0.3": {
- "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
+ "@rolldown/binding-android-arm64@1.1.3": {
+ "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==",
"os": ["android"],
"cpu": ["arm64"]
},
- "@rolldown/binding-darwin-arm64@1.0.3": {
- "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
+ "@rolldown/binding-darwin-arm64@1.1.3": {
+ "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==",
"os": ["darwin"],
"cpu": ["arm64"]
},
- "@rolldown/binding-darwin-x64@1.0.3": {
- "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
+ "@rolldown/binding-darwin-x64@1.1.3": {
+ "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==",
"os": ["darwin"],
"cpu": ["x64"]
},
- "@rolldown/binding-freebsd-x64@1.0.3": {
- "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
+ "@rolldown/binding-freebsd-x64@1.1.3": {
+ "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==",
"os": ["freebsd"],
"cpu": ["x64"]
},
- "@rolldown/binding-linux-arm-gnueabihf@1.0.3": {
- "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
+ "@rolldown/binding-linux-arm-gnueabihf@1.1.3": {
+ "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==",
"os": ["linux"],
"cpu": ["arm"]
},
- "@rolldown/binding-linux-arm64-gnu@1.0.3": {
- "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
+ "@rolldown/binding-linux-arm64-gnu@1.1.3": {
+ "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==",
"os": ["linux"],
"cpu": ["arm64"]
},
- "@rolldown/binding-linux-arm64-musl@1.0.3": {
- "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
+ "@rolldown/binding-linux-arm64-musl@1.1.3": {
+ "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==",
"os": ["linux"],
"cpu": ["arm64"]
},
- "@rolldown/binding-linux-ppc64-gnu@1.0.3": {
- "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
+ "@rolldown/binding-linux-ppc64-gnu@1.1.3": {
+ "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==",
"os": ["linux"],
"cpu": ["ppc64"]
},
- "@rolldown/binding-linux-s390x-gnu@1.0.3": {
- "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
+ "@rolldown/binding-linux-s390x-gnu@1.1.3": {
+ "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==",
"os": ["linux"],
"cpu": ["s390x"]
},
- "@rolldown/binding-linux-x64-gnu@1.0.3": {
- "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
+ "@rolldown/binding-linux-x64-gnu@1.1.3": {
+ "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==",
"os": ["linux"],
"cpu": ["x64"]
},
- "@rolldown/binding-linux-x64-musl@1.0.3": {
- "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
+ "@rolldown/binding-linux-x64-musl@1.1.3": {
+ "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==",
"os": ["linux"],
"cpu": ["x64"]
},
- "@rolldown/binding-openharmony-arm64@1.0.3": {
- "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
+ "@rolldown/binding-openharmony-arm64@1.1.3": {
+ "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==",
"os": ["openharmony"],
"cpu": ["arm64"]
},
- "@rolldown/binding-wasm32-wasi@1.0.3": {
- "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
+ "@rolldown/binding-wasm32-wasi@1.1.3": {
+ "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==",
"dependencies": [
"@emnapi/core",
"@emnapi/runtime",
@@ -598,13 +593,13 @@
],
"cpu": ["wasm32"]
},
- "@rolldown/binding-win32-arm64-msvc@1.0.3": {
- "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
+ "@rolldown/binding-win32-arm64-msvc@1.1.3": {
+ "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==",
"os": ["win32"],
"cpu": ["arm64"]
},
- "@rolldown/binding-win32-x64-msvc@1.0.3": {
- "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
+ "@rolldown/binding-win32-x64-msvc@1.1.3": {
+ "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==",
"os": ["win32"],
"cpu": ["x64"]
},
@@ -626,8 +621,8 @@
"picomatch@4.0.4"
]
},
- "@tailwindcss/node@4.3.0": {
- "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==",
+ "@tailwindcss/node@4.3.1": {
+ "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==",
"dependencies": [
"@jridgewell/remapping",
"enhanced-resolve",
@@ -638,67 +633,67 @@
"tailwindcss"
]
},
- "@tailwindcss/oxide-android-arm64@4.3.0": {
- "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==",
+ "@tailwindcss/oxide-android-arm64@4.3.1": {
+ "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==",
"os": ["android"],
"cpu": ["arm64"]
},
- "@tailwindcss/oxide-darwin-arm64@4.3.0": {
- "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==",
+ "@tailwindcss/oxide-darwin-arm64@4.3.1": {
+ "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==",
"os": ["darwin"],
"cpu": ["arm64"]
},
- "@tailwindcss/oxide-darwin-x64@4.3.0": {
- "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==",
+ "@tailwindcss/oxide-darwin-x64@4.3.1": {
+ "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==",
"os": ["darwin"],
"cpu": ["x64"]
},
- "@tailwindcss/oxide-freebsd-x64@4.3.0": {
- "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==",
+ "@tailwindcss/oxide-freebsd-x64@4.3.1": {
+ "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==",
"os": ["freebsd"],
"cpu": ["x64"]
},
- "@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0": {
- "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==",
+ "@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1": {
+ "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==",
"os": ["linux"],
"cpu": ["arm"]
},
- "@tailwindcss/oxide-linux-arm64-gnu@4.3.0": {
- "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==",
+ "@tailwindcss/oxide-linux-arm64-gnu@4.3.1": {
+ "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==",
"os": ["linux"],
"cpu": ["arm64"]
},
- "@tailwindcss/oxide-linux-arm64-musl@4.3.0": {
- "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==",
+ "@tailwindcss/oxide-linux-arm64-musl@4.3.1": {
+ "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==",
"os": ["linux"],
"cpu": ["arm64"]
},
- "@tailwindcss/oxide-linux-x64-gnu@4.3.0": {
- "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==",
+ "@tailwindcss/oxide-linux-x64-gnu@4.3.1": {
+ "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==",
"os": ["linux"],
"cpu": ["x64"]
},
- "@tailwindcss/oxide-linux-x64-musl@4.3.0": {
- "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==",
+ "@tailwindcss/oxide-linux-x64-musl@4.3.1": {
+ "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==",
"os": ["linux"],
"cpu": ["x64"]
},
- "@tailwindcss/oxide-wasm32-wasi@4.3.0": {
- "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==",
+ "@tailwindcss/oxide-wasm32-wasi@4.3.1": {
+ "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==",
"cpu": ["wasm32"]
},
- "@tailwindcss/oxide-win32-arm64-msvc@4.3.0": {
- "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==",
+ "@tailwindcss/oxide-win32-arm64-msvc@4.3.1": {
+ "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==",
"os": ["win32"],
"cpu": ["arm64"]
},
- "@tailwindcss/oxide-win32-x64-msvc@4.3.0": {
- "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==",
+ "@tailwindcss/oxide-win32-x64-msvc@4.3.1": {
+ "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==",
"os": ["win32"],
"cpu": ["x64"]
},
- "@tailwindcss/oxide@4.3.0": {
- "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==",
+ "@tailwindcss/oxide@4.3.1": {
+ "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==",
"optionalDependencies": [
"@tailwindcss/oxide-android-arm64",
"@tailwindcss/oxide-darwin-arm64",
@@ -714,8 +709,8 @@
"@tailwindcss/oxide-win32-x64-msvc"
]
},
- "@tailwindcss/vite@4.3.0_vite@8.0.16": {
- "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==",
+ "@tailwindcss/vite@4.3.1_vite@8.1.0": {
+ "integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==",
"dependencies": [
"@tailwindcss/node",
"@tailwindcss/oxide",
@@ -723,8 +718,8 @@
"vite"
]
},
- "@tybys/wasm-util@0.10.2": {
- "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
+ "@tybys/wasm-util@0.10.3": {
+ "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
"dependencies": [
"tslib"
]
@@ -786,8 +781,8 @@
"css-what@6.2.2": {
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="
},
- "daisyui@5.5.20": {
- "integrity": "sha512-HemJcjl0Gk9rQ8BcgofN6p+EURrqftQG9wK1Hkxs98i49xe68+QxpNvry+PyxwkIUgrbMpNmZ5ZWjmtffAjfhQ=="
+ "daisyui@5.5.23": {
+ "integrity": "sha512-xuheNUSL4T6ZVtWXoioqcNkjoyGX85QTDz4HTw2aBPfqk4fuMjax5HDo8qCmpV6M1YN8bGvfx5BpYCoDeRlt+A=="
},
"dayjs@1.11.21": {
"integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="
@@ -832,8 +827,8 @@
"electron-to-chromium@1.5.366": {
"integrity": "sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg=="
},
- "enhanced-resolve@5.22.1": {
- "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==",
+ "enhanced-resolve@5.21.6": {
+ "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==",
"dependencies": [
"graceful-fs",
"tapable"
@@ -1004,8 +999,8 @@
"yallist"
]
},
- "lucide-preact@1.17.0_preact@10.29.2": {
- "integrity": "sha512-QoHqgMY9WJanT+zd8x5Hq9quOqY/MHt7oTpuPAZzCkfUhfxsTJ+L0CFnUaBBh+H54OySAElm2+UQ1JwQ2CDPmg==",
+ "lucide-preact@1.21.0_preact@10.29.2": {
+ "integrity": "sha512-GUJs/vYSHNM5HU0UwNADfKvDbNDQ7i6vciniCvtpRVMsXy+FOcaRHgRhqVcY/CiORqA6oMC8xK5JJ7Wvb1r1Sw==",
"dependencies": [
"preact"
]
@@ -1095,8 +1090,8 @@
"prismjs@1.30.0": {
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="
},
- "rolldown@1.0.3": {
- "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
+ "rolldown@1.1.3": {
+ "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==",
"dependencies": [
"@oxc-project/types",
"@rolldown/pluginutils"
@@ -1151,8 +1146,8 @@
"stack-trace@1.0.0": {
"integrity": "sha512-H6D7134xi6qONvh7ZHKgviXf+rd3vhGBSvebPZCaUkd8zvQ+7PtDw6CljPTe4cXWNf2IKZGNqw6VJXSb9IgBpA=="
},
- "tailwindcss@4.3.0": {
- "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="
+ "tailwindcss@4.3.1": {
+ "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q=="
},
"tapable@2.3.3": {
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="
@@ -1176,7 +1171,7 @@
],
"bin": true
},
- "vite-prerender-plugin@0.5.13_vite@8.0.16": {
+ "vite-prerender-plugin@0.5.13_vite@8.1.0": {
"integrity": "sha512-IKSpYkzDBsKAxa05naRbj7GvNVMSdww/Z/E89oO3xndz+gWnOBOKOAbEXv7qDhktY/j3vHgJmoV1pPzqU2tx9g==",
"dependencies": [
"kolorist",
@@ -1188,8 +1183,8 @@
"vite"
]
},
- "vite@8.0.16": {
- "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
+ "vite@8.1.0": {
+ "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==",
"dependencies": [
"lightningcss",
"picomatch@4.0.4",
@@ -1209,11 +1204,14 @@
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="
}
},
+ "remote": {
+ "https://gistcdn.githack.com/kigiri/21df06d173fcdced5281b86ba6ac1382/raw/crypto.js": "e85976e655898538dbade9d87b05ca0a6bb167b3128cd4098622000a582f5f6d"
+ },
"workspace": {
"dependencies": [
"jsr:@01edu/api-client@~0.2.6",
"jsr:@01edu/api-proxy@~0.2.1",
- "jsr:@01edu/api@~0.2.7",
+ "jsr:@01edu/api@~0.2.11",
"jsr:@01edu/time@0.1",
"jsr:@deno/gfm@0.12.0",
"jsr:@std/assert@^1.0.19",
@@ -1226,17 +1224,17 @@
"jsr:@std/streams@^1.1.1",
"jsr:@std/testing@^1.0.19",
"npm:@01edu/signal-router@~0.2.3",
- "npm:@clickhouse/client@^1.19.0",
+ "npm:@clickhouse/client@^1.22.0",
"npm:@deno/vite-plugin@^2.0.2",
"npm:@preact/preset-vite@^2.10.5",
- "npm:@preact/signals@^2.9.1",
- "npm:@tailwindcss/vite@^4.3.0",
+ "npm:@preact/signals@^2.9.2",
+ "npm:@tailwindcss/vite@^4.3.1",
"npm:chdb@^2.0.1",
- "npm:daisyui@^5.5.20",
- "npm:lucide-preact@^1.17.0",
+ "npm:daisyui@^5.5.23",
+ "npm:lucide-preact@^1.21.0",
"npm:preact@^10.29.2",
- "npm:tailwindcss@^4.3.0",
- "npm:vite@^8.0.16"
+ "npm:tailwindcss@^4.3.1",
+ "npm:vite@^8.1.0"
]
}
}
diff --git a/web/pages/DeploymentPage.tsx b/web/pages/DeploymentPage.tsx
index a6c9dc9..dccc66e 100644
--- a/web/pages/DeploymentPage.tsx
+++ b/web/pages/DeploymentPage.tsx
@@ -4,6 +4,7 @@ import {
AlertCircle,
AlertTriangle,
ArrowDown,
+ ArrowLeftRight,
ArrowUp,
BarChart,
BarChart2,
@@ -16,9 +17,11 @@ import {
Database,
Download,
FileText,
+ Globe,
Hash,
Info,
Link2,
+ LucideIcon,
Play,
Plus,
RefreshCw,
@@ -52,6 +55,7 @@ export const tableData = api['POST/api/deployment/table/data'].signal()
export const rowDetailsData = api['POST/api/deployment/table/data'].signal()
export const logDetailsData = api['POST/api/deployment/logs'].signal()
export const metricsData = api['GET/api/deployment/metrics-sql'].signal()
+const routerMetricsData = api['GET/api/deployment/metrics-router'].signal()
const toastSignal = new Signal<
{ message: string; type: 'info' | 'error' } | null
@@ -195,7 +199,7 @@ effect(() => {
dep && schema.fetch({ url: dep })
})
-const tabNames = ['tables', 'queries', 'logs', 'metrics'] as const
+const tabNames = ['tables', 'queries', 'logs', 'metrics', 'routes'] as const
type TabName = (typeof tabNames)[number]
const activeTab = computed(() => {
@@ -874,7 +878,7 @@ function SchemaPanel() {
}
const TabButton = (
- { tabName }: { tabName: 'tables' | 'queries' | 'logs' | 'metrics' },
+ { tabName }: { tabName: TabName },
) => (
- Execute database queries to see performance data here. + {description}