@jheavenknows/bluerouter 5.4.19 → 5.4.21
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/app/.next-cli-build/BUILD_ID +1 -1
- package/app/.next-cli-build/app-path-routes-manifest.json +15 -15
- package/app/.next-cli-build/build-manifest.json +2 -2
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/ai-power-index/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/analytics/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/analytics/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/api-keys/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/audit-proxy/page.js +2 -15
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/audit-proxy/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/audit-proxy/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/model-profiles/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cluster/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/logs/console/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/personal/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/personalcloudprovider/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/personalcloudprovidermonitor/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/personalquota/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/prompt-logs/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/provider-health/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/stt/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/tts/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/resource-monitor/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/_global-error.html +1 -1
- package/app/.next-cli-build/server/app/_global-error.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/_not-found.html +1 -1
- package/app/.next-cli-build/server/app/_not-found.rsc +5 -5
- package/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/api/audit-proxy/ca/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/audit-proxy/me/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/audit-proxy/route.js +1 -1
- package/app/.next-cli-build/server/app/api/audit-proxy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/audit-proxy/users/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/ldap/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/ldap/users/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/login/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/start/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/status/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/view-mode/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/branding/[asset]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/branding/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/branding/upload/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-model-profiles/cloud-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-model-profiles/model-catalog/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-model-profiles/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/autostart/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/prompt-log-db/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/root-ca/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/config/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/heartbeat/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/peers/[id]/command/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/peers/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/peers/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/snapshot/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/sync/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cluster/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/codex-catalog/download/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/codex-catalog/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/codex-catalog/upload/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/combos/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/combos/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/ai-power-index/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/analytics/ai-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/analytics/analyze/route.js +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/analytics/analyze/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/analytics/route.js +6 -7
- package/app/.next-cli-build/server/app/api/dashboard/analytics/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/combos/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/endpoint/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/options/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/token-saver/route.js +2 -2
- package/app/.next-cli-build/server/app/api/dashboard/token-saver/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/caveman-test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/rotate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/mcp/[plugin]/message/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/mcp/[plugin]/sse/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/alias/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/availability/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/custom/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/disabled/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/cursor/auto-import/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/grok-cli/device-code/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/grok-cli/poll/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/[id]/api-key-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/[id]/import-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/[id]/models/[...routeModel]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/[id]/move/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/[id]/usage/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/client/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/monitor/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/permissions/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/routing/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/shares/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/personal-cloud-providers/visibility/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/pricing/catalog/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/pricing/recalculate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/pricing/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-health/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/openai-compatible/manage/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/client/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/test-batch/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/validate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/resource-monitor/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/resource-monitor/ai-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/resource-monitor/analyze/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/resource-monitor/history/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/resource-monitor/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/database/export/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/database/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/require-login/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
- package/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +1 -1
- package/app/.next-cli-build/server/app/api/translator/send/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/translator/translate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/disable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/enable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/status/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-check/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-login/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-start-daemon/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/chart/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/chart/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/history/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/logs/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/providers/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/request-details/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/request-logs/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/stats/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/stats/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/stream/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/api/chat/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/audio/speech/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/embeddings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/images/generations/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/messages/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/responses/compact/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/responses/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/search/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1beta/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
- package/app/.next-cli-build/server/app/api/version/shutdown/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
- package/app/.next-cli-build/server/app/api/version/update/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/callback.html +1 -1
- package/app/.next-cli-build/server/app/callback.rsc +5 -5
- package/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/ai-power-index.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/ai-power-index.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/ai-power-index.segments/!KGRhc2hib2FyZCk/dashboard/ai-power-index/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/ai-power-index.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/ai-power-index.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.rsc +9 -9
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/!KGRhc2hib2FyZCk/dashboard/api-keys/__PAGE__.segment.rsc +9 -9
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/_full.segment.rsc +9 -9
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools/model-profiles.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools/model-profiles.rsc +8 -8
- package/app/.next-cli-build/server/app/dashboard/cli-tools/model-profiles.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/model-profiles/__PAGE__.segment.rsc +8 -8
- package/app/.next-cli-build/server/app/dashboard/cli-tools/model-profiles.segments/_full.segment.rsc +8 -8
- package/app/.next-cli-build/server/app/dashboard/cli-tools/model-profiles.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cluster.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/cluster.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/cluster.segments/!KGRhc2hib2FyZCk/dashboard/cluster/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/cluster.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/cluster.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/logs.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/logs.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/logs.segments/!KGRhc2hib2FyZCk/dashboard/logs/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/logs.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/logs.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/personal.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/personal.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/personal.segments/!KGRhc2hib2FyZCk/dashboard/personal/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/personal.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/personal.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/!KGRhc2hib2FyZCk/dashboard/prompt-logs/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/!KGRhc2hib2FyZCk/dashboard/provider-health/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/stt.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/stt.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/stt.segments/!KGRhc2hib2FyZCk/dashboard/providers/stt/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/stt.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/stt.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/tts.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/tts.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/tts.segments/!KGRhc2hib2FyZCk/dashboard/providers/tts/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/tts.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers/tts.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.rsc +8 -8
- package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +8 -8
- package/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +8 -8
- package/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/resource-monitor.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/resource-monitor.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/resource-monitor.segments/!KGRhc2hib2FyZCk/dashboard/resource-monitor/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/resource-monitor.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/resource-monitor.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/!KGRhc2hib2FyZCk/dashboard/settings/pricing/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/skills.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/skills.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/token-saver.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/token-saver.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard.html +1 -1
- package/app/.next-cli-build/server/app/dashboard.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +7 -7
- package/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/index.html +1 -1
- package/app/.next-cli-build/server/app/index.rsc +5 -5
- package/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/landing.html +1 -1
- package/app/.next-cli-build/server/app/landing.rsc +5 -5
- package/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/login.html +1 -1
- package/app/.next-cli-build/server/app/login.rsc +6 -6
- package/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app-paths-manifest.json +15 -15
- package/app/.next-cli-build/server/chunks/1470.js +81 -81
- package/app/.next-cli-build/server/chunks/2731.js +84 -84
- package/app/.next-cli-build/server/chunks/3096.js +2 -2
- package/app/.next-cli-build/server/chunks/3399.js +1 -1
- package/app/.next-cli-build/server/chunks/3958.js +6 -6
- package/app/.next-cli-build/server/chunks/402.js +5 -5
- package/app/.next-cli-build/server/chunks/4746.js +1 -1
- package/app/.next-cli-build/server/chunks/6328.js +1 -1
- package/app/.next-cli-build/server/chunks/6811.js +1 -1
- package/app/.next-cli-build/server/chunks/6992.js +1 -1
- package/app/.next-cli-build/server/chunks/8640.js +2 -2
- package/app/.next-cli-build/server/chunks/9083.js +5 -5
- package/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
- package/app/.next-cli-build/server/pages/404.html +1 -1
- package/app/.next-cli-build/server/pages/500.html +1 -1
- package/app/.next-cli-build/static/chunks/{5263-d7e8656d89b2ca10.js → 5263-8c9d3413d7af4be6.js} +1 -1
- package/app/.next-cli-build/static/chunks/5497-cd964740ba299403.js +15 -0
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/analytics/page-a490ee99c12ec139.js +1 -0
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/audit-proxy/page-f6b35e9db17b4607.js +8 -0
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/token-saver/{page-7bdaff73571c066b.js → page-85844d8eef5b95df.js} +1 -1
- package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/upgrade-5.4.19-to-5.4.20-5.4.20-20260825-164658/data.sqlite +0 -0
- package/app/cli/.build-home/AppData/Roaming/bluerouter/db/data.sqlite-shm +0 -0
- package/app/cli/.build-home/AppData/Roaming/bluerouter/db/data.sqlite-wal +0 -0
- package/app/package.json +1 -1
- package/package.json +1 -1
- package/app/.next-cli-build/static/chunks/5497-c352fe8c48441441.js +0 -15
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/analytics/page-e71b6a5d6675a48d.js +0 -1
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/audit-proxy/page-7e36c7d76547e65b.js +0 -21
- /package/app/.next-cli-build/static/{WM_Lgz-rTI3jjkU3E5GgA → dD8D7N73BiFCP3LITpWCK}/_buildManifest.js +0 -0
- /package/app/.next-cli-build/static/{WM_Lgz-rTI3jjkU3E5GgA → dD8D7N73BiFCP3LITpWCK}/_ssgManifest.js +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-5.4.13-to-5.4.14-5.4.14-20260824-210858 → upgrade-5.4.17-to-5.4.18-5.4.18-20260824-221830}/data.sqlite +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-5.4.14-to-5.4.15-5.4.15-20260824-213538 → upgrade-5.4.18-to-5.4.19-5.4.19-20260825-075641}/data.sqlite +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8978],{53836:(e,t,s)=>{Promise.resolve().then(s.bind(s,76174)),Promise.resolve().then(s.bind(s,85881)),Promise.resolve().then(s.bind(s,70965))},70965:(e,t,s)=>{"use strict";s.d(t,{default:()=>c});var n=s(95155),r=s(12115),l=s(94027);let a=new Set(["Auto-off thinking","Thinking auto-off","Thinking OFF"]),i=new Set(["Large context"]);function o(e){return"cloud"===String(e||"").trim().toLowerCase()?"cloud":"local"}function d(e){document.cookie=`bluerouter_analytics_scope=${e}; Path=/; Max-Age=31536000; SameSite=Lax`}function c({initialScope:e="local",children:t}){let{isAdmin:s,isMonitorAdmin:x,isAiGatewaysMonitor:m}=(0,l.s)(),u=s||x||m,h=!u,[p,b]=(0,r.useState)(()=>o(e)),[g,y]=(0,r.useState)(!1),j=(0,r.useRef)(null);(0,r.useLayoutEffect)(()=>{u&&d(p),y(!0)},[u,p]),(0,r.useLayoutEffect)(()=>{let e=j.current;if(!e)return;let t=!1,n=()=>{t=!1,function(e,t){if(e){for(let t of e.querySelectorAll("[data-admin-only-thinking-hidden='true']"))t.style.display="",delete t.dataset.adminOnlyThinkingHidden;if(!t){for(let t of e.querySelectorAll("div.text-sm.font-medium.text-text-muted")){if(!a.has(t.textContent?.trim()))continue;let e=t.closest(".min-w-0.rounded-2xl.border.border-border.bg-surface");e&&(e.style.display="none",e.dataset.adminOnlyThinkingHidden="true")}for(let t of e.querySelectorAll("h2")){if(t.textContent?.trim()!=="Thinking Analytics")continue;let e=t.closest(".min-w-0.rounded-2xl.border.border-border.bg-surface");e&&(e.style.display="none",e.dataset.adminOnlyThinkingHidden="true")}}}}(e,s),function(e,t){if(e){for(let t of e.querySelectorAll("[data-regular-user-experience-hidden='true']"))t.style.display="",delete t.dataset.regularUserExperienceHidden;for(let t of e.querySelectorAll("[data-regular-user-experience-full-width='true']"))t.style.removeProperty("grid-column"),t.style.removeProperty("width"),delete t.dataset.regularUserExperienceFullWidth;if(t){for(let t of e.querySelectorAll("div.text-sm.font-medium.text-text-muted")){if(!i.has(t.textContent?.trim()))continue;let e=t.closest(".min-w-0.rounded-2xl.border.border-border.bg-surface");e&&(e.style.display="none",e.dataset.regularUserExperienceHidden="true")}for(let t of e.querySelectorAll("h2")){if(t.textContent?.trim()!=="Large Context Analytics")continue;let e=t.closest(".min-w-0.rounded-2xl.border.border-border.bg-surface");e&&(e.style.gridColumn="1 / -1",e.style.width="100%",e.dataset.regularUserExperienceFullWidth="true")}}}}(e,h)},r=()=>{t||(t=!0,requestAnimationFrame(n))};r();let l=new MutationObserver(r);return l.observe(e,{childList:!0,subtree:!0}),()=>l.disconnect()},[s,h,g]);let v=e=>{if(!u)return;let t=o(e);if(t===p)return;d(t),b(t);let s=new URL(window.location.href);s.searchParams.set("scope",t),window.history.replaceState(window.history.state,"",s.toString())};return(0,n.jsxs)("div",{ref:j,children:[u?(0,n.jsx)("div",{className:"px-4 pt-4 md:px-6 md:pt-6",children:(0,n.jsxs)("div",{className:"flex flex-wrap gap-2 rounded-2xl border border-border bg-surface p-2 shadow-sm",children:[(0,n.jsxs)("button",{type:"button",onClick:()=>v("local"),"aria-pressed":"local"===p,className:`flex min-w-[220px] flex-1 items-center gap-3 rounded-xl px-4 py-3 text-left transition ${"local"===p?"bg-primary text-white shadow-sm":"text-text-muted hover:bg-background hover:text-text-main"}`,children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:"developer_board"}),(0,n.jsxs)("span",{children:[(0,n.jsx)("span",{className:"block text-sm font-semibold",children:"Local models & providers"}),(0,n.jsx)("span",{className:`mt-0.5 block text-xs ${"local"===p?"text-white/75":"text-text-subtle"}`,children:"Self-hosted runtime, latency, TTFT, throughput v\xe0 token"})]})]}),(0,n.jsxs)("button",{type:"button",onClick:()=>v("cloud"),"aria-pressed":"cloud"===p,className:`flex min-w-[220px] flex-1 items-center gap-3 rounded-xl px-4 py-3 text-left transition ${"cloud"===p?"bg-primary text-white shadow-sm":"text-text-muted hover:bg-background hover:text-text-main"}`,children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:"cloud"}),(0,n.jsxs)("span",{children:[(0,n.jsx)("span",{className:"block text-sm font-semibold",children:"Cloud providers"}),(0,n.jsx)("span",{className:`mt-0.5 block text-xs ${"cloud"===p?"text-white/75":"text-text-subtle"}`,children:"External provider reliability, latency, token v\xe0 cost"})]})]})]})}):null,g?(0,n.jsx)("div",{children:t},u?p:"user-owned"):null]})}},76174:(e,t,s)=>{"use strict";s.d(t,{default:()=>eb});var n=s(95155),r=s(12115),l=s(9233),a=s(94027);function i(e){let t=Number(e);return Number.isFinite(t)?t:0}function o(e,t=0){return i(e).toLocaleString("vi-VN",{maximumFractionDigits:t})}function d(e){return new Intl.NumberFormat("en",{notation:"compact",maximumFractionDigits:1}).format(i(e))}function c(e){let t=Number(e);return!Number.isFinite(t)||t<=0?"-":t>=1e3?`${(t/1e3).toLocaleString("vi-VN",{maximumFractionDigits:2})} s`:`${Math.round(t)} ms`}function x(e){let t=Number(e);return Number.isFinite(t)&&t>0?`${t.toLocaleString("vi-VN",{maximumFractionDigits:1})} tok/s`:"-"}function m(e){return`$${i(e).toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:4})}`}function u({row:e}){return(0,n.jsxs)("div",{className:"min-w-[105px] text-xs tabular-nums",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:d(e.totalTokens)}),(0,n.jsxs)("div",{className:"text-text-muted",children:["in ",d(e.promptTokens)," \xb7 out ",d(e.completionTokens)]})]})}function h({label:e,value:t,hint:s}){return(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-background/55 px-3 py-2.5",children:[(0,n.jsx)("div",{className:"text-[10px] font-semibold uppercase tracking-wide text-text-muted",children:e}),(0,n.jsx)("div",{className:"mt-1 text-lg font-semibold tabular-nums text-text-main",children:t}),s?(0,n.jsx)("div",{className:"mt-0.5 text-[10px] text-text-muted",children:s}):null]})}function p({rows:e,cloud:t}){return e.length?(0,n.jsx)("div",{className:"overflow-x-auto overflow-y-auto rounded-2xl border border-border",style:{maxHeight:"520px"},children:(0,n.jsxs)("table",{className:"min-w-[1080px] w-full divide-y divide-border text-sm",children:[(0,n.jsx)("thead",{className:"sticky top-0 z-10 bg-background/95 backdrop-blur",children:(0,n.jsxs)("tr",{children:[(0,n.jsx)("th",{className:"px-3 py-2.5 text-left text-xs font-semibold text-text-muted",children:"Model / Provider"}),(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",children:"Req"}),(0,n.jsx)("th",{className:"px-3 py-2.5 text-left text-xs font-semibold text-text-muted",children:"Tokens"}),(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",children:"Error"}),(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",children:"P95 latency"}),(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",children:"P95 TTFT"}),t?null:(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",title:"Decode tok/s = Σ output tokens / Σ (latency - TTFT). Chỉ d\xf9ng request th\xe0nh c\xf4ng c\xf3 output v\xe0 TTFT hợp lệ.",children:"Decode tok/s"}),t?(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",children:"Cost"}):null,(0,n.jsx)("th",{className:"px-3 py-2.5 text-right text-xs font-semibold text-text-muted",children:"Last used"})]})}),(0,n.jsx)("tbody",{className:"divide-y divide-border/70",children:e.map(e=>{let s,r,l=(s=i(e.requests),r=i(e.errors),s>0?r/s:i(e.errorRate)),a=e.decodeTokensPerSecond,d=i(e.decodeSamples);return(0,n.jsxs)("tr",{className:"hover:bg-background/50",children:[(0,n.jsxs)("td",{className:"px-3 py-2.5",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:e.model||e.label||"unknown"}),(0,n.jsx)("div",{className:"mt-0.5 text-xs text-text-muted",children:e.providerLabel||e.provider||"unknown"})]}),(0,n.jsx)("td",{className:"px-3 py-2.5 text-right tabular-nums",children:o(e.requests)}),(0,n.jsx)("td",{className:"px-3 py-2.5",children:(0,n.jsx)(u,{row:e})}),(0,n.jsx)("td",{className:"px-3 py-2.5 text-right",children:(0,n.jsxs)("span",{className:l>=.05?"text-red-500":l>0?"text-amber-500":"text-emerald-500",children:[(100*l).toLocaleString("vi-VN",{maximumFractionDigits:1}),"%"]})}),(0,n.jsx)("td",{className:"px-3 py-2.5 text-right tabular-nums",children:c(e.p95LatencyMs)}),(0,n.jsx)("td",{className:"px-3 py-2.5 text-right tabular-nums",children:c(e.p95TtftMs)}),t?null:(0,n.jsxs)("td",{className:"px-3 py-2.5 text-right tabular-nums",children:[(0,n.jsx)("div",{className:"font-semibold",children:x(a)}),(0,n.jsxs)("div",{className:"mt-0.5 text-[10px] font-normal text-text-muted",children:[o(d)," mẫu decode"]}),null==a&&e.e2eOutputTokensPerSecond?(0,n.jsxs)("div",{className:"text-[10px] font-normal text-text-subtle",children:["E2E ",x(e.e2eOutputTokensPerSecond)]}):null]}),t?(0,n.jsx)("td",{className:"px-3 py-2.5 text-right tabular-nums text-emerald-600 dark:text-emerald-300",children:m(e.cost)}):null,(0,n.jsx)("td",{className:"px-3 py-2.5 text-right text-xs text-text-muted",children:function(e){if(!e)return"-";let t=new Date(e);return Number.isNaN(t.getTime())?String(e):t.toLocaleString("vi-VN")}(e.lastSeen)})]},e.key||`${e.provider}-${e.model}`)})})]})}):(0,n.jsxs)("div",{className:"rounded-2xl border border-dashed border-border px-4 py-7 text-center text-sm text-text-muted",children:["Kh\xf4ng c\xf3 model ",t?"cloud":"local"," trong khoảng lọc hiện tại."]})}function b({type:e,rows:t,summary:s}){let r="local"===e,l=s.decodeTokensPerSecond,a=[`Σ output / Σ(latency − TTFT) \xb7 ${o(s.decodeSamples||0)} mẫu decode hợp lệ`,null==l&&s.e2eOutputTokensPerSecond?`Chưa c\xf3 mẫu decode hợp lệ \xb7 E2E ${x(s.e2eOutputTokensPerSecond)}`:""].filter(Boolean).join(" \xb7 ");return(0,n.jsxs)("section",{className:"rounded-3xl border border-border bg-surface p-5 shadow-[var(--shadow-soft)]",children:[(0,n.jsxs)("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[(0,n.jsxs)("div",{className:"flex items-start gap-3",children:[(0,n.jsx)("div",{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-xl ${r?"bg-primary/10 text-primary":"bg-amber-500/10 text-amber-600 dark:text-amber-300"}`,children:(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:r?"developer_board":"cloud"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:r?"Local Models":"Cloud Models"}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-text-muted",children:r?"Self-hosted inference: vLLM, SGLang, Ollama, llama.cpp hoặc compatible endpoint được đ\xe1nh dấu Local.":"External/cloud API providers, kể cả compatible endpoint được đ\xe1nh dấu Cloud."})]})]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-background px-3 py-1 text-xs font-semibold text-text-muted",children:[o(s.models??t.length)," models"]})]}),(0,n.jsxs)("div",{className:"mb-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3",children:[(0,n.jsx)(h,{label:"Requests",value:o(s.requests)}),(0,n.jsx)(h,{label:"Total tokens",value:d(s.totalTokens),hint:`In ${d(s.promptTokens)} \xb7 Out ${d(s.completionTokens)}`}),r?(0,n.jsx)(h,{label:"Decode speed",value:x(l),hint:a}):(0,n.jsx)(h,{label:"Estimated cost",value:m(s.cost)})]}),(0,n.jsx)(p,{rows:t,cloud:!r})]})}function g({data:e}){let t=e?.groups||{},s=e?.deploymentAnalytics||{},r=String(e?.analyticsScope||"all").trim().toLowerCase(),l=t.localModels||[],a=t.cloudModels||[],i=t.unknownModels||[];return(0,n.jsxs)("div",{className:"space-y-5",children:["cloud"!==r?(0,n.jsx)(b,{type:"local",rows:l,summary:s.local||{}}):null,"local"!==r?(0,n.jsx)(b,{type:"cloud",rows:a,summary:s.cloud||{}}):null,i.length>0?(0,n.jsx)("div",{className:"rounded-2xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-700 dark:text-amber-300",children:(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[20px]",children:"warning"}),(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"font-semibold",children:[o(i.length)," model chưa x\xe1c định Local / Cloud"]}),(0,n.jsx)("div",{className:"mt-0.5 text-xs opacity-90",children:"Mở Custom Provider tương ứng v\xe0 chọn Deployment để số liệu kh\xf4ng bị gộp sai."})]})]})}):null]})}l.xI.setOptions({gfm:!0,breaks:!0});let y=[{value:"today",label:"H\xf4m nay"},{value:"todayWorking",label:"H\xf4m nay (Working time)"},{value:"yesterday",label:"H\xf4m qua"},{value:"yesterdayWorking",label:"H\xf4m qua (Working time)"},{value:"24h",label:"24 giờ"},{value:"thisWeek",label:"Tuần n\xe0y"},{value:"lastWeek",label:"Tuần trước"},{value:"7d",label:"7 ng\xe0y"},{value:"thisMonth",label:"Th\xe1ng n\xe0y"},{value:"lastMonth",label:"Th\xe1ng trước"},{value:"30d",label:"30 ng\xe0y"},{value:"60d",label:"60 ng\xe0y"},{value:"all",label:"Tất cả (60 ng\xe0y)"}],j=[{value:"overview",label:"Tổng quan",icon:"dashboard"},{value:"apiKeys",label:"API keys",icon:"vpn_key"},{value:"clients",label:"Client/User",icon:"groups"},{value:"sources",label:"Source IP / Tool",icon:"hub"},{value:"providers",label:"Provider / Model",icon:"dns"},{value:"experience",label:"Trải nghiệm",icon:"speed"},{value:"errors",label:"Lỗi & bất thường",icon:"warning"},{value:"raw",label:"Raw usage",icon:"table"},{value:"aiHealth",label:"Đ\xe1nh gi\xe1 AI",icon:"neurology"}],v="blueRouterAnalyticsTab",k={normal:{className:"border-emerald-500/20 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",label:"B\xecnh thường"},warning:{className:"border-amber-500/20 bg-amber-500/10 text-amber-700 dark:text-amber-300",label:"Cảnh b\xe1o"},critical:{className:"border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-300",label:"Nghi\xeam trọng"},no_traffic:{className:"border-border bg-surface-2 text-text-muted",label:"Kh\xf4ng c\xf3 lưu lượng"},unknown:{className:"border-border bg-surface-2 text-text-muted",label:"Kh\xf4ng r\xf5"}};function f({status:e}){let t=k[e]||k.unknown;return(0,n.jsxs)("span",{className:O("inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-semibold",t.className),children:[(0,n.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-current"}),t.label]})}function N(e){let t=Number(e||0);if(!t)return"-";let s=["B","KiB","MiB","GiB","TiB"],n=Math.min(Math.floor(Math.log(t)/Math.log(1024)),s.length-1);return`${(t/1024**n).toLocaleString("vi-VN",{maximumFractionDigits:1})} ${s[n]}`}function T({nodes:e=[]}){return e.length?(0,n.jsxs)("section",{className:"border-y border-border py-4",children:[(0,n.jsxs)("div",{className:"mb-3 flex items-center gap-2",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[19px] text-primary",children:"developer_board"}),(0,n.jsx)("h4",{className:"text-sm font-semibold text-text-main",children:"Cấu h\xecnh phần cứng từng node tại l\xfac đ\xe1nh gi\xe1"})]}),(0,n.jsx)("div",{className:"divide-y divide-border",children:e.map(e=>(0,n.jsxs)("div",{className:"grid gap-2 py-3 text-xs md:grid-cols-[minmax(180px,0.8fr)_minmax(0,2.2fr)]",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:e.name}),(0,n.jsx)("div",{className:"mt-0.5 text-text-muted",children:e.host||e.hostname||"-"}),(0,n.jsx)("div",{className:e.reachable?"mt-1 text-emerald-600 dark:text-emerald-300":"mt-1 text-red-600 dark:text-red-300",children:e.reachable?"C\xf3 dữ liệu":e.error||"Chưa c\xf3 snapshot"})]}),e.reachable?(0,n.jsxs)("div",{className:"space-y-1 text-text-muted",children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"font-medium text-text-main",children:"CPU:"})," ",e.cpu?.model||"-"," \xb7 ",e.cpu?.cores||0," cores \xb7 sử dụng ",Number(e.cpu?.usagePercent||0).toLocaleString("vi-VN",{maximumFractionDigits:1}),"%"]}),(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"font-medium text-text-main",children:"RAM:"})," ",N(e.memory?.totalBytes)," \xb7 đang d\xf9ng ",N(e.memory?.usedBytes)," (",Number(e.memory?.usagePercent||0).toLocaleString("vi-VN",{maximumFractionDigits:1}),"%)"]}),e.gpus?.length?e.gpus.map(t=>(0,n.jsxs)("p",{children:[(0,n.jsxs)("span",{className:"font-medium text-text-main",children:["GPU ",t.index,":"]})," ",t.name," \xb7 VRAM ",(Number(t.memoryTotalMb||0)/1024).toLocaleString("vi-VN",{maximumFractionDigits:1})," GiB \xb7 sử dụng ",Number(t.usagePercent||0).toLocaleString("vi-VN",{maximumFractionDigits:1}),"%"]},`${e.id}-${t.index}`)):(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"font-medium text-text-main",children:"GPU:"})," Kh\xf4ng ph\xe1t hiện NVIDIA GPU"]}),(0,n.jsxs)("p",{className:"text-text-subtle",children:["Snapshot: ",e.statusAt?new Date(e.statusAt).toLocaleString("vi-VN"):"-"]})]}):null]},e.id))})]}):null}function w(){let[e,t]=(0,r.useState)([]),[s,a]=(0,r.useState)(""),[i,o]=(0,r.useState)(null),[d,c]=(0,r.useState)(!1),[x,m]=(0,r.useState)(!1),[u,h]=(0,r.useState)(""),[p,b]=(0,r.useState)(!1),[g,y]=(0,r.useState)(""),[j,v]=(0,r.useState)(""),[k,N]=(0,r.useState)(!1),[w,S]=(0,r.useState)("");(0,r.useEffect)(()=>{(async()=>{let e="";try{let t=await fetch("/api/dashboard/analytics/analyze",{cache:"no-store"}),s=await t.json().catch(()=>({}));if(t.ok){o(s.analysis||null),c(!0===s.standby),e=s.selectedModel||"";let t=s.vllmConfig||"";y(t),v(t)}}catch{}try{let s=await fetch("/api/dashboard/analytics/ai-models",{cache:"no-store"}),n=(await s.json().catch(()=>({}))).options||[];t(n),a(t=>{let s=t||e;return s&&n.some(e=>e.value===s)?s:n[0]?.value||""})}catch{t([])}finally{b(!0)}})()},[]);let q=(0,r.useCallback)(e=>{a(e),fetch("/api/dashboard/analytics/analyze",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:e})}).catch(()=>{})},[]),P=(0,r.useCallback)(async({showMessage:e=!0}={})=>{N(!0),e&&S("");try{let t=await fetch("/api/dashboard/analytics/analyze",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({vllmConfig:g})}),s=await t.json().catch(()=>({}));if(!t.ok)throw Error(s.error||"Kh\xf4ng thể lưu cấu h\xecnh vLLM");let n=s.vllmConfig||"";return y(n),v(n),e&&S("Đ\xe3 lưu cấu h\xecnh vLLM"),n}finally{N(!1)}},[g]),L=(0,r.useCallback)(async()=>{h("");try{await P()}catch(e){S(""),h(e?.message||"Kh\xf4ng thể lưu cấu h\xecnh vLLM")}},[P]),M=(0,r.useCallback)(async()=>{if(!s)return;let e=s.indexOf("::"),t=s.slice(0,e),n=s.slice(e+2);m(!0),h("");try{g.trim()!==j&&await P({showMessage:!1});let e=await fetch("/api/dashboard/analytics/analyze",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({connectionId:t,model:n})}),s=await e.json().catch(()=>({}));if(!e.ok)throw Error(s.error||"Kh\xf4ng thể ph\xe2n t\xedch");o(s.analysis)}catch(e){h(e?.message||"Kh\xf4ng thể ph\xe2n t\xedch")}finally{m(!1)}},[P,j,s,g]),R=(0,r.useMemo)(()=>i?.summary?l.xI.parse(i.summary):"",[i]);return(0,n.jsxs)("section",{className:"overflow-hidden rounded-3xl border border-border bg-surface shadow-[var(--shadow-soft)]",children:[(0,n.jsx)("div",{className:"flex flex-wrap items-center justify-between gap-4 border-b border-border px-6 py-5",children:(0,n.jsxs)("div",{className:"flex items-center gap-4",children:[(0,n.jsx)("div",{className:"flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary",children:(0,n.jsx)("span",{className:"material-symbols-outlined text-[27px]",children:"neurology"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-lg font-semibold text-text-main",children:"Đ\xe1nh gi\xe1 AI về trải nghiệm & hiệu năng"}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-text-muted",children:'Ph\xe2n t\xedch giờ l\xe0m việc h\xf4m nay, tập trung v\xe0o tab "Trải nghiệm" v\xe0 c\xe1c vLLM AI server local. Chạy nền tự động mỗi 1 giờ.'})]})]})}),(0,n.jsxs)("div",{className:"space-y-5 p-6",children:[d?(0,n.jsx)("div",{className:"rounded-xl border border-amber-500/20 bg-amber-500/10 px-4 py-3 text-sm text-amber-700 dark:text-amber-300",children:"Standby mode: kết quả ph\xe2n t\xedch được đồng bộ tự động từ Master. Node n\xe0y kh\xf4ng tự chạy ph\xe2n t\xedch AI."}):null,(0,n.jsxs)("div",{className:"space-y-2",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsx)("label",{htmlFor:"analytics-vllm-config",className:"text-xs font-medium text-text-muted",children:"Cấu h\xecnh vLLM của c\xe1c server"}),(0,n.jsxs)("span",{className:"text-xs text-text-subtle",children:[g.length.toLocaleString("vi-VN")," / 50.000 k\xfd tự"]})]}),(0,n.jsx)("textarea",{id:"analytics-vllm-config",rows:8,maxLength:5e4,value:g,onChange:e=>{y(e.target.value),S("")},disabled:d||k,placeholder:"M\xf4 tả theo từng node, v\xed dụ:\nnode-gpu-01: model=..., --tensor-parallel-size 4, --max-model-len 32768, --gpu-memory-utilization 0.9\nnode-gpu-02: model=..., replicas=2, c\xe1c tham số batching/concurrency...",className:"w-full resize-y rounded-lg border border-border bg-surface px-3 py-2.5 font-mono text-xs leading-5 text-text-main outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:opacity-60"}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsx)("p",{className:"text-xs text-text-muted",children:"D\xf9ng t\xean hoặc host tr\xf9ng với Linux node trong Resource Monitor để AI \xe1nh xạ ch\xednh x\xe1c."}),(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[w?(0,n.jsx)("span",{className:"text-xs text-emerald-600 dark:text-emerald-300",children:w}):null,(0,n.jsxs)("button",{type:"button",onClick:L,disabled:d||k||g.trim()===j,className:"inline-flex items-center gap-2 rounded-lg border border-border bg-surface px-3 py-2 text-xs font-semibold text-text-main transition hover:border-primary/40 disabled:cursor-not-allowed disabled:opacity-50",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[17px]",children:k?"progress_activity":"save"}),k?"Đang lưu...":"Lưu cấu h\xecnh"]})]})]})]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-end gap-3",children:[(0,n.jsxs)("label",{className:"flex min-w-[280px] flex-1 flex-col gap-1.5 text-sm",children:[(0,n.jsx)("span",{className:"text-xs font-medium text-text-muted",children:"AI model d\xf9ng để ph\xe2n t\xedch"}),(0,n.jsxs)("select",{className:"rounded-xl border border-border bg-surface px-3 py-2.5 text-sm text-text-main disabled:opacity-60",value:s,onChange:e=>q(e.target.value),disabled:!e.length||d,children:[e.length?null:(0,n.jsx)("option",{value:"",children:"Chưa c\xf3 kết nối AI n\xe0o đang hoạt động"}),e.map(e=>(0,n.jsx)("option",{value:e.value,children:e.label},e.value))]})]}),(0,n.jsxs)("button",{type:"button",onClick:M,disabled:!s||d||x,className:"flex items-center gap-2 rounded-xl bg-primary px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition disabled:cursor-not-allowed disabled:opacity-60",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[18px]",children:x?"progress_activity":"auto_awesome"}),x?"Đang ph\xe2n t\xedch...":"Ph\xe2n t\xedch lại"]})]}),u?(0,n.jsx)("div",{className:"rounded-xl border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-300",children:u}):null,i?(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2 text-xs text-text-muted",children:[(0,n.jsxs)("span",{children:["Model: ",(0,n.jsx)("span",{className:"font-semibold",children:i.modelLabel})]}),(0,n.jsxs)("span",{children:["Cập nhật l\xfac ",i.generatedAt?new Date(i.generatedAt).toLocaleString("vi-VN"):"-"]})]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsx)("span",{className:"text-xs text-text-muted",children:"Tổng quan:"}),(0,n.jsx)(f,{status:i.status}),(0,n.jsx)("span",{className:"text-xs text-text-muted",children:"vLLM local:"}),(0,n.jsx)(f,{status:i.vllmStatus}),"number"==typeof i.vllmServerCount?(0,n.jsxs)("span",{className:"text-xs text-text-subtle",children:["(",i.vllmServerCount," node)"]}):null]}),(0,n.jsx)(T,{nodes:i.hardwareNodes||[]}),(0,n.jsx)("div",{className:"analytics-ai-body rounded-2xl border border-border bg-surface-2/40 p-5 text-sm leading-6 text-text-main",dangerouslySetInnerHTML:{__html:R}})]}):!x&&p?(0,n.jsx)("div",{className:"rounded-2xl border border-dashed border-border bg-surface-2/40 py-10 text-center text-sm text-text-muted",children:'Chưa c\xf3 ph\xe2n t\xedch n\xe0o — bấm "Ph\xe2n t\xedch lại" để bắt đầu.'}):null]})]})}function S(e,t=0){return Number(e||0).toLocaleString("vi-VN",{maximumFractionDigits:t})}function q(e){let t=Number(e||0);return Intl.NumberFormat("vi-VN",{notation:"compact",maximumFractionDigits:1}).format(t)}function P(e){let t=100*Number(e||0);return`${t.toLocaleString("vi-VN",{maximumFractionDigits:1})}%`}function L(e){let t=Number(e||0);return t?`$${t.toLocaleString("vi-VN",{minimumFractionDigits:4,maximumFractionDigits:6})}`:"$0"}function M(e){if(null==e||Number.isNaN(Number(e)))return"-";let t=Number(e);return t>=1e3?`${(t/1e3).toLocaleString("vi-VN",{maximumFractionDigits:2})}s`:`${t.toLocaleString("vi-VN",{maximumFractionDigits:0})}ms`}function R(e,t="/s"){if(null==e||Number.isNaN(Number(e)))return"-";let s=Number(e);return`${s.toLocaleString("vi-VN",{maximumFractionDigits:s>=10?1:2})}${t}`}function I(e){return null==e||Number.isNaN(Number(e))?"-":`${Number(e).toLocaleString("vi-VN",{maximumFractionDigits:0})}/100`}function C(e){if(!e)return null;let t=String(e).trim();return new Date(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(t)?`${t.replace(" ","T")}Z`:t)}function A(e){if(!e)return"-";try{let t=C(e);if(!t||Number.isNaN(t.getTime()))return String(e);return t.toLocaleString("vi-VN",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}catch{return String(e)}}function $(e){if(!e)return"";try{let t=C(e);if(!t||Number.isNaN(t.getTime()))return String(e);return t.toLocaleString("vi-VN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1})}catch{return String(e)}}function F(){let{isAdmin:e,isMonitorAdmin:t,isAiGatewaysMonitor:s}=(0,a.s)();return e||t||s}function O(...e){return e.filter(Boolean).join(" ")}function K(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}function E(e,t={}){let s=new URLSearchParams;return Object.entries({...e,...t}).forEach(([e,t])=>{let n=String(t??"").trim();n&&s.set(e,n)}),s.toString()}function U({children:e,className:t=""}){return(0,n.jsx)("div",{className:O("min-w-0 rounded-2xl border border-border bg-surface p-5 shadow-sm",t),children:e})}function _({icon:e,label:t,value:s,hint:r,help:l,tone:a="blue"}){return(0,n.jsx)(U,{className:"min-h-[126px]",children:(0,n.jsxs)("div",{className:"flex items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"text-sm font-medium text-text-muted",children:t}),(0,n.jsx)("div",{className:"mt-2 text-2xl font-semibold text-text-main",children:s}),r?(0,n.jsx)("div",{className:"mt-2 text-xs text-text-muted",children:r}):null,l?(0,n.jsx)("div",{className:"mt-1 text-[11px] leading-4 text-text-muted/70",children:l}):null]}),(0,n.jsx)("div",{className:O("flex h-10 w-10 items-center justify-center rounded-xl",{blue:"bg-blue-500/10 text-blue-600 dark:text-blue-300",green:"bg-green-500/10 text-green-600 dark:text-green-300",red:"bg-red-500/10 text-red-600 dark:text-red-300",amber:"bg-amber-500/10 text-amber-600 dark:text-amber-300",purple:"bg-purple-500/10 text-purple-600 dark:text-purple-300",slate:"bg-slate-500/10 text-slate-600 dark:text-slate-300"}[a]||"bg-blue-500/10 text-blue-600 dark:text-blue-300"),children:(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:e})})]})})}function D({label:e,children:t}){return(0,n.jsxs)("label",{className:"space-y-1.5 text-xs font-medium text-text-muted",children:[(0,n.jsx)("span",{children:e}),t]})}function V({value:e,onChange:t,children:s}){return(0,n.jsx)("select",{value:e||"",onChange:e=>t(e.target.value),className:"h-10 w-full rounded-xl border border-border bg-background px-3 text-sm text-text-main outline-none transition focus:border-primary/60 focus:ring-2 focus:ring-primary/20",children:s})}function H({value:e,onChange:t,placeholder:s="",type:r="text"}){return(0,n.jsx)("input",{value:e||"",type:r,onChange:e=>t(e.target.value),placeholder:s,className:"h-10 w-full rounded-xl border border-border bg-background px-3 text-sm text-text-main outline-none transition placeholder:text-text-muted/60 focus:border-primary/60 focus:ring-2 focus:ring-primary/20"})}function B(){return(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsx)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:Array.from({length:8}).map((e,t)=>(0,n.jsx)("div",{className:"h-32 animate-pulse rounded-2xl border border-border bg-surface"},t))}),(0,n.jsx)("div",{className:"h-80 animate-pulse rounded-2xl border border-border bg-surface"})]})}function G({title:e="Kh\xf4ng c\xf3 dữ liệu",description:t="Kh\xf4ng t\xecm thấy dữ liệu theo bộ lọc hiện tại."}){return(0,n.jsxs)("div",{className:"flex min-h-[180px] flex-col items-center justify-center rounded-2xl border border-dashed border-border bg-surface/60 p-8 text-center",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-4xl text-text-muted",children:"database_off"}),(0,n.jsx)("div",{className:"mt-3 text-sm font-semibold text-text-main",children:e}),(0,n.jsx)("div",{className:"mt-1 max-w-xl text-sm text-text-muted",children:t})]})}function z({data:e=[],valueKey:t="totalTokens",secondaryKey:s="requests",height:r=220}){let l=e||[],a=Math.max(...l.map(e=>Number(e[t]||0)),1),i=Math.max(...l.map(e=>Number(e[s]||0)),1);return 0===l.length?(0,n.jsx)(G,{description:"Chưa c\xf3 time-series trong khoảng thời gian n\xe0y."}):(0,n.jsx)("div",{className:"overflow-x-auto",children:(0,n.jsxs)("div",{className:"min-w-[720px]",children:[(0,n.jsx)("div",{className:"flex items-end gap-1",style:{height:r},children:l.map((e,l)=>{let o=Math.max(2,Number(e[t]||0)/a*(r-42)),d=Math.max(2,Number(e[s]||0)/i*(r-42));return(0,n.jsx)("div",{className:"group flex flex-1 flex-col items-center justify-end gap-1",children:(0,n.jsxs)("div",{className:"relative flex h-full w-full max-w-[34px] items-end justify-center gap-0.5",children:[(0,n.jsx)("div",{className:"w-2 rounded-t bg-primary/70",style:{height:o}}),(0,n.jsx)("div",{className:"w-2 rounded-t bg-amber-500/70",style:{height:d}}),(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-full left-1/2 z-20 hidden w-56 -translate-x-1/2 rounded-xl border border-border bg-surface p-3 text-left text-xs shadow-xl group-hover:block",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:$(e.label)}),(0,n.jsxs)("div",{className:"mt-1 text-text-muted",children:["Request: ",S(e.requests)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["Input token: ",S(e.promptTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["Output token: ",S(e.completionTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["Tổng token: ",S(e.totalTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["Lỗi: ",S(e.errors)]})]})]})},`${e.label}-${l}`)})}),(0,n.jsxs)("div",{className:"mt-3 flex justify-between gap-2 text-[11px] text-text-muted",children:[(0,n.jsx)("span",{children:$(l[0]?.label)}),(0,n.jsx)("span",{children:$(l[Math.floor(l.length/2)]?.label)}),(0,n.jsx)("span",{children:$(l[l.length-1]?.label)})]})]})})}function W(){return(0,n.jsxs)("div",{className:"flex flex-wrap gap-3 text-xs text-text-muted",children:[(0,n.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,n.jsx)("span",{className:"h-2.5 w-2.5 rounded-sm bg-primary/70"}),"Token"]}),(0,n.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,n.jsx)("span",{className:"h-2.5 w-2.5 rounded-sm bg-amber-500/70"}),"Request"]})]})}function X({columns:e,rows:t,empty:s="Kh\xf4ng c\xf3 dữ liệu"}){return t&&0!==t.length?(0,n.jsx)("div",{className:"overflow-x-auto overflow-y-auto rounded-2xl border border-border",style:{maxHeight:"500px"},children:(0,n.jsxs)("table",{className:"min-w-full divide-y divide-border text-sm",children:[(0,n.jsx)("thead",{className:"bg-background/70",children:(0,n.jsx)("tr",{children:e.map(e=>(0,n.jsx)("th",{className:O("whitespace-nowrap px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-text-muted",e.className),children:e.label},e.key))})}),(0,n.jsx)("tbody",{className:"divide-y divide-border bg-surface",children:t.map((t,s)=>(0,n.jsx)("tr",{className:"hover:bg-background/60",children:e.map(e=>(0,n.jsx)("td",{className:O("whitespace-nowrap px-4 py-3 align-top text-text-main",e.className),children:e.render?e.render(t,s):t[e.key]??"-"},e.key))},t.key||t.id||`${t.label}-${s}`))})]})}):(0,n.jsx)(G,{title:s})}function J({items:e=[]}){return e&&0!==e.length?(0,n.jsx)("div",{className:"flex max-w-[360px] flex-wrap gap-1.5",children:e.slice(0,3).map(e=>(0,n.jsxs)("span",{className:"rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary",children:[e.label||e.key," \xb7 ",S(e.count??e.requests??e.totalTokens??0)]},e.key))}):(0,n.jsx)("span",{className:"text-text-muted",children:"-"})}function Z({row:e}){return(0,n.jsxs)("div",{className:"space-y-1 text-xs",children:[(0,n.jsxs)("div",{className:"font-semibold text-text-main",children:[q(e.totalTokens)," token"]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["In ",q(e.promptTokens)," / Out ",q(e.completionTokens)]})]})}function Q({leaderboard:e={}}){let t=F(),s=e.rows||[],r=e.status||"warming",l="ready"===r?`${e.periodLabel||"H\xf4m nay"} \xb7 cập nhật ${A(e.generatedAt)} \xb7 refresh nền mỗi ${Math.round((e.refreshEveryMs||9e5)/6e4)} ph\xfat`:"error"===r?"Leaderboard đang chờ job nền tổng hợp lại dữ liệu.":"Leaderboard đang được job nền khởi tạo.";return(0,n.jsxs)(U,{className:"border-amber-500/20 bg-amber-500/[0.03]",children:[(0,n.jsxs)("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-2xl text-amber-500",children:"crown"}),(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Top 5 vinh danh token"})]}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Xếp hạng theo API key owner d\xf9ng nhiều input + output token nhất."})]}),(0,n.jsx)("span",{className:"rounded-full bg-amber-500/10 px-3 py-1 text-xs font-semibold text-amber-700 dark:text-amber-300",children:l})]}),(0,n.jsx)(X,{rows:s,empty:"Chưa c\xf3 snapshot leaderboard từ job nền.",columns:[{key:"rank",label:"Hạng",render:e=>(0,n.jsxs)("div",{className:"flex min-w-[170px] items-center gap-3",children:[(0,n.jsx)("div",{className:O("flex h-10 w-10 shrink-0 items-center justify-center rounded-xl",1===e.rank?"bg-amber-500/15 text-amber-600":"bg-primary/10 text-primary"),children:(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:"crown"})}),(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"font-semibold text-text-main",children:["#",e.rank," \xb7 ",e.title]}),(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:[P(e.tokenShare||0)," tổng token"]})]})]})},{key:"owner",label:"Owner",render:e=>(0,n.jsxs)("div",{className:"min-w-[210px]",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:e.ownerUser||e.label}),(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:[e.apiKeyName||"API key",t&&e.apiKeyFingerprint?` \xb7 ${e.apiKeyFingerprint}`:""]})]})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"scope",label:"Phạm vi",render:e=>(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:[(0,n.jsxs)("div",{children:["API key ",S(e.apiKeyCount)," \xb7 IP ",S(e.sourceIpCount)]}),(0,n.jsxs)("div",{children:["Model ",S(e.modelCount)," \xb7 Provider ",S(e.providerCount)]})]})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]})}function Y({value:e}){let t=Number(e||0);return(0,n.jsx)("span",{className:O("rounded-full px-2 py-1 text-xs font-semibold",t>=.2?"bg-red-500/10 text-red-600 dark:text-red-300":t>=.05?"bg-amber-500/10 text-amber-600 dark:text-amber-300":"bg-green-500/10 text-green-600 dark:text-green-300"),children:P(t)})}function ee({level:e,label:t}){let s=String(e||"none");return(0,n.jsx)("span",{className:O("rounded-full px-2 py-1 text-xs font-semibold",{fast:"bg-green-500/10 text-green-700 dark:text-green-300",ok:"bg-blue-500/10 text-blue-700 dark:text-blue-300",slow:"bg-amber-500/10 text-amber-700 dark:text-amber-300",very_slow:"bg-red-500/10 text-red-700 dark:text-red-300",low_sample:"bg-amber-500/10 text-amber-700 dark:text-amber-300",none:"bg-slate-500/10 text-slate-700 dark:text-slate-300"}[s]||"bg-slate-500/10 text-slate-700 dark:text-slate-300"),children:t||"-"})}function et({level:e,label:t}){let s=String(e||"normal");return(0,n.jsx)("span",{className:O("rounded-full px-2 py-1 text-xs font-semibold",{critical:"bg-red-500/10 text-red-700 dark:text-red-300",high:"bg-amber-500/10 text-amber-700 dark:text-amber-300",medium:"bg-blue-500/10 text-blue-700 dark:text-blue-300",normal:"bg-green-500/10 text-green-700 dark:text-green-300",none:"bg-slate-500/10 text-slate-700 dark:text-slate-300"}[s]||"bg-slate-500/10 text-slate-700 dark:text-slate-300"),children:t||"-"})}function es({value:e}){let t=String(e||"unknown"),s={gateway:{label:"Gateway",cls:"bg-purple-500/10 text-purple-700 dark:text-purple-300"},upstream:{label:"Upstream",cls:"bg-red-500/10 text-red-700 dark:text-red-300"},client:{label:"Client",cls:"bg-slate-500/10 text-slate-700 dark:text-slate-300"},rate_limit:{label:"Rate limit",cls:"bg-amber-500/10 text-amber-700 dark:text-amber-300"},unknown:{label:"Unknown",cls:"bg-zinc-500/10 text-zinc-700 dark:text-zinc-300"}}[t]||{label:t,cls:"bg-zinc-500/10 text-zinc-700 dark:text-zinc-300"};return(0,n.jsx)("span",{className:O("rounded-full px-2 py-1 text-xs font-semibold",s.cls),children:s.label})}function en({row:e}){let t=e.sampleMessage||e.errorMessageShort||"";return t?(0,n.jsx)("span",{className:"block max-w-[360px] truncate text-xs text-text-muted",title:t,children:t}):(0,n.jsx)("span",{className:"text-text-muted",children:"-"})}function er({icon:e,label:t,value:s,hint:r,tone:l="slate"}){return(0,n.jsx)("div",{className:O("rounded-2xl border p-4 shadow-sm",{red:"border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-300",amber:"border-amber-500/20 bg-amber-500/10 text-amber-700 dark:text-amber-300",purple:"border-purple-500/20 bg-purple-500/10 text-purple-700 dark:text-purple-300",slate:"border-border bg-surface text-text-main",green:"border-green-500/20 bg-green-500/10 text-green-700 dark:text-green-300"}[l]||"border-border bg-surface text-text-main"),children:(0,n.jsxs)("div",{className:"flex items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"text-xs font-semibold uppercase tracking-wide opacity-75",children:t}),(0,n.jsx)("div",{className:"mt-2 text-2xl font-bold",children:S(s)}),r?(0,n.jsx)("div",{className:"mt-1 text-xs opacity-80",children:r}):null]}),(0,n.jsx)("span",{className:"material-symbols-outlined text-[24px] opacity-80",children:e})]})})}function el({anomaly:e}){let t="danger"===e.level?"border-red-500/30 bg-red-500/10 text-red-700 dark:text-red-300":"border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300",s="danger"===e.level?"error":"warning";return(0,n.jsx)("div",{className:O("rounded-2xl border p-4",t),children:(0,n.jsxs)("div",{className:"flex gap-3",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:s}),(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.title}),(0,n.jsx)("div",{className:"mt-1 text-sm opacity-90",children:e.detail})]})]})})}function ea({notes:e=[]}){return e.length?(0,n.jsx)("div",{className:"space-y-2 rounded-2xl border border-blue-500/20 bg-blue-500/10 p-4 text-sm text-blue-700 dark:text-blue-300",children:e.map((e,t)=>(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[18px]",children:"info"}),(0,n.jsx)("span",{children:e})]},t))}):null}function ei({filters:e,setFilters:t,options:s,onRefresh:r,onExportCsv:l,loading:a,showProviderFilters:i=!0}){let o=(e,s)=>t(t=>({...t,[e]:s}));return(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-2 xl:grid-cols-6",children:[(0,n.jsx)(D,{label:"Khoảng thời gian",children:(0,n.jsx)(V,{value:e.period,onChange:e=>o("period",e),children:y.map(e=>(0,n.jsx)("option",{value:e.value,children:e.label},e.value))})}),i?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(D,{label:"Provider",children:(0,n.jsxs)(V,{value:e.provider,onChange:e=>o("provider",e),children:[(0,n.jsx)("option",{value:"",children:"Tất cả provider"}),(s.providers||[]).map(e=>{let t="string"==typeof e?e:e.value,s="string"==typeof e?e:e.label||e.value;return(0,n.jsx)("option",{value:t,children:s},t)})]})}),(0,n.jsx)(D,{label:"Model",children:(0,n.jsxs)(V,{value:e.model,onChange:e=>o("model",e),children:[(0,n.jsx)("option",{value:"",children:"Tất cả model"}),(s.models||[]).map(e=>(0,n.jsx)("option",{value:e,children:e},e))]})})]}):null,(0,n.jsx)(D,{label:"Source IP",children:(0,n.jsx)(H,{value:e.clientIp,onChange:e=>o("clientIp",e),placeholder:"172.16.253.1"})}),(0,n.jsx)(D,{label:"Source tool",children:(0,n.jsx)(H,{value:e.sourceTool,onChange:e=>o("sourceTool",e),placeholder:"copilot, antigravity..."})}),(0,n.jsx)(D,{label:"Status",children:(0,n.jsxs)(V,{value:e.status,onChange:e=>o("status",e),children:[(0,n.jsx)("option",{value:"",children:"Tất cả status"}),(s.statuses||[]).map(e=>(0,n.jsx)("option",{value:e,children:e},e))]})}),(0,n.jsx)(D,{label:"Session / keyword",children:(0,n.jsx)(H,{value:e.sessionId||e.keyword,onChange:e=>o("keyword",e),placeholder:"session, prompt, error..."})})]}),(0,n.jsxs)("div",{className:"mt-4 flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Token/cost lấy từ UsageHistory. Source IP/tool/session lấy từ Prompt Logs."}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("button",{onClick:()=>t({period:"today",provider:"",model:"",status:"",clientIp:"",sourceTool:"",sessionId:"",keyword:""}),className:"rounded-xl border border-border px-3 py-2 text-sm font-medium text-text-main hover:bg-background",children:"Reset"}),(0,n.jsxs)("button",{onClick:l,className:"rounded-xl border border-border px-3 py-2 text-sm font-medium text-text-main hover:bg-background",children:[(0,n.jsx)("span",{className:"material-symbols-outlined mr-1 align-[-4px] text-[18px]",children:"download"}),"Export CSV"]}),(0,n.jsxs)("button",{onClick:()=>r?.(),disabled:a,className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white shadow-sm disabled:opacity-60",children:[(0,n.jsx)("span",{className:"material-symbols-outlined mr-1 align-[-5px] text-[18px]",children:"refresh"}),a?"Đang tải...":"Refresh"]})]})]})]})}function eo({data:e}){let t=F(),s=e.overview||{},r=e.latency||{},l=e.experience||{};return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsx)(Q,{leaderboard:e.tokenLeaderboard}),(0,n.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:[(0,n.jsx)(_,{icon:"call_made",label:"Tổng request",value:S(s.requests),hint:`${S(s.requestsPerMinute,2)} request/ph\xfat`,help:"Số request khớp bộ lọc hiện tại."}),(0,n.jsx)(_,{icon:"check_circle",label:"Th\xe0nh c\xf4ng",value:S(s.success),hint:`Tỷ lệ lỗi ${P(s.errorRate)}`,help:"Request trả về th\xe0nh c\xf4ng v\xe0 c\xf3 trạng th\xe1i OK.",tone:"green"}),(0,n.jsx)(_,{icon:"dns",label:"Lỗi server/provider",value:S(s.serverErrorEvents),hint:`Server-impacting ${P(s.serverErrorRate)} \xb7 client ${S(s.clientErrorEvents)}`,help:"Lỗi từ gateway, provider hoặc model server; t\xe1ch ri\xeang lỗi client.",tone:s.serverErrorEvents?"red":"green"}),(0,n.jsx)(_,{icon:"speed",label:"Trải nghiệm",value:I(l.score),hint:`${l.label||"-"} \xb7 ${S(l.samples)} mẫu`,help:"Điểm 0-100. Trừ tối đa 45 cho tốc độ (latency/TTFT/slow-rate t\xednh gộp, kh\xf4ng cộng dồn) v\xe0 40 cho lỗi server. Rate limit v\xe0 lỗi client chỉ trừ nhẹ v\xec kh\xf4ng phản \xe1nh chất lượng dịch vụ.",tone:l.tone||"purple"}),(0,n.jsx)(_,{icon:"timer",label:"Latency P95",value:M(l.p95LatencyMs||r.p95Ms),hint:`AVG ${M(l.avgLatencyMs||r.avgMs)} \xb7 P50 ${M(l.p50LatencyMs||r.p50Ms)}`,help:"95% request ho\xe0n tất nhanh hơn gi\xe1 trị n\xe0y.",tone:"purple"}),(0,n.jsx)(_,{icon:"bolt",label:"TTFT P95",value:M(l.p95TtftMs),hint:`${S(l.ttftSamples)} mẫu TTFT \xb7 chờ token đầu ti\xean`,help:"95% request nhận token đầu ti\xean nhanh hơn gi\xe1 trị n\xe0y. Mẫu TTFT = request th\xe0nh c\xf4ng c\xf3 token v\xe0 c\xf3 ttftMs > 0; rộng hơn mẫu decode của card Output speed.",tone:l.slowTtftRate>=.2?"amber":"blue"}),(0,n.jsx)(_,{icon:"input",label:"Input P95",value:q(l.p95PromptTokens||0),hint:`Avg ${q(l.avgPromptTokens||s.avgPromptTokens)} \xb7 >=30k ${P(l.longInputRate)}`,help:"95% request c\xf3 k\xedch thước input nhỏ hơn gi\xe1 trị n\xe0y."}),(0,n.jsx)(_,{icon:"psychology_alt",label:"Auto-off thinking",value:P(e.thinkingAnalytics?.autoOffRate),hint:`${S(e.thinkingAnalytics?.autoOffRequests||0)} request bị tắt theo policy`,help:"Tỷ lệ request bị tắt thinking do vượt ngưỡng hoặc policy.",tone:(e.thinkingAnalytics?.autoOffRate||0)>=.3?"amber":"slate"}),(0,n.jsx)(_,{icon:"data_object",label:"Large context >=50k",value:P(e.largeContextAnalytics?.gte50kRate),hint:`>=100k ${P(e.largeContextAnalytics?.gte100kRate)}`,help:"Tỷ lệ request c\xf3 context rất lớn, dễ l\xe0m tăng TTFT/latency.",tone:(e.largeContextAnalytics?.gte50kRate||0)>=.3?"amber":"slate"}),(0,n.jsx)(_,{icon:"person_alert",label:"Top user nặng",value:s.topHeavyUser||"-",hint:`Chiếm ${P(s.topHeavyUserTokenShare)} tổng token`,help:"User/API key ti\xeau thụ nhiều token nhất trong bộ lọc.",tone:s.topHeavyUserTokenShare>=.35?"amber":"slate"}),(0,n.jsx)(_,{icon:"running_with_errors",label:"Request chậm",value:P(l.slowRequestRate),hint:`>= ${M(l.thresholds?.slowLatencyMs||45e3)} \xb7 max ${M(l.maxLatencyMs)}`,help:"Tỷ lệ request vượt ngưỡng chậm đ\xe3 cấu h\xecnh.",tone:l.slowRequestRate>=.2?"amber":"green"}),(0,n.jsx)(_,{icon:"output",label:"Output tokens",value:q(s.completionTokens),hint:`Avg ${S(s.avgCompletionTokens,1)} / request`,help:"Tổng token model sinh ra."}),(0,n.jsx)(_,{icon:"token",label:"Tổng tokens",value:q(s.totalTokens),hint:`${q(s.tokensPerMinute)} token/ph\xfat`,help:"Tổng input + output token.",tone:"amber"}),(0,n.jsx)(_,{icon:"speed",label:"Output speed",value:R(l.decodeTokensPerSecond," tok/s"),hint:`${S(l.decodeSamples)} mẫu decode \xb7 Latency/10k input ${M(l.latencyMsPer10kInputTokens)}`,help:"Tốc độ sinh token sau khi model bắt đầu trả lời: Σ output token / Σ(latency − TTFT). Mẫu decode chỉ gồm request th\xe0nh c\xf4ng, c\xf3 TTFT thật v\xe0 c\xf3 output token, n\xean \xedt hơn cả tổng request lẫn số mẫu TTFT d\xf9ng cho card TTFT P95.",tone:"slate"}),(0,n.jsx)(_,{icon:"payments",label:"Cost ước t\xednh",value:L(s.cost),hint:"Dựa tr\xean pricing đ\xe3 cấu h\xecnh",help:"Chi ph\xed suy ra từ token usage v\xe0 bảng gi\xe1 hiện tại.",tone:"green"})]}),(0,n.jsxs)("div",{className:"grid min-w-0 gap-5 xl:grid-cols-[2fr_1fr]",children:[(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Tần suất request & token theo thời gian"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Cột xanh l\xe0 token, cột v\xe0ng l\xe0 số request trong từng bucket thời gian."})]}),(0,n.jsx)(W,{})]}),(0,n.jsx)(z,{data:e.timeSeries||[]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"T\xf3m tắt active"}),(0,n.jsx)("div",{className:"mt-4 space-y-3",children:[["API key đang d\xf9ng",s.activeApiKeys],["Provider active",s.activeProviders],["Model active",s.activeModels],["Endpoint active",s.activeEndpoints],["Cached tokens",s.cachedTokens],["Reasoning tokens",s.reasoningTokens],["Latency AVG",M(l.avgLatencyMs||r.avgMs)],["Latency P50",M(l.p50LatencyMs||r.p50Ms)],["Latency P99",M(l.p99LatencyMs||r.p99Ms)],["TTFT P95",M(l.p95TtftMs)],["Input P95",q(l.p95PromptTokens||0)],["Long input >=30k",P(l.longInputRate)]].map(([e,t])=>(0,n.jsxs)("div",{className:"flex items-center justify-between rounded-xl bg-background px-3 py-2",children:[(0,n.jsx)("span",{className:"text-sm text-text-muted",children:e}),(0,n.jsx)("span",{className:"font-semibold text-text-main",children:"number"==typeof t?S(t):t})]},e))})]})]}),(0,n.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Top API key d\xf9ng nhiều token"}),(0,n.jsx)(X,{rows:(e.clientRequests?.topApiKeysByTokens||e.groups?.apiKeys||[]).slice(0,8),columns:[{key:"name",label:"API key",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.name||e.label}),(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:[t?e.fingerprint||e.apiKeyFingerprint:"",e.ownerUser||e.apiKeyOwner?`${t&&(e.fingerprint||e.apiKeyFingerprint)?" \xb7 ":""}${e.ownerUser||e.apiKeyOwner}`:""]})]})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"input",label:"P95/Max input",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:q(e.p95PromptTokens||0)}),(0,n.jsxs)("div",{className:"text-text-muted",children:["max ",q(e.maxPromptTokens||0)]})]})}]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Top Source IP d\xf9ng nhiều token"}),(0,n.jsx)(X,{rows:(e.clientRequests?.topSourceIpsByTokens||[]).slice(0,8),columns:[{key:"label",label:"Source IP",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"heavy",label:"Nặng",render:e=>(0,n.jsxs)("span",{className:"text-xs text-text-muted",children:[S(e.heavyRequests||0)," req"]})}],empty:"Kh\xf4ng c\xf3 Source IP c\xf3 token trong khoảng lọc."})]})]})]})}function ed({data:e}){let t=F(),s=e.clientRequests||{},r=s.summary||{},l=s.topHeavyUsers||[],a=s.topProblemClients||[],i=s.topApiKeysByTokens||[],o=s.topSourceIpsByTokens||[];s.topSourceIpsByHeavyRequests;let d=s.inputBuckets||[],c=e=>(0,n.jsxs)("div",{className:"min-w-[220px]",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:e.label}),(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:e.ownerUser?`Owner ${e.ownerUser}`:e.apiKeyName||"Kh\xf4ng c\xf3 owner"}),(0,n.jsx)("div",{className:"font-mono text-[11px] text-text-muted",children:t?e.apiKeyFingerprint||e.primaryClientIp||e.key:e.primaryClientIp||""})]}),x=e=>(0,n.jsxs)("div",{className:"space-y-1 text-xs",children:[(0,n.jsxs)("div",{children:["Nặng ",S(e.heavyRequests)," \xb7 ",P(e.heavyRequestRate)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["P95 input ",q(e.p95PromptTokens)," \xb7 Max ",q(e.maxPromptTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:[">=70k ",S(e.extremeInputRequests)," \xb7 ",P(e.extremeInputRate)]})]});return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:[(0,n.jsx)(_,{icon:"person_alert",label:"Top user nặng nhất",value:r.topUserLabel||"-",hint:`${q(r.topUserTokens)} token \xb7 ${P(r.topUserTokenShare)} tổng token`,tone:r.topUserTokenShare>=.35?"amber":"slate"}),(0,n.jsx)(_,{icon:"vpn_key",label:"Top API key nhiều token",value:r.topApiKeyLabel||"-",hint:`${q(r.topApiKeyTokens)} token \xb7 ${P(r.topApiKeyTokenShare)} tổng token`,tone:r.topApiKeyTokenShare>=.35?"amber":"blue"}),(0,n.jsx)(_,{icon:"lan",label:"Top IP nhiều token",value:r.topSourceIpLabel||"-",hint:`${q(r.topSourceIpTokens)} token \xb7 ${P(r.topSourceIpTokenShare)} tổng token`,tone:r.topSourceIpTokenShare>=.35?"amber":"purple"}),(0,n.jsx)(_,{icon:"input",label:"Input d\xe0i >=30k",value:P(r.longInputBucketShare||0),hint:`>=70k ${P(r.extremeInputShare||0)}`,tone:(r.extremeInputShare||0)>=.1?"amber":"green"}),(0,n.jsx)(_,{icon:"groups",label:"User/API key được theo d\xf5i",value:S(r.trackedUsers||0),hint:"Theo owner/API key fingerprint/source IP",tone:"blue"}),(0,n.jsx)(_,{icon:"network_check",label:"Top IP request nặng",value:r.topSourceIpHeavyLabel||"-",hint:`${S(r.topSourceIpHeavyRequests||0)} request >=30k input/total`,tone:r.topSourceIpHeavyRequests?"amber":"slate"}),(0,n.jsx)(_,{icon:"report",label:"Client lỗi nhiều",value:S(r.problemClients||0),hint:"Nh\xf3m user/API key c\xf3 error rows",tone:r.problemClients?"amber":"green"})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Top user/API key gửi request nặng nhất"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Xếp theo tổng input/output token của request th\xe0nh c\xf4ng c\xf3 token. D\xf9ng để ph\xe1t hiện user VS Code/agent đang tạo tải long-context lớn."})]}),(0,n.jsx)("span",{className:"rounded-full bg-primary/10 px-3 py-1 text-xs font-semibold text-primary",children:"Kh\xf4ng hiển thị full bearer token"})]}),(0,n.jsx)(X,{rows:l,columns:[{key:"user",label:"User/API key",render:c},{key:"quality",label:"\xc1p lực",render:e=>(0,n.jsx)(et,{level:e.level,label:e.pressureLabel})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"input",label:"Input pressure",render:e=>(0,n.jsxs)("div",{className:"space-y-1 text-xs",children:[(0,n.jsxs)("div",{children:["Avg ",q(e.avgPromptTokens)," \xb7 P95 ",q(e.p95PromptTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["Max ",q(e.maxPromptTokens)," \xb7 >=30k ",P(e.longInputRate)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:[">=50k ",P(e.hugeInputRate)," \xb7 >=70k ",P(e.extremeInputRate)]})]})},{key:"latency",label:"Latency / TTFT",render:e=>(0,n.jsxs)("div",{className:"space-y-1 text-xs",children:[(0,n.jsxs)("div",{children:["P95 ",M(e.p95LatencyMs)," \xb7 Max ",M(e.maxLatencyMs)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["TTFT P95 ",M(e.p95TtftMs)," \xb7 Slow ",P(e.slowRequestRate)]})]})},{key:"topModels",label:"Top model",render:e=>(0,n.jsx)(J,{items:e.topModels})},{key:"topIps",label:"IP / Tool",render:e=>(0,n.jsxs)("div",{className:"space-y-1",children:[(0,n.jsx)(J,{items:e.topIps}),(0,n.jsx)(J,{items:e.topTools})]})},{key:"meta",label:"Meta",render:e=>(0,n.jsxs)("div",{className:"space-y-1 text-xs text-text-muted",children:[(0,n.jsxs)("div",{children:["Key ",S(e.apiKeyCount)," \xb7 IP ",S(e.sourceIpCount)," \xb7 Tool ",S(e.sourceToolCount)]}),(0,n.jsxs)("div",{children:["Session ",S(e.sessionCount)," \xb7 Last ",A(e.lastSeen)]})]})}],empty:"Kh\xf4ng c\xf3 request th\xe0nh c\xf4ng c\xf3 token trong khoảng lọc."})]}),(0,n.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Top API key d\xf9ng nhiều token nhất"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Xếp theo tổng input + output token từ UsageHistory, kh\xf4ng lộ full bearer token."})]}),(0,n.jsx)(X,{rows:i,columns:[{key:"apiKey",label:"API key",render:e=>(0,n.jsxs)("div",{className:"min-w-[220px]",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:e.label}),(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:e.apiKeyOwner?`Owner ${e.apiKeyOwner}`:e.apiKeyName||e.primarySourceTool||"-"}),(0,n.jsx)("div",{className:"font-mono text-[11px] text-text-muted",children:t?e.apiKeyFingerprint||e.primaryClientIp||e.key:e.primaryClientIp||""})]})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"input",label:"Input nặng",render:x},{key:"meta",label:"Nguồn",render:e=>(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:[(0,n.jsxs)("div",{children:["IP ",S(e.sourceIpCount)," \xb7 Tool ",S(e.sourceToolCount)]}),(0,n.jsxs)("div",{children:["Model ",S(e.modelCount)," \xb7 Provider ",S(e.providerCount)]})]})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}],empty:"Kh\xf4ng c\xf3 API key c\xf3 token trong khoảng lọc."})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Top Source IP d\xf9ng nhiều token nhất"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Dựa tr\xean UsageHistory n\xean c\xf3 input/output token, kh\xe1c với bảng Source IP từ Prompt Logs chỉ đếm log."})]}),(0,n.jsx)(X,{rows:o,columns:[{key:"ip",label:"Source IP",render:e=>(0,n.jsxs)("div",{className:"min-w-[180px]",children:[(0,n.jsx)("div",{className:"font-mono text-sm font-semibold text-text-main",children:e.label}),(0,n.jsxs)("div",{className:"mt-1 text-xs text-text-muted",children:["Tool ",S(e.sourceToolCount)," \xb7 API key ",S(e.apiKeyCount)]}),(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:["Model ",S(e.modelCount)," \xb7 Provider ",S(e.providerCount)]})]})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"input",label:"Input nặng",render:x},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}],empty:"Kh\xf4ng c\xf3 Source IP c\xf3 token trong khoảng lọc."})]})]}),(0,n.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Ph\xe2n bố request theo k\xedch thước input"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Gi\xfap admin biết workload đang l\xe0 chat ngắn hay long-context VS Code/agent."})]}),(0,n.jsx)(X,{rows:d,columns:[{key:"label",label:"Input bucket",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"share",label:"Tỷ trọng",render:e=>P(e.share)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"latency",label:"Latency P95/MAX",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsxs)("div",{children:[M(e.p95LatencyMs)," / ",M(e.maxLatencyMs)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["TTFT P95 ",M(e.p95TtftMs)]})]})}],empty:"Kh\xf4ng c\xf3 dữ liệu bucket input."})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Client/API key lỗi nhiều"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"D\xf9ng để ph\xe1t hiện sai endpoint/model/auth/policy hoặc client tool cấu h\xecnh sai."})]}),(0,n.jsx)(X,{rows:a,columns:[{key:"user",label:"Client",render:c},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"errors",label:"Lỗi",render:e=>S(e.errors)},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"source",label:"IP/Tool",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{className:"font-mono",children:e.primaryClientIp||"-"}),(0,n.jsx)("div",{className:"text-text-muted",children:e.primarySourceTool||"-"})]})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}],empty:"Kh\xf4ng c\xf3 client lỗi theo bộ lọc hiện tại."})]})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"G\xf3c nh\xecn monitor client n\xean d\xf9ng"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"C\xe1c chỉ số n\xe0y bổ sung cho latency/model để admin ph\xe2n biệt server chậm hay client gửi request qu\xe1 nặng."})]}),(0,n.jsx)("div",{className:"grid gap-3 text-sm md:grid-cols-2 xl:grid-cols-3",children:[["Token/user","X\xe1c định user/API key tạo tải lớn nhất, hữu \xedch cho quota v\xe0 hướng dẫn workflow VS Code."],["Input bucket","Nếu phần lớn request nằm ở 30k-70k+, P95/P99 cao chủ yếu do prompt eval/context d\xe0i."],["TTFT theo user","TTFT cao cho một user thường l\xe0 input d\xe0i hoặc chờ slot, kh\xf4ng nhất thiết provider lỗi."],["Error theo client","T\xe1ch lỗi sai endpoint/model/API key khỏi lỗi server/provider để kh\xf4ng cảnh b\xe1o nhầm."],["Source IP/tool","Ph\xe1t hiện m\xe1y/tool gửi request nhiều hoặc cấu h\xecnh sai."],["Top request nặng","D\xf9ng Raw usage để drill-down request cụ thể khi một user k\xe9o tải hệ thống."]].map(([e,t])=>(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-background p-3",children:[(0,n.jsx)("div",{className:"font-semibold text-text-main",children:e}),(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:t})]},e))})]})]})}function ec({data:e}){let t=F();return(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Thống k\xea theo API key"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Kh\xf4ng hiển thị full bearer token. Dashboard chỉ d\xf9ng fingerprint/masked key."})]}),(0,n.jsx)(X,{rows:e.groups?.apiKeys||[],columns:[{key:"name",label:"API key",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.name}),(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:[t?e.fingerprint:"",e.ownerUser?`${t&&e.fingerprint?" \xb7 ":""}Owner: ${e.ownerUser}`:""]})]})},{key:"requests",label:"Requests",render:e=>S(e.requests)},{key:"success",label:"OK/Lỗi",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsxs)("div",{className:"text-green-600",children:["OK ",S(e.success)]}),(0,n.jsxs)("div",{className:"text-red-600",children:["Lỗi ",S(e.errors)]})]})},{key:"tokens",label:"In/Out token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"cost",label:"Cost",render:e=>L(e.cost)},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})},{key:"topModels",label:"Top model",render:e=>(0,n.jsx)(J,{items:e.topModels})},{key:"topProviders",label:"Top provider",render:e=>(0,n.jsx)(J,{items:e.topProviders})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]})}function ex({data:e}){let t=e.clientRequests?.topSourceIpsByTokens||[],s=e.clientRequests?.topSourceIpsByHeavyRequests||[],r=e=>(0,n.jsxs)("div",{className:"min-w-[180px]",children:[(0,n.jsx)("div",{className:"font-mono text-sm font-semibold text-text-main",children:e.label}),(0,n.jsxs)("div",{className:"mt-1 text-xs text-text-muted",children:["API key ",S(e.apiKeyCount)," \xb7 Tool ",S(e.sourceToolCount)]}),(0,n.jsxs)("div",{className:"text-xs text-text-muted",children:["Model ",S(e.modelCount)," \xb7 Provider ",S(e.providerCount)]})]});return(0,n.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Top IP d\xf9ng nhiều token nhất"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Aggregate từ UsageHistory, xếp theo tổng input + output token."})]}),(0,n.jsx)(X,{rows:t,columns:[{key:"ip",label:"Source IP",render:r},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}],empty:"Kh\xf4ng c\xf3 Source IP c\xf3 token trong khoảng lọc."})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Top IP gửi request nặng nhất"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Xếp theo số request input/total token từ 30k trở l\xean, sau đ\xf3 theo max/P95 input."})]}),(0,n.jsx)(X,{rows:s,columns:[{key:"ip",label:"Source IP",render:r},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"heavy",label:"Request nặng",render:e=>(0,n.jsxs)("div",{className:"space-y-1 text-xs",children:[(0,n.jsxs)("div",{children:["Nặng ",S(e.heavyRequests)," \xb7 ",P(e.heavyRequestRate)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["P95 input ",q(e.p95PromptTokens)," \xb7 Max ",q(e.maxPromptTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:[">=70k ",S(e.extremeInputRequests)," \xb7 ",P(e.extremeInputRate)]})]})},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}],empty:"Kh\xf4ng c\xf3 Source IP gửi request nặng trong khoảng lọc."})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Source IP từ Prompt Logs"}),(0,n.jsx)(X,{rows:e.promptLogs?.topClientIps||[],columns:[{key:"label",label:"IP",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Logs",render:e=>S(e.requests)},{key:"errors",label:"Lỗi",render:e=>S(e.errors)},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})},{key:"topTools",label:"Tools",render:e=>(0,n.jsx)(J,{items:e.topTools})},{key:"topModels",label:"Models",render:e=>(0,n.jsx)(J,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Source tool"}),(0,n.jsx)(X,{rows:e.promptLogs?.topSourceTools||[],columns:[{key:"label",label:"Tool",render:e=>(0,n.jsx)("span",{className:"font-semibold",children:e.label})},{key:"requests",label:"Logs",render:e=>S(e.requests)},{key:"errors",label:"Lỗi",render:e=>S(e.errors)},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})},{key:"topIps",label:"Top IP",render:e=>(0,n.jsx)(J,{items:e.topIps})},{key:"topModels",label:"Top model",render:e=>(0,n.jsx)(J,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]}),(0,n.jsxs)(U,{className:"xl:col-span-2",children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Session nhiều hoạt động"}),(0,n.jsx)(X,{rows:e.promptLogs?.topSessions||[],columns:[{key:"label",label:"Session",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Logs",render:e=>S(e.requests)},{key:"errors",label:"Lỗi",render:e=>S(e.errors)},{key:"topIps",label:"IP",render:e=>(0,n.jsx)(J,{items:e.topIps})},{key:"topTools",label:"Tool",render:e=>(0,n.jsx)(J,{items:e.topTools})},{key:"topModels",label:"Model",render:e=>(0,n.jsx)(J,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]})]})}function em({data:e}){return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Provider"}),(0,n.jsx)(X,{rows:e.groups?.providers||[],columns:[{key:"label",label:"Provider",render:e=>(0,n.jsx)("span",{className:"font-semibold",children:e.label})},{key:"requests",label:"Requests",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"cost",label:"Cost",render:e=>L(e.cost)},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})},{key:"topModels",label:"Top model",render:e=>(0,n.jsx)(J,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]}),(0,n.jsx)(g,{data:e}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Provider account / connection"}),(0,n.jsx)(X,{rows:e.groups?.providerAccounts||[],columns:[{key:"label",label:"Account",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.label}),(0,n.jsx)("div",{className:"text-xs text-text-muted",children:e.providerLabel||e.provider||e.connectionId})]})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"errorRate",label:"Lỗi",render:e=>(0,n.jsx)(Y,{value:e.errorRate})}]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Endpoint"}),(0,n.jsx)(X,{rows:e.groups?.endpoints||[],columns:[{key:"label",label:"Endpoint",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Requests",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"cost",label:"Cost",render:e=>L(e.cost)},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]})]})}function eu({data:e}){let t=F(),s=e.experience||{},r=s.thresholds||{},l=e.thinkingAnalytics||{},a=e.largeContextAnalytics||{},i=s.byModel||[],o=s.slowestRequests||[];return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:[(0,n.jsx)(_,{icon:"verified",label:"Đ\xe1nh gi\xe1 tổng",value:I(s.score),hint:`${s.label||"-"} \xb7 ${S(s.samples)} mẫu success c\xf3 token`,help:"Điểm 0-100 từ request th\xe0nh c\xf4ng c\xf3 token. Tốc độ trừ tối đa 45 (chuẩn ho\xe1 theo k\xedch thước input khi prompt lớn), lỗi server trừ tối đa 40. Rate limit trừ nhẹ v\xec đ\xf3 l\xe0 hệ thống tự bảo vệ.",tone:s.tone||"slate"}),(0,n.jsx)(_,{icon:"timer",label:"Latency AVG / P95",value:`${M(s.avgLatencyMs)} / ${M(s.p95LatencyMs)}`,hint:`P50 ${M(s.p50LatencyMs)} \xb7 P99 ${M(s.p99LatencyMs)}`,help:"AVG l\xe0 trung b\xecnh; P95 thể hiện nh\xf3m 5% request chậm nhất.",tone:"purple"}),(0,n.jsx)(_,{icon:"bolt",label:"TTFT AVG / P95",value:`${M(s.avgTtftMs)} / ${M(s.p95TtftMs)}`,hint:`${S(s.ttftSamples)} mẫu TTFT \xb7 queue/prompt eval/input d\xe0i`,help:"Thời gian từ l\xfac gửi request đến token đầu ti\xean. Mẫu TTFT rộng hơn mẫu decode v\xec kh\xf4ng đ\xf2i hỏi c\xf3 output token.",tone:s.slowTtftRate>=.2?"amber":"blue"}),(0,n.jsx)(_,{icon:"keyboard_double_arrow_up",label:"Input AVG / P95",value:`${q(s.avgPromptTokens)} / ${q(s.p95PromptTokens)}`,hint:`>=30k ${P(s.longInputRate)} \xb7 >=50k ${P(s.hugeInputRate)}`,help:"Input c\xe0ng lớn th\xec prompt eval v\xe0 TTFT thường c\xe0ng cao."}),(0,n.jsx)(_,{icon:"running_with_errors",label:"Slow request",value:P(s.slowRequestRate),hint:`Latency >= ${M(r.slowLatencyMs||45e3)} \xb7 rất chậm ${P(s.verySlowRequestRate)}`,help:"Tỷ lệ request ho\xe0n tất chậm hơn ngưỡng vận h\xe0nh.",tone:s.slowRequestRate>=.2?"amber":"green"}),(0,n.jsx)(_,{icon:"pending_actions",label:"Slow TTFT",value:P(s.slowTtftRate),hint:`TTFT >= ${M(r.slowTtftMs||2e4)}`,help:"Tỷ lệ request chờ token đầu ti\xean qu\xe1 l\xe2u.",tone:s.slowTtftRate>=.2?"amber":"green"}),(0,n.jsx)(_,{icon:"speed",label:"Decode tốc độ",value:R(s.decodeTokensPerSecond," tok/s"),hint:`${S(s.decodeSamples)} mẫu decode \xb7 E2E ${R(s.e2eOutputTokensPerSecond," tok/s")}`,help:"Σ output token / Σ(latency − TTFT), chỉ t\xednh request th\xe0nh c\xf4ng c\xf3 TTFT thật v\xe0 c\xf3 output token. Tập mẫu n\xe0y nhỏ hơn tập mẫu TTFT d\xf9ng cho TTFT AVG/P95. E2E l\xe0 output/tổng latency (gồm cả prefill).",tone:"slate"}),(0,n.jsx)(_,{icon:"data_usage",label:"Latency / 10k input",value:M(s.latencyMsPer10kInputTokens),hint:"Hữu \xedch khi VS Code gửi 30k–70k token",help:"Σ latency E2E / (Σ input token / 10k). L\xe0 latency to\xe0n bộ request được chuẩn h\xf3a theo input, n\xean vẫn phụ thuộc độ d\xe0i output — kh\xf4ng phải tốc độ prefill.",tone:"slate"}),(0,n.jsx)(_,{icon:"psychology_alt",label:"Thinking auto-off",value:P(l.autoOffRate),hint:`${S(l.autoOffRequests||0)} / ${S(l.totalRequests||0)} request`,help:"Request bị tắt thinking tự động do vượt ngưỡng prompt chars.",tone:(l.autoOffRate||0)>=.3?"amber":"green"}),(0,n.jsx)(_,{icon:"toggle_off",label:"Thinking OFF",value:P(l.thinkingOffRate),hint:`ON ${P(l.thinkingOnRate)} \xb7 unknown ${P(l.unknownRate)}`,help:"Tỷ lệ request cuối c\xf9ng chạy ở chế độ kh\xf4ng thinking.",tone:(l.thinkingOffRate||0)>=.5?"blue":"slate"}),(0,n.jsx)(_,{icon:"data_object",label:"Large context",value:P(a.gte50kRate),hint:`>=30k ${P(a.gte30kRate)} \xb7 >=100k ${P(a.gte100kRate)}`,help:"Tỷ lệ request c\xf3 context lớn; thường l\xe0 nguy\xean nh\xe2n l\xe0m P95/P99 tăng.",tone:(a.gte50kRate||0)>=.3?"amber":"slate"})]}),(0,n.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Thinking Analytics"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Theo d\xf5i request bật/tắt thinking v\xe0 tỷ lệ auto-off do vượt ngưỡng prompt chars."})]}),(0,n.jsx)("div",{className:"grid gap-3 md:grid-cols-2",children:[["Thinking ON",S(l.thinkingOnRequests||0),P(l.thinkingOnRate)],["Thinking OFF",S(l.thinkingOffRequests||0),P(l.thinkingOffRate)],["Auto-off hit",S(l.autoOffRequests||0),P(l.autoOffRate)],["C\xf3 ngưỡng auto-off",S(l.thresholdConfiguredRequests||0),`hit ${P(l.autoOffEligibleHitRate)}`]].map(([e,t,s])=>(0,n.jsxs)("div",{className:"rounded-2xl bg-background p-4",children:[(0,n.jsx)("div",{className:"text-xs font-semibold uppercase tracking-wide text-text-muted",children:e}),(0,n.jsx)("div",{className:"mt-2 text-xl font-semibold text-text-main",children:t}),(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:s})]},e))}),(0,n.jsx)("div",{className:"mt-4",children:(0,n.jsx)(X,{rows:l.byModel||[],empty:"Chưa c\xf3 dữ liệu thinking trong khoảng lọc.",columns:[{key:"model",label:"Model",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.model}),(0,n.jsx)("div",{className:"text-xs text-text-muted",children:e.provider})]})},{key:"requests",label:"Req",render:e=>S(e.requests)},{key:"autoOff",label:"Auto-off",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:S(e.autoOffRequests)}),(0,n.jsx)("div",{className:"text-text-muted",children:P(e.autoOffRate)})]})},{key:"thinking",label:"ON/OFF",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsxs)("div",{children:["ON ",S(e.thinkingOnRequests)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["OFF ",S(e.thinkingOffRequests)]})]})},{key:"chars",label:"Chars avg/max",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:q(e.avgPromptChars)}),(0,n.jsxs)("div",{className:"text-text-muted",children:["max ",q(e.maxPromptChars)]})]})}]})})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Large Context Analytics"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Bucket theo request size, ưu ti\xean prompt chars; nếu chưa c\xf3 chars th\xec fallback prompt tokens."})]}),(0,n.jsx)("div",{className:"grid gap-3 md:grid-cols-3",children:[[">=30k",a.gte30kRequests,a.gte30kRate],[">=50k",a.gte50kRequests,a.gte50kRate],[">=100k",a.gte100kRequests,a.gte100kRate]].map(([e,t,s])=>(0,n.jsxs)("div",{className:"rounded-2xl bg-background p-4",children:[(0,n.jsx)("div",{className:"text-xs font-semibold uppercase tracking-wide text-text-muted",children:e}),(0,n.jsx)("div",{className:"mt-2 text-xl font-semibold text-text-main",children:S(t||0)}),(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:P(s)})]},e))}),(0,n.jsx)("div",{className:"mt-4",children:(0,n.jsx)(X,{rows:a.buckets||[],empty:"Chưa c\xf3 large context buckets trong khoảng lọc.",columns:[{key:"label",label:"Bucket",render:e=>(0,n.jsx)("span",{className:"font-semibold",children:e.label})},{key:"requests",label:"Req",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:S(e.requests)}),(0,n.jsx)("div",{className:"text-text-muted",children:P(e.share)})]})},{key:"chars",label:"Size avg/max",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:q(e.avgRequestSize)}),(0,n.jsxs)("div",{className:"text-text-muted",children:["max ",q(e.maxRequestSize)]})]})},{key:"latency",label:"Latency/TTFT",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:M(e.avgLatencyMs)}),(0,n.jsxs)("div",{className:"text-text-muted",children:["TTFT ",M(e.avgTtftMs)]})]})},{key:"autoOff",label:"Auto-off",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:S(e.autoOffRequests)}),(0,n.jsx)("div",{className:"text-text-muted",children:P(e.autoOffRate)})]})}]})})]})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"C\xe1ch đọc trải nghiệm user"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Nh\xf3m n\xe0y chỉ t\xednh request th\xe0nh c\xf4ng c\xf3 token v\xe0 latency > 0. Error/pending/success 0-token kh\xf4ng trộn v\xe0o tốc độ model. TTFT l\xe0 thời gian tới token đầu ti\xean; với VS Code input 30k–70k, TTFT cao thường phản \xe1nh chờ slot hoặc prompt eval d\xe0i."})]}),(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-3",children:[(0,n.jsxs)("div",{className:"rounded-2xl bg-background p-4",children:[(0,n.jsx)("div",{className:"text-xs font-semibold uppercase tracking-wide text-text-muted",children:"Nhanh/chậm thực tế"}),(0,n.jsx)("div",{className:"mt-2 text-sm text-text-main",children:"Latency AVG/P50/P95/MAX cho biết user phải chờ bao l\xe2u để request ho\xe0n tất."})]}),(0,n.jsxs)("div",{className:"rounded-2xl bg-background p-4",children:[(0,n.jsx)("div",{className:"text-xs font-semibold uppercase tracking-wide text-text-muted",children:"Queue hoặc prompt eval"}),(0,n.jsx)("div",{className:"mt-2 text-sm text-text-main",children:"TTFT cao + input P95 cao l\xe0 t\xedn hiệu request d\xe0i, hết slot hoặc upstream đang queue."})]}),(0,n.jsxs)("div",{className:"rounded-2xl bg-background p-4",children:[(0,n.jsx)("div",{className:"text-xs font-semibold uppercase tracking-wide text-text-muted",children:"VS Code / agent"}),(0,n.jsx)("div",{className:"mt-2 text-sm text-text-main",children:"Theo d\xf5i tỷ lệ input >=30k/50k/70k để biết P95/P99 cao c\xf3 phải do context cực d\xe0i hay kh\xf4ng."})]})]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Chất lượng phản hồi theo provider/model"}),(0,n.jsx)(X,{rows:i,empty:"Chưa c\xf3 mẫu latency cho model trong khoảng lọc.",columns:[{key:"model",label:"Model",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.model}),(0,n.jsx)("div",{className:"text-xs text-text-muted",children:e.providerLabel||e.provider})]})},{key:"quality",label:"Đ\xe1nh gi\xe1",render:e=>(0,n.jsxs)("div",{className:"space-y-1",children:[(0,n.jsx)(ee,{level:e.level,label:e.labelQuality}),(0,n.jsx)("div",{className:"text-xs text-text-muted",children:I(e.score)})]})},{key:"samples",label:"Mẫu",render:e=>S(e.samples)},{key:"latency",label:"Latency P50/P95/MAX",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsxs)("div",{children:[M(e.p50LatencyMs)," / ",M(e.p95LatencyMs)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:["max ",M(e.maxLatencyMs)]})]})},{key:"ttft",label:"TTFT P95",render:e=>M(e.p95TtftMs)},{key:"input",label:"Input avg/P95",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsxs)("div",{children:[q(e.avgPromptTokens)," / ",q(e.p95PromptTokens)]}),(0,n.jsxs)("div",{className:"text-text-muted",children:[">=30k ",P(e.longInputRate)]})]})},{key:"slow",label:"Chậm",render:e=>(0,n.jsx)(Y,{value:e.slowRequestRate})},{key:"speed",label:"Decode tok/s",render:e=>R(e.decodeTokensPerSecond??e.outputTokensPerSecond," tok/s")}]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Request chậm nhất"}),(0,n.jsx)(X,{rows:o,empty:"Kh\xf4ng c\xf3 request chậm trong khoảng lọc.",columns:[{key:"timestamp",label:"Time",render:e=>A(e.timestamp)},{key:"model",label:"Model",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.model}),(0,n.jsx)("div",{className:"text-xs text-text-muted",children:e.providerLabel||e.provider})]})},{key:"latency",label:"Latency / TTFT",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{className:"font-semibold",children:M(e.latencyMs)}),(0,n.jsxs)("div",{className:"text-text-muted",children:["TTFT ",M(e.ttftMs)]})]})},{key:"tokens",label:"In / Out",render:e=>(0,n.jsx)(Z,{row:e})},{key:"apiKeyName",label:"API key",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{children:e.apiKeyName}),t?(0,n.jsx)("div",{className:"font-mono text-xs text-text-muted",children:e.apiKeyFingerprint}):null]})},{key:"sourceTool",label:"Tool/IP",render:e=>(0,n.jsxs)("div",{className:"text-xs",children:[(0,n.jsx)("div",{children:e.sourceTool||"-"}),(0,n.jsx)("div",{className:"font-mono text-text-muted",children:e.clientIp||"-"})]})},{key:"endpoint",label:"Endpoint",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.endpoint||"-"})}]})]})]})}function eh({data:e}){let t=F(),s=e.requestErrors||{},r=s.summary||{},l=e.overview||{},a=Number(l.serverErrorRate||0),i=Number(l.clientErrorRate||0),o=Number(l.rateLimitErrorRate||0),d=[{key:"faultOwner",label:"Loại",render:e=>(0,n.jsx)(es,{value:e.faultOwner})},{key:"status",label:"Status",render:e=>(0,n.jsx)("span",{className:"rounded-full bg-red-500/10 px-2 py-1 text-xs font-semibold text-red-600 dark:text-red-300",children:e.status})},{key:"provider",label:"Provider",render:e=>e.providerLabel||e.provider},{key:"model",label:"Model"},{key:"endpoint",label:"Endpoint",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.endpoint})},{key:"requests",label:"Lỗi",render:e=>S(e.errors||e.requests)},{key:"errorType",label:"Type",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.errorType||e.errorCode||"-"})},{key:"sampleMessage",label:"Sample",render:e=>(0,n.jsx)(en,{row:e})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}];return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-5",children:[(0,n.jsx)(er,{icon:"dns",label:"Server/provider",value:r.serverImpacting||0,hint:`${P(a)} tr\xean tổng request`,tone:r.serverImpacting?"red":"green"}),(0,n.jsx)(er,{icon:"cloud_off",label:"Upstream",value:r.upstream||0,hint:"Provider/model server, timeout, network, 5xx",tone:r.upstream?"red":"green"}),(0,n.jsx)(er,{icon:"router",label:"Gateway",value:r.gateway||0,hint:"Lỗi nội bộ BlueRouter/gateway",tone:r.gateway?"purple":"green"}),(0,n.jsx)(er,{icon:"integration_instructions",label:"Client/request",value:r.client||0,hint:`${P(i)} do endpoint/model/body/auth`,tone:r.client?"slate":"green"}),(0,n.jsx)(er,{icon:"speed",label:"Rate/quota",value:r.rateLimit||0,hint:`${P(o)} rate-limit/quota`,tone:r.rateLimit?"amber":"green"})]}),(0,n.jsx)("div",{className:"rounded-2xl border border-blue-500/20 bg-blue-500/10 p-4 text-sm text-blue-700 dark:text-blue-300",children:(0,n.jsxs)("div",{className:"flex gap-3",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:"rule_settings"}),(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:"Ph\xe2n loại lỗi đ\xe3 t\xe1ch client khỏi server/provider"}),(0,n.jsxs)("div",{className:"mt-1 opacity-90",children:["Cảnh b\xe1o vận h\xe0nh n\xean ưu ti\xean nh\xf3m ",(0,n.jsx)("b",{children:"Server/provider"})," gồm gateway, upstream, timeout, network v\xe0 5xx. Nh\xf3m ",(0,n.jsx)("b",{children:"Client/request"})," vẫn được log đầy đủ nhưng thường l\xe0 sai endpoint, model, auth, JSON/body hoặc context."]})]})]})}),e.anomalies?.length?(0,n.jsx)("div",{className:"grid gap-4 xl:grid-cols-2",children:e.anomalies.map((e,t)=>(0,n.jsx)(el,{anomaly:e},t))}):(0,n.jsxs)("div",{className:"rounded-2xl border border-green-500/20 bg-green-500/10 p-4 text-sm text-green-700 dark:text-green-300",children:[(0,n.jsx)("span",{className:"material-symbols-outlined mr-2 align-[-5px]",children:"check_circle"}),"Chưa ph\xe1t hiện bất thường server/provider r\xf5 r\xe0ng theo bộ lọc hiện tại."]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Lỗi server/provider cần xử l\xfd"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Chỉ gồm gateway/upstream/server-impacting errors. Đ\xe2y l\xe0 bảng quan trọng nhất cho vận h\xe0nh."})]}),(0,n.jsxs)("span",{className:"rounded-full bg-red-500/10 px-3 py-1 text-xs font-semibold text-red-600 dark:text-red-300",children:[S(r.serverImpacting||0)," lỗi"]})]}),(0,n.jsx)(X,{rows:s.topServerErrors||[],columns:d,empty:"Kh\xf4ng c\xf3 lỗi server/provider trong khoảng lọc."})]}),(0,n.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Lỗi client/request sai"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Sai endpoint, model, auth, JSON/body, context length. D\xf9ng để hướng dẫn client sửa request."})]}),(0,n.jsx)(X,{rows:s.topClientErrors||[],columns:d.filter(e=>!["sampleMessage"].includes(e.key)),empty:"Kh\xf4ng c\xf3 lỗi client/request trong khoảng lọc."})]}),(0,n.jsxs)(U,{children:[(0,n.jsxs)("div",{className:"mb-4",children:[(0,n.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Ph\xe2n bố loại lỗi"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"T\xe1ch nguồn chịu tr\xe1ch nhiệm để kh\xf4ng nhầm lỗi client th\xe0nh lỗi server."})]}),(0,n.jsx)(X,{rows:s.byFaultOwner||[],columns:[{key:"faultOwner",label:"Loại",render:e=>(0,n.jsx)(es,{value:e.faultOwner||e.key})},{key:"requests",label:"Số lỗi",render:e=>S(e.requests)},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}],empty:"Kh\xf4ng c\xf3 lỗi để ph\xe2n loại."})]})]}),s.topRateLimitErrors?.length?(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Rate limit / quota"}),(0,n.jsx)(X,{rows:s.topRateLimitErrors||[],columns:d})]}):null,(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Tất cả lỗi raw theo status/provider/model/endpoint"}),(0,n.jsx)(X,{rows:[...e.groups?.errors||[]].sort((e,t)=>new Date(C(t.lastSeen)||0)-new Date(C(e.lastSeen)||0)||Number(t.errors||t.requests||0)-Number(e.errors||e.requests||0)),columns:[{key:"faultOwner",label:"Loại",render:e=>(0,n.jsx)(es,{value:e.faultOwner})},{key:"status",label:"Status",render:e=>(0,n.jsx)("span",{className:"rounded-full bg-red-500/10 px-2 py-1 text-xs font-semibold text-red-600 dark:text-red-300",children:e.status})},{key:"provider",label:"Provider",render:e=>e.providerLabel||e.provider},{key:"model",label:"Model"},{key:"endpoint",label:"Endpoint",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.endpoint})},{key:"requests",label:"Lỗi",render:e=>S(e.errors||e.requests)},{key:"apiKey",label:"API key",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:t?e.apiKey:e.apiKeyName||"•••"})},{key:"lastSeen",label:"Last seen",render:e=>A(e.lastSeen)}]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Status distribution"}),(0,n.jsx)(X,{rows:e.groups?.statuses||[],columns:[{key:"label",label:"Status"},{key:"requests",label:"Requests",render:e=>S(e.requests)},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"errorRate",label:"Error %",render:e=>(0,n.jsx)(Y,{value:e.errorRate})}]})]})]})}function ep({data:e}){let t=F();return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Top request nặng token"}),(0,n.jsx)(X,{rows:e.heavyRequests||[],columns:[{key:"timestamp",label:"Time",render:e=>A(e.timestamp)},{key:"model",label:"Model",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-semibold",children:e.model}),(0,n.jsx)("div",{className:"text-xs text-text-muted",children:e.providerLabel||e.provider})]})},{key:"apiKeyName",label:"API key",render:e=>(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{children:e.apiKeyName}),t?(0,n.jsx)("div",{className:"font-mono text-xs text-text-muted",children:e.apiKeyFingerprint}):null]})},{key:"accountName",label:"Account"},{key:"endpoint",label:"Endpoint",render:e=>(0,n.jsx)("span",{className:"font-mono text-xs",children:e.endpoint})},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"status",label:"Status"}]})]}),(0,n.jsxs)(U,{children:[(0,n.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Recent usage"}),(0,n.jsx)(X,{rows:e.recentUsage||[],columns:[{key:"timestamp",label:"Time",render:e=>A(e.timestamp)},{key:"provider",label:"Provider",render:e=>e.providerLabel||e.provider},{key:"model",label:"Model"},{key:"apiKeyName",label:"API key"},{key:"tokens",label:"Token",render:e=>(0,n.jsx)(Z,{row:e})},{key:"cost",label:"Cost",render:e=>L(e.cost)},{key:"status",label:"Status"}]})]})]})}function eb(){let{isAdmin:e,isMonitorAdmin:t,isAiGatewaysMonitor:s}=(0,a.s)(),l=e||t||s,i=(0,r.useMemo)(()=>e?j:j.filter(e=>"aiHealth"!==e.value),[e]),[o,d]=(0,r.useState)({period:"today",provider:"",model:"",status:"",clientIp:"",sourceTool:"",sessionId:"",keyword:""}),[c,x]=(0,r.useState)(null),[m,u]=(0,r.useState)(!0),[h,p]=(0,r.useState)(""),[b,g]=(0,r.useState)("overview"),[y,k]=(0,r.useState)(null),f=function(e,t=450){let[s,n]=(0,r.useState)(e);return(0,r.useEffect)(()=>{let s=setTimeout(()=>n(e),t);return()=>clearTimeout(s)},[e,t]),s}(o,450),N=(0,r.useRef)(0),T=(0,r.useCallback)(async({clear:e=!1,filtersOverride:t=null}={})=>{let s=N.current+1;N.current=s,e&&x(null),u(!0),p("");let n=Date.now();try{let e=t||f,r=E(e,{timeZone:K()}),l=await fetch(`/api/dashboard/analytics?${r}`,{cache:"no-store"}),a=await l.json().catch(()=>({}));if(s!==N.current)return;if(!l.ok)throw Error(a.error||"Kh\xf4ng tải được dữ liệu analytics");x(a),k({loadedMs:Date.now()-n,cacheState:a.cacheState||"",cacheAgeMs:a.cacheAgeMs||0})}catch(e){if(s!==N.current)return;p(e.message||"Kh\xf4ng tải được dữ liệu analytics")}finally{s===N.current&&u(!1)}},[f]);(0,r.useEffect)(()=>{T({clear:!0})},[T]),(0,r.useEffect)(()=>{let e=localStorage.getItem(v);e&&i.some(t=>t.value===e)&&g(e)},[i]),(0,r.useEffect)(()=>{i.some(e=>e.value===b)||g("overview")},[i,b]),(0,r.useEffect)(()=>{localStorage.setItem(v,b)},[b]);let S=c?.options||{},q=(0,r.useMemo)(()=>c?.generatedAt?A(c.generatedAt):"-",[c]);return(0,n.jsxs)("div",{className:"space-y-5 p-4 md:p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-primary",children:[(0,n.jsx)("span",{className:"material-symbols-outlined",children:"monitoring"}),(0,n.jsx)("span",{className:"text-sm font-semibold uppercase tracking-wide",children:"BlueRouter Analytics"})]}),(0,n.jsx)("h1",{className:"mt-2 text-2xl font-bold text-text-main",children:"Thống k\xea sử dụng Gateway"}),(0,n.jsx)("p",{className:"mt-1 max-w-3xl text-sm text-text-muted",children:"Theo d\xf5i tần suất request, input/output token, API key, provider, model, endpoint, Source IP, source tool v\xe0 lỗi vận h\xe0nh."})]}),(0,n.jsxs)("div",{className:"flex items-center gap-3 rounded-2xl border border-border bg-surface px-4 py-3 text-sm text-text-muted",children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[20px]",children:"schedule"}),(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:["Generated: ",q]}),y?(0,n.jsxs)("div",{className:"mt-0.5 text-xs",children:["Loaded in ",y.loadedMs>=1e3?`${(y.loadedMs/1e3).toLocaleString("vi-VN",{maximumFractionDigits:1})}s`:`${y.loadedMs}ms`,"hit"===y.cacheState?(0,n.jsxs)("span",{className:"ml-1.5 rounded bg-emerald-500/10 px-1.5 py-0.5 font-medium text-emerald-500",children:["cache hit",y.cacheAgeMs?` \xb7 ${Math.round(y.cacheAgeMs/1e3)}s`:""]}):"joined"===y.cacheState?(0,n.jsx)("span",{className:"ml-1.5 rounded bg-sky-500/10 px-1.5 py-0.5 font-medium text-sky-500",children:"shared compute"}):"fresh"===y.cacheState?(0,n.jsx)("span",{className:"ml-1.5 rounded bg-amber-500/10 px-1.5 py-0.5 font-medium text-amber-500",children:"fresh compute"}):null]}):null]})]})]}),(0,n.jsx)(ei,{filters:o,setFilters:d,options:S,onRefresh:e=>T({filtersOverride:e||o}),onExportCsv:()=>{let e=E(o,{format:"csv",timeZone:K()});window.open(`/api/dashboard/analytics?${e}`,"_blank","noopener,noreferrer")},loading:m,showProviderFilters:l}),h?(0,n.jsxs)("div",{className:"rounded-2xl border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-700 dark:text-red-300",children:[(0,n.jsx)("span",{className:"material-symbols-outlined mr-2 align-[-5px]",children:"error"}),h]}):null,c?.qualityNotes?.length?(0,n.jsx)(ea,{notes:c.qualityNotes}):null,(0,n.jsx)("div",{className:"flex flex-wrap gap-2 rounded-2xl border border-border bg-surface p-2",children:i.map(e=>(0,n.jsxs)("button",{onClick:()=>g(e.value),className:O("flex items-center gap-2 rounded-xl px-3 py-2 text-sm font-medium transition",b===e.value?"bg-primary text-white shadow-sm":"text-text-muted hover:bg-background hover:text-text-main"),children:[(0,n.jsx)("span",{className:"material-symbols-outlined text-[18px]",children:e.icon}),e.label]},e.value))}),m&&!c?(0,n.jsx)(B,{}):null,!m&&c&&c.overview?.requests===0&&0===(c.promptLogs?.total||0)?(0,n.jsx)(G,{title:"Chưa c\xf3 dữ liệu analytics",description:"Kh\xf4ng c\xf3 UsageHistory hoặc Prompt Logs theo bộ lọc hiện tại."}):null,c?(0,n.jsxs)(n.Fragment,{children:["overview"===b?(0,n.jsx)(eo,{data:c}):null,"apiKeys"===b?(0,n.jsx)(ec,{data:c}):null,"clients"===b?(0,n.jsx)(ed,{data:c}):null,"sources"===b?(0,n.jsx)(ex,{data:c}):null,"providers"===b?(0,n.jsx)(em,{data:c}):null,"experience"===b?(0,n.jsx)(eu,{data:c}):null,"errors"===b?(0,n.jsx)(eh,{data:c}):null,"raw"===b?(0,n.jsx)(ep,{data:c}):null]}):null,"aiHealth"===b&&e?(0,n.jsx)(w,{}):null]})}},85881:(e,t,s)=>{"use strict";s.d(t,{default:()=>a});var n=s(12115);let r="blueRouterAnalyticsTab";function l(e){return Array.from(document.querySelectorAll("button")).find(t=>Array.from(t.childNodes).filter(e=>3===e.nodeType).map(e=>e.textContent?.trim()||"").filter(Boolean).join(" ")===e)||null}function a(){return(0,n.useLayoutEffect)(()=>{let e=!1,t=()=>{e||(e=!0,requestAnimationFrame(()=>{let t,s;e=!1,t=document.getElementById("analytics-vllm-config"),(s=t?.closest(".space-y-2"))&&(s.style.display="none",s.setAttribute("aria-hidden","true")),function(){try{"raw"===localStorage.getItem(r)&&localStorage.setItem(r,"overview")}catch{}let e=l("Raw usage");if(e){if(e.classList.contains("bg-primary")){let e=l("Tổng quan");e?.click()}e.remove()}}()}))};t();let s=new MutationObserver(t);return s.observe(document.body,{childList:!0,subtree:!0}),()=>s.disconnect()},[]),null}},94027:(e,t,s)=>{"use strict";s.d(t,{Y:()=>o,s:()=>d});var n=s(95155),r=s(12115),l=s(14051),a=s.n(l);let i=(0,r.createContext)(null);function o({children:e}){let[t,s]=(0,r.useState)(null),[l,a]=(0,r.useState)(!0),[d,c]=(0,r.useState)(""),x=(0,r.useCallback)(async()=>{a(!0),c("");try{let e=await fetch("/api/auth/status",{cache:"no-store"}),t=await e.json().catch(()=>({}));if(!e.ok)throw Error(t?.error||"Kh\xf4ng tải được trạng th\xe1i đăng nhập");return s(t||{}),t||{}}catch(e){return c(e?.message||"Kh\xf4ng tải được trạng th\xe1i đăng nhập"),s({}),{}}finally{a(!1)}},[]);(0,r.useEffect)(()=>{let e=!1;return(async()=>{a(!0),c("");try{let t=await fetch("/api/auth/status",{cache:"no-store"}),n=await t.json().catch(()=>({}));if(e)return;if(!t.ok)throw Error(n?.error||"Kh\xf4ng tải được trạng th\xe1i đăng nhập");s(n||{})}catch(t){e||(c(t?.message||"Kh\xf4ng tải được trạng th\xe1i đăng nhập"),s({}))}finally{e||a(!1)}})(),()=>{e=!0}},[]);let m=(0,r.useMemo)(()=>{let e,s,n,r,l,a,i;return s=(e=t&&"object"==typeof t?t:{}).displayName||e.oidcName||e.oidcEmail||e.userId||"",r=(n=!0===e.actualIsAdmin||!0===e.isAdmin&&!0!==e.showAsUser)&&!0===e.showAsUser,l=!0===e.isAdmin&&!r,a=!0===e.isMonitorAdmin,i=!0===e.isAiGatewaysMonitor,{status:e,displayName:s,userId:e.userId||"",loginMethod:e.loginMethod||"",role:e.role||"guest",actualRole:e.actualRole||e.role||"guest",isAdmin:l,actualIsAdmin:n,showAsUser:r,canToggleUserMode:!0===e.canToggleUserMode||n,isMonitorAdmin:a,isAiGatewaysMonitor:i,canManageApiKeys:!0===e.canManageApiKeys||l||a,canUseMonitorAdminTabs:!0===e.canUseMonitorAdminTabs||l||a,canViewAllAnalytics:!0===e.canViewAllAnalytics||l||a||i,canUseAuditProxy:!0===e.canUseAuditProxy||l}},[t]),u=(0,r.useMemo)(()=>({...m,loading:l,error:d,reload:x}),[m,l,d,x]);return(0,n.jsx)(i.Provider,{value:u,children:e})}function d(){let e=(0,r.useContext)(i);return e||{status:{},displayName:"",userId:"",loginMethod:"",role:"admin",actualRole:"admin",isAdmin:!0,actualIsAdmin:!0,showAsUser:!1,canToggleUserMode:!0,isMonitorAdmin:!1,isAiGatewaysMonitor:!1,canManageApiKeys:!0,canUseMonitorAdminTabs:!0,canViewAllAnalytics:!0,loading:!1,error:"",reload:async()=>({})}}o.propTypes={children:a().node}}},e=>{e.O(0,[9959,8441,3794,7358],()=>e(e.s=53836)),_N_E=e.O()}]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[5236],{23371:(e,t,s)=>{Promise.resolve().then(s.bind(s,95705)),Promise.resolve().then(s.bind(s,35696))},35696:(e,t,s)=>{"use strict";s.d(t,{default:()=>o});var r=s(95155),a=s(12115),n=s(83163);function d({ok:e,children:t}){return(0,r.jsxs)("span",{className:`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium ${e?"border-green-500/30 bg-green-500/10 text-green-600 dark:text-green-400":"border-border bg-surface text-text-muted"}`,children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[13px]",children:e?"check_circle":"radio_button_unchecked"}),t]})}function o(){let[e,t]=(0,a.useState)(null),[s,o]=(0,a.useState)(""),l=(0,a.useCallback)(async()=>{try{let e=await fetch("/api/audit-proxy/me",{cache:"no-store"}),s=await e.json().catch(()=>({}));if(!e.ok)throw Error(s.error||"Kh\xf4ng tải được th\xf4ng tin truy cập Audit Proxy của bạn");t(s)}catch(e){o(e.message||"Kh\xf4ng tải được th\xf4ng tin truy cập Audit Proxy của bạn")}},[]);if((0,a.useEffect)(()=>{l();let e=setInterval(l,15e3);return()=>clearInterval(e)},[l]),s&&!e)return(0,r.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-400",children:s});if(!e)return(0,r.jsx)("div",{className:"rounded-xl border border-border bg-surface p-5 text-sm text-text-muted",children:"Đang tải Enterprise AI Audit Proxy…"});let i=e.rootCA||{},c=e.grant?.ips||[];return(0,r.jsxs)("div",{className:"space-y-4",children:[(0,r.jsxs)("div",{className:"rounded-2xl border border-primary/20 bg-primary/5 p-4",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-primary",children:"policy"}),(0,r.jsx)("h1",{className:"text-lg font-bold text-text-main",children:"Enterprise AI Audit Proxy"}),(0,r.jsx)(d,{ok:!0===e.running,children:e.running?"Đang chạy":"Đ\xe3 dừng"}),(0,r.jsx)(d,{ok:!0===i.validated,children:"Root CA"})]}),(0,r.jsx)("p",{className:"mt-2 max-w-4xl text-sm leading-6 text-text-muted",children:"T\xe0i khoản của bạn được ph\xe9p d\xf9ng audit proxy cho Claude Code v\xe0 Codex. C\xe0i Root CA một lần, sau đ\xf3 khởi động CLI bằng một trong c\xe1c lệnh b\xean dưới. Mọi request đi qua proxy đều được quản trị vi\xean ghi log để phục vụ kiểm to\xe1n."})]}),s?(0,r.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-400",children:s}):null,(0,r.jsxs)("div",{className:"grid gap-4 xl:grid-cols-[0.8fr_1.2fr]",children:[(0,r.jsxs)("div",{className:"space-y-4",children:[(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Quyền truy cập của bạn"}),(0,r.jsx)("p",{className:"mt-1 text-xs leading-5 text-text-muted",children:"Proxy chỉ nhận kết nối từ c\xe1c địa chỉ IP dưới đ\xe2y. Từ m\xe1y c\xf3 IP kh\xe1c, kết nối sẽ bị đ\xf3ng ngay — cần th\xeam địa chỉ th\xec li\xean hệ quản trị vi\xean."}),(0,r.jsxs)("div",{className:"mt-3 grid gap-2 text-xs",children:[(0,r.jsxs)("div",{className:"flex justify-between gap-3",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"T\xe0i khoản"}),(0,r.jsx)("span",{className:"break-all font-mono text-text-main",children:e.grant?.userId||e.userId||"-"})]}),e.grant?.note?(0,r.jsxs)("div",{className:"flex justify-between gap-3",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Ghi ch\xfa"}),(0,r.jsx)("span",{className:"break-all text-text-main",children:e.grant.note})]}):null]}),(0,r.jsxs)("div",{className:"mt-3",children:[(0,r.jsx)("div",{className:"text-[11px] font-medium uppercase tracking-wide text-text-muted",children:"IP được cấp ph\xe9p"}),c.length?(0,r.jsx)("div",{className:"mt-1.5 flex flex-wrap gap-1.5",children:c.map(e=>(0,r.jsx)("span",{className:"rounded-full border border-primary/30 bg-primary/5 px-2.5 py-1 font-mono text-[11px] text-primary",children:e},e))}):(0,r.jsx)("p",{className:"mt-1.5 rounded-lg border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-[11px] leading-5 text-amber-700 dark:text-amber-300",children:e.isAdmin?"T\xe0i khoản admin của bạn kh\xf4ng c\xf3 grant ri\xeang. Grant chỉ d\xf9ng cho allowlist IP của proxy.":"Chưa c\xf3 địa chỉ n\xe0o được cấp, n\xean proxy sẽ từ chối kết nối của bạn. H\xe3y gửi IP m\xe1y trạm của bạn cho quản trị vi\xean."})]})]}),(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Root CA"}),(0,r.jsx)("p",{className:"mt-1 text-xs leading-5 text-text-muted",children:"Tải certificate v\xe0 lưu v\xe0o đ\xfang đường dẫn ghi trong phần hướng dẫn b\xean cạnh. Đ\xe2y l\xe0 certificate c\xf4ng khai, kh\xf4ng chứa private key."}),(0,r.jsxs)("div",{className:"mt-3 grid gap-2 text-xs",children:[(0,r.jsxs)("div",{className:"flex justify-between gap-3",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Trạng th\xe1i"}),(0,r.jsx)("span",{className:"font-medium text-text-main",children:i.validated?"Đ\xe3 x\xe1c thực":i.certExists?"Cần kiểm tra lại":"Chưa tạo"})]}),i.subject?(0,r.jsxs)("div",{className:"grid gap-1",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Subject"}),(0,r.jsx)("span",{className:"break-all font-mono text-[11px] text-text-main",children:i.subject})]}):null,i.fingerprint?(0,r.jsxs)("div",{className:"grid gap-1",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Fingerprint public key"}),(0,r.jsx)("span",{className:"break-all font-mono text-[11px] text-text-main",children:i.fingerprint})]}):null,i.notAfter?(0,r.jsxs)("div",{className:"flex justify-between gap-3",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Hết hạn"}),(0,r.jsx)("span",{className:"text-text-main",children:new Date(i.notAfter).toLocaleString()})]}):null]}),(0,r.jsx)("div",{className:"mt-4",children:(0,r.jsx)("a",{href:"/api/audit-proxy/ca?download=cert",className:`inline-flex rounded-lg border border-primary/30 bg-primary/10 px-3 py-2 text-xs font-semibold text-primary ${i.certExists?"":"pointer-events-none opacity-50"}`,children:"Tải Root CA"})})]})]}),(0,r.jsx)(n.Ay,{clientProxyHost:e.endpoint?.clientProxyHost,port:e.endpoint?.port,onError:o})]})]})}},83163:(e,t,s)=>{"use strict";s.d(t,{Ay:()=>i});var r=s(95155),a=s(12115);let n="localhost,127.0.0.1,::1",d="C:\\BlueRouter\\bluerouter-audit-root-ca.crt",o="$HOME/.bluerouter/bluerouter-audit-root-ca.crt";function l({title:e,subtitle:t,command:s,copyKey:a,copied:n,onCopy:d,recommended:o=!1}){return(0,r.jsxs)("div",{className:`rounded-xl border bg-background p-3 ${o?"border-green-500/30":"border-border"}`,children:[(0,r.jsxs)("div",{className:"flex items-start justify-between gap-3",children:[(0,r.jsxs)("div",{children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,r.jsx)("span",{className:"text-xs font-semibold text-text-main",children:e}),o?(0,r.jsx)("span",{className:"rounded-full bg-green-500/10 px-2 py-0.5 text-[10px] font-semibold text-green-600 dark:text-green-400",children:"Khuyến nghị"}):null]}),t?(0,r.jsx)("div",{className:"mt-0.5 text-[10px] leading-4 text-text-muted",children:t}):null]}),(0,r.jsx)("button",{type:"button",onClick:()=>d(a,s),className:"shrink-0 text-xs font-medium text-primary",children:n===a?"Đ\xe3 copy":"Copy"})]}),(0,r.jsx)("pre",{className:"mt-2 overflow-x-auto whitespace-pre-wrap break-all rounded-lg bg-surface px-3 py-2 text-[11px] leading-5 text-text-muted",children:s})]})}function i({clientProxyHost:e,port:t,onError:s}){let[c,x]=(0,a.useState)(""),m=(0,a.useMemo)(()=>{var s,r;let a,l=(s=e,r=t,`http://${(a=String(s||"").trim()||"<bluerouter-host>").includes(":")&&!a.startsWith("[")?`[${a}]`:a}:${r}`),i=`set "HTTP_PROXY=${l}"&&set "HTTPS_PROXY=${l}"&&set "NO_PROXY=${n}"&&set "no_proxy=${n}"`,c=`HTTP_PROXY='${l}' HTTPS_PROXY='${l}' NO_PROXY='${n}' no_proxy='${n}'`;return{proxyUrl:l,claudePowerShell:`cmd.exe /d /c '${i}&&set "NODE_EXTRA_CA_CERTS=${d}"&&claude'`,codexPowerShell:`cmd.exe /d /c '${i}&&set "CODEX_CA_CERTIFICATE=${d}"&&codex'`,claudeBash:`env ${c} NODE_EXTRA_CA_CERTS="${o}" claude`,codexBash:`env ${c} CODEX_CA_CERTIFICATE="${o}" codex`}},[e,t]),p=`model_provider = "chatgpt_https"
|
|
2
|
+
|
|
3
|
+
[model_providers.chatgpt_https]
|
|
4
|
+
name = "OpenAI ChatGPT (HTTPS)"
|
|
5
|
+
base_url = "https://chatgpt.com/backend-api/codex"
|
|
6
|
+
wire_api = "responses"
|
|
7
|
+
requires_openai_auth = true
|
|
8
|
+
`,u=async(e,t)=>{try{await navigator.clipboard.writeText(t),x(e),setTimeout(()=>x(""),1500)}catch{s?.("Kh\xf4ng truy cập được clipboard của tr\xecnh duyệt.")}};return(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Hướng dẫn cấu h\xecnh m\xe1y trạm"}),(0,r.jsx)("p",{className:"mt-1 text-xs leading-5 text-text-muted",children:"C\xe1c lệnh dưới đ\xe2y chỉ đặt biến m\xf4i trường trong tiến tr\xecnh con — kh\xf4ng d\xf9ng setx, kh\xf4ng đổi proxy của Windows/hệ thống. NO_PROXY giữ cho OAuth callback ở localhost v\xe0 MCP chạy nội bộ kh\xf4ng đi qua proxy."}),(0,r.jsxs)("div",{className:"mt-3 rounded-xl border border-primary/20 bg-primary/5 p-3 text-xs leading-5 text-text-muted",children:[(0,r.jsx)("div",{className:"font-semibold text-primary",children:"L\xe0m một lần trước khi d\xf9ng"}),"Lưu file Root CA vừa tải v\xe0o đ\xfang đường dẫn: ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:d})," tr\xean Windows, hoặc ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:o})," tr\xean Linux/macOS. Nếu CA đ\xe3 được c\xe0i v\xe0o hệ điều h\xe0nh th\xec biến CA trong lệnh vẫn v\xf4 hại, cứ để nguy\xean."]}),(0,r.jsxs)("div",{className:"mt-3 grid gap-3",children:[(0,r.jsxs)("div",{className:"rounded-xl border border-border bg-background p-3",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,r.jsx)("span",{className:"text-xs font-semibold text-text-main",children:"Địa chỉ proxy"}),(0,r.jsx)("button",{type:"button",onClick:()=>u("url",m.proxyUrl),className:"text-xs text-primary",children:"url"===c?"Đ\xe3 copy":"Copy"})]}),(0,r.jsx)("code",{className:"mt-1 block break-all text-xs text-text-muted",children:m.proxyUrl})]}),(0,r.jsx)(l,{title:"Claude Code \xb7 Windows PowerShell",subtitle:"Biến proxy chỉ tồn tại trong tiến tr\xecnh con, đ\xf3ng cửa sổ l\xe0 hết.",command:m.claudePowerShell,copyKey:"claude-ps",copied:c,onCopy:u,recommended:!0}),(0,r.jsxs)("div",{className:"rounded-xl border border-green-500/30 bg-green-500/5 p-3",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,r.jsx)("span",{className:"text-xs font-semibold text-text-main",children:"Codex \xb7 Ghim v\xe0o transport HTTPS"}),(0,r.jsx)("span",{className:"rounded-full bg-green-500/10 px-2 py-0.5 text-[10px] font-semibold text-green-600 dark:text-green-400",children:"Cấu h\xecnh ch\xednh"})]}),(0,r.jsx)("p",{className:"mt-2 text-[11px] leading-5 text-text-muted",children:"Codex ưu ti\xean WebSocket khi khởi động. Audit Proxy kh\xf4ng cho WebSocket upgrade, n\xean h\xe3y cấu h\xecnh Codex d\xf9ng HTTPS để tr\xe1nh khoảng 7 gi\xe2y thử kết nối lại."}),(0,r.jsxs)("p",{className:"mt-2 text-[11px] leading-5 text-text-muted",children:["Tạo hoặc mở file ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:"%USERPROFILE%\\.codex\\config.toml"}),", sau đ\xf3 copy to\xe0n bộ nội dung b\xean dưới v\xe0o file v\xe0 lưu lại."]}),(0,r.jsx)("div",{className:"mt-3",children:(0,r.jsx)(l,{title:"Nội dung file config.toml",subtitle:"Copy to\xe0n bộ nội dung b\xean dưới v\xe0 lưu v\xe0o config.toml.",command:p,copyKey:"codex-https-config",copied:c,onCopy:u,recommended:!0})}),(0,r.jsxs)("p",{className:"mt-2 text-[11px] leading-5 text-amber-600 dark:text-amber-400",children:["Nếu config.toml đ\xe3 c\xf3 nội dung, đặt ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:'model_provider = "chatgpt_https"'})," ở cấp cao nhất v\xe0 chỉ th\xeam một khối ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:"[model_providers.chatgpt_https]"}),". Kh\xf4ng tạo hai kho\xe1 ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:"model_provider"}),"."]}),(0,r.jsxs)("p",{className:"mt-2 text-[11px] leading-5 text-text-muted",children:["File config.toml chỉ chọn transport HTTPS. Proxy vẫn được truyền qua ",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:"HTTP_PROXY"}),"/",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:"HTTPS_PROXY"}),"/",(0,r.jsx)("code",{className:"rounded bg-background px-1 py-0.5",children:"NO_PROXY"}),", n\xean sau khi lưu file h\xe3y chạy Codex bằng lệnh b\xean dưới."]})]}),(0,r.jsx)(l,{title:"Codex \xb7 Windows PowerShell",subtitle:"Kh\xf4ng ghi g\xec v\xe0o biến m\xf4i trường của user hay hệ thống.",command:m.codexPowerShell,copyKey:"codex-ps",copied:c,onCopy:u,recommended:!0}),(0,r.jsxs)("details",{className:"rounded-xl border border-border bg-background p-3",children:[(0,r.jsx)("summary",{className:"cursor-pointer text-xs font-semibold text-text-main",children:"Lệnh cho Linux / macOS"}),(0,r.jsxs)("div",{className:"mt-3 grid gap-3",children:[(0,r.jsx)(l,{title:"Claude Code \xb7 Bash/zsh",command:m.claudeBash,copyKey:"claude-bash",copied:c,onCopy:u}),(0,r.jsx)(l,{title:"Codex \xb7 Bash/zsh",command:m.codexBash,copyKey:"codex-bash",copied:c,onCopy:u})]})]})]})]})}},95705:(e,t,s)=>{"use strict";s.d(t,{default:()=>N});var r=s(95155),a=s(12115),n=s(98500),d=s.n(n);function o(){let[e,t]=(0,a.useState)(!1),[s,n]=(0,a.useState)(!1),[d,o]=(0,a.useState)([]),[l,i]=(0,a.useState)(!1),[c,x]=(0,a.useState)(""),[m,p]=(0,a.useState)(""),u=(e,s)=>{n(e?.proxyAuthEnabled===!0),o((e?.proxyAuthUsers||[]).map(e=>({username:e.username,hasPassword:!0===e.hasPassword,password:""}))),s&&t(!0===s.running)},h=(0,a.useCallback)(async()=>{try{let e=await fetch("/api/audit-proxy?limit=1",{cache:"no-store"}),t=await e.json();if(!e.ok)throw Error(t.error||"Cannot load proxy authentication");u(t.config,t.status)}catch(e){x(e.message||"Cannot load proxy authentication")}},[]);(0,a.useEffect)(()=>{h()},[h]);let b=(e,t)=>{o(s=>s.map((s,r)=>r===e?{...s,...t}:s))},g=async()=>{let e=d.map(e=>({...e,username:e.username.trim()}));if(s&&0===e.length)return void x("Add at least one account before enabling proxy authentication.");let t=e.find(e=>!e.hasPassword&&!e.password);if(t)return void x(`Set a password for ${t.username||"the new account"}.`);i(!0),x(""),p("");try{let t=await fetch("/api/audit-proxy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"save-proxy-auth",enabled:s,users:e.map(e=>e.password?{username:e.username,password:e.password}:{username:e.username})})}),r=await t.json().catch(()=>({}));if(!t.ok)throw Error(r.error||"Failed to save proxy authentication");p(r.restarted?"Proxy authentication saved and Audit Proxy restarted.":"Proxy authentication saved."),u(r.config,r.status)}catch(e){x(e.message||"Failed to save proxy authentication")}finally{i(!1)}};return(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[(0,r.jsxs)("div",{className:"max-w-3xl",children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Proxy authentication"}),(0,r.jsx)("p",{className:"mt-1 text-xs leading-5 text-text-muted",children:"Requires a username and password on every CONNECT, and records which account opened each tunnel, so the audit table answers who rather than only which IP. Give each person or CI job its own account: removing one leaves the others working."}),(0,r.jsx)("p",{className:"mt-2 rounded-lg border border-amber-500/30 bg-amber-500/5 p-2 text-[11px] leading-5 text-amber-700 dark:text-amber-300",children:"The proxy listener speaks plain HTTP, so the credential crosses the client-to-proxy hop unencrypted (Basic is base64, not encryption). This keeps out anyone without the password and attributes traffic to a person; it does not hide the password from someone capturing packets on that network. On an untrusted network use it alongside the client IP allowlist, not instead of it. The password also ends up in HTTPS_PROXY, and so in the process list and shell history."})]}),(0,r.jsxs)("label",{className:"flex shrink-0 items-center gap-2 text-sm text-text-main",children:[(0,r.jsx)("input",{type:"checkbox",checked:s,onChange:e=>n(e.target.checked),disabled:l,className:"h-4 w-4 accent-[var(--color-primary)]"}),"Require credentials"]})]}),(0,r.jsxs)("div",{className:"mt-4 grid gap-2",children:[0===d.length?(0,r.jsx)("p",{className:"rounded-xl border border-border bg-background/50 p-3 text-xs text-text-muted",children:"No accounts yet."}):null,d.map((e,t)=>(0,r.jsxs)("div",{className:"grid gap-2 rounded-xl border border-border bg-background/50 p-3 sm:grid-cols-[1fr_1fr_auto]",children:[(0,r.jsx)("input",{type:"text",value:e.username,onChange:e=>b(t,{username:e.target.value}),disabled:l,placeholder:"username",className:"min-w-0 rounded-lg border border-border bg-background px-3 py-2 font-mono text-xs text-text-main outline-none focus:border-primary disabled:opacity-60"}),(0,r.jsx)("input",{type:"password",value:e.password,onChange:e=>b(t,{password:e.target.value}),disabled:l,placeholder:e.hasPassword?"Saved — leave blank to keep":"Set a password",className:"min-w-0 rounded-lg border border-border bg-background px-3 py-2 font-mono text-xs text-text-main outline-none focus:border-primary disabled:opacity-60"}),(0,r.jsx)("button",{type:"button",onClick:()=>{let e;(!(e=d[t]).hasPassword||window.confirm(`Remove ${e.username}? Anything using this account stops working after the restart.`))&&o(e=>e.filter((e,s)=>s!==t))},disabled:l,className:"rounded-lg border border-border px-3 py-2 text-xs text-text-muted transition hover:border-red-500/40 hover:text-red-600 disabled:opacity-50",children:"Remove"})]},t))]}),(0,r.jsxs)("div",{className:"mt-3 flex flex-wrap items-center gap-2",children:[(0,r.jsx)("button",{type:"button",onClick:()=>o(e=>[...e,{username:"",hasPassword:!1,password:""}]),disabled:l,className:"rounded-lg border border-border px-3 py-1.5 text-xs text-text-muted transition hover:border-primary hover:text-primary disabled:opacity-50",children:"Add account"}),(0,r.jsx)("button",{type:"button",onClick:g,disabled:l,className:"rounded-lg bg-primary px-3 py-1.5 text-xs font-semibold text-white transition hover:opacity-90 disabled:opacity-50",children:l?"Saving…":e?"Save & Restart Proxy":"Save"}),(0,r.jsxs)("span",{className:"text-[11px] text-text-muted",children:["Clients pass credentials in the proxy URL: ",(0,r.jsx)("code",{className:"font-mono",children:"http://USER:PASSWORD@host:port"})," ","— URL-encode ",(0,r.jsx)("code",{className:"font-mono",children:"@ : / #"})," if the password contains them."]})]}),c?(0,r.jsx)("p",{className:"mt-3 rounded-lg border border-red-500/30 bg-red-500/5 p-2 text-xs text-red-600 dark:text-red-400",children:c}):null,m?(0,r.jsx)("p",{className:"mt-3 rounded-lg border border-green-500/30 bg-green-500/5 p-2 text-xs text-green-600 dark:text-green-400",children:m}):null]})}let l={granted:"already granted",ldap:"directory","api-key-owner":"API key owner","oauth-grant":"OAuth access",local:"local login"};function i({onChanged:e}){let[t,s]=(0,a.useState)(null),[n,d]=(0,a.useState)("manual"),[o,c]=(0,a.useState)(0),[x,m]=(0,a.useState)(!1),[p,u]=(0,a.useState)(!1),[h,b]=(0,a.useState)(""),[g,y]=(0,a.useState)(""),[j,f]=(0,a.useState)(""),[N,v]=(0,a.useState)([]),[w,k]=(0,a.useState)(!1),[C,S]=(0,a.useState)(!1),[P,T]=(0,a.useState)(""),[A,R]=(0,a.useState)(""),[E,I]=(0,a.useState)(""),[$,O]=(0,a.useState)(""),_=(0,a.useCallback)(e=>{s(Array.isArray(e?.config?.accessGrants)?e.config.accessGrants:[]),d(e?.status?.security?.clientIpFilterSource||"manual"),c(Number(e?.status?.security?.enforcedClientIpCount||0)),m(e?.status?.running===!0),u(e?.status?.standby===!0)},[]),H=(0,a.useCallback)(async()=>{try{let e=await fetch("/api/audit-proxy?limit=1",{cache:"no-store"}),t=await e.json();if(!e.ok)throw Error(t.error||"Cannot load Audit Proxy access grants");_(t)}catch(e){R(e.message||"Cannot load Audit Proxy access grants")}},[_]);(0,a.useEffect)(()=>{H()},[H]),(0,a.useEffect)(()=>{if(!w)return;let e=!1,t=setTimeout(async()=>{S(!0);try{let t=await fetch(`/api/audit-proxy/users?q=${encodeURIComponent(h.trim())}`,{cache:"no-store"}),s=await t.json().catch(()=>({}));!e&&t.ok&&v(Array.isArray(s.users)?s.users:[])}catch{e||v([])}finally{e||S(!1)}},250);return()=>{e=!0,clearTimeout(t)}},[h,w]);let L=(0,a.useMemo)(()=>String(g||"").split(/[\r\n,]+/).map(e=>e.trim()).filter(Boolean),[g]),q=async(t,s,r)=>{T(t),R(""),I("");try{let a=await fetch("/api/audit-proxy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:t,...s})}),n=await a.json().catch(()=>({}));if(!a.ok)throw Error(n.error||"Failed to save Audit Proxy access grant");_(n);let d=Number(n.droppedConnections||0);return I(`${r} Applied to the running proxy without a restart.${d?` ${d} open connection(s) from addresses that lost access were closed.`:""}`),e?.(),!0}catch(e){return R(e.message||"Failed to save Audit Proxy access grant"),!1}finally{T("")}},D=async()=>{let e=String(h||"").trim().toLowerCase();e?await q("save-access-grant",{userId:e,ips:L,note:j},`Access grant for ${e} saved.`)&&(b(""),y(""),f("")):R("Enter the dashboard username or email to grant access to.")},F=async e=>{await q("delete-access-grant",{userId:e},`Access grant for ${e} revoked.`)&&O("")};if(!t)return null;let U=t.reduce((e,t)=>e+(t.ips?.length||0),0);return(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsx)("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between",children:(0,r.jsxs)("div",{children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-primary",children:"group"}),(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Access grants — who may use this proxy"}),(0,r.jsx)("span",{className:`rounded-full px-2 py-0.5 text-[10px] font-semibold ${"grants"===n?"bg-green-500/10 text-green-600 dark:text-green-400":"bg-surface text-text-muted"}`,children:`IP FILTER ON \xb7 ${o} ALLOWED`})]}),(0,r.jsxs)("p",{className:"mt-1 max-w-4xl text-xs leading-5 text-text-muted",children:["IP filtering is always on. The proxy accepts ",(0,r.jsx)("strong",{children:"only IPs/CIDRs assigned in Access grants"}),"; when no grant contains an IP, every client connection is denied. Each granted user also gets a read-only ",(0,r.jsx)("span",{className:"font-mono",children:"/dashboard/audit-proxy"})," page with the root CA download, launcher commands and their own addresses — no configuration and no audited traffic."]})]})}),A?(0,r.jsx)("div",{className:"mt-3 rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-red-600 dark:text-red-400",children:A}):null,E?(0,r.jsx)("div",{className:"mt-3 rounded-lg border border-green-500/30 bg-green-500/10 px-3 py-2 text-xs text-green-600 dark:text-green-400",children:E}):null,(0,r.jsxs)("div",{className:"mt-4 grid gap-4 lg:grid-cols-[1fr_320px]",children:[(0,r.jsxs)("div",{className:"grid gap-3",children:[(0,r.jsxs)("div",{className:"grid gap-1.5",children:[(0,r.jsx)("span",{className:"text-sm font-semibold text-text-main",children:"Dashboard username / email"}),(0,r.jsxs)("div",{className:"relative",children:[(0,r.jsx)("input",{value:h,onChange:e=>{b(e.target.value),k(!0)},onFocus:()=>k(!0),onBlur:()=>setTimeout(()=>k(!1),150),autoComplete:"off",placeholder:"anh-tct or anh-tct@fujinet.net",className:"w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary"}),w&&(C||N.length>0)?(0,r.jsxs)("div",{className:"absolute z-20 mt-1 max-h-64 w-full overflow-y-auto rounded-lg border border-border bg-surface shadow-lg",children:[C&&0===N.length?(0,r.jsx)("div",{className:"px-3 py-2 text-xs text-text-muted",children:"Searching…"}):null,N.map(e=>{let s=t.some(t=>t.userId===e.id);return(0,r.jsxs)("button",{type:"button",onMouseDown:e=>e.preventDefault(),onClick:()=>{b(e.id),k(!1)},className:"flex w-full items-center justify-between gap-2 px-3 py-2 text-left hover:bg-background",children:[(0,r.jsxs)("span",{className:"min-w-0",children:[(0,r.jsx)("span",{className:"block truncate font-mono text-xs text-text-main",children:e.id}),e.displayName||e.email?(0,r.jsx)("span",{className:"block truncate text-[11px] text-text-muted",children:[e.displayName,e.email].filter(Boolean).join(" \xb7 ")}):null]}),(0,r.jsxs)("span",{className:"flex shrink-0 items-center gap-1",children:[s?(0,r.jsx)("span",{className:"rounded-full bg-green-500/10 px-2 py-0.5 text-[10px] font-semibold text-green-600 dark:text-green-400",children:"granted"}):null,(0,r.jsx)("span",{className:"rounded-full border border-border px-2 py-0.5 text-[10px] text-text-muted",children:l[e.source]||e.source})]})]},`${e.source}:${e.id}`)})]}):null]}),(0,r.jsx)("span",{className:"text-[11px] leading-4 text-text-muted",children:"The identity the user logs into this dashboard with (LDAP/OIDC/local). Either the username or the email form is matched. Suggestions come from the directory and from accounts this install already knows; a name that is not listed can still be typed."})]}),(0,r.jsxs)("label",{className:"grid gap-1.5",children:[(0,r.jsx)("span",{className:"text-sm font-semibold text-text-main",children:"Allowed client IPs / CIDRs"}),(0,r.jsx)("textarea",{rows:4,value:g,onChange:e=>y(e.target.value),placeholder:"172.16.253.2\n172.16.6.0/24",className:"rounded-lg border border-border bg-background px-3 py-2 font-mono text-xs text-text-main outline-none focus:border-primary"}),(0,r.jsx)("span",{className:"text-[11px] leading-4 text-text-muted",children:"One IPv4, IPv6 or CIDR per line — the workstation addresses this user runs Claude Code / Codex from."})]}),(0,r.jsxs)("label",{className:"grid gap-1.5",children:[(0,r.jsx)("span",{className:"text-sm font-semibold text-text-main",children:"Note (optional)"}),(0,r.jsx)("input",{value:j,onChange:e=>f(e.target.value),placeholder:"Laptop + VDI",className:"rounded-lg border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary"})]})]}),(0,r.jsxs)("div",{className:"grid content-start gap-3",children:[(0,r.jsxs)("div",{className:"rounded-xl border border-primary/20 bg-primary/5 p-3 text-xs leading-5 text-text-muted",children:[(0,r.jsx)("div",{className:"font-semibold text-primary",children:"What a grant changes"}),(0,r.jsx)("div",{className:"mt-1",children:"Granted IP → proxy works normally."}),(0,r.jsx)("div",{children:"Any other IP → TCP connection closed before CONNECT is parsed."}),(0,r.jsx)("div",{children:"Granted user → read-only Audit Proxy page + CA download."}),(0,r.jsx)("div",{children:"No grant with an IP → falls back to the Client IP filter below."}),(0,r.jsx)("div",{className:"mt-1 text-[11px]",children:"Applied without restarting the listener."})]}),(0,r.jsx)("button",{type:"button",onClick:D,disabled:!!P||p,className:"rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-white disabled:opacity-50",children:"save-access-grant"===P?"Saving…":"Save grant"}),x?(0,r.jsx)("div",{className:"text-[11px] leading-4 text-text-muted",children:"The listener keeps running: the change governs the next connection, and tunnels held by an address you just removed are closed."}):null]})]}),(0,r.jsxs)("div",{className:"mt-4 border-t border-border pt-4",children:[(0,r.jsxs)("div",{className:"mb-3 flex flex-wrap items-center justify-between gap-2",children:[(0,r.jsx)("h3",{className:"text-sm font-semibold text-text-main",children:"Granted users"}),(0,r.jsxs)("span",{className:"text-[11px] text-text-muted",children:[t.length," user \xb7 ",U," address"]})]}),0===t.length?(0,r.jsx)("div",{className:"rounded-xl border border-dashed border-border p-6 text-center text-xs text-text-muted",children:"No grant yet. The proxy still follows the Client IP filter below, and only admins can open this page."}):(0,r.jsx)("div",{className:"overflow-x-auto rounded-xl border border-border",children:(0,r.jsxs)("table",{className:"min-w-full divide-y divide-border text-xs",children:[(0,r.jsx)("thead",{className:"bg-surface/80 text-left uppercase tracking-wide text-text-muted",children:(0,r.jsxs)("tr",{children:[(0,r.jsx)("th",{className:"px-3 py-2 font-medium",children:"User"}),(0,r.jsx)("th",{className:"px-3 py-2 font-medium",children:"Allowed client IPs"}),(0,r.jsx)("th",{className:"px-3 py-2 font-medium",children:"Note"}),(0,r.jsx)("th",{className:"px-3 py-2 text-right font-medium",children:"Actions"})]})}),(0,r.jsx)("tbody",{className:"divide-y divide-border bg-background",children:t.map(e=>(0,r.jsxs)("tr",{className:"align-top",children:[(0,r.jsx)("td",{className:"px-3 py-3 font-mono text-text-main",children:e.userId}),(0,r.jsx)("td",{className:"px-3 py-3",children:e.ips?.length?(0,r.jsx)("div",{className:"flex flex-wrap gap-1",children:e.ips.map(e=>(0,r.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-0.5 font-mono text-[10px] text-text-muted",children:e},e))}):(0,r.jsx)("span",{className:"text-amber-600 dark:text-amber-400",children:"No IP — page access only, proxy will refuse this user"})}),(0,r.jsx)("td",{className:"px-3 py-3 text-text-muted",children:e.note||"-"}),(0,r.jsx)("td",{className:"px-3 py-3",children:(0,r.jsxs)("div",{className:"flex flex-wrap justify-end gap-2",children:[(0,r.jsx)("button",{type:"button",onClick:()=>{b(e.userId),y((e.ips||[]).join("\n")),f(e.note||"")},disabled:p,className:"rounded-lg border border-border px-2.5 py-1 font-semibold text-text-main hover:bg-surface",children:"Edit"}),$===e.userId?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("button",{type:"button",onClick:()=>F(e.userId),disabled:!!P||p,className:"rounded-lg border border-red-500/30 bg-red-500/10 px-2.5 py-1 font-semibold text-red-600 disabled:opacity-50",children:"Confirm revoke"}),(0,r.jsx)("button",{type:"button",onClick:()=>O(""),className:"rounded-lg border border-border px-2.5 py-1 text-text-muted",children:"Cancel"})]}):(0,r.jsx)("button",{type:"button",onClick:()=>O(e.userId),disabled:p,className:"rounded-lg border border-red-500/30 px-2.5 py-1 font-semibold text-red-600 hover:bg-red-500/10",children:"Revoke"})]})})]},e.userId))})]})})]})]})}var c=s(83163);let x=["api.anthropic.com","*.anthropic.com","claude.ai","*.claude.ai"],m=["api.openai.com","*.openai.com","chatgpt.com","*.chatgpt.com"],p=[{id:"claude-code",label:"Claude Code"},{id:"codex",label:"OpenAI Codex"},{id:"gemini-cli",label:"Gemini CLI"},{id:"cursor",label:"Cursor"},{id:"curl",label:"curl / scripts"}];function u({ok:e,children:t}){return(0,r.jsxs)("span",{className:`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium ${e?"border-green-500/30 bg-green-500/10 text-green-600 dark:text-green-400":"border-border bg-surface text-text-muted"}`,children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[13px]",children:e?"check_circle":"radio_button_unchecked"}),t]})}function h(e){let t=Number(e||0);return!Number.isFinite(t)||t<=0?"0":t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${(t/1e3).toFixed(1)}k`:String(t)}function b(e){let t=Number(e||0);return!Number.isFinite(t)||t<=0?"$0.00":t<.01?`$${t.toFixed(4)}`:`$${t.toFixed(2)}`}function g({label:e,value:t,hint:s}){return(0,r.jsxs)("div",{className:"rounded-xl border border-border bg-background/50 p-3",children:[(0,r.jsx)("div",{className:"text-[11px] font-medium uppercase tracking-wide text-text-muted",children:e}),(0,r.jsx)("div",{className:"mt-1 text-lg font-semibold text-text-main",children:t}),s?(0,r.jsx)("div",{className:"mt-0.5 text-[11px] leading-4 text-text-muted",children:s}):null]})}function y({title:e,rows:t}){return t?.length?(0,r.jsxs)("div",{className:"min-w-0",children:[(0,r.jsx)("h3",{className:"text-xs font-semibold uppercase tracking-wide text-text-muted",children:e}),(0,r.jsx)("div",{className:"mt-2 overflow-x-auto",children:(0,r.jsxs)("table",{className:"w-full min-w-[420px] text-left text-xs",children:[(0,r.jsx)("thead",{className:"border-b border-border text-text-muted",children:(0,r.jsxs)("tr",{children:[(0,r.jsx)("th",{className:"px-2 py-1.5 font-medium",children:"Name"}),(0,r.jsx)("th",{className:"px-2 py-1.5 text-right font-medium",children:"Reqs"}),(0,r.jsx)("th",{className:"px-2 py-1.5 text-right font-medium",children:"In"}),(0,r.jsx)("th",{className:"px-2 py-1.5 text-right font-medium",children:"Out"}),(0,r.jsx)("th",{className:"px-2 py-1.5 text-right font-medium",children:"Cache R/W"}),(0,r.jsx)("th",{className:"px-2 py-1.5 text-right font-medium",children:"Cost"})]})}),(0,r.jsx)("tbody",{children:t.map(e=>(0,r.jsxs)("tr",{className:"border-b border-border/60 text-text-main",children:[(0,r.jsx)("td",{className:"max-w-[220px] truncate px-2 py-1.5 font-mono text-[11px]",title:e.label,children:e.label}),(0,r.jsx)("td",{className:"px-2 py-1.5 text-right",children:e.requests}),(0,r.jsx)("td",{className:"px-2 py-1.5 text-right",children:h(e.inputTokens)}),(0,r.jsx)("td",{className:"px-2 py-1.5 text-right",children:h(e.outputTokens)}),(0,r.jsxs)("td",{className:"px-2 py-1.5 text-right text-text-muted",children:[h(e.cacheReadTokens),"/",h(e.cacheCreationTokens)]}),(0,r.jsx)("td",{className:"px-2 py-1.5 text-right",children:b(e.cost)})]},e.label))})]})})]}):null}function j({label:e,hint:t,children:s}){return(0,r.jsxs)("label",{className:"grid gap-1.5",children:[(0,r.jsx)("span",{className:"text-sm font-semibold text-text-main",children:e}),s,t?(0,r.jsx)("span",{className:"text-[11px] leading-4 text-text-muted",children:t}):null]})}function f({label:e,description:t,checked:s,onChange:a,disabled:n=!1}){return(0,r.jsxs)("label",{className:"flex items-start justify-between gap-4 rounded-xl border border-border bg-background/50 p-3",children:[(0,r.jsxs)("span",{children:[(0,r.jsx)("span",{className:"block text-sm font-semibold text-text-main",children:e}),(0,r.jsx)("span",{className:"mt-0.5 block text-xs leading-5 text-text-muted",children:t})]}),(0,r.jsx)("input",{type:"checkbox",checked:s,onChange:e=>a(e.target.checked),disabled:n,className:"mt-1 h-4 w-4 accent-[var(--color-primary)]"})]})}function N(){let[e,t]=(0,a.useState)(null),[s,n]=(0,a.useState)(null),[l,N]=(0,a.useState)(""),[v,w]=(0,a.useState)(""),[k,C]=(0,a.useState)(""),[S,P]=(0,a.useState)(null),[T,A]=(0,a.useState)("configuration"),R=(0,a.useCallback)(async(e=!0)=>{try{let s=await fetch("/api/audit-proxy?limit=50",{cache:"no-store"}),r=await s.json();if(!s.ok)throw Error(r.error||"Cannot load Audit Proxy");t(r),e?n(e=>e||r.config):n(r.config)}catch(e){w(e.message||"Cannot load Audit Proxy")}},[]);(0,a.useEffect)(()=>{R(!1);let e=setInterval(()=>R(!0),5e3);return()=>clearInterval(e)},[R]);let E=e?.status||{},I=E.security||{},$=E.rootCA||{},O=!0===E.running,_=!0===E.pendingListenerRestart,H=!0===E.standby,L=(s?.allowedHosts||[]).join("\n"),q=(e,t)=>n(s=>({...s,[e]:t})),D=async(e,t={})=>{N(e),w(""),C("");try{let s=await fetch("/api/audit-proxy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,...t})}),r=await s.json().catch(()=>({}));if(!s.ok)throw Error(r.error||`${e} failed`);return"test"===e?(P(r.test),C(`Simulation passed ${r.test.passed}/${r.test.total} checks.`)):C("clear-logs"===e?"Audit logs cleared.":`Audit Proxy ${e} completed.`),await R("start"!==e&&"restart"!==e),r}catch(t){return w(t.message||`${e} failed`),null}finally{N("")}},F=async()=>{N("save"),w(""),C("");try{let e=await fetch("/api/audit-proxy",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({config:s})}),t=await e.json();if(!e.ok)throw Error(t.error||"Save failed");n(t.config);let r=Number(t.droppedConnections||0);C(t.rebindRequired?`Configuration saved and applied. The listener address/port change waits for Save & Restart — the proxy is still on ${E.address?.address||s.bindHost}:${E.address?.port||s.port}.`:`Configuration saved and applied to the running proxy${O?" without a restart":""}.${r?` ${r} connection(s) from addresses that lost access were closed.`:""}`),await R(!0)}catch(e){w(e.message||"Save failed")}finally{N("")}},U=async()=>{N("save-client-host"),w(""),C("");try{let e=await fetch("/api/audit-proxy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"save-client-host",clientProxyHost:s?.clientProxyHost||""})}),t=await e.json().catch(()=>({}));if(!e.ok)throw Error(t.error||"Failed to save Client proxy host");n(e=>({...e,clientProxyHost:t.config?.clientProxyHost||""})),C("Client proxy host saved."),await R(!0)}catch(e){w(e.message||"Failed to save Client proxy host")}finally{N("")}},B=async()=>{N("ca"),w("");try{let e=await fetch("/api/audit-proxy/ca",{method:"POST"}),t=await e.json();if(!e.ok)throw Error(t.error||"CA validation failed");C("Root CA is ready. Existing enterprise CA material was not rotated."),await R(!0)}catch(e){w(e.message||"CA validation failed")}finally{N("")}},M=e=>q("allowedHosts",[...new Set([...s?.allowedHosts||[],...e])]);if(!s)return(0,r.jsx)("div",{className:"rounded-xl border border-border bg-surface p-5 text-sm text-text-muted",children:"Loading Enterprise AI Audit Proxy…"});let X=Math.round(Number(s.captureLimitBytes||0)/1024/1024*10)/10,G=["0.0.0.0","::"].includes(s.bindHost)||!String(s.bindHost).startsWith("127.")&&"localhost"!==s.bindHost&&"::1"!==s.bindHost;return(0,r.jsxs)("div",{className:"space-y-4",children:[(0,r.jsxs)("div",{className:"flex flex-col gap-3 rounded-2xl border border-primary/20 bg-primary/5 p-4 sm:flex-row sm:items-start sm:justify-between",children:[(0,r.jsxs)("div",{children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-primary",children:"policy"}),(0,r.jsx)("h1",{className:"text-lg font-bold text-text-main",children:"Enterprise AI Audit Proxy"}),(0,r.jsx)(u,{ok:O,children:O?"Running":"Stopped"}),(0,r.jsx)(u,{ok:!0===$.validated,children:"Root CA"}),(0,r.jsx)(u,{ok:s.verifyUpstreamTls,children:"Verified upstream TLS"}),(0,r.jsx)(u,{ok:!0,children:E.capabilities?.http2===!0?"HTTP/1.1 + HTTP/2":"HTTP/1.1"})]}),(0,r.jsx)("p",{className:"mt-2 max-w-5xl text-sm leading-6 text-text-muted",children:"Explicit HTTPS CONNECT proxy for Claude Code and Codex. Request method, path, query, authentication values and body bytes are forwarded without content rewriting. Standard hop-by-hop headers and BlueRouter internal headers remain intentionally removed."})]}),(0,r.jsxs)(d(),{href:"/dashboard/mitm",className:"inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[16px]",children:"arrow_back"})," AI Traffic Gateway"]})]}),v?(0,r.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-400",children:v}):null,k?(0,r.jsx)("div",{className:"rounded-xl border border-green-500/30 bg-green-500/10 px-4 py-3 text-sm text-green-600 dark:text-green-400",children:k}):null,(0,r.jsxs)("div",{className:"flex w-fit items-center gap-1 rounded-xl border border-border bg-surface p-1",children:[(0,r.jsx)("button",{type:"button",onClick:()=>A("configuration"),className:`rounded-lg px-3 py-1.5 text-xs font-semibold transition ${"configuration"===T?"bg-primary text-white":"text-text-muted hover:bg-background hover:text-text-main"}`,children:"Configuration"}),(0,r.jsx)("button",{type:"button",onClick:()=>A("audit"),className:`rounded-lg px-3 py-1.5 text-xs font-semibold transition ${"audit"===T?"bg-primary text-white":"text-text-muted hover:bg-background hover:text-text-main"}`,children:"Audit & Usage"})]}),(0,r.jsxs)("div",{className:"configuration"===T?"space-y-4":"hidden",children:[H?(0,r.jsxs)("div",{className:"rounded-xl border border-blue-500/30 bg-blue-500/10 px-4 py-3 text-sm text-blue-700 dark:text-blue-300",children:[(0,r.jsx)("strong",{children:"Node n\xe0y đang l\xe0 Cluster Standby."})," Access grants, TLS allowlist, client tool filter v\xe0 capture được đồng bộ từ Master qua cluster snapshot, n\xean form ở đ\xe2y chỉ đọc. Sửa tr\xean Master rồi để sync \xe1p xuống. Bind address/port, Proxy authentication v\xe0 Root CA vẫn l\xe0 của ri\xeang node n\xe0y."]}):null,_?(0,r.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-700 dark:text-amber-300",children:[(0,r.jsxs)("span",{children:[(0,r.jsx)("strong",{children:"Listener address/port change is pending."})," Saved as ",s.bindHost,":",s.port,", still bound to ",E.address?.address,":",E.address?.port,". A bound socket cannot move — restart the listener to apply it. Everything else you saved is already live."]}),(0,r.jsx)("button",{type:"button",onClick:()=>D("restart",{config:s}),disabled:!!l,className:"shrink-0 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-1.5 text-xs font-semibold disabled:opacity-50",children:"restart"===l?"Restarting…":"Restart listener now"})]}):null,G?(0,r.jsxs)("div",{className:"rounded-xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-700 dark:text-amber-300",children:[(0,r.jsx)("strong",{children:"LAN listener enabled."})," Keep TCP ",s.port," restricted to the intended LAN/VPN and maintain the Client IP allowlist."]}):null,$.expiringSoon?(0,r.jsx)("div",{className:"rounded-xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-700 dark:text-amber-300",children:"Root CA expires soon. Audit Proxy will not rotate enterprise CA material automatically; prepare and deploy the replacement CA through Advanced CA management."}):null,(0,r.jsxs)("div",{className:"grid gap-4 xl:grid-cols-[1.25fr_0.75fr]",children:[(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsxs)("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-2",children:[(0,r.jsxs)("div",{children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Proxy configuration"}),(0,r.jsx)("p",{className:"mt-1 text-xs text-text-muted",children:"All server-side setup is managed here. No proxy daemon CLI is required."})]}),(0,r.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,r.jsx)("button",{type:"button",onClick:()=>M(x),className:"rounded-lg border border-border px-3 py-1.5 text-xs text-text-main hover:bg-background disabled:opacity-50",children:"+ Anthropic preset"}),(0,r.jsx)("button",{type:"button",onClick:()=>M(m),className:"rounded-lg border border-border px-3 py-1.5 text-xs text-text-main hover:bg-background disabled:opacity-50",children:"+ OpenAI preset"})]})]}),(0,r.jsxs)("div",{className:"grid gap-4 md:grid-cols-2",children:[(0,r.jsx)(j,{label:"Bind address",hint:"127.0.0.1 = local only. Use 0.0.0.0 or a LAN IP for other workstations. The only setting that needs Save & Restart while the proxy runs — a bound socket cannot move.",children:(0,r.jsx)("input",{value:s.bindHost,onChange:e=>q("bindHost",e.target.value),className:`rounded-lg border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary ${_?"border-amber-500/50":"border-border"}`})}),(0,r.jsx)(j,{label:"Proxy port",hint:"Default 3128; Docker deployments must publish this port explicitly. Also needs Save & Restart to take effect.",children:(0,r.jsx)("input",{type:"number",min:"1",max:"65535",value:s.port,onChange:e=>q("port",Number(e.target.value)),className:`rounded-lg border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary ${_?"border-amber-500/50":"border-border"}`})}),(0,r.jsx)(j,{label:"Client proxy host",hint:"Manual persistent hostname/IP used only in deployment commands; it does not change the listener.",children:(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)("input",{value:s.clientProxyHost||"",onChange:e=>q("clientProxyHost",e.target.value),placeholder:"172.16.6.8 or proxy.example.local",className:"min-w-0 flex-1 rounded-lg border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary"}),(0,r.jsx)("button",{type:"button",onClick:U,disabled:!!l||H,className:"shrink-0 rounded-lg border border-primary/30 bg-primary/10 px-3 py-2 text-xs font-semibold text-primary disabled:opacity-50",children:"save-client-host"===l?"Saving…":"Save host"})]})}),(0,r.jsx)(j,{label:"Capture limit / request",hint:"Traffic streams immediately; only this bounded prefix is retained for audit.",children:(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)("input",{type:"number",min:"0",max:"16",step:"0.5",value:X,onChange:e=>q("captureLimitBytes",Math.round(1024*Number(e.target.value)*1024)),disabled:!s.captureBodies,className:"min-w-0 flex-1 rounded-lg border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary disabled:opacity-60"}),(0,r.jsx)("span",{className:"text-xs text-text-muted",children:"MB"})]})})]}),(0,r.jsxs)("div",{className:"mt-4 grid gap-3 md:grid-cols-2",children:[(0,r.jsx)(f,{label:"Pass through non-audited hosts",description:"Unknown hosts use a blind TLS tunnel only when they resolve to public addresses on TCP 443. Private/reserved destinations are denied.",checked:s.passthroughUnknown,onChange:e=>q("passthroughUnknown",e)}),(0,r.jsx)(f,{label:"Capture request/response bodies",description:"Credentials are redacted before persistence. Disable to retain metadata and wire hashes only.",checked:s.captureBodies,onChange:e=>q("captureBodies",e)})]}),(0,r.jsxs)("div",{className:"mt-4 grid gap-3",children:[(0,r.jsx)(f,{label:"Restrict which client tools may connect",description:"Refuses a CONNECT whose User-Agent identifies a tool that is not listed. Catches a browser pointed at the proxy, or a script that inherited HTTPS_PROXY. It cannot catch a client that sends no User-Agent — Claude Code sends none at all and Codex only on its first tunnel, so those are always let through, and anyone can do the same by dropping the header. Hygiene, not access control: the client IP allowlist and who holds the root CA are what bound access.",checked:!0===s.clientToolFilterEnabled,onChange:e=>q("clientToolFilterEnabled",e)}),s.clientToolFilterEnabled?(0,r.jsxs)("div",{className:"grid gap-2",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-1.5",children:[(0,r.jsx)("span",{className:"text-[11px] font-medium text-text-muted",children:"Add:"}),p.map(e=>(0,r.jsx)("button",{type:"button",disabled:(s.allowedClientTools||[]).includes(e.id),onClick:()=>q("allowedClientTools",[...new Set([...s.allowedClientTools||[],e.id])]),className:"rounded-lg border border-border px-2 py-1 text-[11px] text-text-muted transition hover:border-primary hover:text-primary disabled:opacity-40",children:e.label},e.id))]}),(0,r.jsx)(j,{label:"Allowed client tools",hint:"One entry per line: a preset id above, or any substring matched against the User-Agent. Only clients that send a User-Agent are checked. Refused connections appear in the audit table with the User-Agent that was rejected, so you can add what you actually use.",children:(0,r.jsx)("textarea",{rows:4,value:(s.allowedClientTools||[]).join("\n"),onChange:e=>q("allowedClientTools",e.target.value.split(/\r?\n/).map(e=>e.trim().toLowerCase()).filter(Boolean)),disabled:O,placeholder:"claude-code\ncodex",className:"rounded-lg border border-border bg-background px-3 py-2 font-mono text-xs text-text-main outline-none focus:border-primary disabled:opacity-60"})})]}):null]}),(0,r.jsxs)("div",{className:"mt-4 grid gap-4 md:grid-cols-[1fr_190px]",children:[(0,r.jsx)(j,{label:"TLS inspection allowlist",hint:"One hostname/wildcard per line. Only these public HTTPS hosts are decrypted and audited.",children:(0,r.jsx)("textarea",{rows:9,value:L,onChange:e=>q("allowedHosts",e.target.value.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)),className:"rounded-lg border border-border bg-background px-3 py-2 font-mono text-xs text-text-main outline-none focus:border-primary disabled:opacity-60"})}),(0,r.jsxs)("div",{className:"grid content-start gap-4",children:[(0,r.jsx)(j,{label:"Retention",hint:"Daily local JSONL segments older than this value are deleted hourly.",children:(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)("input",{type:"number",min:"1",max:"365",value:s.retentionDays,onChange:e=>q("retentionDays",Number(e.target.value)),className:"min-w-0 flex-1 rounded-lg border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary disabled:opacity-60"}),(0,r.jsx)("span",{className:"text-xs text-text-muted",children:"days"})]})}),(0,r.jsxs)("div",{className:"rounded-xl border border-green-500/20 bg-green-500/5 p-3 text-xs leading-5 text-text-muted",children:[(0,r.jsx)("div",{className:"font-semibold text-green-600 dark:text-green-400",children:"Transport controls enforced"}),"TLS verification ON \xb7 HTTP/1.1 \xb7 HTTPS CONNECT only \xb7 public TCP 443 only."]})]})]}),(0,r.jsxs)("div",{className:"mt-4 flex flex-wrap items-center gap-2",children:[(0,r.jsx)("button",{type:"button",onClick:F,disabled:!!l||H,className:"rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-white disabled:opacity-50",children:"save"===l?"Saving…":O?"Save & apply":"Save"}),O?(0,r.jsx)("button",{type:"button",onClick:()=>D("stop"),disabled:!!l,className:"rounded-lg border border-red-500/30 bg-red-500/10 px-4 py-2 text-sm font-semibold text-red-500 disabled:opacity-50",children:"stop"===l?"Stopping…":"Stop Proxy"}):(0,r.jsx)("button",{type:"button",onClick:()=>D("start",{config:s}),disabled:!!l,className:"rounded-lg border border-green-500/30 bg-green-500/10 px-4 py-2 text-sm font-semibold text-green-600 disabled:opacity-50",children:"start"===l?"Starting…":"Start Proxy"}),(0,r.jsx)("button",{type:"button",onClick:()=>D("restart",{config:s}),disabled:!!l,className:"rounded-lg border border-border px-4 py-2 text-sm font-semibold text-text-main hover:bg-background disabled:opacity-50",children:"restart"===l?"Restarting…":"Save & Restart"}),(0,r.jsx)("button",{type:"button",onClick:()=>D("test"),disabled:!!l,className:"rounded-lg border border-primary/30 bg-primary/10 px-4 py-2 text-sm font-semibold text-primary disabled:opacity-50",children:"test"===l?"Testing…":"Run Simulated Test"}),(0,r.jsx)("span",{className:"text-[11px] leading-4 text-text-muted",children:"Save applies to the running proxy immediately — open tunnels keep streaming. Restart is only for the bind address and port."})]})]}),(0,r.jsxs)("div",{className:"space-y-4",children:[(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Root CA"}),(0,r.jsx)("p",{className:"mt-1 text-xs leading-5 text-text-muted",children:"The existing Root CA/key pair is validated and reused. Audit Proxy never auto-rotates enterprise CA material."}),(0,r.jsxs)("div",{className:"mt-3 grid gap-2 text-xs",children:[(0,r.jsxs)("div",{className:"flex justify-between gap-3",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Status"}),(0,r.jsx)("span",{className:"font-medium text-text-main",children:$.validated?"Validated":$.certExists?"Needs attention":"Not generated"})]}),$.subject?(0,r.jsxs)("div",{className:"grid gap-1",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Subject"}),(0,r.jsx)("span",{className:"break-all font-mono text-[11px] text-text-main",children:$.subject})]}):null,$.fingerprint?(0,r.jsxs)("div",{className:"grid gap-1",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Public key fingerprint"}),(0,r.jsx)("span",{className:"break-all font-mono text-[11px] text-text-main",children:$.fingerprint})]}):null,$.notAfter?(0,r.jsxs)("div",{className:"flex justify-between gap-3",children:[(0,r.jsx)("span",{className:"text-text-muted",children:"Expires"}),(0,r.jsx)("span",{className:"text-text-main",children:new Date($.notAfter).toLocaleString()})]}):null,$.error?(0,r.jsx)("div",{className:"rounded-lg bg-red-500/10 p-2 text-red-600 dark:text-red-300",children:$.error}):null]}),(0,r.jsxs)("div",{className:"mt-4 flex flex-wrap gap-2",children:[(0,r.jsx)("button",{type:"button",onClick:B,disabled:!!l,className:"rounded-lg border border-border px-3 py-2 text-xs font-semibold text-text-main hover:bg-background disabled:opacity-50",children:$.certExists?"Validate / Reuse CA":"Generate CA"}),(0,r.jsx)("a",{href:"/api/audit-proxy/ca?download=cert",className:`rounded-lg border border-primary/30 bg-primary/10 px-3 py-2 text-xs font-semibold text-primary ${!$.certExists?"pointer-events-none opacity-50":""}`,children:"Download Root CA"}),(0,r.jsx)(d(),{href:"/dashboard/mitm",className:"rounded-lg border border-border px-3 py-2 text-xs font-semibold text-text-main hover:bg-background",children:"Advanced CA management"})]})]}),(0,r.jsx)(c.Ay,{clientProxyHost:s.clientProxyHost,port:s.port,onError:w})]})]}),S?(0,r.jsxs)("section",{className:`rounded-2xl border p-4 ${S.ok?"border-green-500/30 bg-green-500/5":"border-red-500/30 bg-red-500/5"}`,children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,r.jsxs)("div",{children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Simulated end-to-end test"}),(0,r.jsx)("p",{className:"mt-1 text-xs text-text-muted",children:"Local throwaway TLS endpoints; no cloud credential or external API call is used."})]}),(0,r.jsxs)(u,{ok:S.ok,children:[S.passed,"/",S.total," passed \xb7 ",S.durationMs," ms"]})]}),(0,r.jsx)("div",{className:"mt-3 grid gap-2 md:grid-cols-2 xl:grid-cols-3",children:S.checks?.map(e=>(0,r.jsxs)("div",{className:"flex items-start gap-2 rounded-lg border border-border/70 bg-background/60 px-3 py-2 text-xs",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[16px] ${e.ok?"text-green-500":"text-red-500"}`,children:e.ok?"check_circle":"error"}),(0,r.jsxs)("span",{children:[(0,r.jsx)("span",{className:"font-medium text-text-main",children:e.name}),e.detail?(0,r.jsx)("span",{className:"mt-0.5 block text-text-muted",children:e.detail}):null]})]},e.name))})]}):null,(0,r.jsx)(i,{onChanged:()=>R(!0)}),I.proxyAuthFeatureEnabled?(0,r.jsx)(o,{}):null]}),(0,r.jsxs)("div",{className:"audit"===T?"space-y-4":"hidden",children:[(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,r.jsxs)("div",{children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Token usage"}),(0,r.jsxs)("p",{className:"mt-1 text-xs text-text-muted",children:["Counts are read out of the audited provider responses themselves — ",(0,r.jsx)("code",{className:"font-mono",children:"message_start"})," carries input and cache tokens, the closing ",(0,r.jsx)("code",{className:"font-mono",children:"message_delta"})," carries output. Scope is the same window as the table below."]})]}),e?.usageSummary?.incompleteUsageCount?(0,r.jsxs)("span",{className:"rounded-lg border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[11px] font-medium text-amber-700 dark:text-amber-300",children:[e.usageSummary.incompleteUsageCount," response(s) truncated before the final usage event — output tokens under-counted"]}):null]}),e?.usageSummary?.totals?.requests?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("div",{className:"mt-3 grid gap-2 sm:grid-cols-2 lg:grid-cols-5",children:[(0,r.jsx)(g,{label:"Requests with usage",value:e.usageSummary.totals.requests}),(0,r.jsx)(g,{label:"Input",value:h(e.usageSummary.totals.inputTokens),hint:"new (uncached) input tokens"}),(0,r.jsx)(g,{label:"Output",value:h(e.usageSummary.totals.outputTokens)}),(0,r.jsx)(g,{label:"Cache read / write",value:`${h(e.usageSummary.totals.cacheReadTokens)} / ${h(e.usageSummary.totals.cacheCreationTokens)}`}),(0,r.jsx)(g,{label:"Est. cost",value:b(e.usageSummary.totals.cost),hint:"from the pricing table"})]}),(0,r.jsxs)("div",{className:"mt-4 grid gap-5 lg:grid-cols-2",children:[(0,r.jsx)(y,{title:"By model",rows:e.usageSummary.byModel}),(0,r.jsx)(y,{title:"By client tool",rows:e.usageSummary.bySourceTool})]})]}):(0,r.jsx)("p",{className:"mt-3 rounded-xl border border-border bg-background/50 p-3 text-xs text-text-muted",children:"No token usage recorded yet. Usage appears once an audited request reaches a provider that reports it (Anthropic and OpenAI both do)."})]}),(0,r.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-4",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,r.jsxs)("div",{children:[(0,r.jsx)("h2",{className:"font-semibold text-text-main",children:"Recent audit requests"}),(0,r.jsx)("p",{className:"mt-1 text-xs text-text-muted",children:"Credentials are redacted before persistence. Local writes and MySQL mirroring run through a bounded asynchronous queue."})]}),(0,r.jsxs)("div",{className:"flex items-center gap-3 text-xs text-text-muted",children:[(0,r.jsxs)("span",{children:["Queue ",E.auditStore?.queueDepth||0,"/",E.auditStore?.queueLimit||1e3]}),(0,r.jsx)("button",{type:"button",onClick:()=>D("clear-logs"),disabled:!!l||H,className:"rounded-lg border border-border px-3 py-1.5 hover:bg-background disabled:opacity-50",children:"Clear logs"})]})]}),(0,r.jsx)("div",{className:"mt-3 overflow-x-auto",children:(0,r.jsxs)("table",{className:"w-full min-w-[1250px] text-left text-xs",children:[(0,r.jsx)("thead",{className:"border-b border-border text-text-muted",children:(0,r.jsxs)("tr",{children:[(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Time"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Protocol"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Client"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"User"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Provider"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Host"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Model"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Request"}),(0,r.jsx)("th",{className:"px-2 py-2 text-right font-medium",children:"Tokens (in/out)"}),(0,r.jsx)("th",{className:"px-2 py-2 text-right font-medium",children:"Cache (r/w)"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Status"}),(0,r.jsx)("th",{className:"px-2 py-2 font-medium",children:"Latency"})]})}),(0,r.jsxs)("tbody",{children:[(e?.events||[]).map(e=>(0,r.jsxs)("tr",{className:"border-b border-border/60 align-top text-text-main",children:[(0,r.jsx)("td",{className:"whitespace-nowrap px-2 py-2 text-text-muted",children:new Date(e.timestamp).toLocaleTimeString()}),(0,r.jsx)("td",{className:"px-2 py-2",children:e.protocol||"http/1.1"}),(0,r.jsx)("td",{className:"px-2 py-2 font-mono text-[11px]",children:e.client?.ip||"-"}),(0,r.jsx)("td",{className:"px-2 py-2",children:e.client?.proxyUser||"-"}),(0,r.jsx)("td",{className:"px-2 py-2",children:e.provider||"-"}),(0,r.jsx)("td",{className:"px-2 py-2 font-mono text-[11px]",children:e.host||"-"}),(0,r.jsx)("td",{className:"px-2 py-2",children:e.model||"-"}),(0,r.jsx)("td",{className:"max-w-[300px] px-2 py-2",children:(0,r.jsxs)("details",{children:[(0,r.jsxs)("summary",{className:"cursor-pointer truncate",children:[e.method," ",e.path]}),(0,r.jsx)("pre",{className:"mt-2 max-h-72 overflow-auto whitespace-pre-wrap rounded-lg bg-background p-2 text-[10px] leading-4 text-text-muted",children:JSON.stringify({request:e.request,response:e.response,error:e.error},null,2)})]})}),(0,r.jsx)("td",{className:"whitespace-nowrap px-2 py-2 text-right",children:e.usage?(0,r.jsxs)("span",{title:!1===e.usage.complete?"Response was truncated before the final usage event; output is a lower bound":void 0,children:[h(e.usage.inputTokens),"/",h(e.usage.outputTokens),!1===e.usage.complete?(0,r.jsx)("span",{className:"text-amber-600 dark:text-amber-400",children:"*"}):null]}):(0,r.jsx)("span",{className:"text-text-muted",children:"-"})}),(0,r.jsx)("td",{className:"whitespace-nowrap px-2 py-2 text-right text-text-muted",children:e.usage?`${h(e.usage.cacheReadTokens)}/${h(e.usage.cacheCreationTokens)}`:"-"}),(0,r.jsx)("td",{className:"px-2 py-2",children:e.status||"ERR"}),(0,r.jsxs)("td",{className:"whitespace-nowrap px-2 py-2",children:[e.durationMs??"-"," ms"]})]},e.id)),e?.events?.length?null:(0,r.jsx)("tr",{children:(0,r.jsx)("td",{colSpan:"12",className:"px-2 py-8 text-center text-text-muted",children:"No audited requests yet."})})]})]})})]})]})]})}}},e=>{e.O(0,[8500,8441,3794,7358],()=>e(e.s=23371)),_N_E=e.O()}]);
|