@amaster.ai/client 1.1.0-beta.4 → 1.1.0-beta.41

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.cjs CHANGED
@@ -8,11 +8,18 @@ var asrClient = require('@amaster.ai/asr-client');
8
8
  var copilotClient = require('@amaster.ai/copilot-client');
9
9
  var functionClient = require('@amaster.ai/function-client');
10
10
  var ttsClient = require('@amaster.ai/tts-client');
11
+ var s3Client = require('@amaster.ai/s3-client');
11
12
  var httpClient = require('@amaster.ai/http-client');
12
13
 
13
14
  // src/client.ts
14
15
  function createClient(options) {
15
- const { baseURL, headers = {}, onUnauthorized, onTokenExpired } = options;
16
+ const {
17
+ baseURL,
18
+ headers = {},
19
+ onUnauthorized,
20
+ onTokenExpired,
21
+ autoHandleOAuthCallback
22
+ } = options;
16
23
  const baseHttpClient = httpClient.createHttpClient({
17
24
  baseURL,
18
25
  headers
@@ -21,9 +28,34 @@ function createClient(options) {
21
28
  baseURL,
22
29
  headers,
23
30
  onTokenExpired,
24
- onUnauthorized
31
+ onUnauthorized,
32
+ autoHandleOAuthCallback
25
33
  });
26
34
  const createAuthenticatedHttpClient = () => {
35
+ let isRefreshing = false;
36
+ let refreshPromise = null;
37
+ function isTokenExpired(result) {
38
+ if (result.status !== 401) return false;
39
+ if (result.error?.message && /expired/i.test(result.error.message)) {
40
+ return true;
41
+ }
42
+ if (result.error?.details) {
43
+ const details = result.error.details;
44
+ if (typeof details === "string" && /expired/i.test(details)) {
45
+ return true;
46
+ }
47
+ if (typeof details === "object" && details !== null) {
48
+ const detailsObj = details;
49
+ if (typeof detailsObj.message === "string" && /expired/i.test(detailsObj.message)) {
50
+ return true;
51
+ }
52
+ }
53
+ }
54
+ if (typeof result.data === "string" && /expired/i.test(result.data)) {
55
+ return true;
56
+ }
57
+ return !!auth.getAccessToken();
58
+ }
27
59
  return {
28
60
  async request(config) {
29
61
  const token = auth.getAccessToken();
@@ -35,9 +67,43 @@ function createClient(options) {
35
67
  ...authHeaders
36
68
  }
37
69
  };
38
- const result = await baseHttpClient.request(mergedConfig);
39
- if (result.status === 401 && onUnauthorized) {
40
- onUnauthorized();
70
+ let result = await baseHttpClient.request(mergedConfig);
71
+ if (result.status === 401) {
72
+ if (isTokenExpired(result)) {
73
+ if (!isRefreshing) {
74
+ isRefreshing = true;
75
+ refreshPromise = (async () => {
76
+ try {
77
+ const refreshResult = await auth.refreshToken();
78
+ return !!refreshResult.data;
79
+ } finally {
80
+ isRefreshing = false;
81
+ refreshPromise = null;
82
+ }
83
+ })();
84
+ }
85
+ const refreshed = await refreshPromise;
86
+ if (refreshed) {
87
+ const newToken = auth.getAccessToken();
88
+ const retryHeaders = {
89
+ ...config.headers,
90
+ ...newToken ? { Authorization: `Bearer ${newToken}` } : {}
91
+ };
92
+ const retryConfig = {
93
+ ...config,
94
+ headers: retryHeaders
95
+ };
96
+ result = await baseHttpClient.request(retryConfig);
97
+ } else {
98
+ if (onUnauthorized) {
99
+ onUnauthorized();
100
+ }
101
+ }
102
+ } else {
103
+ if (onUnauthorized) {
104
+ onUnauthorized();
105
+ }
106
+ }
41
107
  }
42
108
  return result;
43
109
  }
@@ -48,9 +114,18 @@ function createClient(options) {
48
114
  const bpm = bpmClient.createBpmClient(authenticatedHttpClient);
49
115
  const workflow = workflowClient.createWorkflowClient(authenticatedHttpClient);
50
116
  const functionClient$1 = functionClient.createFunctionClient(authenticatedHttpClient);
51
- const copilot = copilotClient.createCopilotA2UIClient(authenticatedHttpClient);
52
- const asr = asrClient.createASRClient({});
53
- const tts = ttsClient.createTTSClient({});
117
+ const copilot = copilotClient.createCopilotA2UIClient(
118
+ authenticatedHttpClient,
119
+ baseURL,
120
+ () => auth.getAccessToken()
121
+ );
122
+ const s3 = s3Client.createS3Client(authenticatedHttpClient);
123
+ const asr = asrClient.createASRClient({
124
+ getAccessToken: () => auth.getAccessToken()
125
+ });
126
+ const tts = ttsClient.createTTSClient({
127
+ getAccessToken: () => auth.getAccessToken()
128
+ });
54
129
  const client = {
55
130
  auth,
56
131
  entity,
@@ -60,6 +135,7 @@ function createClient(options) {
60
135
  copilot,
61
136
  function: functionClient$1,
62
137
  tts,
138
+ s3,
63
139
  // Expose token management methods from auth client
64
140
  isAuthenticated: () => auth.isAuthenticated(),
65
141
  getAccessToken: () => auth.getAccessToken(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["createHttpClient","createAuthClient","createEntityClient","createBpmClient","createWorkflowClient","functionClient","createFunctionClient","createCopilotA2UIClient","createASRClient","createTTSClient"],"mappings":";;;;;;;;;;;;;AA8FO,SAAS,aAAa,OAAA,EAA8C;AACzE,EAAA,MAAM,EAAE,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,cAAA,EAAgB,gBAAe,GAAI,OAAA;AAGlE,EAAA,MAAM,iBAAiBA,2BAAA,CAAiB;AAAA,IACtC,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AAGD,EAAA,MAAM,OAAmBC,2BAAA,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,GAAuBC,gCAAmB,uBAAuB,CAAA;AACvE,EAAA,MAAM,GAAA,GAAiBC,0BAAgB,uBAAuB,CAAA;AAC9D,EAAA,MAAM,QAAA,GAA2BC,oCAAqB,uBAAuB,CAAA;AAC7E,EAAA,MAAMC,gBAAA,GAAiCC,oCAAqB,uBAAuB,CAAA;AACnF,EAAA,MAAM,OAAA,GAA6BC,sCAAwB,uBAAuB,CAAA;AAIlF,EAAA,MAAM,GAAA,GAAiBC,yBAAA,CAAgB,EAAE,CAAA;AACzC,EAAA,MAAM,GAAA,GAAiBC,yBAAA,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,EAAUJ,gBAAA;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.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 { 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":["createHttpClient","createAuthClient","createEntityClient","createBpmClient","createWorkflowClient","functionClient","createFunctionClient","createCopilotA2UIClient","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 { 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 { 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) {\n // Check if this is a token expiration (vs. no auth / invalid credentials)\n if (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 // Wait for refresh to complete\n const refreshed = await refreshPromise;\n\n if (refreshed) {\n // Token refreshed successfully, get new token and retry\n const newToken = auth.getAccessToken();\n\n // Rebuild headers with new token for retry\n const retryHeaders = {\n ...config.headers,\n ...(newToken ? { Authorization: `Bearer ${newToken}` } : {}),\n };\n\n const retryConfig: RequestConfig = {\n ...config,\n headers: retryHeaders,\n };\n\n // Retry the request directly with baseHttpClient (avoid recursive wrapper call)\n result = await baseHttpClient.request<T>(retryConfig);\n } else {\n // Refresh failed, trigger unauthorized callback\n if (onUnauthorized) {\n onUnauthorized();\n }\n }\n } else {\n // Not a token expiration, trigger unauthorized callback\n if (onUnauthorized) {\n onUnauthorized();\n }\n }\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 // Pass token getter for streaming authentication (SSE/fetch)\n const copilot: CopilotA2UIClient = createCopilotA2UIClient(authenticatedHttpClient, baseURL, () =>\n auth.getAccessToken()\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\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
@@ -3,7 +3,7 @@ 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
9
  import { ASRClient } from '@amaster.ai/asr-client';
@@ -14,6 +14,8 @@ import { FunctionClient } from '@amaster.ai/function-client';
14
14
  export { FunctionClient } from '@amaster.ai/function-client';
15
15
  import { TTSClient } from '@amaster.ai/tts-client';
16
16
  export { TTSClient, TTSClientConfig } from '@amaster.ai/tts-client';
17
+ import { S3Client } from '@amaster.ai/s3-client';
18
+ export { S3Client, S3Metadata, UploadRes } from '@amaster.ai/s3-client';
17
19
  export { ClientError, ClientResult } from '@amaster.ai/http-client';
18
20
 
19
21
  /**
@@ -54,6 +56,18 @@ interface AmasterClientOptions {
54
56
  * Tokens will be refreshed this many seconds before expiry
55
57
  */
56
58
  refreshThreshold?: number;
59
+ /**
60
+ * Automatically handle OAuth callback on initialization (default: true)
61
+ *
62
+ * When enabled, the client will automatically detect and process OAuth
63
+ * callback URLs containing #access_token. After processing, the hash
64
+ * is automatically cleared from the URL for security.
65
+ *
66
+ * Set to false if you want to manually handle OAuth callbacks.
67
+ *
68
+ * @default true
69
+ */
70
+ autoHandleOAuthCallback?: boolean;
57
71
  }
58
72
  /**
59
73
  * Unified Amaster Client
@@ -193,6 +207,19 @@ interface AmasterClient {
193
207
  * ```
194
208
  */
195
209
  tts: TTSClient;
210
+ /**
211
+ * S3 Storage module
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // Upload file
216
+ * await client.s3.upload(file);
217
+ *
218
+ * // Download file
219
+ * await client.s3.download('path/to/file');
220
+ * ```
221
+ */
222
+ s3: S3Client;
196
223
  /**
197
224
  * Check if the user is currently authenticated
198
225
  */
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ 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
9
  import { ASRClient } from '@amaster.ai/asr-client';
@@ -14,6 +14,8 @@ import { FunctionClient } from '@amaster.ai/function-client';
14
14
  export { FunctionClient } from '@amaster.ai/function-client';
15
15
  import { TTSClient } from '@amaster.ai/tts-client';
16
16
  export { TTSClient, TTSClientConfig } from '@amaster.ai/tts-client';
17
+ import { S3Client } from '@amaster.ai/s3-client';
18
+ export { S3Client, S3Metadata, UploadRes } from '@amaster.ai/s3-client';
17
19
  export { ClientError, ClientResult } from '@amaster.ai/http-client';
18
20
 
19
21
  /**
@@ -54,6 +56,18 @@ interface AmasterClientOptions {
54
56
  * Tokens will be refreshed this many seconds before expiry
55
57
  */
56
58
  refreshThreshold?: number;
59
+ /**
60
+ * Automatically handle OAuth callback on initialization (default: true)
61
+ *
62
+ * When enabled, the client will automatically detect and process OAuth
63
+ * callback URLs containing #access_token. After processing, the hash
64
+ * is automatically cleared from the URL for security.
65
+ *
66
+ * Set to false if you want to manually handle OAuth callbacks.
67
+ *
68
+ * @default true
69
+ */
70
+ autoHandleOAuthCallback?: boolean;
57
71
  }
58
72
  /**
59
73
  * Unified Amaster Client
@@ -193,6 +207,19 @@ interface AmasterClient {
193
207
  * ```
194
208
  */
195
209
  tts: TTSClient;
210
+ /**
211
+ * S3 Storage module
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // Upload file
216
+ * await client.s3.upload(file);
217
+ *
218
+ * // Download file
219
+ * await client.s3.download('path/to/file');
220
+ * ```
221
+ */
222
+ s3: S3Client;
196
223
  /**
197
224
  * Check if the user is currently authenticated
198
225
  */
package/dist/index.js CHANGED
@@ -6,11 +6,18 @@ import { createASRClient } from '@amaster.ai/asr-client';
6
6
  import { createCopilotA2UIClient } 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,9 +65,43 @@ function createClient(options) {
33
65
  ...authHeaders
34
66
  }
35
67
  };
36
- const result = await baseHttpClient.request(mergedConfig);
37
- if (result.status === 401 && onUnauthorized) {
38
- onUnauthorized();
68
+ let result = await baseHttpClient.request(mergedConfig);
69
+ if (result.status === 401) {
70
+ if (isTokenExpired(result)) {
71
+ if (!isRefreshing) {
72
+ isRefreshing = true;
73
+ refreshPromise = (async () => {
74
+ try {
75
+ const refreshResult = await auth.refreshToken();
76
+ return !!refreshResult.data;
77
+ } finally {
78
+ isRefreshing = false;
79
+ refreshPromise = null;
80
+ }
81
+ })();
82
+ }
83
+ const refreshed = await refreshPromise;
84
+ if (refreshed) {
85
+ const newToken = auth.getAccessToken();
86
+ const retryHeaders = {
87
+ ...config.headers,
88
+ ...newToken ? { Authorization: `Bearer ${newToken}` } : {}
89
+ };
90
+ const retryConfig = {
91
+ ...config,
92
+ headers: retryHeaders
93
+ };
94
+ result = await baseHttpClient.request(retryConfig);
95
+ } else {
96
+ if (onUnauthorized) {
97
+ onUnauthorized();
98
+ }
99
+ }
100
+ } else {
101
+ if (onUnauthorized) {
102
+ onUnauthorized();
103
+ }
104
+ }
39
105
  }
40
106
  return result;
41
107
  }
@@ -46,9 +112,18 @@ function createClient(options) {
46
112
  const bpm = createBpmClient(authenticatedHttpClient);
47
113
  const workflow = createWorkflowClient(authenticatedHttpClient);
48
114
  const functionClient = createFunctionClient(authenticatedHttpClient);
49
- const copilot = createCopilotA2UIClient(authenticatedHttpClient);
50
- const asr = createASRClient({});
51
- const tts = createTTSClient({});
115
+ const copilot = createCopilotA2UIClient(
116
+ authenticatedHttpClient,
117
+ baseURL,
118
+ () => auth.getAccessToken()
119
+ );
120
+ const s3 = createS3Client(authenticatedHttpClient);
121
+ const asr = createASRClient({
122
+ getAccessToken: () => auth.getAccessToken()
123
+ });
124
+ const tts = createTTSClient({
125
+ getAccessToken: () => auth.getAccessToken()
126
+ });
52
127
  const client = {
53
128
  auth,
54
129
  entity,
@@ -58,6 +133,7 @@ function createClient(options) {
58
133
  copilot,
59
134
  function: functionClient,
60
135
  tts,
136
+ s3,
61
137
  // Expose token management methods from auth client
62
138
  isAuthenticated: () => auth.isAuthenticated(),
63
139
  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 { 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 { 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) {\n // Check if this is a token expiration (vs. no auth / invalid credentials)\n if (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 // Wait for refresh to complete\n const refreshed = await refreshPromise;\n\n if (refreshed) {\n // Token refreshed successfully, get new token and retry\n const newToken = auth.getAccessToken();\n\n // Rebuild headers with new token for retry\n const retryHeaders = {\n ...config.headers,\n ...(newToken ? { Authorization: `Bearer ${newToken}` } : {}),\n };\n\n const retryConfig: RequestConfig = {\n ...config,\n headers: retryHeaders,\n };\n\n // Retry the request directly with baseHttpClient (avoid recursive wrapper call)\n result = await baseHttpClient.request<T>(retryConfig);\n } else {\n // Refresh failed, trigger unauthorized callback\n if (onUnauthorized) {\n onUnauthorized();\n }\n }\n } else {\n // Not a token expiration, trigger unauthorized callback\n if (onUnauthorized) {\n onUnauthorized();\n }\n }\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 // Pass token getter for streaming authentication (SSE/fetch)\n const copilot: CopilotA2UIClient = createCopilotA2UIClient(authenticatedHttpClient, baseURL, () =>\n auth.getAccessToken()\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\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.4",
3
+ "version": "1.1.0-beta.41",
4
4
  "description": "Unified API client for Amaster platform - All services in one package",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -38,6 +38,9 @@
38
38
  "tts": [
39
39
  "./types/tts.d.ts"
40
40
  ],
41
+ "s3": [
42
+ "./types/s3.d.ts"
43
+ ],
41
44
  "common": [
42
45
  "./types/common.d.ts"
43
46
  ]
@@ -69,16 +72,17 @@
69
72
  "registry": "https://registry.npmjs.org/"
70
73
  },
71
74
  "dependencies": {
72
- "@amaster.ai/asr-client": "1.1.0-beta.3",
73
- "@amaster.ai/asr-http-client": "1.1.0-beta.3",
74
- "@amaster.ai/copilot-client": "1.1.0-beta.3",
75
- "@amaster.ai/auth-client": "1.1.0-beta.3",
76
- "@amaster.ai/function-client": "1.1.0-beta.3",
77
- "@amaster.ai/bpm-client": "1.1.0-beta.3",
78
- "@amaster.ai/entity-client": "1.1.0-beta.3",
79
- "@amaster.ai/tts-client": "1.1.0-beta.3",
80
- "@amaster.ai/workflow-client": "1.1.0-beta.3",
81
- "@amaster.ai/http-client": "1.1.0-beta.3"
75
+ "@amaster.ai/asr-client": "1.1.0-beta.41",
76
+ "@amaster.ai/auth-client": "1.1.0-beta.41",
77
+ "@amaster.ai/bpm-client": "1.1.0-beta.41",
78
+ "@amaster.ai/copilot-client": "1.1.0-beta.41",
79
+ "@amaster.ai/function-client": "1.1.0-beta.41",
80
+ "@amaster.ai/http-client": "1.1.0-beta.41",
81
+ "@amaster.ai/s3-client": "1.1.0-beta.41",
82
+ "@amaster.ai/tts-client": "1.1.0-beta.41",
83
+ "@amaster.ai/workflow-client": "1.1.0-beta.41",
84
+ "@amaster.ai/asr-http-client": "1.1.0-beta.41",
85
+ "@amaster.ai/entity-client": "1.1.0-beta.41"
82
86
  },
83
87
  "peerDependencies": {
84
88
  "axios": "^1.11.0"