@amaster.ai/client 1.0.0-alpha.1

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 ADDED
@@ -0,0 +1,847 @@
1
+ # @amaster.ai/client
2
+
3
+ > Unified API client for the Amaster platform - All services in one package
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@amaster.ai/client.svg)](https://www.npmjs.com/package/@amaster.ai/client)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## 🤖 AI-Friendly Documentation
9
+
10
+ This package is designed with AI tools (GitHub Copilot, Cursor, etc.) in mind:
11
+
12
+ - **Modular Type Definitions**: API documentation split into focused modules
13
+ - **Rich JSDoc**: Every method includes detailed descriptions and examples
14
+ - **On-Demand Loading**: AI tools only load relevant type files when needed
15
+ - **Type-Driven Learning**: Full TypeScript support helps AI understand API patterns
16
+
17
+ ### Type Documentation Structure
18
+
19
+ ```
20
+ types/
21
+ ├── index.d.ts # Main entry (lightweight)
22
+ ├── auth/ # Authentication (split into 7 focused modules)
23
+ │ ├── user.d.ts
24
+ │ ├── password-auth.d.ts
25
+ │ ├── code-auth.d.ts
26
+ │ ├── oauth.d.ts
27
+ │ ├── permissions.d.ts
28
+ │ ├── profile.d.ts
29
+ │ └── index.d.ts
30
+ ├── entity.d.ts # Entity CRUD operations
31
+ ├── bpm.d.ts # Business Process Management
32
+ ├── workflow.d.ts # Workflow execution
33
+ ├── asr.d.ts # Speech Recognition (WebSocket)
34
+ ├── copilot.d.ts # AI Assistant / Chat
35
+ ├── function.d.ts # Function invocation
36
+ └── tts.d.ts # Text-to-Speech (WebSocket)
37
+ ```
38
+
39
+ Each module contains:
40
+
41
+ - Complete method signatures
42
+ - Parameter descriptions
43
+ - Return type definitions
44
+ - Multiple usage examples
45
+ - Best practices
46
+
47
+ ## 🚀 Overview
48
+
49
+ `@amaster.ai/client` is a unified JavaScript/TypeScript client that provides a simple, consistent interface to all Amaster platform services. Inspired by Supabase's elegant API design, it offers:
50
+
51
+ ✨ **Single client instance** for all services
52
+ 🔐 **Automatic authentication** - tokens attached to all requests
53
+ 🔄 **Token auto-refresh** - never worry about expiration
54
+ 📦 **Type-safe** - Full TypeScript support with auto-completion
55
+ 🎯 **Simple API** - Clean, consistent method naming
56
+ 🌐 **Complete Integration** - Auth, Entity, BPM, Workflow, ASR, Copilot, Function, TTS, S3
57
+
58
+ ## 📦 Installation
59
+
60
+ ```bash
61
+ # npm
62
+ npm install @amaster.ai/client axios
63
+
64
+ # pnpm
65
+ pnpm add @amaster.ai/client axios
66
+
67
+ # yarn
68
+ yarn add @amaster.ai/client axios
69
+ ```
70
+
71
+ ## 🎯 Quick Start
72
+
73
+ ```typescript
74
+ import { createClient } from "@amaster.ai/client";
75
+
76
+ // 1. Create client instance (baseURL is optional)
77
+ const client = createClient({
78
+ baseURL: "https://api.amaster.ai", // Optional - auto-detects from env in Taro/Mini-program
79
+ onUnauthorized: () => {
80
+ // Handle unauthorized (redirect to login, show modal, etc.)
81
+ window.location.href = "/login";
82
+ },
83
+ });
84
+
85
+ // Or simply:
86
+ // const client = createClient({}); // Auto-uses VITE_API_BASE_URL or dev proxy
87
+
88
+ // 2. Login
89
+ await client.auth.login({
90
+ email: "user@example.com",
91
+ password: "password123",
92
+ });
93
+
94
+ // 3. Use any service - auth token is automatically attached!
95
+ const users = await client.entity.list("default", "users");
96
+ const tasks = await client.bpm.getMyTasks();
97
+ const result = await client.workflow.execute("my-workflow", { input: {} });
98
+ ```
99
+
100
+ ## 🔑 Authentication
101
+
102
+ ### Login
103
+
104
+ ```typescript
105
+ // Email/Password login
106
+ const result = await client.auth.login({
107
+ email: "user@example.com",
108
+ password: "password123",
109
+ });
110
+
111
+ if (result.success) {
112
+ console.log("Logged in:", result.data.user);
113
+ }
114
+ ```
115
+
116
+ ### Register
117
+
118
+ ```typescript
119
+ const result = await client.auth.register({
120
+ username: "johndoe",
121
+ email: "john@example.com",
122
+ password: "securePassword123",
123
+ });
124
+ ```
125
+
126
+ ### Get Current User
127
+
128
+ ```typescript
129
+ const result = await client.auth.getMe();
130
+ if (result.success) {
131
+ console.log("Current user:", result.data);
132
+ }
133
+ ```
134
+
135
+ ### Logout
136
+
137
+ ```typescript
138
+ await client.auth.logout();
139
+ ```
140
+
141
+ ### Check Authentication Status
142
+
143
+ ```typescript
144
+ if (client.isAuthenticated()) {
145
+ console.log("User is logged in");
146
+ }
147
+ ```
148
+
149
+ ## 📊 Entity Operations (CRUD)
150
+
151
+ Full CRUD operations for your data entities with type safety.
152
+
153
+ ### List Entities
154
+
155
+ ```typescript
156
+ const result = await client.entity.list("default", "users", {
157
+ page: 1,
158
+ perPage: 20,
159
+ orderBy: "createdAt",
160
+ orderDir: "desc",
161
+ // Filters
162
+ "status[eq]": "active",
163
+ "age[gt]": 18,
164
+ });
165
+
166
+ if (result.success) {
167
+ const { items, total, page, perPage } = result.data;
168
+ console.log(`Found ${total} users`);
169
+ }
170
+ ```
171
+
172
+ ### Get Single Entity
173
+
174
+ ```typescript
175
+ const result = await client.entity.get("default", "users", 123);
176
+ if (result.success) {
177
+ console.log("User:", result.data);
178
+ }
179
+ ```
180
+
181
+ ### Create Entity
182
+
183
+ ```typescript
184
+ const result = await client.entity.create("default", "users", {
185
+ name: "John Doe",
186
+ email: "john@example.com",
187
+ status: "active",
188
+ });
189
+ ```
190
+
191
+ ### Update Entity
192
+
193
+ ```typescript
194
+ const result = await client.entity.update("default", "users", 123, {
195
+ name: "Jane Doe",
196
+ status: "inactive",
197
+ });
198
+ ```
199
+
200
+ ### Delete Entity
201
+
202
+ ```typescript
203
+ await client.entity.delete("default", "users", 123);
204
+ ```
205
+
206
+ ### Bulk Operations
207
+
208
+ ```typescript
209
+ // Bulk update
210
+ await client.entity.bulkUpdate("default", "users", [
211
+ { id: 1, status: "active" },
212
+ { id: 2, status: "inactive" },
213
+ ]);
214
+
215
+ // Bulk delete
216
+ await client.entity.bulkDelete("default", "users", [1, 2, 3]);
217
+ ```
218
+
219
+ ## 🔄 BPM (Business Process Management)
220
+
221
+ Manage business processes powered by Camunda 7.
222
+
223
+ ### Start a Process
224
+
225
+ ```typescript
226
+ const result = await client.bpm.startProcess({
227
+ processKey: "approval-process",
228
+ businessKey: "ORDER-12345",
229
+ variables: {
230
+ amount: 1000,
231
+ requester: "john@example.com",
232
+ },
233
+ });
234
+ ```
235
+
236
+ ### Get My Tasks
237
+
238
+ ```typescript
239
+ const result = await client.bpm.getMyTasks({
240
+ page: 1,
241
+ perPage: 20,
242
+ sortBy: "created",
243
+ sortOrder: "desc",
244
+ });
245
+
246
+ if (result.success) {
247
+ console.log("Tasks:", result.data.items);
248
+ }
249
+ ```
250
+
251
+ ### Complete a Task
252
+
253
+ ```typescript
254
+ await client.bpm.completeTask("task-id", {
255
+ approved: true,
256
+ comments: "Looks good!",
257
+ });
258
+ ```
259
+
260
+ ### Claim a Task
261
+
262
+ ```typescript
263
+ await client.bpm.claimTask("task-id");
264
+ ```
265
+
266
+ ## ⚡ Workflow Execution
267
+
268
+ Execute workflows and automation flows.
269
+
270
+ ```typescript
271
+ const result = await client.workflow.execute("data-processing-workflow", {
272
+ input: {
273
+ dataSource: "users",
274
+ filters: { status: "active" },
275
+ },
276
+ });
277
+
278
+ if (result.success) {
279
+ console.log("Workflow result:", result.data);
280
+ }
281
+ ```
282
+
283
+ ## 🎙️ ASR (Automatic Speech Recognition)
284
+
285
+ 实时语音识别支持 WebSocket 流式识别和 HTTP 按压识别两种方式。
286
+
287
+ ### WebSocket ASR(实时流式识别)
288
+
289
+ 适合需要实时看到识别结果的场景,如语音输入、实时字幕等。
290
+
291
+ ```tsx
292
+ import { useRef, useState } from "react";
293
+ import type { ASRClient } from "@amaster.ai/client";
294
+
295
+ function ASRRealtimeDemo() {
296
+ const asrRef = useRef<ASRClient | null>(null);
297
+ const [result, setResult] = useState("");
298
+ const [status, setStatus] = useState("idle"); // idle | connecting | ready | error | closed
299
+
300
+ const start = async () => {
301
+ let finalResult = "";
302
+ let temp = "";
303
+
304
+ setStatus("connecting");
305
+
306
+ const asrClient = client.asr({
307
+ onReady() {
308
+ setStatus("ready");
309
+ },
310
+ onTranscript(text, isFinal) {
311
+ if (!isFinal) {
312
+ temp = text;
313
+ setResult(finalResult + temp);
314
+ } else {
315
+ temp = "";
316
+ finalResult += text;
317
+ setResult(finalResult);
318
+ }
319
+ },
320
+ onError(err) {
321
+ console.error(err);
322
+ setStatus("error");
323
+ },
324
+ onClose() {
325
+ setStatus("closed");
326
+ },
327
+ });
328
+
329
+ await asrClient.connect();
330
+ await asrClient.startRecording();
331
+ asrRef.current = asrClient;
332
+ };
333
+
334
+ const stop = () => {
335
+ asrRef.current?.stopRecording();
336
+ asrRef.current?.close();
337
+ asrRef.current = null;
338
+ setStatus("idle");
339
+ };
340
+
341
+ return (
342
+ <div>
343
+ <div>状态: {status}</div>
344
+ <button onClick={start} disabled={status === "connecting" || status === "ready"}>
345
+ 开始录音
346
+ </button>
347
+ <button onClick={stop} disabled={status !== "ready"}>
348
+ 停止
349
+ </button>
350
+ <div>识别结果: {result || "(等待说话...)"}</div>
351
+ </div>
352
+ );
353
+ }
354
+ ```
355
+
356
+ ### HTTP ASR(按压识别)
357
+
358
+ 适合按住说话、松开识别的场景,如语音消息、语音搜索等。
359
+
360
+ ```tsx
361
+ import { useRef, useState } from "react";
362
+ import type { ASRHttpClient } from "@amaster.ai/client";
363
+
364
+ function ASRPressToTalkDemo() {
365
+ const clientRef = useRef<ASRHttpClient | null>(null);
366
+ const [recording, setRecording] = useState(false);
367
+ const [text, setText] = useState("");
368
+ const [error, setError] = useState<string | null>(null);
369
+
370
+ if (!clientRef.current) {
371
+ clientRef.current = client.asrHttp({
372
+ onRecordingStart() {
373
+ setRecording(true);
374
+ setText("");
375
+ setError(null);
376
+ },
377
+ onRecordingStop() {
378
+ setRecording(false);
379
+ },
380
+ onResult(result) {
381
+ setText(result);
382
+ },
383
+ onError(err) {
384
+ setError(err.message);
385
+ },
386
+ });
387
+ }
388
+
389
+ const asrHttpClient = clientRef.current;
390
+
391
+ return (
392
+ <div>
393
+ <button
394
+ onMouseDown={() => asrHttpClient.startRecording()}
395
+ onMouseUp={() => asrHttpClient.stopRecording()}
396
+ onTouchStart={() => asrHttpClient.startRecording()}
397
+ onTouchEnd={() => asrHttpClient.stopRecording()}
398
+ style={{
399
+ padding: "12px 24px",
400
+ background: recording ? "#f87171" : "#4ade80",
401
+ }}
402
+ >
403
+ {recording ? "松开识别" : "按住说话"}
404
+ </button>
405
+
406
+ <div>
407
+ <strong>识别结果:</strong>
408
+ <div>{text || "(暂无)"}</div>
409
+ </div>
410
+
411
+ {error && <div style={{ color: "red" }}>错误:{error}</div>}
412
+ </div>
413
+ );
414
+ }
415
+ ```
416
+
417
+ **ASR Client 配置说明:**
418
+
419
+ | 参数 | 类型 | 说明 |
420
+ | ------------------ | ------------------------------------------ | ------------------------------ |
421
+ | `onReady` | `() => void` | 会话创建完成 |
422
+ | `onSpeechStart` | `() => void` | 检测到语音开始(仅 WebSocket) |
423
+ | `onSpeechEnd` | `() => void` | 检测到语音结束(仅 WebSocket) |
424
+ | `onTranscript` | `(text: string, isFinal: boolean) => void` | 转写回调(WebSocket) |
425
+ | `onRecordingStart` | `() => void` | 录音开始回调(仅 HTTP) |
426
+ | `onRecordingStop` | `() => void` | 录音停止回调(仅 HTTP) |
427
+ | `onResult` | `(text: string) => void` | 识别结果回调(HTTP) |
428
+ | `onError` | `(error: Error) => void` | 错误回调 |
429
+ | `onClose` | `() => void` | 连接关闭回调(WebSocket) |
430
+
431
+ ## 🔊 TTS (Text-to-Speech)
432
+
433
+ WebSocket 实时语音合成。
434
+
435
+ ```tsx
436
+ import { useRef, useState } from "react";
437
+ import type { TTSClient } from "@amaster.ai/client";
438
+
439
+ function TTSDemo() {
440
+ const [voice, setVoice] = useState("Cherry");
441
+ const [connected, setConnected] = useState(false);
442
+ const [status, setStatus] = useState("disconnected");
443
+ const [text, setText] = useState("你好,欢迎使用实时语音合成服务。");
444
+ const clientRef = useRef<TTSClient | null>(null);
445
+
446
+ const connectTTS = () => {
447
+ if (clientRef.current) return;
448
+
449
+ const ttsClient = client.tts({
450
+ voice,
451
+ autoPlay: true,
452
+ audioFormat: "pcm",
453
+ sampleRate: 24000,
454
+ onReady: () => {
455
+ setConnected(true);
456
+ setStatus("connected");
457
+ },
458
+ onAudioStart: () => setStatus("playing"),
459
+ onAudioEnd: () => setStatus("connected"),
460
+ onAudioChunk: (chunks) => {
461
+ console.log("收到音频片段:", chunks.length);
462
+ },
463
+ onError: (err) => {
464
+ console.error("TTS Error:", err);
465
+ setStatus("error");
466
+ },
467
+ });
468
+
469
+ ttsClient.connect();
470
+ clientRef.current = ttsClient;
471
+ };
472
+
473
+ const sendTTS = () => {
474
+ if (!text || !clientRef.current) return;
475
+ clientRef.current.speak(text);
476
+ setStatus("sending");
477
+ };
478
+
479
+ const disconnectTTS = () => {
480
+ clientRef.current?.close();
481
+ clientRef.current = null;
482
+ setConnected(false);
483
+ setStatus("disconnected");
484
+ };
485
+
486
+ return (
487
+ <div>
488
+ <h3>🔊 实时语音合成</h3>
489
+ <div>状态: {status}</div>
490
+
491
+ <div>
492
+ <label>音色:</label>
493
+ <select value={voice} onChange={(e) => setVoice(e.target.value)}>
494
+ <option value="Cherry">Cherry - 甜美女声</option>
495
+ <option value="Serena">苏瑶 - 温柔小姐姐</option>
496
+ <option value="Ethan">晨煦 - 标准普通话</option>
497
+ <option value="Chelsie">千雪 - 二次元虚拟女友</option>
498
+ <option value="Peter">天津话</option>
499
+ </select>
500
+ </div>
501
+
502
+ <div>
503
+ <label>合成文本:</label>
504
+ <textarea rows={4} value={text} onChange={(e) => setText(e.target.value)} />
505
+ </div>
506
+
507
+ <div>
508
+ <button onClick={connectTTS} disabled={connected}>
509
+ 连接
510
+ </button>
511
+ <button onClick={sendTTS} disabled={!connected}>
512
+ 合成语音
513
+ </button>
514
+ <button onClick={disconnectTTS} disabled={!connected}>
515
+ 断开
516
+ </button>
517
+ </div>
518
+ </div>
519
+ );
520
+ }
521
+ ```
522
+
523
+ **TTS Client 配置说明:**
524
+
525
+ | 参数 | 类型 | 默认值 | 说明 |
526
+ | -------------- | ----------------------------------- | ---------- | ------------------------------ |
527
+ | `voice` | `string` | `"Cherry"` | 发音人名称 |
528
+ | `autoPlay` | `boolean` | `true` | 是否自动播放 |
529
+ | `audioFormat` | `"pcm" \| "mp3" \| "wav" \| "opus"` | `"pcm"` | 音频格式(内置播放仅支持 pcm) |
530
+ | `sampleRate` | `number` | `24000` | 采样率 |
531
+ | `onReady` | `() => void` | - | 会话就绪回调 |
532
+ | `onAudioStart` | `() => void` | - | 音频开始播放回调 |
533
+ | `onAudioEnd` | `() => void` | - | 音频播放结束回调 |
534
+ | `onAudioChunk` | `(chunks: string[]) => void` | - | 音频分片回调 |
535
+ | `onError` | `(error: Error) => void` | - | 错误回调 |
536
+
537
+ ## 🤖 Copilot (AI Assistant)
538
+
539
+ AI assistant / chatbot API.
540
+
541
+ ```typescript
542
+ // Simple chat
543
+ const result = await client.copilot.sendMessage([
544
+ { role: "user", content: "Hello, how can you help?" },
545
+ ]);
546
+
547
+ console.log(result.data.content);
548
+
549
+ // Streaming response
550
+ await client.copilot.sendMessage([{ role: "user", content: "Tell me a story" }], {
551
+ stream: true,
552
+ onChunk: (chunk) => console.log(chunk),
553
+ });
554
+ ```
555
+
556
+ ## ⚙️ Function Invocation
557
+
558
+ 调用服务端函数。
559
+
560
+ ```typescript
561
+ // Call a function
562
+ const result = await client.function.invoke<{ result: string }>("sendEmail", {
563
+ to: "user@example.com",
564
+ subject: "Hello",
565
+ });
566
+
567
+ if (result.data) {
568
+ console.log("Function result:", result.data.result);
569
+ }
570
+ ```
571
+
572
+ ## ☁️ S3 Storage
573
+
574
+ 文件上传下载。
575
+
576
+ ```typescript
577
+ // Upload file
578
+ await client.s3.upload(file);
579
+
580
+ // Download file
581
+ await client.s3.download("path/to/file");
582
+ ```
583
+
584
+ ## ⚙️ Configuration
585
+
586
+ ### Client Options
587
+
588
+ ```typescript
589
+ interface AmasterClientOptions {
590
+ /** Base URL for the Amaster API */
591
+ baseURL: string;
592
+
593
+ /** Optional custom headers */
594
+ headers?: Record<string, string>;
595
+
596
+ /** Called when receiving 401 Unauthorized */
597
+ onUnauthorized?: () => void;
598
+
599
+ /** Called when token expires (before auto-refresh) */
600
+ onTokenExpired?: () => void;
601
+
602
+ /** Enable automatic token refresh (default: true) */
603
+ autoRefresh?: boolean;
604
+
605
+ /** Refresh threshold in seconds (default: 300) */
606
+ refreshThreshold?: number;
607
+
608
+ /** Automatically handle OAuth callback on initialization (default: true) */
609
+ autoHandleOAuthCallback?: boolean;
610
+ }
611
+ ```
612
+
613
+ ### Example with All Options
614
+
615
+ ```typescript
616
+ const client = createClient({
617
+ baseURL: "https://api.amaster.ai",
618
+
619
+ headers: {
620
+ "X-App-Version": "1.0.0",
621
+ },
622
+
623
+ onUnauthorized: () => {
624
+ console.log("Session expired, redirecting to login...");
625
+ window.location.href = "/login";
626
+ },
627
+
628
+ onTokenExpired: () => {
629
+ console.log("Token expired, will auto-refresh");
630
+ },
631
+
632
+ autoRefresh: true,
633
+ refreshThreshold: 300, // Refresh 5 minutes before expiry
634
+ });
635
+ ```
636
+
637
+ ## 🔧 Advanced Usage
638
+
639
+ ### Manual Token Management
640
+
641
+ ```typescript
642
+ // Get current access token
643
+ const token = client.getAccessToken();
644
+
645
+ // Set token manually (useful for SSR or external auth)
646
+ client.setAccessToken("your-jwt-token");
647
+
648
+ // Clear all auth data
649
+ client.clearAuth();
650
+ ```
651
+
652
+ ### Error Handling
653
+
654
+ ```typescript
655
+ const result = await client.entity.list("default", "users");
656
+
657
+ if (result.success) {
658
+ // Success case
659
+ console.log("Data:", result.data);
660
+ } else {
661
+ // Error case
662
+ console.error("Error:", result.error);
663
+ console.error("Status:", result.statusCode);
664
+ }
665
+ ```
666
+
667
+ ### Custom HTTP Requests
668
+
669
+ ```typescript
670
+ // Make a custom request with automatic auth
671
+ const { data, error } = await client.http.request({
672
+ url: "/custom/endpoint",
673
+ method: "POST",
674
+ data: { key: "value" },
675
+ });
676
+ ```
677
+
678
+ ## 🎨 Comparison with Individual Clients
679
+
680
+ ### Before (Using separate clients)
681
+
682
+ ```typescript
683
+ import { createAuthClient } from "@amaster.ai/auth-client";
684
+ import { createEntityClient } from "@amaster.ai/entity-client";
685
+ import { createBpmClient } from "@amaster.ai/bpm-client";
686
+
687
+ const authClient = createAuthClient({ baseURL });
688
+ const entityClient = createEntityClient({ baseURL });
689
+ const bpmClient = createBpmClient({ baseURL });
690
+
691
+ // Need to manage tokens manually across clients
692
+ await authClient.login({ email, password });
693
+ const token = authClient.getAccessToken();
694
+
695
+ // Pass token to other clients somehow...
696
+ ```
697
+
698
+ ### After (Using unified client)
699
+
700
+ ```typescript
701
+ import { createClient } from "@amaster.ai/client";
702
+
703
+ const client = createClient({ baseURL });
704
+
705
+ // One client, automatic token management
706
+ await client.auth.login({ email, password });
707
+ await client.entity.list("default", "users"); // Token automatically attached
708
+ await client.bpm.getMyTasks(); // Token automatically attached
709
+ ```
710
+
711
+ ## 📖 API Reference
712
+
713
+ ### `client.auth`
714
+
715
+ Full authentication API from `@amaster.ai/auth-client`:
716
+
717
+ - `login(params)` - Email/password or code-based login
718
+ - `register(params)` - User registration
719
+ - `logout()` - User logout
720
+ - `getMe()` - Get current user profile
721
+ - `updateMe(params)` - Update current user
722
+ - `changePassword(params)` - Change password
723
+ - `refreshToken()` - Manually refresh token
724
+ - `sendCode(params)` - Send verification code
725
+ - `hasPermission(permission)` - Check user permission
726
+ - `hasRole(role)` - Check user role
727
+
728
+ ### `client.entity`
729
+
730
+ Full CRUD API from `@amaster.ai/entity-client`:
731
+
732
+ - `list(source, entity, params?)` - List entities with pagination
733
+ - `get(source, entity, id)` - Get single entity
734
+ - `create(source, entity, data)` - Create new entity
735
+ - `update(source, entity, id, data)` - Update entity
736
+ - `delete(source, entity, id)` - Delete entity
737
+ - `bulkUpdate(source, entity, items)` - Bulk update
738
+ - `bulkDelete(source, entity, ids)` - Bulk delete
739
+ - `options(source, entity, fields?)` - Get field options
740
+
741
+ ### `client.bpm`
742
+
743
+ Full BPM API from `@amaster.ai/bpm-client`:
744
+
745
+ - `startProcess(params)` - Start process instance
746
+ - `getMyTasks(params?)` - Get current user's tasks
747
+ - `completeTask(taskId, variables?)` - Complete a task
748
+ - `claimTask(taskId)` - Claim a task
749
+ - `unclaimTask(taskId)` - Unclaim a task
750
+ - And more...
751
+
752
+ ### `client.workflow`
753
+
754
+ Workflow execution API from `@amaster.ai/workflow-client`:
755
+
756
+ - `execute(workflowId, params)` - Execute a workflow
757
+ - `getStatus(executionId)` - Get execution status
758
+ - And more...
759
+
760
+ ### `client.asr`
761
+
762
+ WebSocket real-time speech recognition:
763
+
764
+ - `connect()` - Connect to ASR service
765
+ - `startRecording()` - Start microphone recording
766
+ - `stopRecording()` - Stop recording
767
+ - `close()` - Close connection
768
+
769
+ ### `client.asrHttp`
770
+
771
+ HTTP press-to-talk speech recognition:
772
+
773
+ - `startRecording()` - Start recording
774
+ - `stopRecording()` - Stop and get result
775
+ - `recognizeFile(file)` - Recognize audio file
776
+ - `recognizeUrl(url)` - Recognize audio URL
777
+
778
+ ### `client.tts`
779
+
780
+ WebSocket real-time text-to-speech:
781
+
782
+ - `connect()` - Connect to TTS service
783
+ - `speak(text)` - Synthesize and play speech
784
+ - `play()` - Manually play audio
785
+ - `close()` - Close connection
786
+
787
+ ### `client.copilot`
788
+
789
+ AI assistant API:
790
+
791
+ - `sendMessage(messages, options?)` - Send messages to AI
792
+
793
+ ### `client.function`
794
+
795
+ Function invocation API:
796
+
797
+ - `invoke<T>(funcName, params?)` - Invoke a serverless function
798
+
799
+ ### `client.s3`
800
+
801
+ S3 storage API:
802
+
803
+ - `upload(file)` - Upload file
804
+ - `download(path)` - Download file
805
+
806
+ ## 🔐 Token Management Flow
807
+
808
+ ```
809
+ 1. Login → Token stored automatically
810
+ 2. Request → Token attached to headers
811
+ 3. Response 401 → onUnauthorized() called
812
+ 4. Token near expiry → Auto-refresh (if enabled)
813
+ 5. Logout → Token cleared
814
+ ```
815
+
816
+ ## 🌐 Environment Support
817
+
818
+ Works in:
819
+
820
+ - ✅ Browser (modern)
821
+ - ✅ Node.js (18+)
822
+ - ✅ React / Vue / Angular
823
+ - ✅ Next.js / Nuxt
824
+ - ✅ React Native (with axios)
825
+
826
+ ## 📄 License
827
+
828
+ MIT © Amaster Team
829
+
830
+ ## 🤝 Related Packages
831
+
832
+ All these packages are now integrated into `@amaster.ai/client`:
833
+
834
+ - `@amaster.ai/auth-client` - Authentication (login, register, etc.)
835
+ - `@amaster.ai/entity-client` - Entity CRUD operations
836
+ - `@amaster.ai/bpm-client` - Business Process Management
837
+ - `@amaster.ai/workflow-client` - Workflow execution
838
+ - `@amaster.ai/asr-client` - Speech recognition (WebSocket + HTTP)
839
+ - `@amaster.ai/copilot-client` - AI assistant / chatbot
840
+ - `@amaster.ai/function-client` - Function invocation
841
+ - `@amaster.ai/tts-client` - Text-to-speech (WebSocket)
842
+ - `@amaster.ai/s3-client` - S3 storage operations
843
+ - `@amaster.ai/http-client` - HTTP client foundation (internal)
844
+
845
+ ## 💡 Inspiration
846
+
847
+ API design inspired by [Supabase](https://supabase.com) - aiming for the same level of developer experience and simplicity.