@typed-assistant/builder 0.0.68 → 0.0.69
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed-assistant/builder",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"exports": {
|
|
5
5
|
"./appProcess": "./src/appProcess.tsx",
|
|
6
6
|
"./bunInstall": "./src/bunInstall.tsx",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"ts-toolbelt": "^9.6.0",
|
|
27
27
|
"typescript": "^5.3.3",
|
|
28
28
|
"@typed-assistant/eslint-config": "0.0.10",
|
|
29
|
-
"@typed-assistant/logger": "0.0.18",
|
|
30
29
|
"@typed-assistant/typescript-config": "0.0.9",
|
|
30
|
+
"@typed-assistant/logger": "0.0.19",
|
|
31
31
|
"@typed-assistant/utils": "0.0.16"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
package/src/webserver/Logs.tsx
CHANGED
|
@@ -1,82 +1,66 @@
|
|
|
1
|
-
import type { LogSchema } from "@typed-assistant/logger"
|
|
2
1
|
import { levels } from "@typed-assistant/logger/levels"
|
|
3
2
|
import { getPrettyTimestamp } from "@typed-assistant/utils/getPrettyTimestamp"
|
|
4
|
-
import {
|
|
3
|
+
import { useState } from "react"
|
|
5
4
|
import { AppSection } from "./AppSection"
|
|
6
5
|
import { WSIndicator } from "./WSIndicator"
|
|
7
|
-
import {
|
|
6
|
+
import { useLogStore } from "./logStore"
|
|
8
7
|
import { buttonStyle } from "./styles"
|
|
9
|
-
import { useWS } from "./useWS"
|
|
10
8
|
|
|
11
9
|
export const Logs = ({ basePath }: { basePath: string }) => {
|
|
12
|
-
const [limit, setLimit] = useState(200)
|
|
13
|
-
const [level, setLevel] = useState<
|
|
14
|
-
"trace" | "debug" | "info" | "warn" | "error" | "fatal"
|
|
15
|
-
>("info")
|
|
16
10
|
const [dateTimeVisibility, setDateTimeVisibility] = useState<
|
|
17
11
|
"hidden" | "timeOnly" | "visible"
|
|
18
12
|
>("timeOnly")
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
const ws = useWS({
|
|
22
|
-
subscribe: useCallback(
|
|
23
|
-
() =>
|
|
24
|
-
app.logsws.subscribe({ $query: { level, limit: limit.toString() } }),
|
|
25
|
-
[level, limit],
|
|
26
|
-
),
|
|
27
|
-
onMessage: useCallback((event) => {
|
|
28
|
-
console.log("😅😅😅 ~ event:", event)
|
|
29
|
-
setLogs((JSON.parse(event.data) as { logs: LogSchema[] }).logs)
|
|
30
|
-
}, []),
|
|
31
|
-
})
|
|
13
|
+
const { level, setLevel, logs, ws } = useLogStore()
|
|
14
|
+
console.log("😅😅😅 ~ logs:", logs)
|
|
32
15
|
|
|
33
16
|
return (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
17
|
+
<>
|
|
18
|
+
<AppSection
|
|
19
|
+
renderHeader={() => (
|
|
20
|
+
<>
|
|
21
|
+
<h2 className="mb-2 text-2xl flex items-baseline gap-3">
|
|
22
|
+
Logs <WSIndicator ws={ws?.ws} />
|
|
23
|
+
</h2>
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
25
|
+
<a className={buttonStyle} href={`${basePath}/log.txt?limit=500`}>
|
|
26
|
+
View raw log.txt
|
|
27
|
+
</a>
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
29
|
+
<div className="flex flex-wrap gap-2">
|
|
30
|
+
<div className="flex gap-2">
|
|
31
|
+
<label htmlFor="dateTimeVisibility">Date/Time</label>
|
|
32
|
+
<select
|
|
33
|
+
className="border border-gray-300 rounded-md text-slate-800 px-2"
|
|
34
|
+
id="dateTimeVisibility"
|
|
35
|
+
onChange={(e) =>
|
|
36
|
+
setDateTimeVisibility(
|
|
37
|
+
e.target.value as typeof dateTimeVisibility,
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
value={dateTimeVisibility}
|
|
41
|
+
>
|
|
42
|
+
<option value="hidden">Hidden</option>
|
|
43
|
+
<option value="timeOnly">Time only</option>
|
|
44
|
+
<option value="visible">Visible</option>
|
|
45
|
+
</select>
|
|
46
|
+
</div>
|
|
47
|
+
<div className="flex gap-2">
|
|
48
|
+
<label htmlFor="dateTimeVisibility">Level</label>
|
|
49
|
+
<select
|
|
50
|
+
className="border border-gray-300 rounded-md text-slate-800 px-2"
|
|
51
|
+
id="level"
|
|
52
|
+
onChange={(e) => setLevel(e.target.value as typeof level)}
|
|
53
|
+
value={level}
|
|
54
|
+
>
|
|
55
|
+
<option value="trace">Trace</option>
|
|
56
|
+
<option value="debug">Debug</option>
|
|
57
|
+
<option value="info">Info</option>
|
|
58
|
+
<option value="warn">Warn</option>
|
|
59
|
+
<option value="error">Error</option>
|
|
60
|
+
<option value="fatal">Fatal</option>
|
|
61
|
+
</select>
|
|
62
|
+
</div>
|
|
63
|
+
{/* <div className="flex gap-2">
|
|
80
64
|
<label htmlFor="limit">Limit</label>
|
|
81
65
|
<input
|
|
82
66
|
className="border border-gray-300 rounded-md text-slate-800 px-2"
|
|
@@ -86,43 +70,45 @@ export const Logs = ({ basePath }: { basePath: string }) => {
|
|
|
86
70
|
value={limit}
|
|
87
71
|
/>
|
|
88
72
|
</div> */}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.map((log) => {
|
|
101
|
-
return (
|
|
102
|
-
<li key={log.id} className="flex gap-1">
|
|
103
|
-
<span className="text-slate-400 mr-2">
|
|
104
|
-
{dateTimeVisibility === "hidden"
|
|
105
|
-
? null
|
|
106
|
-
: dateTimeVisibility === "timeOnly"
|
|
107
|
-
? new Date(log.time).toLocaleTimeString("en-GB")
|
|
108
|
-
: getPrettyTimestamp(log.time)}
|
|
109
|
-
</span>
|
|
110
|
-
<div className="flex">
|
|
111
|
-
{log.emoji}{" "}
|
|
112
|
-
{log.additionalDetails ? (
|
|
113
|
-
<details>
|
|
114
|
-
<summary>{log.msg}</summary>
|
|
115
|
-
<pre>{log.additionalDetails}</pre>
|
|
116
|
-
</details>
|
|
117
|
-
) : (
|
|
118
|
-
log.msg
|
|
119
|
-
)}
|
|
120
|
-
</div>
|
|
121
|
-
</li>
|
|
73
|
+
</div>
|
|
74
|
+
</>
|
|
75
|
+
)}
|
|
76
|
+
>
|
|
77
|
+
<pre>
|
|
78
|
+
<ul>
|
|
79
|
+
{logs
|
|
80
|
+
.filter((log) => log.level >= (levels[level] ?? 0))
|
|
81
|
+
.sort(
|
|
82
|
+
(a, b) =>
|
|
83
|
+
new Date(b.time).getTime() - new Date(a.time).getTime(),
|
|
122
84
|
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
85
|
+
.map((log) => {
|
|
86
|
+
return (
|
|
87
|
+
<li key={log.id} className="flex gap-1">
|
|
88
|
+
<span className="text-slate-400 mr-2">
|
|
89
|
+
{dateTimeVisibility === "hidden"
|
|
90
|
+
? null
|
|
91
|
+
: dateTimeVisibility === "timeOnly"
|
|
92
|
+
? new Date(log.time).toLocaleTimeString("en-GB")
|
|
93
|
+
: getPrettyTimestamp(log.time)}
|
|
94
|
+
</span>
|
|
95
|
+
<div className="flex">
|
|
96
|
+
{log.emoji}{" "}
|
|
97
|
+
{log.additionalDetails ? (
|
|
98
|
+
<details>
|
|
99
|
+
<summary>{log.msg}</summary>
|
|
100
|
+
<pre>{log.additionalDetails}</pre>
|
|
101
|
+
</details>
|
|
102
|
+
) : (
|
|
103
|
+
log.msg
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
</li>
|
|
107
|
+
)
|
|
108
|
+
})}
|
|
109
|
+
</ul>
|
|
110
|
+
</pre>
|
|
111
|
+
</AppSection>
|
|
112
|
+
</>
|
|
127
113
|
)
|
|
128
114
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export function WSIndicator({ ws }: { ws
|
|
2
|
-
return ws
|
|
1
|
+
export function WSIndicator({ ws }: { ws?: WebSocket }) {
|
|
2
|
+
return ws?.readyState === WebSocket.OPEN ? (
|
|
3
3
|
<div
|
|
4
4
|
title="Connected"
|
|
5
5
|
className="w-4 h-4 rounded-full bg-emerald-300 text-emerald-800 text-xs uppercase"
|
package/src/webserver/index.html
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html class="h-full">
|
|
3
3
|
<head>
|
|
4
|
+
<meta charset="UTF-8"></head>
|
|
4
5
|
<link rel="stylesheet" href="{{ STYLESHEET }}" />
|
|
6
|
+
<link
|
|
7
|
+
rel="shortcut icon"
|
|
8
|
+
href="data:image/svg+xml,<svg xmlns=%22https://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🛠️</text></svg>"
|
|
9
|
+
type="image/svg+xml"
|
|
10
|
+
sizes="any"
|
|
11
|
+
/>
|
|
5
12
|
</head>
|
|
6
13
|
<body class="bg-slate-950 text-white h-full max-h-dvh">
|
|
7
14
|
<div id="root" class="h-full max-h-dvh"></div>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// This is an example of a third-party store
|
|
2
|
+
// that you might need to integrate with React.
|
|
3
|
+
|
|
4
|
+
import type { LogSchema } from "@typed-assistant/logger"
|
|
5
|
+
import type { levels } from "@typed-assistant/logger/levels"
|
|
6
|
+
import { app } from "./api"
|
|
7
|
+
import type { EdenTreaty } from "@elysiajs/eden/treaty"
|
|
8
|
+
import { useMemo, useState, useSyncExternalStore } from "react"
|
|
9
|
+
|
|
10
|
+
let listeners: (() => void)[] = []
|
|
11
|
+
let logStore = {
|
|
12
|
+
logs: [] as LogSchema[],
|
|
13
|
+
ws: undefined as ReturnType<(typeof app.logsws)["subscribe"]> | undefined,
|
|
14
|
+
}
|
|
15
|
+
export const getLogStore = ({
|
|
16
|
+
level,
|
|
17
|
+
limit,
|
|
18
|
+
}: {
|
|
19
|
+
level: keyof typeof levels
|
|
20
|
+
limit: string
|
|
21
|
+
}) => ({
|
|
22
|
+
subscribe: (listener: () => void) => {
|
|
23
|
+
listeners = [...listeners, listener]
|
|
24
|
+
const ws = app.logsws.subscribe({
|
|
25
|
+
$query: { level, limit },
|
|
26
|
+
})
|
|
27
|
+
logStore = {
|
|
28
|
+
logs: [],
|
|
29
|
+
ws,
|
|
30
|
+
}
|
|
31
|
+
emitChange()
|
|
32
|
+
|
|
33
|
+
ws.on("open", (event) => {
|
|
34
|
+
logStore = {
|
|
35
|
+
logs: logStore.logs,
|
|
36
|
+
ws: logStore.ws,
|
|
37
|
+
}
|
|
38
|
+
emitChange()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
ws.on("message", (event) => {
|
|
42
|
+
logStore = {
|
|
43
|
+
logs: (event as EdenTreaty.OnMessage<{ logs: LogSchema[] }>).data.logs,
|
|
44
|
+
ws,
|
|
45
|
+
}
|
|
46
|
+
emitChange()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
logStore.ws?.close()
|
|
51
|
+
listeners = listeners.filter((l) => l !== listener)
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
getSnapshot: () => logStore,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
function emitChange() {
|
|
59
|
+
for (let listener of listeners) {
|
|
60
|
+
listener()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const useLogStore = () => {
|
|
65
|
+
const [limit, setLimit] = useState(200)
|
|
66
|
+
const [level, setLevel] = useState<
|
|
67
|
+
"trace" | "debug" | "info" | "warn" | "error" | "fatal"
|
|
68
|
+
>("info")
|
|
69
|
+
const logStore = useMemo(
|
|
70
|
+
() => getLogStore({ level, limit: limit.toString() }),
|
|
71
|
+
[level, limit],
|
|
72
|
+
)
|
|
73
|
+
const { logs, ws } = useSyncExternalStore(
|
|
74
|
+
logStore.subscribe,
|
|
75
|
+
logStore.getSnapshot,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
limit,
|
|
80
|
+
setLimit,
|
|
81
|
+
level,
|
|
82
|
+
setLevel,
|
|
83
|
+
logs,
|
|
84
|
+
ws,
|
|
85
|
+
}
|
|
86
|
+
}
|