@typed-assistant/builder 0.0.87 → 0.0.89

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,17 @@
1
1
  # @typed-assistant/builder
2
2
 
3
+ ## 0.0.89
4
+
5
+ ### Patch Changes
6
+
7
+ - More robust restarting of app when process error occurs.
8
+
9
+ ## 0.0.88
10
+
11
+ ### Patch Changes
12
+
13
+ - Fire onProcessError when empty stream is detected in web server.
14
+
3
15
  ## 0.0.87
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typed-assistant/builder",
3
- "version": "0.0.87",
3
+ "version": "0.0.89",
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/utils": "0.0.19",
34
- "@typed-assistant/typescript-config": "0.0.11"
33
+ "@typed-assistant/typescript-config": "0.0.11",
34
+ "@typed-assistant/utils": "0.0.19"
35
35
  },
36
36
  "publishConfig": {
37
37
  "access": "public",
@@ -47,16 +47,20 @@ export async function setup({
47
47
  },
48
48
  onProcessError: async (message) => {
49
49
  const messageAll = `${message}. Restarting app...`
50
- logger.fatal({ emoji: "🚨" }, messageAll)
50
+ logger.fatal({ emoji: "🚨" }, messageAll)
51
51
  onProcessError?.(messageAll, addonUrl)
52
- subprocesses = await killAndRestartApp(
52
+ if (subprocesses.app) await killSubprocess(subprocesses.app)
53
+ if (watcher) watcher.close()
54
+ if (processChecker) processChecker.stop()
55
+ if ("stop" in gitPoller) gitPoller.stop()
56
+ setup({
53
57
  entryFile,
54
- { mdiPaths },
55
- subprocesses,
56
- )
58
+ mdiPaths,
59
+ onProcessError,
60
+ })
57
61
  },
58
62
  })
