@typed-assistant/builder 0.0.86 → 0.0.88
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/CHANGELOG.md +13 -0
- package/package.json +3 -3
- package/src/setupWebserver.tsx +56 -30
- package/src/webserver/Logs.tsx +19 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @typed-assistant/builder
|
|
2
2
|
|
|
3
|
+
## 0.0.88
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fire onProcessError when empty stream is detected in web server.
|
|
8
|
+
|
|
9
|
+
## 0.0.87
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Apply search filters before paginating logs so filtered results span all pages.
|
|
14
|
+
- Hide the Next pagination button entirely when no additional log pages are available.
|
|
15
|
+
|
|
3
16
|
## 0.0.86
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed-assistant/builder",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.88",
|
|
4
4
|
"exports": {
|
|
5
5
|
"./appProcess": "./src/appProcess.tsx",
|
|
6
6
|
"./bunInstall": "./src/bunInstall.tsx",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"typescript": "^5.4.0",
|
|
31
31
|
"@typed-assistant/eslint-config": "0.0.10",
|
|
32
32
|
"@typed-assistant/logger": "0.0.22",
|
|
33
|
-
"@typed-assistant/
|
|
34
|
-
"@typed-assistant/
|
|
33
|
+
"@typed-assistant/utils": "0.0.19",
|
|
34
|
+
"@typed-assistant/typescript-config": "0.0.11"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public",
|
package/src/setupWebserver.tsx
CHANGED
|
@@ -347,6 +347,7 @@ export const startWebappServer = async ({
|
|
|
347
347
|
})
|
|
348
348
|
|
|
349
349
|
let emptyStringCount = 0
|
|
350
|
+
let outputStreamsEmptyCount = 0
|
|
350
351
|
|
|
351
352
|
// eslint-disable-next-line no-constant-condition
|
|
352
353
|
while (true) {
|
|
@@ -374,6 +375,12 @@ export const startWebappServer = async ({
|
|
|
374
375
|
"Subprocess output streams ended; waiting for restart or new output",
|
|
375
376
|
)
|
|
376
377
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
378
|
+
outputStreamsEmptyCount += 1
|
|
379
|
+
const outputStreamsEmptyMessage = "Process output streams have ended"
|
|
380
|
+
if (outputStreamsEmptyCount === 10) {
|
|
381
|
+
onProcessError(outputStreamsEmptyMessage)
|
|
382
|
+
break
|
|
383
|
+
}
|
|
377
384
|
continue
|
|
378
385
|
}
|
|
379
386
|
|
|
@@ -385,14 +392,16 @@ export const startWebappServer = async ({
|
|
|
385
392
|
}
|
|
386
393
|
if (convertedMessage === "") {
|
|
387
394
|
emptyStringCount += 1
|
|
388
|
-
const emptyStringMessage =
|
|
389
|
-
"Process is returning an empty string"
|
|
395
|
+
const emptyStringMessage = "Process is returning an empty string"
|
|
390
396
|
if (emptyStringCount === 10) {
|
|
391
397
|
onProcessError(emptyStringMessage)
|
|
398
|
+
break
|
|
392
399
|
}
|
|
393
400
|
subscribers.forEach((send) =>
|
|
394
|
-
send(
|
|
395
|
-
|
|
401
|
+
send(
|
|
402
|
+
"Process is returning an empty string. This was the last non-empty message:\n\n" +
|
|
403
|
+
lastMessage,
|
|
404
|
+
),
|
|
396
405
|
)
|
|
397
406
|
logger.fatal(
|
|
398
407
|
{
|
|
@@ -427,33 +436,50 @@ const getLogsFromFile = async ({
|
|
|
427
436
|
filter?: string
|
|
428
437
|
}) => {
|
|
429
438
|
try {
|
|
430
|
-
const
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
439
|
+
const parsedLimit = Number(limitProp)
|
|
440
|
+
const limit =
|
|
441
|
+
Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : undefined
|
|
442
|
+
const parsedOffset = Number(offsetProp)
|
|
443
|
+
const offset =
|
|
444
|
+
Number.isFinite(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0
|
|
445
|
+
|
|
446
|
+
const normalizedFilter = filter?.toLowerCase().trim()
|
|
447
|
+
|
|
448
|
+
const parsedLogs = (await Bun.file("./log.txt").text())
|
|
449
|
+
.split("\n")
|
|
450
|
+
.reduce((result, line) => {
|
|
451
|
+
if (!line) return result
|
|
452
|
+
|
|
453
|
+
try {
|
|
454
|
+
const log = JSON.parse(line) as LogSchema
|
|
455
|
+
return result.concat(log)
|
|
456
|
+
} catch (e) {
|
|
457
|
+
return result.concat({
|
|
458
|
+
msg: e instanceof Error ? e.message : "Unknown parse error",
|
|
459
|
+
level: levels.fatal,
|
|
460
|
+
} as LogSchema)
|
|
461
|
+
}
|
|
462
|
+
}, [] as LogSchema[])
|
|
463
|
+
|
|
464
|
+
const filteredLogs = parsedLogs.filter((log) => {
|
|
465
|
+
if (log.level < levels[level]) return false
|
|
466
|
+
|
|
467
|
+
if (normalizedFilter) {
|
|
468
|
+
const haystack = JSON.stringify(log).toLowerCase()
|
|
469
|
+
if (!haystack.includes(normalizedFilter)) return false
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return true
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
const paginatedLogs = limit
|
|
476
|
+
? filteredLogs.slice(
|
|
477
|
+
Math.max(filteredLogs.length - limit * (offset + 1), 0),
|
|
478
|
+
filteredLogs.length - limit * offset || filteredLogs.length,
|
|
444
479
|
)
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const log = line
|
|
450
|
-
? JSON.parse(line)
|
|
451
|
-
: { msg: "Empty line", level: levels.fatal }
|
|
452
|
-
if (log.level < levels[level]) return result
|
|
453
|
-
return result.concat(log)
|
|
454
|
-
}, [] as LogSchema[])
|
|
455
|
-
|
|
456
|
-
return { logs }
|
|
480
|
+
: filteredLogs
|
|
481
|
+
|
|
482
|
+
return { logs: paginatedLogs }
|
|
457
483
|
} catch (e) {
|
|
458
484
|
return {
|
|
459
485
|
logs: [
|
package/src/webserver/Logs.tsx
CHANGED
|
@@ -10,9 +10,11 @@ export const Logs = ({ basePath }: { basePath: string }) => {
|
|
|
10
10
|
const [dateTimeVisibility, setDateTimeVisibility] = useState<
|
|
11
11
|
"hidden" | "timeOnly" | "visible"
|
|
12
12
|
>("timeOnly")
|
|
13
|
-
const { level, setLevel, logs, offset, setOffset, ws, filter, setFilter } =
|
|
13
|
+
const { level, setLevel, logs, offset, setOffset, ws, filter, setFilter, limit } =
|
|
14
14
|
useLogStore()
|
|
15
15
|
|
|
16
|
+
const hasNextPage = limit ? logs.length >= limit : false
|
|
17
|
+
|
|
16
18
|
return (
|
|
17
19
|
<>
|
|
18
20
|
<AppSection
|
|
@@ -31,7 +33,10 @@ export const Logs = ({ basePath }: { basePath: string }) => {
|
|
|
31
33
|
placeholder="Filter logs..."
|
|
32
34
|
className="border border-gray-300 rounded-md text-slate-800 px-2 flex-grow placeholder:text-slate-700"
|
|
33
35
|
value={filter}
|
|
34
|
-
onChange={(e) =>
|
|
36
|
+
onChange={(e) => {
|
|
37
|
+
setOffset(0)
|
|
38
|
+
setFilter(e.target.value)
|
|
39
|
+
}}
|
|
35
40
|
/>
|
|
36
41
|
</div>
|
|
37
42
|
|
|
@@ -63,7 +68,10 @@ export const Logs = ({ basePath }: { basePath: string }) => {
|
|
|
63
68
|
<select
|
|
64
69
|
className="border border-gray-300 rounded-md text-slate-800 px-2"
|
|
65
70
|
id="level"
|
|
66
|
-
onChange={(e) =>
|
|
71
|
+
onChange={(e) => {
|
|
72
|
+
setOffset(0)
|
|
73
|
+
setLevel(e.target.value as typeof level)
|
|
74
|
+
}}
|
|
67
75
|
value={level}
|
|
68
76
|
>
|
|
69
77
|
<option value="trace">Trace</option>
|
|
@@ -85,12 +93,14 @@ export const Logs = ({ basePath }: { basePath: string }) => {
|
|
|
85
93
|
Previous
|
|
86
94
|
</button>
|
|
87
95
|
)}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
{hasNextPage && (
|
|
97
|
+
<button
|
|
98
|
+
className={buttonStyle}
|
|
99
|
+
onClick={() => setOffset((offset) => offset + 1)}
|
|
100
|
+
>
|
|
101
|
+
Next
|
|
102
|
+
</button>
|
|
103
|
+
)}
|
|
94
104
|
</div>
|
|
95
105
|
</div>
|
|
96
106
|
</>
|