@typed-assistant/builder 0.0.35 → 0.0.37
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 +3 -3
- package/src/appProcess.tsx +53 -51
- package/src/getAddonInfo.tsx +69 -10
- package/src/setupWebhook.tsx +1 -13
- package/src/setupWebserver.tsx +10 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed-assistant/builder",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"exports": {
|
|
5
5
|
"./appProcess": "./src/appProcess.tsx",
|
|
6
6
|
"./bunInstall": "./src/bunInstall.tsx",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"ts-toolbelt": "^9.6.0",
|
|
26
26
|
"typescript": "^5.3.3",
|
|
27
27
|
"@typed-assistant/eslint-config": "0.0.8",
|
|
28
|
+
"@typed-assistant/logger": "0.0.12",
|
|
28
29
|
"@typed-assistant/typescript-config": "0.0.8",
|
|
29
|
-
"@typed-assistant/utils": "0.0.
|
|
30
|
-
"@typed-assistant/logger": "0.0.12"
|
|
30
|
+
"@typed-assistant/utils": "0.0.13"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"home-assistant-js-websocket": "^8.2.0"
|
package/src/appProcess.tsx
CHANGED
|
@@ -15,7 +15,46 @@ import { setupGitPoller } from "./setupGitPoller"
|
|
|
15
15
|
import { setupWebhook } from "./setupWebhook"
|
|
16
16
|
import { startWebappServer } from "./setupWebserver"
|
|
17
17
|
import { restartAddon } from "./restartAddon"
|
|
18
|
-
import { getAddonInfo } from "./getAddonInfo"
|
|
18
|
+
import { getAddonInfo as getAddonInfoAPI } from "./getAddonInfo"
|
|
19
|
+
import debounce from "debounce"
|
|
20
|
+
|
|
21
|
+
export async function setup({
|
|
22
|
+
entryFile,
|
|
23
|
+
mdiPaths,
|
|
24
|
+
onProcessError,
|
|
25
|
+
}: {
|
|
26
|
+
entryFile: string
|
|
27
|
+
} & Parameters<typeof generateTypes>[0] &
|
|
28
|
+
Pick<Parameters<typeof checkProcesses>[1], "onProcessError">) {
|
|
29
|
+
const addonInfo = await getAddonInfo()
|
|
30
|
+
const basePath = addonInfo?.data.ingress_entry ?? ""
|
|
31
|
+
const slug = addonInfo?.data.slug ?? ""
|
|
32
|
+
const directoryToWatch = join(process.cwd(), "./src")
|
|
33
|
+
const addonUrl = `${slug}/ingress`
|
|
34
|
+
|
|
35
|
+
checkProcesses(entryFile, { addonUrl, onProcessError })
|
|
36
|
+
await setupGitSync()
|
|
37
|
+
|
|
38
|
+
let subprocesses = await buildAndStartAppProcess(entryFile, {
|
|
39
|
+
mdiPaths: mdiPaths,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
startWebappServer({
|
|
43
|
+
basePath,
|
|
44
|
+
getSubprocesses: () => subprocesses,
|
|
45
|
+
})
|
|
46
|
+
setupWatcher({
|
|
47
|
+
directoryToWatch,
|
|
48
|
+
entryFile,
|
|
49
|
+
mdiPaths,
|
|
50
|
+
onSubprocessChange: (newSubprocesses) => {
|
|
51
|
+
subprocesses = newSubprocesses
|
|
52
|
+
},
|
|
53
|
+
getSubprocesses: () => subprocesses,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
return subprocesses
|
|
57
|
+
}
|
|
19
58
|
|
|
20
59
|
type Processes = Awaited<ReturnType<typeof buildAndStartAppProcess>>
|
|
21
60
|
|
|
@@ -58,15 +97,9 @@ const checkProcesses = async (
|
|
|
58
97
|
{
|
|
59
98
|
addonUrl,
|
|
60
99
|
onProcessError,
|
|
61
|
-
restartAddonUrl,
|
|
62
100
|
}: {
|
|
63
101
|
addonUrl: string
|
|
64
|
-
onProcessError?: (
|
|
65
|
-
message: string,
|
|
66
|
-
addonUrl: string,
|
|
67
|
-
restartAddonUrl?: string,
|
|
68
|
-
) => void
|
|
69
|
-
restartAddonUrl: string
|
|
102
|
+
onProcessError?: (message: string, addonUrl: string) => void
|
|
70
103
|
},
|
|
71
104
|
) => {
|
|
72
105
|
const ps = await $`ps -f`.text()
|
|
@@ -75,11 +108,10 @@ const checkProcesses = async (
|
|
|
75
108
|
if (matches.length > 1) {
|
|
76
109
|
multipleProcessesErrorCount++
|
|
77
110
|
if (multipleProcessesErrorCount > 5) {
|
|
78
|
-
const message = `🚨 Multiple processes detected.
|
|
111
|
+
const message = `🚨 Multiple processes detected. Check the logs...`
|
|
79
112
|
log(message)
|
|
80
113
|
log(ps)
|
|
81
|
-
onProcessError?.(message, addonUrl
|
|
82
|
-
// restartAddon()
|
|
114
|
+
onProcessError?.(message, addonUrl)
|
|
83
115
|
return
|
|
84
116
|
}
|
|
85
117
|
} else {
|
|
@@ -89,11 +121,10 @@ const checkProcesses = async (
|
|
|
89
121
|
if (matches.length === 0) {
|
|
90
122
|
noProcessesErrorCount++
|
|
91
123
|
if (noProcessesErrorCount > 5) {
|
|
92
|
-
const message = `🚨 No processes detected.
|
|
124
|
+
const message = `🚨 No processes detected. Check the logs...`
|
|
93
125
|
log(message)
|
|
94
126
|
log(ps)
|
|
95
|
-
onProcessError?.(message, addonUrl
|
|
96
|
-
// restartAddon()
|
|
127
|
+
onProcessError?.(message, addonUrl)
|
|
97
128
|
return
|
|
98
129
|
}
|
|
99
130
|
} else {
|
|
@@ -101,48 +132,19 @@ const checkProcesses = async (
|
|
|
101
132
|
}
|
|
102
133
|
|
|
103
134
|
setTimeout(
|
|
104
|
-
() =>
|
|
105
|
-
checkProcesses(entryFile, { addonUrl, onProcessError, restartAddonUrl }),
|
|
135
|
+
() => checkProcesses(entryFile, { addonUrl, onProcessError }),
|
|
106
136
|
5000,
|
|
107
137
|
)
|
|
108
138
|
}
|
|
109
139
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
mdiPaths,
|
|
113
|
-
onProcessError,
|
|
114
|
-
}: {
|
|
115
|
-
entryFile: string
|
|
116
|
-
} & Parameters<typeof generateTypes>[0] &
|
|
117
|
-
Pick<Parameters<typeof checkProcesses>[1], "onProcessError">) {
|
|
118
|
-
const addonInfo = await getAddonInfo()
|
|
119
|
-
const basePath = addonInfo?.data.ingress_entry ?? ""
|
|
120
|
-
const directoryToWatch = join(process.cwd(), "./src")
|
|
121
|
-
const addonUrl = basePath
|
|
122
|
-
const restartAddonUrl = `${basePath}/restart-addon`
|
|
140
|
+
const getAddonInfo = async () => {
|
|
141
|
+
log("🔍 Getting addon info...")
|
|
123
142
|
|
|
124
|
-
|
|
125
|
-
await setupGitSync()
|
|
143
|
+
const { data, error } = await getAddonInfoAPI()
|
|
126
144
|
|
|
127
|
-
|
|
128
|
-
mdiPaths: mdiPaths,
|
|
129
|
-
})
|
|
145
|
+
if (error) log(`🚨 Failed to get addon info: ${error}`)
|
|
130
146
|
|
|
131
|
-
|
|
132
|
-
basePath,
|
|
133
|
-
getSubprocesses: () => subprocesses,
|
|
134
|
-
})
|
|
135
|
-
setupWatcher({
|
|
136
|
-
directoryToWatch,
|
|
137
|
-
entryFile,
|
|
138
|
-
mdiPaths,
|
|
139
|
-
onSubprocessChange: (newSubprocesses) => {
|
|
140
|
-
subprocesses = newSubprocesses
|
|
141
|
-
},
|
|
142
|
-
getSubprocesses: () => subprocesses,
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
return subprocesses
|
|
147
|
+
return data
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
const setupGitSync = async () => {
|
|
@@ -191,7 +193,7 @@ function setupWatcher({
|
|
|
191
193
|
const watcher = watch(
|
|
192
194
|
directoryToWatch,
|
|
193
195
|
{ recursive: true },
|
|
194
|
-
async function onFileChange(event, filename) {
|
|
196
|
+
debounce(async function onFileChange(event, filename) {
|
|
195
197
|
if (!filename) return
|
|
196
198
|
if (shouldIgnoreFileOrFolder(filename)) return
|
|
197
199
|
log(`⚠️ Change to ${filename} detected.`)
|
|
@@ -203,7 +205,7 @@ function setupWatcher({
|
|
|
203
205
|
await killAndRestartApp(entryFile, { mdiPaths }, getSubprocesses()),
|
|
204
206
|
)
|
|
205
207
|
}
|
|
206
|
-
},
|
|
208
|
+
}, 200),
|
|
207
209
|
)
|
|
208
210
|
|
|
209
211
|
addKillListener(() => {
|
package/src/getAddonInfo.tsx
CHANGED
|
@@ -2,14 +2,73 @@ import { log } from "@typed-assistant/logger"
|
|
|
2
2
|
import { getSupervisorAPI } from "@typed-assistant/utils/getHassAPI"
|
|
3
3
|
import { withErrorHandling } from "@typed-assistant/utils/withErrorHandling"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
type AddonInfoResponse = {
|
|
6
|
+
result: string
|
|
7
|
+
data: {
|
|
8
|
+
name: string
|
|
9
|
+
slug: string
|
|
10
|
+
hostname: string
|
|
11
|
+
description: string
|
|
12
|
+
long_description: string
|
|
13
|
+
advanced: boolean
|
|
14
|
+
stage: string
|
|
15
|
+
repository: string
|
|
16
|
+
version_latest: string
|
|
17
|
+
protected: boolean
|
|
18
|
+
rating: number
|
|
19
|
+
boot: string
|
|
20
|
+
arch: string[]
|
|
21
|
+
machine: any[]
|
|
22
|
+
homeassistant: null
|
|
23
|
+
url: string
|
|
24
|
+
detached: boolean
|
|
25
|
+
available: boolean
|
|
26
|
+
build: boolean
|
|
27
|
+
network: null
|
|
28
|
+
network_description: null
|
|
29
|
+
host_network: boolean
|
|
30
|
+
host_pid: boolean
|
|
31
|
+
host_ipc: boolean
|
|
32
|
+
host_uts: boolean
|
|
33
|
+
host_dbus: boolean
|
|
34
|
+
full_access: boolean
|
|
35
|
+
apparmor: string
|
|
36
|
+
icon: boolean
|
|
37
|
+
logo: boolean
|
|
38
|
+
changelog: boolean
|
|
39
|
+
documentation: boolean
|
|
40
|
+
stdin: boolean
|
|
41
|
+
hassio_api: boolean
|
|
42
|
+
hassio_role: string
|
|
43
|
+
auth_api: boolean
|
|
44
|
+
homeassistant_api: boolean
|
|
45
|
+
gpio: boolean
|
|
46
|
+
usb: boolean
|
|
47
|
+
uart: boolean
|
|
48
|
+
kernel_modules: boolean
|
|
49
|
+
devicetree: boolean
|
|
50
|
+
udev: boolean
|
|
51
|
+
docker_api: boolean
|
|
52
|
+
video: boolean
|
|
53
|
+
audio: boolean
|
|
54
|
+
startup: string
|
|
55
|
+
ingress: boolean
|
|
56
|
+
signed: boolean
|
|
57
|
+
state: string
|
|
58
|
+
webui: null
|
|
59
|
+
ingress_entry: string
|
|
60
|
+
ingress_url: string
|
|
61
|
+
ingress_port: number
|
|
62
|
+
ingress_panel: boolean
|
|
63
|
+
audio_input: null
|
|
64
|
+
audio_output: null
|
|
65
|
+
auto_update: boolean
|
|
66
|
+
ip_address: string
|
|
67
|
+
version: string
|
|
68
|
+
update_available: boolean
|
|
69
|
+
watchdog: boolean
|
|
70
|
+
}
|
|
15
71
|
}
|
|
72
|
+
|
|
73
|
+
export const getAddonInfo = () =>
|
|
74
|
+
withErrorHandling(getSupervisorAPI)<AddonInfoResponse>("/addons/self/info")
|
package/src/setupWebhook.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { log } from "@typed-assistant/logger"
|
|
2
|
+
import { handleFetchError } from "@typed-assistant/utils/getHassAPI"
|
|
2
3
|
import { withErrorHandling } from "@typed-assistant/utils/withErrorHandling"
|
|
3
4
|
import { z } from "zod"
|
|
4
5
|
|
|
@@ -97,19 +98,6 @@ const Webhook = z.object({
|
|
|
97
98
|
|
|
98
99
|
type Webhook = z.infer<typeof Webhook>
|
|
99
100
|
|
|
100
|
-
const handleFetchError = async (d: Response): Promise<Response> => {
|
|
101
|
-
if (!d.ok)
|
|
102
|
-
throw new Error(
|
|
103
|
-
d.status +
|
|
104
|
-
" " +
|
|
105
|
-
d.statusText +
|
|
106
|
-
(d.headers.get("Content-Type")?.includes("application/json")
|
|
107
|
-
? `:\n${JSON.stringify(await d.json(), null, 2)}`
|
|
108
|
-
: ""),
|
|
109
|
-
)
|
|
110
|
-
return d
|
|
111
|
-
}
|
|
112
|
-
|
|
113
101
|
const retryTimeout = 2000
|
|
114
102
|
let retries = 0
|
|
115
103
|
export const setupWebhook = async (): Promise<void> => {
|
package/src/setupWebserver.tsx
CHANGED
|
@@ -6,15 +6,9 @@ import { Elysia, t } from "elysia"
|
|
|
6
6
|
import { watch } from "fs"
|
|
7
7
|
import { basename, join } from "path"
|
|
8
8
|
import type { List, String } from "ts-toolbelt"
|
|
9
|
-
import {
|
|
10
|
-
addKillListener,
|
|
11
|
-
addSoftKillListener,
|
|
12
|
-
killSubprocess,
|
|
13
|
-
} from "./killProcess"
|
|
14
|
-
import { restartAddon } from "./restartAddon"
|
|
15
9
|
import { getAddonInfo } from "./getAddonInfo"
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
10
|
+
import { addKillListener, killSubprocess } from "./killProcess"
|
|
11
|
+
import { restartAddon } from "./restartAddon"
|
|
18
12
|
|
|
19
13
|
const indexHtmlFilePath = `${import.meta.dir}/webserver/index.html` as const
|
|
20
14
|
const cssFile = `${import.meta.dir}/webserver/input.css` as const
|
|
@@ -114,14 +108,18 @@ export const startWebappServer = async ({
|
|
|
114
108
|
.get("/restart-addon", async () => {
|
|
115
109
|
await killSubprocess(getSubprocesses().app)
|
|
116
110
|
restartAddon()
|
|
111
|
+
return { message: "Restarting addon..." }
|
|
117
112
|
})
|
|
118
113
|
.get("/addon-info", async () => {
|
|
119
|
-
const { data, error } = await
|
|
120
|
-
data: { ingress_entry: string }
|
|
121
|
-
}>("/addons/self/info")
|
|
114
|
+
const { data, error } = await getAddonInfo()
|
|
122
115
|
|
|
123
116
|
if (error) return error
|
|
124
|
-
return
|
|
117
|
+
return {
|
|
118
|
+
...data.data,
|
|
119
|
+
options: "HIDDEN",
|
|
120
|
+
schema: "HIDDEN",
|
|
121
|
+
translations: "HIDDEN",
|
|
122
|
+
}
|
|
125
123
|
})
|
|
126
124
|
.get(
|
|
127
125
|
"/log.txt",
|