Effect-based infrastructure + auth library for Bun applications. Each module exports a Context.Tag (or Effect.Service) and a factory — the consuming app reads its own config and composes layers.
postgres— Bun-native SQL connection pool (scoped)redis— Bun-native Redis connection (scoped)stripe— Stripe API + webhook verificationses— AWS SES v2 email (with dev-mode logging)sms— Telnyx SMS (with dev-mode logging)s3— Bun-native S3 clientsession—push/peek/pop/deleteover Rediscrypto—encryptSecret/decryptSecret(AES-256-GCM,enc:v1:prefix)
Jwt+JwtConfig— Ed25519 JWT signing/verification, refresh-token rotationOtpService+OtpAlerts— email-OTP flow with rate-limit + progressive lockout (decisions inotp.policy, glue inotp.service)PasskeyService+PasskeyConfig— WebAuthn registration/authenticationOAuthAccountStore— sole writer tooidc_accounts; row schema seals at-rest token encryption viaEncryptedStringcodecOAuthProviderRegistry+OAuthProviderResolver— registered OAuth providers + cachedopenid-clientConfigurationOidcAuthFlow— authorize-URL build + callback exchange + signup/linking sessions; composes provider resolver + account storeOAuthTokenVault—getValidAccessToken(sub, provider); refreshes viarefreshTokenGrant+ persists; consumed by downstream apps that call third-party APIs (e.g. Google Calendar)RiscService— Google Cross-Account Protection event receiver (processdecodes,dispatchToStoreapplies events toOAuthAccountStore)BaseUserRepository—userstable read/writeAuthConfig+makeAuthConfig— TTLs, lockout schedule, crypto key
- Branded types (
UserSub,Email) - Schemas (
AuthPayload,OAuthClaims,OAuthResult,BaseUser) - Tagged result classes (
OtpSession,InvalidCode,UserLocked,HasOidc,AuthenticatedUser) IdpClient(+IdpClient.layer) — downstream-app client for the IdP: authorize-URL, code exchange, token refresh/revoke, and JWKS-backed access-token verification
Branded primitives + DB row types safe for both server and client bundles.
Each consumer app builds its own runtime by combining layers:
import { Effect, Layer, ManagedRuntime } from 'effect';
import { Postgres, makePostgres, Redis, makeRedis, SessionService, Stripe, makeStripe } from '@polumeyv/lib/server';
import { AuthConfig, makeAuthConfig, OAuthProviderRegistry, OAuthAccountStore, OidcAuthFlow, OAuthTokenVault } from '@polumeyv/lib/auth';
const Live = Layer.provideMerge(
Layer.mergeAll(
OAuthAccountStore.Default,
OidcAuthFlow.Default,
OAuthTokenVault.Default,
// ...your app services
),
Layer.mergeAll(
Layer.scoped(Postgres, makePostgres(DATABASE_URL)),
Layer.scoped(Redis, makeRedis(REDIS_URL)),
SessionService.Default,
Layer.succeed(
OAuthProviderRegistry,
OAuthProviderRegistry.of(new Map([['google', { discoveryUrl: '...', clientId: '...', clientSecret: '...', redirectUri: '...' }]])),
),
makeAuthConfig({ cryptoKey: CRYPTO_KEY }),
),
);
export const Runtime = ManagedRuntime.make(Live);