Files
wpywmail-client/server/account-api.js
T

78 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
* 邮件服务器「账号接口」客户端(对接服务端 v2.2.0 的账号体系)。
*
* 走的是服务器上**只放账号类接口**的公网 HTTPS 入口(默认 https://mail.example.com:9443):
* 注册、邮箱验证码、找回密码、登录换 token、改密码、会话与资料。
* 邮件读写(读信/发件/队列)**不经过这里**,仍然走 IMAP 993 / SMTP 587 ——
* 那个入口对邮件与管理接口一律返回 404(可在服务器上用 /api/messages 验证)。
*
* 零依赖:用 Node 内置的全局 fetch(Node 18+)。
*/
const DEFAULT_API_BASE = 'https://mail.example.com:9443';
/** 服务器给的错误信息本身就是中文说明,直接透传给 UI;只补上网络层失败的可读提示。 */
async function call(base, path, options = {}) {
const { method = 'GET', body, token, timeoutMs = 20000 } = options;
const root = String(base || DEFAULT_API_BASE).replace(/\/+$/, '');
const url = root + path;
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const headers = { 'Content-Type': 'application/json; charset=utf-8' };
if (token) headers.Authorization = `Bearer ${token}`;
const res = await fetch(url, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
signal: controller.signal,
});
const text = await res.text();
let data = null;
try {
data = text ? JSON.parse(text) : null;
} catch {
data = { error: text };
}
if (!res.ok) {
const err = new Error((data && data.error) || `账号接口返回 HTTP ${res.status}`);
err.status = res.status;
err.data = data;
throw err;
}
return data;
} catch (err) {
if (err && err.status) throw err;
if (err && err.name === 'AbortError') throw new Error(`账号接口超时:${url}`);
throw new Error(`连不上账号接口 ${url}:${err && err.message}`);
} finally {
clearTimeout(timer);
}
}
function createAccountApi(base) {
const apiBase = String(base || DEFAULT_API_BASE).replace(/\/+$/, '');
return {
apiBase,
policy: () => call(apiBase, '/api/auth/policy'),
register: (body) => call(apiBase, '/api/register', { method: 'POST', body }),
verifyRegistration: (body) => call(apiBase, '/api/register/verify', { method: 'POST', body }),
resendCode: (body) => call(apiBase, '/api/register/resend', { method: 'POST', body }),
forgot: (email) => call(apiBase, '/api/auth/forgot', { method: 'POST', body: { email } }),
reset: (body) => call(apiBase, '/api/auth/reset', { method: 'POST', body }),
login: (email, password) => call(apiBase, '/api/login', { method: 'POST', body: { email, password } }),
logout: (token) => call(apiBase, '/api/logout', { method: 'POST', body: {}, token }),
changePassword: (token, body) => call(apiBase, '/api/account/password', { method: 'POST', body, token }),
profile: (token) => call(apiBase, '/api/me', { token }),
updateProfile: (token, displayName) =>
call(apiBase, '/api/account/profile', { method: 'PATCH', body: { displayName }, token }),
sessions: (token) => call(apiBase, '/api/account/sessions', { token }),
revokeSessions: (token, body) => call(apiBase, '/api/account/sessions/revoke', { method: 'POST', body, token }),
audit: (token, limit = 30) => call(apiBase, `/api/account/audit?limit=${limit}`, { token }),
};
}
module.exports = { DEFAULT_API_BASE, createAccountApi };