@amaster.ai/client 1.1.0-beta.7 → 1.1.0-beta.71

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/dist/index.d.cts CHANGED
@@ -3,18 +3,21 @@ export { LoginParams, LoginResponse, OAuthProvider, Permission, RegisterParams,
3
3
  import { EntityClient } from '@amaster.ai/entity-client';
4
4
  export { EntityListResponse, EntityQueryParams, FilterGroup, FilterItem, FilterOperator } from '@amaster.ai/entity-client';
5
5
  import { BpmClient } from '@amaster.ai/bpm-client';
6
- export { CamundaVariable, HistoryProcessInstance, HistoryTask, ProcessInstance, ProcessVariable, Task, TaskFormSchema, TaskQueryParams } from '@amaster.ai/bpm-client';
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';
11
- import { CopilotA2UIClient } from '@amaster.ai/copilot-client';
12
- export { ChatMessage, ChatOptions, CopilotA2UIClient, FileContent, ImageContent, MessageContent, TextContent } from '@amaster.ai/copilot-client';
9
+ import { ASRClientConfig, ASRClient, ASRHttpClientConfig, ASRHttpClient } from '@amaster.ai/asr-client';
10
+ export { ASRClient, ASRClientConfig, ASRHttpClient, ASRHttpClientConfig, ASRLanguage } from '@amaster.ai/asr-client';
11
+ import { CopilotClient } from '@amaster.ai/copilot-client';
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
- export { ClientError, ClientResult } from '@amaster.ai/http-client';
17
+ import { S3Client } from '@amaster.ai/s3-client';
18
+ export { S3Client, S3Metadata, UploadRes } from '@amaster.ai/s3-client';
19
+ import { HttpClient } from '@amaster.ai/http-client';
20
+ export { ClientError, ClientResult, HttpClient, RequestConfig } from '@amaster.ai/http-client';
18
21
 
19
22
  /**
20
23
  * Amaster Client Configuration Options
@@ -54,6 +57,18 @@ interface AmasterClientOptions {
54
57
  * Tokens will be refreshed this many seconds before expiry
55
58
  */
56
59
  refreshThreshold?: number;
60
+ /**
61
+ * Automatically handle OAuth callback on initialization (default: true)
62
+ *
63
+ * When enabled, the client will automatically detect and process OAuth
64
+ * callback URLs containing #access_token. After processing, the hash
65
+ * is automatically cleared from the URL for security.
66
+ *
67
+ * Set to false if you want to manually handle OAuth callbacks.
68
+ *
69
+ * @default true
70
+ */
71
+ autoHandleOAuthCallback?: boolean;
57
72
  }
58
73
  /**
59
74
  * Unified Amaster Client
@@ -139,21 +154,71 @@ interface AmasterClient {
139
154
  */
140
155
  workflow: WorkflowClient;
