import * as NodeServices from "@effect/platform-node/NodeServices";import { AuthAdministrativeScopes } from "@t3tools/contracts";import { expect, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer"; import * as ServerConfig from "../config.ts";import * as ServerEnvironment from "../environment/ServerEnvironment.ts";import { SqlitePersistenceMemory } from "../persistence/Layers/Sqlite.ts";import * as PairingGrantStore from "./PairingGrantStore.ts";import * as EnvironmentAuth from "./EnvironmentAuth.ts"; import * as ServerSecretStore from "./ServerSecretStore.ts";import * as SessionStore from "./SessionStore.ts"; /** Pinned so dev-mode cookie tests can assert the port-scoped name. */const TEST_SERVER_PORT = 13_773; const makeServerConfigLayer = (overrides?: Partial<ServerConfig.ServerConfig["Service"]>) => Layer.effect( ServerConfig.ServerConfig, Effect.gen(function* () { const config = yield* ServerConfig.ServerConfig; return { ...config, ...overrides, // Keep the test server deterministic even when the default test layer // changes its development port. port: TEST_SERVER_PORT, } satisfies ServerConfig.ServerConfig["Service"]; }), ).pipe(Layer.provide(ServerConfig.layerTest(process.cwd(), { prefix: "t3-auth-server-test-" }))); const makeEnvironmentAuthLayer = (overrides?: Partial<ServerConfig.ServerConfig["Service"]>) => EnvironmentAuth.layer.pipe( Layer.provide(SqlitePersistenceMemory), Layer.provide(ServerSecretStore.layer), Layer.provide(ServerEnvironment.identityLayer), Layer.provide(makeServerConfigLayer(overrides)), ); const makeCookieRequest = ( cookieName: string, sessionToken: string,): Parameters<EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"]>[0] => ({ cookies: { [cookieName]: sessionToken, }, headers: {}, }) as unknown as Parameters< EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"] >[0]; const makeBearerRequest = ( token: string,): Parameters<EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"]>[0] => ({ cookies: {}, headers: { authorization: `Bearer ${token}`, }, }) as unknown as Parameters< EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"] >[0]; const requestMetadata = { deviceType: "desktop" as const, os: "macOS", browser: "Chrome", ipAddress: "192.168.1.23",}; it.layer(NodeServices.layer)("EnvironmentAuth.layer", (it) => { it.effect("classifies invalid bootstrap credential failures for the HTTP boundary", () => Effect.sync(() => { const error = EnvironmentAuth.toBootstrapExchangeError( new PairingGrantStore.UnknownBootstrapCredentialError({}), ); expect(error._tag).toBe("ServerAuthInvalidCredentialError"); }), ); it.effect("maps unexpected bootstrap failures to 500", () => Effect.sync(() => { const cause = new PairingGrantStore.BootstrapCredentialConsumeError({ cause: new Error("sqlite is unavailable"), }); const error = EnvironmentAuth.toBootstrapExchangeError(cause); expect(error._tag).toBe("ServerAuthBootstrapCredentialValidationError"); expect(error.message).toBe("Failed to validate bootstrap credential."); if (error._tag === "ServerAuthBootstrapCredentialValidationError") { expect(error.cause).toBe(cause); } }), ); it.effect("issues standard pairing credentials by default", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sessions = yield* SessionStore.SessionStore; const pairingCredential = yield* serverAuth.issuePairingCredential(); const exchanged = yield* serverAuth.createBrowserSession( pairingCredential.credential, requestMetadata, ); const verified = yield* serverAuth.authenticateHttpRequest( makeCookieRequest(sessions.cookieName, exchanged.sessionToken), ); expect(verified.sessionId.length).toBeGreaterThan(0); expect(verified.scopes).toEqual([ "orchestration:read", "orchestration:operate", "terminal:operate", "review:write", "relay:read", ]); expect(verified.subject).toBe("one-time-token"); }).pipe(Effect.provide(makeEnvironmentAuthLayer())), ); it.effect("prefers a bearer token over a stale legacy cookie", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sessions = yield* SessionStore.SessionStore; const bearer = yield* serverAuth.issueSession(); const verified = yield* serverAuth.authenticateHttpRequest({ cookies: { [sessions.legacyCookieName ?? "t3_session"]: "stale" }, headers: { authorization: `Bearer ${bearer.token}` }, } as never); expect(verified.sessionId).toBe(bearer.sessionId); }).pipe(Effect.provide(makeEnvironmentAuthLayer({ mode: "web", host: "192.168.1.50" }))), ); it.effect("does not exchange ordinary pairing grants for administrative access tokens", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const pairingCredential = yield* serverAuth.issuePairingCredential(); const error = yield* serverAuth .exchangeBootstrapCredentialForAccessToken( pairingCredential.credential, ["orchestration:read", "access:write"], requestMetadata, ) .pipe(Effect.flip); expect(error._tag).toBe("ServerAuthScopeNotGrantedError"); }).pipe(Effect.provide(makeEnvironmentAuthLayer())), ); it.effect("inherits a constrained pairing grant when token exchange omits scope", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const pairingCredential = yield* serverAuth.issuePairingCredential({ scopes: ["orchestration:read"], }); const token = yield* serverAuth.exchangeBootstrapCredentialForAccessToken( pairingCredential.credential, undefined, requestMetadata, ); expect(token.scope).toBe("orchestration:read"); }).pipe(Effect.provide(makeEnvironmentAuthLayer())), ); it.effect("rotates desktop bearer sessions without accumulating authorized clients", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sessions = yield* SessionStore.SessionStore; const browser = yield* serverAuth.createBrowserSession( "desktop-bootstrap-token", requestMetadata, ); const browserSession = yield* serverAuth.authenticateHttpRequest( makeCookieRequest(sessions.cookieName, browser.sessionToken), ); const staleSessions = yield* Effect.forEach([1, 2, 3], () => sessions.issue({ subject: "desktop-bootstrap", method: "bearer-access-token" }), ); const pairing = yield* serverAuth.issuePairingCredential(); const paired = yield* serverAuth.exchangeBootstrapCredentialForAccessToken( pairing.credential, undefined, { ...requestMetadata, label: "T3 Code Desktop" }, ); const first = yield* serverAuth.exchangeBootstrapCredentialForAccessToken( "desktop-bootstrap-token", undefined, requestMetadata, ); const firstSession = yield* serverAuth.authenticateHttpRequest( makeBearerRequest(first.access_token), ); const second = yield* serverAuth.exchangeBootstrapCredentialForAccessToken( "desktop-bootstrap-token", undefined, requestMetadata, ); const active = yield* serverAuth.listSessions(); const firstError = yield* serverAuth .authenticateHttpRequest(makeBearerRequest(first.access_token)) .pipe(Effect.flip); const secondSession = yield* serverAuth.authenticateHttpRequest( makeBearerRequest(second.access_token), ); expect(active).toHaveLength(3); expect(active.map((entry) => entry.sessionId)).toContain(browserSession.sessionId); expect(active.map((entry) => entry.sessionId)).toContain(secondSession.sessionId); expect(active.map((entry) => entry.sessionId)).not.toContain(firstSession.sessionId); expect(firstError._tag).toBe("ServerAuthInvalidCredentialError"); for (const stale of staleSessions) { const error = yield* sessions.verify(stale.token).pipe(Effect.flip); expect(error._tag).toBe("SessionTokenRevokedError"); } const pairedSession = yield* serverAuth.authenticateHttpRequest( makeBearerRequest(paired.access_token), ); expect(pairedSession.subject).toBe("one-time-token"); expect(active.map((entry) => entry.sessionId)).toContain(pairedSession.sessionId); }).pipe( Effect.provide( makeEnvironmentAuthLayer({ desktopBootstrapToken: "desktop-bootstrap-token", }), ), ), ); it.effect("keeps user-issued administrative pairing links manageable", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const pairingCredential = yield* serverAuth.issuePairingCredential({ scopes: AuthAdministrativeScopes, }); const listedPairingLinks = yield* serverAuth.listPairingLinks(); expect( listedPairingLinks.find((pairingLink) => pairingLink.id === pairingCredential.id)?.subject, ).toBe("one-time-token"); }).pipe(Effect.provide(makeEnvironmentAuthLayer())), ); it.effect("issues startup pairing URLs that bootstrap administrative sessions", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sessions = yield* SessionStore.SessionStore; const pairingUrl = yield* serverAuth.issueStartupPairingUrl("http://127.0.0.1:3773"); const token = new URLSearchParams(new URL(pairingUrl).hash.slice(1)).get("token"); const listedPairingLinks = yield* serverAuth.listPairingLinks(); expect(token).toBeTruthy(); expect( listedPairingLinks.some( (pairingLink) => pairingLink.subject === "administrative-bootstrap", ), ).toBe(false); const exchanged = yield* serverAuth.createBrowserSession(token ?? "", requestMetadata); const verified = yield* serverAuth.authenticateHttpRequest( makeCookieRequest(sessions.cookieName, exchanged.sessionToken), ); expect(verified.scopes).toEqual([ "orchestration:read", "orchestration:operate", "terminal:operate", "review:write", "relay:read", "access:read", "access:write", "relay:write", ]); expect(verified.subject).toBe("administrative-bootstrap"); }).pipe(Effect.provide(makeEnvironmentAuthLayer())), ); it.effect( "lists pairing links and revokes other sessions while keeping the administrative session", () => Effect.gen(function* () { const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sessions = yield* SessionStore.SessionStore; const administrativeExchange = yield* serverAuth.createBrowserSession( "desktop-bootstrap-token", requestMetadata, ); const administrativeSession = yield* serverAuth.authenticateHttpRequest( makeCookieRequest(sessions.cookieName, administrativeExchange.sessionToken), ); const pairingCredential = yield* serverAuth.issuePairingCredential({ label: "Julius iPhone", }); const listedPairingLinks = yield* serverAuth.listPairingLinks(); const clientExchange = yield* serverAuth.createBrowserSession( pairingCredential.credential, { ...requestMetadata, deviceType: "mobile", os: "iOS", browser: "Safari", ipAddress: "192.168.1.88", }, ); const clientSession = yield* serverAuth.authenticateHttpRequest( makeCookieRequest(sessions.cookieName, clientExchange.sessionToken), ); const clientsBeforeRevoke = yield* serverAuth.listClientSessions( administrativeSession.sessionId, ); const revokedCount = yield* serverAuth.revokeOtherClientSessions( administrativeSession.sessionId, ); const clientsAfterRevoke = yield* serverAuth.listClientSessions( administrativeSession.sessionId, ); expect(listedPairingLinks.map((entry) => entry.id)).toContain(pairingCredential.id); expect(listedPairingLinks.find((entry) => entry.id === pairingCredential.id)?.label).toBe( "Julius iPhone", ); expect(clientsBeforeRevoke).toHaveLength(2); expect( clientsBeforeRevoke.find((entry) => entry.sessionId === administrativeSession.sessionId) ?.current, ).toBe(true); expect( clientsBeforeRevoke.find((entry) => entry.sessionId === clientSession.sessionId)?.current, ).toBe(false); expect( clientsBeforeRevoke.find((entry) => entry.sessionId === clientSession.sessionId)?.client .label, ).toBe("Julius iPhone"); expect( clientsBeforeRevoke.find((entry) => entry.sessionId === clientSession.sessionId)?.client .deviceType, ).toBe("mobile"); expect(revokedCount).toBe(1); expect(clientsAfterRevoke).toHaveLength(1); expect(clientsAfterRevoke[0]?.sessionId).toBe(administrativeSession.sessionId); }).pipe( Effect.provide( makeEnvironmentAuthLayer({ desktopBootstrapToken: "desktop-bootstrap-token", }), ), ), );});
import * as NodeServices from "@effect/platform-node/NodeServices";
import { AuthAdministrativeScopes } from "@t3tools/contracts";
import { expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as ServerConfig from "../config.ts";
import * as ServerEnvironment from "../environment/ServerEnvironment.ts";
import { SqlitePersistenceMemory } from "../persistence/Layers/Sqlite.ts";
import * as PairingGrantStore from "./PairingGrantStore.ts";
import * as EnvironmentAuth from "./EnvironmentAuth.ts";
import * as ServerSecretStore from "./ServerSecretStore.ts";
import * as SessionStore from "./SessionStore.ts";
/** Pinned so dev-mode cookie tests can assert the port-scoped name. */
const TEST_SERVER_PORT = 13_773;
const makeServerConfigLayer = (overrides?: Partial<ServerConfig.ServerConfig["Service"]>) =>
Layer.effect(
ServerConfig.ServerConfig,
Effect.gen(function* () {
const config = yield* ServerConfig.ServerConfig;
return {
...config,
...overrides,
// Keep the test server deterministic even when the default test layer
// changes its development port.
port: TEST_SERVER_PORT,
} satisfies ServerConfig.ServerConfig["Service"];
}),
).pipe(Layer.provide(ServerConfig.layerTest(process.cwd(), { prefix: "t3-auth-server-test-" })));
const makeEnvironmentAuthLayer = (overrides?: Partial<ServerConfig.ServerConfig["Service"]>) =>
EnvironmentAuth.layer.pipe(
Layer.provide(SqlitePersistenceMemory),
Layer.provide(ServerSecretStore.layer),
Layer.provide(ServerEnvironment.identityLayer),
Layer.provide(makeServerConfigLayer(overrides)),
);
const makeCookieRequest = (
cookieName: string,
sessionToken: string,
): Parameters<EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"]>[0] =>
({
cookies: {
[cookieName]: sessionToken,
},
headers: {},
}) as unknown as Parameters<
EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"]
>[0];
const makeBearerRequest = (
token: string,
): Parameters<EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"]>[0] =>
({
cookies: {},
headers: {
authorization: `Bearer ${token}`,
},
}) as unknown as Parameters<
EnvironmentAuth.EnvironmentAuth["Service"]["authenticateHttpRequest"]
>[0];
const requestMetadata = {
deviceType: "desktop" as const,
os: "macOS",
browser: "Chrome",
ipAddress: "192.168.1.23",
};
it.layer(NodeServices.layer)("EnvironmentAuth.layer", (it) => {
it.effect("classifies invalid bootstrap credential failures for the HTTP boundary", () =>
Effect.sync(() => {
const error = EnvironmentAuth.toBootstrapExchangeError(
new PairingGrantStore.UnknownBootstrapCredentialError({}),
);
expect(error._tag).toBe("ServerAuthInvalidCredentialError");
}),
);
it.effect("maps unexpected bootstrap failures to 500", () =>
Effect.sync(() => {
const cause = new PairingGrantStore.BootstrapCredentialConsumeError({
cause: new Error("sqlite is unavailable"),
});
const error = EnvironmentAuth.toBootstrapExchangeError(cause);
expect(error._tag).toBe("ServerAuthBootstrapCredentialValidationError");
expect(error.message).toBe("Failed to validate bootstrap credential.");
if (error._tag === "ServerAuthBootstrapCredentialValidationError") {
expect(error.cause).toBe(cause);
}
}),
);
it.effect("issues standard pairing credentials by default", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const sessions = yield* SessionStore.SessionStore;
const pairingCredential = yield* serverAuth.issuePairingCredential();
const exchanged = yield* serverAuth.createBrowserSession(
pairingCredential.credential,
requestMetadata,
);
const verified = yield* serverAuth.authenticateHttpRequest(
makeCookieRequest(sessions.cookieName, exchanged.sessionToken),
);
expect(verified.sessionId.length).toBeGreaterThan(0);
expect(verified.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
]);
expect(verified.subject).toBe("one-time-token");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
it.effect("prefers a bearer token over a stale legacy cookie", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const sessions = yield* SessionStore.SessionStore;
const bearer = yield* serverAuth.issueSession();
const verified = yield* serverAuth.authenticateHttpRequest({
cookies: { [sessions.legacyCookieName ?? "t3_session"]: "stale" },
headers: { authorization: `Bearer ${bearer.token}` },
} as never);
expect(verified.sessionId).toBe(bearer.sessionId);
}).pipe(Effect.provide(makeEnvironmentAuthLayer({ mode: "web", host: "192.168.1.50" }))),
);
it.effect("does not exchange ordinary pairing grants for administrative access tokens", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const pairingCredential = yield* serverAuth.issuePairingCredential();
const error = yield* serverAuth
.exchangeBootstrapCredentialForAccessToken(
pairingCredential.credential,
["orchestration:read", "access:write"],
requestMetadata,
)
.pipe(Effect.flip);
expect(error._tag).toBe("ServerAuthScopeNotGrantedError");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
it.effect("inherits a constrained pairing grant when token exchange omits scope", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const pairingCredential = yield* serverAuth.issuePairingCredential({
scopes: ["orchestration:read"],
});
const token = yield* serverAuth.exchangeBootstrapCredentialForAccessToken(
pairingCredential.credential,
undefined,
requestMetadata,
);
expect(token.scope).toBe("orchestration:read");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
it.effect("rotates desktop bearer sessions without accumulating authorized clients", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const sessions = yield* SessionStore.SessionStore;
const browser = yield* serverAuth.createBrowserSession(
"desktop-bootstrap-token",
requestMetadata,
);
const browserSession = yield* serverAuth.authenticateHttpRequest(
makeCookieRequest(sessions.cookieName, browser.sessionToken),
);
const staleSessions = yield* Effect.forEach([1, 2, 3], () =>
sessions.issue({ subject: "desktop-bootstrap", method: "bearer-access-token" }),
);
const pairing = yield* serverAuth.issuePairingCredential();
const paired = yield* serverAuth.exchangeBootstrapCredentialForAccessToken(
pairing.credential,
undefined,
{ ...requestMetadata, label: "T3 Code Desktop" },
);
const first = yield* serverAuth.exchangeBootstrapCredentialForAccessToken(
"desktop-bootstrap-token",
undefined,
requestMetadata,
);
const firstSession = yield* serverAuth.authenticateHttpRequest(
makeBearerRequest(first.access_token),
);
const second = yield* serverAuth.exchangeBootstrapCredentialForAccessToken(
"desktop-bootstrap-token",
undefined,
requestMetadata,
);
const active = yield* serverAuth.listSessions();
const firstError = yield* serverAuth
.authenticateHttpRequest(makeBearerRequest(first.access_token))
.pipe(Effect.flip);
const secondSession = yield* serverAuth.authenticateHttpRequest(
makeBearerRequest(second.access_token),
);
expect(active).toHaveLength(3);
expect(active.map((entry) => entry.sessionId)).toContain(browserSession.sessionId);
expect(active.map((entry) => entry.sessionId)).toContain(secondSession.sessionId);
expect(active.map((entry) => entry.sessionId)).not.toContain(firstSession.sessionId);
expect(firstError._tag).toBe("ServerAuthInvalidCredentialError");
for (const stale of staleSessions) {
const error = yield* sessions.verify(stale.token).pipe(Effect.flip);
expect(error._tag).toBe("SessionTokenRevokedError");
}
const pairedSession = yield* serverAuth.authenticateHttpRequest(
makeBearerRequest(paired.access_token),
);
expect(pairedSession.subject).toBe("one-time-token");
expect(active.map((entry) => entry.sessionId)).toContain(pairedSession.sessionId);
}).pipe(
Effect.provide(
makeEnvironmentAuthLayer({
desktopBootstrapToken: "desktop-bootstrap-token",
}),
),
),
);
it.effect("keeps user-issued administrative pairing links manageable", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const pairingCredential = yield* serverAuth.issuePairingCredential({
scopes: AuthAdministrativeScopes,
});
const listedPairingLinks = yield* serverAuth.listPairingLinks();
expect(
listedPairingLinks.find((pairingLink) => pairingLink.id === pairingCredential.id)?.subject,
).toBe("one-time-token");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
it.effect("issues startup pairing URLs that bootstrap administrative sessions", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const sessions = yield* SessionStore.SessionStore;
const pairingUrl = yield* serverAuth.issueStartupPairingUrl("http://127.0.0.1:3773");
const token = new URLSearchParams(new URL(pairingUrl).hash.slice(1)).get("token");
const listedPairingLinks = yield* serverAuth.listPairingLinks();
expect(token).toBeTruthy();
expect(
listedPairingLinks.some(
(pairingLink) => pairingLink.subject === "administrative-bootstrap",
),
).toBe(false);
const exchanged = yield* serverAuth.createBrowserSession(token ?? "", requestMetadata);
const verified = yield* serverAuth.authenticateHttpRequest(
makeCookieRequest(sessions.cookieName, exchanged.sessionToken),
);
expect(verified.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
"access:read",
"access:write",
"relay:write",
]);
expect(verified.subject).toBe("administrative-bootstrap");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
it.effect(
"lists pairing links and revokes other sessions while keeping the administrative session",
() =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
const sessions = yield* SessionStore.SessionStore;
const administrativeExchange = yield* serverAuth.createBrowserSession(
"desktop-bootstrap-token",
requestMetadata,
);
const administrativeSession = yield* serverAuth.authenticateHttpRequest(
makeCookieRequest(sessions.cookieName, administrativeExchange.sessionToken),
);
const pairingCredential = yield* serverAuth.issuePairingCredential({
label: "Julius iPhone",
});
const listedPairingLinks = yield* serverAuth.listPairingLinks();
const clientExchange = yield* serverAuth.createBrowserSession(
pairingCredential.credential,
{
...requestMetadata,
deviceType: "mobile",
os: "iOS",
browser: "Safari",
ipAddress: "192.168.1.88",
},
);
const clientSession = yield* serverAuth.authenticateHttpRequest(
makeCookieRequest(sessions.cookieName, clientExchange.sessionToken),
);
const clientsBeforeRevoke = yield* serverAuth.listClientSessions(
administrativeSession.sessionId,
);
const revokedCount = yield* serverAuth.revokeOtherClientSessions(
administrativeSession.sessionId,
);
const clientsAfterRevoke = yield* serverAuth.listClientSessions(
administrativeSession.sessionId,
);
expect(listedPairingLinks.map((entry) => entry.id)).toContain(pairingCredential.id);
expect(listedPairingLinks.find((entry) => entry.id === pairingCredential.id)?.label).toBe(
"Julius iPhone",
);
expect(clientsBeforeRevoke).toHaveLength(2);
expect(
clientsBeforeRevoke.find((entry) => entry.sessionId === administrativeSession.sessionId)
?.current,
).toBe(true);
expect(
clientsBeforeRevoke.find((entry) => entry.sessionId === clientSession.sessionId)?.current,
).toBe(false);
expect(
clientsBeforeRevoke.find((entry) => entry.sessionId === clientSession.sessionId)?.client
.label,
).toBe("Julius iPhone");
expect(
clientsBeforeRevoke.find((entry) => entry.sessionId === clientSession.sessionId)?.client
.deviceType,
).toBe("mobile");
expect(revokedCount).toBe(1);
expect(clientsAfterRevoke).toHaveLength(1);
expect(clientsAfterRevoke[0]?.sessionId).toBe(administrativeSession.sessionId);
}).pipe(
Effect.provide(
makeEnvironmentAuthLayer({
desktopBootstrapToken: "desktop-bootstrap-token",
}),
),
),
);
});