effect-start 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -2
- package/src/Entity.ts +6 -6
- package/src/FileRouterCodegen.ts +4 -4
- package/src/FileSystem.ts +4 -8
- package/src/RouteHook.ts +1 -1
- package/src/RouteSse.ts +3 -3
- package/src/SqlIntrospect.ts +2 -2
- package/src/Start.ts +102 -2
- package/src/Values.ts +11 -0
- package/src/bun/BunRoute.ts +1 -1
- package/src/bun/BunRuntime.ts +5 -5
- package/src/hyper/HyperHtml.ts +11 -7
- package/src/hyper/jsx.d.ts +1 -1
- package/src/lint/plugin.js +174 -4
- package/src/sql/SqlClient.ts +355 -0
- package/src/sql/bun/index.ts +117 -50
- package/src/sql/index.ts +1 -1
- package/src/sql/libsql/index.ts +91 -77
- package/src/sql/libsql/libsql.d.ts +4 -1
- package/src/sql/mssql/index.ts +141 -108
- package/src/sql/mssql/mssql.d.ts +1 -0
- package/src/testing/TestLogger.ts +4 -4
- package/src/x/tailwind/compile.ts +6 -14
- package/src/console/Console.ts +0 -42
- package/src/console/ConsoleErrors.ts +0 -213
- package/src/console/ConsoleLogger.ts +0 -56
- package/src/console/ConsoleMetrics.ts +0 -72
- package/src/console/ConsoleProcess.ts +0 -59
- package/src/console/ConsoleStore.ts +0 -187
- package/src/console/ConsoleTracer.ts +0 -107
- package/src/console/Simulation.ts +0 -814
- package/src/console/console.html +0 -340
- package/src/console/index.ts +0 -3
- package/src/console/routes/errors/route.tsx +0 -97
- package/src/console/routes/fiberDetail.tsx +0 -54
- package/src/console/routes/fibers/route.tsx +0 -45
- package/src/console/routes/git/route.tsx +0 -64
- package/src/console/routes/layout.tsx +0 -4
- package/src/console/routes/logs/route.tsx +0 -77
- package/src/console/routes/metrics/route.tsx +0 -36
- package/src/console/routes/route.tsx +0 -8
- package/src/console/routes/routes/route.tsx +0 -30
- package/src/console/routes/services/route.tsx +0 -21
- package/src/console/routes/system/route.tsx +0 -43
- package/src/console/routes/traceDetail.tsx +0 -22
- package/src/console/routes/traces/route.tsx +0 -81
- package/src/console/routes/tree.ts +0 -30
- package/src/console/ui/Errors.tsx +0 -76
- package/src/console/ui/Fibers.tsx +0 -321
- package/src/console/ui/Git.tsx +0 -182
- package/src/console/ui/Logs.tsx +0 -46
- package/src/console/ui/Metrics.tsx +0 -78
- package/src/console/ui/Routes.tsx +0 -125
- package/src/console/ui/Services.tsx +0 -273
- package/src/console/ui/Shell.tsx +0 -62
- package/src/console/ui/System.tsx +0 -131
- package/src/console/ui/Traces.tsx +0 -426
- package/src/sql/Sql.ts +0 -51
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
import * as Option from "effect/Option"
|
|
2
|
-
|
|
3
|
-
const EffectTypeIds: Record<symbol, string> = {
|
|
4
|
-
[Symbol.for("effect/Ref")]: "Ref",
|
|
5
|
-
[Symbol.for("effect/SynchronizedRef")]: "SynchronizedRef",
|
|
6
|
-
[Symbol.for("effect/QueueDequeue")]: "Dequeue",
|
|
7
|
-
[Symbol.for("effect/QueueEnqueue")]: "Enqueue",
|
|
8
|
-
[Symbol.for("effect/Pool")]: "Pool",
|
|
9
|
-
[Symbol.for("effect/Deferred")]: "Deferred",
|
|
10
|
-
[Symbol.for("effect/FiberRef")]: "FiberRef",
|
|
11
|
-
[Symbol.for("effect/Scope")]: "Scope",
|
|
12
|
-
[Symbol.for("effect/Tracer")]: "Tracer",
|
|
13
|
-
[Symbol.for("effect/Request/Cache")]: "RequestCache",
|
|
14
|
-
[Symbol.for("effect/Logger")]: "Logger",
|
|
15
|
-
[Symbol.for("effect/Supervisor")]: "Supervisor",
|
|
16
|
-
[Symbol.for("effect/Clock")]: "Clock",
|
|
17
|
-
[Symbol.for("effect/Random")]: "Random",
|
|
18
|
-
[Symbol.for("effect/KeyValueStore")]: "KeyValueStore",
|
|
19
|
-
[Symbol.for("effect/RateLimiter")]: "RateLimiter",
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function detectEffectType(value: unknown): string | undefined {
|
|
23
|
-
if (value === null || value === undefined || typeof value !== "object") return undefined
|
|
24
|
-
if ("publish" in value && "subscribe" in value && "offer" in value) return "PubSub"
|
|
25
|
-
for (const sym of Object.getOwnPropertySymbols(value)) {
|
|
26
|
-
const name = EffectTypeIds[sym]
|
|
27
|
-
if (name) return name
|
|
28
|
-
}
|
|
29
|
-
return undefined
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function inspectEffectValue(type: string, value: any): Record<string, unknown> {
|
|
33
|
-
const info: Record<string, unknown> = { _type: type }
|
|
34
|
-
try {
|
|
35
|
-
switch (type) {
|
|
36
|
-
case "PubSub": {
|
|
37
|
-
if (typeof value.capacity === "function") info.capacity = value.capacity()
|
|
38
|
-
if (typeof value.isActive === "function") info.active = value.isActive()
|
|
39
|
-
if (typeof value.unsafeSize === "function") {
|
|
40
|
-
const size = value.unsafeSize()
|
|
41
|
-
info.size = Option.isSome(size) ? size.value : "shutdown"
|
|
42
|
-
}
|
|
43
|
-
if (value.pubsub && typeof value.pubsub.subscriberCount === "number") {
|
|
44
|
-
info.subscribers = value.pubsub.subscriberCount
|
|
45
|
-
}
|
|
46
|
-
break
|
|
47
|
-
}
|
|
48
|
-
case "Enqueue":
|
|
49
|
-
case "Dequeue": {
|
|
50
|
-
if (typeof value.capacity === "function") info.capacity = value.capacity()
|
|
51
|
-
if (typeof value.isActive === "function") info.active = value.isActive()
|
|
52
|
-
if (typeof value.unsafeSize === "function") {
|
|
53
|
-
const size = value.unsafeSize()
|
|
54
|
-
info.size = Option.isSome(size) ? size.value : "shutdown"
|
|
55
|
-
}
|
|
56
|
-
break
|
|
57
|
-
}
|
|
58
|
-
case "Ref":
|
|
59
|
-
case "SynchronizedRef": {
|
|
60
|
-
if (value.ref && "current" in value.ref) {
|
|
61
|
-
const current = value.ref.current
|
|
62
|
-
info.value = safeSerialize(current)
|
|
63
|
-
}
|
|
64
|
-
break
|
|
65
|
-
}
|
|
66
|
-
case "Pool": {
|
|
67
|
-
if (typeof value.minSize === "number") info.minSize = value.minSize
|
|
68
|
-
if (typeof value.maxSize === "number") info.maxSize = value.maxSize
|
|
69
|
-
if (typeof value.concurrency === "number") info.concurrency = value.concurrency
|
|
70
|
-
if (value.items instanceof Set) info.items = value.items.size
|
|
71
|
-
if (value.available instanceof Set) info.available = value.available.size
|
|
72
|
-
if (value.invalidated instanceof Set) info.invalidated = value.invalidated.size
|
|
73
|
-
if (typeof value.waiters === "number") info.waiters = value.waiters
|
|
74
|
-
break
|
|
75
|
-
}
|
|
76
|
-
case "FiberRef": {
|
|
77
|
-
if ("initial" in value) info.initial = safeSerialize(value.initial)
|
|
78
|
-
break
|
|
79
|
-
}
|
|
80
|
-
case "Deferred": {
|
|
81
|
-
if ("state" in value && value.state) {
|
|
82
|
-
const state = value.state
|
|
83
|
-
if (typeof state === "object" && "_tag" in state) {
|
|
84
|
-
info.status = state._tag
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
break
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
} catch {
|
|
91
|
-
// ignore introspection errors
|
|
92
|
-
}
|
|
93
|
-
return info
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function safeSerialize(value: unknown): unknown {
|
|
97
|
-
if (value === null || value === undefined) return value
|
|
98
|
-
if (typeof value === "bigint") return `${value}n`
|
|
99
|
-
if (typeof value === "function") return "<function>"
|
|
100
|
-
if (typeof value === "symbol") return value.toString()
|
|
101
|
-
if (typeof value !== "object") return value
|
|
102
|
-
if (detectEffectType(value)) return `<${detectEffectType(value)}>`
|
|
103
|
-
if (Array.isArray(value)) return value.map(safeSerialize)
|
|
104
|
-
const proto = Object.getPrototypeOf(value)
|
|
105
|
-
if (proto !== null && proto !== Object.prototype)
|
|
106
|
-
return `<${proto.constructor?.name ?? "object"}>`
|
|
107
|
-
const out: Record<string, unknown> = {}
|
|
108
|
-
for (const [k, v] of Object.entries(value)) {
|
|
109
|
-
if (typeof v === "function") continue
|
|
110
|
-
out[k] = safeSerialize(v)
|
|
111
|
-
}
|
|
112
|
-
return out
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface ServiceEntry {
|
|
116
|
-
readonly key: string
|
|
117
|
-
readonly kind: string
|
|
118
|
-
readonly display: string
|
|
119
|
-
readonly type: "config" | "value" | "effect"
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function isJsonPrimitive(value: unknown): boolean {
|
|
123
|
-
if (value === null) return true
|
|
124
|
-
const t = typeof value
|
|
125
|
-
return t === "string" || t === "number" || t === "boolean" || t === "bigint"
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function isPlainJson(value: unknown): boolean {
|
|
129
|
-
if (isJsonPrimitive(value)) return true
|
|
130
|
-
if (Array.isArray(value)) return value.every(isPlainJson)
|
|
131
|
-
if (typeof value === "object" && value !== null) {
|
|
132
|
-
const proto = Object.getPrototypeOf(value)
|
|
133
|
-
if (proto !== null && proto !== Object.prototype) return false
|
|
134
|
-
return Object.values(value).every(isPlainJson)
|
|
135
|
-
}
|
|
136
|
-
return false
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function jsonReplacer(_key: string, v: unknown): unknown {
|
|
140
|
-
if (typeof v === "bigint") return `${v}n`
|
|
141
|
-
return v
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function collectDisplayValues(obj: unknown, prefix: string, out: Record<string, unknown>): void {
|
|
145
|
-
if (typeof obj === "function") return
|
|
146
|
-
if (isJsonPrimitive(obj) || Array.isArray(obj)) {
|
|
147
|
-
out[prefix] = safeSerialize(obj)
|
|
148
|
-
return
|
|
149
|
-
}
|
|
150
|
-
if (typeof obj === "object" && obj !== null) {
|
|
151
|
-
const et = detectEffectType(obj)
|
|
152
|
-
if (et) {
|
|
153
|
-
out[prefix || et] = inspectEffectValue(et, obj)
|
|
154
|
-
return
|
|
155
|
-
}
|
|
156
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
157
|
-
if (typeof v === "function") continue
|
|
158
|
-
const path = prefix ? `${prefix}.${k}` : k
|
|
159
|
-
if (isPlainJson(v)) {
|
|
160
|
-
out[path] = safeSerialize(v)
|
|
161
|
-
} else if (typeof v === "object" && v !== null) {
|
|
162
|
-
collectDisplayValues(v, path, out)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function kindColor(kind: string): { bg: string; fg: string } {
|
|
169
|
-
if (kind === "config") return { bg: "#2d1f0e", fg: "#fbbf24" }
|
|
170
|
-
if (kind === "effect") return { bg: "#2d1a3e", fg: "#c084fc" }
|
|
171
|
-
if (kind === "empty") return { bg: "#1f2937", fg: "#64748b" }
|
|
172
|
-
if (kind === "function") return { bg: "#1a2e1a", fg: "#4ade80" }
|
|
173
|
-
return { bg: "#1e3a5f", fg: "#60a5fa" }
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function ServiceRow({ entry }: { entry: ServiceEntry }) {
|
|
177
|
-
const colors = kindColor(entry.type)
|
|
178
|
-
return (
|
|
179
|
-
<details class="tl-row">
|
|
180
|
-
<summary class="tl-summary tl-cols">
|
|
181
|
-
<span class="tl-cell tl-cell-status">
|
|
182
|
-
<span
|
|
183
|
-
style={`width:8px;height:8px;border-radius:50%;background:${colors.fg};display:block`}
|
|
184
|
-
/>
|
|
185
|
-
</span>
|
|
186
|
-
<span class="tl-cell tl-cell-name">{entry.key}</span>
|
|
187
|
-
<span class="tl-cell tl-cell-dur">
|
|
188
|
-
<span
|
|
189
|
-
style={`font-size:10px;padding:1px 6px;border-radius:4px;background:${colors.bg};color:${colors.fg}`}
|
|
190
|
-
>
|
|
191
|
-
{entry.kind}
|
|
192
|
-
</span>
|
|
193
|
-
</span>
|
|
194
|
-
</summary>
|
|
195
|
-
<div class="tl-body">
|
|
196
|
-
{entry.display ? (
|
|
197
|
-
<pre style="color:#e2e8f0;font-family:monospace;font-size:12px;margin:0;padding:8px;white-space:pre-wrap;word-break:break-all">
|
|
198
|
-
{entry.display}
|
|
199
|
-
</pre>
|
|
200
|
-
) : (
|
|
201
|
-
<div style="padding:4px 8px;color:#64748b;font-size:12px">No inspectable values</div>
|
|
202
|
-
)}
|
|
203
|
-
</div>
|
|
204
|
-
</details>
|
|
205
|
-
)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export function ServiceList({ services }: { services: Array<ServiceEntry> }) {
|
|
209
|
-
if (services.length === 0) {
|
|
210
|
-
return <div class="empty">No services registered</div>
|
|
211
|
-
}
|
|
212
|
-
return (
|
|
213
|
-
<div class="tl-grid">
|
|
214
|
-
<div class="tl-header tl-cols">
|
|
215
|
-
<span class="tl-cell tl-cell-status" />
|
|
216
|
-
<span class="tl-cell tl-cell-name">Service</span>
|
|
217
|
-
<span class="tl-cell tl-cell-dur">Kind</span>
|
|
218
|
-
</div>
|
|
219
|
-
{services.map((s) => (
|
|
220
|
-
<ServiceRow entry={s} />
|
|
221
|
-
))}
|
|
222
|
-
</div>
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export function collectServices(unsafeMap: Map<string, any>): Array<ServiceEntry> {
|
|
227
|
-
const entries: Array<ServiceEntry> = []
|
|
228
|
-
for (const [key, value] of unsafeMap) {
|
|
229
|
-
const isConfig =
|
|
230
|
-
key.toLowerCase().includes("config") || key.toLowerCase().includes("configuration")
|
|
231
|
-
|
|
232
|
-
const effectType =
|
|
233
|
-
typeof value === "object" && value !== null ? detectEffectType(value) : undefined
|
|
234
|
-
if (effectType) {
|
|
235
|
-
const info = inspectEffectValue(effectType, value)
|
|
236
|
-
entries.push({
|
|
237
|
-
key,
|
|
238
|
-
kind: effectType,
|
|
239
|
-
display: JSON.stringify(info, jsonReplacer, 2),
|
|
240
|
-
type: "effect",
|
|
241
|
-
})
|
|
242
|
-
continue
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (typeof value === "function") {
|
|
246
|
-
entries.push({ key, kind: "function", display: "", type: "value" })
|
|
247
|
-
continue
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (value === null || value === undefined) {
|
|
251
|
-
entries.push({ key, kind: "empty", display: "", type: "value" })
|
|
252
|
-
continue
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const type = isConfig ? ("config" as const) : ("value" as const)
|
|
256
|
-
const plain: Record<string, unknown> = {}
|
|
257
|
-
collectDisplayValues(value, "", plain)
|
|
258
|
-
const display = Object.keys(plain).length > 0 ? JSON.stringify(plain, jsonReplacer, 2) : ""
|
|
259
|
-
|
|
260
|
-
let kind = "object"
|
|
261
|
-
if (typeof value !== "object") {
|
|
262
|
-
kind = typeof value
|
|
263
|
-
} else {
|
|
264
|
-
const proto = Object.getPrototypeOf(value)
|
|
265
|
-
if (proto && proto.constructor && proto.constructor.name !== "Object") {
|
|
266
|
-
kind = proto.constructor.name
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
entries.push({ key, kind: isConfig ? "config" : kind, display, type })
|
|
271
|
-
}
|
|
272
|
-
return entries.sort((a, b) => a.key.localeCompare(b.key))
|
|
273
|
-
}
|
package/src/console/ui/Shell.tsx
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
export type NavTab =
|
|
2
|
-
| "traces"
|
|
3
|
-
| "metrics"
|
|
4
|
-
| "logs"
|
|
5
|
-
| "errors"
|
|
6
|
-
| "fibers"
|
|
7
|
-
| "routes"
|
|
8
|
-
| "system"
|
|
9
|
-
| "services"
|
|
10
|
-
| "git"
|
|
11
|
-
|
|
12
|
-
export function Sidebar({ prefix, active }: { prefix: string; active: NavTab }) {
|
|
13
|
-
return (
|
|
14
|
-
<div class="sidebar">
|
|
15
|
-
<div class="sidebar-title">Effect Console</div>
|
|
16
|
-
<a href={`${prefix}/traces`} class={active === "traces" ? "nav-link active" : "nav-link"}>
|
|
17
|
-
Traces
|
|
18
|
-
</a>
|
|
19
|
-
<a href={`${prefix}/metrics`} class={active === "metrics" ? "nav-link active" : "nav-link"}>
|
|
20
|
-
Metrics
|
|
21
|
-
</a>
|
|
22
|
-
<a href={`${prefix}/logs`} class={active === "logs" ? "nav-link active" : "nav-link"}>
|
|
23
|
-
Logs
|
|
24
|
-
</a>
|
|
25
|
-
<a href={`${prefix}/errors`} class={active === "errors" ? "nav-link active" : "nav-link"}>
|
|
26
|
-
Errors
|
|
27
|
-
</a>
|
|
28
|
-
<a href={`${prefix}/fibers`} class={active === "fibers" ? "nav-link active" : "nav-link"}>
|
|
29
|
-
Fibers
|
|
30
|
-
</a>
|
|
31
|
-
<a href={`${prefix}/routes`} class={active === "routes" ? "nav-link active" : "nav-link"}>
|
|
32
|
-
Routes
|
|
33
|
-
</a>
|
|
34
|
-
<a href={`${prefix}/system`} class={active === "system" ? "nav-link active" : "nav-link"}>
|
|
35
|
-
System
|
|
36
|
-
</a>
|
|
37
|
-
<a href={`${prefix}/services`} class={active === "services" ? "nav-link active" : "nav-link"}>
|
|
38
|
-
Services
|
|
39
|
-
</a>
|
|
40
|
-
<a href={`${prefix}/git`} class={active === "git" ? "nav-link active" : "nav-link"}>
|
|
41
|
-
Git
|
|
42
|
-
</a>
|
|
43
|
-
</div>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function Shell({
|
|
48
|
-
prefix,
|
|
49
|
-
active,
|
|
50
|
-
children,
|
|
51
|
-
}: {
|
|
52
|
-
prefix: string
|
|
53
|
-
active: NavTab
|
|
54
|
-
children: any
|
|
55
|
-
}) {
|
|
56
|
-
return (
|
|
57
|
-
<div class="shell">
|
|
58
|
-
<Sidebar prefix={prefix} active={active} />
|
|
59
|
-
<div class="content">{children}</div>
|
|
60
|
-
</div>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import type * as ConsoleStore from "../ConsoleStore.ts"
|
|
2
|
-
|
|
3
|
-
function formatBytes(bytes: number): string {
|
|
4
|
-
if (bytes < 1024) return `${bytes}B`
|
|
5
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`
|
|
6
|
-
if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)}MB`
|
|
7
|
-
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)}GB`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function formatUptime(seconds: number): string {
|
|
11
|
-
const d = Math.floor(seconds / 86400)
|
|
12
|
-
const h = Math.floor((seconds % 86400) / 3600)
|
|
13
|
-
const m = Math.floor((seconds % 3600) / 60)
|
|
14
|
-
const s = Math.floor(seconds % 60)
|
|
15
|
-
if (d > 0) return `${d}d ${h}h ${m}m`
|
|
16
|
-
if (h > 0) return `${h}h ${m}m ${s}s`
|
|
17
|
-
if (m > 0) return `${m}m ${s}s`
|
|
18
|
-
return `${s}s`
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function StatCard({ label, value, sub }: { label: string; value: string; sub?: string }) {
|
|
22
|
-
return (
|
|
23
|
-
<div style="background:#111827;border:1px solid #374151;border-radius:6px;padding:12px;min-width:180px">
|
|
24
|
-
<div style="color:#9ca3af;font-size:11px;margin-bottom:4px">{label}</div>
|
|
25
|
-
<div style="color:#f3f4f6;font-size:22px;font-weight:700;font-family:monospace">{value}</div>
|
|
26
|
-
{sub && <div style="color:#6b7280;font-size:10px;margin-top:2px">{sub}</div>}
|
|
27
|
-
</div>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function BarMeter({ label, used, total }: { label: string; used: number; total: number }) {
|
|
32
|
-
const pct = total > 0 ? (used / total) * 100 : 0
|
|
33
|
-
const color = pct > 90 ? "#ef4444" : pct > 70 ? "#f59e0b" : "#22c55e"
|
|
34
|
-
return (
|
|
35
|
-
<div style="background:#111827;border:1px solid #374151;border-radius:6px;padding:12px">
|
|
36
|
-
<div style="display:flex;justify-content:space-between;margin-bottom:6px">
|
|
37
|
-
<span style="color:#9ca3af;font-size:11px">{label}</span>
|
|
38
|
-
<span style="color:#e5e7eb;font-size:11px;font-family:monospace">
|
|
39
|
-
{formatBytes(used)} / {formatBytes(total)}
|
|
40
|
-
</span>
|
|
41
|
-
</div>
|
|
42
|
-
<div style="height:8px;background:#1f2937;border-radius:4px;overflow:hidden">
|
|
43
|
-
<div
|
|
44
|
-
style={`width:${pct.toFixed(1)}%;height:100%;background:${color};border-radius:4px;transition:width .3s`}
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
<div style="color:#6b7280;font-size:10px;margin-top:2px;text-align:right">
|
|
48
|
-
{pct.toFixed(1)}%
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function SystemStatsView({ stats }: { stats: ConsoleStore.ProcessStats }) {
|
|
55
|
-
const cpuTotal = stats.cpu.user + stats.cpu.system
|
|
56
|
-
return (
|
|
57
|
-
<>
|
|
58
|
-
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;padding:12px">
|
|
59
|
-
<StatCard
|
|
60
|
-
label="PID"
|
|
61
|
-
value={String(stats.pid)}
|
|
62
|
-
sub={`${stats.system.platform} ${stats.system.arch}`}
|
|
63
|
-
/>
|
|
64
|
-
<StatCard label="Uptime" value={formatUptime(stats.uptime)} />
|
|
65
|
-
<StatCard
|
|
66
|
-
label="CPU Time"
|
|
67
|
-
value={`${(cpuTotal / 1_000_000).toFixed(2)}s`}
|
|
68
|
-
sub={`user ${(stats.cpu.user / 1_000_000).toFixed(2)}s / sys ${(stats.cpu.system / 1_000_000).toFixed(2)}s`}
|
|
69
|
-
/>
|
|
70
|
-
<StatCard
|
|
71
|
-
label="Load Average"
|
|
72
|
-
value={stats.system.loadavg[0].toFixed(2)}
|
|
73
|
-
sub={`${stats.system.loadavg[0].toFixed(2)} / ${stats.system.loadavg[1].toFixed(2)} / ${stats.system.loadavg[2].toFixed(2)} (${stats.system.cpuCount} cores)`}
|
|
74
|
-
/>
|
|
75
|
-
</div>
|
|
76
|
-
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;padding:0 12px 12px">
|
|
77
|
-
<BarMeter label="Heap Memory" used={stats.memory.heapUsed} total={stats.memory.heapTotal} />
|
|
78
|
-
<BarMeter
|
|
79
|
-
label="System Memory"
|
|
80
|
-
used={stats.system.totalmem - stats.system.freemem}
|
|
81
|
-
total={stats.system.totalmem}
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;padding:0 12px 12px">
|
|
85
|
-
<StatCard label="RSS" value={formatBytes(stats.memory.rss)} />
|
|
86
|
-
<StatCard label="Peak RSS" value={formatBytes(stats.resourceUsage.maxRSS)} />
|
|
87
|
-
<StatCard label="External" value={formatBytes(stats.memory.external)} />
|
|
88
|
-
<StatCard label="Array Buffers" value={formatBytes(stats.memory.arrayBuffers)} />
|
|
89
|
-
</div>
|
|
90
|
-
<div style="padding:0 12px 12px">
|
|
91
|
-
<div style="background:#111827;border:1px solid #374151;border-radius:6px;padding:12px">
|
|
92
|
-
<div style="color:#9ca3af;font-size:11px;margin-bottom:8px">Resource Usage</div>
|
|
93
|
-
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:4px">
|
|
94
|
-
<div style="display:flex;justify-content:space-between;font-size:12px">
|
|
95
|
-
<span style="color:#6b7280">Page Faults (minor)</span>
|
|
96
|
-
<span style="color:#e5e7eb;font-family:monospace">
|
|
97
|
-
{stats.resourceUsage.minorPageFault}
|
|
98
|
-
</span>
|
|
99
|
-
</div>
|
|
100
|
-
<div style="display:flex;justify-content:space-between;font-size:12px">
|
|
101
|
-
<span style="color:#6b7280">Page Faults (major)</span>
|
|
102
|
-
<span style="color:#e5e7eb;font-family:monospace">
|
|
103
|
-
{stats.resourceUsage.majorPageFault}
|
|
104
|
-
</span>
|
|
105
|
-
</div>
|
|
106
|
-
<div style="display:flex;justify-content:space-between;font-size:12px">
|
|
107
|
-
<span style="color:#6b7280">FS Reads</span>
|
|
108
|
-
<span style="color:#e5e7eb;font-family:monospace">{stats.resourceUsage.fsRead}</span>
|
|
109
|
-
</div>
|
|
110
|
-
<div style="display:flex;justify-content:space-between;font-size:12px">
|
|
111
|
-
<span style="color:#6b7280">FS Writes</span>
|
|
112
|
-
<span style="color:#e5e7eb;font-family:monospace">{stats.resourceUsage.fsWrite}</span>
|
|
113
|
-
</div>
|
|
114
|
-
<div style="display:flex;justify-content:space-between;font-size:12px">
|
|
115
|
-
<span style="color:#6b7280">Context Switches (vol)</span>
|
|
116
|
-
<span style="color:#e5e7eb;font-family:monospace">
|
|
117
|
-
{stats.resourceUsage.voluntaryContextSwitches}
|
|
118
|
-
</span>
|
|
119
|
-
</div>
|
|
120
|
-
<div style="display:flex;justify-content:space-between;font-size:12px">
|
|
121
|
-
<span style="color:#6b7280">Context Switches (invol)</span>
|
|
122
|
-
<span style="color:#e5e7eb;font-family:monospace">
|
|
123
|
-
{stats.resourceUsage.involuntaryContextSwitches}
|
|
124
|
-
</span>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
129
|
-
</>
|
|
130
|
-
)
|
|
131
|
-
}
|