141
156
  /**
142
- * ASR (Automatic Speech Recognition) module
143
- * 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.
144
160
  *
145
161
  * @example
146
162
  * ```typescript
147
- * // Connect and start recording
148
- * await client.asr.connect();
149
- * await client.asr.startRecording();
163
+ * // Real-time streaming recognition
164
+ * import { createClient } from "@amaster.ai/client";
165
+ * export const client = createClient({});
166
+ * const asrClient = client.asr({
167
+ * onReady() {
168
+ * console.log('ASR Ready');
169
+ * },
170
+ * onTranscript(text, isFinal) {
171
+ * console.log(isFinal ? '[Final]' : '[Interim]', text);
172
+ * },
173
+ * onError(err) {
174
+ * console.error('ASR Error:', err);
175
+ * },
176
+ * onClose() {
177
+ * console.log('ASR Connection Closed');
178
+ * },
179
+ * });
180
+ *
181
+ * await asrClient.connect();
182
+ * await asrClient.startRecording();
150
183
  *
151
184
  * // Stop and close
152
- * client.asr.stopRecording();
153
- * client.asr.close();
185
+ * asrClient.stopRecording();
186
+ * asrClient.close();
187
+ * ```
188
+ */
189
+ asr: (config: ASRClientConfig) => ASRClient;
190
+ /**
191
+ * ASR Http module - HTTP-based press-to-talk speech recognition
192
+ *
193
+ * Suitable for press-to-talk scenarios where you hold to speak and release to recognize,
194
+ * such as voice messages, voice search, etc.
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * // Press-to-talk recognition
199
+ * import { createClient } from "@amaster.ai/client";
200
+ * export const client = createClient({});
201
+ * const asrHttpClient = client.asrHttp({
202
+ * onRecordingStart() {
203
+ * console.log('Recording started');
204
+ * },
205
+ * onRecordingStop() {
206
+ * console.log('Recording stopped');
207
+ * },
208
+ * onResult(text) {
209
+ * console.log('Recognition result:', text);
210
+ * },
211
+ * onError(err) {
212
+ * console.error('ASR HTTP Error:', err);
213
+ * },
214
+ * });
215
+ *
216
+ * await asrHttpClient.startRecording();
217
+ * // ... user speaks ...
218
+ * const result = await asrHttpClient.stopRecording();
154
219
  * ```
155
220
  */
156
- asr: ASRClient;
221
+ asrHttp: (config: ASRHttpClientConfig) => ASRHttpClient;
157
222
  /**
158
223
  * Copilot AI assistant module
159
224
  *
@@ -165,7 +230,7 @@ interface AmasterClient {
165
230
  * ]);
166
231
  * ```
167
232
  */
168
- copilot: CopilotA2UIClient;
233
+ copilot: CopilotClient;
169
234
  /**
170
235
  * Function invocation module
171
236
  *
@@ -179,20 +244,83 @@ interface AmasterClient {
179
244
  */
180
245
  function: FunctionClient;
181
246
  /**
182
- * TTS (Text-to-Speech) module
183
- * WebSocket-based real-time speech synthesis
247
+ * TTS (Text-to-Speech) module - WebSocket-based real-time speech synthesis
248
+ *
249
+ * Supports multiple voices and audio formats. Built-in playback only supports PCM format.
184
250
  *
185
251
  * @example
186
252
  * ```typescript
187
253
  * // Connect and speak
188
- * await client.tts.connect();
189
- * await client.tts.speak('Hello world');
254
+ * import { createClient } from "@amaster.ai/client";
255
+ * export const client = createClient({});
256
+ * const ttsClient = client.tts({
257
+ * voice: 'Cherry',
258
+ * autoPlay: true,
259
+ * onReady() {
260
+ * console.log('TTS Ready');
261
+ * },
262
+ * onAudioStart() {
263
+ * console.log('Playing audio');
264
+ * },
265
+ * onAudioEnd() {
266
+ * console.log('Audio playback ended');
267
+ * },
268
+ * });
269
+ *
270
+ * await ttsClient.connect();
271
+ * await ttsClient.speak('Hello, welcome to Amaster!');
190
272
  *
191
- * // Close connection
192
- * client.tts.close();
273
+ * // Close when done
274
+ * ttsClient.close();
275
+ * ```
276
+ */
277
+ tts: (config: TTSClientConfig) => TTSClient;
278
+ /**
279
+ * S3 Storage module
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * // Upload file
284
+ * await client.s3.upload(file);
285
+ *
286
+ * // Download file
287
+ * await client.s3.download('path/to/file');
288
+ * ```
289
+ */
290
+ s3: S3Client;
291
+ /**
292
+ * HTTP client for custom requests
293
+ *
294
+ * Provides direct access to the underlying HTTP client with automatic
295
+ * authentication token attachment. Useful for calling custom endpoints
296
+ * or APIs not covered by the specialized clients.
297
+ *
298
+ * Supports both `data` (Axios style) and `body` (Fetch API style) for request payload.
299
+ *
300
+ * @example
301
+ * ```typescript
302
+ * // Make a custom GET request
303
+ * const { data, error } = await client.http.request({
304
+ * url: '/custom/endpoint',
305
+ * method: 'GET'
306
+ * });
307
+ *
308
+ * // Make a POST request with data (Axios style)
309
+ * const { data, error } = await client.http.request({
310
+ * url: '/custom/endpoint',
311
+ * method: 'POST',
312
+ * data: { key: 'value' }
313
+ * });
314
+ *
315
+ * // Make a POST request with body (Fetch API style, auto-converted to data)
316
+ * const { data, error } = await client.http.request({
317
+ * url: '/custom/endpoint',
318
+ * method: 'POST',
319
+ * body: { key: 'value' }
320
+ * });
193
321
  * ```
194
322
  */
