import type { AuthClientMetadata, AuthClientSession, AuthSessionId, ServerAuthSessionMethod,} from "@t3tools/contracts";import { Data, DateTime, Duration, Context } from "effect";import type { Effect, Stream } from "effect"; export type SessionRole = "owner" | "client"; export interface IssuedSession { readonly sessionId: AuthSessionId; readonly token: string; readonly method: ServerAuthSessionMethod; readonly client: AuthClientMetadata; readonly expiresAt: DateTime.DateTime; readonly role: SessionRole;} export interface VerifiedSession { readonly sessionId: AuthSessionId; readonly token: string; readonly method: ServerAuthSessionMethod; readonly client: AuthClientMetadata; readonly expiresAt?: DateTime.DateTime; readonly subject: string; readonly role: SessionRole;} export type SessionCredentialChange = | { readonly type: "clientUpserted"; readonly clientSession: AuthClientSession; } | { readonly type: "clientRemoved"; readonly sessionId: AuthSessionId; }; export class SessionCredentialError extends Data.TaggedError("SessionCredentialError")<{ readonly message: string; readonly cause?: unknown;}> {} export interface SessionCredentialServiceShape { readonly cookieName: string; readonly issue: (input?: { readonly ttl?: Duration.Duration; readonly subject?: string; readonly method?: ServerAuthSessionMethod; readonly role?: SessionRole; readonly client?: AuthClientMetadata; }) => Effect.Effect<IssuedSession, SessionCredentialError>; readonly verify: (token: string) => Effect.Effect<VerifiedSession, SessionCredentialError>; readonly issueWebSocketToken: ( sessionId: AuthSessionId, input?: { readonly ttl?: Duration.Duration; }, ) => Effect.Effect< { readonly token: string; readonly expiresAt: DateTime.DateTime; }, SessionCredentialError >; readonly verifyWebSocketToken: ( token: string, ) => Effect.Effect<VerifiedSession, SessionCredentialError>; readonly listActive: () => Effect.Effect< ReadonlyArray<AuthClientSession>, SessionCredentialError >; readonly streamChanges: Stream.Stream<SessionCredentialChange>; readonly revoke: (sessionId: AuthSessionId) => Effect.Effect<boolean, SessionCredentialError>; readonly revokeAllExcept: ( sessionId: AuthSessionId, ) => Effect.Effect<number, SessionCredentialError>; readonly markConnected: (sessionId: AuthSessionId) => Effect.Effect<void, never>; readonly markDisconnected: (sessionId: AuthSessionId) => Effect.Effect<void, never>;} export class SessionCredentialService extends Context.Service< SessionCredentialService, SessionCredentialServiceShape>()("t3/auth/Services/SessionCredentialService") {}
import type {
AuthClientMetadata,
AuthClientSession,
AuthSessionId,
ServerAuthSessionMethod,
} from "@t3tools/contracts";
import { Data, DateTime, Duration, Context } from "effect";
import type { Effect, Stream } from "effect";
export type SessionRole = "owner" | "client";
export interface IssuedSession {
readonly sessionId: AuthSessionId;
readonly token: string;
readonly method: ServerAuthSessionMethod;
readonly client: AuthClientMetadata;
readonly expiresAt: DateTime.DateTime;
readonly role: SessionRole;
}
export interface VerifiedSession {
readonly sessionId: AuthSessionId;
readonly token: string;
readonly method: ServerAuthSessionMethod;
readonly client: AuthClientMetadata;
readonly expiresAt?: DateTime.DateTime;
readonly subject: string;
readonly role: SessionRole;
}
export type SessionCredentialChange =
| {
readonly type: "clientUpserted";
readonly clientSession: AuthClientSession;
}
| {
readonly type: "clientRemoved";
readonly sessionId: AuthSessionId;
};
export class SessionCredentialError extends Data.TaggedError("SessionCredentialError")<{
readonly message: string;
readonly cause?: unknown;
}> {}
export interface SessionCredentialServiceShape {
readonly cookieName: string;
readonly issue: (input?: {
readonly ttl?: Duration.Duration;
readonly subject?: string;
readonly method?: ServerAuthSessionMethod;
readonly role?: SessionRole;
readonly client?: AuthClientMetadata;
}) => Effect.Effect<IssuedSession, SessionCredentialError>;
readonly verify: (token: string) => Effect.Effect<VerifiedSession, SessionCredentialError>;
readonly issueWebSocketToken: (
sessionId: AuthSessionId,
input?: {
readonly ttl?: Duration.Duration;
},
) => Effect.Effect<
{
readonly token: string;
readonly expiresAt: DateTime.DateTime;
},
SessionCredentialError
>;
readonly verifyWebSocketToken: (
token: string,
) => Effect.Effect<VerifiedSession, SessionCredentialError>;
readonly listActive: () => Effect.Effect<
ReadonlyArray<AuthClientSession>,
SessionCredentialError
>;
readonly streamChanges: Stream.Stream<SessionCredentialChange>;
readonly revoke: (sessionId: AuthSessionId) => Effect.Effect<boolean, SessionCredentialError>;
readonly revokeAllExcept: (
sessionId: AuthSessionId,
) => Effect.Effect<number, SessionCredentialError>;
readonly markConnected: (sessionId: AuthSessionId) => Effect.Effect<void, never>;
readonly markDisconnected: (sessionId: AuthSessionId) => Effect.Effect<void, never>;
}
export class SessionCredentialService extends Context.Service<
SessionCredentialService,
SessionCredentialServiceShape
>()("t3/auth/Services/SessionCredentialService") {}