| 1 | import { useAtomValue } from "@effect/atom-react"; |
| 2 | import { |
| 3 | createManagedRelayQueryManager, |
| 4 | deregisterManagedRelayEnvironment, |
| 5 | ManagedRelay, |
| 6 | managedRelaySessionAtom, |
| 7 | readManagedRelaySnapshotState, |
| 8 | } from "@t3tools/client-runtime/relay"; |
| 9 | import { |
| 10 | createAtomCommandScheduler, |
| 11 | createRuntimeCommand, |
| 12 | } from "@t3tools/client-runtime/state/runtime"; |
| 13 | import type { |
| 14 | RelayClientDeviceRecord, |
| 15 | RelayClientEnvironmentRecord, |
| 16 | } from "@t3tools/contracts/relay"; |
| 17 | import type { EnvironmentId } from "@t3tools/contracts"; |
| 18 | import * as Context from "effect/Context"; |
| 19 | import * as Effect from "effect/Effect"; |
| 20 | import * as Layer from "effect/Layer"; |
| 21 | import { AsyncResult, Atom } from "effect/reactivity"; |
| 22 | import { useCallback, useEffect } from "react"; |
| 23 | |
| 24 | import { runtime } from "../lib/runtime"; |
| 25 | import { appAtomRegistry } from "../rpc/atomRegistry"; |
| 26 | |
| 27 | const managedRelayAtomRuntime = Atom.runtime( |
| 28 | Layer.effect( |
| 29 | ManagedRelay.ManagedRelayClient, |
| 30 | runtime.contextEffect.pipe( |
| 31 | Effect.map((context) => Context.get(context, ManagedRelay.ManagedRelayClient)), |
| 32 | ), |
| 33 | ), |
| 34 | ); |
| 35 | |
| 36 | const managedRelayQueryManager = createManagedRelayQueryManager(managedRelayAtomRuntime); |
| 37 | |
| 38 | const managedRelayMutationScheduler = createAtomCommandScheduler(); |
| 39 | |
| 40 | export const deregisterManagedRelayEnvironmentCommand = createRuntimeCommand( |
| 41 | managedRelayAtomRuntime, |
| 42 | { |
| 43 | label: "web:managed-relay:deregister-environment", |
| 44 | scheduler: managedRelayMutationScheduler, |
| 45 | concurrency: { |
| 46 | mode: "serial", |
| 47 | key: (input: { readonly accountId: string; readonly environmentId: EnvironmentId }) => |
| 48 | input.accountId, |
| 49 | }, |
| 50 | execute: (input, registry) => deregisterManagedRelayEnvironment(registry, input), |
| 51 | }, |
| 52 | ); |
| 53 | |
| 54 | const EMPTY_ENVIRONMENTS_ATOM = Atom.make( |
| 55 | AsyncResult.success<ReadonlyArray<RelayClientEnvironmentRecord>>([]), |
| 56 | ).pipe(Atom.keepAlive, Atom.withLabel("managed-relay:web:environments:null")); |
| 57 | |
| 58 | const EMPTY_DEVICES_ATOM = Atom.make( |
| 59 | AsyncResult.success<ReadonlyArray<RelayClientDeviceRecord>>([]), |
| 60 | ).pipe(Atom.keepAlive, Atom.withLabel("managed-relay:web:devices:null")); |
| 61 | |
| 62 | export function useManagedRelayEnvironments() { |
| 63 | const session = useAtomValue(managedRelaySessionAtom); |
| 64 | const accountId = session?.accountId ?? null; |
| 65 | const atom = accountId |
| 66 | ? managedRelayQueryManager.environmentsAtom(accountId) |
| 67 | : EMPTY_ENVIRONMENTS_ATOM; |
| 68 | const result = useAtomValue(atom); |
| 69 | const snapshot = readManagedRelaySnapshotState(result); |
| 70 | useEffect(() => { |
| 71 | if (snapshot.error) { |
| 72 | console.error("[t3-cloud] Relay environment listing failed", { |
| 73 | message: snapshot.error, |
| 74 | traceId: snapshot.errorTraceId, |
| 75 | }); |
| 76 | } |
| 77 | }, [snapshot.error, snapshot.errorTraceId]); |
| 78 | const refresh = useCallback(() => { |
| 79 | if (accountId) { |
| 80 | managedRelayQueryManager.refreshEnvironments(appAtomRegistry, accountId); |
| 81 | } |
| 82 | }, [accountId]); |
| 83 | |
| 84 | return { |
| 85 | ...snapshot, |
| 86 | accountId, |
| 87 | refresh, |
| 88 | }; |
| 89 | } |
| 90 | |
| 91 | export function useManagedRelayDevices() { |
| 92 | const session = useAtomValue(managedRelaySessionAtom); |
| 93 | const accountId = session?.accountId ?? null; |
| 94 | const atom = accountId ? managedRelayQueryManager.devicesAtom(accountId) : EMPTY_DEVICES_ATOM; |
| 95 | const result = useAtomValue(atom); |
| 96 | const snapshot = readManagedRelaySnapshotState(result); |
| 97 | useEffect(() => { |
| 98 | if (snapshot.error) { |
| 99 | console.error("[t3-cloud] Relay device listing failed", { |
| 100 | message: snapshot.error, |
| 101 | traceId: snapshot.errorTraceId, |
| 102 | }); |
| 103 | } |
| 104 | }, [snapshot.error, snapshot.errorTraceId]); |
| 105 | const refresh = useCallback(() => { |
| 106 | if (accountId) { |
| 107 | managedRelayQueryManager.refreshDevices(appAtomRegistry, accountId); |
| 108 | } |
| 109 | }, [accountId]); |
| 110 | |
| 111 | return { |
| 112 | ...snapshot, |
| 113 | accountId, |
| 114 | refresh, |
| 115 | }; |
| 116 | } |