@typed-assistant/builder 0.0.47 → 0.0.49

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.47",
3
+ "version": "0.0.49",
4
4
  "exports": {
5
5
  "./appProcess": "./src/appProcess.tsx",
6
6
  "./bunInstall": "./src/bunInstall.tsx",
@@ -24,9 +24,9 @@
24
24
  "home-assistant-js-websocket": "^8.2.0",
25
25
  "ts-toolbelt": "^9.6.0",
26
26
  "typescript": "^5.3.3",
27
- "@typed-assistant/eslint-config": "0.0.8",
28
- "@typed-assistant/logger": "0.0.13",
29
27
  "@typed-assistant/typescript-config": "0.0.8",
28
+ "@typed-assistant/eslint-config": "0.0.8",
29
+ "@typed-assistant/logger": "0.0.14",
30
30
  "@typed-assistant/utils": "0.0.14"
31
31
  },
32
32
  "peerDependencies": {
@@ -68,7 +68,7 @@ async function buildAndStartAppProcess(
68
68
  }
69
69
 
70
70
  async function startApp(appSourceFile: string) {
71
- logger.info("🚀 Starting app...")
71
+ logger.info({ emoji: "🚀" }, "Starting app...")
72
72
  const path = join(process.cwd(), appSourceFile)
73
73
  return Bun.spawn(["bun", path], {
74
74
  stderr: "pipe",
@@ -83,7 +83,7 @@ async function killAndRestartApp(
83
83
  subprocesses: Processes,
84
84
  ) {
85
85
  if (settingUp.current) return subprocesses
86
- logger.fatal("♻️ Restarting app...")
86
+ logger.fatal({ emoji: "♻️" }, "Restarting app...")
87
87
  settingUp.current = true
88
88
  if (subprocesses.app) await killSubprocess(subprocesses.app)
89
89
  const newSubprocesses = await buildAndStartAppProcess(entryFile, options)
@@ -109,8 +109,8 @@ const checkProcesses = async (
109
109
  if (matches.length > 1) {
110
110
  multipleProcessesErrorCount++
111
111
  if (multipleProcessesErrorCount > 5) {
112
- const message = `🚨 Multiple processes detected. Check the logs...`
113
- logger.fatal(message, ps)
112
+ const message = `Multiple processes detected. Check the logs...`
113
+ logger.fatal({ additionalDetails: ps, emoji: "🚨" }, message)
114
114
  onProcessError?.(message, addonUrl)
115
115
  return
116
116
  }
@@ -121,8 +121,8 @@ const checkProcesses = async (
121
121
  if (matches.length === 0) {
122
122
  noProcessesErrorCount++
123
123
  if (noProcessesErrorCount > 5) {
124
- const message = `🚨 No processes detected. Check the logs...`
125
- logger.fatal(message, ps)
124
+ const message = `No processes detected. Check the logs...`
125
+ logger.fatal({ additionalDetails: ps, emoji: "🚨" }, message)
126
126
  onProcessError?.(message, addonUrl)
127
127
  return
128
128
  }
@@ -137,11 +137,11 @@ const checkProcesses = async (
137
137
  }
138
138
 
139
139
  const getAddonInfo = async () => {
140
- logger.info("🔍 Getting addon info...")
140
+ logger.debug({ emoji: "🔍" }, "Getting addon info...")
141
141
 
142
142
  const { data, error } = await getAddonInfoAPI()
143
143
 
144
- if (error) logger.error(`🚨 Failed to get addon info: ${error}`)
144
+ if (error) logger.error({ emoji: "🚨" }, `Failed to get addon info: ${error}`)
145
145
 
146
146
  return data
147
147
  }
@@ -153,7 +153,8 @@ const setupGitSync = async (webhookUrl: string) => {
153
153
  !process.env.GITHUB_REPO
154
154
  ) {
155
155
  logger.warn(
156
- "⚠️ Cannot sync with Github without Github token, username, and repo details. Add these in the add-on configuration.",
156
+ { emoji: "⚠️" },
157
+ "Cannot sync with Github without Github token, username, and repo details. Add these in the add-on configuration.",
157
158
  )
158
159
  return { error: {} }
159
160
  }
@@ -161,7 +162,10 @@ const setupGitSync = async (webhookUrl: string) => {
161
162
  await setupWebhook(webhookUrl)
162
163
  return
163
164
  }
164
- logger.warn("⚠️ No HASS_EXTERNAL_URL found. Setting up git poller...")
165
+ logger.warn(
166
+ { emoji: "⚠️" },
167
+ "No HASS_EXTERNAL_URL found. Setting up git poller...",
168
+ )
165
169
  await setupGitPoller()
166
170
  }
167
171
 
@@ -188,14 +192,14 @@ function setupWatcher({
188
192
  app: Subprocess<"ignore", "pipe", "pipe">
189
193
  }
190
194
  }) {
191
- logger.info("👀 Watching directory:", directoryToWatch)
195
+ logger.debug({ emoji: "👀" }, "Watching directory: ${directoryToWatch}")
192
196
  const watcher = watch(
193
197
  directoryToWatch,
194
198
  { recursive: true },
195
199
  debounce(async function onFileChange(event, filename) {
196
200
  if (!filename) return
197
201
  if (shouldIgnoreFileOrFolder(filename)) return
198
- logger.info(`⚠️ Change to ${filename} detected.`)
202
+ logger.info({ emoji: "⚠️" }, `Change to ${filename} detected.`)
199
203
  if (filename.endsWith("process.tsx")) {
200
204
  await killSubprocess(getSubprocesses().app)
201
205
  await restartAddon()
@@ -215,13 +219,13 @@ function setupWatcher({
215
219
  }
216
220
 
217
221
  process.on("SIGINT", async () => {
218
- logger.fatal("👋 Exiting...")
222
+ logger.fatal({ emoji: "👋" }, "Exiting...")
219
223
  await callSoftKillListeners()
220
224
  await callKillListeners()
221
225
  process.exit(0)
222
226
  })
223
227
  process.on("SIGTERM", async () => {
224
- logger.fatal("👋 Exiting...")
228
+ logger.fatal({ emoji: "👋" }, "Exiting...")
225
229
  await callSoftKillListeners()
226
230
  await callKillListeners()
227
231
  process.exit(0)
@@ -2,10 +2,10 @@ import { logger } from "@typed-assistant/logger"
2
2
  import { $ } from "bun"
3
3
 
4
4
  export async function bunInstall() {
5
- logger.info("🏗️ Running bun install...")
5
+ logger.info({ emoji: "🏗️" }, "Running bun install...")
6
6
  return $`bun install --frozen-lockfile --cache-dir=.bun-cache`
7
7
  .text()
8
8
  .catch((error) => {
9
- logger.error(`🚨 Failed to run bun install: ${error}`)
9
+ logger.error({ emoji: "🚨" }, `Failed to run bun install: ${error}`)
10
10
  })
11
11
  }
@@ -21,7 +21,7 @@ export async function callSoftKillListeners() {
21
21
  }
22
22
 
23
23
  export async function killSubprocess(subprocess: Subprocess) {
24
- logger.fatal(`💀 Killing process: ${subprocess.pid}`)
24
+ logger.fatal({ emoji: "💀" }, `Killing process: ${subprocess.pid}`)
25
25
  await callSoftKillListeners()
26
26
  subprocess.kill()
27
27
  await subprocess.exited
@@ -3,22 +3,25 @@ import { $ } from "bun"
3
3
  import { bunInstall } from "./bunInstall"
4
4
 
5
5
  export const pullChanges = async () => {
6
- logger.info("⬇️ Pulling changes...")
7
- const gitPullText = await $`git pull`.text()
6
+ logger.debug({ emoji: "⬇️" }, "Pulling changes...")
7
+ const { stderr, stdout } = await $`git pull`.quiet()
8
+ if (stderr.length > 0) {
9
+ logger.error(
10
+ { emoji: "⬇️🚨" },
11
+ `Failed to pull changes.\n (${stderr.toString().trim()})`,
12
+ )
13
+ }
14
+ const gitPullText = stdout.toString()
8
15
  const packageJSONUpdated = /package.json/.test(gitPullText)
9
16
  const nothingNew = /Already up to date./.test(gitPullText)
10
- if (!gitPullText) {
11
- logger.error("⬇️🚨 Failed to pull changes.")
12
- return { error: "Failed to pull changes." }
13
- }
14
17
  if (nothingNew) {
15
- logger.info("⬇️👌 No new changes.")
18
+ logger.debug({ emoji: "⬇️👌" }, "No new changes.")
16
19
  return {}
17
20
  } else {
18
- logger.info("⬇️🆕 Changes pulled.")
21
+ logger.info({ emoji: "⬇️🆕" }, "Changes pulled.")
19
22
  }
20
23
  if (packageJSONUpdated) {
21
- logger.info("⬇️📦 package.json updated.")
24
+ logger.info({ emoji: "⬇️📦" }, "package.json updated.")
22
25
  await bunInstall()
23
26
  }
24
27
  return {}
@@ -3,10 +3,10 @@ import { getSupervisorAPI } from "@typed-assistant/utils/getHassAPI"
3
3
 
4
4
  export const restartAddon = async () => {
5
5
  if (!process.env.SUPERVISOR_TOKEN) {
6
- logger.fatal("♻️ Can't restart addon. Exiting...")
6
+ logger.fatal({ emoji: "♻️" }, "Can't restart addon. Exiting...")
7
7
  process.exit(1)
8
8
  return
9
9
  }
10
- logger.fatal("♻️ Restarting addon...")
10
+ logger.fatal({ emoji: "♻️" }, "Restarting addon...")
11
11
  await getSupervisorAPI(`/addons/self/restart`, { method: "POST" })
12
12
  }
@@ -1,7 +1,6 @@
1
1
  import { logger } from "@typed-assistant/logger"
2
2
  import { ONE_SECOND } from "@typed-assistant/utils/durations"
3
3
  import { pullChanges } from "./pullChanges"
4
- import { withErrorHandling } from "@typed-assistant/utils/withErrorHandling"
5
4
 
6
5
  export const setupGitPoller = async ({
7
6
  gitPullPollDuration,
@@ -10,9 +9,11 @@ export const setupGitPoller = async ({
10
9
  gitPullPollDuration?: number
11
10
  } = {}) => {
12
11
  const duration = gitPullPollDuration ?? 30
13
- const { error } = await pullChanges()
14
- if (error) return
15
- logger.info(` ⏳ Pulling changes again in ${duration} seconds...`)
12
+ await pullChanges()
13
+ logger.debug(
14
+ { emoji: "⬇️⏳" },
15
+ `Pulling changes again in ${duration} seconds...`,
16
+ )
16
17
 
17
18
  setTimeout(() => {
18
19
  setupGitPoller({ gitPullPollDuration })
@@ -20,12 +20,14 @@ const webhookIsSetup = async (webhookUrl: string) => {
20
20
  .then((d) => d.json())
21
21
 
22
22
  if (error) {
23
- logger.error(`🚨 Failed to reach webhook "${webhookUrl}"`)
24
- logger.error(` ${error.message}`)
23
+ logger.error(
24
+ { additionalDetails: error.message, emoji: "🚨" },
25
+ `Failed to reach webhook "${webhookUrl}"`,
26
+ )
25
27
  return false
26
28
  }
27
29
 
28
- logger.info("🪝 Webhook reached successfully: ")
30
+ logger.debug({ emoji: "🪝" }, "Webhook reached successfully: ")
29
31
  return true
30
32
  }
31
33
 
@@ -124,13 +126,16 @@ export const setupWebhook = async (webhookUrl: string): Promise<void> => {
124
126
  if (retries < 5) {
125
127
  retries++
126
128
  logger.error(
127
- `🔁 Failed fetching webhooks. Retrying setup in ${retryTimeout / 1000}s...`,
129
+ { emoji: "🔁" },
130
+ `Failed fetching webhooks. Retrying setup in ${retryTimeout / 1000}s...`,
128
131
  )
129
132
  setTimeout(setupWebhook, retryTimeout)
130
133
  return
131
134
  }
132
- logger.error("🚨 Failed fetching webhooks. Giving up.")
133
- logger.error(` ${error.message}`)
135
+ logger.error(
136
+ { additionalDetails: error.message, emoji: "🚨" },
137
+ "Failed fetching webhooks. Giving up.",
138
+ )
134
139
  return
135
140
  }
136
141
 
@@ -139,7 +144,7 @@ export const setupWebhook = async (webhookUrl: string): Promise<void> => {
139
144
  )
140
145
 
141
146
  if (webhookAlreadyExists) {
142
- logger.info("🪝 Webhook already set up")
147
+ logger.info({ emoji: "🪝" }, "Webhook already set up")
143
148
  return
144
149
  }
145
150
 
@@ -152,15 +157,18 @@ export const setupWebhook = async (webhookUrl: string): Promise<void> => {
152
157
  if (retries < 5) {
153
158
  retries++
154
159
  logger.error(
155
- `🔁 Failed creating webhook. Retrying setup in ${retryTimeout / 1000}s...`,
160
+ { emoji: "🔁" },
161
+ `Failed creating webhook. Retrying setup in ${retryTimeout / 1000}s...`,
156
162
  )
157
163
  setTimeout(setupWebhook, retryTimeout)
158
164
  return
159
165
  }
160
- logger.error("🚨 Failed creating webhook. Giving up.")
161
- logger.error(` ${createError.message}`)
166
+ logger.error(
167
+ { additionalDetails: createError.message, emoji: "🚨" },
168
+ "Failed creating webhook. Giving up.",
169
+ )
162
170
  return
163
171
  }
164
172
 
165
- logger.info("🪝 Webhook created: " + webhook.config.url)
173
+ logger.info({ emoji: "🪝" }, "Webhook created: " + webhook.config.url)
166
174
  }
@@ -77,10 +77,10 @@ export const startWebappServer = async ({
77
77
  }
78
78
  throw new Error("Build failed")
79
79
  }
80
- logger.info("🛠️ Web server built successfully")
80
+ logger.debug({ emoji: "🛠️" }, "Web server built successfully")
81
81
 
82
82
  await $`bunx tailwindcss -c ${tailwindConfig} -i ${cssFile} -o ${cssOutputFile}`.quiet()
83
- logger.info("💄 Tailwind built successfully")
83
+ logger.debug({ emoji: "💄" }, "Tailwind built successfully")
84
84
 
85
85
  const indexHtml = (await Bun.file(indexHtmlFilePath).text())
86
86
  .replace(
@@ -189,10 +189,10 @@ export const startWebappServer = async ({
189
189
  })
190
190
 
191
191
  server.listen(8099)
192
- logger.info("🌐 Web server listening on port 8099")
192
+ logger.info({ emoji: "🌐" }, "Web server listening on port 8099")
193
193
 
194
194
  const directory = join(process.cwd(), ".")
195
- logger.info("👀 Watching log.txt")
195
+ logger.debug({ emoji: "👀" }, "Watching log.txt")
196
196
  const watcher = watch(directory, function onFileChange(_event, filename) {
197
197
  if (filename === "log.txt") {
198
198
  logSubscribers.forEach((send) => send())
@@ -6,22 +6,13 @@ import { app } from "./api"
6
6
  import { useWS } from "./useWS"
7
7
  import { getPrettyTimestamp } from "@typed-assistant/utils/getPrettyTimestamp"
8
8
  import { levels } from "@typed-assistant/logger/levels"
9
-
10
- const LogSchema = z.object({
11
- level: z.number(),
12
- time: z.number(),
13
- pid: z.number(),
14
- hostname: z.string(),
15
- msg: z.string(),
16
- })
17
-
18
- type LogSchema = z.infer<typeof LogSchema>
9
+ import type { LogSchema } from "@typed-assistant/logger"
19
10
 
20
11
  export const Logs = () => {
21
12
  const [limit, setLimit] = useState(200)
22
13
  const [level, setLevel] = useState<
23
14
  "trace" | "debug" | "info" | "warn" | "error" | "fatal"
24
- >("trace")
15
+ >("info")
25
16
  const [dateTimeVisibility, setDateTimeVisibility] = useState<
26
17
  "hidden" | "timeOnly" | "visible"
27
18
  >("timeOnly")
@@ -35,7 +26,7 @@ export const Logs = () => {
35
26
  onMessage: useCallback((event) => {
36
27
  setLogs(
37
28
  (JSON.parse(event.data).logs as string[]).map((log: string) =>
38
- LogSchema.parse(JSON.parse(log)),
29
+ JSON.parse(log),
39
30
  ),
40
31
  )
41
32
  }, []),
@@ -101,18 +92,33 @@ export const Logs = () => {
101
92
  {logs
102
93
  .filter((log) => log.level >= (levels[level] ?? 0))
103
94
  .sort((a, b) => b.time - a.time)
104
- .map((log, index) => (
105
- <li key={(log.time ?? index) + log.time + log.msg} className="">
106
- <span className="text-slate-400 mr-2">
107
- {dateTimeVisibility === "hidden"
108
- ? null
109
- : dateTimeVisibility === "timeOnly"
110
- ? new Date(log.time).toLocaleTimeString("en-GB")
111
- : getPrettyTimestamp(log.time)}
112
- </span>
113
- {log.msg}
114
- </li>
115
- ))}
95
+ .map((log, index) => {
96
+ return (
97
+ <li
98
+ key={(log.time ?? index) + log.time + log.msg}
99
+ className="flex gap-1"
100
+ >
101
+ <span className="text-slate-400 mr-2">
102
+ {dateTimeVisibility === "hidden"
103
+ ? null
104
+ : dateTimeVisibility === "timeOnly"
105
+ ? new Date(log.time).toLocaleTimeString("en-GB")
106
+ : getPrettyTimestamp(log.time)}
107
+ </span>
108
+ <div className="flex">
109
+ {log.emoji}{" "}
110
+ {log.additionalDetails ? (
111
+ <details>
112
+ <summary>{log.msg}</summary>
113
+ <pre>{log.additionalDetails}</pre>
114
+ </details>
115
+ ) : (
116
+ log.msg
117
+ )}
118
+ </div>
119
+ </li>
120
+ )
121
+ })}
116
122
  </ul>
117
123
  </pre>
118
124
  </AppSection>