195
- tts: TTSClient;
323
+ http: HttpClient;
196
324
  /**
197
325
  * Check if the user is currently authenticated
198
326
  */
package/dist/index.d.ts CHANGED
@@ -3,18 +3,21 @@ export { LoginParams, LoginResponse, OAuthProvider, Permission, RegisterParams,
3
3
  import { EntityClient } from '@amaster.ai/entity-client';
4
4
  export { EntityListResponse, EntityQueryParams, FilterGroup, FilterItem, FilterOperator } from '@amaster.ai/entity-client';
5
5
  import { BpmClient } from '@amaster.ai/bpm-client';
6
- export { CamundaVariable, HistoryProcessInstance, HistoryTask, ProcessInstance, ProcessVariable, Task, TaskFormSchema, TaskQueryParams } from '@amaster.ai/bpm-client';
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';
11
- import { CopilotA2UIClient } from '@amaster.ai/copilot-client';
12
- export { ChatMessage, ChatOptions, CopilotA2UIClient, FileContent, ImageContent, MessageContent, TextContent } from '@amaster.ai/copilot-client';
9
+ import { ASRClientConfig, ASRClient, ASRHttpClientConfig, ASRHttpClient } from '@amaster.ai/asr-client';
10
+ export { ASRClient, ASRClientConfig, ASRHttpClient, ASRHttpClientConfig, ASRLanguage } from '@amaster.ai/asr-client';
11
+ import { CopilotClient } from '@amaster.ai/copilot-client';
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
- export { ClientError, ClientResult } from '@amaster.ai/http-client';
17
+ import { S3Client } from '@amaster.ai/s3-client';
18
+ export { S3Client, S3Metadata, UploadRes } from '@amaster.ai/s3-client';
19
+ import { HttpClient } from '@amaster.ai/http-client';
20
+ export { ClientError, ClientResult, HttpClient, RequestConfig } from '@amaster.ai/http-client';
18
21
 
19
22
  /**
20
23
  * Amaster Client Configuration Options
@@ -54,6 +57,18 @@ interface AmasterClientOptions {
54
57
  * Tokens will be refreshed this many seconds before expiry
55
58
  */
56
59
  refreshThreshold?: number;
60
+ /**
61
+ * Automatically handle OAuth callback on initialization (default: true)
62
+ *
63
+ * When enabled, the client will automatically detect and process OAuth
64
+ * callback URLs containing #access_token. After processing, the hash
65
+ * is automatically cleared from the URL for security.
66
+ *
67
+ * Set to false if you want to manually handle OAuth callbacks.
68
+ *
69
+ * @default true
70
+ */
71
+ autoHandleOAuthCallback?: boolean;
57
72
  }
58
73
  /**
59
74
  * Unified Amaster Client
@@ -139,21 +154,71 @@ interface AmasterClient {
139
154
  */
140
155
  workflow: WorkflowClient;
