@fabrika/daemon-kit 0.3.3 → 0.4.1

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/README.md CHANGED
@@ -4,7 +4,7 @@ Bun daemon infrastructure without canvas or browser dependencies:
4
4
 
5
5
  - `createNotificationChannel`, `browserFrame`: topic-based WebSocket routing.
6
6
  - `waitForEvent`, `WaitError`: CLI waiting, reconnects and deadlines.
7
- - `createDaemonLifecycle`, `DaemonStartError`: process startup, health and shutdown.
7
+ - `createDaemonLifecycle`, `DaemonStartError`, `DaemonStopError`: process startup, health and shutdown.
8
8
  - `dispatch`, `Route`: HTTP routing.
9
9
  - `jsonResponse`, `corsHeaders`: HTTP response helpers.
10
10
 
package/index.ts CHANGED
@@ -9,7 +9,7 @@ export type {
9
9
  TopicChannel,
10
10
  } from './src/channel'
11
11
  export { corsHeaders, jsonResponse } from './src/http-utils'
12
- export { createDaemonLifecycle, DaemonStartError } from './src/lifecycle'
12
+ export { createDaemonLifecycle, DaemonStartError, DaemonStopError } from './src/lifecycle'
13
13
  export type {
14
14
  DaemonEvent,
15
15
  DaemonHealth,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabrika/daemon-kit",
3
- "version": "0.3.3",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Bun daemon lifecycle, HTTP routing, WebSocket channels and CLI waiters.",
6
6
  "license": "MIT",
package/src/lifecycle.ts CHANGED
@@ -99,11 +99,22 @@ export class DaemonStartError extends Error {
99
99
  }
100
100
  }
101
101
 
102
+ /** A daemon of the wrong version still answers after `stop()`, so no second one is spawned onto its port. */
103
+ export class DaemonStopError extends Error {
104
+ constructor(message: string, readonly pid: number) {
105
+ super(message)
106
+ this.name = 'DaemonStopError'
107
+ }
108
+ }
109
+
102
110
  export interface DaemonLifecycle<H extends DaemonPid> {
103
111
  health(timeoutMs?: number): Promise<DaemonHealth<H>>
104
112
  isRunning(): Promise<boolean>
105
113
  start(): Promise<DaemonHealthUp<H>>
106
- /** A healthy daemon of the expected version, starting or restarting one if needed. */
114
+ /**
115
+ * A healthy daemon of the expected version, starting or restarting one if needed.
116
+ * Throws `DaemonStopError` when a daemon of another version cannot be stopped.
117
+ */
107
118
  ensure(): Promise<DaemonHealthUp<H>>
108
119
  stop(): Promise<DaemonStopResult>
109
120
  restart(): Promise<DaemonHealthUp<H>>
@@ -269,7 +280,12 @@ export function createDaemonLifecycle<H extends DaemonPid>(
269
280
  const running = check?.of(current)
270
281
  if (check && running && running !== check.expected) {
271
282
  emit({ type: 'version-mismatch', running, expected: check.expected })
272
- await stop()
283
+ const stopped = await stop()
284
+ // A spawned daemon would find the port taken, or take it the moment the old one exits.
285
+ const remaining = await health()
286
+ if (remaining.status === 'up') {
287
+ throw new DaemonStopError(`${stopped.message} Not starting a second daemon on ${config.baseUrl}.`, remaining.pid)
288
+ }
273
289
  return await start()
274
290
  }
275
291
  return current