From bf10908dfc04995368ecf3e45ee946c1b0889457 Mon Sep 17 00:00:00 2001 From: Victor Vogel Date: Sun, 1 Nov 2026 17:46:39 +0000 Subject: [PATCH] refactor(client): share the session scope predicate between web and mobile Co-Authored-By: Claude Opus 5.5 --- apps/mobile/src/state/session.test.ts | 3 ++- apps/mobile/src/state/session.ts | 14 +++++--------- apps/web/src/state/session.ts | 14 +++++--------- packages/client-runtime/src/state/session.ts | 16 +++++++++++++++- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/apps/mobile/src/state/session.test.ts b/apps/mobile/src/state/session.test.ts index c965f8d26bfe6..49b366217ce0c 100644 --- a/apps/mobile/src/state/session.test.ts +++ b/apps/mobile/src/state/session.test.ts @@ -20,7 +20,8 @@ vi.mock("@effect/atom-react", async () => { }; }); vi.mock("../connection/runtime", () => ({ connectionAtomRuntime: {} })); -vi.mock("@t3tools/client-runtime/state/session", () => ({ +vi.mock("@t3tools/client-runtime/state/session", async (importOriginal) => ({ + ...(await importOriginal()), createEnvironmentSessionAtoms: () => ({ sessionStateAtom: Atom.family((_id: EnvironmentId) => Atom.make(AsyncResult.initial()).pipe(Atom.keepAlive), diff --git a/apps/mobile/src/state/session.ts b/apps/mobile/src/state/session.ts index c7fbecab5805d..f1977c20486ea 100644 --- a/apps/mobile/src/state/session.ts +++ b/apps/mobile/src/state/session.ts @@ -1,10 +1,12 @@ import { useAtomValue } from "@effect/atom-react"; -import { createEnvironmentSessionAtoms } from "@t3tools/client-runtime/state/session"; +import { + createEnvironmentSessionAtoms, + sessionHasScope, +} from "@t3tools/client-runtime/state/session"; import { type AuthEnvironmentScope, type AuthSessionState, type EnvironmentId, - sessionGrantsScope, } from "@t3tools/contracts"; import * as Option from "effect/Option"; import { AsyncResult, Atom } from "effect/reactivity"; @@ -17,13 +19,7 @@ export const environmentSession = createEnvironmentSessionAtoms(connectionAtomRu const EMPTY_SESSION_STATE_ATOM = Atom.make(AsyncResult.initial()); -export function sessionHasScope( - result: AsyncResult.AsyncResult, - scope: AuthEnvironmentScope, -): boolean { - const session = AsyncResult.getOrElse(result, () => null); - return result._tag !== "Failure" && session !== null && sessionGrantsScope(session, scope); -} +export { sessionHasScope } from "@t3tools/client-runtime/state/session"; export function useEnvironmentScope( environmentId: EnvironmentId | null, diff --git a/apps/web/src/state/session.ts b/apps/web/src/state/session.ts index 13dffb510b93f..f821b83790667 100644 --- a/apps/web/src/state/session.ts +++ b/apps/web/src/state/session.ts @@ -1,10 +1,12 @@ import { useAtomValue } from "@effect/atom-react"; -import { createEnvironmentSessionAtoms } from "@t3tools/client-runtime/state/session"; +import { + createEnvironmentSessionAtoms, + sessionHasScope, +} from "@t3tools/client-runtime/state/session"; import { type AuthEnvironmentScope, type AuthSessionState, type EnvironmentId, - sessionGrantsScope, } from "@t3tools/contracts"; import * as Option from "effect/Option"; import { AsyncResult, Atom } from "effect/reactivity"; @@ -33,13 +35,7 @@ export function useEnvironmentScope( return sessionHasScope(result, scope); } -export function sessionHasScope( - result: AsyncResult.AsyncResult, - scope: AuthEnvironmentScope, -): boolean { - const session = AsyncResult.getOrElse(result, () => null); - return result._tag !== "Failure" && session !== null && sessionGrantsScope(session, scope); -} +export { sessionHasScope } from "@t3tools/client-runtime/state/session"; const environmentsWithScopeAtom = Atom.family((key: string) => { const [scope, idsKey = ""] = key.split(/\n(.*)/s) as [AuthEnvironmentScope, string?]; diff --git a/packages/client-runtime/src/state/session.ts b/packages/client-runtime/src/state/session.ts index 90afa29f9d05d..37af0778fb38a 100644 --- a/packages/client-runtime/src/state/session.ts +++ b/packages/client-runtime/src/state/session.ts @@ -1,5 +1,11 @@ import { pipe } from "effect/Function"; -import type { AuthSessionState, EnvironmentId, ServerConfig } from "@t3tools/contracts"; +import { + type AuthEnvironmentScope, + type AuthSessionState, + type EnvironmentId, + type ServerConfig, + sessionGrantsScope, +} from "@t3tools/contracts"; import * as Data from "effect/Data"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; @@ -237,3 +243,11 @@ export function createEnvironmentSessionAtoms( sessionAtomsByRuntime.set(runtime, atoms); return atoms; } + +export function sessionHasScope( + result: AsyncResult.AsyncResult, + scope: AuthEnvironmentScope, +): boolean { + const session = AsyncResult.getOrElse(result, () => null); + return result._tag !== "Failure" && session !== null && sessionGrantsScope(session, scope); +}