@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 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.86",
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/typescript-config": "0.0.11",
34
- "@typed-assistant/utils": "0.0.19"
33
+ "@typed-assistant/utils": "0.0.19",
34
+ "@typed-assistant/typescript-config": "0.0.11"
35
35
  },
36
36
  "publishConfig": {
37
37
  "access": "public",
@@ -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("Process is returning an empty string. This was the last non-empty message:\n\n" +
395
- lastMessage),
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 limit = Number(limitProp)
431
- const offset = Number(offsetProp)
432
-
433
- const logs = (
434
- await Bun.file("./log.txt")
435
- .text()
436
- .then((text) => text.split("\n"))
437
- .then((lines) =>
438
- limit
439
- ? lines.slice(
440
- lines.length - 1 - limit * (offset + 1),
441
- lines.length - 1 - limit * offset,
442
- )
443
- : lines,
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
- ).reduce((result, line) => {
446
- if (filter && !line.toLowerCase().includes(filter.toLowerCase()))
447
- return result
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: [
@@ -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) => setFilter(e.target.value)}
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) => setLevel(e.target.value as typeof level)}
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
- <button
89
- className={buttonStyle}
90
- onClick={() => setOffset((offset) => offset + 1)}
91
- >
92
- Next
93
- </button>
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
  </>