59
- setupWatcher({
63
+ const watcher = setupWatcher({
60
64
  directoryToWatch,
61
65
  entryFile,
62
66
  mdiPaths,
@@ -66,7 +70,7 @@ export async function setup({
66
70
  getSubprocesses: () => subprocesses,
67
71
  })
68
72
 
69
- checkProcesses(entryFile, {
73
+ const processChecker = checkProcesses(entryFile, {
70
74
  onMultiProcessError: (ps) => {
71
75
  const message = `Multiple processes detected. Restarting addon...`
72
76
  logger.fatal({ additionalDetails: ps, emoji: "🚨" }, message)
@@ -84,7 +88,8 @@ export async function setup({
84
88
  )
85
89
  },
86
90
  })
87
- await setupGitSync({
91
+
92
+ const gitPoller = await setupGitSync({
88
93
  onChangesPulled: async () => {
89
94
  subprocesses = await killAndRestartApp(
90
95
  entryFile,
@@ -133,7 +138,7 @@ async function killAndRestartApp(
133
138
 
134
139
  let multipleProcessesErrorCount = 0
135
140
  let noProcessesErrorCount = 0
136
- const checkProcesses = async (
141
+ const checkProcesses = (
137
142
  entryFile: string,
138
143
  {
139
144
  onMultiProcessError,
@@ -143,33 +148,33 @@ const checkProcesses = async (
143
148
  onNoProcessError?: (psOutput: string) => void | Promise<void>
144
149
  },
145
150
  ) => {
146
- const ps = await $`ps -f`.text()
147
- const matches = ps.match(new RegExp(`bun .+${entryFile}`, "gmi")) ?? []
151
+ const interval = setInterval(async () => {
152
+ const ps = await $`ps -f`.text()
153
+ logger.debug({ emoji: "🔍" }, `Checking processes...\n${ps}`)
154
+ const matches = ps.match(new RegExp(`bun .+${entryFile}`, "gmi")) ?? []
148
155
 
149
- if (matches.length > 1) {
150
- multipleProcessesErrorCount++
151
- if (multipleProcessesErrorCount > 5) {
152
- await onMultiProcessError?.(ps)
153
- return
156
+ if (matches.length > 1) {
157
+ multipleProcessesErrorCount++
158
+ if (multipleProcessesErrorCount > 5) {
159
+ await onMultiProcessError?.(ps)
160
+ return
161
+ }
162
+ } else {
163
+ multipleProcessesErrorCount = 0
154
164
  }
155
- } else {
156
- multipleProcessesErrorCount = 0
157
- }
158
165
 
159
- if (matches.length === 0) {
160
- noProcessesErrorCount++
161
- if (noProcessesErrorCount > 5) {
162
- await onNoProcessError?.(ps)
163
- return
166
+ if (matches.length === 0) {
167
+ noProcessesErrorCount++
168
+ if (noProcessesErrorCount > 5) {
169
+ await onNoProcessError?.(ps)
170
+ return
171
+ }
172
+ } else {
173
+ noProcessesErrorCount = 0
164
174
  }
165
- } else {
166
- noProcessesErrorCount = 0
167
- }
175
+ }, 10000)
168
176
 
169
- setTimeout(
170
- () => checkProcesses(entryFile, { onMultiProcessError, onNoProcessError }),
171
- 5000,
172
- )
177
+ return { stop: () => clearInterval(interval) }
173
178
  }
174
179
 
175
180
  const getAddonInfo = async () => {
@@ -200,7 +205,7 @@ const setupGitSync = async ({
200
205
  }
201
206
 
202
207
  logger.warn({ emoji: "⬇️" }, "Setting up git poller...")
203
- await setupGitPoller({ onChangesPulled })
208
+ return setupGitPoller({ onChangesPulled })
204
209
  }
205
210
 
206
211
  const ig = ignore().add(
@@ -11,13 +11,14 @@ export const setupGitPoller = async ({
11
11
  onChangesPulled: () => void
12
12
  }) => {
13
13
  const duration = gitPullPollDuration ?? 30
14
- await pullChanges({ onChangesPulled })
15
- logger.debug(
16
- { emoji: "⬇️⏳" },
17
- `Pulling changes again in ${duration} seconds...`,
18
- )
19
14
 
20
- setTimeout(() => {
21
- setupGitPoller({ gitPullPollDuration, onChangesPulled })
15
+ const interval = setInterval(async () => {
16
+ await pullChanges({ onChangesPulled })
17
+ logger.debug(
18
+ { emoji: "⬇️⏳" },
19
+ `Pulling changes again in ${duration} seconds...`,
20
+ )
22
21
  }, duration * ONE_SECOND)
22
+
23
+ return { stop: () => clearInterval(interval) }
23
24
  }
@@ -346,7 +346,7 @@ export const startWebappServer = async ({
346
346
  await server.stop()
347
347
  })
348
348
 
349
- let emptyStringCount = 0
349
+ let fatalErrorMessage = ""
350
350
 
351
351
  // eslint-disable-next-line no-constant-condition
352
352
  while (true) {
@@ -366,15 +366,8 @@ export const startWebappServer = async ({
366
366
  stdoutResult.done &&
367
367
  (stderrResult.done || stderrResult.value === undefined)
368
368
  if (streamEnded) {
369
- logger.warn(
370
- {
371
- emoji: "😴",
372
- additionalDetails: JSON.stringify({ exitCode: app.exitCode }),
373
- },
374
- "Subprocess output streams ended; waiting for restart or new output",
375
- )
376
- await new Promise((resolve) => setTimeout(resolve, 1000))
377
- continue
369
+ fatalErrorMessage = "Subprocess output streams ended"
370
+ break
378
371
  }
379
372
 
380
373
  const chunk = stdoutResult.value ?? stderrResult.value
@@ -382,35 +375,22 @@ export const startWebappServer = async ({
382
375
  const convertedMessage = convert.toHtml(decodedString)
383
376
  if (convertedMessage !== "") {
384
377
  lastMessage = convertedMessage
378
+ subscribers.forEach((send) => send(convertedMessage))
379
+ } else {
380
+ fatalErrorMessage = "Process is returning an empty string"
381
+ break
385
382
  }
386
- if (convertedMessage === "") {
387
- emptyStringCount += 1
388
- const emptyStringMessage =
389
- "Process is returning an empty string"
390
- if (emptyStringCount === 10) {
391
- onProcessError(emptyStringMessage)
392
- }
393
- subscribers.forEach((send) =>
394
- send("Process is returning an empty string. This was the last non-empty message:\n\n" +
395
- lastMessage),
396
- )
397
- logger.fatal(
398
- {
399
- emoji: "💀",
400
- additionalDetails: JSON.stringify({
401
- exitCode: getSubprocesses().app.exitCode,
402
- }),
403
- },
404
- emptyStringMessage,
405
- )
406
- await new Promise((resolve) => setTimeout(resolve, 1000))
407
- continue
408
- }
409
- emptyStringCount = 0
410
- subscribers.forEach((send) => send(convertedMessage))
411
383
  }
412
384
 
413
- return server
385
+ subscribers.forEach((send) =>
386
+ send(
387
+ "Fatal error occured. This was the last non-empty message:\n\n" +
388
+ lastMessage,
389
+ ),
390
+ )
391
+
392
+ logger.warn({ emoji: "💀" }, fatalErrorMessage)
393
+ onProcessError(fatalErrorMessage)
414
394
  }
415
395
 
416
396
  export type WebServer = Awaited<ReturnType<typeof startWebappServer>>
@@ -428,13 +408,11 @@ const getLogsFromFile = async ({
428
408
  }) => {
429
409
  try {
430
410
  const parsedLimit = Number(limitProp)
431
- const limit = Number.isFinite(parsedLimit) && parsedLimit > 0
432
- ? parsedLimit
433
- : undefined
411
+ const limit =
412
+ Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : undefined
434
413
  const parsedOffset = Number(offsetProp)
435
- const offset = Number.isFinite(parsedOffset) && parsedOffset >= 0
436
- ? parsedOffset
437
- : 0
414
+ const offset =
415
+ Number.isFinite(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0
438
416
 
439
417
  const normalizedFilter = filter?.toLowerCase().trim()
440
418
 
@@ -450,7 +428,7 @@ const getLogsFromFile = async ({
450
428
  return result.concat({
451
429
  msg: e instanceof Error ? e.message : "Unknown parse error",
452
430
  level: levels.fatal,
453
- })
431
+ } as LogSchema)
454
432
  }
455
433
  }, [] as LogSchema[])
456
434