chatablex-web-sdk 1.0.3 → 1.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # ChatableX Web SDK
2
2
 
3
+ [![license](https://img.shields.io/npm/l/chatablex-web-sdk.svg?style=flat-square)](https://github.com/chatablex/chatablex-web-sdk/blob/main/package.json)
4
+ [![npm version](https://img.shields.io/npm/v/chatablex-web-sdk.svg?style=flat-square)](https://www.npmjs.com/package/chatablex-web-sdk)
5
+ [![CI](https://img.shields.io/github/actions/workflow/status/chatablex/chatablex-web-sdk/ci.yml?branch=main&label=Build%20%26%20Test&logo=github)](https://github.com/chatablex/chatablex-web-sdk/actions/workflows/ci.yml)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/chatablex/chatablex-web-sdk/pulls)
8
+
3
9
  English | [**简体中文**](README.zh-CN.md)
4
10
 
5
11
  **Runtime SDK for building ChatableX AI App WebUI extensions.**
@@ -27,6 +33,8 @@ Your WebUI runs inside a WebView. Many capabilities — native dialogs, file pic
27
33
  - [sdk.storage](#sdkstorage)
28
34
  - [sdk.tools](#sdktools)
29
35
  - [sdk.platform](#sdkplatform)
36
+ - [sdk.auth](#sdkauth)
37
+ - [sdk.cloud](#sdkcloud)
30
38
  - [Events Reference](#events-reference)
31
39
  - [Permissions](#permissions)
32
40
  - [Host Capability Matrix](#host-capability-matrix)
@@ -533,6 +541,111 @@ Throws if `targetUrl` is empty or whitespace-only.
533
541
 
534
542
  ---
535
543
 
544
+ ### `sdk.auth`
545
+
546
+ Unified authentication for **every** WebUI app. In a hosted (Flutter WebView)
547
+ environment it transparently reuses the desktop login session — your app writes
548
+ **zero** login/token code. Just call `getAuthHeaders()` and attach it to your
549
+ `fetch`.
550
+
551
+ | Method | Signature | Description |
552
+ |--------|-----------|-------------|
553
+ | `getToken` | `() => Promise<AuthTokenData \| null>` | Get a valid token (cached, refreshed on demand). `null` when not authenticated. |
554
+ | `getAuthHeaders` | `() => Promise<Record<string,string>>` | `{ Authorization: "Bearer <token>" }`, or `{}` when not authenticated. |
555
+ | `getUserId` | `() => string \| null` | Authenticated user id (sync, cache only). |
556
+ | `isAuthenticated` | `() => boolean` | Whether a valid token is cached (sync). |
557
+ | `refresh` | `() => Promise<boolean>` | Force a refresh via the host. Concurrent calls are merged (single-flight). |
558
+
559
+ ```ts
560
+ // Attach the host login session to any authenticated request — no login code.
561
+ const res = await fetch('https://api.example.com/scenes', {
562
+ headers: {
563
+ 'Content-Type': 'application/json',
564
+ ...(await sdk.auth.getAuthHeaders()),
565
+ },
566
+ });
567
+
568
+ if (!sdk.auth.isAuthenticated()) {
569
+ // not logged in / not hosted — disable features that need auth
570
+ }
571
+
572
+ // On a 401 from your backend, force a refresh and retry once:
573
+ if (res.status === 401 && (await sdk.auth.refresh())) {
574
+ // retry with await sdk.auth.getAuthHeaders()
575
+ }
576
+ ```
577
+
578
+ **Behavior & guarantees**
579
+
580
+ - **Token is in-memory only.** The `refresh_token` never crosses the bridge.
581
+ - **Pre-emptive refresh.** The host refreshes the `access_token` before sending
582
+ when it is expired or near expiry, so you normally never see an expired token.
583
+ - **Safe degradation.** Outside a WebView, or when the host is logged out,
584
+ `getAuthHeaders()` resolves to `{}` and never throws.
585
+ - **Pluggable provider.** Today only `HostAuthProvider` (WebView) is wired up; a
586
+ future browser/unified-login provider will slot in without changing your code.
587
+
588
+ ---
589
+
590
+ ### `sdk.cloud`
591
+
592
+ Unified cloud storage for **all** WebUI apps — keep user files saved across
593
+ devices without losing them. The SDK handles uploads, downloads, and retries;
594
+ you just call the methods. The `appId` (from `ChatableX.init`) is added
595
+ automatically, and each app's data is isolated so files never get mixed up.
596
+
597
+ > Requires: (1) the user is signed in (`sdk.auth`); (2) a configured cloud
598
+ > storage URL — pass `ChatableX.init({ apiBaseUrl })` (in a hosted environment
599
+ > ChatableX can also provide it automatically). Uploading is a **paid
600
+ > capability**: the user must purchase the corresponding tool before uploading,
601
+ > otherwise the upload is rejected.
602
+
603
+ | Method | Signature | Notes |
604
+ |--------|-----------|-------|
605
+ | `upload` | `(fileKey, data, opts?) => Promise<CloudUploadResult>` | Upload (overwrite). `data` accepts `Blob`/`ArrayBuffer`/`TypedArray`/`string`. |
606
+ | `download` | `(fileKey) => Promise<Blob>` | Download a file's bytes. |
607
+ | `getDownloadUrl` | `(fileKey) => Promise<string>` | Short-lived download URL (e.g. for `<img src>`). |
608
+ | `list` | `(opts?) => Promise<CloudFileInfo[]>` | List this app's files for the user; filter by `prefix`. |
609
+ | `delete` | `(fileKey) => Promise<void>` | Delete a file. |
610
+ | `usage` | `() => Promise<CloudUsage>` | Read the account's storage usage / quota. |
611
+
612
+ ```ts
613
+ const sdk = await ChatableX.init({
614
+ appId: 'math-studio',
615
+ apiBaseUrl: import.meta.env.VITE_CHATABLEX_API_BASE,
616
+ });
617
+
618
+ await sdk.cloud.upload('scenes/abc/scene.json.gz', blob, { contentType: 'application/gzip' });
619
+ const files = await sdk.cloud.list({ prefix: 'scenes/' });
620
+ const bytes = await sdk.cloud.download('scenes/abc/scene.json.gz');
621
+ await sdk.cloud.delete('scenes/abc/scene.json.gz');
622
+ const { usedBytes, quotaBytes } = await sdk.cloud.usage();
623
+ ```
624
+
625
+ **Error handling** (all `instanceof`-checkable, exported from the package root):
626
+
627
+ ```ts
628
+ import {
629
+ CloudAuthRequiredError, // not logged in
630
+ CloudSubscriptionRequiredError, // tool not purchased — prompt the user to buy it
631
+ CloudQuotaExceededError, // over storage quota; has usedBytes / quotaBytes
632
+ CloudError, // other cloud errors; has code
633
+ } from 'chatablex-web-sdk';
634
+ ```
635
+
636
+ **Behavior & guarantees**
637
+
638
+ - **Transparent auth.** Reuses `sdk.auth` internally; an expired session is
639
+ refreshed automatically and the request retried once. When the user is not
640
+ signed in it throws `CloudAuthRequiredError` and sends no request.
641
+ - **Data isolation.** Each user's and each app's data is isolated; apps and
642
+ users can never read each other's files.
643
+ - **Paid capability.** Uploading requires the user to have purchased the
644
+ corresponding tool; catch `CloudSubscriptionRequiredError` to drive a purchase
645
+ prompt.
646
+
647
+ ---
648
+
536
649
  ## Events Reference
537
650
 
538
651
  | Event | Payload | When fired |
@@ -576,6 +689,8 @@ SDK methods are thin RPC wrappers. Some host handlers are fully implemented; oth
576
689
  | `sdk.ui.pickFile` | **Production** | Requires `file_access` |
577
690
  | `sdk.ui.updateState` | **Production** | Delegates to host |
578
691
  | `sdk.platform.openInBrowser` | **Production** | Auth handoff |
692
+ | `sdk.auth.*` | **Production** | Hosted: reuses desktop login via `host.getAuthToken` (pre-refresh) |
693
+ | `sdk.cloud.*` | **Production** | Cloud file storage; needs `apiBaseUrl`, uploading requires purchasing the tool |
579
694
  | `sdk.ai.chat` | **Production** | Requires `ai_chat` + delegate |
580
695
  | `sdk.ai.getContext` | **Partial** | Returns minimal context |
581
696
  | `sdk.ai.chatStream` | **Partial** | Returns `{ streaming: true }`; tokens via events |
package/README.zh-CN.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # ChatableX Web SDK
2
2
 
3
+ [![license](https://img.shields.io/npm/l/chatablex-web-sdk.svg?style=flat-square)](https://github.com/chatablex/chatablex-web-sdk/blob/main/package.json)
4
+ [![npm version](https://img.shields.io/npm/v/chatablex-web-sdk.svg?style=flat-square)](https://www.npmjs.com/package/chatablex-web-sdk)
5
+ [![CI](https://img.shields.io/github/actions/workflow/status/chatablex/chatablex-web-sdk/ci.yml?branch=main&label=Build%20%26%20Test&logo=github)](https://github.com/chatablex/chatablex-web-sdk/actions/workflows/ci.yml)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/chatablex/chatablex-web-sdk/pulls)
8
+
3
9
  **[English](README.md)** | 简体中文
4
10
 
5
11
  **用于构建 ChatableX AI App WebUI 扩展的官方运行时 SDK。**
@@ -27,6 +33,8 @@
27
33
  - [sdk.storage](#sdkstorage)
28
34
  - [sdk.tools](#sdktools)
29
35
  - [sdk.platform](#sdkplatform)
36
+ - [sdk.auth](#sdkauth)
37
+ - [sdk.cloud](#sdkcloud)
30
38
  - [事件参考](#事件参考)
31
39
  - [权限声明](#权限声明)
32
40
  - [宿主能力矩阵](#宿主能力矩阵)
@@ -533,6 +541,117 @@ await sdk.platform.openInBrowser('https://docs.example.com/guide');
533
541
 
534
542
  ---
535
543
 
544
+ ### `sdk.auth`
545
+
546
+ 面向**所有** WebUI 应用的统一鉴权入口。在宿主(Flutter WebView)环境下,它会
547
+ 透明复用桌面端的登录态——你的应用**无需编写任何登录/Token 代码**,只需调用
548
+ `getAuthHeaders()` 并附加到 `fetch` 即可。
549
+
550
+ | 方法 | 签名 | 说明 |
551
+ |------|------|------|
552
+ | `getToken` | `() => Promise<AuthTokenData \| null>` | 取有效 Token(内存缓存,按需刷新);未登录返回 `null`。 |
553
+ | `getAuthHeaders` | `() => Promise<Record<string,string>>` | 返回 `{ Authorization: "Bearer <token>" }`,未登录则返回 `{}`。 |
554
+ | `getUserId` | `() => string \| null` | 当前登录用户 id(同步,仅读缓存)。 |
555
+ | `isAuthenticated` | `() => boolean` | 是否已缓存有效 Token(同步)。 |
556
+ | `refresh` | `() => Promise<boolean>` | 强制经宿主刷新;并发调用合并为一次(single-flight)。 |
557
+
558
+ ```ts
559
+ // 给任意需要鉴权的请求附加宿主登录态——无需任何登录代码。
560
+ const res = await fetch('https://api.example.com/scenes', {
561
+ headers: {
562
+ 'Content-Type': 'application/json',
563
+ ...(await sdk.auth.getAuthHeaders()),
564
+ },
565
+ });
566
+
567
+ if (!sdk.auth.isAuthenticated()) {
568
+ // 未登录 / 非 WebView——禁用需要鉴权的功能
569
+ }
570
+
571
+ // 后端返回 401 时,强制刷新并重试一次:
572
+ if (res.status === 401 && (await sdk.auth.refresh())) {
573
+ // 用 await sdk.auth.getAuthHeaders() 重试
574
+ }
575
+ ```
576
+
577
+ **行为与保证**
578
+
579
+ - **Token 仅存内存。** `refresh_token` 永不经过 bridge。
580
+ - **下发前刷新。** 宿主在 Token 过期或临近过期时会先刷新再下发,正常情况下你
581
+ 不会拿到过期 Token。
582
+ - **安全降级。** 在非 WebView 或宿主未登录时,`getAuthHeaders()` 返回 `{}` 且
583
+ 不抛异常。
584
+ - **Provider 可插拔。** 目前仅接入 `HostAuthProvider`(WebView);未来的浏览器/
585
+ 统一登录 provider 可无缝替换,消费方代码无需改动。
586
+
587
+ ---
588
+
589
+ ### `sdk.cloud`
590
+
591
+ 面向**所有** WebUI 应用的统一云存储,让用户文件跨设备保存、不丢失。上传、下载、
592
+ 重试等细节都由 SDK 处理,你只管调方法。`appId`(来自 `ChatableX.init`)会自动带上,
593
+ 每个应用的数据互相隔离,不会串。
594
+
595
+ > 需要:(1) 用户已登录(`sdk.auth`);(2) 已配置云存储服务地址——在
596
+ > `ChatableX.init({ apiBaseUrl })` 传入(宿主环境下也可由 ChatableX 自动提供)。
597
+ > 上传是**付费能力**:用户需购买对应工具后才能上传,未购买时上传会被拒绝。
598
+
599
+ | 方法 | 签名 | 说明 |
600
+ |------|------|------|
601
+ | `upload` | `(fileKey, data, opts?) => Promise<CloudUploadResult>` | 上传(覆盖写)。`data` 支持 `Blob`/`ArrayBuffer`/`TypedArray`/`string`。 |
602
+ | `download` | `(fileKey) => Promise<Blob>` | 下载文件字节。 |
603
+ | `getDownloadUrl` | `(fileKey) => Promise<string>` | 获取短期有效的下载链接(如喂给 `<img src>`)。 |
604
+ | `list` | `(opts?) => Promise<CloudFileInfo[]>` | 列出当前应用在该用户下的文件,可按 `prefix` 过滤。 |
605
+ | `delete` | `(fileKey) => Promise<void>` | 删除文件。 |
606
+ | `usage` | `() => Promise<CloudUsage>` | 读取账户存储用量/配额。 |
607
+
608
+ ```ts
609
+ const sdk = await ChatableX.init({
610
+ appId: 'math-studio',
611
+ apiBaseUrl: import.meta.env.VITE_CHATABLEX_API_BASE,
612
+ });
613
+
614
+ // 上传(app_id 自动注入,无需手动传)
615
+ await sdk.cloud.upload('scenes/abc/scene.json.gz', blob, { contentType: 'application/gzip' });
616
+
617
+ // 列表 / 下载 / 删除 / 用量
618
+ const files = await sdk.cloud.list({ prefix: 'scenes/' });
619
+ const bytes = await sdk.cloud.download('scenes/abc/scene.json.gz');
620
+ await sdk.cloud.delete('scenes/abc/scene.json.gz');
621
+ const { usedBytes, quotaBytes } = await sdk.cloud.usage();
622
+ ```
623
+
624
+ **错误处理**(均可 `instanceof` 判断,从包根导出):
625
+
626
+ ```ts
627
+ import {
628
+ CloudAuthRequiredError, // 未登录:提示登录 ChatableX
629
+ CloudSubscriptionRequiredError, // 未购买:引导用户购买工具
630
+ CloudQuotaExceededError, // 超出存储配额,含 usedBytes / quotaBytes
631
+ CloudError, // 其他云存储错误,含 code
632
+ } from 'chatablex-web-sdk';
633
+
634
+ try {
635
+ await sdk.cloud.upload('big.bin', buf);
636
+ } catch (e) {
637
+ if (e instanceof CloudSubscriptionRequiredError) {/* 弹出购买引导 */}
638
+ else if (e instanceof CloudQuotaExceededError) {/* 提示清理 / 升级,e.usedBytes/e.quotaBytes */}
639
+ else if (e instanceof CloudAuthRequiredError) {/* 提示登录 */}
640
+ else throw e;
641
+ }
642
+ ```
643
+
644
+ **行为与保证**
645
+
646
+ - **鉴权透明。** 内部复用 `sdk.auth`,登录态过期会自动刷新并重试一次;用户未登录
647
+ 时直接抛 `CloudAuthRequiredError`,不会发出无效请求。
648
+ - **数据隔离。** 每个用户、每个应用的数据互相隔离,应用之间、用户之间都不会读到
649
+ 对方的文件。
650
+ - **付费能力。** 上传需用户已购买对应工具;通过捕获
651
+ `CloudSubscriptionRequiredError` 引导用户购买。
652
+
653
+ ---
654
+
536
655
  ## 事件参考
537
656
 
538
657
  | 事件 | 载荷 | 触发时机 |
@@ -576,6 +695,8 @@ SDK 方法是薄 RPC 封装。部分宿主处理器已完整实现,部分返
576
695
  | `sdk.ui.pickFile` | **生产可用** | 需要 `file_access` |
577
696
  | `sdk.ui.updateState` | **生产可用** | 委托给宿主 |
578
697
  | `sdk.platform.openInBrowser` | **生产可用** | 鉴权传递 |
698
+ | `sdk.auth.*` | **生产可用** | 宿主态:经 `host.getAuthToken` 复用桌面登录(下发前刷新) |
699
+ | `sdk.cloud.*` | **生产可用** | 云端文件存储;需配置 `apiBaseUrl`,上传需购买对应工具 |
579
700
  | `sdk.ai.chat` | **生产可用** | 需要 `ai_chat` + delegate |
580
701
  | `sdk.ai.getContext` | **部分实现** | 返回最小上下文 |
581
702
  | `sdk.ai.chatStream` | **部分实现** | 返回 `{ streaming: true }`;token 走事件 |
package/dist/index.d.mts CHANGED
@@ -119,6 +119,14 @@ interface ChatableXInitConfig {
119
119
  debug?: boolean;
120
120
  /** Timeout in ms for the handshake with Flutter (default: 10000) */
121
121
  timeout?: number;
122
+ /**
123
+ * Base URL of the ChatableX cloud API (auth-fc), e.g.
124
+ * `https://chatabl-fc-prod-xxxx.cn-hangzhou.fcapp.run`. Required for
125
+ * `sdk.cloud` to work. When omitted, the SDK best-effort asks the host via
126
+ * the `host.getApiBaseUrl` bridge call; if that is also unavailable, cloud
127
+ * calls reject with a clear error.
128
+ */
129
+ apiBaseUrl?: string;
122
130
  }
123
131
  interface ChatableXAI {
124
132
  chat(message: string, options?: ChatOptions): Promise<ChatResponse>;
@@ -156,6 +164,103 @@ interface ChatableXPlatform {
156
164
  /** Open URL in system browser with auth handoff (WebView only; implemented by Flutter host). */
157
165
  openInBrowser(targetUrl: string): Promise<void>;
158
166
  }
167
+ /** Token payload returned by the host (never includes the refresh_token). */
168
+ interface AuthTokenData {
169
+ /** Bearer access token to put in the Authorization header. */
170
+ access_token: string;
171
+ /** Access token expiry, epoch milliseconds. */
172
+ expires_at: number;
173
+ /** Authenticated user id. */
174
+ user_id: string;
175
+ }
176
+ /**
177
+ * Unified auth entry point for all WebUI apps.
178
+ *
179
+ * In a hosted (Flutter WebView) environment this reuses the desktop login
180
+ * session via the `host.getAuthToken` bridge call — apps never implement
181
+ * login or token handling themselves.
182
+ */
183
+ interface ChatableXAuth {
184
+ /**
185
+ * Get a valid access token. Returns the in-memory cached token when still
186
+ * valid, otherwise fetches a fresh one from the host. Returns `null` when
187
+ * not authenticated / not hosted.
188
+ */
189
+ getToken(): Promise<AuthTokenData | null>;
190
+ /**
191
+ * Build auth headers ready to spread into a `fetch`. Returns
192
+ * `{ Authorization: "Bearer <token>" }` when authenticated, otherwise `{}`.
193
+ */
194
+ getAuthHeaders(): Promise<Record<string, string>>;
195
+ /** Currently authenticated user id, or `null`. Synchronous (cache only). */
196
+ getUserId(): string | null;
197
+ /** Whether a valid token is currently cached. Synchronous (cache only). */
198
+ isAuthenticated(): boolean;
199
+ /** Force a token refresh via the host. Resolves `true` on success. */
200
+ refresh(): Promise<boolean>;
201
+ }
202
+ /** Binary payload accepted by `sdk.cloud.upload`. */
203
+ type CloudUploadData = Blob | ArrayBuffer | ArrayBufferView | string;
204
+ interface CloudUploadOptions {
205
+ /**
206
+ * MIME type to store the object as. Defaults to the `Blob.type` when a Blob
207
+ * is given, otherwise `application/octet-stream`. Must be one allowed by the
208
+ * server's content-type whitelist.
209
+ */
210
+ contentType?: string;
211
+ }
212
+ /** Result of a successful `sdk.cloud.upload`. */
213
+ interface CloudUploadResult {
214
+ /** App-relative key (the same `fileKey` passed to `upload`). */
215
+ fileKey: string;
216
+ /** Fully-qualified OSS object key (`user-data/{user_id}/{app_id}/{fileKey}`). */
217
+ objectKey: string;
218
+ /** Bytes uploaded. */
219
+ size: number;
220
+ /** MIME type the object was stored as. */
221
+ contentType: string;
222
+ }
223
+ /** A single file in the user's cloud storage for this app. */
224
+ interface CloudFileInfo {
225
+ fileKey: string;
226
+ size: number;
227
+ /** ISO-8601 timestamp. */
228
+ lastModified: string;
229
+ }
230
+ interface CloudListOptions {
231
+ /** Restrict the listing to keys under this app-relative prefix. */
232
+ prefix?: string;
233
+ }
234
+ /** The user's storage usage / quota for the whole account. */
235
+ interface CloudUsage {
236
+ usedBytes: number;
237
+ quotaBytes: number;
238
+ fileCount: number;
239
+ /** ISO-8601 timestamp of the last server-side reconciliation, if any. */
240
+ reconciledAt?: string;
241
+ }
242
+ /**
243
+ * Cloud storage for WebUI apps. Backed by auth-fc presigned OSS URLs; the
244
+ * app's `appId` (from `ChatableX.init`) is injected automatically so every key
245
+ * is namespaced to `{user}/{app}` and apps cannot reach into each other's data.
246
+ *
247
+ * Requires an authenticated session (`sdk.auth`) and a configured cloud API
248
+ * base URL (see `ChatableXInitConfig.apiBaseUrl`).
249
+ */
250
+ interface ChatableXCloud {
251
+ /** Upload (overwrite) a file. Resolves once the bytes are stored in OSS. */
252
+ upload(fileKey: string, data: CloudUploadData, options?: CloudUploadOptions): Promise<CloudUploadResult>;
253
+ /** Download a file's bytes as a Blob. */
254
+ download(fileKey: string): Promise<Blob>;
255
+ /** Get a short-lived presigned GET URL (e.g. to feed an `<img src>`). */
256
+ getDownloadUrl(fileKey: string): Promise<string>;
257
+ /** List the current app's files for this user. */
258
+ list(options?: CloudListOptions): Promise<CloudFileInfo[]>;
259
+ /** Delete a file. Resolves even if the object did not exist. */
260
+ delete(fileKey: string): Promise<void>;
261
+ /** Read the account's storage usage / quota. */
262
+ usage(): Promise<CloudUsage>;
263
+ }
159
264
  interface ChatableXSDK {
160
265
  ai: ChatableXAI;
161
266
  tools: ChatableXTools;
@@ -164,6 +269,8 @@ interface ChatableXSDK {
164
269
  storage: ChatableXStorage;
165
270
  tool: ChatableXToolModule;
166
271
  platform: ChatableXPlatform;
272
+ auth: ChatableXAuth;
273
+ cloud: ChatableXCloud;
167
274
  }
168
275
  declare global {
169
276
  interface Window {
@@ -210,6 +317,33 @@ declare class Bridge {
210
317
  destroy(): void;
211
318
  }
212
319
 
320
+ /** Base error for all `sdk.cloud` failures. */
321
+ declare class CloudError extends Error {
322
+ /** Business code from auth-fc (or the HTTP status when none was returned). */
323
+ readonly code: number;
324
+ constructor(message: string, code: number);
325
+ }
326
+ /**
327
+ * Thrown when no authenticated session is available. The app should prompt the
328
+ * user to log in to ChatableX before retrying.
329
+ */
330
+ declare class CloudAuthRequiredError extends CloudError {
331
+ constructor(message?: string);
332
+ }
333
+ /**
334
+ * Thrown when the user lacks the entitlement (purchased tool / membership)
335
+ * required to write to cloud storage. Maps to auth-fc code `40302`.
336
+ */
337
+ declare class CloudSubscriptionRequiredError extends CloudError {
338
+ constructor(message?: string);
339
+ }
340
+ /** Thrown when the upload would exceed the user's storage quota (code `40301`). */
341
+ declare class CloudQuotaExceededError extends CloudError {
342
+ readonly usedBytes: number;
343
+ readonly quotaBytes: number;
344
+ constructor(usedBytes: number, quotaBytes: number, message?: string);
345
+ }
346
+
213
347
  /**
214
348
  * chatablex-web-sdk
215
349
  *
@@ -252,4 +386,4 @@ declare const ChatableX: {
252
386
  version: string;
253
387
  };
254
388
 
255
- export { type AiResponseEventData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXEvents, type ChatableXInitConfig, type ChatableXPlatform, type ChatableXSDK, type ChatableXStorage, type ChatableXToolModule, type ChatableXTools, type ChatableXUI, type CloseEventData, type EventCallbackMap, type EventType, type FilePickerOptions, type Message, type NotificationType, SDK_VERSION, type SessionContext, type StateUpdate, type StreamingContentEventData, type TabConfig, type ToolCall, type ToolExecuteHandler, type ToolExecutionEventData, type ToolInfo, type ToolParameter, type ToolResult, type Unsubscribe, type UserMessageEventData };
389
+ export { type AiResponseEventData, type AuthTokenData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXAuth, type ChatableXCloud, type ChatableXEvents, type ChatableXInitConfig, type ChatableXPlatform, type ChatableXSDK, type ChatableXStorage, type ChatableXToolModule, type ChatableXTools, type ChatableXUI, type CloseEventData, CloudAuthRequiredError, CloudError, type CloudFileInfo, type CloudListOptions, CloudQuotaExceededError, CloudSubscriptionRequiredError, type CloudUploadData, type CloudUploadOptions, type CloudUploadResult, type CloudUsage, type EventCallbackMap, type EventType, type FilePickerOptions, type Message, type NotificationType, SDK_VERSION, type SessionContext, type StateUpdate, type StreamingContentEventData, type TabConfig, type ToolCall, type ToolExecuteHandler, type ToolExecutionEventData, type ToolInfo, type ToolParameter, type ToolResult, type Unsubscribe, type UserMessageEventData };
package/dist/index.d.ts CHANGED
@@ -119,6 +119,14 @@ interface ChatableXInitConfig {
119
119
  debug?: boolean;
120
120
  /** Timeout in ms for the handshake with Flutter (default: 10000) */
121
121
  timeout?: number;
122
+ /**
123
+ * Base URL of the ChatableX cloud API (auth-fc), e.g.
124
+ * `https://chatabl-fc-prod-xxxx.cn-hangzhou.fcapp.run`. Required for
125
+ * `sdk.cloud` to work. When omitted, the SDK best-effort asks the host via
126
+ * the `host.getApiBaseUrl` bridge call; if that is also unavailable, cloud
127
+ * calls reject with a clear error.
128
+ */
129
+ apiBaseUrl?: string;
122
130
  }
123
131
  interface ChatableXAI {
124
132
  chat(message: string, options?: ChatOptions): Promise<ChatResponse>;
@@ -156,6 +164,103 @@ interface ChatableXPlatform {
156
164
  /** Open URL in system browser with auth handoff (WebView only; implemented by Flutter host). */
157
165
  openInBrowser(targetUrl: string): Promise<void>;
158
166
  }
167
+ /** Token payload returned by the host (never includes the refresh_token). */
168
+ interface AuthTokenData {
169
+ /** Bearer access token to put in the Authorization header. */
170
+ access_token: string;
171
+ /** Access token expiry, epoch milliseconds. */
172
+ expires_at: number;
173
+ /** Authenticated user id. */
174
+ user_id: string;
175
+ }
176
+ /**
177
+ * Unified auth entry point for all WebUI apps.
178
+ *
179
+ * In a hosted (Flutter WebView) environment this reuses the desktop login
180
+ * session via the `host.getAuthToken` bridge call — apps never implement
181
+ * login or token handling themselves.
182
+ */
183
+ interface ChatableXAuth {
184
+ /**
185
+ * Get a valid access token. Returns the in-memory cached token when still
186
+ * valid, otherwise fetches a fresh one from the host. Returns `null` when
187
+ * not authenticated / not hosted.
188
+ */
189
+ getToken(): Promise<AuthTokenData | null>;
190
+ /**
191
+ * Build auth headers ready to spread into a `fetch`. Returns
192
+ * `{ Authorization: "Bearer <token>" }` when authenticated, otherwise `{}`.
193
+ */
194
+ getAuthHeaders(): Promise<Record<string, string>>;
195
+ /** Currently authenticated user id, or `null`. Synchronous (cache only). */
196
+ getUserId(): string | null;
197
+ /** Whether a valid token is currently cached. Synchronous (cache only). */
198
+ isAuthenticated(): boolean;
199
+ /** Force a token refresh via the host. Resolves `true` on success. */
200
+ refresh(): Promise<boolean>;
201
+ }
202
+ /** Binary payload accepted by `sdk.cloud.upload`. */
203
+ type CloudUploadData = Blob | ArrayBuffer | ArrayBufferView | string;
204
+ interface CloudUploadOptions {
205
+ /**
206
+ * MIME type to store the object as. Defaults to the `Blob.type` when a Blob
207
+ * is given, otherwise `application/octet-stream`. Must be one allowed by the
208
+ * server's content-type whitelist.
209
+ */
210
+ contentType?: string;
211
+ }
212
+ /** Result of a successful `sdk.cloud.upload`. */
213
+ interface CloudUploadResult {
214
+ /** App-relative key (the same `fileKey` passed to `upload`). */
215
+ fileKey: string;
216
+ /** Fully-qualified OSS object key (`user-data/{user_id}/{app_id}/{fileKey}`). */
217
+ objectKey: string;
218
+ /** Bytes uploaded. */
219
+ size: number;
220
+ /** MIME type the object was stored as. */
221
+ contentType: string;
222
+ }
223
+ /** A single file in the user's cloud storage for this app. */
224
+ interface CloudFileInfo {
225
+ fileKey: string;
226
+ size: number;
227
+ /** ISO-8601 timestamp. */
228
+ lastModified: string;
229
+ }
230
+ interface CloudListOptions {
231
+ /** Restrict the listing to keys under this app-relative prefix. */
232
+ prefix?: string;
233
+ }
234
+ /** The user's storage usage / quota for the whole account. */
235
+ interface CloudUsage {
236
+ usedBytes: number;
237
+ quotaBytes: number;
238
+ fileCount: number;
239
+ /** ISO-8601 timestamp of the last server-side reconciliation, if any. */
240
+ reconciledAt?: string;
241
+ }
242
+ /**
243
+ * Cloud storage for WebUI apps. Backed by auth-fc presigned OSS URLs; the
244
+ * app's `appId` (from `ChatableX.init`) is injected automatically so every key
245
+ * is namespaced to `{user}/{app}` and apps cannot reach into each other's data.
246
+ *
247
+ * Requires an authenticated session (`sdk.auth`) and a configured cloud API
248
+ * base URL (see `ChatableXInitConfig.apiBaseUrl`).
249
+ */
250
+ interface ChatableXCloud {
251
+ /** Upload (overwrite) a file. Resolves once the bytes are stored in OSS. */
252
+ upload(fileKey: string, data: CloudUploadData, options?: CloudUploadOptions): Promise<CloudUploadResult>;
253
+ /** Download a file's bytes as a Blob. */
254
+ download(fileKey: string): Promise<Blob>;
255
+ /** Get a short-lived presigned GET URL (e.g. to feed an `<img src>`). */
256
+ getDownloadUrl(fileKey: string): Promise<string>;
257
+ /** List the current app's files for this user. */
258
+ list(options?: CloudListOptions): Promise<CloudFileInfo[]>;
259
+ /** Delete a file. Resolves even if the object did not exist. */
260
+ delete(fileKey: string): Promise<void>;
261
+ /** Read the account's storage usage / quota. */
262
+ usage(): Promise<CloudUsage>;
263
+ }
159
264
  interface ChatableXSDK {
160
265
  ai: ChatableXAI;
161
266
  tools: ChatableXTools;
@@ -164,6 +269,8 @@ interface ChatableXSDK {
164
269
  storage: ChatableXStorage;
165
270
  tool: ChatableXToolModule;
166
271
  platform: ChatableXPlatform;
272
+ auth: ChatableXAuth;
273
+ cloud: ChatableXCloud;
167
274
  }
168
275
  declare global {
169
276
  interface Window {
@@ -210,6 +317,33 @@ declare class Bridge {
210
317
  destroy(): void;
211
318
  }
212
319
 
320
+ /** Base error for all `sdk.cloud` failures. */
321
+ declare class CloudError extends Error {
322
+ /** Business code from auth-fc (or the HTTP status when none was returned). */
323
+ readonly code: number;
324
+ constructor(message: string, code: number);
325
+ }
326
+ /**
327
+ * Thrown when no authenticated session is available. The app should prompt the
328
+ * user to log in to ChatableX before retrying.
329
+ */
330
+ declare class CloudAuthRequiredError extends CloudError {
331
+ constructor(message?: string);
332
+ }
333
+ /**
334
+ * Thrown when the user lacks the entitlement (purchased tool / membership)
335
+ * required to write to cloud storage. Maps to auth-fc code `40302`.
336
+ */
337
+ declare class CloudSubscriptionRequiredError extends CloudError {
338
+ constructor(message?: string);
339
+ }
340
+ /** Thrown when the upload would exceed the user's storage quota (code `40301`). */
341
+ declare class CloudQuotaExceededError extends CloudError {
342
+ readonly usedBytes: number;
343
+ readonly quotaBytes: number;
344
+ constructor(usedBytes: number, quotaBytes: number, message?: string);
345
+ }
346
+
213
347
  /**
214
348
  * chatablex-web-sdk
215
349
  *
@@ -252,4 +386,4 @@ declare const ChatableX: {
252
386
  version: string;
253
387
  };
254
388
 
255
- export { type AiResponseEventData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXEvents, type ChatableXInitConfig, type ChatableXPlatform, type ChatableXSDK, type ChatableXStorage, type ChatableXToolModule, type ChatableXTools, type ChatableXUI, type CloseEventData, type EventCallbackMap, type EventType, type FilePickerOptions, type Message, type NotificationType, SDK_VERSION, type SessionContext, type StateUpdate, type StreamingContentEventData, type TabConfig, type ToolCall, type ToolExecuteHandler, type ToolExecutionEventData, type ToolInfo, type ToolParameter, type ToolResult, type Unsubscribe, type UserMessageEventData };
389
+ export { type AiResponseEventData, type AuthTokenData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXAuth, type ChatableXCloud, type ChatableXEvents, type ChatableXInitConfig, type ChatableXPlatform, type ChatableXSDK, type ChatableXStorage, type ChatableXToolModule, type ChatableXTools, type ChatableXUI, type CloseEventData, CloudAuthRequiredError, CloudError, type CloudFileInfo, type CloudListOptions, CloudQuotaExceededError, CloudSubscriptionRequiredError, type CloudUploadData, type CloudUploadOptions, type CloudUploadResult, type CloudUsage, type EventCallbackMap, type EventType, type FilePickerOptions, type Message, type NotificationType, SDK_VERSION, type SessionContext, type StateUpdate, type StreamingContentEventData, type TabConfig, type ToolCall, type ToolExecuteHandler, type ToolExecutionEventData, type ToolInfo, type ToolParameter, type ToolResult, type Unsubscribe, type UserMessageEventData };