@amaster.ai/client 1.1.0-beta.49 → 1.1.0-beta.50

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
@@ -53,7 +53,7 @@ Each module contains:
53
53
  🔄 **Token auto-refresh** - never worry about expiration
54
54
  📦 **Type-safe** - Full TypeScript support with auto-completion
55
55
  🎯 **Simple API** - Clean, consistent method naming
56
- 🌐 **Complete Integration** - Auth, Entity, BPM, Workflow, ASR, Copilot, Function, TTS
56
+ 🌐 **Complete Integration** - Auth, Entity, BPM, Workflow, ASR, Copilot, Function, TTS, S3
57
57
 
58
58
  ## 📦 Installation
59
59
 
@@ -280,6 +280,307 @@ if (result.success) {
280
280
  }
281
281
  ```
282
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
+
283
584
  ## ⚙️ Configuration
284
585
 
285
586
  ### Client Options
@@ -303,6 +604,9 @@ interface AmasterClientOptions {
303
604
 
304
605
  /** Refresh threshold in seconds (default: 300) */
305
606
  refreshThreshold?: number;
607
+
608
+ /** Automatically handle OAuth callback on initialization (default: true) */
609
+ autoHandleOAuthCallback?: boolean;
306
610
  }
307
611
  ```
308
612
 
@@ -360,6 +664,17 @@ if (result.success) {
360
664
  }
361
665
  ```
362
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
+
363
678
  ## 🎨 Comparison with Individual Clients
364
679
 
365
680
  ### Before (Using separate clients)
@@ -444,101 +759,49 @@ Workflow execution API from `@amaster.ai/workflow-client`:
444
759
 
445
760
  ### `client.asr`
446
761
 
447
- Real-time speech recognition API from `@amaster.ai/asr-client`:
762
+ WebSocket real-time speech recognition:
448
763
 
449
- - `connect()` - Connect to ASR service via WebSocket
764
+ - `connect()` - Connect to ASR service
450
765
  - `startRecording()` - Start microphone recording
451
766
  - `stopRecording()` - Stop recording
452
767
  - `close()` - Close connection
453
768
 
454
- **Example:**
769
+ ### `client.asrHttp`
455
770
 
456
- ```typescript
457
- // Configure callbacks
458
- client.asr = createASRClient({
459
- onTranscript: (text, isFinal) => {
460
- console.log(isFinal ? `[FINAL] ${text}` : `[INTERIM] ${text}`);
461
- },
462
- });
771
+ HTTP press-to-talk speech recognition:
463
772
 
464
- // Connect and start
465
- await client.asr.connect();
466
- await client.asr.startRecording();
773
+ - `startRecording()` - Start recording
774
+ - `stopRecording()` - Stop and get result
775
+ - `recognizeFile(file)` - Recognize audio file
776
+ - `recognizeUrl(url)` - Recognize audio URL
467
777
 
468
- // Stop when done
469
- client.asr.stopRecording();
470
- client.asr.close();
471
- ```
472
-
473
- ### `client.copilot`
474
-
475
- AI assistant / chatbot API from `@amaster.ai/copilot-client`:
778
+ ### `client.tts`
476
779
 
477
- - `sendMessage(messages, options?)` - Send messages to AI assistant
780
+ WebSocket real-time text-to-speech:
478
781
 
479
- **Example:**
782
+ - `connect()` - Connect to TTS service
783
+ - `speak(text)` - Synthesize and play speech
784
+ - `play()` - Manually play audio
785
+ - `close()` - Close connection
480
786
 
481
- ```typescript
482
- // Simple chat
483
- const result = await client.copilot.sendMessage([
484
- { role: "user", content: "Hello, how can you help?" },
485
- ]);
787
+ ### `client.copilot`
486
788
 
487
- console.log(result.data.content);
789
+ AI assistant API:
488
790
 
