Unified · Split
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | import { Link, Outlet, useLocation } from "@tanstack/react-router"; |
| 2 | 2 | import { useCallback, useEffect, useRef, useState } from "react"; |
| 3 | 3 | import { useAtomRefresh } from "@effect/atom-react"; |
| 4 | +import { Data, Effect, Exit } from "effect"; | |
| 4 | 5 | import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; |
| 5 | 6 | import { sourcesAtom, toolsAtom } from "@executor-js/react/api/atoms"; |
| 6 | 7 | import { useSourcesWithPending } from "@executor-js/react/api/optimistic"; |
| @@ -29,6 +30,10 @@ type UpdateChannel = "latest" | "beta"; · 22 unmodified lines | ||
| 29 | 30 | |
| 30 | 31 | const EXECUTOR_DIST_TAGS_PATH = "/v1/app/npm/dist-tags"; |
| 31 | 32 | |
| 33 | +class LatestVersionCheckError extends Data.TaggedError("LatestVersionCheckError")<{ | |
| 34 | + readonly cause: unknown; | |
| 35 | +}> {} | |
| 36 | + | |
| 32 | 37 | type ParsedVersion = { |
| 33 | 38 | readonly major: number; |
| 34 | 39 | readonly minor: number; |
| @@ -95,15 +100,22 @@ function useLatestVersion(currentVersion: string) { · 60 unmodified lines | ||
| 95 | 100 | |
| 96 | 101 | useEffect(() => { |
| 97 | 102 | let cancelled = false; |
| 98 | − fetch(EXECUTOR_DIST_TAGS_PATH) | |
| 99 | − .then(async (res) => { | |
| 100 | − if (!res.ok) throw new Error(`Failed to load dist tags: ${res.status}`); | |
| 101 | − return res.json() as Promise<Partial<Record<UpdateChannel, string>>>; | |
| 102 | − }) | |
| 103 | − .then((data) => { | |
| 104 | − if (!cancelled) setLatestVersion(data[channel] ?? null); | |
| 105 | − }) | |
| 106 | − .catch(() => {}); | |
| 103 | + | |
| 104 | + const latestVersionEffect = Effect.tryPromise({ | |
| 105 | + try: async () => { | |
| 106 | + const res = await fetch(EXECUTOR_DIST_TAGS_PATH); | |
| 107 | + if (!res.ok) return {}; | |
| 108 | + return (await res.json()) as Partial<Record<UpdateChannel, string>>; | |
| 109 | + }, | |
| 110 | + catch: (cause) => new LatestVersionCheckError({ cause }), | |
| 111 | + }); | |
| 112 | + | |
| 113 | + void Effect.runPromiseExit(latestVersionEffect).then((exit) => { | |
| 114 | + if (!cancelled && Exit.isSuccess(exit)) { | |
| 115 | + setLatestVersion(exit.value[channel] ?? null); | |
| 116 | + } | |
| 117 | + }); | |
| 118 | + | |
| 107 | 119 | return () => { |
| 108 | 120 | cancelled = true; |
| 109 | 121 | }; |