@typed-assistant/builder 0.0.67 → 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.67",
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": {
@@ -299,17 +299,6 @@ export const startWebappServer = async ({
299
299
  const convertedMessage = convert.toHtml(decodedString)
300
300
  if (convertedMessage !== "") {
301
301
  lastMessage = convertedMessage
302
- logger.fatal(
303
- {
304
- emoji: "💀",
305
- additionalDetails: JSON.stringify(
306
- { exitCode: getSubprocesses().app.exitCode },
307
- null,
308
- 2,
309
- ),
310
- },
311
- "Process is returning an empty string",
312
- )
313
302
  }
314
303
  if (convertedMessage === "") {
315
304
  subscribers.forEach((send) =>
@@ -318,6 +307,15 @@ export const startWebappServer = async ({
318
307
  lastMessage,
319
308
  ),
320
309
  )
310
+ logger.fatal(
311
+ {
312
+ emoji: "💀",
313
+ additionalDetails: JSON.stringify({
314
+ exitCode: getSubprocesses().app.exitCode,
315
+ }),
316
+ },
317
+ "Process is returning an empty string",
318
+ )
321
319
  await new Promise((resolve) => setTimeout(resolve, 1000))
322
320
  continue
323
321
  }
@@ -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 { useCallback, useState } from "react"
3
+ import { useState } from "react"
5
4
  import { AppSection } from "./AppSection"
6
5
  import { WSIndicator } from "./WSIndicator"
7
- import { app } from "./api"
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 [logs, setLogs] = useState<LogSchema[]>([])
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
- <AppSection
35
- renderHeader={() => (
36
- <>
37
- <h2 className="mb-2 text-2xl flex items-baseline gap-3">
38
- Logs <WSIndicator ws={ws.ws} />
39
- </h2>
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
- <a className={buttonStyle} href={`${basePath}/log.txt?limit=500`}>
42
- View raw log.txt
43
- </a>
25
+ <a className={buttonStyle} href={`${basePath}/log.txt?limit=500`}>
26
+ View raw log.txt
27
+ </a>
44
28
 
45
- <div className="flex flex-wrap gap-2">
46
- <div className="flex gap-2">
47
- <label htmlFor="dateTimeVisibility">Date/Time</label>
48
- <select
49
- className="border border-gray-300 rounded-md text-slate-800 px-2"
50
- id="dateTimeVisibility"
51
- onChange={(e) =>
52
- setDateTimeVisibility(
53
- e.target.value as typeof dateTimeVisibility,
54
- )
55
- }
56
- value={dateTimeVisibility}
57
- >
58
- <option value="hidden">Hidden</option>
59
- <option value="timeOnly">Time only</option>
60
- <option value="visible">Visible</option>
61
- </select>
62
- </div>
63
- <div className="flex gap-2">
64
- <label htmlFor="dateTimeVisibility">Level</label>
65
- <select
66
- className="border border-gray-300 rounded-md text-slate-800 px-2"
67
- id="level"
68
- onChange={(e) => setLevel(e.target.value as typeof level)}
69
- value={level}
70
- >
71
- <option value="trace">Trace</option>
72
- <option value="debug">Debug</option>
73
- <option value="info">Info</option>
74
- <option value="warn">Warn</option>
75
- <option value="error">Error</option>
76
- <option value="fatal">Fatal</option>
77
- </select>
78
- </div>
79
- {/* <div className="flex gap-2">
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
- </div>
90
- </>
91
- )}
92
- >
93
- <pre>
94
- <ul>
95
- {logs
96
- .filter((log) => log.level >= (levels[level] ?? 0))
97
- .sort(
98
- (a, b) => new Date(b.time).getTime() - new Date(a.time).getTime(),
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
- </ul>
125
- </pre>
126
- </AppSection>
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: WebSocket }) {
2
- return ws.readyState === WebSocket.OPEN ? (
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"
@@ -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
+ }