@carlesandres/house 0.4.0 → 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.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Process-singleton wiring for the update probe.
3
+ *
4
+ * The probe runs at most once per process. The result lands in a module
5
+ * variable so:
6
+ * - any UI surface (DiscoverShell, App) can subscribe and re-render when
7
+ * it resolves, without each one issuing its own request;
8
+ * - the `process.on("exit")` hook can synchronously read the result and
9
+ * print the quit-time notice (async work can't run during 'exit').
10
+ *
11
+ * Failures resolve to `null` — silent by design. See `check.ts`.
12
+ */
13
+
14
+ import type { UpdateInfo } from "./check.ts"
15
+ import { checkForUpdate } from "./check.ts"
16
+
17
+ let current: UpdateInfo | null = null
18
+ let started = false
19
+ let pending: Promise<void> | null = null
20
+ const listeners = new Set<(info: UpdateInfo) => void>()
21
+
22
+ export const startUpdateProbe = (pkgName: string, currentVersion: string): Promise<void> => {
23
+ if (pending) return pending
24
+ started = true
25
+ pending = checkForUpdate({ pkgName, currentVersion })
26
+ .then((info) => {
27
+ if (info) {
28
+ current = info
29
+ for (const cb of listeners) cb(info)
30
+ }
31
+ })
32
+ .catch(() => {
33
+ // silent — the feature is opportunistic
34
+ })
35
+ return pending
36
+ }
37
+
38
+ export const currentUpdateInfo = (): UpdateInfo | null => current
39
+
40
+ export const subscribeUpdateInfo = (cb: (info: UpdateInfo) => void): (() => void) => {
41
+ if (current) cb(current)
42
+ listeners.add(cb)
43
+ return () => {
44
+ listeners.delete(cb)
45
+ }
46
+ }
47
+
48
+ export const isProbeStarted = (): boolean => started
@@ -0,0 +1,24 @@
1
+ /**
2
+ * React hook for the update-available footer toast.
3
+ *
4
+ * Returns the formatted one-liner once the singleton probe resolves with a
5
+ * strictly-newer-and-downloadable version, and `null` otherwise. Mounting
6
+ * multiple consumers is safe — they all share the same probe via
7
+ * `runtime.ts`.
8
+ */
9
+
10
+ import { useEffect, useState } from "react"
11
+ import { currentUpdateInfo, subscribeUpdateInfo } from "./runtime.ts"
12
+ import { formatFooterNotice } from "./notice.ts"
13
+
14
+ export const useUpdateNotice = (): string | null => {
15
+ const [text, setText] = useState<string | null>(() => {
16
+ const cur = currentUpdateInfo()
17
+ return cur ? formatFooterNotice(cur) : null
18
+ })
19
+ useEffect(() => {
20
+ const unsub = subscribeUpdateInfo((info) => setText(formatFooterNotice(info)))
21
+ return unsub
22
+ }, [])
23
+ return text
24
+ }