266 lines · 9.7 KB · TypeScript
RawDownload
import { Schema } from "effect"; import { AuthSessionId, TrimmedNonEmptyString } from "./baseSchemas"; /** * Declares the server's overall authentication posture. * * This is a high-level policy label that tells clients how the environment is * expected to be accessed, not a transport detail and not an exhaustive list * of every accepted credential. * * Typical usage: * - rendered in auth/pairing UI so the user understands what kind of *   environment they are connecting to * - used by clients to decide whether silent desktop bootstrap is expected or *   whether an explicit pairing flow should be shown * * Meanings: * - `desktop-managed-local`: local desktop-managed environment with narrow *   trusted bootstrap, intended to avoid login prompts on the same machine * - `loopback-browser`: standalone local server intended for browser pairing on *   the same machine * - `remote-reachable`: environment intended to be reached from other devices *   or networks, where explicit pairing/auth is expected * - `unsafe-no-auth`: intentionally unauthenticated mode; this is an explicit *   unsafe escape hatch, not a normal deployment mode */export const ServerAuthPolicy = Schema.Literals([  "desktop-managed-local",  "loopback-browser",  "remote-reachable",  "unsafe-no-auth",]);export type ServerAuthPolicy = typeof ServerAuthPolicy.Type; /** * A credential type that can be exchanged for a real authenticated session. * * Bootstrap methods are for establishing trust at the start of a connection or * pairing flow. They are not the long-lived credential used for ordinary * authenticated HTTP / WebSocket traffic after pairing succeeds. * * Current methods: * - `desktop-bootstrap`: a trusted local desktop handoff, used so the desktop *   shell can pair the renderer without a login screen * - `one-time-token`: a short-lived pairing token, suitable for manual pairing *   flows such as `/pair?token=...` */export const ServerAuthBootstrapMethod = Schema.Literals(["desktop-bootstrap", "one-time-token"]);export type ServerAuthBootstrapMethod = typeof ServerAuthBootstrapMethod.Type; /** * A credential type accepted for steady-state authenticated requests after a * client has already paired. * * These methods are used by the server-wide auth layer for privileged HTTP and * WebSocket access. They are distinct from bootstrap methods so clients can * reason clearly about "pair first, then use session auth". * * Current methods: * - `browser-session-cookie`: cookie-backed browser session, used by the web *   app after bootstrap/pairing * - `bearer-session-token`: token-based session suitable for non-cookie or *   non-browser clients */export const ServerAuthSessionMethod = Schema.Literals([  "browser-session-cookie",  "bearer-session-token",]);export type ServerAuthSessionMethod = typeof ServerAuthSessionMethod.Type; export const AuthSessionRole = Schema.Literals(["owner", "client"]);export type AuthSessionRole = typeof AuthSessionRole.Type; /** * Server-advertised auth capabilities for a specific execution environment. * * Clients should treat this as the authoritative description of how that * environment expects to be paired and how authenticated requests should be * made afterward. * * Field meanings: * - `policy`: high-level auth posture for the environment * - `bootstrapMethods`: pairing/bootstrap methods the server is currently *   willing to accept * - `sessionMethods`: authenticated request/session methods the server supports *   once pairing is complete * - `sessionCookieName`: cookie name clients should expect when *   `browser-session-cookie` is in use * * This descriptor is intentionally capability-oriented. It lets clients choose * the right UX without embedding server-specific auth logic or assuming a * single access method. */export const ServerAuthDescriptor = Schema.Struct({  policy: ServerAuthPolicy,  bootstrapMethods: Schema.Array(ServerAuthBootstrapMethod),  sessionMethods: Schema.Array(ServerAuthSessionMethod),  sessionCookieName: TrimmedNonEmptyString,});export type ServerAuthDescriptor = typeof ServerAuthDescriptor.Type; export const AuthBootstrapInput = Schema.Struct({  credential: TrimmedNonEmptyString,});export type AuthBootstrapInput = typeof AuthBootstrapInput.Type; export const AuthBootstrapResult = Schema.Struct({  authenticated: Schema.Literal(true),  role: AuthSessionRole,  sessionMethod: ServerAuthSessionMethod,  expiresAt: Schema.DateTimeUtc,});export type AuthBootstrapResult = typeof AuthBootstrapResult.Type; export const AuthBearerBootstrapResult = Schema.Struct({  authenticated: Schema.Literal(true),  role: AuthSessionRole,  sessionMethod: Schema.Literal("bearer-session-token"),  expiresAt: Schema.DateTimeUtc,  sessionToken: TrimmedNonEmptyString,});export type AuthBearerBootstrapResult = typeof AuthBearerBootstrapResult.Type; export const AuthWebSocketTokenResult = Schema.Struct({  token: TrimmedNonEmptyString,  expiresAt: Schema.DateTimeUtc,});export type AuthWebSocketTokenResult = typeof AuthWebSocketTokenResult.Type; export const AuthPairingCredentialResult = Schema.Struct({  id: TrimmedNonEmptyString,  credential: TrimmedNonEmptyString,  label: Schema.optionalKey(TrimmedNonEmptyString),  expiresAt: Schema.DateTimeUtc,});export type AuthPairingCredentialResult = typeof AuthPairingCredentialResult.Type; export const AuthPairingLink = Schema.Struct({  id: TrimmedNonEmptyString,  credential: TrimmedNonEmptyString,  role: AuthSessionRole,  subject: TrimmedNonEmptyString,  label: Schema.optionalKey(TrimmedNonEmptyString),  createdAt: Schema.DateTimeUtc,  expiresAt: Schema.DateTimeUtc,});export type AuthPairingLink = typeof AuthPairingLink.Type; export const AuthClientMetadataDeviceType = Schema.Literals([  "desktop",  "mobile",  "tablet",  "bot",  "unknown",]);export type AuthClientMetadataDeviceType = typeof AuthClientMetadataDeviceType.Type; export const AuthClientMetadata = Schema.Struct({  label: Schema.optionalKey(TrimmedNonEmptyString),  ipAddress: Schema.optionalKey(TrimmedNonEmptyString),  userAgent: Schema.optionalKey(TrimmedNonEmptyString),  deviceType: AuthClientMetadataDeviceType,  os: Schema.optionalKey(TrimmedNonEmptyString),  browser: Schema.optionalKey(TrimmedNonEmptyString),});export type AuthClientMetadata = typeof AuthClientMetadata.Type; export const AuthClientSession = Schema.Struct({  sessionId: AuthSessionId,  subject: TrimmedNonEmptyString,  role: AuthSessionRole,  method: ServerAuthSessionMethod,  client: AuthClientMetadata,  issuedAt: Schema.DateTimeUtc,  expiresAt: Schema.DateTimeUtc,  lastConnectedAt: Schema.NullOr(Schema.DateTimeUtc),  connected: Schema.Boolean,  current: Schema.Boolean,});export type AuthClientSession = typeof AuthClientSession.Type; export const AuthAccessSnapshot = Schema.Struct({  pairingLinks: Schema.Array(AuthPairingLink),  clientSessions: Schema.Array(AuthClientSession),});export type AuthAccessSnapshot = typeof AuthAccessSnapshot.Type; export const AuthAccessStreamSnapshotEvent = Schema.Struct({  version: Schema.Literal(1),  revision: Schema.Number,  type: Schema.Literal("snapshot"),  payload: AuthAccessSnapshot,});export type AuthAccessStreamSnapshotEvent = typeof AuthAccessStreamSnapshotEvent.Type; export const AuthAccessStreamPairingLinkUpsertedEvent = Schema.Struct({  version: Schema.Literal(1),  revision: Schema.Number,  type: Schema.Literal("pairingLinkUpserted"),  payload: AuthPairingLink,});export type AuthAccessStreamPairingLinkUpsertedEvent =  typeof AuthAccessStreamPairingLinkUpsertedEvent.Type; export const AuthAccessStreamPairingLinkRemovedEvent = Schema.Struct({  version: Schema.Literal(1),  revision: Schema.Number,  type: Schema.Literal("pairingLinkRemoved"),  payload: Schema.Struct({    id: TrimmedNonEmptyString,  }),});export type AuthAccessStreamPairingLinkRemovedEvent =  typeof AuthAccessStreamPairingLinkRemovedEvent.Type; export const AuthAccessStreamClientUpsertedEvent = Schema.Struct({  version: Schema.Literal(1),  revision: Schema.Number,  type: Schema.Literal("clientUpserted"),  payload: AuthClientSession,});export type AuthAccessStreamClientUpsertedEvent = typeof AuthAccessStreamClientUpsertedEvent.Type; export const AuthAccessStreamClientRemovedEvent = Schema.Struct({  version: Schema.Literal(1),  revision: Schema.Number,  type: Schema.Literal("clientRemoved"),  payload: Schema.Struct({    sessionId: AuthSessionId,  }),});export type AuthAccessStreamClientRemovedEvent = typeof AuthAccessStreamClientRemovedEvent.Type; export const AuthAccessStreamEvent = Schema.Union([  AuthAccessStreamSnapshotEvent,  AuthAccessStreamPairingLinkUpsertedEvent,  AuthAccessStreamPairingLinkRemovedEvent,  AuthAccessStreamClientUpsertedEvent,  AuthAccessStreamClientRemovedEvent,]);export type AuthAccessStreamEvent = typeof AuthAccessStreamEvent.Type; export const AuthRevokePairingLinkInput = Schema.Struct({  id: TrimmedNonEmptyString,});export type AuthRevokePairingLinkInput = typeof AuthRevokePairingLinkInput.Type; export const AuthRevokeClientSessionInput = Schema.Struct({  sessionId: AuthSessionId,});export type AuthRevokeClientSessionInput = typeof AuthRevokeClientSessionInput.Type; export const AuthCreatePairingCredentialInput = Schema.Struct({  label: Schema.optionalKey(TrimmedNonEmptyString),});export type AuthCreatePairingCredentialInput = typeof AuthCreatePairingCredentialInput.Type; export const AuthSessionState = Schema.Struct({  authenticated: Schema.Boolean,  auth: ServerAuthDescriptor,  role: Schema.optionalKey(AuthSessionRole),  sessionMethod: Schema.optionalKey(ServerAuthSessionMethod),  expiresAt: Schema.optionalKey(Schema.DateTimeUtc),});export type AuthSessionState = typeof AuthSessionState.Type;