@ dedgespark/ 客户端
EdgeSpark BaaS的浏览器SDK - 一个软件包中的认证+API客户端.
安装
npm i @edgespark/client
说明: 此SDK只使用浏览器. 它不支持节点.js或SSR环境.
快速启动
import { createEdgeSpark } from "@edgespark/client";
import "@edgespark/client/styles.css";
const client = createEdgeSpark({ baseUrl: "https://api.example.com" });
// Option 1: Use managed login UI (recommended)
await client.auth.renderAuthUI(document.getElementById("auth")!, {
redirectTo: "/dashboard",
onLogin: (user) => console.log("Logged in!", user.email),
});
// Option 2: Build custom UI with direct API calls
await client.auth.signIn.email({ email, password });
const session = await client.auth.getSession();
// API requests (auth token auto-injected)
const res = await client.api.fetch("/api/users");
管理登录 UI
renderAuthUI 提供完整的外框认证流程 :
| 流动 | 说明 |
|---|---|
| 签名 | 电子邮件/密码登录、 OAuth( Google等), 匿名临时账户 |
| 注册 | 电子邮件/密码登记(自动处理电子邮件核查) |
| 忘记密码 | 发送重置代码 输入代码 设置新密码 |
| 电子邮件验证 | 注册后发送校验邮件, 支持再发送 |
集装箱需求
管理下的登录UI对这些容器尺寸进行了优化:
| 尺寸 | 数值 | 页:1 |
|---|---|---|
| 最大宽度 | 420px | 匹配 --edgespark-auth-card-width |
| 最小宽度 | 320px | 移动设备 |
| 响应 | width: 100%; max-width: 420px | 建议 |
<div id="auth" style="width: 100%; max-width: 420px; margin: 0 auto;"></div>
基本用途
import { createEdgeSpark } from "@edgespark/client";
import "@edgespark/client/styles.css"; // Required
const client = createEdgeSpark({ baseUrl: "https://api.example.com" });
// Check if already logged in
const session = await client.auth.getSession();
if (session.data?.user) {
window.location.href = "/dashboard";
} else {
// Render login UI
await client.auth.renderAuthUI(document.getElementById("auth")!, {
redirectTo: "/dashboard",
onError: (error) => console.error("Auth error:", error),
});
}
反应示例
import { useRef, useEffect } from "react";
import { createEdgeSpark } from "@edgespark/client";
import "@edgespark/client/styles.css";
// Create client outside component (singleton)
const client = createEdgeSpark({ baseUrl: "https://api.example.com" });
export function AuthPage() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!ref.current) return;
// Check login status first
client.auth.getSession().then((session) => {
if (session.data?.user) {
window.location.href = "/dashboard";
return;
}
client.auth.renderAuthUI(ref.current!, {
redirectTo: "/dashboard",
});
});
}, []);
return <div ref={ref} />;
}
// Dashboard page - get user info here
export function DashboardPage() {
const [user, setUser] = useState(null);
useEffect(() => {
client.auth.getSession().then((session) => {
if (!session.data?.user) {
window.location.href = "/login";
return;
}
setUser(session.data.user);
});
}, []);
if (!user) return <div>Loading...</div>;
return <div>Welcome, {user.name}!</div>;
}
自定义标签
覆盖默认标签通过 labels 参数( 部分覆盖支持) :
await client.auth.renderAuthUI(container, {
labels: {
// Common labels
common: {
continueButton: "Continue",
backButton: "Back",
unknownError: "Something went wrong, please try again",
},
// Sign in page
signIn: {
title: "Welcome Back",
subtitle: "Sign in to continue",
emailPlaceholder: "Enter your email",
passwordPlaceholder: "Enter your password",
loginButton: "Sign In",
forgotPassword: "Forgot password?",
signUpPrompt: "Don't have an account?",
toggleToSignUp: "Sign up now",
guestPrompt: "Not ready to sign up?",
guestLinkText: "Continue with temporary account",
},
// Sign up page
signUp: {
title: "Create Account",
subtitle: "Sign up to get started",
emailPlaceholder: "Enter your email",
passwordPlaceholder: "Enter your password",
confirmPasswordPlaceholder: "Confirm your password",
signUpButton: "Sign Up",
toggleToSignIn: "Already have an account?",
toggleToSignInLink: "Sign in now",
},
// Verification code page
verifyCode: {
title: "Enter Verification Code",
sentTo: "Code sent to",
resendCode: "Resend",
resendCountdown: "Resend in {seconds}s", // {seconds} is a placeholder
},
// Reset password
resetPassword: {
title: "Reset Password",
subtitle: "Enter your email to receive a reset code",
sendResetButton: "Send Reset Code",
backToSignIn: "Back to sign in",
},
// Set new password
setNewPassword: {
title: "Set New Password",
subtitle: "Code sent to",
newPasswordLabel: "New password",
confirmPasswordLabel: "Confirm password",
setPasswordButton: "Set Password",
},
// OAuth buttons
oauth: {
googleBtnName: "Continue with Google",
githubBtnName: "Continue with GitHub",
},
// Error messages (override backend error codes)
errors: {
INVALID_EMAIL_OR_PASSWORD: "Invalid email or password",
INVALID_EMAIL: "Invalid email format",
PASSWORD_MISMATCH: "Passwords do not match",
PASSWORD_TOO_SHORT: "Password is too short",
USER_ALREADY_EXISTS: "This email is already registered",
EMAIL_NOT_VERIFIED: "Email not verified, please check your inbox",
INVALID_OTP: "Invalid verification code",
OTP_EXPIRED: "Verification code has expired",
TOO_MANY_ATTEMPTS: "Too many attempts, please try again later",
},
// Success page
success: {
title: "Success!",
continueButton: "Continue",
},
// iframe OAuth modal (for preview page limitations)
iframeModal: {
titleTemplate: "Sign in with {provider}", // {provider} is a placeholder
messageTemplate: "Due to preview limitations, {provider} sign-in must be completed in a new tab.",
actionButton: "Open in New Tab",
},
},
});
自定义样式
所有样式都标注在下面 [data-edgespark-auth]。通过 CSS 变量导入 CSS并覆盖:
/* In your CSS file */
[data-edgespark-auth] {
/* Colors */
--edgespark-auth-color-primary: rgba(0, 0, 0, 0.95);
--edgespark-auth-color-secondary: rgba(0, 0, 0, 0.65);
--edgespark-auth-color-tertiary: rgba(0, 0, 0, 0.45);
--edgespark-auth-color-text: rgba(0, 0, 0, 0.95);
--edgespark-auth-color-text-inverse: #ffffff;
--edgespark-auth-color-error: #dc2626;
--edgespark-auth-color-border: rgba(0, 0, 0, 0.12);
--edgespark-auth-color-bg: #ffffff;
--edgespark-auth-color-bg-secondary: rgba(0, 0, 0, 0.05);
--edgespark-auth-color-bg-link: #0077ff;
/* Typography */
--edgespark-auth-font-family: 'Roboto Flex', -apple-system, sans-serif;
--edgespark-auth-font-size-title: 32px;
--edgespark-auth-font-size-body: 14px;
--edgespark-auth-font-size-small: 12px;
/* Sizing & Border Radius */
--edgespark-auth-radius-card: 30px;
--edgespark-auth-radius-input: 12px;
--edgespark-auth-radius-button: 999px;
--edgespark-auth-spacing: 16px;
--edgespark-auth-input-height: 48px;
--edgespark-auth-button-height: 48px;
--edgespark-auth-card-width: 420px;
}
自定义用户界面
如果管理下的UI不能满足你的需要,就打电话 client.auth API直接构建自己的UI.
client.auth 是基于 好一点了 客户端并支持所有更好的自动方法.
签名
// Email/password sign in
const result = await client.auth.signIn.email({
email: "[email protected]",
password: "password",
});
if (result.error) {
console.error("Sign in failed:", result.error.message);
} else {
console.log("Sign in successful:", result.data);
}
// OAuth sign in (redirects to third-party page)
await client.auth.signIn.social({
provider: "google",
callbackURL: "/dashboard", // Redirect after success
});
// Anonymous temporary account (requires backend support)
await client.auth.signIn.anonymous();
注册
const result = await client.auth.signUp.email({
name: "John Doe",
email: "[email protected]",
password: "password",
callbackURL: "/verify-email", // Link destination in verification email
});
if (result.error) {
console.error("Sign up failed:", result.error.message);
}
获取用户信息
// Get current logged-in user's session
const session = await client.auth.getSession();
if (session.data) {
console.log("User info:", session.data.user);
console.log("Session:", session.data.session);
} else {
console.log("Not logged in");
}
签出
await client.auth.signOut();
忘记密码/ 重置密码
// 1. Send reset code to email
await client.auth.forgetPassword.emailOtp({
email: "[email protected]",
});
// 2. Set new password with verification code
const result = await client.auth.emailOtp.resetPassword({
email: "[email protected]",
otp: "123456",
password: "newpassword",
});
if (result.error) {
console.error("Reset failed:", result.error.message);
}
收听 Auth 状态更改
// Listen to auth state changes (login/logout/token refresh)
const unsubscribe = client.auth.onAuthStateChange(() => {
// Get latest session when state changes
client.auth.getSession().then((session) => {
if (session?.data?.user) {
console.log("Logged in", session.data.user);
} else {
console.log("Logged out");
}
});
});
// Unsubscribe
unsubscribe();
API 模块
client.api.fetch 实值 fetch 带有自动注入的认证符号 :
// GET
const res = await client.api.fetch("/api/users");
const users = await res.json();
// POST
const res = await client.api.fetch("/api/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Hello" }),
});
安全说明: Token 仅为同源请求注入(域名与
baseUrl) (中文(简体) ). 跨源请求不会自动包含符号 .
生命周期和最佳做法
在渲染前检查登录状态
总是在渲染登录用户前检查用户是否已经登录 :
const session = await client.auth.getSession();
if (session.data?.user) {
// Already logged in, redirect to dashboard
window.location.href = "/dashboard";
return;
}
// Not logged in, render login UI
await client.auth.renderAuthUI(container, {
redirectTo: "/dashboard",
});
在目标页面上获取用户信息
重定向后, 使用 getSession() 目标页面上 - 这是 建议 获取用户信息的方法 :
// /dashboard page
const session = await client.auth.getSession();
if (!session.data?.user) {
window.location.href = "/login";
return;
}
console.log("Welcome", session.data.user.name);
在Login vs 获得会议对 AuthState Change 上
| API 密码 | 使用大小写 | 页:1 |
|---|---|---|
getSession() | 建议: 获取当前用户信息 | 到处都行,同声 |
onLogin | 快速同步操作( 分析、 日志) | 未呼叫 OAuth; 重新定向前起火 |
onAuthStateChange | 高级:实时认证监测 | 需要手动取消订阅; 在任何符号更改上起火 |
反应最佳做法
// ✅ Create client outside component (singleton)
const client = createEdgeSpark({ baseUrl: "..." });
function AuthPage() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!ref.current) return;
// Check if already logged in
client.auth.getSession().then((session) => {
if (session.data?.user) {
window.location.href = "/dashboard";
return;
}
// Render login UI
client.auth.renderAuthUI(ref.current!, {
redirectTo: "/dashboard",
});
});
// No need to destroy - renderAuthUI auto-cleans previous UI
}, []);
return <div ref={ref} />;
}
清理
// Destroy client (cleanup UI, event listeners, etc.)
client.destroy();
// Also clear locally stored token
client.destroy({ clearToken: true });
说明: 只有电话
destroy()当整个应用程序卸载时, 而不是组件卸载时.
API 参考
createEdgeSpark(options)
创建 EdgeSpark 客户端. 初始化为同步.
| 选项 | 类型 | 说明 |
|---|---|---|
baseUrl | string | 后端 URL( 需要) |
fetchCredentials | RequestCredentials | 获取证书模式, 默认 "include" |
client.auth
认证客户端基于更好的事实。 主要方法:
| 方法 | 说明 |
|---|---|
signIn.email({ email, password }) | 电子邮件/密码符号 |
signIn.social({ provider, callbackURL }) | 代理签名 |
signIn.anonymous() | 匿名签名 |
signUp.email({ name, email, password }) | 电子邮件注册 |
signOut() | 签字 |
getSession() | 获取当前会话/用户信息 |
forgetPassword.emailOtp({ email }) | 发送密码重置代码 |
emailOtp.resetPassword({ email, otp, password }) | 用代码重置密码 |
renderAuthUI(container, options) | Render 管理登录 UI |
onAuthStateChange(listener) | 听值变化 |
client.api
| 方法 | 说明 |
|---|---|
fetch(path, options?) | 用认证符号获取 |
LoginUIOptions
备选方案 renderAuthUI数字 :
| 选项 | 类型 | 说明 |
|---|---|---|
redirectTo | string | 登录后重定向 URL (简单模式) |
redirects | RedirectOptions | 精细重定向配置( 覆盖) redirectTo(中文(简体) ) |
labels | Partial<ExtendedLabels> | 自定义标签 |
onLogin | (user) => void | 可选: 用于快速同步操作, 如分析( 不呼叫 OAuth) |
onError | (error) => void | 回调错误 |
RedirectOptions
interface RedirectOptions {
oauth?: {
success?: string; // OAuth login success
newUser?: string; // OAuth first-time signup
error?: string; // OAuth error
};
emailPassword?: string; // Email/password login success
emailVerification?: string; // Email verification link destination
anonymous?: string; // Anonymous login success
}
构建
npm run build # Build
npm run dev # Run example (examples/dev)