489
- // Streaming response
490
- await client.copilot.sendMessage([{ role: "user", content: "Tell me a story" }], {
491
- stream: true,
492
- onChunk: (chunk) => console.log(chunk),
493
- });
494
- ```
791
+ - `sendMessage(messages, options?)` - Send messages to AI
495
792
 
496
793
  ### `client.function`
497
794
 
498
- Function invocation API from `@amaster.ai/function-client`:
795
+ Function invocation API:
499
796
 
500
797
  - `invoke<T>(funcName, params?)` - Invoke a serverless function
501
798
 
502
- **Example:**
799
+ ### `client.s3`
503
800
 
504
- ```typescript
505
- // Call a function
506
- const result = await client.function.invoke<{ result: string }>("sendEmail", {
507
- to: "user@example.com",
508
- subject: "Hello",
509
- });
510
-
511
- if (result.data) {
512
- console.log("Function result:", result.data.result);
513
- }
514
- ```
801
+ S3 storage API:
515
802
 
516
- ### `client.tts`
517
-
518
- Real-time text-to-speech API from `@amaster.ai/tts-client`:
519
-
520
- - `connect()` - Connect to TTS service via WebSocket
521
- - `speak(text)` - Synthesize and play speech
522
- - `play()` - Manually play audio (when autoPlay is off)
523
- - `close()` - Close connection
524
-
525
- **Example:**
526
-
527
- ```typescript
528
- // Configure TTS
529
- client.tts = createTTSClient({
530
- voice: "Cherry",
531
- autoPlay: true,
532
- onAudioStart: () => console.log("Playing audio"),
533
- });
534
-
535
- // Connect and speak
536
- await client.tts.connect();
537
- await client.tts.speak("Hello, welcome to Amaster!");
538
-
539
- // Close when done
540
- client.tts.close();
541
- ```
803
+ - `upload(file)` - Upload file
804
+ - `download(path)` - Download file
542
805
 
543
806
  ## 🔐 Token Management Flow
544
807
 
@@ -572,10 +835,11 @@ All these packages are now integrated into `@amaster.ai/client`:
572
835
  - `@amaster.ai/entity-client` - Entity CRUD operations
573
836
  - `@amaster.ai/bpm-client` - Business Process Management
574
837
  - `@amaster.ai/workflow-client` - Workflow execution
575
- - `@amaster.ai/asr-client` - Speech recognition (WebSocket)
838
+ - `@amaster.ai/asr-client` - Speech recognition (WebSocket + HTTP)
576
839
  - `@amaster.ai/copilot-client` - AI assistant / chatbot
577
840
  - `@amaster.ai/function-client` - Function invocation
578
841
  - `@amaster.ai/tts-client` - Text-to-speech (WebSocket)
842
+ - `@amaster.ai/s3-client` - S3 storage operations
579
843
  - `@amaster.ai/http-client` - HTTP client foundation (internal)
580
844
 
581
845
  ## 💡 Inspiration
package/dist/index.cjs CHANGED
@@ -130,6 +130,9 @@ function createClient(options) {
130
130
  const asr = asrClient.createASRClient({
131
131
  getAccessToken: () => auth.getAccessToken()
132
132
  });
133
+ const asrHttp = asrClient.createASRHttpClient({
134
+ getAccessToken: () => auth.getAccessToken()
135
+ });
133
136
  const tts = ttsClient.createTTSClient({
134
137
  getAccessToken: () => auth.getAccessToken()
135
138
  });
@@ -139,6 +142,7 @@ function createClient(options) {
139
142
  bpm,
140
143
  workflow,
141
144
  asr,
145
+ asrHttp,
142
146
  copilot,
143
147
  function: functionClient$1,
144
148
  tts,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["createHttpClient","createAuthClient","createEntityClient","createBpmClient","createWorkflowClient","functionClient","createFunctionClient","createCopilotClient","createS3Client","createASRClient","createTTSClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ============================================================================\n * @amaster.ai/client - Unified Amaster Client\n * ============================================================================\n *\n * Supabase-inspired unified API client for the Amaster platform\n *\n * Features:\n * - Single client instance for all services (auth, entity, bpm, workflow)\n * - Automatic token management and refresh\n * - Auto-attach authentication to all requests\n * - Centralized error handling\n *\n * @example\n * ```typescript\n * // With explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Auto-detect baseURL from env (Taro/Mini-program)\n * const client = createClient({\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Login\n * await client.auth.login({ email, password });\n *\n * // All subsequent requests automatically include auth token\n * await client.entity.list('default', 'users');\n * await client.bpm.startProcess({ processKey: 'approval' });\n * ```\n */\n\nimport { createAuthClient, type AuthClient } from \"@amaster.ai/auth-client\";\nimport { createEntityClient, type EntityClient } from \"@amaster.ai/entity-client\";\nimport { createBpmClient, type BpmClient } from \"@amaster.ai/bpm-client\";\nimport { createWorkflowClient, type WorkflowClient } from \"@amaster.ai/workflow-client\";\nimport { createASRClient, type ASRClient } from \"@amaster.ai/asr-client\";\nimport { createCopilotClient, type CopilotClient } from \"@amaster.ai/copilot-client\";\nimport { createFunctionClient, type FunctionClient } from \"@amaster.ai/function-client\";\nimport { createTTSClient, type TTSClient } from \"@amaster.ai/tts-client\";\nimport { createS3Client, type S3Client } from \"@amaster.ai/s3-client\";\nimport {\n createHttpClient,\n type HttpClient,\n type RequestConfig,\n type ClientResult,\n} from \"@amaster.ai/http-client\";\nimport type { AmasterClient, AmasterClientOptions } from \"./types\";\n\n/**\n * Create a unified Amaster client instance\n *\n * This function creates a single client that provides access to all Amaster services:\n * - Authentication (login, register, logout)\n * - Entity CRUD operations\n * - BPM (Business Process Management)\n * - Workflow execution\n *\n * All sub-clients automatically share the same HTTP client and authentication state,\n * ensuring that tokens are consistently attached to all requests.\n *\n * @param options - Client configuration options\n * @returns A unified Amaster client instance\n *\n * @example\n * ```typescript\n * // Basic usage with explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai'\n * });\n *\n * // Auto-detect baseURL (for Taro/Mini-program or dev proxy)\n * const client = createClient({});\n *\n * // With authentication callbacks\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => {\n * // Redirect to login or show auth modal\n * window.location.href = '/login';\n * },\n * onTokenExpired: () => {\n * console.log('Token expired, refreshing...');\n * }\n * });\n *\n * // Login\n * await client.auth.login({\n * email: 'user@example.com',\n * password: 'password123'\n * });\n *\n * // Now all requests automatically include the auth token\n * const users = await client.entity.list('default', 'users');\n * const tasks = await client.bpm.getMyTasks();\n * ```\n */\nexport function createClient(options: AmasterClientOptions): AmasterClient {\n const {\n baseURL,\n headers = {},\n onUnauthorized,\n onTokenExpired,\n autoHandleOAuthCallback,\n } = options;\n\n // Create the base HTTP client\n const baseHttpClient = createHttpClient({\n baseURL,\n headers,\n });\n\n // Create the auth client first (it manages its own HTTP client internally)\n const auth: AuthClient = createAuthClient({\n baseURL,\n headers,\n onTokenExpired,\n onUnauthorized,\n autoHandleOAuthCallback,\n });\n\n // Create a wrapper HTTP client that automatically adds the auth token\n const createAuthenticatedHttpClient = (): HttpClient => {\n // Track if we're currently refreshing to avoid multiple simultaneous refreshes\n let isRefreshing = false;\n let refreshPromise: Promise<boolean> | null = null;\n\n /**\n * Check if 401 error is due to token expiration\n * Traefik JWT plugin returns plain text like \"Jwt is expired\" or \"Token is expired\"\n */\n function isTokenExpired(result: ClientResult<unknown>): boolean {\n if (result.status !== 401) return false;\n\n // Check error message (could be from backend JSON response)\n if (result.error?.message && /expired/i.test(result.error.message)) {\n return true;\n }\n\n // Check error details (traefik returns plain text in details)\n if (result.error?.details) {\n const details = result.error.details;\n if (typeof details === \"string\" && /expired/i.test(details)) {\n return true;\n }\n // Also check if details is an object with message field\n if (typeof details === \"object\" && details !== null) {\n const detailsObj = details as Record<string, unknown>;\n if (typeof detailsObj.message === \"string\" && /expired/i.test(detailsObj.message)) {\n return true;\n }\n }\n }\n\n // Check raw data (could be plain text from traefik)\n if (typeof result.data === \"string\" && /expired/i.test(result.data)) {\n return true;\n }\n\n // If we have a token but got 401, assume it might be expired\n return !!auth.getAccessToken();\n }\n\n return {\n async request<T>(config: RequestConfig): Promise<ClientResult<T>> {\n // Get the current token from auth client\n const token = auth.getAccessToken();\n\n // Merge Authorization header with existing headers\n const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};\n const mergedConfig: RequestConfig = {\n ...config,\n headers: {\n ...config.headers,\n ...authHeaders,\n },\n };\n\n // Make the request with the updated config\n let result = await baseHttpClient.request<T>(mergedConfig);\n\n // Handle 401 errors with automatic token refresh\n if (result.status === 401 && isTokenExpired(result)) {\n // Attempt to refresh token\n if (!isRefreshing) {\n isRefreshing = true;\n refreshPromise = (async () => {\n try {\n const refreshResult = await auth.refreshToken();\n return !!refreshResult.data;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n })();\n }\n\n const refreshed = await refreshPromise;\n\n if (refreshed) {\n // Retry with new token\n const newToken = auth.getAccessToken();\n result = await baseHttpClient.request<T>({\n ...config,\n headers: {\n ...config.headers,\n ...(newToken ? { Authorization: `Bearer ${newToken}` } : {}),\n },\n });\n }\n }\n\n // Trigger unauthorized if still 401\n if (result.status === 401 && onUnauthorized) {\n onUnauthorized();\n }\n\n return result;\n },\n };\n };\n\n const authenticatedHttpClient = createAuthenticatedHttpClient();\n\n let cachedUserUid: string | null = null;\n\n auth.on(\"login\", (user: { uid?: string }) => {\n cachedUserUid = user?.uid ?? null;\n });\n auth.on(\"logout\", () => {\n cachedUserUid = null;\n });\n\n if (auth.isAuthenticated()) {\n auth\n .getMe()\n .then((result) => {\n if (result.data?.uid) {\n cachedUserUid = result.data.uid;\n }\n })\n .catch(() => {});\n }\n\n // Create other clients using the authenticated HTTP client\n const entity: EntityClient = createEntityClient(authenticatedHttpClient);\n const bpm: BpmClient = createBpmClient(authenticatedHttpClient);\n const workflow: WorkflowClient = createWorkflowClient(authenticatedHttpClient);\n const functionClient: FunctionClient = createFunctionClient(authenticatedHttpClient);\n const copilot: CopilotClient = createCopilotClient(\n authenticatedHttpClient,\n baseURL,\n () => auth.getAccessToken(),\n () => cachedUserUid\n );\n const s3: S3Client = createS3Client(authenticatedHttpClient);\n\n // ASR and TTS clients use WebSocket, pass token getter for authentication\n // Token can be appended to WebSocket URL as query parameter\n const asr: ASRClient = createASRClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n const tts: TTSClient = createTTSClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n\n // Return unified client interface\n const client: AmasterClient = {\n auth,\n entity,\n bpm,\n workflow,\n asr,\n copilot,\n function: functionClient,\n tts,\n s3,\n http: authenticatedHttpClient,\n\n // Expose token management methods from auth client\n isAuthenticated: () => auth.isAuthenticated(),\n getAccessToken: () => auth.getAccessToken(),\n setAccessToken: (token: string) => auth.setAccessToken(token),\n clearAuth: () => auth.clearAuth(),\n };\n\n return client;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":["createHttpClient","createAuthClient","createEntityClient","createBpmClient","createWorkflowClient","functionClient","createFunctionClient","createCopilotClient","createS3Client","createASRClient","createASRHttpClient","createTTSClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ============================================================================\n * @amaster.ai/client - Unified Amaster Client\n * ============================================================================\n *\n * Supabase-inspired unified API client for the Amaster platform\n *\n * Features:\n * - Single client instance for all services (auth, entity, bpm, workflow)\n * - Automatic token management and refresh\n * - Auto-attach authentication to all requests\n * - Centralized error handling\n *\n * @example\n * ```typescript\n * // With explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Auto-detect baseURL from env (Taro/Mini-program)\n * const client = createClient({\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Login\n * await client.auth.login({ email, password });\n *\n * // All subsequent requests automatically include auth token\n * await client.entity.list('default', 'users');\n * await client.bpm.startProcess({ processKey: 'approval' });\n * ```\n */\n\nimport { createAuthClient, type AuthClient } from \"@amaster.ai/auth-client\";\nimport { createEntityClient, type EntityClient } from \"@amaster.ai/entity-client\";\nimport { createBpmClient, type BpmClient } from \"@amaster.ai/bpm-client\";\nimport { createWorkflowClient, type WorkflowClient } from \"@amaster.ai/workflow-client\";\nimport {\n createASRClient,\n createASRHttpClient,\n type ASRClientConfig,\n type ASRClient,\n type ASRHttpClientConfig,\n type ASRHttpClient,\n} from \"@amaster.ai/asr-client\";\nimport { createCopilotClient, type CopilotClient } from \"@amaster.ai/copilot-client\";\nimport { createFunctionClient, type FunctionClient } from \"@amaster.ai/function-client\";\nimport { createTTSClient, TTSClientConfig, type TTSClient } from \"@amaster.ai/tts-client\";\nimport { createS3Client, type S3Client } from \"@amaster.ai/s3-client\";\nimport {\n createHttpClient,\n type HttpClient,\n type RequestConfig,\n type ClientResult,\n} from \"@amaster.ai/http-client\";\nimport type { AmasterClient, AmasterClientOptions } from \"./types\";\n\n/**\n * Create a unified Amaster client instance\n *\n * This function creates a single client that provides access to all Amaster services:\n * - Authentication (login, register, logout)\n * - Entity CRUD operations\n * - BPM (Business Process Management)\n * - Workflow execution\n *\n * All sub-clients automatically share the same HTTP client and authentication state,\n * ensuring that tokens are consistently attached to all requests.\n *\n * @param options - Client configuration options\n * @returns A unified Amaster client instance\n *\n * @example\n * ```typescript\n * // Basic usage with explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai'\n * });\n *\n * // Auto-detect baseURL (for Taro/Mini-program or dev proxy)\n * const client = createClient({});\n *\n * // With authentication callbacks\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => {\n * // Redirect to login or show auth modal\n * window.location.href = '/login';\n * },\n * onTokenExpired: () => {\n * console.log('Token expired, refreshing...');\n * }\n * });\n *\n * // Login\n * await client.auth.login({\n * email: 'user@example.com',\n * password: 'password123'\n * });\n *\n * // Now all requests automatically include the auth token\n * const users = await client.entity.list('default', 'users');\n * const tasks = await client.bpm.getMyTasks();\n * ```\n */\nexport function createClient(options: AmasterClientOptions): AmasterClient {\n const {\n baseURL,\n headers = {},\n onUnauthorized,\n onTokenExpired,\n autoHandleOAuthCallback,\n } = options;\n\n // Create the base HTTP client\n const baseHttpClient = createHttpClient({\n baseURL,\n headers,\n });\n\n // Create the auth client first (it manages its own HTTP client internally)\n const auth: AuthClient = createAuthClient({\n baseURL,\n headers,\n onTokenExpired,\n onUnauthorized,\n autoHandleOAuthCallback,\n });\n\n // Create a wrapper HTTP client that automatically adds the auth token\n const createAuthenticatedHttpClient = (): HttpClient => {\n // Track if we're currently refreshing to avoid multiple simultaneous refreshes\n let isRefreshing = false;\n let refreshPromise: Promise<boolean> | null = null;\n\n /**\n * Check if 401 error is due to token expiration\n * Traefik JWT plugin returns plain text like \"Jwt is expired\" or \"Token is expired\"\n */\n function isTokenExpired(result: ClientResult<unknown>): boolean {\n if (result.status !== 401) return false;\n\n // Check error message (could be from backend JSON response)\n if (result.error?.message && /expired/i.test(result.error.message)) {\n return true;\n }\n\n // Check error details (traefik returns plain text in details)\n if (result.error?.details) {\n const details = result.error.details;\n if (typeof details === \"string\" && /expired/i.test(details)) {\n return true;\n }\n // Also check if details is an object with message field\n if (typeof details === \"object\" && details !== null) {\n const detailsObj = details as Record<string, unknown>;\n if (typeof detailsObj.message === \"string\" && /expired/i.test(detailsObj.message)) {\n return true;\n }\n }\n }\n\n // Check raw data (could be plain text from traefik)\n if (typeof result.data === \"string\" && /expired/i.test(result.data)) {\n return true;\n }\n\n // If we have a token but got 401, assume it might be expired\n return !!auth.getAccessToken();\n }\n\n return {\n async request<T>(config: RequestConfig): Promise<ClientResult<T>> {\n // Get the current token from auth client\n const token = auth.getAccessToken();\n\n // Merge Authorization header with existing headers\n const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};\n const mergedConfig: RequestConfig = {\n ...config,\n headers: {\n ...config.headers,\n ...authHeaders,\n },\n };\n\n // Make the request with the updated config\n let result = await baseHttpClient.request<T>(mergedConfig);\n\n // Handle 401 errors with automatic token refresh\n if (result.status === 401 && isTokenExpired(result)) {\n // Attempt to refresh token\n if (!isRefreshing) {\n isRefreshing = true;\n refreshPromise = (async () => {\n try {\n const refreshResult = await auth.refreshToken();\n return !!refreshResult.data;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n })();\n }\n\n const refreshed = await refreshPromise;\n\n if (refreshed) {\n // Retry with new token\n const newToken = auth.getAccessToken();\n result = await baseHttpClient.request<T>({\n ...config,\n headers: {\n ...config.headers,\n ...(newToken ? { Authorization: `Bearer ${newToken}` } : {}),\n },\n });\n }\n }\n\n // Trigger unauthorized if still 401\n if (result.status === 401 && onUnauthorized) {\n onUnauthorized();\n }\n\n return result;\n },\n };\n };\n\n const authenticatedHttpClient = createAuthenticatedHttpClient();\n\n let cachedUserUid: string | null = null;\n\n auth.on(\"login\", (user: { uid?: string }) => {\n cachedUserUid = user?.uid ?? null;\n });\n auth.on(\"logout\", () => {\n cachedUserUid = null;\n });\n\n if (auth.isAuthenticated()) {\n auth\n .getMe()\n .then((result) => {\n if (result.data?.uid) {\n cachedUserUid = result.data.uid;\n }\n })\n .catch(() => {});\n }\n\n // Create other clients using the authenticated HTTP client\n const entity: EntityClient = createEntityClient(authenticatedHttpClient);\n const bpm: BpmClient = createBpmClient(authenticatedHttpClient);\n const workflow: WorkflowClient = createWorkflowClient(authenticatedHttpClient);\n const functionClient: FunctionClient = createFunctionClient(authenticatedHttpClient);\n const copilot: CopilotClient = createCopilotClient(\n authenticatedHttpClient,\n baseURL,\n () => auth.getAccessToken(),\n () => cachedUserUid\n );\n const s3: S3Client = createS3Client(authenticatedHttpClient);\n\n // ASR and TTS clients use WebSocket, pass token getter for authentication\n // Token can be appended to WebSocket URL as query parameter\n const asr: (config: ASRClientConfig) => ASRClient = createASRClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n const asrHttp: (config: ASRHttpClientConfig) => ASRHttpClient = createASRHttpClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n const tts: (config: TTSClientConfig) => TTSClient = createTTSClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n\n // Return unified client interface\n const client: AmasterClient = {\n auth,\n entity,\n bpm,\n workflow,\n asr,\n asrHttp,\n copilot,\n function: functionClient,\n tts,\n s3,\n http: authenticatedHttpClient,\n\n // Expose token management methods from auth client\n isAuthenticated: () => auth.isAuthenticated(),\n getAccessToken: () => auth.getAccessToken(),\n setAccessToken: (token: string) => auth.setAccessToken(token),\n clearAuth: () => auth.clearAuth(),\n };\n\n return client;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -6,13 +6,13 @@ import { BpmClient } from '@amaster.ai/bpm-client';