141
156
  /**
142
- * ASR (Automatic Speech Recognition) module
143
- * 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.
144
160
  *
145
161
  * @example
146
162
  * ```typescript
147
- * // Connect and start recording
148
- * await client.asr.connect();
149
- * await client.asr.startRecording();
163
+ * // Real-time streaming recognition
164
+ * import { createClient } from "@amaster.ai/client";
165
+ * export const client = createClient({});
166
+ * const asrClient = client.asr({
167
+ * onReady() {
168
+ * console.log('ASR Ready');
169
+ * },
170
+ * onTranscript(text, isFinal) {
171
+ * console.log(isFinal ? '[Final]' : '[Interim]', text);
172
+ * },
173
+ * onError(err) {
174
+ * console.error('ASR Error:', err);
175
+ * },
176
+ * onClose() {
177
+ * console.log('ASR Connection Closed');
178
+ * },
179
+ * });
180
+ *
181
+ * await asrClient.connect();
182
+ * await asrClient.startRecording();
150
183
  *
151
184
  * // Stop and close
152
- * client.asr.stopRecording();
153
- * client.asr.close();
185
+ * asrClient.stopRecording();
186
+ * asrClient.close();
187
+ * ```
188
+ */
189
+ asr: (config: ASRClientConfig) => ASRClient;
190
+ /**
191
+ * ASR Http module - HTTP-based press-to-talk speech recognition
192
+ *
193
+ * Suitable for press-to-talk scenarios where you hold to speak and release to recognize,
194
+ * such as voice messages, voice search, etc.
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * // Press-to-talk recognition
199
+ * import { createClient } from "@amaster.ai/client";
200
+ * export const client = createClient({});
201
+ * const asrHttpClient = client.asrHttp({
202
+ * onRecordingStart() {
203
+ * console.log('Recording started');
204
+ * },
205
+ * onRecordingStop() {
206
+ * console.log('Recording stopped');
207
+ * },
208
+ * onResult(text) {
209
+ * console.log('Recognition result:', text);
210
+ * },
211
+ * onError(err) {
212
+ * console.error('ASR HTTP Error:', err);
213
+ * },
214
+ * });
215
+ *
216
+ * await asrHttpClient.startRecording();
217
+ * // ... user speaks ...
218
+ * const result = await asrHttpClient.stopRecording();
154
219
  * ```
155
220
  */
156
- asr: ASRClient;
221
+ asrHttp: (config: ASRHttpClientConfig) => ASRHttpClient;
157
222
  /**
158
223
  * Copilot AI assistant module
159
224
  *
@@ -165,7 +230,7 @@ interface AmasterClient {
165
230
  * ]);
166
231
  * ```
167
232
  */
168
- copilot: CopilotA2UIClient;
233
+ copilot: CopilotClient;
169
234
  /**
170
235
  * Function invocation module
171
236
  *
@@ -179,20 +244,83 @@ interface AmasterClient {
179
244
  */
180
245
  function: FunctionClient;
