import type { AuthAccessSnapshot, AuthAccessStreamEvent, AuthAccessStreamSnapshotEvent, } from "@t3tools/contracts"; import { WS_METHODS } from "@t3tools/contracts"; import * as Stream from "effect/Stream"; import { Atom } from "effect/unstable/reactivity"; import type { EnvironmentRegistry } from "../connection/registry.ts"; import { subscribe } from "../rpc/client.ts"; import { createEnvironmentSubscriptionAtomFamily } from "./runtime.ts"; export const EMPTY_AUTH_ACCESS_SNAPSHOT: AuthAccessSnapshot = { pairingLinks: [], clientSessions: [], }; function upsertByKey( values: ReadonlyArray, next: A, key: (value: A) => string, ): ReadonlyArray { const nextKey = key(next); return [...values.filter((value) => key(value) !== nextKey), next]; } export function applyAuthAccessStreamEvent( current: AuthAccessSnapshot, event: AuthAccessStreamEvent, ): AuthAccessSnapshot { switch (event.type) { case "snapshot": return event.payload; case "pairingLinkUpserted": return { ...current, pairingLinks: upsertByKey(current.pairingLinks, event.payload, (value) => value.id), }; case "pairingLinkRemoved": return { ...current, pairingLinks: current.pairingLinks.filter((value) => value.id !== event.payload.id), }; case "clientUpserted": return { ...current, clientSessions: upsertByKey( current.clientSessions, event.payload, (value) => value.sessionId, ), }; case "clientRemoved": return { ...current, clientSessions: current.clientSessions.filter( (value) => value.sessionId !== event.payload.sessionId, ), }; } } function projectAuthAccessSnapshot( current: AuthAccessSnapshot, event: AuthAccessStreamEvent, ): readonly [AuthAccessSnapshot, ReadonlyArray] { const snapshot = applyAuthAccessStreamEvent(current, event); const projected: AuthAccessStreamSnapshotEvent = { version: 1, revision: event.revision, type: "snapshot", payload: snapshot, }; return [snapshot, [projected]]; } export function createAuthEnvironmentAtoms( runtime: Atom.AtomRuntime, ) { return { accessChanges: createEnvironmentSubscriptionAtomFamily(runtime, { label: "environment-data:server:auth-access-changes", subscribe: (_input: null) => subscribe(WS_METHODS.subscribeAuthAccess, {}).pipe( Stream.mapAccum(() => EMPTY_AUTH_ACCESS_SNAPSHOT, projectAuthAccessSnapshot), ), }), }; }