6
6
  export { ActivityInstanceTree, CamundaVariable, HistoryActivityInstance, HistoryProcessInstance, HistoryTask, ProcessInstance, ProcessVariable, Task, TaskFormSchema, TaskQueryParams, UserOperationLog } from '@amaster.ai/bpm-client';
7
7
  import { WorkflowClient } from '@amaster.ai/workflow-client';
8
8
  export { WorkflowFile, WorkflowInputValue, WorkflowRunRequest, WorkflowRunResponse } from '@amaster.ai/workflow-client';
9
- import { ASRClient } from '@amaster.ai/asr-client';
10
- export { ASRClient, ASRClientConfig } from '@amaster.ai/asr-client';
9
+ import { ASRClientConfig, ASRClient, ASRHttpClientConfig, ASRHttpClient } from '@amaster.ai/asr-client';
10
+ export { ASRClient, ASRClientConfig, ASRHttpClient, ASRHttpClientConfig } from '@amaster.ai/asr-client';
11
11
  import { CopilotClient } from '@amaster.ai/copilot-client';
12
12
  export { ChatMessage, ChatOptions, CopilotClient, FileContent, ImageContent, MessageContent, TextContent } from '@amaster.ai/copilot-client';
13
13
  import { FunctionClient } from '@amaster.ai/function-client';
