/** * `@drama/auth` 公共面 —— 身份认证域唯一对外导出口(任务文档 §3 契约)。 * * 设计纪律(架构 §9 红线 + §1 边界): * - 包内不读 `process.env`、不在模块顶层建任何连接(db 由 `createUserRepo(db)` 注入, * 密钥/JWKS/OAuth client 全由注入的 Port 在 composition root 持有)。 * - 绝不自研密码学:JWT 签发/验证走 `tokenSigner`,OAuth 验签走 `oauth`, * 密码哈希走 `hasher`。本包只编排这些 Port + 把会话/凭据/验证码状态落库。 * - 唯一对外错误类型是 `AuthError`(结构化 `code`/`retryable`)。 * * ----- 注入式 Port 协议(实现在 composition root,本包只消费契约)----- * * @typedef {Object} TokenSigner 薄封装 jose。 * @property {(claims: object, opts: { ttlMs: number }) => string|Promise} sign * @property {(token: string) => object|Promise} verify 验签 + 过期校验,失败抛错。 * * @typedef {Object} Hasher 薄封装 argon2 / bcrypt。 * @property {(plain: string) => string|Promise} hash * @property {(plain: string, hash: string) => boolean|Promise} verify * * @typedef {Object} OauthExchangeResult * @property {string} provider_user_id * @property {string} email * @property {boolean} email_verified * * @typedef {Object} OauthPort 薄封装各家 SDK(含验签)。 * @property {(args: { provider: 'google'|'apple', code: string, oauth_flow: 'access_token'|'authorization_code', redirect_uri?: string }) => OauthExchangeResult|Promise} exchange * * 来自 @drama/email 的投递端口(验证码投递)。 * @typedef {Object} EmailPort * @property {(args: { to: string, code: string, purpose: string, locale?: string }) => void|Promise} sendCode * * ----- 领域 DTO(与 @drama/contracts 的 User/Session 对齐)----- * * @typedef {Object} User * @property {string} id * @property {string} email * @property {string} [password_hash] * @property {Array<{ provider: string, provider_user_id: string }>} [oauth_providers] * @property {string} [locale] * @property {Date} [email_verified_at] * * @typedef {Object} Session * @property {string} sid * @property {string} user_id * @property {string} refresh_hash * @property {string} family * @property {Date} expires_at UTC * @property {boolean} [used] * @property {boolean} [revoked] * * @typedef {Object} CodeRecord * @property {string} email * @property {string} purpose * @property {string} code_hash * @property {Date} expires_at UTC * @property {number} attempts * * ----- UserRepo 形态(createUserRepo(db) 返回,本包内消费)----- * * @typedef {Object} UserRepo * @property {(email: string) => Promise} findByEmail * @property {(id: string) => Promise} findById * @property {(args: { email: string, password_hash?: string, oauth_providers?: Array<{provider:string,provider_user_id:string}>, locale?: string, email_verified_at?: Date }) => Promise} create * @property {(args: { user_id: string, provider: string, provider_user_id: string }) => Promise} linkOauth * @property {(args: { user_id: string, password_hash: string }) => Promise} updatePasswordHash * @property {(args: { user_id: string, sid: string, refresh_hash: string, family: string, expires_at: Date }) => Promise} saveSession * @property {(args: { sid: string }) => Promise} findSession * @property {(args: { sid: string }) => Promise} markRefreshUsed * @property {(args: { family: string }) => Promise} revokeFamily * @property {(args: { user_id: string }) => Promise} revokeUserSessions * @property {(args: { key: string, ip?: string, at: Date }) => Promise} recordAttempt * @property {(args: { key: string, ip?: string, windowMs: number }) => Promise} countRecentAttempts * @property {(args: { email: string, purpose: string, code_hash: string, expires_at: Date }) => Promise} saveCode * @property {(args: { email: string, purpose: string }) => Promise} consumeCode * @property {(args: { email: string, purpose: string, attempts: number }) => Promise} [bumpCodeAttempts] * * ----- Auth 形态(createAuth(...) 返回,全部返回 Promise)----- * * @typedef {Object} AuthTokens * @property {User} user * @property {string} access_token * @property {string} refresh_token * * @typedef {Object} Auth * @property {(args: { email: string, password: string, locale?: string, email_verified_at?: Date }) => Promise} register * @property {(args: { email: string, password: string, ip?: string, device_id?: string }) => Promise} login * @property {(args: { provider: 'google'|'apple', code: string, redirect_uri?: string, device_id?: string }) => Promise} oauthLogin * @property {(args: { refresh_token: string }) => Promise<{ user: User|{id:string}, access_token: string, refresh_token: string }>} refresh * @property {(args: { email: string, code: string, purpose: 'register'|'login'|'reset' }) => Promise<{ ok: true }>} verifyCode * @property {(args: { email: string, purpose: 'register'|'login'|'reset', locale?: string, ip?: string }) => Promise<{ ok: true }>} sendCode * @property {(args: { email: string, locale?: string, ip?: string }) => Promise<{ ok: true }>} requestPasswordReset * @property {(args: { email: string, password: string }) => Promise<{ ok: true }>} resetPassword * @property {(args: { user_id: string }) => Promise} getUser * @property {(token: string) => Promise} verifyAccessToken * @property {(args: { refresh_token: string }) => Promise<{ ok: true }>} logout * @property {(args: { user_id: string }) => Promise<{ ok: true }>} revokeAllSessions */ export { createAuth } from './auth.js' export { createUserRepo } from './repo.js' export { AuthError } from './errors.js' export { createFakeUserRepo } from './fake-repo.js' export { default as authDbSchema } from './db/tables/index.cjs'