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
package/src/console/console.html
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html style="height: 100%">
|
|
3
|
-
<head>
|
|
4
|
-
<title>Effect Console</title>
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<script type="module" src="effect-start/datastar"></script>
|
|
7
|
-
<style>
|
|
8
|
-
* {
|
|
9
|
-
margin: 0;
|
|
10
|
-
padding: 0;
|
|
11
|
-
box-sizing: border-box;
|
|
12
|
-
}
|
|
13
|
-
body {
|
|
14
|
-
height: 100%;
|
|
15
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
16
|
-
background: #0f172a;
|
|
17
|
-
color: #e5e7eb;
|
|
18
|
-
}
|
|
19
|
-
.shell {
|
|
20
|
-
display: flex;
|
|
21
|
-
height: 100%;
|
|
22
|
-
}
|
|
23
|
-
.sidebar {
|
|
24
|
-
width: 180px;
|
|
25
|
-
background: #1e293b;
|
|
26
|
-
border-right: 1px solid #334155;
|
|
27
|
-
padding: 16px 0;
|
|
28
|
-
flex-shrink: 0;
|
|
29
|
-
display: flex;
|
|
30
|
-
flex-direction: column;
|
|
31
|
-
}
|
|
32
|
-
.sidebar-title {
|
|
33
|
-
font-size: 14px;
|
|
34
|
-
font-weight: 700;
|
|
35
|
-
color: #f1f5f9;
|
|
36
|
-
padding: 0 16px 16px;
|
|
37
|
-
border-bottom: 1px solid #334155;
|
|
38
|
-
margin-bottom: 8px;
|
|
39
|
-
}
|
|
40
|
-
.nav-link {
|
|
41
|
-
display: block;
|
|
42
|
-
padding: 8px 16px;
|
|
43
|
-
color: #94a3b8;
|
|
44
|
-
text-decoration: none;
|
|
45
|
-
font-size: 13px;
|
|
46
|
-
}
|
|
47
|
-
.nav-link:hover {
|
|
48
|
-
color: #e2e8f0;
|
|
49
|
-
background: #334155;
|
|
50
|
-
}
|
|
51
|
-
.nav-link.active {
|
|
52
|
-
color: #38bdf8;
|
|
53
|
-
background: #0f172a;
|
|
54
|
-
border-right: 2px solid #38bdf8;
|
|
55
|
-
}
|
|
56
|
-
.content {
|
|
57
|
-
flex: 1;
|
|
58
|
-
display: flex;
|
|
59
|
-
flex-direction: column;
|
|
60
|
-
overflow: hidden;
|
|
61
|
-
}
|
|
62
|
-
.tab-header {
|
|
63
|
-
font-size: 15px;
|
|
64
|
-
font-weight: 600;
|
|
65
|
-
padding: 12px 16px;
|
|
66
|
-
border-bottom: 1px solid #1e293b;
|
|
67
|
-
}
|
|
68
|
-
.tab-body {
|
|
69
|
-
flex: 1;
|
|
70
|
-
overflow-y: auto;
|
|
71
|
-
padding: 8px;
|
|
72
|
-
}
|
|
73
|
-
.filter-bar {
|
|
74
|
-
display: flex;
|
|
75
|
-
gap: 8px;
|
|
76
|
-
padding: 8px 16px;
|
|
77
|
-
border-bottom: 1px solid #1e293b;
|
|
78
|
-
}
|
|
79
|
-
.filter-bar select,
|
|
80
|
-
.filter-bar input {
|
|
81
|
-
background: #1e293b;
|
|
82
|
-
border: 1px solid #334155;
|
|
83
|
-
color: #e5e7eb;
|
|
84
|
-
padding: 4px 8px;
|
|
85
|
-
border-radius: 4px;
|
|
86
|
-
font-size: 12px;
|
|
87
|
-
}
|
|
88
|
-
.filter-bar input {
|
|
89
|
-
flex: 1;
|
|
90
|
-
}
|
|
91
|
-
.metrics-grid {
|
|
92
|
-
display: grid;
|
|
93
|
-
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
94
|
-
gap: 12px;
|
|
95
|
-
}
|
|
96
|
-
.empty {
|
|
97
|
-
color: #64748b;
|
|
98
|
-
font-size: 13px;
|
|
99
|
-
text-align: center;
|
|
100
|
-
padding: 48px 0;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/* Waterfall grid */
|
|
104
|
-
.wf-grid {
|
|
105
|
-
display: grid;
|
|
106
|
-
grid-template-columns: minmax(200px, 30%) 1fr;
|
|
107
|
-
font-size: 12px;
|
|
108
|
-
}
|
|
109
|
-
.wf-row {
|
|
110
|
-
display: contents;
|
|
111
|
-
}
|
|
112
|
-
.wf-row:hover > .wf-name,
|
|
113
|
-
.wf-row:hover > .wf-bar-cell {
|
|
114
|
-
background: #1e293b;
|
|
115
|
-
}
|
|
116
|
-
.wf-name {
|
|
117
|
-
padding: 4px 8px;
|
|
118
|
-
font-family: monospace;
|
|
119
|
-
color: #d1d5db;
|
|
120
|
-
white-space: nowrap;
|
|
121
|
-
overflow: hidden;
|
|
122
|
-
text-overflow: ellipsis;
|
|
123
|
-
border-bottom: 1px solid #1e293b;
|
|
124
|
-
position: relative;
|
|
125
|
-
display: flex;
|
|
126
|
-
align-items: center;
|
|
127
|
-
gap: 4px;
|
|
128
|
-
}
|
|
129
|
-
.wf-bar-cell {
|
|
130
|
-
padding: 4px 8px;
|
|
131
|
-
position: relative;
|
|
132
|
-
border-bottom: 1px solid #1e293b;
|
|
133
|
-
display: flex;
|
|
134
|
-
align-items: center;
|
|
135
|
-
}
|
|
136
|
-
.wf-bar {
|
|
137
|
-
height: 14px;
|
|
138
|
-
border-radius: 2px;
|
|
139
|
-
position: absolute;
|
|
140
|
-
min-width: 2px;
|
|
141
|
-
top: 50%;
|
|
142
|
-
transform: translateY(-50%);
|
|
143
|
-
}
|
|
144
|
-
.wf-dur {
|
|
145
|
-
position: absolute;
|
|
146
|
-
color: #9ca3af;
|
|
147
|
-
font-family: monospace;
|
|
148
|
-
font-size: 11px;
|
|
149
|
-
white-space: nowrap;
|
|
150
|
-
top: 50%;
|
|
151
|
-
transform: translateY(-50%);
|
|
152
|
-
}
|
|
153
|
-
.wf-axis {
|
|
154
|
-
display: grid;
|
|
155
|
-
grid-template-columns: minmax(200px, 30%) 1fr;
|
|
156
|
-
border-bottom: 1px solid #334155;
|
|
157
|
-
font-size: 11px;
|
|
158
|
-
color: #64748b;
|
|
159
|
-
font-family: monospace;
|
|
160
|
-
}
|
|
161
|
-
.wf-axis-ticks {
|
|
162
|
-
display: flex;
|
|
163
|
-
justify-content: space-between;
|
|
164
|
-
padding: 4px 8px;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/* Tree connectors */
|
|
168
|
-
.wf-tree {
|
|
169
|
-
position: relative;
|
|
170
|
-
display: flex;
|
|
171
|
-
align-items: center;
|
|
172
|
-
gap: 4px;
|
|
173
|
-
flex-shrink: 0;
|
|
174
|
-
}
|
|
175
|
-
.wf-vline {
|
|
176
|
-
position: absolute;
|
|
177
|
-
width: 1px;
|
|
178
|
-
background: #475569;
|
|
179
|
-
top: -4px;
|
|
180
|
-
bottom: -4px;
|
|
181
|
-
}
|
|
182
|
-
.wf-branch {
|
|
183
|
-
position: absolute;
|
|
184
|
-
height: 1px;
|
|
185
|
-
background: #475569;
|
|
186
|
-
width: 8px;
|
|
187
|
-
}
|
|
188
|
-
.wf-elbow {
|
|
189
|
-
position: absolute;
|
|
190
|
-
width: 1px;
|
|
191
|
-
background: #475569;
|
|
192
|
-
top: -4px;
|
|
193
|
-
bottom: 50%;
|
|
194
|
-
}
|
|
195
|
-
.wf-hline {
|
|
196
|
-
position: absolute;
|
|
197
|
-
height: 1px;
|
|
198
|
-
background: #475569;
|
|
199
|
-
width: 8px;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/* Child count badge */
|
|
203
|
-
.wf-badge {
|
|
204
|
-
font-size: 10px;
|
|
205
|
-
padding: 0 5px;
|
|
206
|
-
border-radius: 8px;
|
|
207
|
-
background: #1e293b;
|
|
208
|
-
color: #64748b;
|
|
209
|
-
flex-shrink: 0;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/* Mini waterfall */
|
|
213
|
-
.mini-wf {
|
|
214
|
-
height: 20px;
|
|
215
|
-
background: #1f2937;
|
|
216
|
-
border-radius: 3px;
|
|
217
|
-
position: relative;
|
|
218
|
-
overflow: hidden;
|
|
219
|
-
}
|
|
220
|
-
.mini-wf-bar {
|
|
221
|
-
position: absolute;
|
|
222
|
-
height: 6px;
|
|
223
|
-
border-radius: 1px;
|
|
224
|
-
min-width: 2px;
|
|
225
|
-
top: 50%;
|
|
226
|
-
transform: translateY(-50%);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/* Trace cards */
|
|
230
|
-
.trace-card {
|
|
231
|
-
display: block;
|
|
232
|
-
margin-bottom: 8px;
|
|
233
|
-
background: #111827;
|
|
234
|
-
border: 1px solid #1e293b;
|
|
235
|
-
border-radius: 6px;
|
|
236
|
-
overflow: hidden;
|
|
237
|
-
text-decoration: none;
|
|
238
|
-
color: inherit;
|
|
239
|
-
transition: border-color 0.15s;
|
|
240
|
-
}
|
|
241
|
-
.trace-card:hover {
|
|
242
|
-
border-color: #475569;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/* Trace list */
|
|
246
|
-
.tl-grid {
|
|
247
|
-
font-size: 12px;
|
|
248
|
-
}
|
|
249
|
-
.tl-cols {
|
|
250
|
-
display: grid;
|
|
251
|
-
grid-template-columns: 24px 1fr 48px 72px 90px;
|
|
252
|
-
}
|
|
253
|
-
.tl-header {
|
|
254
|
-
position: sticky;
|
|
255
|
-
top: 0;
|
|
256
|
-
z-index: 1;
|
|
257
|
-
background: #0f172a;
|
|
258
|
-
border-bottom: 1px solid #334155;
|
|
259
|
-
color: #64748b;
|
|
260
|
-
font-size: 11px;
|
|
261
|
-
}
|
|
262
|
-
.tl-row {
|
|
263
|
-
border-bottom: 1px solid #1e293b;
|
|
264
|
-
}
|
|
265
|
-
.tl-row[open] {
|
|
266
|
-
background: #111827;
|
|
267
|
-
}
|
|
268
|
-
.tl-summary {
|
|
269
|
-
cursor: pointer;
|
|
270
|
-
user-select: none;
|
|
271
|
-
list-style: none;
|
|
272
|
-
}
|
|
273
|
-
.tl-summary::-webkit-details-marker {
|
|
274
|
-
display: none;
|
|
275
|
-
}
|
|
276
|
-
.tl-summary:hover {
|
|
277
|
-
background: #1e293b;
|
|
278
|
-
}
|
|
279
|
-
.tl-cell {
|
|
280
|
-
padding: 6px 8px;
|
|
281
|
-
display: flex;
|
|
282
|
-
align-items: center;
|
|
283
|
-
overflow: hidden;
|
|
284
|
-
}
|
|
285
|
-
.tl-cell-name {
|
|
286
|
-
font-family: monospace;
|
|
287
|
-
color: #e2e8f0;
|
|
288
|
-
font-weight: 600;
|
|
289
|
-
white-space: nowrap;
|
|
290
|
-
text-overflow: ellipsis;
|
|
291
|
-
}
|
|
292
|
-
.tl-cell-spans {
|
|
293
|
-
color: #64748b;
|
|
294
|
-
font-size: 11px;
|
|
295
|
-
justify-content: flex-end;
|
|
296
|
-
}
|
|
297
|
-
.tl-cell-dur {
|
|
298
|
-
color: #64748b;
|
|
299
|
-
font-family: monospace;
|
|
300
|
-
font-size: 11px;
|
|
301
|
-
justify-content: flex-end;
|
|
302
|
-
}
|
|
303
|
-
.tl-cell-id {
|
|
304
|
-
color: #475569;
|
|
305
|
-
font-family: monospace;
|
|
306
|
-
font-size: 10px;
|
|
307
|
-
}
|
|
308
|
-
.tl-body {
|
|
309
|
-
padding: 8px 12px 12px;
|
|
310
|
-
border-top: 1px solid #1e293b;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/* Span detail panel */
|
|
314
|
-
.span-panel {
|
|
315
|
-
background: #111827;
|
|
316
|
-
border: 1px solid #1e293b;
|
|
317
|
-
border-radius: 6px;
|
|
318
|
-
overflow: hidden;
|
|
319
|
-
margin: 4px 0;
|
|
320
|
-
}
|
|
321
|
-
.span-panel-header {
|
|
322
|
-
padding: 6px 12px;
|
|
323
|
-
display: flex;
|
|
324
|
-
align-items: center;
|
|
325
|
-
gap: 8px;
|
|
326
|
-
cursor: pointer;
|
|
327
|
-
user-select: none;
|
|
328
|
-
}
|
|
329
|
-
.span-panel-header:hover {
|
|
330
|
-
background: #1e293b;
|
|
331
|
-
}
|
|
332
|
-
.span-panel-body {
|
|
333
|
-
padding: 0 12px 8px;
|
|
334
|
-
}
|
|
335
|
-
</style>
|
|
336
|
-
</head>
|
|
337
|
-
<body>
|
|
338
|
-
%children%
|
|
339
|
-
</body>
|
|
340
|
-
</html>
|
package/src/console/index.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import * as Stream from "effect/Stream"
|
|
2
|
-
import * as Route from "../../../Route.ts"
|
|
3
|
-
import * as HyperHtml from "../../../hyper/HyperHtml.ts"
|
|
4
|
-
import * as HyperRoute from "../../../hyper/HyperRoute.ts"
|
|
5
|
-
import * as ConsoleStore from "../../ConsoleStore.ts"
|
|
6
|
-
import * as Errors from "../../ui/Errors.tsx"
|
|
7
|
-
import * as Shell from "../../ui/Shell.tsx"
|
|
8
|
-
|
|
9
|
-
const prefix = ConsoleStore.store.prefix
|
|
10
|
-
|
|
11
|
-
function collectTags(): Array<string> {
|
|
12
|
-
const tags = new Set<string>()
|
|
13
|
-
for (const error of ConsoleStore.store.errors.toArray()) {
|
|
14
|
-
for (const d of error.details) {
|
|
15
|
-
if (d.tag) tags.add(d.tag)
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return Array.from(tags).sort()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function filterErrors(url: URL): Array<ConsoleStore.ConsoleError> {
|
|
22
|
-
const search = url.searchParams.get("errorSearch") || ""
|
|
23
|
-
const tag = url.searchParams.get("errorTag") || ""
|
|
24
|
-
let errors = ConsoleStore.store.errors.toArray()
|
|
25
|
-
if (tag) {
|
|
26
|
-
errors = errors.filter((e) => e.details.some((d) => d.tag && d.tag.startsWith(tag)))
|
|
27
|
-
}
|
|
28
|
-
if (search) {
|
|
29
|
-
const lower = search.toLowerCase()
|
|
30
|
-
errors = errors.filter((e) => {
|
|
31
|
-
const firstLine = e.prettyPrint.split("\n")[0] ?? ""
|
|
32
|
-
return firstLine.toLowerCase().includes(lower)
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
return errors.reverse()
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export default Route.get(
|
|
39
|
-
HyperRoute.html(function* (ctx) {
|
|
40
|
-
const url = new URL(ctx.request.url)
|
|
41
|
-
const errors = filterErrors(url)
|
|
42
|
-
const tags = collectTags()
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<Shell.Shell prefix={prefix} active="errors">
|
|
46
|
-
<form
|
|
47
|
-
data-signals={{ errorSearch: "", errorTag: "" }}
|
|
48
|
-
style="display:flex;flex-direction:column;flex:1;overflow:hidden"
|
|
49
|
-
>
|
|
50
|
-
<div class="tab-header">Errors</div>
|
|
51
|
-
<div class="filter-bar">
|
|
52
|
-
<input
|
|
53
|
-
type="text"
|
|
54
|
-
name="errorSearch"
|
|
55
|
-
placeholder="Search..."
|
|
56
|
-
data-bind:errorSearch
|
|
57
|
-
data-on:input={(c) => c.actions.get(location.href, { contentType: "form" })}
|
|
58
|
-
/>
|
|
59
|
-
<input
|
|
60
|
-
type="text"
|
|
61
|
-
name="errorTag"
|
|
62
|
-
placeholder="Tag..."
|
|
63
|
-
list="error-tags"
|
|
64
|
-
data-bind:errorTag
|
|
65
|
-
data-on:input={(c) => c.actions.get(location.href, { contentType: "form" })}
|
|
66
|
-
/>
|
|
67
|
-
<datalist id="error-tags">
|
|
68
|
-
{tags.map((t) => (
|
|
69
|
-
<option value={t} />
|
|
70
|
-
))}
|
|
71
|
-
</datalist>
|
|
72
|
-
</div>
|
|
73
|
-
<div id="errors-list" class="tab-body">
|
|
74
|
-
{errors.map((e) => (
|
|
75
|
-
<Errors.ErrorLine error={e} />
|
|
76
|
-
))}
|
|
77
|
-
</div>
|
|
78
|
-
</form>
|
|
79
|
-
</Shell.Shell>
|
|
80
|
-
)
|
|
81
|
-
}),
|
|
82
|
-
Route.sse(
|
|
83
|
-
Stream.fromPubSub(ConsoleStore.store.events).pipe(
|
|
84
|
-
Stream.filter((e) => e._tag === "Error"),
|
|
85
|
-
Stream.map((e) => {
|
|
86
|
-
const html = HyperHtml.renderToString(<Errors.ErrorLine error={e.error} />).replace(
|
|
87
|
-
/\n/g,
|
|
88
|
-
"",
|
|
89
|
-
)
|
|
90
|
-
return {
|
|
91
|
-
event: "datastar-patch-elements",
|
|
92
|
-
data: `selector #errors-list\nmode prepend\nelements ${html}`,
|
|
93
|
-
}
|
|
94
|
-
}),
|
|
95
|
-
),
|
|
96
|
-
),
|
|
97
|
-
)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import * as Schema from "effect/Schema"
|
|
2
|
-
import * as Route from "../../Route.ts"
|
|
3
|
-
import * as RouteSchema from "../../RouteSchema.ts"
|
|
4
|
-
import * as HyperRoute from "../../hyper/HyperRoute.ts"
|
|
5
|
-
import * as ConsoleStore from "../ConsoleStore.ts"
|
|
6
|
-
import * as Fibers from "../ui/Fibers.tsx"
|
|
7
|
-
import * as Shell from "../ui/Shell.tsx"
|
|
8
|
-
|
|
9
|
-
export default Route.get(
|
|
10
|
-
RouteSchema.schemaPathParams(Schema.Struct({ id: Schema.String })),
|
|
11
|
-
HyperRoute.html(function* (ctx) {
|
|
12
|
-
const fiberId = ctx.pathParams.id
|
|
13
|
-
const fiberName = fiberId.startsWith("#") ? fiberId : `#${fiberId}`
|
|
14
|
-
|
|
15
|
-
const allLogs = ConsoleStore.store.logs.toArray()
|
|
16
|
-
const fiberLogs = allLogs.filter((l) => l.fiberId === fiberName)
|
|
17
|
-
|
|
18
|
-
const allSpans = ConsoleStore.store.spans.toArray()
|
|
19
|
-
const fiberSpans = allSpans.filter((s) => {
|
|
20
|
-
const spanFiber = s.attributes["fiber.id"] as string | undefined
|
|
21
|
-
return spanFiber === fiberName
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
const fiberNum = parseInt(fiberName.slice(1), 10)
|
|
25
|
-
const counter = ConsoleStore.fiberIdCounter()
|
|
26
|
-
let alive: "alive" | "dead" | "unknown" = "unknown"
|
|
27
|
-
if (!isNaN(fiberNum)) {
|
|
28
|
-
if (fiberNum < counter) alive = "dead"
|
|
29
|
-
else alive = "unknown"
|
|
30
|
-
}
|
|
31
|
-
if (fiberLogs.length > 0 || fiberSpans.length > 0) {
|
|
32
|
-
const hasRecent = fiberLogs.some((l) => Date.now() - l.date.getTime() < 5000)
|
|
33
|
-
if (hasRecent) alive = "alive"
|
|
34
|
-
else if (fiberNum < counter) alive = "dead"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const parents = Fibers.getParentChain(fiberName, ConsoleStore.store.fiberParents)
|
|
38
|
-
const fiberContext = ConsoleStore.store.fiberContexts.get(fiberName)
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<Shell.Shell prefix={ConsoleStore.store.prefix} active="fibers">
|
|
42
|
-
<Fibers.FiberDetail
|
|
43
|
-
prefix={ConsoleStore.store.prefix}
|
|
44
|
-
fiberId={fiberName}
|
|
45
|
-
logs={fiberLogs}
|
|
46
|
-
spans={fiberSpans}
|
|
47
|
-
alive={alive}
|
|
48
|
-
parents={parents}
|
|
49
|
-
context={fiberContext}
|
|
50
|
-
/>
|
|
51
|
-
</Shell.Shell>
|
|
52
|
-
)
|
|
53
|
-
}),
|
|
54
|
-
)
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import * as Stream from "effect/Stream"
|
|
2
|
-
import * as Route from "../../../Route.ts"
|
|
3
|
-
import * as HyperHtml from "../../../hyper/HyperHtml.ts"
|
|
4
|
-
import * as HyperRoute from "../../../hyper/HyperRoute.ts"
|
|
5
|
-
import * as ConsoleStore from "../../ConsoleStore.ts"
|
|
6
|
-
import * as Fibers from "../../ui/Fibers.tsx"
|
|
7
|
-
import * as Shell from "../../ui/Shell.tsx"
|
|
8
|
-
|
|
9
|
-
export default Route.get(
|
|
10
|
-
HyperRoute.html(function* () {
|
|
11
|
-
const fibers = Fibers.collectFibers(
|
|
12
|
-
ConsoleStore.store.logs.toArray(),
|
|
13
|
-
ConsoleStore.store.spans.toArray(),
|
|
14
|
-
)
|
|
15
|
-
return (
|
|
16
|
-
<Shell.Shell prefix={ConsoleStore.store.prefix} active="fibers">
|
|
17
|
-
<div style="display:flex;flex-direction:column;flex:1;overflow:hidden">
|
|
18
|
-
<div class="tab-header">Fibers</div>
|
|
19
|
-
<div id="fibers-container" class="tab-body">
|
|
20
|
-
<Fibers.FiberList fibers={fibers} prefix={ConsoleStore.store.prefix} />
|
|
21
|
-
</div>
|
|
22
|
-
<div data-init={`@get('${ConsoleStore.store.prefix}/fibers')`} />
|
|
23
|
-
</div>
|
|
24
|
-
</Shell.Shell>
|
|
25
|
-
)
|
|
26
|
-
}),
|
|
27
|
-
Route.sse(
|
|
28
|
-
Stream.fromPubSub(ConsoleStore.store.events).pipe(
|
|
29
|
-
Stream.filter((e) => e._tag === "SpanStart" || e._tag === "SpanEnd" || e._tag === "Log"),
|
|
30
|
-
Stream.map(() => {
|
|
31
|
-
const fibers = Fibers.collectFibers(
|
|
32
|
-
ConsoleStore.store.logs.toArray(),
|
|
33
|
-
ConsoleStore.store.spans.toArray(),
|
|
34
|
-
)
|
|
35
|
-
const html = HyperHtml.renderToString(
|
|
36
|
-
<Fibers.FiberList fibers={fibers} prefix={ConsoleStore.store.prefix} />,
|
|
37
|
-
).replace(/\n/g, "")
|
|
38
|
-
return {
|
|
39
|
-
event: "datastar-patch-elements",
|
|
40
|
-
data: `selector #fibers-container\nmode inner\nelements ${html}`,
|
|
41
|
-
}
|
|
42
|
-
}),
|
|
43
|
-
),
|
|
44
|
-
),
|
|
45
|
-
)
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import * as Effect from "effect/Effect"
|
|
2
|
-
import * as Schedule from "effect/Schedule"
|
|
3
|
-
import * as Stream from "effect/Stream"
|
|
4
|
-
import * as ChildProcess from "../../../ChildProcess.ts"
|
|
5
|
-
import * as Route from "../../../Route.ts"
|
|
6
|
-
import * as HyperHtml from "../../../hyper/HyperHtml.ts"
|
|
7
|
-
import * as HyperRoute from "../../../hyper/HyperRoute.ts"
|
|
8
|
-
import * as ConsoleStore from "../../ConsoleStore.ts"
|
|
9
|
-
import * as Git from "../../ui/Git.tsx"
|
|
10
|
-
import * as Shell from "../../ui/Shell.tsx"
|
|
11
|
-
|
|
12
|
-
const exec = (args: Array<string>, cwd?: string) =>
|
|
13
|
-
Effect.gen(function* () {
|
|
14
|
-
const handle = yield* ChildProcess.make("git", args, cwd ? { cwd } : undefined)
|
|
15
|
-
return yield* handle.stdout.pipe(Stream.decodeText("utf-8"), Stream.mkString)
|
|
16
|
-
}).pipe(Effect.catchAll(() => Effect.succeed("")))
|
|
17
|
-
|
|
18
|
-
const gitStatus = exec(["rev-parse", "--show-toplevel"]).pipe(
|
|
19
|
-
Effect.flatMap((root) => {
|
|
20
|
-
const cwd = root.trim()
|
|
21
|
-
return Effect.all(
|
|
22
|
-
{
|
|
23
|
-
porcelain: exec(["status", "--porcelain=v2", "--branch"], cwd),
|
|
24
|
-
tag: exec(["describe", "--tags", "--abbrev=0"], cwd),
|
|
25
|
-
tagDistance: exec(["rev-list", "--count", "HEAD", "--not", "--tags"], cwd),
|
|
26
|
-
},
|
|
27
|
-
{ concurrency: "unbounded" },
|
|
28
|
-
)
|
|
29
|
-
}),
|
|
30
|
-
Effect.map(({ porcelain, tag, tagDistance }) =>
|
|
31
|
-
Git.parseGitStatus(porcelain, `${tag.trim()}\n${tagDistance.trim()}`),
|
|
32
|
-
),
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
export default Route.get(
|
|
36
|
-
HyperRoute.html(function* () {
|
|
37
|
-
const status = yield* gitStatus
|
|
38
|
-
return (
|
|
39
|
-
<Shell.Shell prefix={ConsoleStore.store.prefix} active="git">
|
|
40
|
-
<div class="tab-header">Git</div>
|
|
41
|
-
<div id="git-container" class="tab-body">
|
|
42
|
-
<Git.GitStatusView status={status} />
|
|
43
|
-
</div>
|
|
44
|
-
<div data-init={`@get('${ConsoleStore.store.prefix}/git')`} />
|
|
45
|
-
</Shell.Shell>
|
|
46
|
-
)
|
|
47
|
-
}),
|
|
48
|
-
Route.sse(
|
|
49
|
-
Stream.repeatEffect(
|
|
50
|
-
gitStatus.pipe(
|
|
51
|
-
Effect.map((status) => {
|
|
52
|
-
const html = HyperHtml.renderToString(<Git.GitStatusView status={status} />).replace(
|
|
53
|
-
/\n/g,
|
|
54
|
-
"",
|
|
55
|
-
)
|
|
56
|
-
return {
|
|
57
|
-
event: "datastar-patch-elements" as const,
|
|
58
|
-
data: `selector #git-container\nmode inner\nelements ${html}`,
|
|
59
|
-
}
|
|
60
|
-
}),
|
|
61
|
-
),
|
|
62
|
-
).pipe(Stream.schedule(Schedule.spaced("2 seconds"))),
|
|
63
|
-
),
|
|
64
|
-
)
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import * as Stream from "effect/Stream"
|
|
2
|
-
import * as Route from "../../../Route.ts"
|
|
3
|
-
import * as HyperHtml from "../../../hyper/HyperHtml.ts"
|
|
4
|
-
import * as HyperRoute from "../../../hyper/HyperRoute.ts"
|
|
5
|
-
import * as ConsoleStore from "../../ConsoleStore.ts"
|
|
6
|
-
import * as Logs from "../../ui/Logs.tsx"
|
|
7
|
-
import * as Shell from "../../ui/Shell.tsx"
|
|
8
|
-
|
|
9
|
-
const prefix = ConsoleStore.store.prefix
|
|
10
|
-
|
|
11
|
-
function filterLogs(url: URL): Array<ConsoleStore.ConsoleLog> {
|
|
12
|
-
const level = url.searchParams.get("logLevel") || ""
|
|
13
|
-
const search = url.searchParams.get("logSearch") || ""
|
|
14
|
-
let logs = ConsoleStore.store.logs.toArray()
|
|
15
|
-
if (level) logs = logs.filter((l) => l.level === level)
|
|
16
|
-
if (search) {
|
|
17
|
-
const lower = search.toLowerCase()
|
|
18
|
-
logs = logs.filter((l) => l.message.toLowerCase().includes(lower))
|
|
19
|
-
}
|
|
20
|
-
return logs.reverse()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default Route.get(
|
|
24
|
-
HyperRoute.html(function* (ctx) {
|
|
25
|
-
const url = new URL(ctx.request.url)
|
|
26
|
-
const logs = filterLogs(url)
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<Shell.Shell prefix={prefix} active="logs">
|
|
30
|
-
<form
|
|
31
|
-
data-signals={{ logLevel: "", logSearch: "" }}
|
|
32
|
-
style="display:flex;flex-direction:column;flex:1;overflow:hidden"
|
|
33
|
-
>
|
|
34
|
-
<div class="tab-header">Logs</div>
|
|
35
|
-
<div class="filter-bar">
|
|
36
|
-
<select
|
|
37
|
-
name="logLevel"
|
|
38
|
-
data-bind:logLevel
|
|
39
|
-
data-on:change={(c) => c.actions.get(location.href, { contentType: "form" })}
|
|
40
|
-
>
|
|
41
|
-
<option value="">All levels</option>
|
|
42
|
-
<option value="DEBUG">DEBUG</option>
|
|
43
|
-
<option value="INFO">INFO</option>
|
|
44
|
-
<option value="WARNING">WARNING</option>
|
|
45
|
-
<option value="ERROR">ERROR</option>
|
|
46
|
-
<option value="FATAL">FATAL</option>
|
|
47
|
-
</select>
|
|
48
|
-
<input
|
|
49
|
-
type="text"
|
|
50
|
-
name="logSearch"
|
|
51
|
-
placeholder="Search..."
|
|
52
|
-
data-bind:logSearch
|
|
53
|
-
data-on:input={(c) => c.actions.get(location.href, { contentType: "form" })}
|
|
54
|
-
/>
|
|
55
|
-
</div>
|
|
56
|
-
<div id="logs-container" class="tab-body">
|
|
57
|
-
{logs.map((l) => (
|
|
58
|
-
<Logs.LogLine log={l} />
|
|
59
|
-
))}
|
|
60
|
-
</div>
|
|
61
|
-
</form>
|
|
62
|
-
</Shell.Shell>
|
|
63
|
-
)
|
|
64
|
-
}),
|
|
65
|
-
Route.sse(
|
|
66
|
-
Stream.fromPubSub(ConsoleStore.store.events).pipe(
|
|
67
|
-
Stream.filter((e) => e._tag === "Log"),
|
|
68
|
-
Stream.map((e) => {
|
|
69
|
-
const html = HyperHtml.renderToString(<Logs.LogLine log={e.log} />).replace(/\n/g, "")
|
|
70
|
-
return {
|
|
71
|
-
event: "datastar-patch-elements",
|
|
72
|
-
data: `selector #logs-container\nmode prepend\nelements ${html}`,
|
|
73
|
-
}
|
|
74
|
-
}),
|
|
75
|
-
),
|
|
76
|
-
),
|
|
77
|
-
)
|