14
14
  export { FunctionClient } from '@amaster.ai/function-client';
15
- import { TTSClient } from '@amaster.ai/tts-client';
15
+ import { TTSClientConfig, TTSClient } from '@amaster.ai/tts-client';
16
16
  export { TTSClient, TTSClientConfig } from '@amaster.ai/tts-client';
17
17
  import { S3Client } from '@amaster.ai/s3-client';
18
18
  export { S3Client, S3Metadata, UploadRes } from '@amaster.ai/s3-client';
@@ -154,21 +154,67 @@ interface AmasterClient {
154
154
  */
155
155
  workflow: WorkflowClient;
156
156
  /**
157
- * ASR (Automatic Speech Recognition) module
158
- * WebSocket-based real-time speech recognition
157
+ * ASR (Automatic Speech Recognition) module - WebSocket-based real-time speech recognition
158
+ *
159
+ * Suitable for scenarios requiring real-time transcription results, such as voice input, live captions, etc.
159
160
  *
160
161
  * @example
161
162
  * ```typescript
162
- * // Connect and start recording
163
- * await client.asr.connect();
164
- * await client.asr.startRecording();
163
+ * // Real-time streaming recognition
164
+ * const asrClient = client.asr({
165
+ * onReady() {
166
+ * console.log('ASR Ready');
167
+ * },
168
+ * onTranscript(text, isFinal) {
169
+ * console.log(isFinal ? '[Final]' : '[Interim]', text);
170
+ * },
171
+ * onError(err) {
172
+ * console.error('ASR Error:', err);
173
+ * },
174
+ * onClose() {
175
+ * console.log('ASR Connection Closed');
176
+ * },
177
+ * });
178
+ *
179
+ * await asrClient.connect();
180
+ * await asrClient.startRecording();
165
181
  *
166
182
  * // Stop and close
167
- * client.asr.stopRecording();
168
- * client.asr.close();
183
+ * asrClient.stopRecording();
184
+ * asrClient.close();
169
185
  * ```
170
186
  */
171
- asr: ASRClient;
187
+ asr: (config: ASRClientConfig) => ASRClient;
188
+ /**
189
+ * ASR Http module - HTTP-based press-to-talk speech recognition
190
+ *
191
+ * Suitable for press-to-talk scenarios where you hold to speak and release to recognize,
192
+ * such as voice messages, voice search, etc.
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * // Press-to-talk recognition
197
+ * const asrHttpClient = client.asrHttp({
198
+ * onRecordingStart() {
199
+ * console.log('Recording started');
200
+ * },
201
+ * onRecordingStop() {
202
+ * console.log('Recording stopped');
203
+ * },
204
+ * onResult(text) {
205
+ * console.log('Recognition result:', text);
206
+ * },
207
+ * onError(err) {
208
+ * console.error('ASR HTTP Error:', err);
209
+ * },
210
+ * });
211
+ *
212
+ * await asrHttpClient.startRecording();
213
+ * // ... user speaks ...
214
+ * const result = await asrHttpClient.stopRecording();
215
+ * ```
216
+ */
217
+ asrHttp: (config: ASRHttpClientConfig) => ASRHttpClient;
172
218
  /**
173
219
  * Copilot AI assistant module
174
220
  *
@@ -194,20 +240,35 @@ interface AmasterClient {
194
240
  */
195
241
  function: FunctionClient;
196
242
  /**
197
- * TTS (Text-to-Speech) module
198
- * WebSocket-based real-time speech synthesis
243
+ * TTS (Text-to-Speech) module - WebSocket-based real-time speech synthesis
244
+ *
245
+ * Supports multiple voices and audio formats. Built-in playback only supports PCM format.
199
246
  *
200
247
  * @example
201
248
  * ```typescript
202
249
  * // Connect and speak
203
- * await client.tts.connect();
204
- * await client.tts.speak('Hello world');
250
+ * const ttsClient = client.tts({
251
+ * voice: 'Cherry',
252
+ * autoPlay: true,
253
+ * onReady() {
254
+ * console.log('TTS Ready');
255
+ * },
256
+ * onAudioStart() {
257
+ * console.log('Playing audio');
258
+ * },
259
+ * onAudioEnd() {
260
+ * console.log('Audio playback ended');
261
+ * },
262
+ * });
263
+ *
264
+ * await ttsClient.connect();
265
+ * await ttsClient.speak('Hello, welcome to Amaster!');
205
266
  *
206
- * // Close connection
207
- * client.tts.close();
267
+ * // Close when done
268
+ * ttsClient.close();
208
269
  * ```
209
270
  */
210
- tts: TTSClient;
271
+ tts: (config: TTSClientConfig) => TTSClient;
211
272
  /**
212
273
  * S3 Storage module
213
274
  *
package/dist/index.d.ts CHANGED
@@ -6,13 +6,13 @@ import { BpmClient } from '@amaster.ai/bpm-client';
6
6
  export { ActivityInstanceTree, CamundaVariable, HistoryActivityInstance, HistoryProcessInstance, HistoryTask, ProcessInstance, ProcessVariable, Task, TaskFormSchema, TaskQueryParams, UserOperationLog } from '@amaster.ai/bpm-client';
7
7
  import { WorkflowClient } from '@amaster.ai/workflow-client';
8
8
  export { WorkflowFile, WorkflowInputValue, WorkflowRunRequest, WorkflowRunResponse } from '@amaster.ai/workflow-client';
9
- import { ASRClient } from '@amaster.ai/asr-client';
10
- export { ASRClient, ASRClientConfig } from '@amaster.ai/asr-client';
9
+ import { ASRClientConfig, ASRClient, ASRHttpClientConfig, ASRHttpClient } from '@amaster.ai/asr-client';
10
+ export { ASRClient, ASRClientConfig, ASRHttpClient, ASRHttpClientConfig } from '@amaster.ai/asr-client';
11
11
  import { CopilotClient } from '@amaster.ai/copilot-client';
12
12
  export { ChatMessage, ChatOptions, CopilotClient, FileContent, ImageContent, MessageContent, TextContent } from '@amaster.ai/copilot-client';
13
13
  import { FunctionClient } from '@amaster.ai/function-client';
14
14
  export { FunctionClient } from '@amaster.ai/function-client';
15
- import { TTSClient } from '@amaster.ai/tts-client';
15
+ import { TTSClientConfig, TTSClient } from '@amaster.ai/tts-client';
16
16
  export { TTSClient, TTSClientConfig } from '@amaster.ai/tts-client';
17
17
  import { S3Client } from '@amaster.ai/s3-client';
18
18
  export { S3Client, S3Metadata, UploadRes } from '@amaster.ai/s3-client';
@@ -154,21 +154,67 @@ interface AmasterClient {
154
154
  */
155
155
  workflow: WorkflowClient;
156
156
  /**
157
- * ASR (Automatic Speech Recognition) module
158
- * WebSocket-based real-time speech recognition
157
+ * ASR (Automatic Speech Recognition) module - WebSocket-based real-time speech recognition
158
+ *
159
+ * Suitable for scenarios requiring real-time transcription results, such as voice input, live captions, etc.
159
160
  *
160
161
  * @example
161
162
  * ```typescript
162
- * // Connect and start recording
163
- * await client.asr.connect();
164
- * await client.asr.startRecording();
163
+ * // Real-time streaming recognition
164
+ * const asrClient = client.asr({
165
+ * onReady() {
166
+ * console.log('ASR Ready');
167
+ * },
168
+ * onTranscript(text, isFinal) {
169
+ * console.log(isFinal ? '[Final]' : '[Interim]', text);
170
+ * },
171
+ * onError(err) {
172
+ * console.error('ASR Error:', err);
173
+ * },
174
+ * onClose() {
175
+ * console.log('ASR Connection Closed');
176
+ * },
177
+ * });
178
+ *
179
+ * await asrClient.connect();
180
+ * await asrClient.startRecording();
165
181
  *
166
182
  * // Stop and close
167
- * client.asr.stopRecording();
168
- * client.asr.close();
183
+ * asrClient.stopRecording();
184
+ * asrClient.close();
169
185
  * ```
170
186
  */
171
- asr: ASRClient;
187
+ asr: (config: ASRClientConfig) => ASRClient;
188
+ /**
189
+ * ASR Http module - HTTP-based press-to-talk speech recognition
190
+ *
191
+ * Suitable for press-to-talk scenarios where you hold to speak and release to recognize,
192
+ * such as voice messages, voice search, etc.
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * // Press-to-talk recognition
197
+ * const asrHttpClient = client.asrHttp({
198
+ * onRecordingStart() {
199
+ * console.log('Recording started');
200
+ * },
201
+ * onRecordingStop() {
202
+ * console.log('Recording stopped');
203
+ * },
204
+ * onResult(text) {
205
+ * console.log('Recognition result:', text);
206
+ * },
207
+ * onError(err) {
208
+ * console.error('ASR HTTP Error:', err);
209
+ * },
210
+ * });
211
+ *
212
+ * await asrHttpClient.startRecording();
213
+ * // ... user speaks ...
214
+ * const result = await asrHttpClient.stopRecording();
215
+ * ```
216
+ */
217
+ asrHttp: (config: ASRHttpClientConfig) => ASRHttpClient;
172
218
  /**
173
219
  * Copilot AI assistant module
174
220
  *
@@ -194,20 +240,35 @@ interface AmasterClient {
194
240
  */
195
241
  function: FunctionClient;
196
242
  /**
197
- * TTS (Text-to-Speech) module
198
- * WebSocket-based real-time speech synthesis
243
+ * TTS (Text-to-Speech) module - WebSocket-based real-time speech synthesis
244
+ *
245
+ * Supports multiple voices and audio formats. Built-in playback only supports PCM format.
199
246
  *
200
247
  * @example
201
248
  * ```typescript
202
249
  * // Connect and speak
203
- * await client.tts.connect();
204
- * await client.tts.speak('Hello world');
250
+ * const ttsClient = client.tts({
251
+ * voice: 'Cherry',
252
+ * autoPlay: true,
253
+ * onReady() {
254
+ * console.log('TTS Ready');
255
+ * },
256
+ * onAudioStart() {
257
+ * console.log('Playing audio');
258
+ * },
259
+ * onAudioEnd() {
260
+ * console.log('Audio playback ended');
261
+ * },
262
+ * });
263
+ *
264
+ * await ttsClient.connect();
265
+ * await ttsClient.speak('Hello, welcome to Amaster!');
205
266
  *
206
- * // Close connection
207
- * client.tts.close();
267
+ * // Close when done
268
+ * ttsClient.close();
208
269
  * ```
209
270
  */
210
- tts: TTSClient;
271
+ tts: (config: TTSClientConfig) => TTSClient;
211
272
  /**
212
273
  * S3 Storage module
213
274
  *
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { createAuthClient } from '@amaster.ai/auth-client';
2
2
  import { createEntityClient } from '@amaster.ai/entity-client';
3
3
  import { createBpmClient } from '@amaster.ai/bpm-client';
4
4
  import { createWorkflowClient } from '@amaster.ai/workflow-client';
5
- import { createASRClient } from '@amaster.ai/asr-client';
5
+ import { createASRClient, createASRHttpClient } from '@amaster.ai/asr-client';
6
6
  import { createCopilotClient } from '@amaster.ai/copilot-client';
7
7
  import { createFunctionClient } from '@amaster.ai/function-client';
8
8
  import { createTTSClient } from '@amaster.ai/tts-client';
@@ -128,6 +128,9 @@ function createClient(options) {
128
128
  const asr = createASRClient({
129
129
  getAccessToken: () => auth.getAccessToken()
130
130
  });
131
+ const asrHttp = createASRHttpClient({
132
+ getAccessToken: () => auth.getAccessToken()
133
+ });
131
134
  const tts = createTTSClient({
132
135
  getAccessToken: () => auth.getAccessToken()
133
136
  });
@@ -137,6 +140,7 @@ function createClient(options) {
137
140
  bpm,
138
141
  workflow,
139
142
  asr,
143
+ asrHttp,
140
144
  copilot,
141
145
  function: functionClient,
142
146
  tts,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * ============================================================================\n * @amaster.ai/client - Unified Amaster Client\n * ============================================================================\n *\n * Supabase-inspired unified API client for the Amaster platform\n *\n * Features:\n * - Single client instance for all services (auth, entity, bpm, workflow)\n * - Automatic token management and refresh\n * - Auto-attach authentication to all requests\n * - Centralized error handling\n *\n * @example\n * ```typescript\n * // With explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Auto-detect baseURL from env (Taro/Mini-program)\n * const client = createClient({\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Login\n * await client.auth.login({ email, password });\n *\n * // All subsequent requests automatically include auth token\n * await client.entity.list('default', 'users');\n * await client.bpm.startProcess({ processKey: 'approval' });\n * ```\n */\n\nimport { createAuthClient, type AuthClient } from \"@amaster.ai/auth-client\";\nimport { createEntityClient, type EntityClient } from \"@amaster.ai/entity-client\";\nimport { createBpmClient, type BpmClient } from \"@amaster.ai/bpm-client\";\nimport { createWorkflowClient, type WorkflowClient } from \"@amaster.ai/workflow-client\";\nimport { createASRClient, type ASRClient } from \"@amaster.ai/asr-client\";\nimport { createCopilotClient, type CopilotClient } from \"@amaster.ai/copilot-client\";\nimport { createFunctionClient, type FunctionClient } from \"@amaster.ai/function-client\";\nimport { createTTSClient, type TTSClient } from \"@amaster.ai/tts-client\";\nimport { createS3Client, type S3Client } from \"@amaster.ai/s3-client\";\nimport {\n createHttpClient,\n type HttpClient,\n type RequestConfig,\n type ClientResult,\n} from \"@amaster.ai/http-client\";\nimport type { AmasterClient, AmasterClientOptions } from \"./types\";\n\n/**\n * Create a unified Amaster client instance\n *\n * This function creates a single client that provides access to all Amaster services:\n * - Authentication (login, register, logout)\n * - Entity CRUD operations\n * - BPM (Business Process Management)\n * - Workflow execution\n *\n * All sub-clients automatically share the same HTTP client and authentication state,\n * ensuring that tokens are consistently attached to all requests.\n *\n * @param options - Client configuration options\n * @returns A unified Amaster client instance\n *\n * @example\n * ```typescript\n * // Basic usage with explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai'\n * });\n *\n * // Auto-detect baseURL (for Taro/Mini-program or dev proxy)\n * const client = createClient({});\n *\n * // With authentication callbacks\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => {\n * // Redirect to login or show auth modal\n * window.location.href = '/login';\n * },\n * onTokenExpired: () => {\n * console.log('Token expired, refreshing...');\n * }\n * });\n *\n * // Login\n * await client.auth.login({\n * email: 'user@example.com',\n * password: 'password123'\n * });\n *\n * // Now all requests automatically include the auth token\n * const users = await client.entity.list('default', 'users');\n * const tasks = await client.bpm.getMyTasks();\n * ```\n */\nexport function createClient(options: AmasterClientOptions): AmasterClient {\n const {\n baseURL,\n headers = {},\n onUnauthorized,\n onTokenExpired,\n autoHandleOAuthCallback,\n } = options;\n\n // Create the base HTTP client\n const baseHttpClient = createHttpClient({\n baseURL,\n headers,\n });\n\n // Create the auth client first (it manages its own HTTP client internally)\n const auth: AuthClient = createAuthClient({\n baseURL,\n headers,\n onTokenExpired,\n onUnauthorized,\n autoHandleOAuthCallback,\n });\n\n // Create a wrapper HTTP client that automatically adds the auth token\n const createAuthenticatedHttpClient = (): HttpClient => {\n // Track if we're currently refreshing to avoid multiple simultaneous refreshes\n let isRefreshing = false;\n let refreshPromise: Promise<boolean> | null = null;\n\n /**\n * Check if 401 error is due to token expiration\n * Traefik JWT plugin returns plain text like \"Jwt is expired\" or \"Token is expired\"\n */\n function isTokenExpired(result: ClientResult<unknown>): boolean {\n if (result.status !== 401) return false;\n\n // Check error message (could be from backend JSON response)\n if (result.error?.message && /expired/i.test(result.error.message)) {\n return true;\n }\n\n // Check error details (traefik returns plain text in details)\n if (result.error?.details) {\n const details = result.error.details;\n if (typeof details === \"string\" && /expired/i.test(details)) {\n return true;\n }\n // Also check if details is an object with message field\n if (typeof details === \"object\" && details !== null) {\n const detailsObj = details as Record<string, unknown>;\n if (typeof detailsObj.message === \"string\" && /expired/i.test(detailsObj.message)) {\n return true;\n }\n }\n }\n\n // Check raw data (could be plain text from traefik)\n if (typeof result.data === \"string\" && /expired/i.test(result.data)) {\n return true;\n }\n\n // If we have a token but got 401, assume it might be expired\n return !!auth.getAccessToken();\n }\n\n return {\n async request<T>(config: RequestConfig): Promise<ClientResult<T>> {\n // Get the current token from auth client\n const token = auth.getAccessToken();\n\n // Merge Authorization header with existing headers\n const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};\n const mergedConfig: RequestConfig = {\n ...config,\n headers: {\n ...config.headers,\n ...authHeaders,\n },\n };\n\n // Make the request with the updated config\n let result = await baseHttpClient.request<T>(mergedConfig);\n\n // Handle 401 errors with automatic token refresh\n if (result.status === 401 && isTokenExpired(result)) {\n // Attempt to refresh token\n if (!isRefreshing) {\n isRefreshing = true;\n refreshPromise = (async () => {\n try {\n const refreshResult = await auth.refreshToken();\n return !!refreshResult.data;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n })();\n }\n\n const refreshed = await refreshPromise;\n\n if (refreshed) {\n // Retry with new token\n const newToken = auth.getAccessToken();\n result = await baseHttpClient.request<T>({\n ...config,\n headers: {\n ...config.headers,\n ...(newToken ? { Authorization: `Bearer ${newToken}` } : {}),\n },\n });\n }\n }\n\n // Trigger unauthorized if still 401\n if (result.status === 401 && onUnauthorized) {\n onUnauthorized();\n }\n\n return result;\n },\n };\n };\n\n const authenticatedHttpClient = createAuthenticatedHttpClient();\n\n let cachedUserUid: string | null = null;\n\n auth.on(\"login\", (user: { uid?: string }) => {\n cachedUserUid = user?.uid ?? null;\n });\n auth.on(\"logout\", () => {\n cachedUserUid = null;\n });\n\n if (auth.isAuthenticated()) {\n auth\n .getMe()\n .then((result) => {\n if (result.data?.uid) {\n cachedUserUid = result.data.uid;\n }\n })\n .catch(() => {});\n }\n\n // Create other clients using the authenticated HTTP client\n const entity: EntityClient = createEntityClient(authenticatedHttpClient);\n const bpm: BpmClient = createBpmClient(authenticatedHttpClient);\n const workflow: WorkflowClient = createWorkflowClient(authenticatedHttpClient);\n const functionClient: FunctionClient = createFunctionClient(authenticatedHttpClient);\n const copilot: CopilotClient = createCopilotClient(\n authenticatedHttpClient,\n baseURL,\n () => auth.getAccessToken(),\n () => cachedUserUid\n );\n const s3: S3Client = createS3Client(authenticatedHttpClient);\n\n // ASR and TTS clients use WebSocket, pass token getter for authentication\n // Token can be appended to WebSocket URL as query parameter\n const asr: ASRClient = createASRClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n const tts: TTSClient = createTTSClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n\n // Return unified client interface\n const client: AmasterClient = {\n auth,\n entity,\n bpm,\n workflow,\n asr,\n copilot,\n function: functionClient,\n tts,\n s3,\n http: authenticatedHttpClient,\n\n // Expose token management methods from auth client\n isAuthenticated: () => auth.isAuthenticated(),\n getAccessToken: () => auth.getAccessToken(),\n setAccessToken: (token: string) => auth.setAccessToken(token),\n clearAuth: () => auth.clearAuth(),\n };\n\n return client;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * ============================================================================\n * @amaster.ai/client - Unified Amaster Client\n * ============================================================================\n *\n * Supabase-inspired unified API client for the Amaster platform\n *\n * Features:\n * - Single client instance for all services (auth, entity, bpm, workflow)\n * - Automatic token management and refresh\n * - Auto-attach authentication to all requests\n * - Centralized error handling\n *\n * @example\n * ```typescript\n * // With explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Auto-detect baseURL from env (Taro/Mini-program)\n * const client = createClient({\n * onUnauthorized: () => window.location.href = '/login'\n * });\n *\n * // Login\n * await client.auth.login({ email, password });\n *\n * // All subsequent requests automatically include auth token\n * await client.entity.list('default', 'users');\n * await client.bpm.startProcess({ processKey: 'approval' });\n * ```\n */\n\nimport { createAuthClient, type AuthClient } from \"@amaster.ai/auth-client\";\nimport { createEntityClient, type EntityClient } from \"@amaster.ai/entity-client\";\nimport { createBpmClient, type BpmClient } from \"@amaster.ai/bpm-client\";\nimport { createWorkflowClient, type WorkflowClient } from \"@amaster.ai/workflow-client\";\nimport {\n createASRClient,\n createASRHttpClient,\n type ASRClientConfig,\n type ASRClient,\n type ASRHttpClientConfig,\n type ASRHttpClient,\n} from \"@amaster.ai/asr-client\";\nimport { createCopilotClient, type CopilotClient } from \"@amaster.ai/copilot-client\";\nimport { createFunctionClient, type FunctionClient } from \"@amaster.ai/function-client\";\nimport { createTTSClient, TTSClientConfig, type TTSClient } from \"@amaster.ai/tts-client\";\nimport { createS3Client, type S3Client } from \"@amaster.ai/s3-client\";\nimport {\n createHttpClient,\n type HttpClient,\n type RequestConfig,\n type ClientResult,\n} from \"@amaster.ai/http-client\";\nimport type { AmasterClient, AmasterClientOptions } from \"./types\";\n\n/**\n * Create a unified Amaster client instance\n *\n * This function creates a single client that provides access to all Amaster services:\n * - Authentication (login, register, logout)\n * - Entity CRUD operations\n * - BPM (Business Process Management)\n * - Workflow execution\n *\n * All sub-clients automatically share the same HTTP client and authentication state,\n * ensuring that tokens are consistently attached to all requests.\n *\n * @param options - Client configuration options\n * @returns A unified Amaster client instance\n *\n * @example\n * ```typescript\n * // Basic usage with explicit baseURL\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai'\n * });\n *\n * // Auto-detect baseURL (for Taro/Mini-program or dev proxy)\n * const client = createClient({});\n *\n * // With authentication callbacks\n * const client = createClient({\n * baseURL: 'https://api.amaster.ai',\n * onUnauthorized: () => {\n * // Redirect to login or show auth modal\n * window.location.href = '/login';\n * },\n * onTokenExpired: () => {\n * console.log('Token expired, refreshing...');\n * }\n * });\n *\n * // Login\n * await client.auth.login({\n * email: 'user@example.com',\n * password: 'password123'\n * });\n *\n * // Now all requests automatically include the auth token\n * const users = await client.entity.list('default', 'users');\n * const tasks = await client.bpm.getMyTasks();\n * ```\n */\nexport function createClient(options: AmasterClientOptions): AmasterClient {\n const {\n baseURL,\n headers = {},\n onUnauthorized,\n onTokenExpired,\n autoHandleOAuthCallback,\n } = options;\n\n // Create the base HTTP client\n const baseHttpClient = createHttpClient({\n baseURL,\n headers,\n });\n\n // Create the auth client first (it manages its own HTTP client internally)\n const auth: AuthClient = createAuthClient({\n baseURL,\n headers,\n onTokenExpired,\n onUnauthorized,\n autoHandleOAuthCallback,\n });\n\n // Create a wrapper HTTP client that automatically adds the auth token\n const createAuthenticatedHttpClient = (): HttpClient => {\n // Track if we're currently refreshing to avoid multiple simultaneous refreshes\n let isRefreshing = false;\n let refreshPromise: Promise<boolean> | null = null;\n\n /**\n * Check if 401 error is due to token expiration\n * Traefik JWT plugin returns plain text like \"Jwt is expired\" or \"Token is expired\"\n */\n function isTokenExpired(result: ClientResult<unknown>): boolean {\n if (result.status !== 401) return false;\n\n // Check error message (could be from backend JSON response)\n if (result.error?.message && /expired/i.test(result.error.message)) {\n return true;\n }\n\n // Check error details (traefik returns plain text in details)\n if (result.error?.details) {\n const details = result.error.details;\n if (typeof details === \"string\" && /expired/i.test(details)) {\n return true;\n }\n // Also check if details is an object with message field\n if (typeof details === \"object\" && details !== null) {\n const detailsObj = details as Record<string, unknown>;\n if (typeof detailsObj.message === \"string\" && /expired/i.test(detailsObj.message)) {\n return true;\n }\n }\n }\n\n // Check raw data (could be plain text from traefik)\n if (typeof result.data === \"string\" && /expired/i.test(result.data)) {\n return true;\n }\n\n // If we have a token but got 401, assume it might be expired\n return !!auth.getAccessToken();\n }\n\n return {\n async request<T>(config: RequestConfig): Promise<ClientResult<T>> {\n // Get the current token from auth client\n const token = auth.getAccessToken();\n\n // Merge Authorization header with existing headers\n const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};\n const mergedConfig: RequestConfig = {\n ...config,\n headers: {\n ...config.headers,\n ...authHeaders,\n },\n };\n\n // Make the request with the updated config\n let result = await baseHttpClient.request<T>(mergedConfig);\n\n // Handle 401 errors with automatic token refresh\n if (result.status === 401 && isTokenExpired(result)) {\n // Attempt to refresh token\n if (!isRefreshing) {\n isRefreshing = true;\n refreshPromise = (async () => {\n try {\n const refreshResult = await auth.refreshToken();\n return !!refreshResult.data;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n })();\n }\n\n const refreshed = await refreshPromise;\n\n if (refreshed) {\n // Retry with new token\n const newToken = auth.getAccessToken();\n result = await baseHttpClient.request<T>({\n ...config,\n headers: {\n ...config.headers,\n ...(newToken ? { Authorization: `Bearer ${newToken}` } : {}),\n },\n });\n }\n }\n\n // Trigger unauthorized if still 401\n if (result.status === 401 && onUnauthorized) {\n onUnauthorized();\n }\n\n return result;\n },\n };\n };\n\n const authenticatedHttpClient = createAuthenticatedHttpClient();\n\n let cachedUserUid: string | null = null;\n\n auth.on(\"login\", (user: { uid?: string }) => {\n cachedUserUid = user?.uid ?? null;\n });\n auth.on(\"logout\", () => {\n cachedUserUid = null;\n });\n\n if (auth.isAuthenticated()) {\n auth\n .getMe()\n .then((result) => {\n if (result.data?.uid) {\n cachedUserUid = result.data.uid;\n }\n })\n .catch(() => {});\n }\n\n // Create other clients using the authenticated HTTP client\n const entity: EntityClient = createEntityClient(authenticatedHttpClient);\n const bpm: BpmClient = createBpmClient(authenticatedHttpClient);\n const workflow: WorkflowClient = createWorkflowClient(authenticatedHttpClient);\n const functionClient: FunctionClient = createFunctionClient(authenticatedHttpClient);\n const copilot: CopilotClient = createCopilotClient(\n authenticatedHttpClient,\n baseURL,\n () => auth.getAccessToken(),\n () => cachedUserUid\n );\n const s3: S3Client = createS3Client(authenticatedHttpClient);\n\n // ASR and TTS clients use WebSocket, pass token getter for authentication\n // Token can be appended to WebSocket URL as query parameter\n const asr: (config: ASRClientConfig) => ASRClient = createASRClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n const asrHttp: (config: ASRHttpClientConfig) => ASRHttpClient = createASRHttpClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n const tts: (config: TTSClientConfig) => TTSClient = createTTSClient({\n getAccessToken: () => auth.getAccessToken(),\n });\n\n // Return unified client interface\n const client: AmasterClient = {\n auth,\n entity,\n bpm,\n workflow,\n asr,\n asrHttp,\n copilot,\n function: functionClient,\n tts,\n s3,\n http: authenticatedHttpClient,\n\n // Expose token management methods from auth client\n isAuthenticated: () => auth.isAuthenticated(),\n getAccessToken: () => auth.getAccessToken(),\n setAccessToken: (token: string) => auth.setAccessToken(token),\n clearAuth: () => auth.clearAuth(),\n };\n\n return client;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amaster.ai/client",
3
- "version": "1.1.0-beta.49",
3
+ "version": "1.1.0-beta.50",
4
4
  "description": "Unified API client for Amaster platform - All services in one package",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -72,17 +72,16 @@
72
72
  "registry": "https://registry.npmjs.org/"
73
73
  },
