chatablex-web-sdk 1.0.0 → 1.0.31
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 +754 -109
- package/README.zh-CN.md +751 -107
- package/dist/index.d.mts +44 -33
- package/dist/index.d.ts +44 -33
- package/dist/index.js +131 -10
- package/dist/index.mjs +131 -10
- package/package.json +13 -4
- package/src/bridge.ts +1 -1
- package/src/index.ts +6 -3
- package/src/modules/auth.ts +102 -0
- package/src/modules/platform.ts +14 -0
- package/src/modules/ui.ts +2 -2
- package/src/types.ts +48 -38
- package/src/modules/skills.ts +0 -14
package/dist/index.d.mts
CHANGED
|
@@ -66,31 +66,6 @@ interface ToolResult {
|
|
|
66
66
|
duration?: number;
|
|
67
67
|
}
|
|
68
68
|
type ToolExecuteHandler = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
69
|
-
interface Skill {
|
|
70
|
-
id: string;
|
|
71
|
-
name: string;
|
|
72
|
-
description: string;
|
|
73
|
-
version: string;
|
|
74
|
-
author?: string;
|
|
75
|
-
category?: string;
|
|
76
|
-
toolIds: string[];
|
|
77
|
-
variables: SkillVariable[];
|
|
78
|
-
installed: boolean;
|
|
79
|
-
}
|
|
80
|
-
interface SkillVariable {
|
|
81
|
-
name: string;
|
|
82
|
-
type: string;
|
|
83
|
-
description: string;
|
|
84
|
-
required: boolean;
|
|
85
|
-
default?: unknown;
|
|
86
|
-
}
|
|
87
|
-
interface SkillResult {
|
|
88
|
-
success: boolean;
|
|
89
|
-
data?: unknown;
|
|
90
|
-
error?: string;
|
|
91
|
-
skillId: string;
|
|
92
|
-
toolResults?: ToolResult[];
|
|
93
|
-
}
|
|
94
69
|
type NotificationType = 'info' | 'success' | 'warning' | 'error';
|
|
95
70
|
interface FilePickerOptions {
|
|
96
71
|
type?: 'any' | 'image' | 'video' | 'audio' | 'custom';
|
|
@@ -155,10 +130,6 @@ interface ChatableXTools {
|
|
|
155
130
|
execute(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
156
131
|
executeWithConfirm(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
157
132
|
}
|
|
158
|
-
interface ChatableXSkills {
|
|
159
|
-
list(): Promise<Skill[]>;
|
|
160
|
-
execute(skillId: string, variables: Record<string, unknown>): Promise<SkillResult>;
|
|
161
|
-
}
|
|
162
133
|
interface ChatableXUI {
|
|
163
134
|
showNotification(message: string, type?: NotificationType): Promise<void>;
|
|
164
135
|
showConfirm(title: string, message: string): Promise<boolean>;
|
|
@@ -181,14 +152,54 @@ interface ChatableXToolModule {
|
|
|
181
152
|
getInfo(): ToolInfo;
|
|
182
153
|
onExecute(handler: ToolExecuteHandler): void;
|
|
183
154
|
}
|
|
155
|
+
interface ChatableXPlatform {
|
|
156
|
+
/** Open URL in system browser with auth handoff (WebView only; implemented by Flutter host). */
|
|
157
|
+
openInBrowser(targetUrl: string): Promise<void>;
|
|
158
|
+
}
|
|
159
|
+
/** Token payload returned by the host (never includes the refresh_token). */
|
|
160
|
+
interface AuthTokenData {
|
|
161
|
+
/** Bearer access token to put in the Authorization header. */
|
|
162
|
+
access_token: string;
|
|
163
|
+
/** Access token expiry, epoch milliseconds. */
|
|
164
|
+
expires_at: number;
|
|
165
|
+
/** Authenticated user id. */
|
|
166
|
+
user_id: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Unified auth entry point for all WebUI apps.
|
|
170
|
+
*
|
|
171
|
+
* In a hosted (Flutter WebView) environment this reuses the desktop login
|
|
172
|
+
* session via the `host.getAuthToken` bridge call — apps never implement
|
|
173
|
+
* login or token handling themselves.
|
|
174
|
+
*/
|
|
175
|
+
interface ChatableXAuth {
|
|
176
|
+
/**
|
|
177
|
+
* Get a valid access token. Returns the in-memory cached token when still
|
|
178
|
+
* valid, otherwise fetches a fresh one from the host. Returns `null` when
|
|
179
|
+
* not authenticated / not hosted.
|
|
180
|
+
*/
|
|
181
|
+
getToken(): Promise<AuthTokenData | null>;
|
|
182
|
+
/**
|
|
183
|
+
* Build auth headers ready to spread into a `fetch`. Returns
|
|
184
|
+
* `{ Authorization: "Bearer <token>" }` when authenticated, otherwise `{}`.
|
|
185
|
+
*/
|
|
186
|
+
getAuthHeaders(): Promise<Record<string, string>>;
|
|
187
|
+
/** Currently authenticated user id, or `null`. Synchronous (cache only). */
|
|
188
|
+
getUserId(): string | null;
|
|
189
|
+
/** Whether a valid token is currently cached. Synchronous (cache only). */
|
|
190
|
+
isAuthenticated(): boolean;
|
|
191
|
+
/** Force a token refresh via the host. Resolves `true` on success. */
|
|
192
|
+
refresh(): Promise<boolean>;
|
|
193
|
+
}
|
|
184
194
|
interface ChatableXSDK {
|
|
185
195
|
ai: ChatableXAI;
|
|
186
196
|
tools: ChatableXTools;
|
|
187
|
-
skills: ChatableXSkills;
|
|
188
197
|
ui: ChatableXUI;
|
|
189
198
|
events: ChatableXEvents;
|
|
190
199
|
storage: ChatableXStorage;
|
|
191
200
|
tool: ChatableXToolModule;
|
|
201
|
+
platform: ChatableXPlatform;
|
|
202
|
+
auth: ChatableXAuth;
|
|
192
203
|
}
|
|
193
204
|
declare global {
|
|
194
205
|
interface Window {
|
|
@@ -224,7 +235,7 @@ declare class Bridge {
|
|
|
224
235
|
/** Wait for ChatableXBridge (set by Flutter) to become available. */
|
|
225
236
|
waitForBridge(timeoutMs: number): Promise<void>;
|
|
226
237
|
/** Send a request to Flutter and wait for a response. */
|
|
227
|
-
sendMessage(method: string, params?:
|
|
238
|
+
sendMessage(method: string, params?: object, requestTimeoutMs?: number): Promise<unknown>;
|
|
228
239
|
private _handleResponse;
|
|
229
240
|
private _handleEvent;
|
|
230
241
|
addEventListener(eventType: string, handler: EventHandler): () => void;
|
|
@@ -255,7 +266,7 @@ declare class Bridge {
|
|
|
255
266
|
* ```
|
|
256
267
|
*/
|
|
257
268
|
|
|
258
|
-
declare const SDK_VERSION
|
|
269
|
+
declare const SDK_VERSION: string;
|
|
259
270
|
/**
|
|
260
271
|
* Main entry point. Provides `ChatableX.init()` to bootstrap the SDK.
|
|
261
272
|
*/
|
|
@@ -277,4 +288,4 @@ declare const ChatableX: {
|
|
|
277
288
|
version: string;
|
|
278
289
|
};
|
|
279
290
|
|
|
280
|
-
export { type AiResponseEventData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXEvents, type ChatableXInitConfig, type
|
|
291
|
+
export { type AiResponseEventData, type AuthTokenData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXAuth, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -66,31 +66,6 @@ interface ToolResult {
|
|
|
66
66
|
duration?: number;
|
|
67
67
|
}
|
|
68
68
|
type ToolExecuteHandler = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
69
|
-
interface Skill {
|
|
70
|
-
id: string;
|
|
71
|
-
name: string;
|
|
72
|
-
description: string;
|
|
73
|
-
version: string;
|
|
74
|
-
author?: string;
|
|
75
|
-
category?: string;
|
|
76
|
-
toolIds: string[];
|
|
77
|
-
variables: SkillVariable[];
|
|
78
|
-
installed: boolean;
|
|
79
|
-
}
|
|
80
|
-
interface SkillVariable {
|
|
81
|
-
name: string;
|
|
82
|
-
type: string;
|
|
83
|
-
description: string;
|
|
84
|
-
required: boolean;
|
|
85
|
-
default?: unknown;
|
|
86
|
-
}
|
|
87
|
-
interface SkillResult {
|
|
88
|
-
success: boolean;
|
|
89
|
-
data?: unknown;
|
|
90
|
-
error?: string;
|
|
91
|
-
skillId: string;
|
|
92
|
-
toolResults?: ToolResult[];
|
|
93
|
-
}
|
|
94
69
|
type NotificationType = 'info' | 'success' | 'warning' | 'error';
|
|
95
70
|
interface FilePickerOptions {
|
|
96
71
|
type?: 'any' | 'image' | 'video' | 'audio' | 'custom';
|
|
@@ -155,10 +130,6 @@ interface ChatableXTools {
|
|
|
155
130
|
execute(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
156
131
|
executeWithConfirm(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
157
132
|
}
|
|
158
|
-
interface ChatableXSkills {
|
|
159
|
-
list(): Promise<Skill[]>;
|
|
160
|
-
execute(skillId: string, variables: Record<string, unknown>): Promise<SkillResult>;
|
|
161
|
-
}
|
|
162
133
|
interface ChatableXUI {
|
|
163
134
|
showNotification(message: string, type?: NotificationType): Promise<void>;
|
|
164
135
|
showConfirm(title: string, message: string): Promise<boolean>;
|
|
@@ -181,14 +152,54 @@ interface ChatableXToolModule {
|
|
|
181
152
|
getInfo(): ToolInfo;
|
|
182
153
|
onExecute(handler: ToolExecuteHandler): void;
|
|
183
154
|
}
|
|
155
|
+
interface ChatableXPlatform {
|
|
156
|
+
/** Open URL in system browser with auth handoff (WebView only; implemented by Flutter host). */
|
|
157
|
+
openInBrowser(targetUrl: string): Promise<void>;
|
|
158
|
+
}
|
|
159
|
+
/** Token payload returned by the host (never includes the refresh_token). */
|
|
160
|
+
interface AuthTokenData {
|
|
161
|
+
/** Bearer access token to put in the Authorization header. */
|
|
162
|
+
access_token: string;
|
|
163
|
+
/** Access token expiry, epoch milliseconds. */
|
|
164
|
+
expires_at: number;
|
|
165
|
+
/** Authenticated user id. */
|
|
166
|
+
user_id: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Unified auth entry point for all WebUI apps.
|
|
170
|
+
*
|
|
171
|
+
* In a hosted (Flutter WebView) environment this reuses the desktop login
|
|
172
|
+
* session via the `host.getAuthToken` bridge call — apps never implement
|
|
173
|
+
* login or token handling themselves.
|
|
174
|
+
*/
|
|
175
|
+
interface ChatableXAuth {
|
|
176
|
+
/**
|
|
177
|
+
* Get a valid access token. Returns the in-memory cached token when still
|
|
178
|
+
* valid, otherwise fetches a fresh one from the host. Returns `null` when
|
|
179
|
+
* not authenticated / not hosted.
|
|
180
|
+
*/
|
|
181
|
+
getToken(): Promise<AuthTokenData | null>;
|
|
182
|
+
/**
|
|
183
|
+
* Build auth headers ready to spread into a `fetch`. Returns
|
|
184
|
+
* `{ Authorization: "Bearer <token>" }` when authenticated, otherwise `{}`.
|
|
185
|
+
*/
|
|
186
|
+
getAuthHeaders(): Promise<Record<string, string>>;
|
|
187
|
+
/** Currently authenticated user id, or `null`. Synchronous (cache only). */
|
|
188
|
+
getUserId(): string | null;
|
|
189
|
+
/** Whether a valid token is currently cached. Synchronous (cache only). */
|
|
190
|
+
isAuthenticated(): boolean;
|
|
191
|
+
/** Force a token refresh via the host. Resolves `true` on success. */
|
|
192
|
+
refresh(): Promise<boolean>;
|
|
193
|
+
}
|
|
184
194
|
interface ChatableXSDK {
|
|
185
195
|
ai: ChatableXAI;
|
|
186
196
|
tools: ChatableXTools;
|
|
187
|
-
skills: ChatableXSkills;
|
|
188
197
|
ui: ChatableXUI;
|
|
189
198
|
events: ChatableXEvents;
|
|
190
199
|
storage: ChatableXStorage;
|
|
191
200
|
tool: ChatableXToolModule;
|
|
201
|
+
platform: ChatableXPlatform;
|
|
202
|
+
auth: ChatableXAuth;
|
|
192
203
|
}
|
|
193
204
|
declare global {
|
|
194
205
|
interface Window {
|
|
@@ -224,7 +235,7 @@ declare class Bridge {
|
|
|
224
235
|
/** Wait for ChatableXBridge (set by Flutter) to become available. */
|
|
225
236
|
waitForBridge(timeoutMs: number): Promise<void>;
|
|
226
237
|
/** Send a request to Flutter and wait for a response. */
|
|
227
|
-
sendMessage(method: string, params?:
|
|
238
|
+
sendMessage(method: string, params?: object, requestTimeoutMs?: number): Promise<unknown>;
|
|
228
239
|
private _handleResponse;
|
|
229
240
|
private _handleEvent;
|
|
230
241
|
addEventListener(eventType: string, handler: EventHandler): () => void;
|
|
@@ -255,7 +266,7 @@ declare class Bridge {
|
|
|
255
266
|
* ```
|
|
256
267
|
*/
|
|
257
268
|
|
|
258
|
-
declare const SDK_VERSION
|
|
269
|
+
declare const SDK_VERSION: string;
|
|
259
270
|
/**
|
|
260
271
|
* Main entry point. Provides `ChatableX.init()` to bootstrap the SDK.
|
|
261
272
|
*/
|
|
@@ -277,4 +288,4 @@ declare const ChatableX: {
|
|
|
277
288
|
version: string;
|
|
278
289
|
};
|
|
279
290
|
|
|
280
|
-
export { type AiResponseEventData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXEvents, type ChatableXInitConfig, type
|
|
291
|
+
export { type AiResponseEventData, type AuthTokenData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXAuth, 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 };
|
package/dist/index.js
CHANGED
|
@@ -286,20 +286,140 @@ function createToolsModule(bridge) {
|
|
|
286
286
|
};
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
// src/modules/
|
|
290
|
-
function
|
|
289
|
+
// src/modules/platform.ts
|
|
290
|
+
function createPlatformModule(bridge) {
|
|
291
291
|
return {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
292
|
+
async openInBrowser(targetUrl) {
|
|
293
|
+
const url = typeof targetUrl === "string" ? targetUrl.trim() : "";
|
|
294
|
+
if (!url) {
|
|
295
|
+
throw new Error("openInBrowser: targetUrl is required");
|
|
296
|
+
}
|
|
297
|
+
await bridge.sendMessage("host.openInBrowser", { url });
|
|
297
298
|
}
|
|
298
299
|
};
|
|
299
300
|
}
|
|
300
301
|
|
|
302
|
+
// src/modules/auth.ts
|
|
303
|
+
var EXPIRY_SKEW_MS = 5e3;
|
|
304
|
+
function isValid(token, now) {
|
|
305
|
+
return !!token && typeof token.access_token === "string" && token.access_token.length > 0 && token.expires_at - EXPIRY_SKEW_MS > now;
|
|
306
|
+
}
|
|
307
|
+
var HostAuthProvider = class {
|
|
308
|
+
constructor(bridge) {
|
|
309
|
+
this._token = null;
|
|
310
|
+
/** In-flight refresh, so concurrent callers share one host round-trip. */
|
|
311
|
+
this._refreshing = null;
|
|
312
|
+
this._bridge = bridge;
|
|
313
|
+
}
|
|
314
|
+
async getToken() {
|
|
315
|
+
if (isValid(this._token, Date.now())) return this._token;
|
|
316
|
+
const ok = await this.refresh();
|
|
317
|
+
return ok ? this._token : null;
|
|
318
|
+
}
|
|
319
|
+
async getAuthHeaders() {
|
|
320
|
+
const token = await this.getToken();
|
|
321
|
+
if (!token) return {};
|
|
322
|
+
return { Authorization: `Bearer ${token.access_token}` };
|
|
323
|
+
}
|
|
324
|
+
getUserId() {
|
|
325
|
+
return this._token?.user_id ?? null;
|
|
326
|
+
}
|
|
327
|
+
isAuthenticated() {
|
|
328
|
+
return isValid(this._token, Date.now());
|
|
329
|
+
}
|
|
330
|
+
refresh() {
|
|
331
|
+
if (this._refreshing) return this._refreshing;
|
|
332
|
+
this._refreshing = this._doRefresh().finally(() => {
|
|
333
|
+
this._refreshing = null;
|
|
334
|
+
});
|
|
335
|
+
return this._refreshing;
|
|
336
|
+
}
|
|
337
|
+
async _doRefresh() {
|
|
338
|
+
try {
|
|
339
|
+
const raw = await this._bridge.sendMessage("host.getAuthToken");
|
|
340
|
+
if (raw && typeof raw === "object" && typeof raw.access_token === "string" && raw.access_token.length > 0) {
|
|
341
|
+
this._token = {
|
|
342
|
+
access_token: raw.access_token,
|
|
343
|
+
expires_at: Number(raw.expires_at) || 0,
|
|
344
|
+
user_id: String(raw.user_id ?? "")
|
|
345
|
+
};
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
this._token = null;
|
|
349
|
+
return false;
|
|
350
|
+
} catch {
|
|
351
|
+
this._token = null;
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
function createAuthModule(bridge) {
|
|
357
|
+
return new HostAuthProvider(bridge);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// package.json
|
|
361
|
+
var package_default = {
|
|
362
|
+
name: "chatablex-web-sdk",
|
|
363
|
+
version: "1.0.31",
|
|
364
|
+
description: "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
|
|
365
|
+
main: "dist/index.js",
|
|
366
|
+
module: "dist/index.mjs",
|
|
367
|
+
types: "dist/index.d.ts",
|
|
368
|
+
exports: {
|
|
369
|
+
".": {
|
|
370
|
+
types: "./dist/index.d.ts",
|
|
371
|
+
import: "./dist/index.mjs",
|
|
372
|
+
require: "./dist/index.js"
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
files: [
|
|
376
|
+
"dist",
|
|
377
|
+
"src",
|
|
378
|
+
"README.md",
|
|
379
|
+
"README.zh-CN.md"
|
|
380
|
+
],
|
|
381
|
+
scripts: {
|
|
382
|
+
build: "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
383
|
+
dev: "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
384
|
+
typecheck: "tsc --noEmit",
|
|
385
|
+
test: "vitest run",
|
|
386
|
+
"test:watch": "vitest",
|
|
387
|
+
"test:examples": "npm test --prefix examples/counter-app && npm test --prefix examples/todo-app",
|
|
388
|
+
"build:examples": "npm run build --prefix examples/counter-app && npm run build --prefix examples/todo-app",
|
|
389
|
+
"deploy:examples": "bash scripts/deploy-examples.sh",
|
|
390
|
+
"test:e2e": "node scripts/e2e-verify.mjs",
|
|
391
|
+
"verify:all": "npm test && npm run test:examples && npm run build:examples && npm run deploy:examples && npm run test:e2e",
|
|
392
|
+
"sync-version": "node scripts/sync-version.mjs",
|
|
393
|
+
prepublishOnly: "npm run build"
|
|
394
|
+
},
|
|
395
|
+
keywords: [
|
|
396
|
+
"chatablex",
|
|
397
|
+
"sdk",
|
|
398
|
+
"webui",
|
|
399
|
+
"ai",
|
|
400
|
+
"flutter",
|
|
401
|
+
"webview",
|
|
402
|
+
"bridge"
|
|
403
|
+
],
|
|
404
|
+
author: "ChatableX Team",
|
|
405
|
+
license: "MIT",
|
|
406
|
+
repository: {
|
|
407
|
+
type: "git",
|
|
408
|
+
url: "https://github.com/chatablex/chatablex-web-sdk.git"
|
|
409
|
+
},
|
|
410
|
+
devDependencies: {
|
|
411
|
+
jsdom: "^26.0.0",
|
|
412
|
+
tsup: "^8.0.1",
|
|
413
|
+
typescript: "^5.3.0",
|
|
414
|
+
vitest: "^3.0.0"
|
|
415
|
+
},
|
|
416
|
+
engines: {
|
|
417
|
+
node: ">=16.0.0"
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
301
421
|
// src/index.ts
|
|
302
|
-
var SDK_VERSION =
|
|
422
|
+
var SDK_VERSION = package_default.version;
|
|
303
423
|
var _instance = null;
|
|
304
424
|
var ChatableX = {
|
|
305
425
|
/**
|
|
@@ -335,11 +455,12 @@ var ChatableX = {
|
|
|
335
455
|
const sdk = {
|
|
336
456
|
ai: createAIModule(bridge),
|
|
337
457
|
tools: createToolsModule(bridge),
|
|
338
|
-
skills: createSkillsModule(bridge),
|
|
339
458
|
ui: createUIModule(bridge),
|
|
340
459
|
events: createEventsModule(bridge),
|
|
341
460
|
storage: createStorageModule(bridge),
|
|
342
|
-
tool: toolModule
|
|
461
|
+
tool: toolModule,
|
|
462
|
+
platform: createPlatformModule(bridge),
|
|
463
|
+
auth: createAuthModule(bridge)
|
|
343
464
|
};
|
|
344
465
|
window.ChatableX = sdk;
|
|
345
466
|
_instance = sdk;
|
package/dist/index.mjs
CHANGED
|
@@ -258,20 +258,140 @@ function createToolsModule(bridge) {
|
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
// src/modules/
|
|
262
|
-
function
|
|
261
|
+
// src/modules/platform.ts
|
|
262
|
+
function createPlatformModule(bridge) {
|
|
263
263
|
return {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
async openInBrowser(targetUrl) {
|
|
265
|
+
const url = typeof targetUrl === "string" ? targetUrl.trim() : "";
|
|
266
|
+
if (!url) {
|
|
267
|
+
throw new Error("openInBrowser: targetUrl is required");
|
|
268
|
+
}
|
|
269
|
+
await bridge.sendMessage("host.openInBrowser", { url });
|
|
269
270
|
}
|
|
270
271
|
};
|
|
271
272
|
}
|
|
272
273
|
|
|
274
|
+
// src/modules/auth.ts
|
|
275
|
+
var EXPIRY_SKEW_MS = 5e3;
|
|
276
|
+
function isValid(token, now) {
|
|
277
|
+
return !!token && typeof token.access_token === "string" && token.access_token.length > 0 && token.expires_at - EXPIRY_SKEW_MS > now;
|
|
278
|
+
}
|
|
279
|
+
var HostAuthProvider = class {
|
|
280
|
+
constructor(bridge) {
|
|
281
|
+
this._token = null;
|
|
282
|
+
/** In-flight refresh, so concurrent callers share one host round-trip. */
|
|
283
|
+
this._refreshing = null;
|
|
284
|
+
this._bridge = bridge;
|
|
285
|
+
}
|
|
286
|
+
async getToken() {
|
|
287
|
+
if (isValid(this._token, Date.now())) return this._token;
|
|
288
|
+
const ok = await this.refresh();
|
|
289
|
+
return ok ? this._token : null;
|
|
290
|
+
}
|
|
291
|
+
async getAuthHeaders() {
|
|
292
|
+
const token = await this.getToken();
|
|
293
|
+
if (!token) return {};
|
|
294
|
+
return { Authorization: `Bearer ${token.access_token}` };
|
|
295
|
+
}
|
|
296
|
+
getUserId() {
|
|
297
|
+
return this._token?.user_id ?? null;
|
|
298
|
+
}
|
|
299
|
+
isAuthenticated() {
|
|
300
|
+
return isValid(this._token, Date.now());
|
|
301
|
+
}
|
|
302
|
+
refresh() {
|
|
303
|
+
if (this._refreshing) return this._refreshing;
|
|
304
|
+
this._refreshing = this._doRefresh().finally(() => {
|
|
305
|
+
this._refreshing = null;
|
|
306
|
+
});
|
|
307
|
+
return this._refreshing;
|
|
308
|
+
}
|
|
309
|
+
async _doRefresh() {
|
|
310
|
+
try {
|
|
311
|
+
const raw = await this._bridge.sendMessage("host.getAuthToken");
|
|
312
|
+
if (raw && typeof raw === "object" && typeof raw.access_token === "string" && raw.access_token.length > 0) {
|
|
313
|
+
this._token = {
|
|
314
|
+
access_token: raw.access_token,
|
|
315
|
+
expires_at: Number(raw.expires_at) || 0,
|
|
316
|
+
user_id: String(raw.user_id ?? "")
|
|
317
|
+
};
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
this._token = null;
|
|
321
|
+
return false;
|
|
322
|
+
} catch {
|
|
323
|
+
this._token = null;
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
function createAuthModule(bridge) {
|
|
329
|
+
return new HostAuthProvider(bridge);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// package.json
|
|
333
|
+
var package_default = {
|
|
334
|
+
name: "chatablex-web-sdk",
|
|
335
|
+
version: "1.0.31",
|
|
336
|
+
description: "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
|
|
337
|
+
main: "dist/index.js",
|
|
338
|
+
module: "dist/index.mjs",
|
|
339
|
+
types: "dist/index.d.ts",
|
|
340
|
+
exports: {
|
|
341
|
+
".": {
|
|
342
|
+
types: "./dist/index.d.ts",
|
|
343
|
+
import: "./dist/index.mjs",
|
|
344
|
+
require: "./dist/index.js"
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
files: [
|
|
348
|
+
"dist",
|
|
349
|
+
"src",
|
|
350
|
+
"README.md",
|
|
351
|
+
"README.zh-CN.md"
|
|
352
|
+
],
|
|
353
|
+
scripts: {
|
|
354
|
+
build: "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
355
|
+
dev: "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
356
|
+
typecheck: "tsc --noEmit",
|
|
357
|
+
test: "vitest run",
|
|
358
|
+
"test:watch": "vitest",
|
|
359
|
+
"test:examples": "npm test --prefix examples/counter-app && npm test --prefix examples/todo-app",
|
|
360
|
+
"build:examples": "npm run build --prefix examples/counter-app && npm run build --prefix examples/todo-app",
|
|
361
|
+
"deploy:examples": "bash scripts/deploy-examples.sh",
|
|
362
|
+
"test:e2e": "node scripts/e2e-verify.mjs",
|
|
363
|
+
"verify:all": "npm test && npm run test:examples && npm run build:examples && npm run deploy:examples && npm run test:e2e",
|
|
364
|
+
"sync-version": "node scripts/sync-version.mjs",
|
|
365
|
+
prepublishOnly: "npm run build"
|
|
366
|
+
},
|
|
367
|
+
keywords: [
|
|
368
|
+
"chatablex",
|
|
369
|
+
"sdk",
|
|
370
|
+
"webui",
|
|
371
|
+
"ai",
|
|
372
|
+
"flutter",
|
|
373
|
+
"webview",
|
|
374
|
+
"bridge"
|
|
375
|
+
],
|
|
376
|
+
author: "ChatableX Team",
|
|
377
|
+
license: "MIT",
|
|
378
|
+
repository: {
|
|
379
|
+
type: "git",
|
|
380
|
+
url: "https://github.com/chatablex/chatablex-web-sdk.git"
|
|
381
|
+
},
|
|
382
|
+
devDependencies: {
|
|
383
|
+
jsdom: "^26.0.0",
|
|
384
|
+
tsup: "^8.0.1",
|
|
385
|
+
typescript: "^5.3.0",
|
|
386
|
+
vitest: "^3.0.0"
|
|
387
|
+
},
|
|
388
|
+
engines: {
|
|
389
|
+
node: ">=16.0.0"
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
273
393
|
// src/index.ts
|
|
274
|
-
var SDK_VERSION =
|
|
394
|
+
var SDK_VERSION = package_default.version;
|
|
275
395
|
var _instance = null;
|
|
276
396
|
var ChatableX = {
|
|
277
397
|
/**
|
|
@@ -307,11 +427,12 @@ var ChatableX = {
|
|
|
307
427
|
const sdk = {
|
|
308
428
|
ai: createAIModule(bridge),
|
|
309
429
|
tools: createToolsModule(bridge),
|
|
310
|
-
skills: createSkillsModule(bridge),
|
|
311
430
|
ui: createUIModule(bridge),
|
|
312
431
|
events: createEventsModule(bridge),
|
|
313
432
|
storage: createStorageModule(bridge),
|
|
314
|
-
tool: toolModule
|
|
433
|
+
tool: toolModule,
|
|
434
|
+
platform: createPlatformModule(bridge),
|
|
435
|
+
auth: createAuthModule(bridge)
|
|
315
436
|
};
|
|
316
437
|
window.ChatableX = sdk;
|
|
317
438
|
_instance = sdk;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatablex-web-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
23
23
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:examples": "npm test --prefix examples/counter-app && npm test --prefix examples/todo-app",
|
|
28
|
+
"build:examples": "npm run build --prefix examples/counter-app && npm run build --prefix examples/todo-app",
|
|
29
|
+
"deploy:examples": "bash scripts/deploy-examples.sh",
|
|
30
|
+
"test:e2e": "node scripts/e2e-verify.mjs",
|
|
31
|
+
"verify:all": "npm test && npm run test:examples && npm run build:examples && npm run deploy:examples && npm run test:e2e",
|
|
32
|
+
"sync-version": "node scripts/sync-version.mjs",
|
|
25
33
|
"prepublishOnly": "npm run build"
|
|
26
34
|
},
|
|
27
35
|
"keywords": [
|
|
@@ -37,12 +45,13 @@
|
|
|
37
45
|
"license": "MIT",
|
|
38
46
|
"repository": {
|
|
39
47
|
"type": "git",
|
|
40
|
-
"url": "https://github.com/
|
|
41
|
-
"directory": "chatablex-web-sdk"
|
|
48
|
+
"url": "https://github.com/chatablex/chatablex-web-sdk.git"
|
|
42
49
|
},
|
|
43
50
|
"devDependencies": {
|
|
51
|
+
"jsdom": "^26.0.0",
|
|
44
52
|
"tsup": "^8.0.1",
|
|
45
|
-
"typescript": "^5.3.0"
|
|
53
|
+
"typescript": "^5.3.0",
|
|
54
|
+
"vitest": "^3.0.0"
|
|
46
55
|
},
|
|
47
56
|
"engines": {
|
|
48
57
|
"node": ">=16.0.0"
|
package/src/bridge.ts
CHANGED
|
@@ -70,7 +70,7 @@ export class Bridge {
|
|
|
70
70
|
// -------------------------------------------------------------------------
|
|
71
71
|
|
|
72
72
|
/** Send a request to Flutter and wait for a response. */
|
|
73
|
-
sendMessage(method: string, params:
|
|
73
|
+
sendMessage(method: string, params: object = {}, requestTimeoutMs = 30_000): Promise<unknown> {
|
|
74
74
|
return new Promise((resolve, reject) => {
|
|
75
75
|
const id = this._nextId();
|
|
76
76
|
const message = { id, method, params, timestamp: Date.now() };
|
package/src/index.ts
CHANGED
|
@@ -25,10 +25,12 @@ import { createAIModule } from './modules/ai';
|
|
|
25
25
|
import { createUIModule } from './modules/ui';
|
|
26
26
|
import { createStorageModule } from './modules/storage';
|
|
27
27
|
import { createToolsModule } from './modules/tools';
|
|
28
|
-
import {
|
|
28
|
+
import { createPlatformModule } from './modules/platform';
|
|
29
|
+
import { createAuthModule } from './modules/auth';
|
|
29
30
|
import type { ChatableXSDK, ChatableXInitConfig, ToolInfo } from './types';
|
|
31
|
+
import pkg from '../package.json';
|
|
30
32
|
|
|
31
|
-
export const SDK_VERSION =
|
|
33
|
+
export const SDK_VERSION = pkg.version;
|
|
32
34
|
|
|
33
35
|
let _instance: ChatableXSDK | null = null;
|
|
34
36
|
|
|
@@ -80,11 +82,12 @@ export const ChatableX = {
|
|
|
80
82
|
const sdk: ChatableXSDK = {
|
|
81
83
|
ai: createAIModule(bridge),
|
|
82
84
|
tools: createToolsModule(bridge),
|
|
83
|
-
skills: createSkillsModule(bridge),
|
|
84
85
|
ui: createUIModule(bridge),
|
|
85
86
|
events: createEventsModule(bridge),
|
|
86
87
|
storage: createStorageModule(bridge),
|
|
87
88
|
tool: toolModule,
|
|
89
|
+
platform: createPlatformModule(bridge),
|
|
90
|
+
auth: createAuthModule(bridge),
|
|
88
91
|
};
|
|
89
92
|
|
|
90
93
|
// Expose on window for debugging / Flutter interop
|