181
246
  /**
182
- * TTS (Text-to-Speech) module
183
- * WebSocket-based real-time speech synthesis
247
+ * TTS (Text-to-Speech) module - WebSocket-based real-time speech synthesis
248
+ *
249
+ * Supports multiple voices and audio formats. Built-in playback only supports PCM format.
184
250
  *
185
251
  * @example
186
252
  * ```typescript
187
253
  * // Connect and speak
188
- * await client.tts.connect();
189
- * await client.tts.speak('Hello world');
254
+ * import { createClient } from "@amaster.ai/client";
255
+ * export const client = createClient({});
256
+ * const ttsClient = client.tts({
257
+ * voice: 'Cherry',
258
+ * autoPlay: true,
259
+ * onReady() {
260
+ * console.log('TTS Ready');
261
+ * },
262
+ * onAudioStart() {
263
+ * console.log('Playing audio');
264
+ * },
265
+ * onAudioEnd() {
266
+ * console.log('Audio playback ended');
267
+ * },
268
+ * });
269
+ *
270
+ * await ttsClient.connect();
271
+ * await ttsClient.speak('Hello, welcome to Amaster!');
190
272
  *
191
- * // Close connection
192
- * client.tts.close();
273
+ * // Close when done
274
+ * ttsClient.close();
275
+ * ```
276
+ */
277
+ tts: (config: TTSClientConfig) => TTSClient;
278
+ /**
279
+ * S3 Storage module
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * // Upload file
284
+ * await client.s3.upload(file);
285
+ *
286
+ * // Download file
287
+ * await client.s3.download('path/to/file');
288
+ * ```
289
+ */
290
+ s3: S3Client;
291
+ /**
292
+ * HTTP client for custom requests
293
+ *
294
+ * Provides direct access to the underlying HTTP client with automatic
295
+ * authentication token attachment. Useful for calling custom endpoints
296
+ * or APIs not covered by the specialized clients.
297
+ *
298
+ * Supports both `data` (Axios style) and `body` (Fetch API style) for request payload.
299
+ *
300
+ * @example
301
+ * ```typescript
302
+ * // Make a custom GET request
303
+ * const { data, error } = await client.http.request({
304
+ * url: '/custom/endpoint',
305
+ * method: 'GET'
306
+ * });
307
+ *
308
+ * // Make a POST request with data (Axios style)
309
+ * const { data, error } = await client.http.request({
310
+ * url: '/custom/endpoint',
311
+ * method: 'POST',
312
+ * data: { key: 'value' }
313
+ * });
314
+ *
315
+ * // Make a POST request with body (Fetch API style, auto-converted to data)
316
+ * const { data, error } = await client.http.request({
317
+ * url: '/custom/endpoint',
318
+ * method: 'POST',
319
+ * body: { key: 'value' }
320
+ * });
193
321
  * ```
194
322
  */
195
- tts: TTSClient;
323
+ http: HttpClient;
196
324
  /**
197
325
  * Check if the user is currently authenticated
198
326
  */
package/dist/index.js CHANGED
@@ -2,15 +2,22 @@ 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';
6
- import { createCopilotA2UIClient } from '@amaster.ai/copilot-client';
5
+ import { createASRClient, createASRHttpClient } from '@amaster.ai/asr-client';
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';
9
+ import { createS3Client } from '@amaster.ai/s3-client';
9
10
  import { createHttpClient } from '@amaster.ai/http-client';
10
11
 
11
12
  // src/client.ts