74
74
  "dependencies": {
75
- "@amaster.ai/asr-client": "1.1.0-beta.49",
76
- "@amaster.ai/asr-http-client": "1.1.0-beta.49",
77
- "@amaster.ai/auth-client": "1.1.0-beta.49",
78
- "@amaster.ai/function-client": "1.1.0-beta.49",
79
- "@amaster.ai/bpm-client": "1.1.0-beta.49",
80
- "@amaster.ai/entity-client": "1.1.0-beta.49",
81
- "@amaster.ai/copilot-client": "1.1.0-beta.49",
82
- "@amaster.ai/http-client": "1.1.0-beta.49",
83
- "@amaster.ai/tts-client": "1.1.0-beta.49",
84
- "@amaster.ai/s3-client": "1.1.0-beta.49",
85
- "@amaster.ai/workflow-client": "1.1.0-beta.49"
75
+ "@amaster.ai/asr-client": "1.1.0-beta.50",
76
+ "@amaster.ai/copilot-client": "1.1.0-beta.50",
77
+ "@amaster.ai/auth-client": "1.1.0-beta.50",
78
+ "@amaster.ai/entity-client": "1.1.0-beta.50",
79
+ "@amaster.ai/function-client": "1.1.0-beta.50",
80
+ "@amaster.ai/http-client": "1.1.0-beta.50",
81
+ "@amaster.ai/s3-client": "1.1.0-beta.50",
82
+ "@amaster.ai/bpm-client": "1.1.0-beta.50",
83
+ "@amaster.ai/tts-client": "1.1.0-beta.50",
84
+ "@amaster.ai/workflow-client": "1.1.0-beta.50"
86
85
  },
