@archie/反应-sdk
反应钩、提供者和组件 阿奇・巴斯 平台.
建于顶上 @archie/js-sdk,这个软件包提供了与认证状态管理,声明数据获取,实时订阅,文件上传与进度跟踪,以及路由守护的完全反应反应集成.
目录
安装
npm install @archie/js-sdk @archie/react-sdk
# or
pnpm add @archie/js-sdk @archie/react-sdk
同伴依赖性 : react >=18, (中文(简体) ), @archie/js-sdk
快速启动
import { createClient } from '@archie/js-sdk';
import { ArchieProvider, useAuth, useQuery, AuthGuard } from '@archie/react-sdk';
const archie = createClient({
projectId: 'your-project-uuid',
apiKey: 'anon your-api-key',
apiUrl: 'https://your-project.archiecore.com',
environment: 'master',
retries: 3, // automatic retry with backoff (inherited from js-sdk)
timeout: 15_000, // request timeout in ms
});
function App() {
return (
<ArchieProvider client={archie}>
<AuthGuard fallback={<LoginPage />} loadingComponent={<Spinner />}>
<Dashboard />
</AuthGuard>
</ArchieProvider>
);
}
function LoginPage() {
const { signIn } = useAuth();
const handleSubmit = async (email: string, password: string) => {
const { session, error } = await signIn({ email, password });
if (error) console.error(error.message);
};
return <form onSubmit={/* ... */}>/* ... */</form>;
}
function Dashboard() {
const { user, signOut } = useAuth();
const { data, isLoading } = useQuery<{ orders: Order[] }>('{ orders { id total status } }');
return (
<div>
<p>Welcome, {user?.email}</p>
<button onClick={signOut}>Sign Out</button>
{isLoading ? <Spinner /> : <OrderList orders={data?.orders ?? []} />}
</div>
);
}
阿尔奇提供器
通过上下文包装您的 React 应用程序以提供 Archie 客户端和 认证会话状态 .
import { createClient } from '@archie/js-sdk';
import { ArchieProvider } from '@archie/react-sdk';
const archie = createClient({ projectId: '...', apiKey: 'anon ...' });
function App() {
return (
<ArchieProvider client={archie}>
<MyApp />
</ArchieProvider>
);
}
道具 :
| Prop | 类型 | 说明 |
|---|---|---|
client | ArchieClient | 客户实例 createClient() |
children | ReactNode | 儿童成分 |
内部 :
- 创建反应上下文
ArchieClient实例 - 电话
client.auth.waitForInit()挂起以恢复恒定会话 - 订阅
onAuthStateChange并按上下文更新会话 - 提供
{ client, session, isLoading }切入所有子钩
钩子
使用Archie客户端
返回原始数据 ArchieClient 举个例子 用于提供钩外的先进用例.
const archie = useArchieClient();
// Direct access to any module
const jwks = await archie.auth.getJWKS();
掷出 如果在外边使用 <ArchieProvider>。 。 。 .
用户
完全认证状态及操作. 所有同步方法返回 { data/session, error } - 他们从来不扔.
const {
user, // User | null
session, // Session | null
isLoading, // boolean — true until initial session check completes
isAuthenticated, // boolean — shorthand for session !== null
signIn, // (params) => Promise<{ session, error }>
signUp, // (params) => Promise<{ data, error }>
exchangeCode, // ({ code }) => Promise<{ session, error }> — single-use code from a trusted server; session cannot be refreshed
signOut, // () => Promise<void>
confirmSignUp, // (params) => Promise<{ session, error }>
recoverPassword, // (params) => Promise<{ data, error }>
resetPassword, // (params) => Promise<{ data, error }>
refreshSession, // () => Promise<{ session, error }>
} = useAuth();
示例 — 签名
function LoginForm() {
const { signIn, isLoading } = useAuth();
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const { session, error } = await signIn({ email, password });
if (error) {
setError(error.message);
}
// session is automatically updated in context — no manual setState needed
};
return (
<form onSubmit={handleSubmit}>
{error && <p className="error">{error}</p>}
{/* inputs */}
<button disabled={isLoading}>Sign In</button>
</form>
);
}
示例 — 签名流量 :
const { signUp, confirmSignUp } = useAuth();
// Step 1: Register
const { data, error } = await signUp({ email, password });
// data = { userId: '...', message: 'Check your email' }
// Step 2: Confirm with code from email
const { session, error: confirmError } = await confirmSignUp({
email,
code: '123456',
});
示例 密码回收 :
const { recoverPassword, resetPassword } = useAuth();
// Step 1: Request reset
await recoverPassword({ email });
// Step 2: Reset with code
await resetPassword({ email, code: '123456', newPassword: 'newPass!' });
所有方法都记着 useCallback ——安全通过为道具,而不会引起回放.
使用查询
声明性图表QL查询,包含缓存, Stale-while-validated, 民意测验,和自动分解.
const { data, error, isLoading, isRefetching, refetch } = useQuery<T>(
gql, // GraphQL query string
variables?, // Record<string, unknown>
options?, // UseQueryOptions
);
选项 :
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled | boolean | true | 设定 false 以跳过获取(有条件查询) |
refetchInterval | number | —— 说 | 投票间隔( 毫秒) |
refetchOnWindowFocus | boolean | false | 窗口重现焦点时反射 |
onSuccess | (data: T) => void | —— 说 | 在成功获取时调用 |
onError | (error: ArchieError) => void | —— 说 | 调用错误 |
返回 :
| 外地 | 类型 | 说明 |
|---|---|---|
data | T | null | 查询结果 |
error | ArchieError | null | 失败时出错 |
isLoading | boolean | 初始负载为真 |
isRefetching | boolean | 在背景回溯中为真 |
refetch | () => Promise<void> | 手动触发回推 |
行为 :
- 重新确认时: 立即显示缓存数据, 在背景中反省
- 复制: 多个具有相同查询+可变特性的组件共享单个网络请求
- 关于认证更改的自动回放: 当用户的令牌更改时, 所有正在运行的查询都会自动重排
- 无效时自动调试:一个挂载的查询一旦其密钥失效即重新运行(例如通过 a)
useMutation与invalidateQueries; 同一键的同步消费者仍共享一个请求 - 最近的答复-赢: 当键被失效时, 已经在飞行中的反应被丢弃, 而不是用模拟前数据重新油漆视图
- 错误从不空白视图: 失败的再验证集
error但数据已经保留在屏幕上 - 变量跟踪: 深度比较
JSON.stringify——变量变化时的回溯 - 安保部门安全: 无
window访问时间refetchOnWindowFocus已禁用
实例:
// Basic query
const { data, isLoading } = useQuery<{ users: User[] }>('{ users { id email name } }');
// With variables
const { data } = useQuery<{ user: User }>('query($id: ID!) { user(id: $id) { id email } }', {
id: userId,
});
// Conditional query (wait for userId)
const { data } = useQuery<{ user: User }>(
'query($id: ID!) { user(id: $id) { id email } }',
{ id: userId },
{ enabled: !!userId },
);
// Polling every 5 seconds
const { data } = useQuery<{ stats: Stats }>('{ stats { activeUsers requests } }', undefined, {
refetchInterval: 5000,
});
组合
带有缓存的图QL突变无效 .
const { mutate, mutateAsync, data, error, isLoading, reset } = useMutation<T>(
gql, // GraphQL mutation string
options?, // UseMutationOptions
);
选项 :
| 选项 | 类型 | 说明 |
|---|---|---|
onSuccess | (data: T) => void | 成功突变后调用 |
onError | (error: ArchieError) => void | 调用错误 |
onSettled | () => void | 在成功或出错后调用 |
invalidateQueries | string[] | 查询成功后无效的子字符串 —— 每个挂载 useQuery 其密钥匹配反切 |
返回 :
| 外地 | 类型 | 说明 |
|---|---|---|
mutate | (vars?) => void | 火灾和遗忘变异 |
mutateAsync | (vars?) => Promise<T | null> | 等待结果 |
data | T | null | 最后一个成功结果 |
error | ArchieError | null | 上次错误 |
isLoading | boolean | 执行时为真 |
reset | () => void | 清除数据/误差/正在下载 |
示例
const { mutate, isLoading } = useMutation<{ createUser: User }>(
'mutation($input: CreateUserInput!) { createUser(input: $input) { id email } }',
{
invalidateQueries: ['users'],
onSuccess: (data) => toast.success(`Created ${data.createUser.email}`),
},
);
const handleCreate = () => {
mutate({ input: { email: '[email protected]', name: 'John' } });
};
匹配是通过子字符串这样
invalidateQueries: ['id']{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}会反射每一次 包含文本的挂载查询id- 每一个都是真正的网络请求 偏爱 模式特性足以命名您变异的实体。 通过了几个 模式是便宜的:整个阵列是作为一个批次应用的,因此一个查询与 其中不止一个仍然只修补过一次.
用户订阅
通过 WebSocket 实时 GraphQL 订阅. 订阅挂载, 未订阅挂载 .
const { data, error, connectionState } = useSubscription<T>(
gql, // GraphQL subscription string
variables?, // Record<string, unknown>
options?, // UseSubscriptionOptions
);
选项 :
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled | boolean | true | 设定 false 跳过订阅 |
onData | (data: T) => void | —— 说 | 调用每个新值 |
onError | (error: ArchieError) => void | —— 说 | 调用错误 |
返回 :
| 外地 | 类型 | 说明 |
|---|---|---|
data | T | null | 最近订阅价值 |
error | ArchieError | null | 上次错误 |
connectionState | ConnectionState | 'DISCONNECTED' | 'CONNECTING' | 'CONNECTED' | 'RECONNECTING' |
示例
function LiveOrders() {
const { data, connectionState } = useSubscription<{ orderUpdated: Order }>(
'subscription { orderUpdated { id status total } }',
);
return (
<div>
<Badge>{connectionState}</Badge>
{data && <OrderCard order={data.orderUpdated} />}
</div>
);
}
生命周期 : 重新连接由基础自动处理 js-sdk 实时模块(责任后退).
使用文件加载
带有进度跟踪的文件上传 .
const { upload, progress, isUploading, data, error, retry, abort, reset } = useFileUpload();
返回 :
| 外地 | 类型 | 说明 |
|---|---|---|
upload | (file: File | Blob, opts?: FileUploadOptions) => Promise<FileUploadResult | null> | 开始上传;解析结果,或 null 故障/损坏 |
progress | number | 真正的上传进度, 0. 100( 跳出 0 到 100 不使用 XMLHttp 请求) |
fraction | number | 进展与0.1相同 |
isUploading | boolean | 上传时为真 |
data | FileUploadResult | null | { fileId, url, filename, mimetype, size } 成绩报告(url 实值 null 如果搜索失败) |
error | ArchieError | null | 失败时出错 |
retry | () => Promise<FileUploadResult | null> | 重运行最后一个 upload() 带有相同文件和选项 |
abort | () => void | 在飞行中中止上传( E)error.code 实值 REQUEST_ABORTED(中文(简体) ) |
reset | () => void | 清除全部状态 |
FileUploadOptions数字 : { filename?, contentType?, providerType? } (文件名和内容) File's; 一个平原 Blob 不需要类型 contentType) (中文(简体) ). 还有 { onProgress?, signal? }。 。 。 . error.code 是稳定的上传代码( e)FILE_TOO_LARGE, (中文(简体) ), UNSUPPORTED_FILE_TYPE, (中文(简体) ), STORAGE_NOT_ENABLED, (中文(简体) ), UPLOAD_AUTH_REQUIRED, (中文(简体) ), UPLOADS_DISABLED, (中文(简体) ), STORAGE_QUOTA_EXCEEDED, (中文(简体) ), REQUEST_ABORTED, (中文(简体) ), TIMEOUT。浏览器(XMLHttprequest)中的进展是真实的;在节点/SSR中它跳出0到1.
示例
function FileUploader() {
const { upload, progress, isUploading, data, error, reset } = useFileUpload();
return (
<div>
<input
type="file"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) upload(file, { contentType: file.type, filename: file.name });
}}
/>
{isUploading && <ProgressBar value={progress} />}
{data && <p>Uploaded: {data.url ?? data.fileId}</p>}
{error && <p className="error">{error.message}</p>}
{data && <button onClick={reset}>Upload Another</button>}
</div>
);
}
用户
直接返回 REST 模块,用于必须的 REST API 调用 .
const rest = useRest();
// rest.get<T>(path, options?)
// rest.post<T>(path, body?, options?)
// rest.put<T>(path, body?, options?)
// rest.patch<T>(path, body?, options?)
// rest.delete<T>(path, options?)
示例
function ProductActions() {
const rest = useRest();
const handleExport = async () => {
const csv = await rest.get<string>('/api/products/export');
downloadCsv(csv);
};
return <button onClick={handleExport}>Export CSV</button>;
}
使用Rest查询
用于获取自定义 REST 端点的请求的声明钩 .
const { data, error, isLoading, refetch } = useRestQuery<T>(path, options?);
选项 扩展 RestRequestOptions (单位:千美元){ headers?, params?, signal? }与 enabled?: boolean。 。 。 .
返回 :
| 外地 | 类型 | 说明 |
|---|---|---|
data | T | null | 答复数据 |
error | ArchieError | null | 失败时出错 |
isLoading | boolean | 初始负载为真 |
refetch | () => Promise<void> | 手动触发回推 |
示例
const { data, isLoading } = useRestQuery<Product[]>('/api/products');
const { data: product } = useRestQuery<Product>(`/api/products/${id}`, { enabled: !!id });
反应
POST/PUT/PATCH/DELETE请求的必备钩.
const { execute, data, error, isLoading, reset } = useRestMutation<T>(path, method?);
参数 :
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
path | string | —— 说 | REST 端点路径 |
method | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'POST' | HTTP 方法 |
返回 :
| 外地 | 类型 | 说明 |
|---|---|---|
execute | (body?, overrideOptions?: RestRequestOptions) => Promise<T | null> | 执行请求 |
data | T | null | 最后一个成功结果 |
error | ArchieError | null | 上次错误 |
isLoading | boolean | 执行时为真 |
reset | () => void | 清除数据/误差/正在下载 |
这个 execute 函数接受可选的第二个参数 overrideOptions (单位:千美元)RestRequestOptions(通过自定义) headers, (中文(简体) ), params,或 signal 每个请求.
示例
const { execute, isLoading } = useRestMutation<Product>('/api/products', 'POST');
const handleCreate = async () => {
const product = await execute({ name: 'Widget', price: 9.99 });
if (product) router.push(`/products/${product.id}`);
};
// With custom headers per request
await execute(payload, { headers: { 'x-idempotency-key': uuid() } });
说明
订阅可访问应用程序通知并管理读状态 。 在挂载上打开一个 WebSocket 频道, 在卸载上关闭 .
const { user } = useAuth();
const receiverId = user?.id ?? '';
const {
notifications,
latest,
unreadCount,
isLoading,
error,
connectionState,
markAsRead,
markAllAsRead,
refetch,
} = useNotifications(receiverId, { enabled: !!user, limit: 20 });
选项 :
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled | boolean | true | 设定 false 以跳过加载和订阅( 如用户为无效) |
unreadOnly | boolean | false | 初始负载只返回未读通知 |
limit | number | —— 说 | 在初始获取中装入的最大项 |
onNotification | (n: NotificationWithSafeUrl) => void | —— 说 | 每一份新的现场通知(例如:吐司或音响)都使用 |
回返情况:
| 外地 | 类型 | 说明 |
|---|---|---|
notifications | Notification[] | 历史+活来者,最先来者,由: id |
latest | Notification | null | 最后一次通知是现场收到的(烤面包方便) |
unreadCount | number | 直播未读数——自动更新 |
isLoading | boolean | 初始历史载入时为真 |
error | ArchieError | null | 最近的操作失败出错 |
connectionState | ConnectionState | 'CONNECTING' | 'CONNECTED' | 'DISCONNECTED' | 'RECONNECTING' |
markAsRead | (id: string) => Promise<void> | 标出一个通知; 乐观地更新本地状态 |
markAllAsRead | () => Promise<void> | 标记已装入的所有通知; 对齐 unreadCount 使用服务器( 通常为 0) |
refetch | () => Promise<void> | 重新装入通知历史 |
无穷卷轴
useNotifications 页面在历史中向后, 不丢弃或复制活件 :
const { notifications, fetchMore, hasMore, isFetchingMore, error } = useNotifications(user.id, {
limit: 20, // page size for fetchMore()
});
// e.g. an IntersectionObserver on a sentinel at the bottom of the list.
// Gate on `!error` so a failed page doesn't drive a tight auto-retry loop
// (the hook also suppresses fetchMore internally after an error until refetch).
useEffect(() => {
if (hasMore && !isFetchingMore && !error) void fetchMore();
}, [hasMore, isFetchingMore, error, fetchMore]);
fetchMore()——加载下一个更古老的一页并附加它(dedup,最新-first). 什么时候不行!hasMore,获取器已经在飞行中,钩被禁用,或者之前fetchMore错误( 调用)refetch()——或更改receiverId编号 :unreadOnly——重试).hasMore——主动过滤器有更古老的记录.isFetchingMorea 包括:fetchMore()呼叫正在飞行中(驱动下方的"加载更老"指示器).
变化 receiverId 或者说 unreadOnly 从第一页重排 pagination并重播.
示例——未读徽章的通知钟:
import { useAuth, useNotifications } from '@archie/react-sdk';
function NotificationBell() {
const { user } = useAuth();
const receiverId = user?.id ?? '';
const { unreadCount, connectionState } = useNotifications(receiverId, { enabled: !!user });
return (
<button aria-label="Notifications">
<BellIcon />
{unreadCount > 0 && <span className="badge">{unreadCount > 99 ? '99+' : unreadCount}</span>}
{connectionState !== 'CONNECTED' && <span className="dot reconnecting" />}
</button>
);
}
示例——备注即读的通知列表:
function NotificationList() {
const { user } = useAuth();
const receiverId = user?.id ?? '';
const { notifications, isLoading, unreadCount, markAsRead, markAllAsRead } = useNotifications(
receiverId,
{ enabled: !!user, limit: 20 },
);
if (isLoading) return <Spinner />;
return (
<div>
<header>
<span>{unreadCount} unread</span>
<button onClick={() => markAllAsRead()} disabled={unreadCount === 0}>
Mark all read
</button>
</header>
<ul>
{notifications.map((n) => (
<li
key={n.id}
className={n.isRead ? 'read' : 'unread'}
onClick={() => !n.isRead && markAsRead(n.id)}
>
<p>{n.actionText ?? n.notificationKey}</p>
<time>{new Date(n.createdAt).toLocaleString()}</time>
</li>
))}
</ul>
</div>
);
}
总是无条件叫钩子 (接钩规则). 如果没有经认证的用户,请通过
receiverId=''财务报告和审定财务报表enabled: false——钩子不会加载或订阅.
安全说明. 永远不要生下来
n.actionUrl作为href——是不信任的服务器数据(javascript:, (中文(简体) ),data:, (中文(简体) ),//evil.com, (中文(简体) ),https://[email protected]) (中文(简体) ). 返回行数useNotifications携带先天化的safeActionUrl字段 (string | null)或使用NotificationAction组件。 处理n.metadata财务报告和审定财务报表n.params也不值得信赖 见 js-sdk 读取 警卫科 确切规则safeActionUrl。 。 。 .
safeActionUrl 每一行都一样. 里面的每件东西 notifications (和 latest)是原始通知加 safeActionUrl: string | null。 。 。 . actionUrl 它本身没有受到任何影响,所以它纯粹是添加剂.
{
notifications.map((n) => (
<li key={n.id}>
{n.safeActionUrl ? (
<a href={n.safeActionUrl} rel="noopener noreferrer">
Open
</a>
) : null}
</li>
));
}
使用AIChat 语句
现场聊天Archie AI(client.ai.stream(原始内容存档于2012-10-12). Reste SE. 对于一发任务(摘要、分类、取出),偏好图形QL aiChat 与 useMutation。 。 。 .
import { useAIChat } from '@archie/react-sdk';
function Assistant() {
const { messages, send, stop, status, usage, error } = useAIChat({
system: 'You help customers with their orders.',
tools: [
{
name: 'getOrders',
description: 'List the current user orders',
parameters: { type: 'object', properties: { limit: { type: 'number' } } },
execute: async ({ limit }) => fetchOrders(Number(limit ?? 5)),
},
],
metadata: { feature: 'order-assistant' },
});
// render messages; send('Where is my order?'); stop() aborts
}
messages处于合同状态,并在答案流时进行实时更新.providerState从done被保留在助理消息上 并在下一个回合怀恨在心.- 工具环: 每个
tool_call运行tool.execute(args, { toolCall, signal })(或onToolCall(call, { signal })),其结果(字符串作为正弦,JSON的其他值;一掷变为isError: true页:1tool信件和聊天会自动继续,直到maxSteps模式调用send()(默认5). status数字 :idle|submitted|streaming|error· ;usage在对话中积累;error是一个AIError(单位:千美元)insufficient_credits, (中文(简体) ),rate_limited(中文(简体) ).stop(), (中文(简体) ),reset(),一个新的send()并卸载在飞行中中止请求;被中断的转会保留其文本并放下未解答的工具调用,所以下转是有效的.- 选项 :
model, (中文(简体) ),provider, (中文(简体) ),system, (中文(简体) ),tools, (中文(简体) ),toolChoice, (中文(简体) ),responseFormat, (中文(简体) ),reasoning, (中文(简体) ),maxTokens, (中文(简体) ),temperature, (中文(简体) ),metadata, (中文(简体) ),providerOptions, (中文(简体) ),initialMessages, (中文(简体) ),maxSteps, (中文(简体) ),onToolCall, (中文(简体) ),onFinish, (中文(简体) ),onError。 。 。 .
构成部分
自动守护
基于认证状态的有条件渲染.
<AuthGuard fallback={<LoginPage />} loadingComponent={<Spinner />} requiredRoles={['admin']}>
<ProtectedContent />
</AuthGuard>
道具 :
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
children | ReactNode | —— 说 | 授权时显示的内容 |
fallback | ReactNode | null | 未经认证或未经授权时显示的内容 |
loadingComponent | ReactNode | null | 会话加载时显示的内容 |
requiredRoles | string[] | —— 说 | 用户必须至少有其中之一角色 |
行为:
- 虽然
isLoading* 提供loadingComponent - 如果未经认证,则提供
fallback - 若为
requiredRoles指定且用户缺少全部 ~ 渲染fallback - 否则... 提供
children
被蒙住的警卫:
<AuthGuard fallback={<LoginPage />}>
<AppLayout>
<AuthGuard requiredRoles={['admin']} fallback={<Unauthorized />}>
<AdminPanel />
</AuthGuard>
</AppLayout>
</AuthGuard>
通知行动
安全地发出通知.
import { NotificationAction } from '@archie/react-sdk';
<NotificationAction notification={n} className="btn" />
<NotificationAction notification={n}>View details</NotificationAction>
道具 :
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
notification | { actionText?, actionUrl? } 联合国 Notification(中文(简体) ) | —— 说 | 标签和链接的来源 |
className | string | —— 说 | 适用于 <a> (或对 <span> 当没有链接时) |
children | ReactNode | actionText | 覆盖标签 |
行为:
- URL通过
safeActionUrl(单位:千美元)https://或同一来源/path页:1. - 安全吗
<a href rel="noopener noreferrer">;标签是一个纯反应文本子(已逃出,从未使用 HTML). - 不安全或缺少 URL − 标签为
<span>没有链接. - 没有标签... ... ...
再出口类型
为了方便, @archie/react-sdk 从 @archie/js-sdk,因此不需要从两个包中导入:
import {
// Client
createClient,
type ArchieClient,
type ArchieClientOptions,
// Auth types
type Session,
type User,
type AuthSignUpParams,
type AuthSignInParams,
type AuthConfirmParams,
type AuthRecoverParams,
type AuthResetPasswordParams,
type AuthEvent,
type AuthEventCallback,
// GraphQL types
type GraphQLResponse,
type GraphQLRequestOptions,
type GraphQLRawRequest,
// File types
type FileUploadOptions,
type FileUploadResult,
type CsvUploadOptions,
// Realtime types
type Subscription,
type SubscriptionCallbacks,
type RealtimeEvent,
type RealtimeChannel,
type ConnectionState,
type ConnectionStateCallback,
// REST types
type RestRequestOptions,
// Error classes
ArchieError,
AuthError,
GraphQLError,
NetworkError,
// Storage
type StorageAdapter,
BrowserLocalStorage,
MemoryStorage,
// Interfaces (SOLID)
type IAuthModule,
type IGraphQLModule,
type IFileModule,
type IRealtimeModule,
type IRestModule,
type IHttpClient,
type Logger,
type TokenAccessor,
} from '@archie/react-sdk';
// React-specific prop types
import type { ArchieProviderProps, AuthGuardProps } from '@archie/react-sdk';
处理错误
全体 useAuth 方法返回 { data/session, error } - 他们从来不扔。 对于 useQuery 财务报告和审定财务报表 useMutation,错误通过 error 字段中的字段.
错误类来自 @archie/js-sdk数字 :
| 类 | 何时 |
|---|---|
AuthError | 认证失败( 签名、 签名、 刷新) |
GraphQLError | 图QL 回复错误 |
NetworkError | 网络故障、 超时 |
ArchieError | 所有 Archie 错误的基础类 |
const { error } = useQuery<{ users: User[] }>('{ users { id } }');
if (error) {
if (error instanceof AuthError) {
// Token expired, redirect to login
} else if (error instanceof NetworkError) {
// Show offline indicator
} else {
// Show generic error
}
}
SSR 兼容性
所有钩子都是安全的:
- 没有
window或者说document初始提交时的访问 refetchOnWindowFocus检查typeof window在添加听众之前ArchieProvider同步初始化会话( 没有屏蔽 SSR)AuthGuard调制loadingComponent在未知会话时服务器渲染时
对于像Next.js这样的框架,在组件树外创建客户端:
// lib/archie.ts
import { createClient } from '@archie/js-sdk';
export const archie = createClient({
projectId: process.env.NEXT_PUBLIC_ARCHIE_PROJECT_ID!,
apiKey: process.env.NEXT_PUBLIC_ARCHIE_ANON_KEY!,
});
// app/providers.tsx
('use client');
import { ArchieProvider } from '@archie/react-sdk';
import { archie } from '@/lib/archie';
export function Providers({ children }: { children: React.ReactNode }) {
return <ArchieProvider client={archie}>{children}</ArchieProvider>;
}
高级客户端选项
@archie/react-sdk 继承所有高级选项 @archie/js-sdk 通过 createClient()。这些在客户端创建时被配置一次,并自动向所有钩子传播:
import { createClient, consoleLogger } from '@archie/js-sdk';
const archie = createClient({
projectId: 'your-project-uuid',
// Retry & timeout
retries: 3, // retry transient errors (429, 500, 502, 503, 504, network)
retryDelay: 200, // initial backoff delay in ms (exponential with jitter)
timeout: 15_000, // abort requests after 15 seconds (0 = disabled)
// Custom fetch — for testing, proxies, or edge runtimes
fetch: customFetchImpl,
// Logger
logger: consoleLogger, // or a custom Logger implementation
});
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
timeout | number | 30000 | 请求超时以毫秒( 0 = 已禁用) |
retries | number | 0 | 最大重试尝试瞬态错误 |
retryDelay | number | 200 | 初始后退延迟( ms) |
fetch | typeof fetch | globalThis.fetch | 自定义获取执行 |
健康检查
幕后客户也会曝光 ping()数字 :
const archie = useArchieClient();
const isUp = await archie.ping();
见全 @archie/js-sdk 读取 关于重试行为、后退策略、超时语义和自定义取用的详细文档.
类型脚本
所有的钩子都是完全通用的:
interface User {
id: string;
email: string;
name: string;
}
// Typed query response
const { data } = useQuery<{ users: User[] }>('{ users { id email name } }');
// ^? { users: User[] } | null
// Typed mutation response
const { mutateAsync } = useMutation<{ createUser: User }>('mutation ...');
const result = await mutateAsync({ input: { email: '[email protected]' } });
// ^? { createUser: User } | null
// Typed subscription
const { data } = useSubscription<{ orderUpdated: Order }>('subscription ...');
// ^? { orderUpdated: Order } | null
// Typed REST
const { data } = useRestQuery<Product[]>('/api/products');
// ^? Product[] | null