12
13
  function createClient(options) {
13
- const { baseURL, headers = {}, onUnauthorized, onTokenExpired } = options;
14
+ const {
15
+ baseURL,
16
+ headers = {},
17
+ onUnauthorized,
18
+ onTokenExpired,
19
+ autoHandleOAuthCallback
20
+ } = options;
14
21
  const baseHttpClient = createHttpClient({
15
22
  baseURL,
16
23
  headers
@@ -19,9 +26,34 @@ function createClient(options) {
19
26
  baseURL,
20
27
  headers,
21
28
  onTokenExpired,
22
- onUnauthorized
29
+ onUnauthorized,
30
+ autoHandleOAuthCallback
23
31
  });
24
32
  const createAuthenticatedHttpClient = () => {
33
+ let isRefreshing = false;
34
+ let refreshPromise = null;
35
+ function isTokenExpired(result) {
36
+ if (result.status !== 401) return false;
37
+ if (result.error?.message && /expired/i.test(result.error.message)) {
38
+ return true;
39
+ }
40
+ if (result.error?.details) {
41
+ const details = result.error.details;
42
+ if (typeof details === "string" && /expired/i.test(details)) {
43
+ return true;
44
+ }
45
+ if (typeof details === "object" && details !== null) {
46
+ const detailsObj = details;
47
+ if (typeof detailsObj.message === "string" && /expired/i.test(detailsObj.message)) {
48
+ return true;
49
+ }
50
+ }
51
+ }
52
+ if (typeof result.data === "string" && /expired/i.test(result.data)) {
53
+ return true;
54
+ }
55
+ return !!auth.getAccessToken();
56
+ }
25
57
  return {
26
58
  async request(config) {
27
59
  const token = auth.getAccessToken();
@@ -33,7 +65,32 @@ function createClient(options) {
33
65
  ...authHeaders
34
66
  }
35
67
  };
36
- const result = await baseHttpClient.request(mergedConfig);
68
+ let result = await baseHttpClient.request(mergedConfig);
69
+ if (result.status === 401 && isTokenExpired(result)) {
70
+ if (!isRefreshing) {
71
+ isRefreshing = true;
72
+ refreshPromise = (async () => {
73
+ try {
74
+ const refreshResult = await auth.refreshToken();
75
+ return !!refreshResult.data;
76
+ } finally {
77
+ isRefreshing = false;
78
+ refreshPromise = null;
79
+ }
80
+ })();
81
+ }
82
+ const refreshed = await refreshPromise;
83
+ if (refreshed) {
84
+ const newToken = auth.getAccessToken();
85
+ result = await baseHttpClient.request({
86
+ ...config,
87
+ headers: {
88
+ ...config.headers,
89
+ ...newToken ? { Authorization: `Bearer ${newToken}` } : {}
90
+ }
91
+ });
92
+ }
93
+ }
37
94
  if (result.status === 401 && onUnauthorized) {
38
95
  onUnauthorized();
39
96
  }
@@ -42,22 +99,54 @@ function createClient(options) {
42
99
  };
43
100
  };
44
101
  const authenticatedHttpClient = createAuthenticatedHttpClient();
102
+ let cachedUserUid = null;
103
+ auth.on("login", (user) => {
104
+ cachedUserUid = user?.uid ?? null;
105
+ });
106
+ auth.on("logout", () => {
107
+ cachedUserUid = null;
108
+ });
109
+ if (auth.isAuthenticated()) {
110
+ auth.getMe().then((result) => {
111
+ if (result.data?.uid) {
112
+ cachedUserUid = result.data.uid;
113
+ }
114
+ }).catch(() => {
115
+ });
116
+ }
45
117
  const entity = createEntityClient(authenticatedHttpClient);
46
118
  const bpm = createBpmClient(authenticatedHttpClient);
47
119
  const workflow = createWorkflowClient(authenticatedHttpClient);
48
120
  const functionClient = createFunctionClient(authenticatedHttpClient);
49
- const copilot = createCopilotA2UIClient(authenticatedHttpClient);
50
- const asr = createASRClient({});
51
- const tts = createTTSClient({});
121
+ const copilot = createCopilotClient(
122
+ authenticatedHttpClient,
123
+ baseURL,
124
+ () => auth.getAccessToken(),
125
+ () => cachedUserUid
126
+ );
127
+ const s3 = createS3Client(authenticatedHttpClient);
128
+ const asr = createASRClient({
129
+ getAccessToken: () => auth.getAccessToken()
130
+ });
131
+ const asrHttp = createASRHttpClient({
132
+ getAccessToken: () => auth.getAccessToken(),
133
+ http: authenticatedHttpClient
134
+ });
135
+ const tts = createTTSClient({
136
+ getAccessToken: () => auth.getAccessToken()
137
+ });
52
138
  const client = {
53
139
  auth,
54
140
  entity,
55
141
  bpm,
56
142
  workflow,
57
143
  asr,
144
+ asrHttp,
58
145
  copilot,
59
146
  function: functionClient,
60
147
  tts,
148
+ s3,
149
+ http: authenticatedHttpClient,
61
150
  // Expose token management methods from auth client
62
151
  isAuthenticated: () => auth.isAuthenticated(),
63
152
  getAccessToken: () => auth.getAccessToken(),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;;;;;;;;;AA8FO,SAAS,aAAa,OAAA,EAA8C;AACzE,EAAA,MAAM,EAAE,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,cAAA,EAAgB,gBAAe,GAAI,OAAA;AAGlE,EAAA,MAAM,iBAAiB,gBAAA,CAAiB;AAAA,IACtC,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AAGD,EAAA,MAAM,OAAmB,gBAAA,CAAiB;AAAA,IACxC,OAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACD,CAAA;AAGD,EAAA,MAAM,gCAAgC,MAAkB;AACtD,IAAA,OAAO;AAAA,MACL,MAAM,QAAW,MAAA,EAAiD;AAEhE,QAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,EAAe;AAGlC,QAAA,MAAM,WAAA,GAAc,QAAQ,EAAE,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA,KAAO,EAAC;AACpE,QAAA,MAAM,YAAA,GAA8B;AAAA,UAClC,GAAG,MAAA;AAAA,UACH,OAAA,EAAS;AAAA,YACP,GAAG,MAAA,CAAO,OAAA;AAAA,YACV,GAAG;AAAA;AACL,SACF;AAGA,QAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,OAAA,CAAW,YAAY,CAAA;AAG3D,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,GAAA,IAAO,cAAA,EAAgB;AAC3C,UAAA,cAAA,EAAe;AAAA,QACjB;AAEA,QAAA,OAAO,MAAA;AAAA,MACT;AAAA,KACF;AAAA,EACF,CAAA;AAGA,EAAA,MAAM,0BAA0B,6BAAA,EAA8B;AAG9D,EAAA,MAAM,MAAA,GAAuB,mBAAmB,uBAAuB,CAAA;AACvE,EAAA,MAAM,GAAA,GAAiB,gBAAgB,uBAAuB,CAAA;AAC9D,EAAA,MAAM,QAAA,GAA2B,qBAAqB,uBAAuB,CAAA;AAC7E,EAAA,MAAM,cAAA,GAAiC,qBAAqB,uBAAuB,CAAA;AACnF,EAAA,MAAM,OAAA,GAA6B,wBAAwB,uBAAuB,CAAA;AAIlF,EAAA,MAAM,GAAA,GAAiB,eAAA,CAAgB,EAAE,CAAA;AACzC,EAAA,MAAM,GAAA,GAAiB,eAAA,CAAgB,EAAE,CAAA;AAGzC,EAAA,MAAM,MAAA,GAAwB;AAAA,IAC5B,IAAA;AAAA,IACA,MAAA;AAAA,IACA,GAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA,EAAU,cAAA;AAAA,IACV,GAAA;AAAA;AAAA,IAGA,eAAA,EAAiB,MAAM,IAAA,CAAK,eAAA,EAAgB;AAAA,IAC5C,cAAA,EAAgB,MAAM,IAAA,CAAK,cAAA,EAAe;AAAA,IAC1C,cAAA,EAAgB,CAAC,KAAA,KAAkB,IAAA,CAAK,eAAe,KAAK,CAAA;AAAA,IAC5D,SAAA,EAAW,MAAM,IAAA,CAAK,SAAA;AAAU,GAClC;AAEA,EAAA,OAAO,MAAA;AACT","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 { createCopilotA2UIClient, type CopilotA2UIClient } from \"@amaster.ai/copilot-client\";\nimport { createFunctionClient, type FunctionClient } from \"@amaster.ai/function-client\";\nimport { createTTSClient, type TTSClient } from \"@amaster.ai/tts-client\";\nimport { createHttpClient, type HttpClient, type RequestConfig, type ClientResult } 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 { baseURL, headers = {}, onUnauthorized, onTokenExpired } = 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 });\n\n // Create a wrapper HTTP client that automatically adds the auth token\n const createAuthenticatedHttpClient = (): HttpClient => {\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 const result = await baseHttpClient.request<T>(mergedConfig);\n\n // Handle 401 errors\n if (result.status === 401 && onUnauthorized) {\n onUnauthorized();\n }\n\n return result;\n },\n };\n };\n\n // Create the authenticated HTTP client\n const authenticatedHttpClient = createAuthenticatedHttpClient();\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: CopilotA2UIClient = createCopilotA2UIClient(authenticatedHttpClient);\n\n // ASR and TTS clients use WebSocket, create with default config\n // Users can reconfigure by accessing client.asr / client.tts directly\n const asr: ASRClient = createASRClient({});\n const tts: TTSClient = createTTSClient({});\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\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 http: authenticatedHttpClient,\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"]}