# @edgespark/client 中文文档

规范地址：https://npmcn.com/package/%40edgespark/client/

版本：1\.0\.4
npm 元数据更新时间：2026-03-18T07:09:04.607Z
中文译文更新时间：2026-11-13T06:50:15.969Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40edgespark/client
原文对照：https://npmcn.com/package/%40edgespark/client/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：314 kB，45 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：1 个
- 首次发布：2025-12-04T03:54:42.969Z
- 最新版本发布：2026-03-18T07:09:04.420Z
- 近 30 天下载量：3076（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：32（近 12 个月 32 个）

## 中文简介

边缘spark 伞客户端: auth UI/APIs 外加 HTTP 公用.

## 安装

```sh
npm install @edgespark/client
```

也可以使用：`pnpm add @edgespark/client`、`yarn add @edgespark/client`、`bun add @edgespark/client`

## README

# @ dedgespark/ 客户端

EdgeSpark BaaS的浏览器SDK - 一个软件包中的认证+API客户端.

## 安装

```bash
npm i @edgespark/client
```

> **说明**: 此SDK只使用浏览器. 它不支持节点.js或SSR环境.

## 快速启动

```ts
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` | 建议 |

```html
<div id="auth" style="width: 100%; max-width: 420px; margin: 0 auto;"></div>
```

### 基本用途

```ts
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),
  });
}
```

### 反应示例

```tsx
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` 参数( 部分覆盖支持) :

```ts
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并覆盖:

```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` 是基于 [好一点了](https://www.better-auth.com/) 客户端并支持所有更好的自动方法.

### 签名

```ts
// Email/password sign in
const result = await client.auth.signIn.email({
  email: "user@example.com",
  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();
```

### 注册

```ts
const result = await client.auth.signUp.email({
  name: "John Doe",
  email: "john@example.com",
  password: "password",
  callbackURL: "/verify-email",  // Link destination in verification email
});

if (result.error) {
  console.error("Sign up failed:", result.error.message);
}
```

### 获取用户信息

```ts
// 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");
}
```

### 签出

```ts
await client.auth.signOut();
```

### 忘记密码/ 重置密码

```ts
// 1. Send reset code to email
await client.auth.forgetPassword.emailOtp({
  email: "user@example.com",
});

// 2. Set new password with verification code
const result = await client.auth.emailOtp.resetPassword({
  email: "user@example.com",
  otp: "123456",
  password: "newpassword",
});

if (result.error) {
  console.error("Reset failed:", result.error.message);
}
```

### 收听 Auth 状态更改

```ts
// 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` 带有自动注入的认证符号 :

```ts
// 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`) (中文(简体) ). 跨源请求不会自动包含符号 .

* * *

## 生命周期和最佳做法

### 在渲染前检查登录状态

总是在渲染登录用户前检查用户是否已经登录 :

```ts
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()` 目标页面上 - 这是 **建议** 获取用户信息的方法 :

```ts
// /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` | 高级:实时认证监测 | 需要手动取消订阅; 在任何符号更改上起火 |

### 反应最佳做法

```tsx
// ✅ 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} />;
}
```

### 清理

```ts
// 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`

```ts
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
}
```

* * *

## 构建

```bash
npm run build      # Build
npm run dev        # Run example (examples/dev)
```

## 常见问题

### @edgespark/client 是什么？

边缘spark 伞客户端: auth UI/APIs 外加 HTTP 公用\.

### 如何安装 @edgespark/client？

在项目目录运行 npm install @edgespark/client，或使用 pnpm add / yarn add / bun add。

### @edgespark/client 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @edgespark/client 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @edgespark/client 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @edgespark/client 可以商用吗？

@edgespark/client 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @edgespark/client 的下载量有多少？

根据 npm 官方下载统计，@edgespark/client 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,076 次，日均约 103 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @edgespark/client 还在维护吗？

最新版本 1\.0\.4 发布于 2026/03/18（7 个月前）；至今共发布 32 个版本，其中过去 12 个月发布了 32 个；首次发布于 2025/12/04。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