87
86
  "peerDependencies": {
88
87
  "axios": "^1.11.0"
package/types/asr.d.ts CHANGED
@@ -36,9 +36,6 @@ export interface ASRClientConfig {
36
36
 
37
37
  /** Called on connection close */
38
38
  onClose?: () => void;
39
-
40
- /** WebSocket path override */
41
- path?: string;
42
39
  }
43
40
 
44
41
  /**
@@ -86,3 +83,32 @@ export interface ASRClientAPI {
86
83
  */
87
84
  close(): void;
88
85
  }
86
+
87
+ export interface ASRHttpClientConfig {
88
+ /** Get access token */
89
+ getAccessToken?(): string | null;
90
+ /** Language, default 'zh' */
91
+ language?: string;
92
+ /** Sample rate, default 16000 */
93
+ sampleRate?: number;
94
+ /** Called when recording starts */
95
+ onRecordingStart?: () => void;
96
+ /** Called when recording stops */
97
+ onRecordingStop?: () => void;
98
+ /** Called with recognition result */
99
+ onResult?: (text: string) => void;
100
+ /** Called on error */
101
+ onError?: (error: Error) => void;
102
+ }
103
+ export interface ASRHttpClient {
104
+ /** Start recording (press-to-talk) */
105
+ startRecording(): Promise<void>;
106
+ /** Stop recording and get result */
107
+ stopRecording(): Promise<string>;
108
+ /** Record for specific duration then recognize */
109
+ recordAndRecognize(durationMs: number): Promise<string>;
110
+ /** Recognize audio file (File or Blob) */
111
+ recognizeFile(file: File | Blob): Promise<string>;
112
+ /** Recognize audio from URL */
113
+ recognizeUrl(audioUrl: string): Promise<string>;
114
+ }
package/types/tts.d.ts CHANGED
@@ -9,8 +9,6 @@
9
9
  *
10
10
  */
11
11
  export interface TTSClientConfig {
12
- /** WebSocket path override */
13
- path?: string;
14
12
 
15
13
  /** Voice name, default 'Cherry' */
16
14
  voice?: string;