import { expect, it } from "@effect/vitest"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as AuthConnectClients from "../persistence/AuthConnectClients.ts"; import * as ServerSecretStore from "./ServerSecretStore.ts"; import * as ConnectClientStore from "./ConnectClientStore.ts"; const textEncoder = new TextEncoder(); const requestedAt = DateTime.makeUnsafe("2026-06-27T12:00:00.000Z"); const approvedAt = DateTime.makeUnsafe("2026-06-27T12:05:00.000Z"); const rejectedAt = DateTime.makeUnsafe("2026-06-27T12:06:00.000Z"); const approvedRecord: AuthConnectClients.AuthConnectClientRecord = { clientProofKeyThumbprint: "client-thumbprint", cloudUserId: "cloud-user", deviceId: "device-1", status: "approved", client: { label: "Client", ipAddress: null, userAgent: null, deviceType: "desktop", os: "macOS", browser: null, }, requestedAt, updatedAt: approvedAt, approvedAt, rejectedAt: null, revokedAt: null, lastSeenAt: null, }; const makeSecretStoreLayer = (mode: string) => Layer.succeed( ServerSecretStore.ServerSecretStore, ServerSecretStore.ServerSecretStore.of({ get: () => Effect.succeed(Option.some(textEncoder.encode(mode))), set: () => Effect.void, create: () => Effect.void, getOrCreateRandom: () => Effect.succeed(new Uint8Array()), remove: () => Effect.void, }), ); const secretStoreLayer = makeSecretStoreLayer("client-approval"); const makeStoreOnlyLayer = (mode: string) => Layer.effect(ConnectClientStore.ConnectClientStore, ConnectClientStore.make).pipe( Layer.provide(makeSecretStoreLayer(mode)), Layer.provide( Layer.succeed( AuthConnectClients.AuthConnectClientRepository, AuthConnectClients.AuthConnectClientRepository.of({ upsertRequest: () => Effect.succeed(approvedRecord), updateStatus: () => Effect.succeed(Option.none()), revoke: () => Effect.succeed(false), markSeen: () => Effect.succeed(Option.some(approvedRecord)), listActive: () => Effect.succeed([]), }), ), ), ); const makeStoreLayer = ( overrides: Partial, ) => Layer.effect(ConnectClientStore.ConnectClientStore, ConnectClientStore.make).pipe( Layer.provide(secretStoreLayer), Layer.provide( Layer.succeed( AuthConnectClients.AuthConnectClientRepository, AuthConnectClients.AuthConnectClientRepository.of({ upsertRequest: () => Effect.succeed(approvedRecord), updateStatus: () => Effect.succeed(Option.none()), revoke: () => Effect.succeed(false), markSeen: () => Effect.succeed(Option.some(approvedRecord)), listActive: () => Effect.succeed([]), ...overrides, }), ), ), ); it.effect("fails closed when persisted security mode is invalid", () => Effect.gen(function* () { const store = yield* ConnectClientStore.ConnectClientStore; const error = yield* Effect.flip(store.getSecurityMode()); expect(error._tag).toBe("ConnectSecurityModeLoadError"); }).pipe(Effect.provide(makeStoreOnlyLayer("invalid-mode"))), ); it.effect("returns rejected when an approved client is rejected before last-seen update", () => Effect.gen(function* () { const store = yield* ConnectClientStore.ConnectClientStore; const authorization = yield* store.requestClient({ cloudUserId: "cloud-user", clientProofKeyThumbprint: "client-thumbprint", }); expect(authorization.mode).toBe("client-approval"); expect(authorization.status).toBe("rejected"); }).pipe( Effect.provide( makeStoreLayer({ markSeen: () => Effect.succeed( Option.some({ ...approvedRecord, status: "rejected", updatedAt: rejectedAt, rejectedAt, }), ), }), ), ), ); it.effect("returns pending when an approved client is revoked before last-seen update", () => Effect.gen(function* () { const store = yield* ConnectClientStore.ConnectClientStore; const authorization = yield* store.requestClient({ cloudUserId: "cloud-user", clientProofKeyThumbprint: "client-thumbprint", }); expect(authorization.mode).toBe("client-approval"); expect(authorization.status).toBe("pending"); if (authorization.mode === "client-approval") { expect(authorization.client.status).toBe("pending"); expect(authorization.client.approvedAt).toBeNull(); expect(authorization.client.lastSeenAt).toBeNull(); } }).pipe( Effect.provide( makeStoreLayer({ markSeen: () => Effect.succeed(Option.none()), }), ), ), );