57 lines · 1.9 KB · TypeScript
RawDownload
import { useAtomValue } from "@effect/atom-react";import type { DesktopBridge, DesktopUpdateState } from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as Queue from "effect/Queue";import * as Stream from "effect/Stream";import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";import { Atom } from "effect/unstable/reactivity"; type DesktopUpdateBridge = Pick<DesktopBridge, "getUpdateState" | "onUpdateState">; function getDesktopUpdateBridge(): DesktopUpdateBridge | undefined {  return typeof window === "undefined" ? undefined : window.desktopBridge;} export function createDesktopUpdateStateAtom(getBridge: () => DesktopUpdateBridge | undefined) {  const updates = Stream.callback<DesktopUpdateState | null>((queue) =>    Effect.gen(function* () {      const bridge = getBridge();      if (!bridge) {        Queue.offerUnsafe(queue, null);        return yield* Effect.never;      }       let receivedUpdate = false;      yield* Effect.acquireRelease(        Effect.sync(() =>          bridge.onUpdateState((state) => {            receivedUpdate = true;            Queue.offerUnsafe(queue, state);          }),        ),        (unsubscribe) => Effect.sync(unsubscribe),      );       const initialState = yield* Effect.tryPromise(() => bridge.getUpdateState()).pipe(        Effect.retry({ times: 2 }),        Effect.orElseSucceed(() => null),      );      if (!receivedUpdate && initialState !== null) {        Queue.offerUnsafe(queue, initialState);      }       return yield* Effect.never;    }),  );   return Atom.make(updates, { initialValue: null }).pipe(    Atom.keepAlive,    Atom.withLabel("desktop:update-state"),  );} const desktopUpdateStateAtom = createDesktopUpdateStateAtom(getDesktopUpdateBridge); export function useDesktopUpdateState(): DesktopUpdateState | null {  return AsyncResult.getOrElse(useAtomValue(desktopUpdateStateAtom), () => null);}