diff --git a/AGENTS.md b/AGENTS.md
index f1ba1da..8bf3e2c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -117,6 +117,38 @@ cd ..\server && dart analyze # demo backend
cd d:\FlutterProgram\zero_auth && dart pub publish --dry-run # 0 warnings
```
+### Docs site preflight (always run before pushing `website/**`)
+
+The Pages site is **pre-built**: `pages.yml` uploads `docs/` verbatim and never
+builds `website/`. `docs/` is regenerated only by the git pre-commit hook, so an
+uninstalled hook silently ships a stale site — missing pages, and an outdated
+version on the Installation page because `__ZERO_AUTH_VERSION__` is injected at
+build time.
+文档站是**预先构建**的:`pages.yml` 原样上传 `docs/`,从不构建 `website/`。`docs/`
+只由 git pre-commit hook 重建,hook 未安装会导致线上静默停留在旧站点——缺页面,且安装
+页版本号过期(`__ZERO_AUTH_VERSION__` 是在构建时注入的)。
+
+```powershell
+# Once per clone — installs the hook that rebuilds & syncs docs/.
+# 每个克隆仅需一次——安装负责重建并同步 docs/ 的 hook。
+npm --prefix website run setup-hook
+
+# Sanity check — this must return True.
+# 检查——必须返回 True。
+Test-Path .git\hooks\pre-commit
+
+# Recovery — website/ already committed and docs/ still stale.
+# 补救——website/ 改动已提交、docs/ 仍是旧的。
+node website/scripts/sync-docs.mjs --force
+```
+
+> **Symptom → cause / 症状 → 原因:** you changed `website/**` (or bumped the
+> version) but `git status` shows no `docs/` changes ⇒ the hook is missing. Run
+> the setup command above, then the `--force` sync once to catch up.
+>
+> 你改了 `website/**`(或升了版本号)而 `git status` 里没有 `docs/` 变化 ⇒ hook 未安装。
+> 先执行上面的安装命令,再跑一次 `--force` 补构建。
+
### Running the demo end to end
```powershell
# Terminal 1 — demo backend
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f24a9f5..c0661f3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -40,6 +40,25 @@ cd example && flutter analyze && flutter test
cd ..\server && dart analyze
```
+## Docs site / 文档站
+
+The Pages site is served from the **pre-built** `docs/` folder; it is regenerated
+from `website/out/` by a git pre-commit hook. The hook must be installed once per
+clone, otherwise edits under `website/` never reach GitHub Pages.
+
+文档站由**预先构建**的 `docs/` 目录提供,它由 git pre-commit hook 从 `website/out/`
+重新生成。每个克隆必须安装一次该 hook,否则你在 `website/` 下的改动永远不会上线。
+
+```powershell
+npm --prefix website run setup-hook
+```
+
+If you changed `website/**` but `git status` shows no `docs/` changes, the hook is
+missing — reinstall it and run `node website/scripts/sync-docs.mjs --force` once.
+
+若你改了 `website/**` 而 `git status` 中没有 `docs/` 变化,说明 hook 未安装——重装它,
+再手动执行一次 `node website/scripts/sync-docs.mjs --force`。
+
## Branching & pull requests
- Branch from `main` with a typed prefix: `feat/`, `fix/`, `docs/`, `ci/`,
diff --git a/docs/404.html b/docs/404.html
index b920dfa..c4125cc 100644
--- a/docs/404.html
+++ b/docs/404.html
@@ -1 +1 @@
-
404: This page could not be found
404
This page could not be found.
\ No newline at end of file
+404: This page could not be found
404
This page could not be found.
\ No newline at end of file
diff --git a/docs/404/index.html b/docs/404/index.html
index b920dfa..c4125cc 100644
--- a/docs/404/index.html
+++ b/docs/404/index.html
@@ -1 +1 @@
-404: This page could not be found
404
This page could not be found.
\ No newline at end of file
+404: This page could not be found
404
This page could not be found.
\ No newline at end of file
diff --git a/docs/Auth-State-Machine/index.html b/docs/Auth-State-Machine/index.html
index a6768ca..0a45068 100644
--- a/docs/Auth-State-Machine/index.html
+++ b/docs/Auth-State-Machine/index.html
@@ -1,7 +1,7 @@
-
🧭 Auth State Machine
Auth State Machine / 认证状态机
+
🧭 Auth State Machine
Auth State Machine / 认证状态机
States / 状态
-
AuthState is a sealed class with four subtypes:
-
AuthState 是一个密封类,包含四个子类型:
+
AuthState is a sealed class with six subtypes:
+
AuthState 是一个密封类,包含六个子类型:
@@ -32,7 +32,26 @@
State
Fields
Meaning
AuthUnauthenticated
—
No session / 无会话
Authenticating
—
login/register/restore in flight / 登录/注册/恢复进行中
Authenticated
session: AuthSession
A valid session / 有效会话
AuthError
error: AppException
Last operation failed / 上一次操作失败
+
+
+
+
+
+
+
+
+
+
+
State
Fields
Meaning
Unauthenticated
—
No session / 无会话
Authenticating
—
login/register in flight / 登录/注册进行中
Authenticated
session: AuthSession
A valid session / 有效会话
Refreshing
session: AuthSession
Renewal in flight; the previous session is still usable / 续期进行中,旧会话仍可用
LoggingOut
session: AuthSession
logout() in flight; that session is being discarded / 登出进行中,该会话即将被丢弃
AuthError
error: AppException
Last operation failed / 上一次操作失败
+
Two helpers save you from spelling out every case:
+
两个辅助属性可避免你手写全部分支:
+
+
state.isAuthenticated — true for AuthenticatedandRefreshing, so a
+renewal never unmounts your signed-in UI. / 在 Authenticated 与 Refreshing
+下均为 true,续期不会卸载已登录界面。
+
state.isBusy — true while Authenticating, Refreshing or LoggingOut. /
+在 Authenticating、Refreshing、LoggingOut 期间为 true。
+
The stream / 状态流
AuthManager.state is a Stream<AuthState> that replays the latest value to every new listener (BehaviorSubject-like). This means:
restore() restores a live session → Authenticated.
+
+
+
restore() restores an expired session → attempts Refreshing; if it
+cannot be renewed (or there is no refresh token) the store is cleared and it
+lands on Unauthenticated. restore(refreshIfExpired: false) restores it
+verbatim instead.
+
+
+
A failed login/register → AuthError, and the future rethrows.
+
+
+
A failed refresh → AuthError, followed by Unauthenticated when the
+failure policy considers the grant unrecoverable,
+or by Authenticated (previous session) when it looks transient.
+
+
+
Duplicate consecutive emissions are suppressed, so listeners only rebuild on a
+real change.
-
A failed login/register → AuthError (the previous state is retained as the “last good” state if any).
\ No newline at end of file
diff --git a/docs/Backend-Strategy/index.html b/docs/Backend-Strategy/index.html
index cc1ac5c..558846f 100644
--- a/docs/Backend-Strategy/index.html
+++ b/docs/Backend-Strategy/index.html
@@ -1,4 +1,4 @@
-
🔌 Backend Strategy
Backend Strategy / 后端策略
+
🔌 Backend Strategy
Backend Strategy / 后端策略
AuthStrategy is the only boundary the core needs from a backend. Implement four methods and zero_auth works with REST, gRPC, Firebase, or a private RPC.
\ No newline at end of file
diff --git a/docs/Configuration/index.html b/docs/Configuration/index.html
index 5ab9731..bf71d8c 100644
--- a/docs/Configuration/index.html
+++ b/docs/Configuration/index.html
@@ -1,10 +1,13 @@
-
⚙️ Configuration
Configuration / 配置
+
⚙️ Configuration
Configuration / 配置
zero_auth is deliberately minimal: there is no global config object. Behavior is composed from the two boundaries you pass to AuthManager.
How the bearer token reaches HTTP clients / 令牌如何到达 HTTP 客户端
+
+
+
+
+
+
+
+
+
+
+
Knob
Where
Effect
Backend endpoints & auth scheme
AuthStrategy
What login/refresh/… actually do / login/refresh 等的实际行为
Token persistence
TokenStore
Disk / secure storage / in-memory / 磁盘/安全存储/内存
Refresh timing
AuthSession.expiresAt + autoRefreshAhead
Proactive renewal is scheduled that far before expiry / 在过期前该时长调度主动续期
Refresh failure handling
refreshFailurePolicy
Whether a failed refresh signs the user out / 刷新失败是否让用户登出
Time source
clock
Drives expiry maths and proactive scheduling; inject one for deterministic tests or to tolerate device clock skew / 驱动过期计算与主动刷新调度;注入时钟可实现确定性测试或容忍设备时钟偏移
Token injection
AuthTokenSource / validAccessToken()
How the bearer token reaches HTTP clients, optionally renewing an expired token first / 令牌如何到达 HTTP 客户端,必要时先续期过期令牌
Refresh strategy / 刷新策略
refresh() is single-flight by construction: concurrent callers share one in-flight request. You decide when to refresh:
refresh() 天生单飞:并发调用方共享同一次进行中的请求。何时刷新由你决定:
@@ -44,8 +57,45 @@
Proactively, when session.isExpired is approaching, before a request. / 在请求前、当 session.isExpired 临近时主动刷新。
Reactively, on a 401 from your API (see Network Integration). / 响应式地,在 API 返回 401 时刷新。
-
A failed refresh clears the session and emits AuthError; your app should route the user back to login.
-
刷新失败会清空会话并发出 AuthError,应用应将用户引导回登录。
+
A failed refresh is always reported through AuthError (and the rethrown future),
+but whether it ends the session is decided by refreshFailurePolicy. See
+Refresh failure policy below.
The default policy signs the user out only for failures that can never succeed
+again, keeping the session when the failure looks transient (so a network blip
+does not log people out):
Store cleared → Unauthenticated / 清空存储 → Unauthenticated
Anything else (network, 5xx…) / 其它(网络、5xx 等)
Session kept → back to Authenticated / 保留会话 → 回到 Authenticated
+
// Never sign out on a failed refresh — useful when refresh tokens are
+// long-lived and your backend is occasionally flaky.
+// 刷新失败也绝不登出——适用于刷新令牌长期有效、后端偶尔不稳定的场景。
+final auth = AuthManager(
+ strategy: strategy,
+ refreshFailurePolicy: (AppException error) => false,
+);
+
Proactive (background) refresh failures are handled internally, so a scheduled
+renewal can never surface as an unhandled async error.
+
主动(后台)刷新的失败会在内部处理,因此定时续期永远不会以未处理异步错误的形式泄漏。
No global singletons / 没有全局单例
AuthManager is a plain object — create one per app, hold it in your DI container or a top-level variable. The core has no static mutable state.
AuthManager 是一个普通对象——每个应用创建一个,放在 DI 容器或顶层变量中即可。内核没有静态可变状态。
\ No newline at end of file
diff --git a/docs/Errors/index.html b/docs/Errors/index.html
index 893f128..327c812 100644
--- a/docs/Errors/index.html
+++ b/docs/Errors/index.html
@@ -1,4 +1,4 @@
-
⚠️ Errors
Errors / 错误
+
⚠️ Errors
Errors / 错误
zero_auth never lets a raw Exception cross its public surface. Every failure is expressed through one of two mechanisms.
}
final class AuthException extends AppException {
- // auth-specific cases: invalid_credentials, session_expired, …
- // 认证相关场景:invalid_credentials、session_expired 等
-}
+ // Base type for every auth failure / 所有认证失败的基类型
+}
+
+// Concrete subtypes — catch these to branch on what actually went wrong.
+// 具体子类型——捕获它们即可按实际错误分支处理。
+final class InvalidCredentialsException extends AuthException {} // invalid_credentials / 凭据无效
+final class SessionExpiredException extends AuthException {} // session_expired / 会话过期
+final class NoActiveSessionException extends AuthException {} // no_active_session / 无活动会话
+final class RefreshTokenMissingException extends AuthException {} // refresh_token_missing / 缺少刷新令牌
+final class UnexpectedAuthException extends AuthException {} // unexpected_auth_failure / 意外失败
+
AuthStrategy authors opt into these subtypes simply by throwing an
+AuthException carrying the matching code; mapAuthFailure performs the
+mapping, preserving any vocabulary it does not recognise.
AuthError(error) emitted, then Unauthenticated (unrecoverable) or back to Authenticated (transient) per the failure policy / 发出 AuthError,随后按失败策略转为 Unauthenticated(不可恢复)或回到 Authenticated(瞬时)
restore() finds nothing
Stays Unauthenticated (not an error) / 保持 Unauthenticated(不算错误)
TokenStore.load() throws
Mapped to AppException, treated as “no session” / 映射为 AppException,按”无会话”处理
\ No newline at end of file
diff --git a/docs/FAQ/index.html b/docs/FAQ/index.html
index beff1ea..e7efe70 100644
--- a/docs/FAQ/index.html
+++ b/docs/FAQ/index.html
@@ -1,4 +1,4 @@
-
❓ FAQ
FAQ / 常见问题
+
❓ FAQ
FAQ / 常见问题
Does zero_auth ship an HTTP client? / zero_auth 内置 HTTP 客户端吗?
No. The core is backend-agnostic and ships no HTTP, SDK or native code. You implement AuthStrategy to call your backend.
\ No newline at end of file
diff --git a/docs/Getting-Started/index.html b/docs/Getting-Started/index.html
index 9045919..c96520f 100644
--- a/docs/Getting-Started/index.html
+++ b/docs/Getting-Started/index.html
@@ -1,4 +1,4 @@
-
🚀 Getting Started
Getting Started / 快速开始
+
🚀 Getting Started
Getting Started / 快速开始
Quick Start / 快速开始
zero_auth is a headless core: you bring the backend (AuthStrategy) and the persistence (TokenStore), and AuthManager drives the session lifecycle.
auth.state.listen((state) { switch (state) {
- case AuthUnauthenticated():
+ case Unauthenticated(): showLoginScreen(); case Authenticating():
+ case LoggingOut(): showSpinner(); case Authenticated(:final session): showHome(session.userId);
+ case Refreshing(:final session):
+ // Still signed in: only the token is being renewed.
+ // 仍处于已登录状态:只是令牌在续期。
+ showHome(session.userId, renewing: true); case AuthError(:final error): showError(error); }});
+
+
If you prefer if/else over exhaustiveness, use state.isAuthenticated and
+state.isBusy instead of state is Authenticated — isAuthenticated stays
+true during Refreshing, so your UI never bounces back to the login screen
+mid-refresh.
\ No newline at end of file
diff --git a/docs/Installation/index.html b/docs/Installation/index.html
index 3dcaadc..cd8aa02 100644
--- a/docs/Installation/index.html
+++ b/docs/Installation/index.html
@@ -1,9 +1,9 @@
-
\ No newline at end of file
diff --git a/docs/Network-Integration/index.html b/docs/Network-Integration/index.html
index daa1ffc..1e84110 100644
--- a/docs/Network-Integration/index.html
+++ b/docs/Network-Integration/index.html
@@ -1,4 +1,4 @@
-
🌐 Network Integration
Network Integration / 网络集成
+
🌐 Network Integration
Network Integration / 网络集成
AuthManager implements AuthTokenSource, so HTTP clients can read the current access token without depending on the manager object. This keeps your Dio setup decoupled from zero_auth.
AuthManager 实现了 AuthTokenSource,因此 HTTP 客户端可在不依赖管理器对象的前提下读取当前访问令牌,使 Dio 配置与 zero_auth 解耦。
\ No newline at end of file
diff --git a/docs/Persistence/index.html b/docs/Persistence/index.html
new file mode 100644
index 0000000..c1b0f54
--- /dev/null
+++ b/docs/Persistence/index.html
@@ -0,0 +1,45 @@
+
💽 Session Persistence
Session Persistence / 会话持久化
+
InMemoryTokenStore loses the session on every restart. For a real app you must persist it — and zero_auth now ships the primitives that make this a one-liner: session (de)serialization plus two ready-to-copy reference stores.
For mobile, persist into the OS keychain / keystore via flutter_secure_storage. A reference implementation lives at example/lib/secure_token_store.dart:
final auth = AuthManager(
+ strategy: myStrategy,
+ tokenStore: SecureTokenStore(), // from example/
+);
+
+await auth.restore(); // rehydrate before the first frame
+
+
Never store refresh tokens in plain SharedPreferences. Use OS-backed secure storage only.
This is ideal for a backend that keeps a logged-in user across process restarts, or a CLI that stays authenticated between invocations.
+
这非常适合「重启后仍保持登录」的后端,或「多次调用之间保持认证」的 CLI。
+
4. Combine with auto-refresh / 结合自动刷新
+
When you enable proactive auto-refresh, the manager renews the token before it expires — and every renewal is persisted through save(), so the on-disk session always carries a fresh access token.
\ No newline at end of file
diff --git a/docs/Third-Party-Login/index.html b/docs/Third-Party-Login/index.html
new file mode 100644
index 0000000..1dc46ca
--- /dev/null
+++ b/docs/Third-Party-Login/index.html
@@ -0,0 +1,111 @@
+
🔑 Third-Party Login
Third-Party Login / 第三方登录
+
The key idea / 核心思路
+
zero_auth does not run the OAuth handshake — and that is deliberate. It is a
+pure-Dart package, so it ships no platform code, no browser plumbing and no
+redirect URL handling (those live outside lib/).
+
Instead, zero_auth manages what comes after the handshake: the session your
+own backend issues.
Because the login method is invisible to the manager, password login and
+Google/Apple login end up sharing one token lifecycle. That is the whole
+point.
+
登录方式对管理器是透明的,因此密码登录与 Google / Apple 登录最终共享同一套
+令牌生命周期机制。这正是关键所在。
+
When this fits / 适用场景
+
This pattern fits when your backend brokers the provider — you have a
+backend, it verifies the provider token, then mints your own tokens.
+
下面的模式适用于你的后端作为经纪方:你有后端,它校验提供方令牌,然后签发你自己的
+令牌。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Scenario
Fit
Own backend + Google/Apple/GitHub sign-in / 自有后端 + 第三方登录
✅ Ideal / 理想
Own backend + password AND social logins / 自有后端,密码与社交登录并存
✅ One shared session model / 共用一套会话模型
Firebase/Supabase issues the tokens directly / 由 Firebase/Supabase 直接签发令牌
⚠️ Use their SDK instead / 请改用其 SDK
+
Wiring it up / 接线步骤
+
1. Run the handshake outside this package.
+Use whichever OAuth client fits your targets (flutter_web_auth, AppAuth, or a
+server-side flow). This code lives in your app or a sibling Flutter package, never
+in lib/.
2. Trade the provider credential for your tokens on your backend.
+
2. 用提供方凭据到你的后端换取自有令牌。
+
Future<AuthSession> signInWithGoogle(BuildContext context) async {
+ // 1) Provider consent (outside zero_auth) → authorization code / id_token.
+ // 提供方授权(零依赖,在 zero_auth 之外)→ 授权码 / id_token。
+ final code = await myOAuthClient.authenticate();
+
+ // 2) Your backend verifies it with Google and returns YOUR tokens.
+ // 你的后端用它与 Google 校验,并返回「你自己的」令牌。
+ final res = await myApi.post('/auth/google', data: {'code': code});
+
+ return AuthSession(
+ accessToken: res['accessToken'] as String,
+ refreshToken: RefreshToken(res['refreshToken'] as String),
+ expiresAt: DateTime.now().add(Duration(seconds: res['expiresIn'] as int)),
+ userId: res['userId'] as String,
+ );
+}
+
3. Hand the session to the manager with loginWith.
+loginWith is the escape hatch for flows that are not login / register: the
+manager still owns persistence, the state machine and proactive refresh.
final result = await auth.loginWith((strategy) => signInWithGoogle(context));
+// emits Authenticating → Authenticated, or AuthError + rethrow.
+// 发出 Authenticating → Authenticated;失败则发 AuthError 并重新抛出。
+
+
Keep signInWithGoogle throwing AuthException with a meaningful code
+('invalid_credentials', 'session_expired', …) so failures map to the typed
+exceptions in Errors.
// Password users and Google users end up with the same AuthSession shape.
+// 密码用户与 Google 用户最终得到的都是同一种 AuthSession。
+await auth.login(const Credentials(username: user, password: pass));
+await auth.loginWith((strategy) => signInWithGoogle(context));
+
Your UI only ever reads state.isAuthenticated, and your network layer only ever
+reads auth.validAccessToken() — regardless of how the user signed in.
\ No newline at end of file
diff --git a/docs/Token-Store/index.html b/docs/Token-Store/index.html
index 8a99e51..25f4048 100644
--- a/docs/Token-Store/index.html
+++ b/docs/Token-Store/index.html
@@ -1,4 +1,4 @@
-
💾 Token Store
Token Store / 令牌存储
+
💾 Token Store
Token Store / 令牌存储
TokenStore is the only persistence surface. The core never touches disk, secure storage, or SharedPreferences directly — you decide where tokens live.
\ No newline at end of file
diff --git a/docs/Usage/index.html b/docs/Usage/index.html
index 0dd4800..2e8c87f 100644
--- a/docs/Usage/index.html
+++ b/docs/Usage/index.html
@@ -1,4 +1,4 @@
-
📖 Usage
Usage / 使用指南
+
📖 Usage
Usage / 使用指南
Three-step integration / 三步集成
1. Implement AuthStrategy / 实现后端边界
class MyAuthStrategy extends AuthStrategy {
@@ -74,4 +74,4 @@
\ No newline at end of file
diff --git a/docs/_next/static/8slIfVBTb0f8-uhdir3Fp/_buildManifest.js b/docs/_next/static/8slIfVBTb0f8-uhdir3Fp/_buildManifest.js
new file mode 100644
index 0000000..dbdaad8
--- /dev/null
+++ b/docs/_next/static/8slIfVBTb0f8-uhdir3Fp/_buildManifest.js
@@ -0,0 +1 @@
+self.__BUILD_MANIFEST=function(e){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[e,"static/chunks/pages/index-b1e2daa6b933b65e.js"],"/Auth-State-Machine":[e,"static/chunks/pages/Auth-State-Machine-a0956e7d1204bfea.js"],"/Backend-Strategy":[e,"static/chunks/pages/Backend-Strategy-68c4f189b6536e77.js"],"/Configuration":[e,"static/chunks/pages/Configuration-c14db61163f267c4.js"],"/Errors":[e,"static/chunks/pages/Errors-6d95421b1599c81e.js"],"/FAQ":[e,"static/chunks/pages/FAQ-63a2841fb00fcc12.js"],"/Getting-Started":[e,"static/chunks/pages/Getting-Started-7a2d78c0e4a938dc.js"],"/Installation":[e,"static/chunks/pages/Installation-2ec080b97b32b024.js"],"/Network-Integration":[e,"static/chunks/pages/Network-Integration-b0e7e91cc72afa34.js"],"/Persistence":[e,"static/chunks/pages/Persistence-2758c9191f4e1054.js"],"/Third-Party-Login":[e,"static/chunks/pages/Third-Party-Login-9e3cc5e5b7759af8.js"],"/Token-Store":[e,"static/chunks/pages/Token-Store-efeab42b53dd2d2e.js"],"/Usage":[e,"static/chunks/pages/Usage-929e5120b89b23b6.js"],"/_error":["static/chunks/pages/_error-7a92967bea80186d.js"],"/_meta":["static/chunks/pages/_meta-b47e7a01bb6b7929.js"],sortedPages:["/","/Auth-State-Machine","/Backend-Strategy","/Configuration","/Errors","/FAQ","/Getting-Started","/Installation","/Network-Integration","/Persistence","/Third-Party-Login","/Token-Store","/Usage","/_app","/_error","/_meta"]}}("static/chunks/812-0b5992150f379e9a.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
\ No newline at end of file
diff --git a/docs/_next/static/xA0AkSUGK7rA_hFr787Ng/_ssgManifest.js b/docs/_next/static/8slIfVBTb0f8-uhdir3Fp/_ssgManifest.js
similarity index 100%
rename from docs/_next/static/xA0AkSUGK7rA_hFr787Ng/_ssgManifest.js
rename to docs/_next/static/8slIfVBTb0f8-uhdir3Fp/_ssgManifest.js
diff --git a/docs/_next/static/chunks/nextra-data-en-US.json b/docs/_next/static/chunks/nextra-data-en-US.json
index 67c16de..183a123 100644
--- a/docs/_next/static/chunks/nextra-data-en-US.json
+++ b/docs/_next/static/chunks/nextra-data-en-US.json
@@ -1 +1 @@
-{"/Backend-Strategy":{"title":"Backend Strategy / 后端策略","data":{"":"AuthStrategy is the only boundary the core needs from a backend. Implement four methods and zero_auth works with REST, gRPC, Firebase, or a private RPC.AuthStrategy 是内核向后台要求的唯一边界。实现四个方法后,zero_auth 即可对接 REST、gRPC、Firebase 或私有 RPC。","the-contract--契约#The contract / 契约":"abstract class AuthStrategy {\r\n Future login(String username, String password);\r\n Future register(String username, String password);\r\n Future logout(AuthSession session);\r\n Future refresh(AuthSession session);\r\n}\nMethod\tWhen called\tMust return\tlogin\tAuthManager.login\tA fresh AuthSession\tregister\tAuthManager.register\tA fresh AuthSession\tlogout\tAuthManager.logout\tvoid (revoke server-side if applicable)\trefresh\tAuthManager.refresh\tA new AuthSession (new tokens)","mapping-failures--映射失败#Mapping failures / 映射失败":"Every thrown error should be mapped to AppException (or AuthException for auth-specific cases). Raw Exceptions must never cross the public surface — the manager wraps unknowns.所有抛出的错误都应映射为 AppException(认证相关场景用 AuthException)。裸 Exception 不得越过公共边界——管理器会包裹未知异常。\nFuture login(String u, String p) async {\r\n try {\r\n final json = await myApi.post('/login', {'u': u, 'p': p});\r\n return AuthSession.fromJson(json);\r\n } on MyApiAuthError catch (e) {\r\n throw AuthException(code: 'invalid_credentials', message: e.message);\r\n }\r\n}","building-the-session--构造会话#Building the session / 构造会话":"Return an AuthSession carrying at least the access token, the refresh token, and an expiry:返回 AuthSession,至少包含访问令牌、刷新令牌与过期时间:\nAuthSession(\r\n accessToken: json['access'],\r\n refreshToken: json['refresh'],\r\n expiresAt: DateTime.parse(json['expiresAt']),\r\n userId: json['userId'],\r\n displayName: json['displayName'],\r\n claims: json, // optional raw claims / 可选的原始 claims\r\n)","example-backend--演示后端#Example backend / 演示后端":"server/ is a zero-dependency dart:io demo backend exercising /login, /refresh, /logout and /me. Run it with dart run bin/server.dart on port 8080.server/ 是一个零依赖的 dart:io 演示后端,提供 /login、/refresh、/logout 与 /me。用 dart run bin/server.dart 在 8080 端口启动。","next-steps--下一步#Next Steps / 下一步":"Token Store — Where sessions are persisted / 会话持久化到何处\nNetwork Integration — Attaching the bearer token / 附加 Bearer 令牌"}},"/Configuration":{"title":"Configuration / 配置","data":{"":"zero_auth is deliberately minimal: there is no global config object. Behavior is composed from the two boundaries you pass to AuthManager.zero_auth 刻意保持精简:没有全局配置对象。行为由你传给 AuthManager 的两个边界组合而成。","composing-authmanager--组合管理器#Composing AuthManager / 组合管理器":"final auth = AuthManager(\r\n strategy: MyAuthStrategy(), // how to talk to the backend / 如何与后端通信\r\n tokenStore: SecureTokenStore(), // where to persist tokens / 令牌持久化位置\r\n);\nKnob\tWhere\tEffect\tBackend endpoints & auth scheme\tAuthStrategy\tWhat login/refresh/… actually do / login/refresh 等的实际行为\tToken persistence\tTokenStore\tDisk / secure storage / in-memory / 磁盘/安全存储/内存\tRefresh timing\tAuthSession.expiresAt\tisExpired drives proactive refresh / 由 isExpired 驱动主动刷新\tToken injection\tAuthTokenSource\tHow the bearer token reaches HTTP clients / 令牌如何到达 HTTP 客户端","refresh-strategy--刷新策略#Refresh strategy / 刷新策略":"refresh() is single-flight by construction: concurrent callers share one in-flight request. You decide when to refresh:refresh() 天生单飞:并发调用方共享同一次进行中的请求。何时刷新由你决定:\nProactively, when session.isExpired is approaching, before a request. / 在请求前、当 session.isExpired 临近时主动刷新。\nReactively, on a 401 from your API (see Network Integration). / 响应式地,在 API 返回 401 时刷新。\nA failed refresh clears the session and emits AuthError; your app should route the user back to login.刷新失败会清空会话并发出 AuthError,应用应将用户引导回登录。","no-global-singletons--没有全局单例#No global singletons / 没有全局单例":"AuthManager is a plain object — create one per app, hold it in your DI container or a top-level variable. The core has no static mutable state.AuthManager 是一个普通对象——每个应用创建一个,放在 DI 容器或顶层变量中即可。内核没有静态可变状态。","next-steps--下一步#Next Steps / 下一步":"Usage — Putting it together / 综合使用\nFAQ — Common questions / 常见问题"}},"/Errors":{"title":"Errors / 错误","data":{"":"zero_auth never lets a raw Exception cross its public surface. Every failure is expressed through one of two mechanisms.zero_auth 绝不允许裸 Exception 越过公共边界。每个失败都通过下面两种机制之一表达。","appexception--异常类型#AppException / 异常类型":"All domain failures extend AppException:所有领域失败都继承 AppException:\nsealed class AppException implements Exception {\r\n final String code; // stable, machine-readable / 稳定、机器可读\r\n final String message; // human-readable / 人类可读\r\n final Object? cause; // original error, if any / 原始错误\r\n}\r\n\r\nfinal class AuthException extends AppException {\r\n // auth-specific cases: invalid_credentials, session_expired, …\r\n // 认证相关场景:invalid_credentials、session_expired 等\r\n}\nAuthStrategy implementations should map transport/API errors into AuthException (or a custom AppException subclass) so callers get a stable code.AuthStrategy 实现方应将传输层/API 错误映射为 AuthException(或自定义 AppException 子类),让调用方拿到稳定的 code。","resultt--结果类型#Result / 结果类型":"For explicit, exception-free handling, use Result:如需显式、无异常的处理,可使用 Result:\nsealed class Result {\r\n const factory Result.ok(T value) = Ok;\r\n const factory Result.err(AppException error) = Err;\r\n}\nfinal result = await auth.tryLogin(user, pass); // returns Result\r\nswitch (result) {\r\n case Ok(:final value):\r\n /* authenticated / 已认证 */\r\n case Err(:final error):\r\n /* inspect error.code / 读取 error.code */\r\n}","how-failures-surface--失败如何呈现#How failures surface / 失败如何呈现":"Situation\tSurfaced as\tlogin/register fails\tAuthState becomes AuthError(error) and the future throws AppException / 状态变为 AuthError,且 future 抛出 AppException\trefresh fails\tSession cleared; AuthError(error) emitted / 会话清空,发出 AuthError\trestore() finds nothing\tStays Unauthenticated (not an error) / 保持 Unauthenticated(不算错误)\tTokenStore.load() throws\tMapped to AppException, treated as \"no session\" / 映射为 AppException,按\"无会话\"处理","next-steps--下一步#Next Steps / 下一步":"Backend Strategy — Map your API errors / 映射你的 API 错误\nConfiguration — Tuning refresh & retry / 调优刷新与重试"}},"/Auth-State-Machine":{"title":"Auth State Machine / 认证状态机","data":{"states--状态#States / 状态":"AuthState is a sealed class with four subtypes:AuthState 是一个密封类,包含四个子类型:\nState\tFields\tMeaning\tAuthUnauthenticated\t—\tNo session / 无会话\tAuthenticating\t—\tlogin/register/restore in flight / 登录/注册/恢复进行中\tAuthenticated\tsession: AuthSession\tA valid session / 有效会话\tAuthError\terror: AppException\tLast operation failed / 上一次操作失败","the-stream--状态流#The stream / 状态流":"AuthManager.state is a Stream that replays the latest value to every new listener (BehaviorSubject-like). This means:AuthManager.state 是一个 Stream,会向每个新订阅者重放最近的值(类似于 BehaviorSubject)。这意味着:\nA freshly mounted widget renders the correct screen on its first frame / 新挂载的 widget 首帧即渲染正确界面。\nYou never need to read a separate \"current state\" field / 无需另读一个\"当前状态\"字段。\nauth.state.listen((state) {\r\n switch (state) {\r\n case Authenticated(:final session):\r\n /* ... */\r\n case AuthError(:final error):\r\n /* ... */\r\n default:\r\n }\r\n});","transitions--状态转移#Transitions / 状态转移":"login/register ──► Authenticating ──► Authenticated\r\n Unauthenticated ◄──────────────────────────────────────┘ (error)\r\n ▲ │ logout\r\n │ ▼\r\n └─────────────────────── AuthError ◄── refresh fails ── Authenticated\r\n └──────────────────────────── restore() finds nothing\nrestore() finds a persisted session → Authenticated; none → stays Unauthenticated.\nA failed login/register → AuthError (the previous state is retained as the \"last good\" state if any).\nA failed refresh clears the session → AuthError.\nrestore() 找到持久化会话 → Authenticated;找不到 → 保持 Unauthenticated。\nlogin/register 失败 → AuthError(若有,则保留上一个\"良好\"状态)。\nrefresh 失败清空会话 → AuthError。","next-steps--下一步#Next Steps / 下一步":"Usage — How to drive the UI from the stream / 如何用状态流驱动界面\nBackend Strategy — What each operation calls / 各操作调用什么"}},"/Getting-Started":{"title":"Getting Started / 快速开始","data":{"quick-start--快速开始#Quick Start / 快速开始":"zero_auth is a headless core: you bring the backend (AuthStrategy) and the persistence (TokenStore), and AuthManager drives the session lifecycle.zero_auth 是一个无头内核:你提供后端(AuthStrategy)与持久化(TokenStore),AuthManager 负责驱动会话生命周期。\nimport 'package:zero_auth/zero_auth.dart';\r\n\r\n// 1. Implement your backend (four methods only).\r\n// 1. 实现你的后端(只需四个方法)。\r\nfinal strategy = MyAuthStrategy();\r\n// 2. Pick a token store. InMemoryTokenStore ships in-core; for production use\r\n// the flutter_secure_storage reference in example/lib/secure_token_store.dart.\r\n// 2. 选择令牌存储。内核自带 InMemoryTokenStore;生产环境请用\r\n// example/lib/secure_token_store.dart 中的 flutter_secure_storage 实现。\r\nfinal store = InMemoryTokenStore();\r\n// 3. Create the manager and restore any persisted session.\r\n// 3. 创建管理器并恢复已持久化的会话。\r\nfinal auth = AuthManager(strategy: strategy, tokenStore: store);\r\nawait auth.restore();\nThen drive the UI from the state stream:随后用状态流驱动界面:\nauth.state.listen((state) {\r\n switch (state) {\r\n case AuthUnauthenticated():\r\n showLoginScreen();\r\n case Authenticating():\r\n showSpinner();\r\n case Authenticated(:final session):\r\n showHome(session.userId);\r\n case AuthError(:final error):\r\n showError(error);\r\n }\r\n});","the-lifecycle--生命周期#The Lifecycle / 生命周期":"AuthManager broadcasts an explicit, sealed state machine:AuthManager 广播一个显式、密封的状态机:\nState\tMeaning\tUnauthenticated\tNo session / 无会话\tAuthenticating\tlogin/register/restore in flight / 登录/注册/恢复进行中\tAuthenticated\tA valid session is present / 存在有效会话\tAuthError\tThe last operation failed / 上一次操作失败\t\nThe stream replays the latest value to new listeners, so a widget renders the correct screen on its first frame.状态流会向新订阅者重放最近的值,因此 widget 在首帧即可渲染正确界面。","next-steps--下一步#Next Steps / 下一步":"Installation — Detailed installation methods / 详细安装方式\nUsage — Full usage guide / 完整使用指南\nBackend Strategy — Implement AuthStrategy / 实现后端边界"}},"/Network-Integration":{"title":"Network Integration / 网络集成","data":{"":"AuthManager implements AuthTokenSource, so HTTP clients can read the current access token without depending on the manager object. This keeps your Dio setup decoupled from zero_auth.AuthManager 实现了 AuthTokenSource,因此 HTTP 客户端可在不依赖管理器对象的前提下读取当前访问令牌,使 Dio 配置与 zero_auth 解耦。","authtokensource--令牌源#AuthTokenSource / 令牌源":"abstract class AuthTokenSource {\r\n Future get accessToken;\r\n}\nAuthManager.accessToken returns the current token, or null when unauthenticated. It can also trigger a transparent refresh when the token is near expiry (implementation-dependent).AuthManager.accessToken 返回当前令牌;未认证时返回 null。在令牌接近过期时,它还可触发一次透明的刷新(取决于实现)。","dio-interceptor--dio-拦截器#Dio interceptor / Dio 拦截器":"example/lib/dio_interceptor.dart ships a ready-to-use interceptor:example/lib/dio_interceptor.dart 提供了一个开箱即用的拦截器:\nclass AuthInterceptor extends Interceptor {\r\n AuthInterceptor(this.tokens); // an AuthTokenSource\r\n final AuthTokenSource tokens;\r\n\r\n @override\r\n void onRequest(RequestOptions o, RequestInterceptorHandler h) async {\r\n final t = await tokens.accessToken;\r\n if (t != null) o.headers['Authorization'] = 'Bearer $t';\r\n h.next(o);\r\n }\r\n}\nfinal dio = Dio()\r\n ..interceptors.add(AuthInterceptor(authManager));\nWhen a 401 is returned, refresh the session and retry; if refresh fails, the manager emits AuthError and your app routes back to login.当返回 401 时,刷新会话并重试;若刷新失败,管理器会发出 AuthError,应用随之跳转登录。","other-http-clients--其它客户端#Other HTTP clients / 其它客户端":"Because AuthTokenSource is a plain interface, the same pattern works for package:http, chopper, or any client that lets you mutate request headers.由于 AuthTokenSource 是普通接口,同样的模式适用于 package:http、chopper 或任何允许修改请求头的客户端。","next-steps--下一步#Next Steps / 下一步":"Usage — Full integration walkthrough / 完整集成讲解\nErrors — Handling 401 and refresh failures / 处理 401 与刷新失败"}},"/Token-Store":{"title":"Token Store / 令牌存储","data":{"":"TokenStore is the only persistence surface. The core never touches disk, secure storage, or SharedPreferences directly — you decide where tokens live.TokenStore 是唯一的持久化接口。内核绝不直接访问磁盘、安全存储或 SharedPreferences——由你决定令牌存放位置。","the-contract--契约#The contract / 契约":"abstract class TokenStore {\r\n Future save(AuthSession session);\r\n Future load();\r\n Future clear();\r\n}\nAuthManager calls load() during restore(), save() after every successful login/refresh, and clear() on logout or a failed refresh.AuthManager 在 restore() 时调用 load(),每次登录/刷新成功后调用 save(),在登出或刷新失败失败时调用 clear()。","in-memory-ships-in-core--内存实现内核自带#In-memory (ships in-core) / 内存实现(内核自带)":"InMemoryTokenStore is the default. It survives process restarts? No — it is in-memory only, so the session is lost on restart. Use it for tests and quick prototypes.InMemoryTokenStore 是默认实现,仅存在于内存,进程重启后会话丢失。适用于测试与原型。\nfinal auth = AuthManager(strategy: s, tokenStore: InMemoryTokenStore());","secure-storage-production--安全存储生产#Secure storage (production) / 安全存储(生产)":"example/lib/secure_token_store.dart shows a flutter_secure_storage-backed reference implementation. Adapt it for your app:example/lib/secure_token_store.dart 提供了基于 flutter_secure_storage 的参考实现,可据此改造:\nclass SecureTokenStore implements TokenStore {\r\n final _box = FlutterSecureStorage();\r\n @override\r\n Future save(AuthSession s) =>\r\n _box.write(key: 'zero_auth', value: jsonEncode(s.toJson()));\r\n @override\r\n Future load() async {\r\n final raw = await _box.read(key: 'zero_auth');\r\n return raw == null ? null : AuthSession.fromJson(jsonDecode(raw));\r\n }\r\n @override\r\n Future clear() => _box.delete(key: 'zero_auth');\r\n}\nPersist tokens only in OS-backed secure storage (Keychain / Keystore). Never store refresh tokens in plain SharedPreferences.令牌只应存放在操作系统级安全存储(Keychain / Keystore)中,切勿把刷新令牌明文存入 SharedPreferences。","next-steps--下一步#Next Steps / 下一步":"Backend Strategy — The other boundary / 另一个边界\nErrors — What load() failures become / load() 失败会变成什么"}},"/Usage":{"title":"Usage / 使用指南","data":{"three-step-integration--三步集成#Three-step integration / 三步集成":"","1-implement-authstrategy--实现后端边界#1. Implement AuthStrategy / 实现后端边界":"class MyAuthStrategy extends AuthStrategy {\r\n @override\r\n Future login(String username, String password) =>\r\n myApi.login(username, password);\r\n\r\n @override\r\n Future register(String username, String password) =>\r\n myApi.register(username, password);\r\n\r\n @override\r\n Future logout(AuthSession session) => myApi.logout(session);\r\n\r\n @override\r\n Future refresh(AuthSession session) =>\r\n myApi.refresh(session);\r\n}","2-create-authmanager-and-restore--创建管理器并恢复#2. Create AuthManager and restore / 创建管理器并恢复":"final auth = AuthManager(\r\n strategy: MyAuthStrategy(),\r\n tokenStore: InMemoryTokenStore(),\r\n);\r\nawait auth.restore(); // rehydrate a persisted session / 恢复持久化会话","3-drive-the-ui-from-the-state-stream--用状态流驱动界面#3. Drive the UI from the state stream / 用状态流驱动界面":"await for (final state in auth.state) {\r\n // render based on state / 根据状态渲染\r\n}","operations--操作#Operations / 操作":"Method\tDescription\trestore()\tRehydrate the persisted session at startup / 启动时恢复会话\tlogin(username, password)\tAuthenticate and enter Authenticated / 登录并进入已认证\tregister(username, password)\tRegister and authenticate / 注册并认证\tlogout()\tClear the session / 清除会话\trefresh()\tSilent token refresh — concurrent calls share one flight / 静默刷新,并发共享单飞\ttokenSource\tAn AuthTokenSource for HTTP clients / 供 HTTP 客户端使用的令牌源","token-refresh--expiry--令牌刷新与过期#Token refresh & expiry / 令牌刷新与过期":"AuthSession exposes isExpired so callers can refresh proactively. refresh() is single-flight: if several callers request a refresh at once, only one network call is made and its result is shared.AuthSession 提供 isExpired,调用方可主动刷新。refresh() 为单飞:多个调用方同时请求刷新时,只发起一次网络调用并共享结果。 A failed refresh clears the session and emits AuthError.刷新失败会清空会话并发出 AuthError。","attaching-the-bearer-token--附加-bearer-令牌#Attaching the bearer token / 附加 Bearer 令牌":"AuthManager implements AuthTokenSource, so a Dio interceptor can read the current token without depending on the manager. See Network Integration.AuthManager 实现了 AuthTokenSource,Dio 拦截器可在不依赖管理器的情况下读取当前令牌。详见网络集成。","next-steps--下一步#Next Steps / 下一步":"Auth State Machine — State lifecycle details / 状态机细节\nBackend Strategy — Full AuthStrategy contract / 完整后端契约\nErrors — Exception & Result model / 异常与结果模型"}},"/":{"title":"Zero Auth","data":{"":"A backend-agnostic auth state machine & session lifecycle core for Dart/Flutter. Pure Dart, headless, no HTTP/SDK/native code. Wire your own backend via AuthStrategy and your own persistence via TokenStore.一个后端无关的认证状态机与会话生命周期内核,面向 Dart/Flutter。纯 Dart、无头(headless),不含 HTTP、SDK 或原生代码。通过 AuthStrategy 接入自有后端,通过 TokenStore 接入自有持久化层。","-features--功能特性#✨ Features / 功能特性":"Feature\tDescription\tBackend-agnostic\tImplement only login/register/logout/refresh; REST, gRPC, Firebase or a private RPC are equally valid targets / 只需实现四个方法,REST、gRPC、Firebase 或私有 RPC 均可接入\tAuth State Machine\tSealed Unauthenticated → Authenticating → Authenticated → AuthError lifecycle on a Stream that replays the latest value to new listeners / 密封状态机 + 重放最近值的状态流,首帧即可渲染正确界面\tSilent Restore\trestore() rehydrates the persisted session at startup / 启动时静默恢复持久化会话\tSingle-flight Refresh\tConcurrent refresh() calls share one in-flight request instead of stampeding the backend / 并发刷新共享同一次请求,避免冲击后端\tPluggable Persistence\tThe only persistence surface is TokenStore.save/load/clear; InMemoryTokenStore ships in-core / 唯一的持久化接口,内核自带内存实现\tTyped Session\tAuthSession carries access/refresh tokens, expiry (isExpired), user id, display name and raw claims / 强类型会话,无需手工解析令牌\tUnified Errors\tEvery failure maps to AppException (AuthException for auth cases) or a Result wrapper; raw exceptions never cross the public surface / 统一异常与结果,裸异常不越界\tNetwork Integration\tAuthManager itself is an AuthTokenSource, so a Dio interceptor can attach Authorization: Bearer without depending on the manager / 管理器即令牌源,Dio 拦截器零依赖附加令牌\tRunnable Example\tA full Flutter demo app (Android/iOS/Web/Windows) plus a zero-dependency dart:io demo backend / 完整 Flutter 示例与一个零依赖演示后端\tCross-platform\tPure Dart — runs anywhere Dart or Flutter runs / 纯 Dart,跨平台","-table-of-contents--目录#📚 Table of Contents / 目录":"Page\tDescription\tGetting Started\tQuick start guide / 快速开始\tInstallation\tHow to install / 安装方式\tUsage\tDetailed usage / 详细使用\tAuth State Machine\tState lifecycle & stream / 状态机与状态流\tBackend Strategy\tImplement AuthStrategy / 实现后端边界\tToken Store\tPersistence boundary / 持久化边界\tNetwork Integration\tDio interceptor & token source / 网络集成与拦截器\tErrors\tException & Result model / 异常与结果模型\tConfiguration\tConfiguration options / 配置说明\tFAQ\tFrequently asked questions / 常见问题","-links--链接#🔗 Links / 链接":"GitHub\nOfficial Website\npub.dev","-license--许可证#📄 License / 许可证":"This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).本项目采用 Mozilla Public License 2.0 (MPL-2.0) 许可证。This package is provided \"as is\", without warranty of any kind. The author assumes no responsibility or liability for the functionality, security, or any consequences arising from the use of modified versions or derivative projects.本包按\"原样\"提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及任何使用后果承担责任。"}},"/FAQ":{"title":"FAQ / 常见问题","data":{"does-zero_auth-ship-an-http-client--zero_auth-内置-http-客户端吗#Does zero_auth ship an HTTP client? / zero_auth 内置 HTTP 客户端吗?":"No. The core is backend-agnostic and ships no HTTP, SDK or native code. You implement AuthStrategy to call your backend.不。内核后端无关,不含任何 HTTP、SDK 或原生代码。你通过实现 AuthStrategy 来调用自己的后端。","does-it-depend-on-flutter--它依赖-flutter-吗#Does it depend on Flutter? / 它依赖 Flutter 吗?":"No. It is a pure-Dart package; flutter: is only a declared constraint because the example app uses Flutter. The runtime has no Flutter dependency.不。它是纯 Dart 包;仅因示例 App 用到 Flutter 才声明 flutter: 约束,运行时不依赖 Flutter。","where-are-tokens-stored--令牌存在哪里#Where are tokens stored? / 令牌存在哪里?":"Wherever your TokenStore puts them. The core ships InMemoryTokenStore (lost on restart). For production, use the flutter_secure_storage-backed reference in example/lib/secure_token_store.dart.取决于你的 TokenStore。内核自带 InMemoryTokenStore(重启即丢失)。生产请用 example/lib/secure_token_store.dart 中基于 flutter_secure_storage 的参考实现。","what-happens-on-a-failed-refresh--刷新失败会怎样#What happens on a failed refresh? / 刷新失败会怎样?":"The session is cleared and AuthState becomes AuthError. Route the user back to login.会话被清空,AuthState 变为 AuthError,应将用户引导回登录。","is-token-refresh-concurrent-safe--令牌刷新是否并发安全#Is token refresh concurrent-safe? / 令牌刷新是否并发安全?":"Yes — refresh() is single-flight: many concurrent callers share one in-flight request and its result.是的——refresh() 为单飞:多个并发调用方共享同一次请求及其结果。","how-do-i-attach-the-bearer-token-to-requests--如何给请求附加-bearer-令牌#How do I attach the bearer token to requests? / 如何给请求附加 Bearer 令牌?":"AuthManager is an AuthTokenSource. Use the Dio interceptor in example/lib/dio_interceptor.dart, or read accessToken directly.AuthManager 即 AuthTokenSource。可用 example/lib/dio_interceptor.dart 中的 Dio 拦截器,或直接读取 accessToken。","which-platforms-are-supported--支持哪些平台#Which platforms are supported? / 支持哪些平台?":"Any platform where Dart or Flutter runs (Android, iOS, Web, Windows, macOS, Linux).任何能运行 Dart 或 Flutter 的平台(Android、iOS、Web、Windows、macOS、Linux)。"}},"/Installation":{"title":"Installation / 安装","data":{"from-pubdev-recommended--从-pubdev-安装推荐#From pub.dev (Recommended) / 从 pub.dev 安装(推荐)":"Add the following to your pubspec.yaml:在 pubspec.yaml 中添加以下依赖:\ndependencies:\r\n zero_auth: ^__ZERO_AUTH_VERSION__\nThen run:然后运行:\ndart pub get","from-github--从-github-安装#From GitHub / 从 GitHub 安装":"Alternatively, install from GitHub:或者从 GitHub 安装:\ndependencies:\r\n zero_auth:\r\n git:\r\n url: https://github.com/zero-labsco/zero_auth.git\r\n ref: release/v__ZERO_AUTH_VERSION__","import--导入#Import / 导入":"import 'package:zero_auth/zero_auth.dart';","requirements--环境要求#Requirements / 环境要求":"Requirement\tVersion\tDart SDK\t>= 3.4.0\tFlutter\t>= 3.0.0 (only a constraint; no Flutter runtime dependency)\t\nzero_auth is a pure-Dart package. Flutter is only listed because the example app uses it; the core has no Flutter dependency.zero_auth 是纯 Dart 包,仅因示例 App 用到 Flutter 才列出;内核本身不依赖 Flutter。","next-steps--下一步#Next Steps / 下一步":"Getting Started — Quick start guide / 快速开始\nUsage — Full usage guide / 完整使用指南"}}}
\ No newline at end of file
+{"/Auth-State-Machine":{"title":"Auth State Machine / 认证状态机","data":{"states--状态#States / 状态":"AuthState is a sealed class with six subtypes:AuthState 是一个密封类,包含六个子类型:\nState\tFields\tMeaning\tUnauthenticated\t—\tNo session / 无会话\tAuthenticating\t—\tlogin/register in flight / 登录/注册进行中\tAuthenticated\tsession: AuthSession\tA valid session / 有效会话\tRefreshing\tsession: AuthSession\tRenewal in flight; the previous session is still usable / 续期进行中,旧会话仍可用\tLoggingOut\tsession: AuthSession\tlogout() in flight; that session is being discarded / 登出进行中,该会话即将被丢弃\tAuthError\terror: AppException\tLast operation failed / 上一次操作失败\t\nTwo helpers save you from spelling out every case:两个辅助属性可避免你手写全部分支:\nstate.isAuthenticated — true for Authenticated and Refreshing, so a\nrenewal never unmounts your signed-in UI. / 在 Authenticated 与 Refreshing\n下均为 true,续期不会卸载已登录界面。\nstate.isBusy — true while Authenticating, Refreshing or LoggingOut. /\n在 Authenticating、Refreshing、LoggingOut 期间为 true。","the-stream--状态流#The stream / 状态流":"AuthManager.state is a Stream that replays the latest value to every new listener (BehaviorSubject-like). This means:AuthManager.state 是一个 Stream,会向每个新订阅者重放最近的值(类似于 BehaviorSubject)。这意味着:\nA freshly mounted widget renders the correct screen on its first frame / 新挂载的 widget 首帧即渲染正确界面。\nYou never need to read a separate \"current state\" field / 无需另读一个\"当前状态\"字段。\nauth.state.listen((state) {\n switch (state) {\n case Authenticated(:final session):\n /* ... */\n case AuthError(:final error):\n /* ... */\n default:\n }\n});","transitions--状态转移#Transitions / 状态转移":"login/register ──► Authenticating ──► Authenticated\n │ ▲\n refresh │ │ success\n ─────────► ▼ │\n Refreshing\n │\n failure │\n ▼\n AuthError ──policy: sign out──► Unauthenticated\n └──policy: keep session─► Authenticated (old session)\n Authenticated ──logout──► LoggingOut ──► Unauthenticated\n Unauthenticated ──restore() finds nothing / nothing persisted──► Unauthenticated\nrestore() restores a live session → Authenticated.\nrestore() restores an expired session → attempts Refreshing; if it\ncannot be renewed (or there is no refresh token) the store is cleared and it\nlands on Unauthenticated. restore(refreshIfExpired: false) restores it\nverbatim instead.\nA failed login/register → AuthError, and the future rethrows.\nA failed refresh → AuthError, followed by Unauthenticated when the\nfailure policy considers the grant unrecoverable,\nor by Authenticated (previous session) when it looks transient.\nDuplicate consecutive emissions are suppressed, so listeners only rebuild on a\nreal change.\nrestore() 恢复未过期会话 → Authenticated。\nrestore() 恢复已过期会话 → 先走 Refreshing;若无法续期(或没有刷新令牌),\n则清空存储并落到 Unauthenticated。restore(refreshIfExpired: false) 则原样恢复。\nlogin/register 失败 → AuthError,同时 future 再次抛出错误。\nrefresh 失败 → AuthError;随后由失败策略决定:\n认为授权不可恢复则转 Unauthenticated,认为只是瞬时故障则回到 Authenticated。\n连续重复的状态会被抑制,监听器只会在真正变化时重建。","next-steps--下一步#Next Steps / 下一步":"Usage — How to drive the UI from the stream / 如何用状态流驱动界面\nBackend Strategy — What each operation calls / 各操作调用什么"}},"/Backend-Strategy":{"title":"Backend Strategy / 后端策略","data":{"":"AuthStrategy is the only boundary the core needs from a backend. Implement four methods and zero_auth works with REST, gRPC, Firebase, or a private RPC.AuthStrategy 是内核向后台要求的唯一边界。实现四个方法后,zero_auth 即可对接 REST、gRPC、Firebase 或私有 RPC。","the-contract--契约#The contract / 契约":"abstract class AuthStrategy {\n Future login(String username, String password);\n Future register(String username, String password);\n Future logout(AuthSession session);\n Future refresh(AuthSession session);\n}\nMethod\tWhen called\tMust return\tlogin\tAuthManager.login\tA fresh AuthSession\tregister\tAuthManager.register\tA fresh AuthSession\tlogout\tAuthManager.logout\tvoid (revoke server-side if applicable)\trefresh\tAuthManager.refresh\tA new AuthSession (new tokens)","mapping-failures--映射失败#Mapping failures / 映射失败":"Every thrown error should be mapped to AppException (or AuthException for auth-specific cases). Raw Exceptions must never cross the public surface — the manager wraps unknowns.所有抛出的错误都应映射为 AppException(认证相关场景用 AuthException)。裸 Exception 不得越过公共边界——管理器会包裹未知异常。\nFuture login(String u, String p) async {\n try {\n final json = await myApi.post('/login', {'u': u, 'p': p});\n return AuthSession.fromJson(json);\n } on MyApiAuthError catch (e) {\n throw AuthException(code: 'invalid_credentials', message: e.message);\n }\n}","building-the-session--构造会话#Building the session / 构造会话":"Return an AuthSession carrying at least the access token, the refresh token, and an expiry:返回 AuthSession,至少包含访问令牌、刷新令牌与过期时间:\nAuthSession(\n accessToken: json['access'],\n refreshToken: json['refresh'],\n expiresAt: DateTime.parse(json['expiresAt']),\n userId: json['userId'],\n displayName: json['displayName'],\n claims: json, // optional raw claims / 可选的原始 claims\n)","example-backend--演示后端#Example backend / 演示后端":"server/ is a zero-dependency dart:io demo backend exercising /login, /refresh, /logout and /me. Run it with dart run bin/server.dart on port 8080.server/ 是一个零依赖的 dart:io 演示后端,提供 /login、/refresh、/logout 与 /me。用 dart run bin/server.dart 在 8080 端口启动。","next-steps--下一步#Next Steps / 下一步":"Token Store — Where sessions are persisted / 会话持久化到何处\nNetwork Integration — Attaching the bearer token / 附加 Bearer 令牌"}},"/Configuration":{"title":"Configuration / 配置","data":{"":"zero_auth is deliberately minimal: there is no global config object. Behavior is composed from the two boundaries you pass to AuthManager.zero_auth 刻意保持精简:没有全局配置对象。行为由你传给 AuthManager 的两个边界组合而成。","composing-authmanager--组合管理器#Composing AuthManager / 组合管理器":"final auth = AuthManager(\n strategy: MyAuthStrategy(), // how to talk to the backend / 如何与后端通信\n tokenStore: SecureTokenStore(), // where to persist tokens / 令牌持久化位置\n autoRefreshAhead: const Duration(minutes: 5), // proactive renewal / 主动续期\n refreshFailurePolicy: defaultRefreshFailurePolicy, // sign-out rule / 登出规则\n clock: () => DateTime.now(), // time source (tests, skew) / 时间源(测试、时钟偏移)\n);\nKnob\tWhere\tEffect\tBackend endpoints & auth scheme\tAuthStrategy\tWhat login/refresh/… actually do / login/refresh 等的实际行为\tToken persistence\tTokenStore\tDisk / secure storage / in-memory / 磁盘/安全存储/内存\tRefresh timing\tAuthSession.expiresAt + autoRefreshAhead\tProactive renewal is scheduled that far before expiry / 在过期前该时长调度主动续期\tRefresh failure handling\trefreshFailurePolicy\tWhether a failed refresh signs the user out / 刷新失败是否让用户登出\tTime source\tclock\tDrives expiry maths and proactive scheduling; inject one for deterministic tests or to tolerate device clock skew / 驱动过期计算与主动刷新调度;注入时钟可实现确定性测试或容忍设备时钟偏移\tToken injection\tAuthTokenSource / validAccessToken()\tHow the bearer token reaches HTTP clients, optionally renewing an expired token first / 令牌如何到达 HTTP 客户端,必要时先续期过期令牌","refresh-strategy--刷新策略#Refresh strategy / 刷新策略":"refresh() is single-flight by construction: concurrent callers share one in-flight request. You decide when to refresh:refresh() 天生单飞:并发调用方共享同一次进行中的请求。何时刷新由你决定:\nProactively, when session.isExpired is approaching, before a request. / 在请求前、当 session.isExpired 临近时主动刷新。\nReactively, on a 401 from your API (see Network Integration). / 响应式地,在 API 返回 401 时刷新。\nA failed refresh is always reported through AuthError (and the rethrown future),\nbut whether it ends the session is decided by refreshFailurePolicy. See\nRefresh failure policy below.刷新失败总会通过 AuthError(以及重新抛出的 future)上报,但是否终止会话由\nrefreshFailurePolicy 决定,详见下方「刷新失败策略」。","refresh-failure-policy--刷新失败策略#Refresh failure policy / 刷新失败策略":"The default policy signs the user out only for failures that can never succeed\nagain, keeping the session when the failure looks transient (so a network blip\ndoes not log people out):默认策略仅在失败「注定无法重试成功」时让用户登出;看起来像瞬时故障时保留会话(避免一次\n网络抖动就把人踢下线):\nFailure / 失败类型\tDefault outcome / 默认结果\tSessionExpiredException, InvalidCredentialsException\tStore cleared → Unauthenticated / 清空存储 → Unauthenticated\tAnything else (network, 5xx…) / 其它(网络、5xx 等)\tSession kept → back to Authenticated / 保留会话 → 回到 Authenticated\t\n// Never sign out on a failed refresh — useful when refresh tokens are\n// long-lived and your backend is occasionally flaky.\n// 刷新失败也绝不登出——适用于刷新令牌长期有效、后端偶尔不稳定的场景。\nfinal auth = AuthManager(\n strategy: strategy,\n refreshFailurePolicy: (AppException error) => false,\n);\nProactive (background) refresh failures are handled internally, so a scheduled\nrenewal can never surface as an unhandled async error.主动(后台)刷新的失败会在内部处理,因此定时续期永远不会以未处理异步错误的形式泄漏。","no-global-singletons--没有全局单例#No global singletons / 没有全局单例":"AuthManager is a plain object — create one per app, hold it in your DI container or a top-level variable. The core has no static mutable state.AuthManager 是一个普通对象——每个应用创建一个,放在 DI 容器或顶层变量中即可。内核没有静态可变状态。","next-steps--下一步#Next Steps / 下一步":"Usage — Putting it together / 综合使用\nFAQ — Common questions / 常见问题"}},"/Errors":{"title":"Errors / 错误","data":{"":"zero_auth never lets a raw Exception cross its public surface. Every failure is expressed through one of two mechanisms.zero_auth 绝不允许裸 Exception 越过公共边界。每个失败都通过下面两种机制之一表达。","appexception--异常类型#AppException / 异常类型":"All domain failures extend AppException:所有领域失败都继承 AppException:\nsealed class AppException implements Exception {\n final String code; // stable, machine-readable / 稳定、机器可读\n final String message; // human-readable / 人类可读\n final Object? cause; // original error, if any / 原始错误\n}\nfinal class AuthException extends AppException {\n // Base type for every auth failure / 所有认证失败的基类型\n}\n// Concrete subtypes — catch these to branch on what actually went wrong.\n// 具体子类型——捕获它们即可按实际错误分支处理。\nfinal class InvalidCredentialsException extends AuthException {} // invalid_credentials / 凭据无效\nfinal class SessionExpiredException extends AuthException {} // session_expired / 会话过期\nfinal class NoActiveSessionException extends AuthException {} // no_active_session / 无活动会话\nfinal class RefreshTokenMissingException extends AuthException {} // refresh_token_missing / 缺少刷新令牌\nfinal class UnexpectedAuthException extends AuthException {} // unexpected_auth_failure / 意外失败\nAuthStrategy authors opt into these subtypes simply by throwing an\nAuthException carrying the matching code; mapAuthFailure performs the\nmapping, preserving any vocabulary it does not recognise.AuthStrategy 实现者只需抛出携带对应 code 的 AuthException 即可参与映射;\nmapAuthFailure 负责转换,并保留它无法识别的自定义错误类型。\ncode\tMapped type / 映射结果\tinvalid_credentials\tInvalidCredentialsException\tinvalid_grant, invalid_refresh_token, token_expired, session_expired\tSessionExpiredException\tno_active_session\tNoActiveSessionException\trefresh_token_missing\tRefreshTokenMissingException\tanything else / 其它\tpreserved as-is, or UnexpectedAuthException / 原样保留或包装为 UnexpectedAuthException\t\nAuthStrategy implementations should map transport/API errors into AuthException (or a custom AppException subclass) so callers get a stable code.AuthStrategy 实现方应将传输层/API 错误映射为 AuthException(或自定义 AppException 子类),让调用方拿到稳定的 code。","resultt--结果类型#Result / 结果类型":"For explicit, exception-free handling, use Result:如需显式、无异常的处理,可使用 Result:\nsealed class Result {\n const factory Result.ok(T value) = Ok;\n const factory Result.err(AppException error) = Err;\n}\nfinal result = await auth.tryLogin(user, pass); // returns Result\nswitch (result) {\n case Ok(:final value):\n /* authenticated / 已认证 */\n case Err(:final error):\n /* inspect error.code / 读取 error.code */\n}","how-failures-surface--失败如何呈现#How failures surface / 失败如何呈现":"Situation\tSurfaced as\tlogin/register fails\tAuthState becomes AuthError(error) and the future throws AppException / 状态变为 AuthError,且 future 抛出 AppException\trefresh fails\tAuthError(error) emitted, then Unauthenticated (unrecoverable) or back to Authenticated (transient) per the failure policy / 发出 AuthError,随后按失败策略转为 Unauthenticated(不可恢复)或回到 Authenticated(瞬时)\trestore() finds nothing\tStays Unauthenticated (not an error) / 保持 Unauthenticated(不算错误)\tTokenStore.load() throws\tMapped to AppException, treated as \"no session\" / 映射为 AppException,按\"无会话\"处理","next-steps--下一步#Next Steps / 下一步":"Backend Strategy — Map your API errors / 映射你的 API 错误\nConfiguration — Tuning refresh & retry / 调优刷新与重试"}},"/Getting-Started":{"title":"Getting Started / 快速开始","data":{"quick-start--快速开始#Quick Start / 快速开始":"zero_auth is a headless core: you bring the backend (AuthStrategy) and the persistence (TokenStore), and AuthManager drives the session lifecycle.zero_auth 是一个无头内核:你提供后端(AuthStrategy)与持久化(TokenStore),AuthManager 负责驱动会话生命周期。\nimport 'package:zero_auth/zero_auth.dart';\n// 1. Implement your backend (four methods only).\n// 1. 实现你的后端(只需四个方法)。\nfinal strategy = MyAuthStrategy();\n// 2. Pick a token store. InMemoryTokenStore ships in-core; for production use\n// the flutter_secure_storage reference in example/lib/secure_token_store.dart.\n// 2. 选择令牌存储。内核自带 InMemoryTokenStore;生产环境请用\n// example/lib/secure_token_store.dart 中的 flutter_secure_storage 实现。\nfinal store = InMemoryTokenStore();\n// 3. Create the manager and restore any persisted session.\n// 3. 创建管理器并恢复已持久化的会话。\nfinal auth = AuthManager(strategy: strategy, tokenStore: store);\nawait auth.restore();\nThen drive the UI from the state stream:随后用状态流驱动界面:\nauth.state.listen((state) {\n switch (state) {\n case Unauthenticated():\n showLoginScreen();\n case Authenticating():\n case LoggingOut():\n showSpinner();\n case Authenticated(:final session):\n showHome(session.userId);\n case Refreshing(:final session):\n // Still signed in: only the token is being renewed.\n // 仍处于已登录状态:只是令牌在续期。\n showHome(session.userId, renewing: true);\n case AuthError(:final error):\n showError(error);\n }\n});\nIf you prefer if/else over exhaustiveness, use state.isAuthenticated and\nstate.isBusy instead of state is Authenticated — isAuthenticated stays\ntrue during Refreshing, so your UI never bounces back to the login screen\nmid-refresh.若不想用穷举匹配,请用 state.isAuthenticated / state.isBusy 代替\nstate is Authenticated——isAuthenticated 在 Refreshing 期间仍为 true,\n界面不会在刷新途中退回登录页。","the-lifecycle--生命周期#The Lifecycle / 生命周期":"AuthManager broadcasts an explicit, sealed state machine:AuthManager 广播一个显式、密封的状态机:\nState\tMeaning\tUnauthenticated\tNo session / 无会话\tAuthenticating\tlogin/register in flight / 登录/注册进行中\tAuthenticated\tA valid session is present / 存在有效会话\tRefreshing\tSession renewal in flight; the previous session stays usable / 续期进行中,旧会话仍可用\tLoggingOut\tlogout() in flight / 登出进行中\tAuthError\tThe last operation failed / 上一次操作失败\t\nThe stream replays the latest value to new listeners, so a widget renders the correct screen on its first frame.状态流会向新订阅者重放最近的值,因此 widget 在首帧即可渲染正确界面。","next-steps--下一步#Next Steps / 下一步":"Installation — Detailed installation methods / 详细安装方式\nUsage — Full usage guide / 完整使用指南\nBackend Strategy — Implement AuthStrategy / 实现后端边界"}},"/Network-Integration":{"title":"Network Integration / 网络集成","data":{"":"AuthManager implements AuthTokenSource, so HTTP clients can read the current access token without depending on the manager object. This keeps your Dio setup decoupled from zero_auth.AuthManager 实现了 AuthTokenSource,因此 HTTP 客户端可在不依赖管理器对象的前提下读取当前访问令牌,使 Dio 配置与 zero_auth 解耦。","authtokensource--令牌源#AuthTokenSource / 令牌源":"abstract class AuthTokenSource {\n Future get accessToken;\n}\nAuthManager.accessToken returns the current token, or null when unauthenticated. It can also trigger a transparent refresh when the token is near expiry (implementation-dependent).AuthManager.accessToken 返回当前令牌;未认证时返回 null。在令牌接近过期时,它还可触发一次透明的刷新(取决于实现)。","dio-interceptor--dio-拦截器#Dio interceptor / Dio 拦截器":"example/lib/dio_interceptor.dart ships a ready-to-use interceptor:example/lib/dio_interceptor.dart 提供了一个开箱即用的拦截器:\nclass AuthInterceptor extends Interceptor {\n AuthInterceptor(this.tokens); // an AuthTokenSource\n final AuthTokenSource tokens;\n @override\n void onRequest(RequestOptions o, RequestInterceptorHandler h) async {\n final t = await tokens.accessToken;\n if (t != null) o.headers['Authorization'] = 'Bearer $t';\n h.next(o);\n }\n}\nfinal dio = Dio()\n ..interceptors.add(AuthInterceptor(authManager));\nWhen a 401 is returned, refresh the session and retry; if refresh fails, the manager emits AuthError and your app routes back to login.当返回 401 时,刷新会话并重试;若刷新失败,管理器会发出 AuthError,应用随之跳转登录。","other-http-clients--其它客户端#Other HTTP clients / 其它客户端":"Because AuthTokenSource is a plain interface, the same pattern works for package:http, chopper, or any client that lets you mutate request headers.由于 AuthTokenSource 是普通接口,同样的模式适用于 package:http、chopper 或任何允许修改请求头的客户端。","next-steps--下一步#Next Steps / 下一步":"Usage — Full integration walkthrough / 完整集成讲解\nErrors — Handling 401 and refresh failures / 处理 401 与刷新失败"}},"/Persistence":{"title":"Session Persistence / 会话持久化","data":{"":"InMemoryTokenStore loses the session on every restart. For a real app you must persist it — and zero_auth now ships the primitives that make this a one-liner: session (de)serialization plus two ready-to-copy reference stores.InMemoryTokenStore 会在每次重启时丢失会话。真实应用必须把它持久化——而 zero_auth 现在提供了让这件事变成「一行代码」的原语:会话(反)序列化,外加两个开箱即用的参考存储。","1-serialize-the-session--序列化会话#1. Serialize the session / 序列化会话":"AuthSession is JSON-safe out of the box. null fields are omitted, and claims round-trips as a plain map.AuthSession 天生就是 JSON 安全的:null 字段会被省略,claims 作为普通映射原样往返。\nfinal json = session.toJson(); // Map\nfinal restored = AuthSession.fromJson(json);\nRefreshToken serializes to its raw string too, so a persisted session rehydrates losslessly.RefreshToken 也序列化为其原始字符串,因此持久化的会话可无损恢复。","2-flutter--encrypted-secure-storage--flutter--加密安全存储#2. Flutter — encrypted secure storage / Flutter —— 加密安全存储":"For mobile, persist into the OS keychain / keystore via flutter_secure_storage. A reference implementation lives at example/lib/secure_token_store.dart:在移动端,通过 flutter_secure_storage 把令牌存入系统钥匙串 / Keystore。参考实现位于 example/lib/secure_token_store.dart:\nfinal auth = AuthManager(\n strategy: myStrategy,\n tokenStore: SecureTokenStore(), // from example/\n);\nawait auth.restore(); // rehydrate before the first frame\nNever store refresh tokens in plain SharedPreferences. Use OS-backed secure storage only.切勿把刷新令牌明文存入 SharedPreferences,只使用操作系统级安全存储。","3-server--cli--desktop--json-file--服务端--cli--桌面--json-文件#3. Server / CLI / desktop — JSON file / 服务端 / CLI / 桌面 —— JSON 文件":"On non-mobile Dart targets you can write the serialized session to a file. A reference implementation lives at example/lib/json_token_store.dart:在非移动端 Dart 目标上,可以把序列化后的会话写入文件。参考实现位于 example/lib/json_token_store.dart:\nfinal auth = AuthManager(\n strategy: myStrategy,\n tokenStore: FileTokenStore(File('.zero_auth_session.json')),\n);\nThis is ideal for a backend that keeps a logged-in user across process restarts, or a CLI that stays authenticated between invocations.这非常适合「重启后仍保持登录」的后端,或「多次调用之间保持认证」的 CLI。","4-combine-with-auto-refresh--结合自动刷新#4. Combine with auto-refresh / 结合自动刷新":"When you enable proactive auto-refresh, the manager renews the token before it expires — and every renewal is persisted through save(), so the on-disk session always carries a fresh access token.当你开启主动自动刷新时,管理器会在令牌过期前续期——而每次续期都会通过 save() 落盘,因此磁盘上的会话始终持有崭新的访问令牌。\nfinal auth = AuthManager(\n strategy: myStrategy,\n tokenStore: SecureTokenStore(),\n autoRefreshAhead: const Duration(minutes: 5),\n);","next-steps--下一步#Next Steps / 下一步":"Token Store — the save / load / clear contract / save / load / clear 契约\nConfiguration — enable proactive auto-refresh / 开启主动自动刷新"}},"/Third-Party-Login":{"title":"Third-Party Login / 第三方登录","data":{"the-key-idea--核心思路#The key idea / 核心思路":"zero_auth does not run the OAuth handshake — and that is deliberate. It is a\r\npure-Dart package, so it ships no platform code, no browser plumbing and no\r\nredirect URL handling (those live outside lib/).Instead, zero_auth manages what comes after the handshake: the session your\r\nown backend issues.zero_auth 不负责 OAuth 握手环节,这是刻意为之:它是纯 Dart 包,不含任何平台\r\n代码、浏览器通道或重定向回调处理(这些只能在 lib/ 之外)。它负责的是握手之后的事:你自己后端所签发的会话。\nprovider consent ──► code / id_token ──► YOUR BACKEND ──► your access + refresh tokens ──► zero_auth\r\n (outside) (any language) (this package)\nBecause the login method is invisible to the manager, password login and\r\nGoogle/Apple login end up sharing one token lifecycle. That is the whole\r\npoint.登录方式对管理器是透明的,因此密码登录与 Google / Apple 登录最终共享同一套\r\n令牌生命周期机制。这正是关键所在。","when-this-fits--适用场景#When this fits / 适用场景":"This pattern fits when your backend brokers the provider — you have a\r\nbackend, it verifies the provider token, then mints your own tokens.下面的模式适用于你的后端作为经纪方:你有后端,它校验提供方令牌,然后签发你自己的\r\n令牌。\nScenario\tFit\tOwn backend + Google/Apple/GitHub sign-in / 自有后端 + 第三方登录\t✅ Ideal / 理想\tOwn backend + password AND social logins / 自有后端,密码与社交登录并存\t✅ One shared session model / 共用一套会话模型\tFirebase/Supabase issues the tokens directly / 由 Firebase/Supabase 直接签发令牌\t⚠️ Use their SDK instead / 请改用其 SDK","wiring-it-up--接线步骤#Wiring it up / 接线步骤":"1. Run the handshake outside this package.\r\nUse whichever OAuth client fits your targets (flutter_web_auth, AppAuth, or a\r\nserver-side flow). This code lives in your app or a sibling Flutter package, never\r\nin lib/.1. 在本包之外完成握手。\r\n使用适合目标平台的 OAuth 客户端(flutter_web_auth、AppAuth 或服务端流程)。这部分\r\n代码放在你的应用或兄弟 Flutter 包里,绝不放在 lib/。2. Trade the provider credential for your tokens on your backend.2. 用提供方凭据到你的后端换取自有令牌。\nFuture signInWithGoogle(BuildContext context) async {\r\n // 1) Provider consent (outside zero_auth) → authorization code / id_token.\r\n // 提供方授权(零依赖,在 zero_auth 之外)→ 授权码 / id_token。\r\n final code = await myOAuthClient.authenticate();\r\n\r\n // 2) Your backend verifies it with Google and returns YOUR tokens.\r\n // 你的后端用它与 Google 校验,并返回「你自己的」令牌。\r\n final res = await myApi.post('/auth/google', data: {'code': code});\r\n\r\n return AuthSession(\r\n accessToken: res['accessToken'] as String,\r\n refreshToken: RefreshToken(res['refreshToken'] as String),\r\n expiresAt: DateTime.now().add(Duration(seconds: res['expiresIn'] as int)),\r\n userId: res['userId'] as String,\r\n );\r\n}\n3. Hand the session to the manager with loginWith.\r\nloginWith is the escape hatch for flows that are not login / register: the\r\nmanager still owns persistence, the state machine and proactive refresh.3. 用 loginWith 把会话交给管理器。\r\nloginWith 是为那些不符合 login / register 形态的流程准备的逃生口:持久化、状态机\r\n与主动刷新仍由管理器负责。\nfinal result = await auth.loginWith((strategy) => signInWithGoogle(context));\r\n// emits Authenticating → Authenticated, or AuthError + rethrow.\r\n// 发出 Authenticating → Authenticated;失败则发 AuthError 并重新抛出。\nKeep signInWithGoogle throwing AuthException with a meaningful code\r\n('invalid_credentials', 'session_expired', …) so failures map to the typed\r\nexceptions in Errors.让 signInWithGoogle 抛出带有实用 code('invalid_credentials'、\r\n'session_expired' 等)的 AuthException,这样失败就能映射为\r\nErrors 里的具体异常类型。","same-model-for-every-method--各登录方式共用一套模型#Same model for every method / 各登录方式共用一套模型":"// Password users and Google users end up with the same AuthSession shape.\r\n// 密码用户与 Google 用户最终得到的都是同一种 AuthSession。\r\nawait auth.login(const Credentials(username: user, password: pass));\r\nawait auth.loginWith((strategy) => signInWithGoogle(context));\nYour UI only ever reads state.isAuthenticated, and your network layer only ever\r\nreads auth.validAccessToken() — regardless of how the user signed in.你的界面只需要读 state.isAuthenticated,网络层只需要读 auth.validAccessToken()\r\n——无需关心用户是哪种方式登录的。","also-works-for--同样适用于#Also works for / 同样适用于":"loginWith covers any flow you drive yourself:loginWith 适用于任何由你驱动的流程:\nMagic links / email OTP / 魔法链接、邮箱验证码\nPasskeys / WebAuthn\nBiometric re-unlock (load a locked session and re-mint tokens) / 生物识别解锁\nMigrating from another auth SDK / 从其它认证 SDK 迁移","next-steps--下一步#Next Steps / 下一步":"Backend Strategy — what your strategy must implement / 策略需要实现什么\nAuth State Machine — the states this flow emits / 该流程发出的状态\nErrors — typed exceptions and codes / 类型化异常与 code"}},"/Usage":{"title":"Usage / 使用指南","data":{"three-step-integration--三步集成#Three-step integration / 三步集成":"","1-implement-authstrategy--实现后端边界#1. Implement AuthStrategy / 实现后端边界":"class MyAuthStrategy extends AuthStrategy {\n @override\n Future login(String username, String password) =>\n myApi.login(username, password);\n @override\n Future register(String username, String password) =>\n myApi.register(username, password);\n @override\n Future logout(AuthSession session) => myApi.logout(session);\n @override\n Future refresh(AuthSession session) =>\n myApi.refresh(session);\n}","2-create-authmanager-and-restore--创建管理器并恢复#2. Create AuthManager and restore / 创建管理器并恢复":"final auth = AuthManager(\n strategy: MyAuthStrategy(),\n tokenStore: InMemoryTokenStore(),\n);\nawait auth.restore(); // rehydrate a persisted session / 恢复持久化会话","3-drive-the-ui-from-the-state-stream--用状态流驱动界面#3. Drive the UI from the state stream / 用状态流驱动界面":"await for (final state in auth.state) {\n // render based on state / 根据状态渲染\n}","operations--操作#Operations / 操作":"Method\tDescription\trestore()\tRehydrate the persisted session at startup / 启动时恢复会话\tlogin(username, password)\tAuthenticate and enter Authenticated / 登录并进入已认证\tregister(username, password)\tRegister and authenticate / 注册并认证\tlogout()\tClear the session / 清除会话\trefresh()\tSilent token refresh — concurrent calls share one flight / 静默刷新,并发共享单飞\ttokenSource\tAn AuthTokenSource for HTTP clients / 供 HTTP 客户端使用的令牌源","token-refresh--expiry--令牌刷新与过期#Token refresh & expiry / 令牌刷新与过期":"AuthSession exposes isExpired so callers can refresh proactively. refresh() is single-flight: if several callers request a refresh at once, only one network call is made and its result is shared.AuthSession 提供 isExpired,调用方可主动刷新。refresh() 为单飞:多个调用方同时请求刷新时,只发起一次网络调用并共享结果。 A failed refresh clears the session and emits AuthError.刷新失败会清空会话并发出 AuthError。","attaching-the-bearer-token--附加-bearer-令牌#Attaching the bearer token / 附加 Bearer 令牌":"AuthManager implements AuthTokenSource, so a Dio interceptor can read the current token without depending on the manager. See Network Integration.AuthManager 实现了 AuthTokenSource,Dio 拦截器可在不依赖管理器的情况下读取当前令牌。详见网络集成。","next-steps--下一步#Next Steps / 下一步":"Auth State Machine — State lifecycle details / 状态机细节\nBackend Strategy — Full AuthStrategy contract / 完整后端契约\nErrors — Exception & Result model / 异常与结果模型"}},"/Token-Store":{"title":"Token Store / 令牌存储","data":{"":"TokenStore is the only persistence surface. The core never touches disk, secure storage, or SharedPreferences directly — you decide where tokens live.TokenStore 是唯一的持久化接口。内核绝不直接访问磁盘、安全存储或 SharedPreferences——由你决定令牌存放位置。","the-contract--契约#The contract / 契约":"abstract class TokenStore {\n Future save(AuthSession session);\n Future load();\n Future clear();\n}\nAuthManager calls load() during restore(), save() after every successful login/refresh, and clear() on logout or a failed refresh.AuthManager 在 restore() 时调用 load(),每次登录/刷新成功后调用 save(),在登出或刷新失败失败时调用 clear()。","in-memory-ships-in-core--内存实现内核自带#In-memory (ships in-core) / 内存实现(内核自带)":"InMemoryTokenStore is the default. It survives process restarts? No — it is in-memory only, so the session is lost on restart. Use it for tests and quick prototypes.InMemoryTokenStore 是默认实现,仅存在于内存,进程重启后会话丢失。适用于测试与原型。\nfinal auth = AuthManager(strategy: s, tokenStore: InMemoryTokenStore());","secure-storage-production--安全存储生产#Secure storage (production) / 安全存储(生产)":"example/lib/secure_token_store.dart shows a flutter_secure_storage-backed reference implementation. Adapt it for your app:example/lib/secure_token_store.dart 提供了基于 flutter_secure_storage 的参考实现,可据此改造:\nclass SecureTokenStore implements TokenStore {\n final _box = FlutterSecureStorage();\n @override\n Future save(AuthSession s) =>\n _box.write(key: 'zero_auth', value: jsonEncode(s.toJson()));\n @override\n Future load() async {\n final raw = await _box.read(key: 'zero_auth');\n return raw == null ? null : AuthSession.fromJson(jsonDecode(raw));\n }\n @override\n Future clear() => _box.delete(key: 'zero_auth');\n}\nPersist tokens only in OS-backed secure storage (Keychain / Keystore). Never store refresh tokens in plain SharedPreferences.令牌只应存放在操作系统级安全存储(Keychain / Keystore)中,切勿把刷新令牌明文存入 SharedPreferences。","next-steps--下一步#Next Steps / 下一步":"Session Persistence — persist sessions across restarts (serialization + reference stores) / 跨重启持久化会话(序列化与参考存储)\nBackend Strategy — The other boundary / 另一个边界\nErrors — What load() failures become / load() 失败会变成什么"}},"/":{"title":"Zero Auth","data":{"":"A backend-agnostic auth state machine & session lifecycle core for Dart/Flutter. Pure Dart, headless, no HTTP/SDK/native code. Wire your own backend via AuthStrategy and your own persistence via TokenStore.一个后端无关的认证状态机与会话生命周期内核,面向 Dart/Flutter。纯 Dart、无头(headless),不含 HTTP、SDK 或原生代码。通过 AuthStrategy 接入自有后端,通过 TokenStore 接入自有持久化层。","-features--功能特性#✨ Features / 功能特性":"Feature\tDescription\tBackend-agnostic\tImplement only login/register/logout/refresh; REST, gRPC, Firebase or a private RPC are equally valid targets / 只需实现四个方法,REST、gRPC、Firebase 或私有 RPC 均可接入\tAuth State Machine\tSealed Unauthenticated → Authenticating → Authenticated → AuthError lifecycle on a Stream that replays the latest value to new listeners / 密封状态机 + 重放最近值的状态流,首帧即可渲染正确界面\tSilent Restore\trestore() rehydrates the persisted session at startup / 启动时静默恢复持久化会话\tSingle-flight Refresh\tConcurrent refresh() calls share one in-flight request instead of stampeding the backend / 并发刷新共享同一次请求,避免冲击后端\tPluggable Persistence\tThe only persistence surface is TokenStore.save/load/clear; InMemoryTokenStore ships in-core / 唯一的持久化接口,内核自带内存实现\tTyped Session\tAuthSession carries access/refresh tokens, expiry (isExpired), user id, display name and raw claims / 强类型会话,无需手工解析令牌\tUnified Errors\tEvery failure maps to AppException (AuthException for auth cases) or a Result wrapper; raw exceptions never cross the public surface / 统一异常与结果,裸异常不越界\tNetwork Integration\tAuthManager itself is an AuthTokenSource, so a Dio interceptor can attach Authorization: Bearer without depending on the manager / 管理器即令牌源,Dio 拦截器零依赖附加令牌\tSession Serialization\tAuthSession.toJson / fromJson make persistence a one-liner; a file-based reference store ships for server/CLI / AuthSession.toJson / fromJson 让持久化一行搞定,并附带面向服务端 / CLI 的文件参考存储\tProactive Auto-refresh\tPass autoRefreshAhead to renew tokens before expiry (single-flight) / 传入 autoRefreshAhead 在过期前自动续期(单飞)\tRunnable Example\tA full Flutter demo app (Android/iOS/Web/Windows) plus a zero-dependency dart:io demo backend / 完整 Flutter 示例与一个零依赖演示后端\tCross-platform\tPure Dart — runs anywhere Dart or Flutter runs / 纯 Dart,跨平台","-table-of-contents--目录#📚 Table of Contents / 目录":"Page\tDescription\tGetting Started\tQuick start guide / 快速开始\tInstallation\tHow to install / 安装方式\tUsage\tDetailed usage / 详细使用\tAuth State Machine\tState lifecycle & stream / 状态机与状态流\tBackend Strategy\tImplement AuthStrategy / 实现后端边界\tToken Store\tPersistence boundary / 持久化边界\tNetwork Integration\tDio interceptor & token source / 网络集成与拦截器\tErrors\tException & Result model / 异常与结果模型\tConfiguration\tConfiguration options / 配置说明\tFAQ\tFrequently asked questions / 常见问题","-links--链接#🔗 Links / 链接":"GitHub\nOfficial Website\npub.dev","-license--许可证#📄 License / 许可证":"This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).本项目采用 Mozilla Public License 2.0 (MPL-2.0) 许可证。This package is provided \"as is\", without warranty of any kind. The author assumes no responsibility or liability for the functionality, security, or any consequences arising from the use of modified versions or derivative projects.本包按\"原样\"提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及任何使用后果承担责任。"}},"/FAQ":{"title":"FAQ / 常见问题","data":{"does-zero_auth-ship-an-http-client--zero_auth-内置-http-客户端吗#Does zero_auth ship an HTTP client? / zero_auth 内置 HTTP 客户端吗?":"No. The core is backend-agnostic and ships no HTTP, SDK or native code. You implement AuthStrategy to call your backend.不。内核后端无关,不含任何 HTTP、SDK 或原生代码。你通过实现 AuthStrategy 来调用自己的后端。","does-it-depend-on-flutter--它依赖-flutter-吗#Does it depend on Flutter? / 它依赖 Flutter 吗?":"No. It is a pure-Dart package; flutter: is only a declared constraint because the example app uses Flutter. The runtime has no Flutter dependency.不。它是纯 Dart 包;仅因示例 App 用到 Flutter 才声明 flutter: 约束,运行时不依赖 Flutter。","where-are-tokens-stored--令牌存在哪里#Where are tokens stored? / 令牌存在哪里?":"Wherever your TokenStore puts them. The core ships InMemoryTokenStore (lost on restart). For production, use the flutter_secure_storage-backed reference in example/lib/secure_token_store.dart.取决于你的 TokenStore。内核自带 InMemoryTokenStore(重启即丢失)。生产请用 example/lib/secure_token_store.dart 中基于 flutter_secure_storage 的参考实现。","what-happens-on-a-failed-refresh--刷新失败会怎样#What happens on a failed refresh? / 刷新失败会怎样?":"The session is cleared and AuthState becomes AuthError. Route the user back to login.会话被清空,AuthState 变为 AuthError,应将用户引导回登录。","is-token-refresh-concurrent-safe--令牌刷新是否并发安全#Is token refresh concurrent-safe? / 令牌刷新是否并发安全?":"Yes — refresh() is single-flight: many concurrent callers share one in-flight request and its result.是的——refresh() 为单飞:多个并发调用方共享同一次请求及其结果。","how-do-i-attach-the-bearer-token-to-requests--如何给请求附加-bearer-令牌#How do I attach the bearer token to requests? / 如何给请求附加 Bearer 令牌?":"AuthManager is an AuthTokenSource. Use the Dio interceptor in example/lib/dio_interceptor.dart, or read accessToken directly.AuthManager 即 AuthTokenSource。可用 example/lib/dio_interceptor.dart 中的 Dio 拦截器,或直接读取 accessToken。","which-platforms-are-supported--支持哪些平台#Which platforms are supported? / 支持哪些平台?":"Any platform where Dart or Flutter runs (Android, iOS, Web, Windows, macOS, Linux).任何能运行 Dart 或 Flutter 的平台(Android、iOS、Web、Windows、macOS、Linux)。"}},"/Installation":{"title":"Installation / 安装","data":{"from-pubdev-recommended--从-pubdev-安装推荐#From pub.dev (Recommended) / 从 pub.dev 安装(推荐)":"Add the following to your pubspec.yaml:在 pubspec.yaml 中添加以下依赖:\ndependencies:\n zero_auth: ^0.3.0\nThen run:然后运行:\ndart pub get","from-github--从-github-安装#From GitHub / 从 GitHub 安装":"Alternatively, install from GitHub:或者从 GitHub 安装:\ndependencies:\n zero_auth:\n git:\n url: https://github.com/zero-labsco/zero_auth.git\n ref: release/v0.3.0","import--导入#Import / 导入":"import 'package:zero_auth/zero_auth.dart';","requirements--环境要求#Requirements / 环境要求":"Requirement\tVersion\tDart SDK\t>= 3.4.0\tFlutter\t>= 3.0.0 (only a constraint; no Flutter runtime dependency)\t\nzero_auth is a pure-Dart package. Flutter is only listed because the example app uses it; the core has no Flutter dependency.zero_auth 是纯 Dart 包,仅因示例 App 用到 Flutter 才列出;内核本身不依赖 Flutter。","next-steps--下一步#Next Steps / 下一步":"Getting Started — Quick start guide / 快速开始\nUsage — Full usage guide / 完整使用指南"}}}
\ No newline at end of file
diff --git a/docs/_next/static/chunks/nextra-page-map-.mjs b/docs/_next/static/chunks/nextra-page-map-.mjs
index 8e0ddb1..81b44e8 100644
--- a/docs/_next/static/chunks/nextra-page-map-.mjs
+++ b/docs/_next/static/chunks/nextra-page-map-.mjs
@@ -55,6 +55,18 @@ export const pageMap = [{
frontMatter: {
"sidebarTitle": "Network Integration"
}
+}, {
+ name: "Persistence",
+ route: "/Persistence",
+ frontMatter: {
+ "sidebarTitle": "Persistence"
+ }
+}, {
+ name: "Third-Party-Login",
+ route: "/Third-Party-Login",
+ frontMatter: {
+ "sidebarTitle": "Third Party Login"
+ }
}, {
name: "Token-Store",
route: "/Token-Store",
diff --git a/docs/_next/static/chunks/pages/Auth-State-Machine-0602992353358b58.js b/docs/_next/static/chunks/pages/Auth-State-Machine-0602992353358b58.js
deleted file mode 100644
index e9c7635..0000000
--- a/docs/_next/static/chunks/pages/Auth-State-Machine-0602992353358b58.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[207],{4778:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Auth-State-Machine",function(){return t(6503)}])},6503:function(e,n,t){"use strict";t.r(n),t.d(n,{useTOC:function(){return d}});var i=t(5893),s=t(7812),r=t(7080),a=t(8925);function d(e){return[{value:"States / 状态",id:"states--状态",depth:2},{value:"The stream / 状态流",id:"the-stream--状态流",depth:2},{value:"Transitions / 状态转移",id:"transitions--状态转移",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}n.default=(0,s.c)(function(e){let{toc:n=d(e)}=e,t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{children:"Auth State Machine / 认证状态机"}),"\n",(0,i.jsx)(t.h2,{id:n[0].id,children:n[0].value}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"AuthState"})," is a sealed class with four subtypes:"]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"AuthState"})," 是一个密封类,包含四个子类型:"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,i.jsxs)(t.table,{children:[(0,i.jsx)(t.thead,{children:(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.th,{children:"State"}),(0,i.jsx)(t.th,{children:"Fields"}),(0,i.jsx)(t.th,{children:"Meaning"})]})}),(0,i.jsxs)(t.tbody,{children:[(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.code,{children:"AuthUnauthenticated"})}),(0,i.jsx)(t.td,{children:"—"}),(0,i.jsx)(t.td,{children:"No session / 无会话"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.code,{children:"Authenticating"})}),(0,i.jsx)(t.td,{children:"—"}),(0,i.jsxs)(t.td,{children:[(0,i.jsx)(t.code,{children:"login"}),"/",(0,i.jsx)(t.code,{children:"register"}),"/",(0,i.jsx)(t.code,{children:"restore"})," in flight / 登录/注册/恢复进行中"]})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.code,{children:"Authenticated"})}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.code,{children:"session: AuthSession"})}),(0,i.jsx)(t.td,{children:"A valid session / 有效会话"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.code,{children:"AuthError"})}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.code,{children:"error: AppException"})}),(0,i.jsx)(t.td,{children:"Last operation failed / 上一次操作失败"})]})]})]}),"\n",(0,i.jsx)(t.h2,{id:n[1].id,children:n[1].value}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"AuthManager.state"})," is a ",(0,i.jsx)(t.code,{children:"Stream"})," that ",(0,i.jsx)(t.strong,{children:"replays the latest value"})," to every new listener (",(0,i.jsx)(t.code,{children:"BehaviorSubject"}),"-like). This means:"]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"AuthManager.state"})," 是一个 ",(0,i.jsx)(t.code,{children:"Stream"}),",会向每个新订阅者",(0,i.jsx)(t.strong,{children:"重放最近的值"}),"(类似于 ",(0,i.jsx)(t.code,{children:"BehaviorSubject"}),")。这意味着:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"A freshly mounted widget renders the correct screen on its first frame / 新挂载的 widget 首帧即渲染正确界面。"}),"\n",(0,i.jsx)(t.li,{children:"You never need to read a separate “current state” field / 无需另读一个”当前状态”字段。"}),"\n"]}),"\n",(0,i.jsx)(t.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,i.jsxs)(t.code,{children:[(0,i.jsxs)(t.span,{children:[(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"auth.state."}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"listen"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((state) {"})]}),"\n",(0,i.jsxs)(t.span,{children:[(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" switch"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (state) {"})]}),"\n",(0,i.jsxs)(t.span,{children:[(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Authenticated"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session)"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* ... */"})}),"\n",(0,i.jsxs)(t.span,{children:[(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthError"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error)"}),(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* ... */"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" default:"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})})]})}),"\n",(0,i.jsx)(t.h2,{id:n[2].id,children:n[2].value}),"\n",(0,i.jsx)(t.pre,{tabIndex:"0","data-language":"plaintext","data-word-wrap":"","data-copy":"",children:(0,i.jsxs)(t.code,{children:[(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{children:" login/register ──► Authenticating ──► Authenticated"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{children:" Unauthenticated ◄──────────────────────────────────────┘ (error)"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{children:" ▲ │ logout"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{children:" │ ▼"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{children:" └─────────────────────── AuthError ◄── refresh fails ── Authenticated"})}),"\n",(0,i.jsx)(t.span,{children:(0,i.jsx)(t.span,{children:" └──────────────────────────── restore() finds nothing"})})]})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"restore()"})," finds a persisted session → ",(0,i.jsx)(t.code,{children:"Authenticated"}),"; none → stays ",(0,i.jsx)(t.code,{children:"Unauthenticated"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(t.li,{children:["\n",(0,i.jsxs)(t.p,{children:["A failed ",(0,i.jsx)(t.code,{children:"login"}),"/",(0,i.jsx)(t.code,{children:"register"})," → ",(0,i.jsx)(t.code,{children:"AuthError"})," (the previous state is retained as the “last good” state if any)."]}),"\n"]}),"\n",(0,i.jsxs)(t.li,{children:["\n",(0,i.jsxs)(t.p,{children:["A failed ",(0,i.jsx)(t.code,{children:"refresh"})," clears the session → ",(0,i.jsx)(t.code,{children:"AuthError"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(t.li,{children:["\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"restore()"})," 找到持久化会话 → ",(0,i.jsx)(t.code,{children:"Authenticated"}),";找不到 → 保持 ",(0,i.jsx)(t.code,{children:"Unauthenticated"}),"。"]}),"\n"]}),"\n",(0,i.jsxs)(t.li,{children:["\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"login"}),"/",(0,i.jsx)(t.code,{children:"register"})," 失败 → ",(0,i.jsx)(t.code,{children:"AuthError"}),"(若有,则保留上一个”良好”状态)。"]}),"\n"]}),"\n",(0,i.jsxs)(t.li,{children:["\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"refresh"})," 失败清空会话 → ",(0,i.jsx)(t.code,{children:"AuthError"}),"。"]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:n[3].id,children:n[3].value}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"Usage",children:"Usage"})," — How to drive the UI from the stream / 如何用状态流驱动界面"]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — What each operation calls / 各操作调用什么"]}),"\n"]})]})},"/Auth-State-Machine",{filePath:"pages/Auth-State-Machine.md",pageMap:r.v,frontMatter:{},title:"Auth State Machine / 认证状态机"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,n,t){"use strict";t.d(n,{v:function(){return i}});let i=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=4778)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Auth-State-Machine-a0956e7d1204bfea.js b/docs/_next/static/chunks/pages/Auth-State-Machine-a0956e7d1204bfea.js
new file mode 100644
index 0000000..0400565
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Auth-State-Machine-a0956e7d1204bfea.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[207],{4778:function(e,n,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Auth-State-Machine",function(){return s(6503)}])},6503:function(e,n,s){"use strict";s.r(n),s.d(n,{useTOC:function(){return h}});var i=s(5893),t=s(7812),r=s(7080),d=s(8925);function h(e){return[{value:"States / 状态",id:"states--状态",depth:2},{value:"The stream / 状态流",id:"the-stream--状态流",depth:2},{value:"Transitions / 状态转移",id:"transitions--状态转移",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}n.default=(0,t.c)(function(e){let{toc:n=h(e)}=e,s={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(s.h1,{children:"Auth State Machine / 认证状态机"}),"\n",(0,i.jsx)(s.h2,{id:n[0].id,children:n[0].value}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"AuthState"})," is a sealed class with six subtypes:"]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"AuthState"})," 是一个密封类,包含六个子类型:"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"State"}),(0,i.jsx)(s.th,{children:"Fields"}),(0,i.jsx)(s.th,{children:"Meaning"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"Unauthenticated"})}),(0,i.jsx)(s.td,{children:"—"}),(0,i.jsx)(s.td,{children:"No session / 无会话"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"Authenticating"})}),(0,i.jsx)(s.td,{children:"—"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"login"}),"/",(0,i.jsx)(s.code,{children:"register"})," in flight / 登录/注册进行中"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"Authenticated"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"session: AuthSession"})}),(0,i.jsx)(s.td,{children:"A valid session / 有效会话"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"Refreshing"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"session: AuthSession"})}),(0,i.jsx)(s.td,{children:"Renewal in flight; the previous session is still usable / 续期进行中,旧会话仍可用"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"LoggingOut"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"session: AuthSession"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"logout()"})," in flight; that session is being discarded / 登出进行中,该会话即将被丢弃"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"AuthError"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"error: AppException"})}),(0,i.jsx)(s.td,{children:"Last operation failed / 上一次操作失败"})]})]})]}),"\n",(0,i.jsx)(s.p,{children:"Two helpers save you from spelling out every case:"}),"\n",(0,i.jsx)(s.p,{children:"两个辅助属性可避免你手写全部分支:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"state.isAuthenticated"})," — ",(0,i.jsx)(s.code,{children:"true"})," for ",(0,i.jsx)(s.code,{children:"Authenticated"})," ",(0,i.jsx)(s.strong,{children:"and"})," ",(0,i.jsx)(s.code,{children:"Refreshing"}),", so a\nrenewal never unmounts your signed-in UI. / 在 ",(0,i.jsx)(s.code,{children:"Authenticated"})," 与 ",(0,i.jsx)(s.code,{children:"Refreshing"}),"\n下均为 ",(0,i.jsx)(s.code,{children:"true"}),",续期不会卸载已登录界面。"]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"state.isBusy"})," — ",(0,i.jsx)(s.code,{children:"true"})," while ",(0,i.jsx)(s.code,{children:"Authenticating"}),", ",(0,i.jsx)(s.code,{children:"Refreshing"})," or ",(0,i.jsx)(s.code,{children:"LoggingOut"}),". /\n在 ",(0,i.jsx)(s.code,{children:"Authenticating"}),"、",(0,i.jsx)(s.code,{children:"Refreshing"}),"、",(0,i.jsx)(s.code,{children:"LoggingOut"})," 期间为 ",(0,i.jsx)(s.code,{children:"true"}),"。"]}),"\n"]}),"\n",(0,i.jsx)(s.h2,{id:n[1].id,children:n[1].value}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"AuthManager.state"})," is a ",(0,i.jsx)(s.code,{children:"Stream"})," that ",(0,i.jsx)(s.strong,{children:"replays the latest value"})," to every new listener (",(0,i.jsx)(s.code,{children:"BehaviorSubject"}),"-like). This means:"]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"AuthManager.state"})," 是一个 ",(0,i.jsx)(s.code,{children:"Stream"}),",会向每个新订阅者",(0,i.jsx)(s.strong,{children:"重放最近的值"}),"(类似于 ",(0,i.jsx)(s.code,{children:"BehaviorSubject"}),")。这意味着:"]}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsx)(s.li,{children:"A freshly mounted widget renders the correct screen on its first frame / 新挂载的 widget 首帧即渲染正确界面。"}),"\n",(0,i.jsx)(s.li,{children:"You never need to read a separate “current state” field / 无需另读一个”当前状态”字段。"}),"\n"]}),"\n",(0,i.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,i.jsxs)(s.code,{children:[(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"auth.state."}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"listen"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((state) {"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" switch"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (state) {"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Authenticated"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session)"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* ... */"})}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthError"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error)"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* ... */"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" default:"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})})]})}),"\n",(0,i.jsx)(s.h2,{id:n[2].id,children:n[2].value}),"\n",(0,i.jsx)(s.pre,{tabIndex:"0","data-language":"plaintext","data-word-wrap":"","data-copy":"",children:(0,i.jsxs)(s.code,{children:[(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" login/register ──► Authenticating ──► Authenticated"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" │ ▲"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" refresh │ │ success"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" ─────────► ▼ │"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" Refreshing"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" │"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" failure │"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" ▼"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" AuthError ──policy: sign out──► Unauthenticated"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" └──policy: keep session─► Authenticated (old session)"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" Authenticated ──logout──► LoggingOut ──► Unauthenticated"})}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{children:" Unauthenticated ──restore() finds nothing / nothing persisted──► Unauthenticated"})})]})}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"restore()"})," restores a live session → ",(0,i.jsx)(s.code,{children:"Authenticated"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"restore()"})," restores an ",(0,i.jsx)(s.strong,{children:"expired"})," session → attempts ",(0,i.jsx)(s.code,{children:"Refreshing"}),"; if it\ncannot be renewed (or there is no refresh token) the store is cleared and it\nlands on ",(0,i.jsx)(s.code,{children:"Unauthenticated"}),". ",(0,i.jsx)(s.code,{children:"restore(refreshIfExpired: false)"})," restores it\nverbatim instead."]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:["A failed ",(0,i.jsx)(s.code,{children:"login"}),"/",(0,i.jsx)(s.code,{children:"register"})," → ",(0,i.jsx)(s.code,{children:"AuthError"}),", and the future rethrows."]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:["A failed ",(0,i.jsx)(s.code,{children:"refresh"})," → ",(0,i.jsx)(s.code,{children:"AuthError"}),", followed by ",(0,i.jsx)(s.code,{children:"Unauthenticated"})," when the\n",(0,i.jsx)(s.a,{href:"#refresh-failure-policy",children:"failure policy"})," considers the grant unrecoverable,\nor by ",(0,i.jsx)(s.code,{children:"Authenticated"})," (previous session) when it looks transient."]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsx)(s.p,{children:"Duplicate consecutive emissions are suppressed, so listeners only rebuild on a\nreal change."}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"restore()"})," 恢复未过期会话 → ",(0,i.jsx)(s.code,{children:"Authenticated"}),"。"]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"restore()"})," 恢复",(0,i.jsx)(s.strong,{children:"已过期"}),"会话 → 先走 ",(0,i.jsx)(s.code,{children:"Refreshing"}),";若无法续期(或没有刷新令牌),\n则清空存储并落到 ",(0,i.jsx)(s.code,{children:"Unauthenticated"}),"。",(0,i.jsx)(s.code,{children:"restore(refreshIfExpired: false)"})," 则原样恢复。"]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"login"}),"/",(0,i.jsx)(s.code,{children:"register"})," 失败 → ",(0,i.jsx)(s.code,{children:"AuthError"}),",同时 future 再次抛出错误。"]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"refresh"})," 失败 → ",(0,i.jsx)(s.code,{children:"AuthError"}),";随后由",(0,i.jsx)(s.a,{href:"#refresh-failure-policy",children:"失败策略"}),"决定:\n认为授权不可恢复则转 ",(0,i.jsx)(s.code,{children:"Unauthenticated"}),",认为只是瞬时故障则回到 ",(0,i.jsx)(s.code,{children:"Authenticated"}),"。"]}),"\n"]}),"\n",(0,i.jsxs)(s.li,{children:["\n",(0,i.jsx)(s.p,{children:"连续重复的状态会被抑制,监听器只会在真正变化时重建。"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(s.h2,{id:n[3].id,children:n[3].value}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.a,{href:"Usage",children:"Usage"})," — How to drive the UI from the stream / 如何用状态流驱动界面"]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — What each operation calls / 各操作调用什么"]}),"\n"]})]})},"/Auth-State-Machine",{filePath:"pages/Auth-State-Machine.md",timestamp:178966094e4,pageMap:r.v,frontMatter:{},title:"Auth State Machine / 认证状态机"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)},7080:function(e,n,s){"use strict";s.d(n,{v:function(){return i}});let i=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=4778)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Backend-Strategy-68c4f189b6536e77.js b/docs/_next/static/chunks/pages/Backend-Strategy-68c4f189b6536e77.js
new file mode 100644
index 0000000..f7430dc
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Backend-Strategy-68c4f189b6536e77.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[19],{1199:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Backend-Strategy",function(){return e(18)}])},18:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var n=e(5893),h=e(7812),r=e(7080),t=e(8925);function l(i){return[{value:"The contract / 契约",id:"the-contract--契约",depth:2},{value:"Mapping failures / 映射失败",id:"mapping-failures--映射失败",depth:2},{value:"Building the session / 构造会话",id:"building-the-session--构造会话",depth:2},{value:"Example backend / 演示后端",id:"example-backend--演示后端",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Backend Strategy / 后端策略"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," is the ",(0,n.jsx)(e.strong,{children:"only"})," boundary the core needs from a backend. Implement four methods and ",(0,n.jsx)(e.code,{children:"zero_auth"})," works with REST, gRPC, Firebase, or a private RPC."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," 是内核向后台要求的",(0,n.jsx)(e.strong,{children:"唯一"}),"边界。实现四个方法后,",(0,n.jsx)(e.code,{children:"zero_auth"})," 即可对接 REST、gRPC、Firebase 或私有 RPC。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"abstract"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"register"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"logout"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"refresh"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session);"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Method"}),(0,n.jsx)(e.th,{children:"When called"}),(0,n.jsx)(e.th,{children:"Must return"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"login"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"AuthManager.login"})}),(0,n.jsxs)(e.td,{children:["A fresh ",(0,n.jsx)(e.code,{children:"AuthSession"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"register"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"AuthManager.register"})}),(0,n.jsxs)(e.td,{children:["A fresh ",(0,n.jsx)(e.code,{children:"AuthSession"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"logout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"AuthManager.logout"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"void"})," (revoke server-side if applicable)"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"refresh"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"AuthManager.refresh"})}),(0,n.jsxs)(e.td,{children:["A new ",(0,n.jsx)(e.code,{children:"AuthSession"})," (new tokens)"]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:["Every thrown error should be mapped to ",(0,n.jsx)(e.code,{children:"AppException"})," (or ",(0,n.jsx)(e.code,{children:"AuthException"})," for auth-specific cases). Raw ",(0,n.jsx)(e.code,{children:"Exception"}),"s must never cross the public surface — the manager wraps unknowns."]}),"\n",(0,n.jsxs)(e.p,{children:["所有抛出的错误都应映射为 ",(0,n.jsx)(e.code,{children:"AppException"}),"(认证相关场景用 ",(0,n.jsx)(e.code,{children:"AuthException"}),")。裸 ",(0,n.jsx)(e.code,{children:"Exception"})," 不得越过公共边界——管理器会包裹未知异常。"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" u, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" p) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" try"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"post"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'/login'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", {"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'u'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" u, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'p'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" p});"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromJson"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" } "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"on"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyApiAuthError"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" catch"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (e) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" throw"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(code"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'invalid_credentials'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", message"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" e.message);"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsxs)(e.p,{children:["Return an ",(0,n.jsx)(e.code,{children:"AuthSession"})," carrying at least the access token, the refresh token, and an expiry:"]}),"\n",(0,n.jsxs)(e.p,{children:["返回 ",(0,n.jsx)(e.code,{children:"AuthSession"}),",至少包含访问令牌、刷新令牌与过期时间:"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" accessToken"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'access'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" refreshToken"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'refresh'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" expiresAt"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" DateTime"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"parse"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'expiresAt'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"]),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" userId"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'userId'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" displayName"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'displayName'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" claims"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// optional raw claims / 可选的原始 claims"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"server/"})," is a zero-dependency ",(0,n.jsx)(e.code,{children:"dart:io"})," demo backend exercising ",(0,n.jsx)(e.code,{children:"/login"}),", ",(0,n.jsx)(e.code,{children:"/refresh"}),", ",(0,n.jsx)(e.code,{children:"/logout"})," and ",(0,n.jsx)(e.code,{children:"/me"}),". Run it with ",(0,n.jsx)(e.code,{children:"dart run bin/server.dart"})," on port ",(0,n.jsx)(e.code,{children:"8080"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"server/"})," 是一个零依赖的 ",(0,n.jsx)(e.code,{children:"dart:io"})," 演示后端,提供 ",(0,n.jsx)(e.code,{children:"/login"}),"、",(0,n.jsx)(e.code,{children:"/refresh"}),"、",(0,n.jsx)(e.code,{children:"/logout"})," 与 ",(0,n.jsx)(e.code,{children:"/me"}),"。用 ",(0,n.jsx)(e.code,{children:"dart run bin/server.dart"})," 在 ",(0,n.jsx)(e.code,{children:"8080"})," 端口启动。"]}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Token-Store",children:"Token Store"})," — Where sessions are persisted / 会话持久化到何处"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Network-Integration",children:"Network Integration"})," — Attaching the bearer token / 附加 Bearer 令牌"]}),"\n"]})]})},"/Backend-Strategy",{filePath:"pages/Backend-Strategy.md",timestamp:1789598212e3,pageMap:r.v,frontMatter:{},title:"Backend Strategy / 后端策略"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=1199)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Backend-Strategy-ccb76f118248a4ea.js b/docs/_next/static/chunks/pages/Backend-Strategy-ccb76f118248a4ea.js
deleted file mode 100644
index 439ab5a..0000000
--- a/docs/_next/static/chunks/pages/Backend-Strategy-ccb76f118248a4ea.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[19],{1199:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Backend-Strategy",function(){return e(18)}])},18:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var h=e(5893),n=e(7812),r=e(7080),t=e(8925);function l(i){return[{value:"The contract / 契约",id:"the-contract--契约",depth:2},{value:"Mapping failures / 映射失败",id:"mapping-failures--映射失败",depth:2},{value:"Building the session / 构造会话",id:"building-the-session--构造会话",depth:2},{value:"Example backend / 演示后端",id:"example-backend--演示后端",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Backend Strategy / 后端策略"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"AuthStrategy"})," is the ",(0,h.jsx)(e.strong,{children:"only"})," boundary the core needs from a backend. Implement four methods and ",(0,h.jsx)(e.code,{children:"zero_auth"})," works with REST, gRPC, Firebase, or a private RPC."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"AuthStrategy"})," 是内核向后台要求的",(0,h.jsx)(e.strong,{children:"唯一"}),"边界。实现四个方法后,",(0,h.jsx)(e.code,{children:"zero_auth"})," 即可对接 REST、gRPC、Firebase 或私有 RPC。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"abstract"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthStrategy"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"register"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"logout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"refresh"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session);"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Method"}),(0,h.jsx)(e.th,{children:"When called"}),(0,h.jsx)(e.th,{children:"Must return"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"login"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"AuthManager.login"})}),(0,h.jsxs)(e.td,{children:["A fresh ",(0,h.jsx)(e.code,{children:"AuthSession"})]})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"register"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"AuthManager.register"})}),(0,h.jsxs)(e.td,{children:["A fresh ",(0,h.jsx)(e.code,{children:"AuthSession"})]})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"logout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"AuthManager.logout"})}),(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"void"})," (revoke server-side if applicable)"]})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"refresh"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"AuthManager.refresh"})}),(0,h.jsxs)(e.td,{children:["A new ",(0,h.jsx)(e.code,{children:"AuthSession"})," (new tokens)"]})]})]})]}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsxs)(e.p,{children:["Every thrown error should be mapped to ",(0,h.jsx)(e.code,{children:"AppException"})," (or ",(0,h.jsx)(e.code,{children:"AuthException"})," for auth-specific cases). Raw ",(0,h.jsx)(e.code,{children:"Exception"}),"s must never cross the public surface — the manager wraps unknowns."]}),"\n",(0,h.jsxs)(e.p,{children:["所有抛出的错误都应映射为 ",(0,h.jsx)(e.code,{children:"AppException"}),"(认证相关场景用 ",(0,h.jsx)(e.code,{children:"AuthException"}),")。裸 ",(0,h.jsx)(e.code,{children:"Exception"})," 不得越过公共边界——管理器会包裹未知异常。"]}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" u, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" p) "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" try"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"post"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'/login'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", {"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'u'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" u, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'p'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" p});"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromJson"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" } "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"on"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyApiAuthError"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" catch"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (e) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" throw"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(code"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'invalid_credentials'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", message"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" e.message);"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,h.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,h.jsxs)(e.p,{children:["Return an ",(0,h.jsx)(e.code,{children:"AuthSession"})," carrying at least the access token, the refresh token, and an expiry:"]}),"\n",(0,h.jsxs)(e.p,{children:["返回 ",(0,h.jsx)(e.code,{children:"AuthSession"}),",至少包含访问令牌、刷新令牌与过期时间:"]}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" accessToken"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'access'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" refreshToken"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'refresh'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" expiresAt"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" DateTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"parse"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'expiresAt'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"]),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" userId"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'userId'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" displayName"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'displayName'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" claims"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// optional raw claims / 可选的原始 claims"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")"})})]})}),"\n",(0,h.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"server/"})," is a zero-dependency ",(0,h.jsx)(e.code,{children:"dart:io"})," demo backend exercising ",(0,h.jsx)(e.code,{children:"/login"}),", ",(0,h.jsx)(e.code,{children:"/refresh"}),", ",(0,h.jsx)(e.code,{children:"/logout"})," and ",(0,h.jsx)(e.code,{children:"/me"}),". Run it with ",(0,h.jsx)(e.code,{children:"dart run bin/server.dart"})," on port ",(0,h.jsx)(e.code,{children:"8080"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"server/"})," 是一个零依赖的 ",(0,h.jsx)(e.code,{children:"dart:io"})," 演示后端,提供 ",(0,h.jsx)(e.code,{children:"/login"}),"、",(0,h.jsx)(e.code,{children:"/refresh"}),"、",(0,h.jsx)(e.code,{children:"/logout"})," 与 ",(0,h.jsx)(e.code,{children:"/me"}),"。用 ",(0,h.jsx)(e.code,{children:"dart run bin/server.dart"})," 在 ",(0,h.jsx)(e.code,{children:"8080"})," 端口启动。"]}),"\n",(0,h.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,h.jsxs)(e.ul,{children:["\n",(0,h.jsxs)(e.li,{children:[(0,h.jsx)(e.a,{href:"Token-Store",children:"Token Store"})," — Where sessions are persisted / 会话持久化到何处"]}),"\n",(0,h.jsxs)(e.li,{children:[(0,h.jsx)(e.a,{href:"Network-Integration",children:"Network Integration"})," — Attaching the bearer token / 附加 Bearer 令牌"]}),"\n"]})]})},"/Backend-Strategy",{filePath:"pages/Backend-Strategy.md",pageMap:r.v,frontMatter:{},title:"Backend Strategy / 后端策略"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=1199)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Configuration-0a11f8b0ddbb5cde.js b/docs/_next/static/chunks/pages/Configuration-0a11f8b0ddbb5cde.js
deleted file mode 100644
index 9555ec8..0000000
--- a/docs/_next/static/chunks/pages/Configuration-0a11f8b0ddbb5cde.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[717],{9321:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Configuration",function(){return t(3223)}])},3223:function(e,n,t){"use strict";t.r(n),t.d(n,{useTOC:function(){return d}});var r=t(5893),i=t(7812),s=t(7080),a=t(8925);function d(e){let n={code:"code",...(0,a.a)()};return[{value:(0,r.jsxs)(r.Fragment,{children:["Composing ",(0,r.jsx)(n.code,{children:"AuthManager"})," / 组合管理器"]}),id:"composing-authmanager--组合管理器",depth:2},{value:"Refresh strategy / 刷新策略",id:"refresh-strategy--刷新策略",depth:2},{value:"No global singletons / 没有全局单例",id:"no-global-singletons--没有全局单例",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}n.default=(0,i.c)(function(e){let{toc:n=d(e)}=e,t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{children:"Configuration / 配置"}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"zero_auth"})," is deliberately minimal: there is no global config object. Behavior is composed from the two boundaries you pass to ",(0,r.jsx)(t.code,{children:"AuthManager"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"zero_auth"})," 刻意保持精简:没有全局配置对象。行为由你传给 ",(0,r.jsx)(t.code,{children:"AuthManager"})," 的两个边界组合而成。"]}),"\n",(0,r.jsx)(t.h2,{id:n[0].id,children:n[0].value}),"\n",(0,r.jsx)(t.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,r.jsxs)(t.code,{children:[(0,r.jsxs)(t.span,{children:[(0,r.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,r.jsxs)(t.span,{children:[(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// how to talk to the backend / 如何与后端通信"})]}),"\n",(0,r.jsxs)(t.span,{children:[(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SecureTokenStore"}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,r.jsx)(t.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// where to persist tokens / 令牌持久化位置"})]}),"\n",(0,r.jsx)(t.span,{children:(0,r.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Knob"}),(0,r.jsx)(t.th,{children:"Where"}),(0,r.jsx)(t.th,{children:"Effect"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Backend endpoints & auth scheme"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"AuthStrategy"})}),(0,r.jsxs)(t.td,{children:["What ",(0,r.jsx)(t.code,{children:"login"}),"/",(0,r.jsx)(t.code,{children:"refresh"}),"/… actually do / ",(0,r.jsx)(t.code,{children:"login"}),"/",(0,r.jsx)(t.code,{children:"refresh"})," 等的实际行为"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Token persistence"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"TokenStore"})}),(0,r.jsx)(t.td,{children:"Disk / secure storage / in-memory / 磁盘/安全存储/内存"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Refresh timing"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"AuthSession.expiresAt"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"isExpired"})," drives proactive refresh / 由 ",(0,r.jsx)(t.code,{children:"isExpired"})," 驱动主动刷新"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Token injection"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"AuthTokenSource"})}),(0,r.jsx)(t.td,{children:"How the bearer token reaches HTTP clients / 令牌如何到达 HTTP 客户端"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[1].id,children:n[1].value}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"refresh()"})," is ",(0,r.jsx)(t.strong,{children:"single-flight"})," by construction: concurrent callers share one in-flight request. You decide ",(0,r.jsx)(t.em,{children:"when"})," to refresh:"]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"refresh()"})," 天生",(0,r.jsx)(t.strong,{children:"单飞"}),":并发调用方共享同一次进行中的请求。",(0,r.jsx)(t.em,{children:"何时"}),"刷新由你决定:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Proactively, when ",(0,r.jsx)(t.code,{children:"session.isExpired"})," is approaching, before a request. / 在请求前、当 ",(0,r.jsx)(t.code,{children:"session.isExpired"})," 临近时主动刷新。"]}),"\n",(0,r.jsxs)(t.li,{children:["Reactively, on a ",(0,r.jsx)(t.code,{children:"401"})," from your API (see ",(0,r.jsx)(t.a,{href:"Network-Integration",children:"Network Integration"}),"). / 响应式地,在 API 返回 ",(0,r.jsx)(t.code,{children:"401"})," 时刷新。"]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["A failed refresh clears the session and emits ",(0,r.jsx)(t.code,{children:"AuthError"}),"; your app should route the user back to login."]}),"\n",(0,r.jsxs)(t.p,{children:["刷新失败会清空会话并发出 ",(0,r.jsx)(t.code,{children:"AuthError"}),",应用应将用户引导回登录。"]}),"\n",(0,r.jsx)(t.h2,{id:n[2].id,children:n[2].value}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"AuthManager"})," is a plain object — create one per app, hold it in your DI container or a top-level variable. The core has no static mutable state."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"AuthManager"})," 是一个普通对象——每个应用创建一个,放在 DI 容器或顶层变量中即可。内核没有静态可变状态。"]}),"\n",(0,r.jsx)(t.h2,{id:n[3].id,children:n[3].value}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"Usage",children:"Usage"})," — Putting it together / 综合使用"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"FAQ",children:"FAQ"})," — Common questions / 常见问题"]}),"\n"]})]})},"/Configuration",{filePath:"pages/Configuration.md",pageMap:s.v,frontMatter:{},title:"Configuration / 配置"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,n,t){"use strict";t.d(n,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9321)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Configuration-c14db61163f267c4.js b/docs/_next/static/chunks/pages/Configuration-c14db61163f267c4.js
new file mode 100644
index 0000000..973d1d0
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Configuration-c14db61163f267c4.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[717],{9321:function(e,i,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Configuration",function(){return s(3223)}])},3223:function(e,i,s){"use strict";s.r(i),s.d(i,{useTOC:function(){return l}});var n=s(5893),r=s(7812),t=s(7080),h=s(8925);function l(e){let i={code:"code",...(0,h.a)()};return[{value:(0,n.jsxs)(n.Fragment,{children:["Composing ",(0,n.jsx)(i.code,{children:"AuthManager"})," / 组合管理器"]}),id:"composing-authmanager--组合管理器",depth:2},{value:"Refresh strategy / 刷新策略",id:"refresh-strategy--刷新策略",depth:2},{value:"Refresh failure policy / 刷新失败策略",id:"refresh-failure-policy--刷新失败策略",depth:2},{value:"No global singletons / 没有全局单例",id:"no-global-singletons--没有全局单例",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}i.default=(0,r.c)(function(e){let{toc:i=l(e)}=e,s={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,h.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Configuration / 配置"}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_auth"})," is deliberately minimal: there is no global config object. Behavior is composed from the two boundaries you pass to ",(0,n.jsx)(s.code,{children:"AuthManager"}),"."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_auth"})," 刻意保持精简:没有全局配置对象。行为由你传给 ",(0,n.jsx)(s.code,{children:"AuthManager"})," 的两个边界组合而成。"]}),"\n",(0,n.jsx)(s.h2,{id:i[0].id,children:i[0].value}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// how to talk to the backend / 如何与后端通信"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SecureTokenStore"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// where to persist tokens / 令牌持久化位置"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" autoRefreshAhead"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(minutes"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// proactive renewal / 主动续期"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" refreshFailurePolicy"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" defaultRefreshFailurePolicy, "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// sign-out rule / 登出规则"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" clock"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" () "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" DateTime"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"now"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// time source (tests, skew) / 时间源(测试、时钟偏移)"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Knob"}),(0,n.jsx)(s.th,{children:"Where"}),(0,n.jsx)(s.th,{children:"Effect"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Backend endpoints & auth scheme"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"AuthStrategy"})}),(0,n.jsxs)(s.td,{children:["What ",(0,n.jsx)(s.code,{children:"login"}),"/",(0,n.jsx)(s.code,{children:"refresh"}),"/… actually do / ",(0,n.jsx)(s.code,{children:"login"}),"/",(0,n.jsx)(s.code,{children:"refresh"})," 等的实际行为"]})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Token persistence"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"TokenStore"})}),(0,n.jsx)(s.td,{children:"Disk / secure storage / in-memory / 磁盘/安全存储/内存"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Refresh timing"}),(0,n.jsxs)(s.td,{children:[(0,n.jsx)(s.code,{children:"AuthSession.expiresAt"})," + ",(0,n.jsx)(s.code,{children:"autoRefreshAhead"})]}),(0,n.jsx)(s.td,{children:"Proactive renewal is scheduled that far before expiry / 在过期前该时长调度主动续期"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Refresh failure handling"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"refreshFailurePolicy"})}),(0,n.jsx)(s.td,{children:"Whether a failed refresh signs the user out / 刷新失败是否让用户登出"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Time source"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"clock"})}),(0,n.jsx)(s.td,{children:"Drives expiry maths and proactive scheduling; inject one for deterministic tests or to tolerate device clock skew / 驱动过期计算与主动刷新调度;注入时钟可实现确定性测试或容忍设备时钟偏移"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Token injection"}),(0,n.jsxs)(s.td,{children:[(0,n.jsx)(s.code,{children:"AuthTokenSource"})," / ",(0,n.jsx)(s.code,{children:"validAccessToken()"})]}),(0,n.jsx)(s.td,{children:"How the bearer token reaches HTTP clients, optionally renewing an expired token first / 令牌如何到达 HTTP 客户端,必要时先续期过期令牌"})]})]})]}),"\n",(0,n.jsx)(s.h2,{id:i[1].id,children:i[1].value}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"refresh()"})," is ",(0,n.jsx)(s.strong,{children:"single-flight"})," by construction: concurrent callers share one in-flight request. You decide ",(0,n.jsx)(s.em,{children:"when"})," to refresh:"]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"refresh()"})," 天生",(0,n.jsx)(s.strong,{children:"单飞"}),":并发调用方共享同一次进行中的请求。",(0,n.jsx)(s.em,{children:"何时"}),"刷新由你决定:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:["Proactively, when ",(0,n.jsx)(s.code,{children:"session.isExpired"})," is approaching, before a request. / 在请求前、当 ",(0,n.jsx)(s.code,{children:"session.isExpired"})," 临近时主动刷新。"]}),"\n",(0,n.jsxs)(s.li,{children:["Reactively, on a ",(0,n.jsx)(s.code,{children:"401"})," from your API (see ",(0,n.jsx)(s.a,{href:"Network-Integration",children:"Network Integration"}),"). / 响应式地,在 API 返回 ",(0,n.jsx)(s.code,{children:"401"})," 时刷新。"]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["A failed refresh is always reported through ",(0,n.jsx)(s.code,{children:"AuthError"})," (and the rethrown future),\nbut whether it ",(0,n.jsx)(s.strong,{children:"ends the session"})," is decided by ",(0,n.jsx)(s.code,{children:"refreshFailurePolicy"}),". See\n",(0,n.jsx)(s.strong,{children:"Refresh failure policy"})," below."]}),"\n",(0,n.jsxs)(s.p,{children:["刷新失败总会通过 ",(0,n.jsx)(s.code,{children:"AuthError"}),"(以及重新抛出的 future)上报,但是否",(0,n.jsx)(s.strong,{children:"终止会话"}),"由\n",(0,n.jsx)(s.code,{children:"refreshFailurePolicy"})," 决定,详见下方「刷新失败策略」。"]}),"\n",(0,n.jsx)(s.h2,{id:i[2].id,children:i[2].value}),"\n",(0,n.jsx)(s.p,{children:"The default policy signs the user out only for failures that can never succeed\nagain, keeping the session when the failure looks transient (so a network blip\ndoes not log people out):"}),"\n",(0,n.jsx)(s.p,{children:"默认策略仅在失败「注定无法重试成功」时让用户登出;看起来像瞬时故障时保留会话(避免一次\n网络抖动就把人踢下线):"}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Failure / 失败类型"}),(0,n.jsx)(s.th,{children:"Default outcome / 默认结果"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:[(0,n.jsx)(s.code,{children:"SessionExpiredException"}),", ",(0,n.jsx)(s.code,{children:"InvalidCredentialsException"})]}),(0,n.jsxs)(s.td,{children:["Store cleared → ",(0,n.jsx)(s.code,{children:"Unauthenticated"})," / 清空存储 → ",(0,n.jsx)(s.code,{children:"Unauthenticated"})]})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Anything else (network, 5xx…) / 其它(网络、5xx 等)"}),(0,n.jsxs)(s.td,{children:["Session kept → back to ",(0,n.jsx)(s.code,{children:"Authenticated"})," / 保留会话 → 回到 ",(0,n.jsx)(s.code,{children:"Authenticated"})]})]})]})]}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Never sign out on a failed refresh — useful when refresh tokens are"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// long-lived and your backend is occasionally flaky."})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 刷新失败也绝不登出——适用于刷新令牌长期有效、后端偶尔不稳定的场景。"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy,"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" refreshFailurePolicy"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AppException"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error) "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,n.jsx)(s.p,{children:"Proactive (background) refresh failures are handled internally, so a scheduled\nrenewal can never surface as an unhandled async error."}),"\n",(0,n.jsx)(s.p,{children:"主动(后台)刷新的失败会在内部处理,因此定时续期永远不会以未处理异步错误的形式泄漏。"}),"\n",(0,n.jsx)(s.h2,{id:i[3].id,children:i[3].value}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"AuthManager"})," is a plain object — create one per app, hold it in your DI container or a top-level variable. The core has no static mutable state."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"AuthManager"})," 是一个普通对象——每个应用创建一个,放在 DI 容器或顶层变量中即可。内核没有静态可变状态。"]}),"\n",(0,n.jsx)(s.h2,{id:i[4].id,children:i[4].value}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Usage",children:"Usage"})," — Putting it together / 综合使用"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"FAQ",children:"FAQ"})," — Common questions / 常见问题"]}),"\n"]})]})},"/Configuration",{filePath:"pages/Configuration.md",timestamp:178966094e4,pageMap:t.v,frontMatter:{},title:"Configuration / 配置"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,i,s){"use strict";s.d(i,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9321)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Errors-4c6a1995069645ad.js b/docs/_next/static/chunks/pages/Errors-6d95421b1599c81e.js
similarity index 54%
rename from docs/_next/static/chunks/pages/Errors-4c6a1995069645ad.js
rename to docs/_next/static/chunks/pages/Errors-6d95421b1599c81e.js
index 223e5d1..f5be0e7 100644
--- a/docs/_next/static/chunks/pages/Errors-4c6a1995069645ad.js
+++ b/docs/_next/static/chunks/pages/Errors-6d95421b1599c81e.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[302],{7031:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Errors",function(){return e(1824)}])},1824:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var n=e(5893),r=e(7812),t=e(7080),h=e(8925);function l(i){let s={code:"code",...(0,h.a)()};return[{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.code,{children:"AppException"})," / 异常类型"]}),id:"appexception--异常类型",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.code,{children:"Result"})," / 结果类型"]}),id:"resultt--结果类型",depth:2},{value:"How failures surface / 失败如何呈现",id:"how-failures-surface--失败如何呈现",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,r.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,h.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Errors / 错误"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," never lets a raw ",(0,n.jsx)(e.code,{children:"Exception"})," cross its public surface. Every failure is expressed through one of two mechanisms."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," 绝不允许裸 ",(0,n.jsx)(e.code,{children:"Exception"})," 越过公共边界。每个失败都通过下面两种机制之一表达。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsxs)(e.p,{children:["All domain failures extend ",(0,n.jsx)(e.code,{children:"AppException"}),":"]}),"\n",(0,n.jsxs)(e.p,{children:["所有领域失败都继承 ",(0,n.jsx)(e.code,{children:"AppException"}),":"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"sealed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AppException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" implements"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Exception"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" code; "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// stable, machine-readable / 稳定、机器可读"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" message; "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// human-readable / 人类可读"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Object"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" cause; "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// original error, if any / 原始错误"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AppException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // auth-specific cases: invalid_credentials, session_expired, …"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 认证相关场景:invalid_credentials、session_expired 等"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," implementations should map transport/API errors into ",(0,n.jsx)(e.code,{children:"AuthException"})," (or a custom ",(0,n.jsx)(e.code,{children:"AppException"})," subclass) so callers get a stable ",(0,n.jsx)(e.code,{children:"code"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," 实现方应将传输层/API 错误映射为 ",(0,n.jsx)(e.code,{children:"AuthException"}),"(或自定义 ",(0,n.jsx)(e.code,{children:"AppException"})," 子类),让调用方拿到稳定的 ",(0,n.jsx)(e.code,{children:"code"}),"。"]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:["For explicit, exception-free handling, use ",(0,n.jsx)(e.code,{children:"Result"}),":"]}),"\n",(0,n.jsxs)(e.p,{children:["如需显式、无异常的处理,可使用 ",(0,n.jsx)(e.code,{children:"Result"}),":"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"sealed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Result"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" factory"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Result"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"ok"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" value) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Ok"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">;"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" factory"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Result"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"err"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AppException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Err"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">;"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"tryLogin"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(user, pass); "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// returns Result"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"switch"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (result) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Ok"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" value)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* authenticated / 已认证 */"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Err"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* inspect error.code / 读取 error.code */"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Situation"}),(0,n.jsx)(e.th,{children:"Surfaced as"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"login"}),"/",(0,n.jsx)(e.code,{children:"register"})," fails"]}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"AuthState"})," becomes ",(0,n.jsx)(e.code,{children:"AuthError(error)"})," ",(0,n.jsx)(e.strong,{children:"and"})," the future throws ",(0,n.jsx)(e.code,{children:"AppException"})," / 状态变为 ",(0,n.jsx)(e.code,{children:"AuthError"}),",且 future 抛出 ",(0,n.jsx)(e.code,{children:"AppException"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"refresh"})," fails"]}),(0,n.jsxs)(e.td,{children:["Session cleared; ",(0,n.jsx)(e.code,{children:"AuthError(error)"})," emitted / 会话清空,发出 ",(0,n.jsx)(e.code,{children:"AuthError"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"restore()"})," finds nothing"]}),(0,n.jsxs)(e.td,{children:["Stays ",(0,n.jsx)(e.code,{children:"Unauthenticated"})," (not an error) / 保持 ",(0,n.jsx)(e.code,{children:"Unauthenticated"}),"(不算错误)"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"TokenStore.load()"})," throws"]}),(0,n.jsxs)(e.td,{children:["Mapped to ",(0,n.jsx)(e.code,{children:"AppException"}),", treated as “no session” / 映射为 ",(0,n.jsx)(e.code,{children:"AppException"}),",按”无会话”处理"]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — Map your API errors / 映射你的 API 错误"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Configuration",children:"Configuration"})," — Tuning refresh & retry / 调优刷新与重试"]}),"\n"]})]})},"/Errors",{filePath:"pages/Errors.md",pageMap:t.v,frontMatter:{},title:"Errors / 错误"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=7031)}),_N_E=i.O()}]);
\ No newline at end of file
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[302],{7031:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Errors",function(){return e(1824)}])},1824:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var n=e(5893),h=e(7812),r=e(7080),t=e(8925);function l(i){let s={code:"code",...(0,t.a)()};return[{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.code,{children:"AppException"})," / 异常类型"]}),id:"appexception--异常类型",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.code,{children:"Result"})," / 结果类型"]}),id:"resultt--结果类型",depth:2},{value:"How failures surface / 失败如何呈现",id:"how-failures-surface--失败如何呈现",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Errors / 错误"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," never lets a raw ",(0,n.jsx)(e.code,{children:"Exception"})," cross its public surface. Every failure is expressed through one of two mechanisms."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," 绝不允许裸 ",(0,n.jsx)(e.code,{children:"Exception"})," 越过公共边界。每个失败都通过下面两种机制之一表达。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsxs)(e.p,{children:["All domain failures extend ",(0,n.jsx)(e.code,{children:"AppException"}),":"]}),"\n",(0,n.jsxs)(e.p,{children:["所有领域失败都继承 ",(0,n.jsx)(e.code,{children:"AppException"}),":"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"sealed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AppException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" implements"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Exception"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" code; "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// stable, machine-readable / 稳定、机器可读"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" message; "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// human-readable / 人类可读"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Object"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" cause; "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// original error, if any / 原始错误"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AppException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // Base type for every auth failure / 所有认证失败的基类型"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Concrete subtypes — catch these to branch on what actually went wrong."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 具体子类型——捕获它们即可按实际错误分支处理。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InvalidCredentialsException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {} "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// invalid_credentials / 凭据无效"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SessionExpiredException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {} "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// session_expired / 会话过期"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NoActiveSessionException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {} "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// no_active_session / 无活动会话"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" RefreshTokenMissingException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {} "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// refresh_token_missing / 缺少刷新令牌"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" UnexpectedAuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {} "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// unexpected_auth_failure / 意外失败"})]})]})}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," authors opt into these subtypes simply by throwing an\n",(0,n.jsx)(e.code,{children:"AuthException"})," carrying the matching ",(0,n.jsx)(e.code,{children:"code"}),"; ",(0,n.jsx)(e.code,{children:"mapAuthFailure"})," performs the\nmapping, preserving any vocabulary it does not recognise."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," 实现者只需抛出携带对应 ",(0,n.jsx)(e.code,{children:"code"})," 的 ",(0,n.jsx)(e.code,{children:"AuthException"})," 即可参与映射;\n",(0,n.jsx)(e.code,{children:"mapAuthFailure"})," 负责转换,并保留它无法识别的自定义错误类型。"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"code"}),(0,n.jsx)(e.th,{children:"Mapped type / 映射结果"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"invalid_credentials"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"InvalidCredentialsException"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"invalid_grant"}),", ",(0,n.jsx)(e.code,{children:"invalid_refresh_token"}),", ",(0,n.jsx)(e.code,{children:"token_expired"}),", ",(0,n.jsx)(e.code,{children:"session_expired"})]}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SessionExpiredException"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"no_active_session"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NoActiveSessionException"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"refresh_token_missing"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"RefreshTokenMissingException"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"anything else / 其它"}),(0,n.jsxs)(e.td,{children:["preserved as-is, or ",(0,n.jsx)(e.code,{children:"UnexpectedAuthException"})," / 原样保留或包装为 ",(0,n.jsx)(e.code,{children:"UnexpectedAuthException"})]})]})]})]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," implementations should map transport/API errors into ",(0,n.jsx)(e.code,{children:"AuthException"})," (or a custom ",(0,n.jsx)(e.code,{children:"AppException"})," subclass) so callers get a stable ",(0,n.jsx)(e.code,{children:"code"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthStrategy"})," 实现方应将传输层/API 错误映射为 ",(0,n.jsx)(e.code,{children:"AuthException"}),"(或自定义 ",(0,n.jsx)(e.code,{children:"AppException"})," 子类),让调用方拿到稳定的 ",(0,n.jsx)(e.code,{children:"code"}),"。"]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:["For explicit, exception-free handling, use ",(0,n.jsx)(e.code,{children:"Result"}),":"]}),"\n",(0,n.jsxs)(e.p,{children:["如需显式、无异常的处理,可使用 ",(0,n.jsx)(e.code,{children:"Result"}),":"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"sealed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Result"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" factory"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Result"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"ok"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" value) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Ok"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">;"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" factory"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Result"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"err"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AppException"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Err"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"T"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">;"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"tryLogin"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(user, pass); "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// returns Result"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"switch"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (result) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Ok"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" value)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* authenticated / 已认证 */"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Err"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" /* inspect error.code / 读取 error.code */"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Situation"}),(0,n.jsx)(e.th,{children:"Surfaced as"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"login"}),"/",(0,n.jsx)(e.code,{children:"register"})," fails"]}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"AuthState"})," becomes ",(0,n.jsx)(e.code,{children:"AuthError(error)"})," ",(0,n.jsx)(e.strong,{children:"and"})," the future throws ",(0,n.jsx)(e.code,{children:"AppException"})," / 状态变为 ",(0,n.jsx)(e.code,{children:"AuthError"}),",且 future 抛出 ",(0,n.jsx)(e.code,{children:"AppException"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"refresh"})," fails"]}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"AuthError(error)"})," emitted, then ",(0,n.jsx)(e.code,{children:"Unauthenticated"})," (unrecoverable) or back to ",(0,n.jsx)(e.code,{children:"Authenticated"})," (transient) per the ",(0,n.jsx)(e.a,{href:"Configuration#refresh-failure-policy",children:"failure policy"})," / 发出 ",(0,n.jsx)(e.code,{children:"AuthError"}),",随后按",(0,n.jsx)(e.a,{href:"Configuration#refresh-failure-policy",children:"失败策略"}),"转为 ",(0,n.jsx)(e.code,{children:"Unauthenticated"}),"(不可恢复)或回到 ",(0,n.jsx)(e.code,{children:"Authenticated"}),"(瞬时)"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"restore()"})," finds nothing"]}),(0,n.jsxs)(e.td,{children:["Stays ",(0,n.jsx)(e.code,{children:"Unauthenticated"})," (not an error) / 保持 ",(0,n.jsx)(e.code,{children:"Unauthenticated"}),"(不算错误)"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"TokenStore.load()"})," throws"]}),(0,n.jsxs)(e.td,{children:["Mapped to ",(0,n.jsx)(e.code,{children:"AppException"}),", treated as “no session” / 映射为 ",(0,n.jsx)(e.code,{children:"AppException"}),",按”无会话”处理"]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — Map your API errors / 映射你的 API 错误"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Configuration",children:"Configuration"})," — Tuning refresh & retry / 调优刷新与重试"]}),"\n"]})]})},"/Errors",{filePath:"pages/Errors.md",timestamp:178966094e4,pageMap:r.v,frontMatter:{},title:"Errors / 错误"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=7031)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/FAQ-3be268e4c7e2ac58.js b/docs/_next/static/chunks/pages/FAQ-63a2841fb00fcc12.js
similarity index 65%
rename from docs/_next/static/chunks/pages/FAQ-3be268e4c7e2ac58.js
rename to docs/_next/static/chunks/pages/FAQ-63a2841fb00fcc12.js
index 01856bf..1096edb 100644
--- a/docs/_next/static/chunks/pages/FAQ-3be268e4c7e2ac58.js
+++ b/docs/_next/static/chunks/pages/FAQ-63a2841fb00fcc12.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[210],{9238:function(e,t,r){(window.__NEXT_P=window.__NEXT_P||[]).push(["/FAQ",function(){return r(5797)}])},5797:function(e,t,r){"use strict";r.r(t),r.d(t,{useTOC:function(){return d}});var n=r(5893),o=r(7812),a=r(7080),i=r(8925);function d(e){let t={code:"code",...(0,i.a)()};return[{value:(0,n.jsxs)(n.Fragment,{children:["Does ",(0,n.jsx)(t.code,{children:"zero_auth"})," ship an HTTP client? / ",(0,n.jsx)(t.code,{children:"zero_auth"})," 内置 HTTP 客户端吗?"]}),id:"does-zero_auth-ship-an-http-client--zero_auth-内置-http-客户端吗",depth:3},{value:"Does it depend on Flutter? / 它依赖 Flutter 吗?",id:"does-it-depend-on-flutter--它依赖-flutter-吗",depth:3},{value:"Where are tokens stored? / 令牌存在哪里?",id:"where-are-tokens-stored--令牌存在哪里",depth:3},{value:"What happens on a failed refresh? / 刷新失败会怎样?",id:"what-happens-on-a-failed-refresh--刷新失败会怎样",depth:3},{value:"Is token refresh concurrent-safe? / 令牌刷新是否并发安全?",id:"is-token-refresh-concurrent-safe--令牌刷新是否并发安全",depth:3},{value:"How do I attach the bearer token to requests? / 如何给请求附加 Bearer 令牌?",id:"how-do-i-attach-the-bearer-token-to-requests--如何给请求附加-bearer-令牌",depth:3},{value:"Which platforms are supported? / 支持哪些平台?",id:"which-platforms-are-supported--支持哪些平台",depth:3}]}t.default=(0,o.c)(function(e){let{toc:t=d(e)}=e,r={code:"code",h1:"h1",h3:"h3",p:"p",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h1,{children:"FAQ / 常见问题"}),"\n",(0,n.jsx)(r.h3,{id:t[0].id,children:t[0].value}),"\n",(0,n.jsxs)(r.p,{children:["No. The core is backend-agnostic and ships no HTTP, SDK or native code. You implement ",(0,n.jsx)(r.code,{children:"AuthStrategy"})," to call your backend."]}),"\n",(0,n.jsxs)(r.p,{children:["不。内核后端无关,不含任何 HTTP、SDK 或原生代码。你通过实现 ",(0,n.jsx)(r.code,{children:"AuthStrategy"})," 来调用自己的后端。"]}),"\n",(0,n.jsx)(r.h3,{id:t[1].id,children:t[1].value}),"\n",(0,n.jsxs)(r.p,{children:["No. It is a pure-Dart package; ",(0,n.jsx)(r.code,{children:"flutter:"})," is only a declared constraint because the example app uses Flutter. The runtime has no Flutter dependency."]}),"\n",(0,n.jsxs)(r.p,{children:["不。它是纯 Dart 包;仅因示例 App 用到 Flutter 才声明 ",(0,n.jsx)(r.code,{children:"flutter:"})," 约束,运行时不依赖 Flutter。"]}),"\n",(0,n.jsx)(r.h3,{id:t[2].id,children:t[2].value}),"\n",(0,n.jsxs)(r.p,{children:["Wherever your ",(0,n.jsx)(r.code,{children:"TokenStore"})," puts them. The core ships ",(0,n.jsx)(r.code,{children:"InMemoryTokenStore"})," (lost on restart). For production, use the ",(0,n.jsx)(r.code,{children:"flutter_secure_storage"}),"-backed reference in ",(0,n.jsx)(r.code,{children:"example/lib/secure_token_store.dart"}),"."]}),"\n",(0,n.jsxs)(r.p,{children:["取决于你的 ",(0,n.jsx)(r.code,{children:"TokenStore"}),"。内核自带 ",(0,n.jsx)(r.code,{children:"InMemoryTokenStore"}),"(重启即丢失)。生产请用 ",(0,n.jsx)(r.code,{children:"example/lib/secure_token_store.dart"})," 中基于 ",(0,n.jsx)(r.code,{children:"flutter_secure_storage"})," 的参考实现。"]}),"\n",(0,n.jsx)(r.h3,{id:t[3].id,children:t[3].value}),"\n",(0,n.jsxs)(r.p,{children:["The session is cleared and ",(0,n.jsx)(r.code,{children:"AuthState"})," becomes ",(0,n.jsx)(r.code,{children:"AuthError"}),". Route the user back to login."]}),"\n",(0,n.jsxs)(r.p,{children:["会话被清空,",(0,n.jsx)(r.code,{children:"AuthState"})," 变为 ",(0,n.jsx)(r.code,{children:"AuthError"}),",应将用户引导回登录。"]}),"\n",(0,n.jsx)(r.h3,{id:t[4].id,children:t[4].value}),"\n",(0,n.jsxs)(r.p,{children:["Yes — ",(0,n.jsx)(r.code,{children:"refresh()"})," is single-flight: many concurrent callers share one in-flight request and its result."]}),"\n",(0,n.jsxs)(r.p,{children:["是的——",(0,n.jsx)(r.code,{children:"refresh()"})," 为单飞:多个并发调用方共享同一次请求及其结果。"]}),"\n",(0,n.jsx)(r.h3,{id:t[5].id,children:t[5].value}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"AuthManager"})," is an ",(0,n.jsx)(r.code,{children:"AuthTokenSource"}),". Use the Dio interceptor in ",(0,n.jsx)(r.code,{children:"example/lib/dio_interceptor.dart"}),", or read ",(0,n.jsx)(r.code,{children:"accessToken"})," directly."]}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"AuthManager"})," 即 ",(0,n.jsx)(r.code,{children:"AuthTokenSource"}),"。可用 ",(0,n.jsx)(r.code,{children:"example/lib/dio_interceptor.dart"})," 中的 Dio 拦截器,或直接读取 ",(0,n.jsx)(r.code,{children:"accessToken"}),"。"]}),"\n",(0,n.jsx)(r.h3,{id:t[6].id,children:t[6].value}),"\n",(0,n.jsx)(r.p,{children:"Any platform where Dart or Flutter runs (Android, iOS, Web, Windows, macOS, Linux)."}),"\n",(0,n.jsx)(r.p,{children:"任何能运行 Dart 或 Flutter 的平台(Android、iOS、Web、Windows、macOS、Linux)。"})]})},"/FAQ",{filePath:"pages/FAQ.md",pageMap:a.v,frontMatter:{},title:"FAQ / 常见问题"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,t,r){"use strict";r.d(t,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9238)}),_N_E=e.O()}]);
\ No newline at end of file
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[210],{9238:function(e,t,r){(window.__NEXT_P=window.__NEXT_P||[]).push(["/FAQ",function(){return r(5797)}])},5797:function(e,t,r){"use strict";r.r(t),r.d(t,{useTOC:function(){return s}});var n=r(5893),o=r(7812),i=r(7080),a=r(8925);function s(e){let t={code:"code",...(0,a.a)()};return[{value:(0,n.jsxs)(n.Fragment,{children:["Does ",(0,n.jsx)(t.code,{children:"zero_auth"})," ship an HTTP client? / ",(0,n.jsx)(t.code,{children:"zero_auth"})," 内置 HTTP 客户端吗?"]}),id:"does-zero_auth-ship-an-http-client--zero_auth-内置-http-客户端吗",depth:3},{value:"Does it depend on Flutter? / 它依赖 Flutter 吗?",id:"does-it-depend-on-flutter--它依赖-flutter-吗",depth:3},{value:"Where are tokens stored? / 令牌存在哪里?",id:"where-are-tokens-stored--令牌存在哪里",depth:3},{value:"What happens on a failed refresh? / 刷新失败会怎样?",id:"what-happens-on-a-failed-refresh--刷新失败会怎样",depth:3},{value:"Is token refresh concurrent-safe? / 令牌刷新是否并发安全?",id:"is-token-refresh-concurrent-safe--令牌刷新是否并发安全",depth:3},{value:"How do I attach the bearer token to requests? / 如何给请求附加 Bearer 令牌?",id:"how-do-i-attach-the-bearer-token-to-requests--如何给请求附加-bearer-令牌",depth:3},{value:"Which platforms are supported? / 支持哪些平台?",id:"which-platforms-are-supported--支持哪些平台",depth:3}]}t.default=(0,o.c)(function(e){let{toc:t=s(e)}=e,r={code:"code",h1:"h1",h3:"h3",p:"p",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h1,{children:"FAQ / 常见问题"}),"\n",(0,n.jsx)(r.h3,{id:t[0].id,children:t[0].value}),"\n",(0,n.jsxs)(r.p,{children:["No. The core is backend-agnostic and ships no HTTP, SDK or native code. You implement ",(0,n.jsx)(r.code,{children:"AuthStrategy"})," to call your backend."]}),"\n",(0,n.jsxs)(r.p,{children:["不。内核后端无关,不含任何 HTTP、SDK 或原生代码。你通过实现 ",(0,n.jsx)(r.code,{children:"AuthStrategy"})," 来调用自己的后端。"]}),"\n",(0,n.jsx)(r.h3,{id:t[1].id,children:t[1].value}),"\n",(0,n.jsxs)(r.p,{children:["No. It is a pure-Dart package; ",(0,n.jsx)(r.code,{children:"flutter:"})," is only a declared constraint because the example app uses Flutter. The runtime has no Flutter dependency."]}),"\n",(0,n.jsxs)(r.p,{children:["不。它是纯 Dart 包;仅因示例 App 用到 Flutter 才声明 ",(0,n.jsx)(r.code,{children:"flutter:"})," 约束,运行时不依赖 Flutter。"]}),"\n",(0,n.jsx)(r.h3,{id:t[2].id,children:t[2].value}),"\n",(0,n.jsxs)(r.p,{children:["Wherever your ",(0,n.jsx)(r.code,{children:"TokenStore"})," puts them. The core ships ",(0,n.jsx)(r.code,{children:"InMemoryTokenStore"})," (lost on restart). For production, use the ",(0,n.jsx)(r.code,{children:"flutter_secure_storage"}),"-backed reference in ",(0,n.jsx)(r.code,{children:"example/lib/secure_token_store.dart"}),"."]}),"\n",(0,n.jsxs)(r.p,{children:["取决于你的 ",(0,n.jsx)(r.code,{children:"TokenStore"}),"。内核自带 ",(0,n.jsx)(r.code,{children:"InMemoryTokenStore"}),"(重启即丢失)。生产请用 ",(0,n.jsx)(r.code,{children:"example/lib/secure_token_store.dart"})," 中基于 ",(0,n.jsx)(r.code,{children:"flutter_secure_storage"})," 的参考实现。"]}),"\n",(0,n.jsx)(r.h3,{id:t[3].id,children:t[3].value}),"\n",(0,n.jsxs)(r.p,{children:["The session is cleared and ",(0,n.jsx)(r.code,{children:"AuthState"})," becomes ",(0,n.jsx)(r.code,{children:"AuthError"}),". Route the user back to login."]}),"\n",(0,n.jsxs)(r.p,{children:["会话被清空,",(0,n.jsx)(r.code,{children:"AuthState"})," 变为 ",(0,n.jsx)(r.code,{children:"AuthError"}),",应将用户引导回登录。"]}),"\n",(0,n.jsx)(r.h3,{id:t[4].id,children:t[4].value}),"\n",(0,n.jsxs)(r.p,{children:["Yes — ",(0,n.jsx)(r.code,{children:"refresh()"})," is single-flight: many concurrent callers share one in-flight request and its result."]}),"\n",(0,n.jsxs)(r.p,{children:["是的——",(0,n.jsx)(r.code,{children:"refresh()"})," 为单飞:多个并发调用方共享同一次请求及其结果。"]}),"\n",(0,n.jsx)(r.h3,{id:t[5].id,children:t[5].value}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"AuthManager"})," is an ",(0,n.jsx)(r.code,{children:"AuthTokenSource"}),". Use the Dio interceptor in ",(0,n.jsx)(r.code,{children:"example/lib/dio_interceptor.dart"}),", or read ",(0,n.jsx)(r.code,{children:"accessToken"})," directly."]}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"AuthManager"})," 即 ",(0,n.jsx)(r.code,{children:"AuthTokenSource"}),"。可用 ",(0,n.jsx)(r.code,{children:"example/lib/dio_interceptor.dart"})," 中的 Dio 拦截器,或直接读取 ",(0,n.jsx)(r.code,{children:"accessToken"}),"。"]}),"\n",(0,n.jsx)(r.h3,{id:t[6].id,children:t[6].value}),"\n",(0,n.jsx)(r.p,{children:"Any platform where Dart or Flutter runs (Android, iOS, Web, Windows, macOS, Linux)."}),"\n",(0,n.jsx)(r.p,{children:"任何能运行 Dart 或 Flutter 的平台(Android、iOS、Web、Windows、macOS、Linux)。"})]})},"/FAQ",{filePath:"pages/FAQ.md",timestamp:1789598212e3,pageMap:i.v,frontMatter:{},title:"FAQ / 常见问题"},"undefined"==typeof RemoteContent?s:RemoteContent.useTOC)},7080:function(e,t,r){"use strict";r.d(t,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9238)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Getting-Started-45e6ee34ef6f3f61.js b/docs/_next/static/chunks/pages/Getting-Started-45e6ee34ef6f3f61.js
deleted file mode 100644
index 5beec3a..0000000
--- a/docs/_next/static/chunks/pages/Getting-Started-45e6ee34ef6f3f61.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[796],{9364:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Getting-Started",function(){return e(1028)}])},1028:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return a}});var t=e(5893),n=e(7812),r=e(7080),h=e(8925);function a(i){return[{value:"Quick Start / 快速开始",id:"quick-start--快速开始",depth:2},{value:"The Lifecycle / 生命周期",id:"the-lifecycle--生命周期",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=a(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,h.a)(),...i.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{children:"Getting Started / 快速开始"}),"\n",(0,t.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:"zero_auth"})," is a headless core: you bring the backend (",(0,t.jsx)(e.code,{children:"AuthStrategy"}),") and the persistence (",(0,t.jsx)(e.code,{children:"TokenStore"}),"), and ",(0,t.jsx)(e.code,{children:"AuthManager"})," drives the session lifecycle."]}),"\n",(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:"zero_auth"})," 是一个无头内核:你提供后端(",(0,t.jsx)(e.code,{children:"AuthStrategy"}),")与持久化(",(0,t.jsx)(e.code,{children:"TokenStore"}),"),",(0,t.jsx)(e.code,{children:"AuthManager"})," 负责驱动会话生命周期。"]}),"\n",(0,t.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(e.code,{children:[(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_auth/zero_auth.dart'"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,t.jsx)(e.span,{children:" "}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 1. Implement your backend (four methods only)."})}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 1. 实现你的后端(只需四个方法)。"})}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy "}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 2. Pick a token store. InMemoryTokenStore ships in-core; for production use"})}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// the flutter_secure_storage reference in example/lib/secure_token_store.dart."})}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 2. 选择令牌存储。内核自带 InMemoryTokenStore;生产环境请用"})}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// example/lib/secure_token_store.dart 中的 flutter_secure_storage 实现。"})}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" store "}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InMemoryTokenStore"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 3. Create the manager and restore any persisted session."})}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 3. 创建管理器并恢复已持久化的会话。"})}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(strategy"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy, tokenStore"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" store);"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"restore"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,t.jsx)(e.p,{children:"Then drive the UI from the state stream:"}),"\n",(0,t.jsx)(e.p,{children:"随后用状态流驱动界面:"}),"\n",(0,t.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(e.code,{children:[(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"auth.state."}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"listen"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((state) {"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" switch"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (state) {"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthUnauthenticated"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showLoginScreen"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Authenticating"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showSpinner"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Authenticated"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session)"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showHome"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session.userId);"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthError"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error)"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,t.jsxs)(e.span,{children:[(0,t.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showError"}),(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(error);"})]}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,t.jsx)(e.span,{children:(0,t.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})})]})}),"\n",(0,t.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:"AuthManager"})," broadcasts an explicit, sealed state machine:"]}),"\n",(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:"AuthManager"})," 广播一个显式、密封的状态机:"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,t.jsxs)(e.table,{children:[(0,t.jsx)(e.thead,{children:(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.th,{children:"State"}),(0,t.jsx)(e.th,{children:"Meaning"})]})}),(0,t.jsxs)(e.tbody,{children:[(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:"Unauthenticated"})}),(0,t.jsx)(e.td,{children:"No session / 无会话"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:"Authenticating"})}),(0,t.jsxs)(e.td,{children:[(0,t.jsx)(e.code,{children:"login"}),"/",(0,t.jsx)(e.code,{children:"register"}),"/",(0,t.jsx)(e.code,{children:"restore"})," in flight / 登录/注册/恢复进行中"]})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:"Authenticated"})}),(0,t.jsx)(e.td,{children:"A valid session is present / 存在有效会话"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:"AuthError"})}),(0,t.jsx)(e.td,{children:"The last operation failed / 上一次操作失败"})]})]})]}),"\n",(0,t.jsx)(e.p,{children:"The stream replays the latest value to new listeners, so a widget renders the correct screen on its first frame."}),"\n",(0,t.jsx)(e.p,{children:"状态流会向新订阅者重放最近的值,因此 widget 在首帧即可渲染正确界面。"}),"\n",(0,t.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,t.jsxs)(e.ul,{children:["\n",(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:"Installation",children:"Installation"})," — Detailed installation methods / 详细安装方式"]}),"\n",(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:"Usage",children:"Usage"})," — Full usage guide / 完整使用指南"]}),"\n",(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — Implement ",(0,t.jsx)(e.code,{children:"AuthStrategy"})," / 实现后端边界"]}),"\n"]})]})},"/Getting-Started",{filePath:"pages/Getting-Started.md",pageMap:r.v,frontMatter:{},title:"Getting Started / 快速开始"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return t}});let t=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9364)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Getting-Started-7a2d78c0e4a938dc.js b/docs/_next/static/chunks/pages/Getting-Started-7a2d78c0e4a938dc.js
new file mode 100644
index 0000000..3f1f691
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Getting-Started-7a2d78c0e4a938dc.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[796],{9364:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Getting-Started",function(){return e(1028)}])},1028:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return a}});var n=e(5893),t=e(7812),r=e(7080),h=e(8925);function a(i){return[{value:"Quick Start / 快速开始",id:"quick-start--快速开始",depth:2},{value:"The Lifecycle / 生命周期",id:"the-lifecycle--生命周期",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,t.c)(function(i){let{toc:s=a(i)}=i,e={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,h.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Getting Started / 快速开始"}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," is a headless core: you bring the backend (",(0,n.jsx)(e.code,{children:"AuthStrategy"}),") and the persistence (",(0,n.jsx)(e.code,{children:"TokenStore"}),"), and ",(0,n.jsx)(e.code,{children:"AuthManager"})," drives the session lifecycle."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," 是一个无头内核:你提供后端(",(0,n.jsx)(e.code,{children:"AuthStrategy"}),")与持久化(",(0,n.jsx)(e.code,{children:"TokenStore"}),"),",(0,n.jsx)(e.code,{children:"AuthManager"})," 负责驱动会话生命周期。"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_auth/zero_auth.dart'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 1. Implement your backend (four methods only)."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 1. 实现你的后端(只需四个方法)。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 2. Pick a token store. InMemoryTokenStore ships in-core; for production use"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// the flutter_secure_storage reference in example/lib/secure_token_store.dart."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 2. 选择令牌存储。内核自带 InMemoryTokenStore;生产环境请用"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// example/lib/secure_token_store.dart 中的 flutter_secure_storage 实现。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" store "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InMemoryTokenStore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 3. Create the manager and restore any persisted session."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 3. 创建管理器并恢复已持久化的会话。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(strategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy, tokenStore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" store);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"restore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsx)(e.p,{children:"Then drive the UI from the state stream:"}),"\n",(0,n.jsx)(e.p,{children:"随后用状态流驱动界面:"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"auth.state."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"listen"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((state) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" switch"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (state) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Unauthenticated"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showLoginScreen"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Authenticating"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" LoggingOut"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showSpinner"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Authenticated"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showHome"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session.userId);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Refreshing"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // Still signed in: only the token is being renewed."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 仍处于已登录状态:只是令牌在续期。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showHome"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session.userId, renewing"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" case"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthError"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" error)"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" showError"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(error);"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})})]})}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsxs)(e.p,{children:["If you prefer ",(0,n.jsx)(e.code,{children:"if"}),"/",(0,n.jsx)(e.code,{children:"else"})," over exhaustiveness, use ",(0,n.jsx)(e.code,{children:"state.isAuthenticated"})," and\n",(0,n.jsx)(e.code,{children:"state.isBusy"})," instead of ",(0,n.jsx)(e.code,{children:"state is Authenticated"})," — ",(0,n.jsx)(e.code,{children:"isAuthenticated"})," stays\n",(0,n.jsx)(e.code,{children:"true"})," during ",(0,n.jsx)(e.code,{children:"Refreshing"}),", so your UI never bounces back to the login screen\nmid-refresh."]}),"\n",(0,n.jsxs)(e.p,{children:["若不想用穷举匹配,请用 ",(0,n.jsx)(e.code,{children:"state.isAuthenticated"})," / ",(0,n.jsx)(e.code,{children:"state.isBusy"})," 代替\n",(0,n.jsx)(e.code,{children:"state is Authenticated"}),"——",(0,n.jsx)(e.code,{children:"isAuthenticated"})," 在 ",(0,n.jsx)(e.code,{children:"Refreshing"})," 期间仍为 ",(0,n.jsx)(e.code,{children:"true"}),",\n界面不会在刷新途中退回登录页。"]}),"\n"]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthManager"})," broadcasts an explicit, sealed state machine:"]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthManager"})," 广播一个显式、密封的状态机:"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"State"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"Unauthenticated"})}),(0,n.jsx)(e.td,{children:"No session / 无会话"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"Authenticating"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"login"}),"/",(0,n.jsx)(e.code,{children:"register"})," in flight / 登录/注册进行中"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"Authenticated"})}),(0,n.jsx)(e.td,{children:"A valid session is present / 存在有效会话"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"Refreshing"})}),(0,n.jsx)(e.td,{children:"Session renewal in flight; the previous session stays usable / 续期进行中,旧会话仍可用"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"LoggingOut"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"logout()"})," in flight / 登出进行中"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"AuthError"})}),(0,n.jsx)(e.td,{children:"The last operation failed / 上一次操作失败"})]})]})]}),"\n",(0,n.jsx)(e.p,{children:"The stream replays the latest value to new listeners, so a widget renders the correct screen on its first frame."}),"\n",(0,n.jsx)(e.p,{children:"状态流会向新订阅者重放最近的值,因此 widget 在首帧即可渲染正确界面。"}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Installation",children:"Installation"})," — Detailed installation methods / 详细安装方式"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Usage",children:"Usage"})," — Full usage guide / 完整使用指南"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — Implement ",(0,n.jsx)(e.code,{children:"AuthStrategy"})," / 实现后端边界"]}),"\n"]})]})},"/Getting-Started",{filePath:"pages/Getting-Started.md",timestamp:178966094e4,pageMap:r.v,frontMatter:{},title:"Getting Started / 快速开始"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9364)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Installation-2ec080b97b32b024.js b/docs/_next/static/chunks/pages/Installation-2ec080b97b32b024.js
new file mode 100644
index 0000000..f6b2e5f
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Installation-2ec080b97b32b024.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[139],{9720:function(e,t,i){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Installation",function(){return i(1220)}])},1220:function(e,t,i){"use strict";i.r(t),i.d(t,{useTOC:function(){return l}});var n=i(5893),r=i(7812),s=i(7080),a=i(8925),d=i(5192);function l(e){return[{value:"From pub.dev (Recommended) / 从 pub.dev 安装(推荐)",id:"from-pubdev-recommended--从-pubdev-安装推荐",depth:2},{value:"From GitHub / 从 GitHub 安装",id:"from-github--从-github-安装",depth:2},{value:"Import / 导入",id:"import--导入",depth:2},{value:"Requirements / 环境要求",id:"requirements--环境要求",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}t.default=(0,r.c)(function(e){let{toc:t=l(e)}=e,i={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{children:"Installation / 安装"}),"\n",(0,n.jsx)(i.h2,{id:t[0].id,children:t[0].value}),"\n",(0,n.jsxs)(i.p,{children:["Add the following to your ",(0,n.jsx)(i.code,{children:"pubspec.yaml"}),":"]}),"\n",(0,n.jsxs)(i.p,{children:["在 ",(0,n.jsx)(i.code,{children:"pubspec.yaml"})," 中添加以下依赖:"]}),"\n",(0,n.jsx)(i.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(i.code,{children:[(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_auth"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"^0.3.0"})]})]})}),"\n",(0,n.jsx)(i.p,{children:"Then run:"}),"\n",(0,n.jsx)(i.p,{children:"然后运行:"}),"\n",(0,n.jsx)(i.pre,{icon:d.Fx,tabIndex:"0","data-language":"bash","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(i.code,{children:(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"dart"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" pub"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" get"})]})})}),"\n",(0,n.jsx)(i.h2,{id:t[1].id,children:t[1].value}),"\n",(0,n.jsx)(i.p,{children:"Alternatively, install from GitHub:"}),"\n",(0,n.jsx)(i.p,{children:"或者从 GitHub 安装:"}),"\n",(0,n.jsx)(i.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(i.code,{children:[(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_auth"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" git"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" url"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"https://github.com/zero-labsco/zero_auth.git"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" ref"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"release/v0.3.0"})]})]})}),"\n",(0,n.jsx)(i.h2,{id:t[2].id,children:t[2].value}),"\n",(0,n.jsx)(i.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(i.code,{children:(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_auth/zero_auth.dart'"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]})})}),"\n",(0,n.jsx)(i.h2,{id:t[3].id,children:t[3].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(i.table,{children:[(0,n.jsx)(i.thead,{children:(0,n.jsxs)(i.tr,{children:[(0,n.jsx)(i.th,{children:"Requirement"}),(0,n.jsx)(i.th,{children:"Version"})]})}),(0,n.jsxs)(i.tbody,{children:[(0,n.jsxs)(i.tr,{children:[(0,n.jsx)(i.td,{children:"Dart SDK"}),(0,n.jsx)(i.td,{children:">= 3.4.0"})]}),(0,n.jsxs)(i.tr,{children:[(0,n.jsx)(i.td,{children:"Flutter"}),(0,n.jsx)(i.td,{children:">= 3.0.0 (only a constraint; no Flutter runtime dependency)"})]})]})]}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.code,{children:"zero_auth"})," is a pure-Dart package. Flutter is only listed because the example app uses it; the core has no Flutter dependency."]}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.code,{children:"zero_auth"})," 是纯 Dart 包,仅因示例 App 用到 Flutter 才列出;内核本身不依赖 Flutter。"]}),"\n",(0,n.jsx)(i.h2,{id:t[4].id,children:t[4].value}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.a,{href:"Getting-Started",children:"Getting Started"})," — Quick start guide / 快速开始"]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.a,{href:"Usage",children:"Usage"})," — Full usage guide / 完整使用指南"]}),"\n"]})]})},"/Installation",{filePath:"pages/Installation.md",timestamp:1789598212e3,pageMap:s.v,frontMatter:{},title:"Installation / 安装"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,t,i){"use strict";i.d(t,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9720)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Installation-38862789c9f657bb.js b/docs/_next/static/chunks/pages/Installation-38862789c9f657bb.js
deleted file mode 100644
index 4138218..0000000
--- a/docs/_next/static/chunks/pages/Installation-38862789c9f657bb.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[139],{9720:function(e,t,i){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Installation",function(){return i(1220)}])},1220:function(e,t,i){"use strict";i.r(t),i.d(t,{useTOC:function(){return l}});var n=i(5893),r=i(7812),s=i(7080),a=i(8925),d=i(5192);function l(e){return[{value:"From pub.dev (Recommended) / 从 pub.dev 安装(推荐)",id:"from-pubdev-recommended--从-pubdev-安装推荐",depth:2},{value:"From GitHub / 从 GitHub 安装",id:"from-github--从-github-安装",depth:2},{value:"Import / 导入",id:"import--导入",depth:2},{value:"Requirements / 环境要求",id:"requirements--环境要求",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}t.default=(0,r.c)(function(e){let{toc:t=l(e)}=e,i={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{children:"Installation / 安装"}),"\n",(0,n.jsx)(i.h2,{id:t[0].id,children:t[0].value}),"\n",(0,n.jsxs)(i.p,{children:["Add the following to your ",(0,n.jsx)(i.code,{children:"pubspec.yaml"}),":"]}),"\n",(0,n.jsxs)(i.p,{children:["在 ",(0,n.jsx)(i.code,{children:"pubspec.yaml"})," 中添加以下依赖:"]}),"\n",(0,n.jsx)(i.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(i.code,{children:[(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_auth"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"^__ZERO_AUTH_VERSION__"})]})]})}),"\n",(0,n.jsx)(i.p,{children:"Then run:"}),"\n",(0,n.jsx)(i.p,{children:"然后运行:"}),"\n",(0,n.jsx)(i.pre,{icon:d.Fx,tabIndex:"0","data-language":"bash","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(i.code,{children:(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"dart"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" pub"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" get"})]})})}),"\n",(0,n.jsx)(i.h2,{id:t[1].id,children:t[1].value}),"\n",(0,n.jsx)(i.p,{children:"Alternatively, install from GitHub:"}),"\n",(0,n.jsx)(i.p,{children:"或者从 GitHub 安装:"}),"\n",(0,n.jsx)(i.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(i.code,{children:[(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_auth"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" git"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" url"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"https://github.com/zero-labsco/zero_auth.git"})]}),"\n",(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" ref"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"release/v__ZERO_AUTH_VERSION__"})]})]})}),"\n",(0,n.jsx)(i.h2,{id:t[2].id,children:t[2].value}),"\n",(0,n.jsx)(i.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(i.code,{children:(0,n.jsxs)(i.span,{children:[(0,n.jsx)(i.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_auth/zero_auth.dart'"}),(0,n.jsx)(i.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]})})}),"\n",(0,n.jsx)(i.h2,{id:t[3].id,children:t[3].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(i.table,{children:[(0,n.jsx)(i.thead,{children:(0,n.jsxs)(i.tr,{children:[(0,n.jsx)(i.th,{children:"Requirement"}),(0,n.jsx)(i.th,{children:"Version"})]})}),(0,n.jsxs)(i.tbody,{children:[(0,n.jsxs)(i.tr,{children:[(0,n.jsx)(i.td,{children:"Dart SDK"}),(0,n.jsx)(i.td,{children:">= 3.4.0"})]}),(0,n.jsxs)(i.tr,{children:[(0,n.jsx)(i.td,{children:"Flutter"}),(0,n.jsx)(i.td,{children:">= 3.0.0 (only a constraint; no Flutter runtime dependency)"})]})]})]}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.code,{children:"zero_auth"})," is a pure-Dart package. Flutter is only listed because the example app uses it; the core has no Flutter dependency."]}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.code,{children:"zero_auth"})," 是纯 Dart 包,仅因示例 App 用到 Flutter 才列出;内核本身不依赖 Flutter。"]}),"\n",(0,n.jsx)(i.h2,{id:t[4].id,children:t[4].value}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.a,{href:"Getting-Started",children:"Getting Started"})," — Quick start guide / 快速开始"]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.a,{href:"Usage",children:"Usage"})," — Full usage guide / 完整使用指南"]}),"\n"]})]})},"/Installation",{filePath:"pages/Installation.md",pageMap:s.v,frontMatter:{},title:"Installation / 安装"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,t,i){"use strict";i.d(t,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9720)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Network-Integration-76d31e3c99016d3a.js b/docs/_next/static/chunks/pages/Network-Integration-b0e7e91cc72afa34.js
similarity index 84%
rename from docs/_next/static/chunks/pages/Network-Integration-76d31e3c99016d3a.js
rename to docs/_next/static/chunks/pages/Network-Integration-b0e7e91cc72afa34.js
index f61af35..d5fde7f 100644
--- a/docs/_next/static/chunks/pages/Network-Integration-76d31e3c99016d3a.js
+++ b/docs/_next/static/chunks/pages/Network-Integration-b0e7e91cc72afa34.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[773],{7293:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Network-Integration",function(){return s(2063)}])},2063:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return a}});var t=s(5893),n=s(7812),r=s(7080),h=s(8925);function a(i){let e={code:"code",...(0,h.a)()};return[{value:(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.code,{children:"AuthTokenSource"})," / 令牌源"]}),id:"authtokensource--令牌源",depth:2},{value:"Dio interceptor / Dio 拦截器",id:"dio-interceptor--dio-拦截器",depth:2},{value:"Other HTTP clients / 其它客户端",id:"other-http-clients--其它客户端",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}e.default=(0,n.c)(function(i){let{toc:e=a(i)}=i,s={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...(0,h.a)(),...i.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{children:"Network Integration / 网络集成"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager"})," implements ",(0,t.jsx)(s.code,{children:"AuthTokenSource"}),", so HTTP clients can read the current access token ",(0,t.jsx)(s.strong,{children:"without depending on the manager object"}),". This keeps your Dio setup decoupled from ",(0,t.jsx)(s.code,{children:"zero_auth"}),"."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager"})," 实现了 ",(0,t.jsx)(s.code,{children:"AuthTokenSource"}),",因此 HTTP 客户端可在",(0,t.jsx)(s.strong,{children:"不依赖管理器对象"}),"的前提下读取当前访问令牌,使 Dio 配置与 ",(0,t.jsx)(s.code,{children:"zero_auth"})," 解耦。"]}),"\n",(0,t.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"abstract"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthTokenSource"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?> "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"get"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" accessToken;"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager.accessToken"})," returns the current token, or ",(0,t.jsx)(s.code,{children:"null"})," when unauthenticated. It can also trigger a transparent refresh when the token is near expiry (implementation-dependent)."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager.accessToken"})," 返回当前令牌;未认证时返回 ",(0,t.jsx)(s.code,{children:"null"}),"。在令牌接近过期时,它还可触发一次透明的刷新(取决于实现)。"]}),"\n",(0,t.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"example/lib/dio_interceptor.dart"})," ships a ready-to-use interceptor:"]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"example/lib/dio_interceptor.dart"})," 提供了一个开箱即用的拦截器:"]}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthInterceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Interceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthInterceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"this"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".tokens); "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// an AuthTokenSource"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthTokenSource"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokens;"})]}),"\n",(0,t.jsx)(s.span,{children:" "}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" void"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" onRequest"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"RequestOptions"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" o, "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"RequestInterceptorHandler"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" h) "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" t "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokens.accessToken;"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (t "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") o.headers["}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Authorization'"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'Bearer "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"$"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"t"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" h."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"next"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(o);"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dio "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Dio"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ..interceptors."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"add"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthInterceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(authManager));"})]})]})}),"\n",(0,t.jsxs)(s.p,{children:["When a ",(0,t.jsx)(s.code,{children:"401"})," is returned, refresh the session and retry; if refresh fails, the manager emits ",(0,t.jsx)(s.code,{children:"AuthError"})," and your app routes back to login."]}),"\n",(0,t.jsxs)(s.p,{children:["当返回 ",(0,t.jsx)(s.code,{children:"401"})," 时,刷新会话并重试;若刷新失败,管理器会发出 ",(0,t.jsx)(s.code,{children:"AuthError"}),",应用随之跳转登录。"]}),"\n",(0,t.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,t.jsxs)(s.p,{children:["Because ",(0,t.jsx)(s.code,{children:"AuthTokenSource"})," is a plain interface, the same pattern works for ",(0,t.jsx)(s.code,{children:"package:http"}),", ",(0,t.jsx)(s.code,{children:"chopper"}),", or any client that lets you mutate request headers."]}),"\n",(0,t.jsxs)(s.p,{children:["由于 ",(0,t.jsx)(s.code,{children:"AuthTokenSource"})," 是普通接口,同样的模式适用于 ",(0,t.jsx)(s.code,{children:"package:http"}),"、",(0,t.jsx)(s.code,{children:"chopper"})," 或任何允许修改请求头的客户端。"]}),"\n",(0,t.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.a,{href:"Usage",children:"Usage"})," — Full integration walkthrough / 完整集成讲解"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.a,{href:"Errors",children:"Errors"})," — Handling ",(0,t.jsx)(s.code,{children:"401"})," and refresh failures / 处理 401 与刷新失败"]}),"\n"]})]})},"/Network-Integration",{filePath:"pages/Network-Integration.md",pageMap:r.v,frontMatter:{},title:"Network Integration / 网络集成"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return t}});let t=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=7293)}),_N_E=i.O()}]);
\ No newline at end of file
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[773],{7293:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Network-Integration",function(){return s(2063)}])},2063:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return a}});var t=s(5893),n=s(7812),r=s(7080),h=s(8925);function a(i){let e={code:"code",...(0,h.a)()};return[{value:(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.code,{children:"AuthTokenSource"})," / 令牌源"]}),id:"authtokensource--令牌源",depth:2},{value:"Dio interceptor / Dio 拦截器",id:"dio-interceptor--dio-拦截器",depth:2},{value:"Other HTTP clients / 其它客户端",id:"other-http-clients--其它客户端",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}e.default=(0,n.c)(function(i){let{toc:e=a(i)}=i,s={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...(0,h.a)(),...i.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{children:"Network Integration / 网络集成"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager"})," implements ",(0,t.jsx)(s.code,{children:"AuthTokenSource"}),", so HTTP clients can read the current access token ",(0,t.jsx)(s.strong,{children:"without depending on the manager object"}),". This keeps your Dio setup decoupled from ",(0,t.jsx)(s.code,{children:"zero_auth"}),"."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager"})," 实现了 ",(0,t.jsx)(s.code,{children:"AuthTokenSource"}),",因此 HTTP 客户端可在",(0,t.jsx)(s.strong,{children:"不依赖管理器对象"}),"的前提下读取当前访问令牌,使 Dio 配置与 ",(0,t.jsx)(s.code,{children:"zero_auth"})," 解耦。"]}),"\n",(0,t.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"abstract"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthTokenSource"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?> "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"get"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" accessToken;"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager.accessToken"})," returns the current token, or ",(0,t.jsx)(s.code,{children:"null"})," when unauthenticated. It can also trigger a transparent refresh when the token is near expiry (implementation-dependent)."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthManager.accessToken"})," 返回当前令牌;未认证时返回 ",(0,t.jsx)(s.code,{children:"null"}),"。在令牌接近过期时,它还可触发一次透明的刷新(取决于实现)。"]}),"\n",(0,t.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"example/lib/dio_interceptor.dart"})," ships a ready-to-use interceptor:"]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"example/lib/dio_interceptor.dart"})," 提供了一个开箱即用的拦截器:"]}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthInterceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Interceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthInterceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"this"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".tokens); "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// an AuthTokenSource"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthTokenSource"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokens;"})]}),"\n",(0,t.jsx)(s.span,{children:" "}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" void"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" onRequest"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"RequestOptions"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" o, "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"RequestInterceptorHandler"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" h) "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" t "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokens.accessToken;"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (t "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") o.headers["}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Authorization'"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'Bearer "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"$"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"t"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" h."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"next"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(o);"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dio "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Dio"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ..interceptors."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"add"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthInterceptor"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(authManager));"})]})]})}),"\n",(0,t.jsxs)(s.p,{children:["When a ",(0,t.jsx)(s.code,{children:"401"})," is returned, refresh the session and retry; if refresh fails, the manager emits ",(0,t.jsx)(s.code,{children:"AuthError"})," and your app routes back to login."]}),"\n",(0,t.jsxs)(s.p,{children:["当返回 ",(0,t.jsx)(s.code,{children:"401"})," 时,刷新会话并重试;若刷新失败,管理器会发出 ",(0,t.jsx)(s.code,{children:"AuthError"}),",应用随之跳转登录。"]}),"\n",(0,t.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,t.jsxs)(s.p,{children:["Because ",(0,t.jsx)(s.code,{children:"AuthTokenSource"})," is a plain interface, the same pattern works for ",(0,t.jsx)(s.code,{children:"package:http"}),", ",(0,t.jsx)(s.code,{children:"chopper"}),", or any client that lets you mutate request headers."]}),"\n",(0,t.jsxs)(s.p,{children:["由于 ",(0,t.jsx)(s.code,{children:"AuthTokenSource"})," 是普通接口,同样的模式适用于 ",(0,t.jsx)(s.code,{children:"package:http"}),"、",(0,t.jsx)(s.code,{children:"chopper"})," 或任何允许修改请求头的客户端。"]}),"\n",(0,t.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.a,{href:"Usage",children:"Usage"})," — Full integration walkthrough / 完整集成讲解"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.a,{href:"Errors",children:"Errors"})," — Handling ",(0,t.jsx)(s.code,{children:"401"})," and refresh failures / 处理 401 与刷新失败"]}),"\n"]})]})},"/Network-Integration",{filePath:"pages/Network-Integration.md",timestamp:1789598212e3,pageMap:r.v,frontMatter:{},title:"Network Integration / 网络集成"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return t}});let t=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=7293)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Persistence-2758c9191f4e1054.js b/docs/_next/static/chunks/pages/Persistence-2758c9191f4e1054.js
new file mode 100644
index 0000000..d5ee64a
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Persistence-2758c9191f4e1054.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[746],{7423:function(e,i,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Persistence",function(){return s(2960)}])},2960:function(e,i,s){"use strict";s.r(i),s.d(i,{useTOC:function(){return h}});var t=s(5893),n=s(7812),r=s(7080),a=s(8925);function h(e){return[{value:"1. Serialize the session / 序列化会话",id:"1-serialize-the-session--序列化会话",depth:2},{value:"2. Flutter — encrypted secure storage / Flutter —— 加密安全存储",id:"2-flutter--encrypted-secure-storage--flutter--加密安全存储",depth:2},{value:"3. Server / CLI / desktop — JSON file / 服务端 / CLI / 桌面 —— JSON 文件",id:"3-server--cli--desktop--json-file--服务端--cli--桌面--json-文件",depth:2},{value:"4. Combine with auto-refresh / 结合自动刷新",id:"4-combine-with-auto-refresh--结合自动刷新",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}i.default=(0,n.c)(function(e){let{toc:i=h(e)}=e,s={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...(0,a.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{children:"Session Persistence / 会话持久化"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"InMemoryTokenStore"})," loses the session on every restart. For a real app you must persist it — and ",(0,t.jsx)(s.code,{children:"zero_auth"})," now ships the primitives that make this a one-liner: ",(0,t.jsx)(s.strong,{children:"session (de)serialization"})," plus two ready-to-copy reference stores."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"InMemoryTokenStore"})," 会在每次重启时丢失会话。真实应用必须把它持久化——而 ",(0,t.jsx)(s.code,{children:"zero_auth"})," 现在提供了让这件事变成「一行代码」的原语:",(0,t.jsx)(s.strong,{children:"会话(反)序列化"}),",外加两个开箱即用的参考存储。"]}),"\n",(0,t.jsx)(s.h2,{id:i[0].id,children:i[0].value}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthSession"})," is JSON-safe out of the box. ",(0,t.jsx)(s.code,{children:"null"})," fields are omitted, and ",(0,t.jsx)(s.code,{children:"claims"})," round-trips as a plain map."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"AuthSession"})," 天生就是 JSON 安全的:",(0,t.jsx)(s.code,{children:"null"})," 字段会被省略,",(0,t.jsx)(s.code,{children:"claims"})," 作为普通映射原样往返。"]}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toJson"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(); "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Map"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" restored "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthSession"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromJson"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json);"})]})]})}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"RefreshToken"})," serializes to its raw string too, so a persisted session rehydrates losslessly."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"RefreshToken"})," 也序列化为其原始字符串,因此持久化的会话可无损恢复。"]}),"\n",(0,t.jsx)(s.h2,{id:i[1].id,children:i[1].value}),"\n",(0,t.jsxs)(s.p,{children:["For mobile, persist into the OS keychain / keystore via ",(0,t.jsx)(s.code,{children:"flutter_secure_storage"}),". A reference implementation lives at ",(0,t.jsx)(s.code,{children:"example/lib/secure_token_store.dart"}),":"]}),"\n",(0,t.jsxs)(s.p,{children:["在移动端,通过 ",(0,t.jsx)(s.code,{children:"flutter_secure_storage"})," 把令牌存入系统钥匙串 / Keystore。参考实现位于 ",(0,t.jsx)(s.code,{children:"example/lib/secure_token_store.dart"}),":"]}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myStrategy,"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SecureTokenStore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// from example/"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,t.jsx)(s.span,{children:" "}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"restore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(); "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// rehydrate before the first frame"})]})]})}),"\n",(0,t.jsxs)(s.blockquote,{children:["\n",(0,t.jsxs)(s.p,{children:["Never store refresh tokens in plain ",(0,t.jsx)(s.code,{children:"SharedPreferences"}),". Use OS-backed secure storage only."]}),"\n",(0,t.jsxs)(s.p,{children:["切勿把刷新令牌明文存入 ",(0,t.jsx)(s.code,{children:"SharedPreferences"}),",只使用操作系统级安全存储。"]}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:i[2].id,children:i[2].value}),"\n",(0,t.jsxs)(s.p,{children:["On non-mobile Dart targets you can write the serialized session to a file. A reference implementation lives at ",(0,t.jsx)(s.code,{children:"example/lib/json_token_store.dart"}),":"]}),"\n",(0,t.jsxs)(s.p,{children:["在非移动端 Dart 目标上,可以把序列化后的会话写入文件。参考实现位于 ",(0,t.jsx)(s.code,{children:"example/lib/json_token_store.dart"}),":"]}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myStrategy,"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FileTokenStore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"File"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'.zero_auth_session.json'"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,t.jsx)(s.p,{children:"This is ideal for a backend that keeps a logged-in user across process restarts, or a CLI that stays authenticated between invocations."}),"\n",(0,t.jsx)(s.p,{children:"这非常适合「重启后仍保持登录」的后端,或「多次调用之间保持认证」的 CLI。"}),"\n",(0,t.jsx)(s.h2,{id:i[3].id,children:i[3].value}),"\n",(0,t.jsxs)(s.p,{children:["When you enable ",(0,t.jsx)(s.a,{href:"Configuration",children:"proactive auto-refresh"}),", the manager renews the token before it expires — and every renewal is persisted through ",(0,t.jsx)(s.code,{children:"save()"}),", so the on-disk session always carries a fresh access token."]}),"\n",(0,t.jsxs)(s.p,{children:["当你开启",(0,t.jsx)(s.a,{href:"Configuration",children:"主动自动刷新"}),"时,管理器会在令牌过期前续期——而每次续期都会通过 ",(0,t.jsx)(s.code,{children:"save()"})," 落盘,因此磁盘上的会话始终持有崭新的访问令牌。"]}),"\n",(0,t.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(s.code,{children:[(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myStrategy,"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SecureTokenStore"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,t.jsxs)(s.span,{children:[(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" autoRefreshAhead"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(minutes"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,t.jsx)(s.span,{children:(0,t.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,t.jsx)(s.h2,{id:i[4].id,children:i[4].value}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.a,{href:"Token-Store",children:"Token Store"})," — the ",(0,t.jsx)(s.code,{children:"save"})," / ",(0,t.jsx)(s.code,{children:"load"})," / ",(0,t.jsx)(s.code,{children:"clear"})," contract / ",(0,t.jsx)(s.code,{children:"save"})," / ",(0,t.jsx)(s.code,{children:"load"})," / ",(0,t.jsx)(s.code,{children:"clear"})," 契约"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.a,{href:"Configuration",children:"Configuration"})," — enable proactive auto-refresh / 开启主动自动刷新"]}),"\n"]})]})},"/Persistence",{filePath:"pages/Persistence.md",timestamp:1789600805e3,pageMap:r.v,frontMatter:{},title:"Session Persistence / 会话持久化"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)},7080:function(e,i,s){"use strict";s.d(i,{v:function(){return t}});let t=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=7423)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Third-Party-Login-9e3cc5e5b7759af8.js b/docs/_next/static/chunks/pages/Third-Party-Login-9e3cc5e5b7759af8.js
new file mode 100644
index 0000000..ed048ca
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Third-Party-Login-9e3cc5e5b7759af8.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[509],{6662:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Third-Party-Login",function(){return e(353)}])},353:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var n=e(5893),h=e(7812),t=e(7080),r=e(8925);function l(i){return[{value:"The key idea / 核心思路",id:"the-key-idea--核心思路",depth:2},{value:"When this fits / 适用场景",id:"when-this-fits--适用场景",depth:2},{value:"Wiring it up / 接线步骤",id:"wiring-it-up--接线步骤",depth:2},{value:"Same model for every method / 各登录方式共用一套模型",id:"same-model-for-every-method--各登录方式共用一套模型",depth:2},{value:"Also works for / 同样适用于",id:"also-works-for--同样适用于",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Third-Party Login / 第三方登录"}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," does ",(0,n.jsx)(e.strong,{children:"not"})," run the OAuth handshake — and that is deliberate. It is a\r\npure-Dart package, so it ships no platform code, no browser plumbing and no\r\nredirect URL handling (those live outside ",(0,n.jsx)(e.code,{children:"lib/"}),")."]}),"\n",(0,n.jsxs)(e.p,{children:["Instead, ",(0,n.jsx)(e.code,{children:"zero_auth"})," manages what comes ",(0,n.jsx)(e.strong,{children:"after"})," the handshake: the session your\r\nown backend issues."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"zero_auth"})," ",(0,n.jsx)(e.strong,{children:"不负责"})," OAuth 握手环节,这是刻意为之:它是纯 Dart 包,不含任何平台\r\n代码、浏览器通道或重定向回调处理(这些只能在 ",(0,n.jsx)(e.code,{children:"lib/"})," 之外)。"]}),"\n",(0,n.jsxs)(e.p,{children:["它负责的是握手",(0,n.jsx)(e.strong,{children:"之后"}),"的事:你自己后端所签发的会话。"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"plaintext","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{children:"provider consent ──► code / id_token ──► YOUR BACKEND ──► your access + refresh tokens ──► zero_auth"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{children:" (outside) (any language) (this package)"})})]})}),"\n",(0,n.jsxs)(e.p,{children:["Because the login ",(0,n.jsx)(e.em,{children:"method"})," is invisible to the manager, password login and\r\nGoogle/Apple login end up sharing ",(0,n.jsx)(e.strong,{children:"one"})," token lifecycle. That is the whole\r\npoint."]}),"\n",(0,n.jsxs)(e.p,{children:["登录",(0,n.jsx)(e.em,{children:"方式"}),"对管理器是透明的,因此密码登录与 Google / Apple 登录最终共享",(0,n.jsx)(e.strong,{children:"同一套"}),"\r\n令牌生命周期机制。这正是关键所在。"]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:["This pattern fits when ",(0,n.jsx)(e.strong,{children:"your backend brokers the provider"})," — you have a\r\nbackend, it verifies the provider token, then mints your own tokens."]}),"\n",(0,n.jsxs)(e.p,{children:["下面的模式适用于",(0,n.jsx)(e.strong,{children:"你的后端作为经纪方"}),":你有后端,它校验提供方令牌,然后签发你自己的\r\n令牌。"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Scenario"}),(0,n.jsx)(e.th,{children:"Fit"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Own backend + Google/Apple/GitHub sign-in / 自有后端 + 第三方登录"}),(0,n.jsx)(e.td,{children:"✅ Ideal / 理想"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Own backend + password AND social logins / 自有后端,密码与社交登录并存"}),(0,n.jsx)(e.td,{children:"✅ One shared session model / 共用一套会话模型"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Firebase/Supabase issues the tokens directly / 由 Firebase/Supabase 直接签发令牌"}),(0,n.jsx)(e.td,{children:"⚠️ Use their SDK instead / 请改用其 SDK"})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"1. Run the handshake outside this package."}),"\r\nUse whichever OAuth client fits your targets (",(0,n.jsx)(e.code,{children:"flutter_web_auth"}),", AppAuth, or a\r\nserver-side flow). This code lives in your app or a sibling Flutter package, never\r\nin ",(0,n.jsx)(e.code,{children:"lib/"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"1. 在本包之外完成握手。"}),"\r\n使用适合目标平台的 OAuth 客户端(",(0,n.jsx)(e.code,{children:"flutter_web_auth"}),"、AppAuth 或服务端流程)。这部分\r\n代码放在你的应用或兄弟 Flutter 包里,绝不放在 ",(0,n.jsx)(e.code,{children:"lib/"}),"。"]}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:"2. Trade the provider credential for your tokens on your backend."})}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:"2. 用提供方凭据到你的后端换取自有令牌。"})}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"signInWithGoogle"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"BuildContext"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" context) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 1) Provider consent (outside zero_auth) → authorization code / id_token."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 提供方授权(零依赖,在 zero_auth 之外)→ 授权码 / id_token。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" code "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myOAuthClient."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"authenticate"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 2) Your backend verifies it with Google and returns YOUR tokens."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 你的后端用它与 Google 校验,并返回「你自己的」令牌。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" res "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"post"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'/auth/google'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", data"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'code'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" code});"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" accessToken"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" res["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'accessToken'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" refreshToken"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" RefreshToken"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(res["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'refreshToken'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" expiresAt"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" DateTime"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"now"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"add"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Duration"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" res["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'expiresIn'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" int"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" userId"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" res["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'userId'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsxs)(e.strong,{children:["3. Hand the session to the manager with ",(0,n.jsx)(e.code,{children:"loginWith"}),"."]}),"\r\n",(0,n.jsx)(e.code,{children:"loginWith"})," is the escape hatch for flows that are not ",(0,n.jsx)(e.code,{children:"login"})," / ",(0,n.jsx)(e.code,{children:"register"}),": the\r\nmanager still owns persistence, the state machine and proactive refresh."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsxs)(e.strong,{children:["3. 用 ",(0,n.jsx)(e.code,{children:"loginWith"})," 把会话交给管理器。"]}),"\r\n",(0,n.jsx)(e.code,{children:"loginWith"})," 是为那些不符合 ",(0,n.jsx)(e.code,{children:"login"})," / ",(0,n.jsx)(e.code,{children:"register"})," 形态的流程准备的逃生口:持久化、状态机\r\n与主动刷新仍由管理器负责。"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"loginWith"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((strategy) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" signInWithGoogle"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(context));"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// emits Authenticating → Authenticated, or AuthError + rethrow."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 发出 Authenticating → Authenticated;失败则发 AuthError 并重新抛出。"})})]})}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsxs)(e.p,{children:["Keep ",(0,n.jsx)(e.code,{children:"signInWithGoogle"})," throwing ",(0,n.jsx)(e.code,{children:"AuthException"})," with a meaningful ",(0,n.jsx)(e.code,{children:"code"}),"\r\n(",(0,n.jsx)(e.code,{children:"'invalid_credentials'"}),", ",(0,n.jsx)(e.code,{children:"'session_expired'"}),", …) so failures map to the typed\r\nexceptions in ",(0,n.jsx)(e.a,{href:"Errors",children:"Errors"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:["让 ",(0,n.jsx)(e.code,{children:"signInWithGoogle"})," 抛出带有实用 ",(0,n.jsx)(e.code,{children:"code"}),"(",(0,n.jsx)(e.code,{children:"'invalid_credentials'"}),"、\r\n",(0,n.jsx)(e.code,{children:"'session_expired'"})," 等)的 ",(0,n.jsx)(e.code,{children:"AuthException"}),",这样失败就能映射为\r\n",(0,n.jsx)(e.a,{href:"Errors",children:"Errors"})," 里的具体异常类型。"]}),"\n"]}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Password users and Google users end up with the same AuthSession shape."})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 密码用户与 Google 用户最终得到的都是同一种 AuthSession。"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Credentials"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(username"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" user, password"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pass));"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"loginWith"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((strategy) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" signInWithGoogle"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(context));"})]})]})}),"\n",(0,n.jsxs)(e.p,{children:["Your UI only ever reads ",(0,n.jsx)(e.code,{children:"state.isAuthenticated"}),", and your network layer only ever\r\nreads ",(0,n.jsx)(e.code,{children:"auth.validAccessToken()"})," — regardless of how the user signed in."]}),"\n",(0,n.jsxs)(e.p,{children:["你的界面只需要读 ",(0,n.jsx)(e.code,{children:"state.isAuthenticated"}),",网络层只需要读 ",(0,n.jsx)(e.code,{children:"auth.validAccessToken()"}),"\r\n——无需关心用户是哪种方式登录的。"]}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"loginWith"})," covers any flow you drive yourself:"]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"loginWith"})," 适用于任何由你驱动的流程:"]}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsx)(e.li,{children:"Magic links / email OTP / 魔法链接、邮箱验证码"}),"\n",(0,n.jsx)(e.li,{children:"Passkeys / WebAuthn"}),"\n",(0,n.jsx)(e.li,{children:"Biometric re-unlock (load a locked session and re-mint tokens) / 生物识别解锁"}),"\n",(0,n.jsx)(e.li,{children:"Migrating from another auth SDK / 从其它认证 SDK 迁移"}),"\n"]}),"\n",(0,n.jsx)(e.h2,{id:s[5].id,children:s[5].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — what your strategy must implement / 策略需要实现什么"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Auth-State-Machine",children:"Auth State Machine"})," — the states this flow emits / 该流程发出的状态"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Errors",children:"Errors"})," — typed exceptions and codes / 类型化异常与 code"]}),"\n"]})]})},"/Third-Party-Login",{filePath:"pages/Third-Party-Login.md",timestamp:178966094e4,pageMap:t.v,frontMatter:{},title:"Third-Party Login / 第三方登录"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=6662)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Token-Store-efeab42b53dd2d2e.js b/docs/_next/static/chunks/pages/Token-Store-efeab42b53dd2d2e.js
new file mode 100644
index 0000000..c5d9805
--- /dev/null
+++ b/docs/_next/static/chunks/pages/Token-Store-efeab42b53dd2d2e.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[909],{8560:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Token-Store",function(){return e(9327)}])},9327:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var r=e(5893),h=e(7812),n=e(7080),t=e(8925);function l(i){return[{value:"The contract / 契约",id:"the-contract--契约",depth:2},{value:"In-memory (ships in-core) / 内存实现(内核自带)",id:"in-memory-ships-in-core--内存实现内核自带",depth:2},{value:"Secure storage (production) / 安全存储(生产)",id:"secure-storage-production--安全存储生产",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...(0,t.a)(),...i.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.h1,{children:"Token Store / 令牌存储"}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"TokenStore"})," is the ",(0,r.jsx)(e.strong,{children:"only"})," persistence surface. The core never touches disk, secure storage, or ",(0,r.jsx)(e.code,{children:"SharedPreferences"})," directly — you decide where tokens live."]}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"TokenStore"})," 是",(0,r.jsx)(e.strong,{children:"唯一"}),"的持久化接口。内核绝不直接访问磁盘、安全存储或 ",(0,r.jsx)(e.code,{children:"SharedPreferences"}),"——由你决定令牌存放位置。"]}),"\n",(0,r.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,r.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,r.jsxs)(e.code,{children:[(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"abstract"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" TokenStore"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"save"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session);"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?> "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"load"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"clear"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,r.jsx)(e.span,{children:(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"AuthManager"})," calls ",(0,r.jsx)(e.code,{children:"load()"})," during ",(0,r.jsx)(e.code,{children:"restore()"}),", ",(0,r.jsx)(e.code,{children:"save()"})," after every successful login/refresh, and ",(0,r.jsx)(e.code,{children:"clear()"})," on logout or a failed refresh."]}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"AuthManager"})," 在 ",(0,r.jsx)(e.code,{children:"restore()"})," 时调用 ",(0,r.jsx)(e.code,{children:"load()"}),",每次登录/刷新成功后调用 ",(0,r.jsx)(e.code,{children:"save()"}),",在登出或刷新失败失败时调用 ",(0,r.jsx)(e.code,{children:"clear()"}),"。"]}),"\n",(0,r.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"InMemoryTokenStore"})," is the default. It survives process restarts? No — it is in-memory only, so the session is lost on restart. Use it for tests and quick prototypes."]}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"InMemoryTokenStore"})," 是默认实现,仅存在于内存,进程重启后会话丢失。适用于测试与原型。"]}),"\n",(0,r.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,r.jsx)(e.code,{children:(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(strategy"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" s, tokenStore"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InMemoryTokenStore"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]})})}),"\n",(0,r.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"example/lib/secure_token_store.dart"})," shows a ",(0,r.jsx)(e.code,{children:"flutter_secure_storage"}),"-backed reference implementation. Adapt it for your app:"]}),"\n",(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"example/lib/secure_token_store.dart"})," 提供了基于 ",(0,r.jsx)(e.code,{children:"flutter_secure_storage"})," 的参考实现,可据此改造:"]}),"\n",(0,r.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,r.jsxs)(e.code,{children:[(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SecureTokenStore"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" implements"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" TokenStore"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FlutterSecureStorage"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,r.jsx)(e.span,{children:(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"save"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" s) "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box."}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"write"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(key"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zero_auth'"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", value"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" jsonEncode"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(s."}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toJson"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()));"})]}),"\n",(0,r.jsx)(e.span,{children:(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?> "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"load"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" raw "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box."}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"read"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(key"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zero_auth'"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" raw "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" ?"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" :"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthSession"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromJson"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"jsonDecode"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(raw));"})]}),"\n",(0,r.jsx)(e.span,{children:(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,r.jsx)(e.span,{children:(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,r.jsxs)(e.span,{children:[(0,r.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"clear"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() "}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box."}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"delete"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(key"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zero_auth'"}),(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,r.jsx)(e.span,{children:(0,r.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,r.jsxs)(e.blockquote,{children:["\n",(0,r.jsxs)(e.p,{children:["Persist tokens only in OS-backed secure storage (Keychain / Keystore). Never store refresh tokens in plain ",(0,r.jsx)(e.code,{children:"SharedPreferences"}),"."]}),"\n",(0,r.jsxs)(e.p,{children:["令牌只应存放在操作系统级安全存储(Keychain / Keystore)中,切勿把刷新令牌明文存入 ",(0,r.jsx)(e.code,{children:"SharedPreferences"}),"。"]}),"\n"]}),"\n",(0,r.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,r.jsxs)(e.ul,{children:["\n",(0,r.jsxs)(e.li,{children:[(0,r.jsx)(e.a,{href:"Persistence",children:"Session Persistence"})," — persist sessions across restarts (serialization + reference stores) / 跨重启持久化会话(序列化与参考存储)"]}),"\n",(0,r.jsxs)(e.li,{children:[(0,r.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — The other boundary / 另一个边界"]}),"\n",(0,r.jsxs)(e.li,{children:[(0,r.jsx)(e.a,{href:"Errors",children:"Errors"})," — What ",(0,r.jsx)(e.code,{children:"load()"})," failures become / ",(0,r.jsx)(e.code,{children:"load()"})," 失败会变成什么"]}),"\n"]})]})},"/Token-Store",{filePath:"pages/Token-Store.md",timestamp:1789600805e3,pageMap:n.v,frontMatter:{},title:"Token Store / 令牌存储"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=8560)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Token-Store-f3901d9b893ae812.js b/docs/_next/static/chunks/pages/Token-Store-f3901d9b893ae812.js
deleted file mode 100644
index e438aba..0000000
--- a/docs/_next/static/chunks/pages/Token-Store-f3901d9b893ae812.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[909],{8560:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Token-Store",function(){return e(9327)}])},9327:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return l}});var h=e(5893),r=e(7812),n=e(7080),t=e(8925);function l(i){return[{value:"The contract / 契约",id:"the-contract--契约",depth:2},{value:"In-memory (ships in-core) / 内存实现(内核自带)",id:"in-memory-ships-in-core--内存实现内核自带",depth:2},{value:"Secure storage (production) / 安全存储(生产)",id:"secure-storage-production--安全存储生产",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,r.c)(function(i){let{toc:s=l(i)}=i,e={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...(0,t.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Token Store / 令牌存储"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"TokenStore"})," is the ",(0,h.jsx)(e.strong,{children:"only"})," persistence surface. The core never touches disk, secure storage, or ",(0,h.jsx)(e.code,{children:"SharedPreferences"})," directly — you decide where tokens live."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"TokenStore"})," 是",(0,h.jsx)(e.strong,{children:"唯一"}),"的持久化接口。内核绝不直接访问磁盘、安全存储或 ",(0,h.jsx)(e.code,{children:"SharedPreferences"}),"——由你决定令牌存放位置。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"abstract"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" class"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" TokenStore"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"save"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"load"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"clear"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"AuthManager"})," calls ",(0,h.jsx)(e.code,{children:"load()"})," during ",(0,h.jsx)(e.code,{children:"restore()"}),", ",(0,h.jsx)(e.code,{children:"save()"})," after every successful login/refresh, and ",(0,h.jsx)(e.code,{children:"clear()"})," on logout or a failed refresh."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"AuthManager"})," 在 ",(0,h.jsx)(e.code,{children:"restore()"})," 时调用 ",(0,h.jsx)(e.code,{children:"load()"}),",每次登录/刷新成功后调用 ",(0,h.jsx)(e.code,{children:"save()"}),",在登出或刷新失败失败时调用 ",(0,h.jsx)(e.code,{children:"clear()"}),"。"]}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"InMemoryTokenStore"})," is the default. It survives process restarts? No — it is in-memory only, so the session is lost on restart. Use it for tests and quick prototypes."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"InMemoryTokenStore"})," 是默认实现,仅存在于内存,进程重启后会话丢失。适用于测试与原型。"]}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsx)(e.code,{children:(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(strategy"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" s, tokenStore"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InMemoryTokenStore"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]})})}),"\n",(0,h.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"example/lib/secure_token_store.dart"})," shows a ",(0,h.jsx)(e.code,{children:"flutter_secure_storage"}),"-backed reference implementation. Adapt it for your app:"]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"example/lib/secure_token_store.dart"})," 提供了基于 ",(0,h.jsx)(e.code,{children:"flutter_secure_storage"})," 的参考实现,可据此改造:"]}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SecureTokenStore"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" implements"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" TokenStore"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FlutterSecureStorage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"save"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" s) "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"write"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(key"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zero_auth'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", value"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" jsonEncode"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(s."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toJson"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()));"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"load"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" raw "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"read"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(key"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zero_auth'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" raw "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" ?"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" :"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthSession"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromJson"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"jsonDecode"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(raw));"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"clear"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" _box."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"delete"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(key"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zero_auth'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:["Persist tokens only in OS-backed secure storage (Keychain / Keystore). Never store refresh tokens in plain ",(0,h.jsx)(e.code,{children:"SharedPreferences"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:["令牌只应存放在操作系统级安全存储(Keychain / Keystore)中,切勿把刷新令牌明文存入 ",(0,h.jsx)(e.code,{children:"SharedPreferences"}),"。"]}),"\n"]}),"\n",(0,h.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,h.jsxs)(e.ul,{children:["\n",(0,h.jsxs)(e.li,{children:[(0,h.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — The other boundary / 另一个边界"]}),"\n",(0,h.jsxs)(e.li,{children:[(0,h.jsx)(e.a,{href:"Errors",children:"Errors"})," — What ",(0,h.jsx)(e.code,{children:"load()"})," failures become / ",(0,h.jsx)(e.code,{children:"load()"})," 失败会变成什么"]}),"\n"]})]})},"/Token-Store",{filePath:"pages/Token-Store.md",pageMap:n.v,frontMatter:{},title:"Token Store / 令牌存储"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=8560)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/Usage-882d908f033c5eda.js b/docs/_next/static/chunks/pages/Usage-929e5120b89b23b6.js
similarity index 87%
rename from docs/_next/static/chunks/pages/Usage-882d908f033c5eda.js
rename to docs/_next/static/chunks/pages/Usage-929e5120b89b23b6.js
index 6bb966a..a73e2fe 100644
--- a/docs/_next/static/chunks/pages/Usage-882d908f033c5eda.js
+++ b/docs/_next/static/chunks/pages/Usage-929e5120b89b23b6.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[848],{4276:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Usage",function(){return e(1258)}])},1258:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return a}});var n=e(5893),t=e(7812),r=e(7080),h=e(8925);function a(i){let s={code:"code",...(0,h.a)()};return[{value:"Three-step integration / 三步集成",id:"three-step-integration--三步集成",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:["1. Implement ",(0,n.jsx)(s.code,{children:"AuthStrategy"})," / 实现后端边界"]}),id:"1-implement-authstrategy--实现后端边界",depth:3},{value:(0,n.jsxs)(n.Fragment,{children:["2. Create ",(0,n.jsx)(s.code,{children:"AuthManager"})," and restore / 创建管理器并恢复"]}),id:"2-create-authmanager-and-restore--创建管理器并恢复",depth:3},{value:"3. Drive the UI from the state stream / 用状态流驱动界面",id:"3-drive-the-ui-from-the-state-stream--用状态流驱动界面",depth:3},{value:"Operations / 操作",id:"operations--操作",depth:2},{value:"Token refresh & expiry / 令牌刷新与过期",id:"token-refresh--expiry--令牌刷新与过期",depth:2},{value:"Attaching the bearer token / 附加 Bearer 令牌",id:"attaching-the-bearer-token--附加-bearer-令牌",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,t.c)(function(i){let{toc:s=a(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,h.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Usage / 使用指南"}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.h3,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(username, password);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"register"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"register"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(username, password);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"logout"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"logout"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"refresh"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"refresh"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session);"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h3,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InMemoryTokenStore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"restore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(); "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// rehydrate a persisted session / 恢复持久化会话"})]})]})}),"\n",(0,n.jsx)(e.h3,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" for"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" state "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth.state) {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // render based on state / 根据状态渲染"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Method"}),(0,n.jsx)(e.th,{children:"Description"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"restore()"})}),(0,n.jsx)(e.td,{children:"Rehydrate the persisted session at startup / 启动时恢复会话"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"login(username, password)"})}),(0,n.jsxs)(e.td,{children:["Authenticate and enter ",(0,n.jsx)(e.code,{children:"Authenticated"})," / 登录并进入已认证"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"register(username, password)"})}),(0,n.jsx)(e.td,{children:"Register and authenticate / 注册并认证"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"logout()"})}),(0,n.jsx)(e.td,{children:"Clear the session / 清除会话"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"refresh()"})}),(0,n.jsx)(e.td,{children:"Silent token refresh — concurrent calls share one flight / 静默刷新,并发共享单飞"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"tokenSource"})}),(0,n.jsxs)(e.td,{children:["An ",(0,n.jsx)(e.code,{children:"AuthTokenSource"})," for HTTP clients / 供 HTTP 客户端使用的令牌源"]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[5].id,children:s[5].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthSession"})," exposes ",(0,n.jsx)(e.code,{children:"isExpired"})," so callers can refresh proactively. ",(0,n.jsx)(e.code,{children:"refresh()"})," is single-flight: if several callers request a refresh at once, only one network call is made and its result is shared."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthSession"})," 提供 ",(0,n.jsx)(e.code,{children:"isExpired"}),",调用方可主动刷新。",(0,n.jsx)(e.code,{children:"refresh()"})," 为单飞:多个调用方同时请求刷新时,只发起一次网络调用并共享结果。 A failed refresh clears the session and emits ",(0,n.jsx)(e.code,{children:"AuthError"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:["刷新失败会清空会话并发出 ",(0,n.jsx)(e.code,{children:"AuthError"}),"。"]}),"\n",(0,n.jsx)(e.h2,{id:s[6].id,children:s[6].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthManager"})," implements ",(0,n.jsx)(e.code,{children:"AuthTokenSource"}),", so a Dio interceptor can read the current token without depending on the manager. See ",(0,n.jsx)(e.a,{href:"Network-Integration",children:"Network Integration"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthManager"})," 实现了 ",(0,n.jsx)(e.code,{children:"AuthTokenSource"}),",Dio 拦截器可在不依赖管理器的情况下读取当前令牌。详见",(0,n.jsx)(e.a,{href:"Network-Integration",children:"网络集成"}),"。"]}),"\n",(0,n.jsx)(e.h2,{id:s[7].id,children:s[7].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Auth-State-Machine",children:"Auth State Machine"})," — State lifecycle details / 状态机细节"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — Full ",(0,n.jsx)(e.code,{children:"AuthStrategy"})," contract / 完整后端契约"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Errors",children:"Errors"})," — Exception & ",(0,n.jsx)(e.code,{children:"Result"})," model / 异常与结果模型"]}),"\n"]})]})},"/Usage",{filePath:"pages/Usage.md",pageMap:r.v,frontMatter:{},title:"Usage / 使用指南"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=4276)}),_N_E=i.O()}]);
\ No newline at end of file
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[848],{4276:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Usage",function(){return e(1258)}])},1258:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return a}});var n=e(5893),t=e(7812),r=e(7080),h=e(8925);function a(i){let s={code:"code",...(0,h.a)()};return[{value:"Three-step integration / 三步集成",id:"three-step-integration--三步集成",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:["1. Implement ",(0,n.jsx)(s.code,{children:"AuthStrategy"})," / 实现后端边界"]}),id:"1-implement-authstrategy--实现后端边界",depth:3},{value:(0,n.jsxs)(n.Fragment,{children:["2. Create ",(0,n.jsx)(s.code,{children:"AuthManager"})," and restore / 创建管理器并恢复"]}),id:"2-create-authmanager-and-restore--创建管理器并恢复",depth:3},{value:"3. Drive the UI from the state stream / 用状态流驱动界面",id:"3-drive-the-ui-from-the-state-stream--用状态流驱动界面",depth:3},{value:"Operations / 操作",id:"operations--操作",depth:2},{value:"Token refresh & expiry / 令牌刷新与过期",id:"token-refresh--expiry--令牌刷新与过期",depth:2},{value:"Attaching the bearer token / 附加 Bearer 令牌",id:"attaching-the-bearer-token--附加-bearer-令牌",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}s.default=(0,t.c)(function(i){let{toc:s=a(i)}=i,e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,h.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Usage / 使用指南"}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.h3,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"login"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(username, password);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"register"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" username, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" password) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"register"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(username, password);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"logout"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"logout"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"refresh"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"AuthSession"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" session) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" myApi."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"refresh"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(session);"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h3,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" AuthManager"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" strategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyAuthStrategy"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenStore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" InMemoryTokenStore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"restore"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(); "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// rehydrate a persisted session / 恢复持久化会话"})]})]})}),"\n",(0,n.jsx)(e.h3,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" for"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" state "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" auth.state) {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // render based on state / 根据状态渲染"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Method"}),(0,n.jsx)(e.th,{children:"Description"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"restore()"})}),(0,n.jsx)(e.td,{children:"Rehydrate the persisted session at startup / 启动时恢复会话"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"login(username, password)"})}),(0,n.jsxs)(e.td,{children:["Authenticate and enter ",(0,n.jsx)(e.code,{children:"Authenticated"})," / 登录并进入已认证"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"register(username, password)"})}),(0,n.jsx)(e.td,{children:"Register and authenticate / 注册并认证"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"logout()"})}),(0,n.jsx)(e.td,{children:"Clear the session / 清除会话"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"refresh()"})}),(0,n.jsx)(e.td,{children:"Silent token refresh — concurrent calls share one flight / 静默刷新,并发共享单飞"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"tokenSource"})}),(0,n.jsxs)(e.td,{children:["An ",(0,n.jsx)(e.code,{children:"AuthTokenSource"})," for HTTP clients / 供 HTTP 客户端使用的令牌源"]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[5].id,children:s[5].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthSession"})," exposes ",(0,n.jsx)(e.code,{children:"isExpired"})," so callers can refresh proactively. ",(0,n.jsx)(e.code,{children:"refresh()"})," is single-flight: if several callers request a refresh at once, only one network call is made and its result is shared."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthSession"})," 提供 ",(0,n.jsx)(e.code,{children:"isExpired"}),",调用方可主动刷新。",(0,n.jsx)(e.code,{children:"refresh()"})," 为单飞:多个调用方同时请求刷新时,只发起一次网络调用并共享结果。 A failed refresh clears the session and emits ",(0,n.jsx)(e.code,{children:"AuthError"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:["刷新失败会清空会话并发出 ",(0,n.jsx)(e.code,{children:"AuthError"}),"。"]}),"\n",(0,n.jsx)(e.h2,{id:s[6].id,children:s[6].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthManager"})," implements ",(0,n.jsx)(e.code,{children:"AuthTokenSource"}),", so a Dio interceptor can read the current token without depending on the manager. See ",(0,n.jsx)(e.a,{href:"Network-Integration",children:"Network Integration"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"AuthManager"})," 实现了 ",(0,n.jsx)(e.code,{children:"AuthTokenSource"}),",Dio 拦截器可在不依赖管理器的情况下读取当前令牌。详见",(0,n.jsx)(e.a,{href:"Network-Integration",children:"网络集成"}),"。"]}),"\n",(0,n.jsx)(e.h2,{id:s[7].id,children:s[7].value}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Auth-State-Machine",children:"Auth State Machine"})," — State lifecycle details / 状态机细节"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Backend-Strategy",children:"Backend Strategy"})," — Full ",(0,n.jsx)(e.code,{children:"AuthStrategy"})," contract / 完整后端契约"]}),"\n",(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.a,{href:"Errors",children:"Errors"})," — Exception & ",(0,n.jsx)(e.code,{children:"Result"})," model / 异常与结果模型"]}),"\n"]})]})},"/Usage",{filePath:"pages/Usage.md",timestamp:1789598212e3,pageMap:r.v,frontMatter:{},title:"Usage / 使用指南"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=4276)}),_N_E=i.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/index-3f32cd0b8ea33fd9.js b/docs/_next/static/chunks/pages/index-3f32cd0b8ea33fd9.js
deleted file mode 100644
index 63e8197..0000000
--- a/docs/_next/static/chunks/pages/index-3f32cd0b8ea33fd9.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[405],{2725:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return t(4991)}])},4991:function(e,n,t){"use strict";t.r(n),t.d(n,{useTOC:function(){return a}});var r=t(5893),s=t(7812),i=t(7080),d=t(8925);function a(e){return[{value:"✨ Features / 功能特性",id:"-features--功能特性",depth:2},{value:"\uD83D\uDCDA Table of Contents / 目录",id:"-table-of-contents--目录",depth:2},{value:"\uD83D\uDD17 Links / 链接",id:"-links--链接",depth:2},{value:"\uD83D\uDCC4 License / 许可证",id:"-license--许可证",depth:2}]}n.default=(0,s.c)(function(e){let{toc:n=a(e)}=e,t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{children:"Zero Auth"}),"\n",(0,r.jsxs)(t.p,{children:["A backend-agnostic auth state machine & session lifecycle core for Dart/Flutter. Pure Dart, headless, no HTTP/SDK/native code. Wire your own backend via ",(0,r.jsx)(t.code,{children:"AuthStrategy"})," and your own persistence via ",(0,r.jsx)(t.code,{children:"TokenStore"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["一个后端无关的认证状态机与会话生命周期内核,面向 Dart/Flutter。纯 Dart、无头(headless),不含 HTTP、SDK 或原生代码。通过 ",(0,r.jsx)(t.code,{children:"AuthStrategy"})," 接入自有后端,通过 ",(0,r.jsx)(t.code,{children:"TokenStore"})," 接入自有持久化层。"]}),"\n",(0,r.jsx)(t.h2,{id:n[0].id,children:n[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Feature"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Backend-agnostic"})}),(0,r.jsxs)(t.td,{children:["Implement only ",(0,r.jsx)(t.code,{children:"login"}),"/",(0,r.jsx)(t.code,{children:"register"}),"/",(0,r.jsx)(t.code,{children:"logout"}),"/",(0,r.jsx)(t.code,{children:"refresh"}),"; REST, gRPC, Firebase or a private RPC are equally valid targets / 只需实现四个方法,REST、gRPC、Firebase 或私有 RPC 均可接入"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Auth State Machine"})}),(0,r.jsxs)(t.td,{children:["Sealed ",(0,r.jsx)(t.code,{children:"Unauthenticated → Authenticating → Authenticated → AuthError"})," lifecycle on a ",(0,r.jsx)(t.code,{children:"Stream"})," that replays the latest value to new listeners / 密封状态机 + 重放最近值的状态流,首帧即可渲染正确界面"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Silent Restore"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"restore()"})," rehydrates the persisted session at startup / 启动时静默恢复持久化会话"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Single-flight Refresh"})}),(0,r.jsxs)(t.td,{children:["Concurrent ",(0,r.jsx)(t.code,{children:"refresh()"})," calls share one in-flight request instead of stampeding the backend / 并发刷新共享同一次请求,避免冲击后端"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Pluggable Persistence"})}),(0,r.jsxs)(t.td,{children:["The only persistence surface is ",(0,r.jsx)(t.code,{children:"TokenStore.save/load/clear"}),"; ",(0,r.jsx)(t.code,{children:"InMemoryTokenStore"})," ships in-core / 唯一的持久化接口,内核自带内存实现"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Typed Session"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"AuthSession"})," carries access/refresh tokens, expiry (",(0,r.jsx)(t.code,{children:"isExpired"}),"), user id, display name and raw claims / 强类型会话,无需手工解析令牌"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Unified Errors"})}),(0,r.jsxs)(t.td,{children:["Every failure maps to ",(0,r.jsx)(t.code,{children:"AppException"})," (",(0,r.jsx)(t.code,{children:"AuthException"})," for auth cases) or a ",(0,r.jsx)(t.code,{children:"Result"})," wrapper; raw exceptions never cross the public surface / 统一异常与结果,裸异常不越界"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Network Integration"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"AuthManager"})," itself is an ",(0,r.jsx)(t.code,{children:"AuthTokenSource"}),", so a Dio interceptor can attach ",(0,r.jsx)(t.code,{children:"Authorization: Bearer"})," without depending on the manager / 管理器即令牌源,Dio 拦截器零依赖附加令牌"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Runnable Example"})}),(0,r.jsxs)(t.td,{children:["A full Flutter demo app (Android/iOS/Web/Windows) plus a zero-dependency ",(0,r.jsx)(t.code,{children:"dart:io"})," demo backend / 完整 Flutter 示例与一个零依赖演示后端"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Cross-platform"})}),(0,r.jsx)(t.td,{children:"Pure Dart — runs anywhere Dart or Flutter runs / 纯 Dart,跨平台"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[1].id,children:n[1].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Page"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Getting-Started",children:"Getting Started"})}),(0,r.jsx)(t.td,{children:"Quick start guide / 快速开始"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Installation",children:"Installation"})}),(0,r.jsx)(t.td,{children:"How to install / 安装方式"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Usage",children:"Usage"})}),(0,r.jsx)(t.td,{children:"Detailed usage / 详细使用"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Auth-State-Machine",children:"Auth State Machine"})}),(0,r.jsx)(t.td,{children:"State lifecycle & stream / 状态机与状态流"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Backend-Strategy",children:"Backend Strategy"})}),(0,r.jsxs)(t.td,{children:["Implement ",(0,r.jsx)(t.code,{children:"AuthStrategy"})," / 实现后端边界"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Token-Store",children:"Token Store"})}),(0,r.jsx)(t.td,{children:"Persistence boundary / 持久化边界"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Network-Integration",children:"Network Integration"})}),(0,r.jsx)(t.td,{children:"Dio interceptor & token source / 网络集成与拦截器"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Errors",children:"Errors"})}),(0,r.jsxs)(t.td,{children:["Exception & ",(0,r.jsx)(t.code,{children:"Result"})," model / 异常与结果模型"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Configuration",children:"Configuration"})}),(0,r.jsx)(t.td,{children:"Configuration options / 配置说明"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"FAQ",children:"FAQ"})}),(0,r.jsx)(t.td,{children:"Frequently asked questions / 常见问题"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[2].id,children:n[2].value}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://github.com/zero-labsco/zero_auth",children:"GitHub"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://www.zerolabsco.com/",children:"Official Website"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://pub.dev/packages/zero_auth",children:"pub.dev"})}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:n[3].id,children:n[3].value}),"\n",(0,r.jsxs)(t.p,{children:["This project is licensed under the ",(0,r.jsx)(t.strong,{children:"Mozilla Public License 2.0 (MPL-2.0)"}),"."]}),"\n",(0,r.jsx)(t.p,{children:"本项目采用 Mozilla Public License 2.0 (MPL-2.0) 许可证。"}),"\n",(0,r.jsx)(t.p,{children:"This package is provided “as is”, without warranty of any kind. The author assumes no responsibility or liability for the functionality, security, or any consequences arising from the use of modified versions or derivative projects."}),"\n",(0,r.jsx)(t.p,{children:"本包按”原样”提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及任何使用后果承担责任。"})]})},"/",{filePath:"pages/index.md",pageMap:i.v,frontMatter:{},title:"Zero Auth"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(e,n,t){"use strict";t.d(n,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=2725)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/chunks/pages/index-b1e2daa6b933b65e.js b/docs/_next/static/chunks/pages/index-b1e2daa6b933b65e.js
new file mode 100644
index 0000000..0641eca
--- /dev/null
+++ b/docs/_next/static/chunks/pages/index-b1e2daa6b933b65e.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[405],{2725:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return t(4991)}])},4991:function(e,n,t){"use strict";t.r(n),t.d(n,{useTOC:function(){return a}});var r=t(5893),s=t(7812),i=t(7080),d=t(8925);function a(e){return[{value:"✨ Features / 功能特性",id:"-features--功能特性",depth:2},{value:"\uD83D\uDCDA Table of Contents / 目录",id:"-table-of-contents--目录",depth:2},{value:"\uD83D\uDD17 Links / 链接",id:"-links--链接",depth:2},{value:"\uD83D\uDCC4 License / 许可证",id:"-license--许可证",depth:2}]}n.default=(0,s.c)(function(e){let{toc:n=a(e)}=e,t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{children:"Zero Auth"}),"\n",(0,r.jsxs)(t.p,{children:["A backend-agnostic auth state machine & session lifecycle core for Dart/Flutter. Pure Dart, headless, no HTTP/SDK/native code. Wire your own backend via ",(0,r.jsx)(t.code,{children:"AuthStrategy"})," and your own persistence via ",(0,r.jsx)(t.code,{children:"TokenStore"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["一个后端无关的认证状态机与会话生命周期内核,面向 Dart/Flutter。纯 Dart、无头(headless),不含 HTTP、SDK 或原生代码。通过 ",(0,r.jsx)(t.code,{children:"AuthStrategy"})," 接入自有后端,通过 ",(0,r.jsx)(t.code,{children:"TokenStore"})," 接入自有持久化层。"]}),"\n",(0,r.jsx)(t.h2,{id:n[0].id,children:n[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Feature"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Backend-agnostic"})}),(0,r.jsxs)(t.td,{children:["Implement only ",(0,r.jsx)(t.code,{children:"login"}),"/",(0,r.jsx)(t.code,{children:"register"}),"/",(0,r.jsx)(t.code,{children:"logout"}),"/",(0,r.jsx)(t.code,{children:"refresh"}),"; REST, gRPC, Firebase or a private RPC are equally valid targets / 只需实现四个方法,REST、gRPC、Firebase 或私有 RPC 均可接入"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Auth State Machine"})}),(0,r.jsxs)(t.td,{children:["Sealed ",(0,r.jsx)(t.code,{children:"Unauthenticated → Authenticating → Authenticated → AuthError"})," lifecycle on a ",(0,r.jsx)(t.code,{children:"Stream"})," that replays the latest value to new listeners / 密封状态机 + 重放最近值的状态流,首帧即可渲染正确界面"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Silent Restore"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"restore()"})," rehydrates the persisted session at startup / 启动时静默恢复持久化会话"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Single-flight Refresh"})}),(0,r.jsxs)(t.td,{children:["Concurrent ",(0,r.jsx)(t.code,{children:"refresh()"})," calls share one in-flight request instead of stampeding the backend / 并发刷新共享同一次请求,避免冲击后端"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Pluggable Persistence"})}),(0,r.jsxs)(t.td,{children:["The only persistence surface is ",(0,r.jsx)(t.code,{children:"TokenStore.save/load/clear"}),"; ",(0,r.jsx)(t.code,{children:"InMemoryTokenStore"})," ships in-core / 唯一的持久化接口,内核自带内存实现"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Typed Session"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"AuthSession"})," carries access/refresh tokens, expiry (",(0,r.jsx)(t.code,{children:"isExpired"}),"), user id, display name and raw claims / 强类型会话,无需手工解析令牌"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Unified Errors"})}),(0,r.jsxs)(t.td,{children:["Every failure maps to ",(0,r.jsx)(t.code,{children:"AppException"})," (",(0,r.jsx)(t.code,{children:"AuthException"})," for auth cases) or a ",(0,r.jsx)(t.code,{children:"Result"})," wrapper; raw exceptions never cross the public surface / 统一异常与结果,裸异常不越界"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Network Integration"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"AuthManager"})," itself is an ",(0,r.jsx)(t.code,{children:"AuthTokenSource"}),", so a Dio interceptor can attach ",(0,r.jsx)(t.code,{children:"Authorization: Bearer"})," without depending on the manager / 管理器即令牌源,Dio 拦截器零依赖附加令牌"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Session Serialization"})}),(0,r.jsxs)(t.td,{children:[(0,r.jsx)(t.code,{children:"AuthSession.toJson"})," / ",(0,r.jsx)(t.code,{children:"fromJson"})," make persistence a one-liner; a file-based reference store ships for server/CLI / ",(0,r.jsx)(t.code,{children:"AuthSession.toJson"})," / ",(0,r.jsx)(t.code,{children:"fromJson"})," 让持久化一行搞定,并附带面向服务端 / CLI 的文件参考存储"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Proactive Auto-refresh"})}),(0,r.jsxs)(t.td,{children:["Pass ",(0,r.jsx)(t.code,{children:"autoRefreshAhead"})," to renew tokens before expiry (single-flight) / 传入 ",(0,r.jsx)(t.code,{children:"autoRefreshAhead"})," 在过期前自动续期(单飞)"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Runnable Example"})}),(0,r.jsxs)(t.td,{children:["A full Flutter demo app (Android/iOS/Web/Windows) plus a zero-dependency ",(0,r.jsx)(t.code,{children:"dart:io"})," demo backend / 完整 Flutter 示例与一个零依赖演示后端"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Cross-platform"})}),(0,r.jsx)(t.td,{children:"Pure Dart — runs anywhere Dart or Flutter runs / 纯 Dart,跨平台"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[1].id,children:n[1].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Page"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Getting-Started",children:"Getting Started"})}),(0,r.jsx)(t.td,{children:"Quick start guide / 快速开始"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Installation",children:"Installation"})}),(0,r.jsx)(t.td,{children:"How to install / 安装方式"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Usage",children:"Usage"})}),(0,r.jsx)(t.td,{children:"Detailed usage / 详细使用"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Auth-State-Machine",children:"Auth State Machine"})}),(0,r.jsx)(t.td,{children:"State lifecycle & stream / 状态机与状态流"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Backend-Strategy",children:"Backend Strategy"})}),(0,r.jsxs)(t.td,{children:["Implement ",(0,r.jsx)(t.code,{children:"AuthStrategy"})," / 实现后端边界"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Token-Store",children:"Token Store"})}),(0,r.jsx)(t.td,{children:"Persistence boundary / 持久化边界"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Network-Integration",children:"Network Integration"})}),(0,r.jsx)(t.td,{children:"Dio interceptor & token source / 网络集成与拦截器"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Errors",children:"Errors"})}),(0,r.jsxs)(t.td,{children:["Exception & ",(0,r.jsx)(t.code,{children:"Result"})," model / 异常与结果模型"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Configuration",children:"Configuration"})}),(0,r.jsx)(t.td,{children:"Configuration options / 配置说明"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"FAQ",children:"FAQ"})}),(0,r.jsx)(t.td,{children:"Frequently asked questions / 常见问题"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[2].id,children:n[2].value}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://github.com/zero-labsco/zero_auth",children:"GitHub"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://www.zerolabsco.com/",children:"Official Website"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://pub.dev/packages/zero_auth",children:"pub.dev"})}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:n[3].id,children:n[3].value}),"\n",(0,r.jsxs)(t.p,{children:["This project is licensed under the ",(0,r.jsx)(t.strong,{children:"Mozilla Public License 2.0 (MPL-2.0)"}),"."]}),"\n",(0,r.jsx)(t.p,{children:"本项目采用 Mozilla Public License 2.0 (MPL-2.0) 许可证。"}),"\n",(0,r.jsx)(t.p,{children:"This package is provided “as is”, without warranty of any kind. The author assumes no responsibility or liability for the functionality, security, or any consequences arising from the use of modified versions or derivative projects."}),"\n",(0,r.jsx)(t.p,{children:"本包按”原样”提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及任何使用后果承担责任。"})]})},"/",{filePath:"pages/index.md",timestamp:1789600805e3,pageMap:i.v,frontMatter:{},title:"Zero Auth"},"undefined"==typeof RemoteContent?a:RemoteContent.useTOC)},7080:function(e,n,t){"use strict";t.d(n,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--features":{type:"separator",title:"\uD83D\uDD27 Features"},"Auth-State-Machine":"\uD83E\uDDED Auth State Machine","Backend-Strategy":"\uD83D\uDD0C Backend Strategy","Token-Store":"\uD83D\uDCBE Token Store","Network-Integration":"\uD83C\uDF10 Network Integration","--cookbook":{type:"separator",title:"\uD83C\uDF73 Cookbook"},"Third-Party-Login":"\uD83D\uDD11 Third-Party Login","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},Errors:"⚠️ Errors",Configuration:"⚙️ Configuration",Persistence:"\uD83D\uDCBD Session Persistence","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"Auth-State-Machine",route:"/Auth-State-Machine",frontMatter:{sidebarTitle:"Auth State Machine"}},{name:"Backend-Strategy",route:"/Backend-Strategy",frontMatter:{sidebarTitle:"Backend Strategy"}},{name:"Configuration",route:"/Configuration",frontMatter:{sidebarTitle:"Configuration"}},{name:"Errors",route:"/Errors",frontMatter:{sidebarTitle:"Errors"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Network-Integration",route:"/Network-Integration",frontMatter:{sidebarTitle:"Network Integration"}},{name:"Persistence",route:"/Persistence",frontMatter:{sidebarTitle:"Persistence"}},{name:"Third-Party-Login",route:"/Third-Party-Login",frontMatter:{sidebarTitle:"Third Party Login"}},{name:"Token-Store",route:"/Token-Store",frontMatter:{sidebarTitle:"Token Store"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=2725)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/docs/_next/static/xA0AkSUGK7rA_hFr787Ng/_buildManifest.js b/docs/_next/static/xA0AkSUGK7rA_hFr787Ng/_buildManifest.js
deleted file mode 100644
index 82eedc3..0000000
--- a/docs/_next/static/xA0AkSUGK7rA_hFr787Ng/_buildManifest.js
+++ /dev/null
@@ -1 +0,0 @@
-self.__BUILD_MANIFEST=function(t){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[t,"static/chunks/pages/index-3f32cd0b8ea33fd9.js"],"/Auth-State-Machine":[t,"static/chunks/pages/Auth-State-Machine-0602992353358b58.js"],"/Backend-Strategy":[t,"static/chunks/pages/Backend-Strategy-ccb76f118248a4ea.js"],"/Configuration":[t,"static/chunks/pages/Configuration-0a11f8b0ddbb5cde.js"],"/Errors":[t,"static/chunks/pages/Errors-4c6a1995069645ad.js"],"/FAQ":[t,"static/chunks/pages/FAQ-3be268e4c7e2ac58.js"],"/Getting-Started":[t,"static/chunks/pages/Getting-Started-45e6ee34ef6f3f61.js"],"/Installation":[t,"static/chunks/pages/Installation-38862789c9f657bb.js"],"/Network-Integration":[t,"static/chunks/pages/Network-Integration-76d31e3c99016d3a.js"],"/Token-Store":[t,"static/chunks/pages/Token-Store-f3901d9b893ae812.js"],"/Usage":[t,"static/chunks/pages/Usage-882d908f033c5eda.js"],"/_error":["static/chunks/pages/_error-7a92967bea80186d.js"],"/_meta":["static/chunks/pages/_meta-b47e7a01bb6b7929.js"],sortedPages:["/","/Auth-State-Machine","/Backend-Strategy","/Configuration","/Errors","/FAQ","/Getting-Started","/Installation","/Network-Integration","/Token-Store","/Usage","/_app","/_error","/_meta"]}}("static/chunks/812-0b5992150f379e9a.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
index 911ccfb..a472aa8 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,4 +1,4 @@
-
🏠 Home
Zero Auth
+
🏠 Home
Zero Auth
A backend-agnostic auth state machine & session lifecycle core for Dart/Flutter. Pure Dart, headless, no HTTP/SDK/native code. Wire your own backend via AuthStrategy and your own persistence via TokenStore.
Implement only login/register/logout/refresh; REST, gRPC, Firebase or a private RPC are equally valid targets / 只需实现四个方法,REST、gRPC、Firebase 或私有 RPC 均可接入
Auth State Machine
Sealed Unauthenticated → Authenticating → Authenticated → AuthError lifecycle on a Stream<AuthState> that replays the latest value to new listeners / 密封状态机 + 重放最近值的状态流,首帧即可渲染正确界面
Silent Restore
restore() rehydrates the persisted session at startup / 启动时静默恢复持久化会话
Single-flight Refresh
Concurrent refresh() calls share one in-flight request instead of stampeding the backend / 并发刷新共享同一次请求,避免冲击后端
Pluggable Persistence
The only persistence surface is TokenStore.save/load/clear; InMemoryTokenStore ships in-core / 唯一的持久化接口,内核自带内存实现
Typed Session
AuthSession carries access/refresh tokens, expiry (isExpired), user id, display name and raw claims / 强类型会话,无需手工解析令牌
Unified Errors
Every failure maps to AppException (AuthException for auth cases) or a Result<T> wrapper; raw exceptions never cross the public surface / 统一异常与结果,裸异常不越界
Network Integration
AuthManager itself is an AuthTokenSource, so a Dio interceptor can attach Authorization: Bearer without depending on the manager / 管理器即令牌源,Dio 拦截器零依赖附加令牌
Runnable Example
A full Flutter demo app (Android/iOS/Web/Windows) plus a zero-dependency dart:io demo backend / 完整 Flutter 示例与一个零依赖演示后端
Cross-platform
Pure Dart — runs anywhere Dart or Flutter runs / 纯 Dart,跨平台
+
+
+
+
+
+
+
+
+
Feature
Description
Backend-agnostic
Implement only login/register/logout/refresh; REST, gRPC, Firebase or a private RPC are equally valid targets / 只需实现四个方法,REST、gRPC、Firebase 或私有 RPC 均可接入
Auth State Machine
Sealed Unauthenticated → Authenticating → Authenticated → AuthError lifecycle on a Stream<AuthState> that replays the latest value to new listeners / 密封状态机 + 重放最近值的状态流,首帧即可渲染正确界面
Silent Restore
restore() rehydrates the persisted session at startup / 启动时静默恢复持久化会话
Single-flight Refresh
Concurrent refresh() calls share one in-flight request instead of stampeding the backend / 并发刷新共享同一次请求,避免冲击后端
Pluggable Persistence
The only persistence surface is TokenStore.save/load/clear; InMemoryTokenStore ships in-core / 唯一的持久化接口,内核自带内存实现
Typed Session
AuthSession carries access/refresh tokens, expiry (isExpired), user id, display name and raw claims / 强类型会话,无需手工解析令牌
Unified Errors
Every failure maps to AppException (AuthException for auth cases) or a Result<T> wrapper; raw exceptions never cross the public surface / 统一异常与结果,裸异常不越界
Network Integration
AuthManager itself is an AuthTokenSource, so a Dio interceptor can attach Authorization: Bearer without depending on the manager / 管理器即令牌源,Dio 拦截器零依赖附加令牌
Session Serialization
AuthSession.toJson / fromJson make persistence a one-liner; a file-based reference store ships for server/CLI / AuthSession.toJson / fromJson 让持久化一行搞定,并附带面向服务端 / CLI 的文件参考存储
Proactive Auto-refresh
Pass autoRefreshAhead to renew tokens before expiry (single-flight) / 传入 autoRefreshAhead 在过期前自动续期(单飞)
Runnable Example
A full Flutter demo app (Android/iOS/Web/Windows) plus a zero-dependency dart:io demo backend / 完整 Flutter 示例与一个零依赖演示后端
Cross-platform
Pure Dart — runs anywhere Dart or Flutter runs / 纯 Dart,跨平台
📚 Table of Contents / 目录
@@ -113,4 +121,4 @@
This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).
本项目采用 Mozilla Public License 2.0 (MPL-2.0) 许可证。
This package is provided “as is”, without warranty of any kind. The author assumes no responsibility or liability for the functionality, security, or any consequences arising from the use of modified versions or derivative projects.
\ No newline at end of file
diff --git a/website/scripts/sync-docs.mjs b/website/scripts/sync-docs.mjs
index a67916f..700eeab 100644
--- a/website/scripts/sync-docs.mjs
+++ b/website/scripts/sync-docs.mjs
@@ -158,7 +158,14 @@ function main() {
const dryRun =
process.argv.includes('--dry-run') || process.env.SYNC_DOCS_DRYRUN === '1';
- if (!websiteSourceChanged() && !pubspecVersionChanged()) {
+ // `--force` bypasses change detection. Needed when the website changes are
+ // already committed (no git diff left) but docs/ still holds a stale build —
+ // e.g. after installing the hook late, or recovering a missed sync.
+ // `--force` 跳过变更检测:当 website 改动已提交(diff 为空)而 docs/ 仍是旧构建时
+ // 需要它,例如 hook 补装较晚或漏同步后的补救。
+ const force = process.argv.includes('--force');
+
+ if (!force && !websiteSourceChanged() && !pubspecVersionChanged()) {
console.log(
'[sync-docs] No website source or pubspec version changes — skipping build.',
);