@sinas/sdk 0.2.3 → 0.5.0
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/{chunk-Z6NVKMMG.js → chunk-IABVF56L.js} +189 -18
- package/dist/chunk-IABVF56L.js.map +1 -0
- package/dist/client.cjs +198 -19
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +118 -5
- package/dist/client.d.ts +118 -5
- package/dist/client.js +19 -3
- package/dist/index.cjs +331 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -4
- package/dist/index.d.ts +41 -4
- package/dist/index.js +151 -86
- package/dist/index.js.map +1 -1
- package/dist/sinas-sdk.umd.js +321 -101
- package/dist/sinas-sdk.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-Z6NVKMMG.js.map +0 -1
|
@@ -32,16 +32,131 @@ var SinasTimeoutError = class extends SinasError {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
// src/client/auth.ts
|
|
36
|
+
function trimBase(baseUrl) {
|
|
37
|
+
return baseUrl.replace(/\/+$/, "");
|
|
38
|
+
}
|
|
39
|
+
async function authFetch(baseUrl, path, init = {}, accessToken) {
|
|
40
|
+
const headers = new Headers(init.headers);
|
|
41
|
+
if (!headers.has("Content-Type") && init.body !== void 0) {
|
|
42
|
+
headers.set("Content-Type", "application/json");
|
|
43
|
+
}
|
|
44
|
+
if (accessToken) headers.set("Authorization", `Bearer ${accessToken}`);
|
|
45
|
+
const res = await fetch(`${trimBase(baseUrl)}${path}`, { ...init, headers });
|
|
46
|
+
if (res.ok || res.status === 204) return res;
|
|
47
|
+
let detail = res.statusText;
|
|
48
|
+
try {
|
|
49
|
+
const body = await res.clone().json();
|
|
50
|
+
detail = body.detail || body.message || detail;
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
if (res.status === 401) throw new SinasAuthError(detail);
|
|
54
|
+
if (res.status === 403) throw new SinasPermissionError(detail);
|
|
55
|
+
if (res.status === 404) throw new SinasNotFoundError(detail);
|
|
56
|
+
throw new SinasError(detail, res.status, detail);
|
|
57
|
+
}
|
|
58
|
+
async function getInfo(baseUrl) {
|
|
59
|
+
const res = await authFetch(baseUrl, "/info");
|
|
60
|
+
return await res.json();
|
|
61
|
+
}
|
|
62
|
+
async function login(baseUrl, request) {
|
|
63
|
+
const res = await authFetch(baseUrl, "/auth/login", {
|
|
64
|
+
method: "POST",
|
|
65
|
+
body: JSON.stringify(request)
|
|
66
|
+
});
|
|
67
|
+
return await res.json();
|
|
68
|
+
}
|
|
69
|
+
async function verifyOTP(baseUrl, request) {
|
|
70
|
+
const res = await authFetch(baseUrl, "/auth/verify-otp", {
|
|
71
|
+
method: "POST",
|
|
72
|
+
body: JSON.stringify(request)
|
|
73
|
+
});
|
|
74
|
+
return await res.json();
|
|
75
|
+
}
|
|
76
|
+
async function refresh(baseUrl, refreshToken) {
|
|
77
|
+
const res = await authFetch(baseUrl, "/auth/refresh", {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
80
|
+
});
|
|
81
|
+
return await res.json();
|
|
82
|
+
}
|
|
83
|
+
async function logout(baseUrl, refreshToken) {
|
|
84
|
+
try {
|
|
85
|
+
await authFetch(baseUrl, "/auth/logout", {
|
|
86
|
+
method: "POST",
|
|
87
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
88
|
+
});
|
|
89
|
+
} catch (e) {
|
|
90
|
+
if (e instanceof SinasNotFoundError) return;
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function getMe(baseUrl, accessToken) {
|
|
95
|
+
const res = await authFetch(baseUrl, "/auth/me", { method: "GET" }, accessToken);
|
|
96
|
+
return await res.json();
|
|
97
|
+
}
|
|
98
|
+
async function checkPermissions(baseUrl, accessToken, request) {
|
|
99
|
+
const res = await authFetch(
|
|
100
|
+
baseUrl,
|
|
101
|
+
"/auth/check-permissions",
|
|
102
|
+
{
|
|
103
|
+
method: "POST",
|
|
104
|
+
body: JSON.stringify({ logic: "AND", ...request })
|
|
105
|
+
},
|
|
106
|
+
accessToken
|
|
107
|
+
);
|
|
108
|
+
return await res.json();
|
|
109
|
+
}
|
|
110
|
+
|
|
35
111
|
// src/client/SinasClient.ts
|
|
112
|
+
function hasWindow() {
|
|
113
|
+
return typeof window !== "undefined";
|
|
114
|
+
}
|
|
115
|
+
function trim(url) {
|
|
116
|
+
return url.replace(/\/+$/, "");
|
|
117
|
+
}
|
|
118
|
+
var SinasClientAuth = class {
|
|
119
|
+
constructor(client) {
|
|
120
|
+
this.client = client;
|
|
121
|
+
}
|
|
122
|
+
getInfo() {
|
|
123
|
+
return getInfo(this.client.requireBaseUrl());
|
|
124
|
+
}
|
|
125
|
+
login(request) {
|
|
126
|
+
return login(this.client.requireBaseUrl(), request);
|
|
127
|
+
}
|
|
128
|
+
verifyOTP(request) {
|
|
129
|
+
return verifyOTP(this.client.requireBaseUrl(), request);
|
|
130
|
+
}
|
|
131
|
+
refresh(refreshToken) {
|
|
132
|
+
return refresh(this.client.requireBaseUrl(), refreshToken);
|
|
133
|
+
}
|
|
134
|
+
logout(refreshToken) {
|
|
135
|
+
return logout(this.client.requireBaseUrl(), refreshToken);
|
|
136
|
+
}
|
|
137
|
+
getMe() {
|
|
138
|
+
const token = this.client.getAccessToken();
|
|
139
|
+
if (!token) throw new SinasAuthError("No access token available");
|
|
140
|
+
return getMe(this.client.requireBaseUrl(), token);
|
|
141
|
+
}
|
|
142
|
+
checkPermissions(request) {
|
|
143
|
+
const token = this.client.getAccessToken();
|
|
144
|
+
if (!token) throw new SinasAuthError("No access token available");
|
|
145
|
+
return checkPermissions(this.client.requireBaseUrl(), token, request);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
36
148
|
var SinasClient = class {
|
|
37
|
-
constructor(
|
|
38
|
-
this.
|
|
149
|
+
constructor(options = {}) {
|
|
150
|
+
this.refreshInFlight = null;
|
|
151
|
+
this.options = options;
|
|
152
|
+
this.auth = new SinasClientAuth(this);
|
|
39
153
|
}
|
|
154
|
+
// ─── Config / base URL ───
|
|
40
155
|
getConfig() {
|
|
41
|
-
const config = this.
|
|
156
|
+
const config = this.options.config || (hasWindow() ? window.__SINAS_CONFIG__ : void 0);
|
|
42
157
|
if (!config) {
|
|
43
158
|
return {
|
|
44
|
-
apiBase: "",
|
|
159
|
+
apiBase: this.options.baseUrl ? `${trim(this.options.baseUrl)}/api/v1` : "",
|
|
45
160
|
component: { namespace: "", name: "", version: "" },
|
|
46
161
|
resources: {
|
|
47
162
|
enabledAgents: [],
|
|
@@ -58,12 +173,56 @@ var SinasClient = class {
|
|
|
58
173
|
getInput() {
|
|
59
174
|
return this.getConfig().input || {};
|
|
60
175
|
}
|
|
176
|
+
/** Workspace base URL (root of the Sinas instance). Throws if unset. */
|
|
177
|
+
requireBaseUrl() {
|
|
178
|
+
const url = this.getBaseUrl();
|
|
179
|
+
if (!url) {
|
|
180
|
+
throw new SinasError(
|
|
181
|
+
"No baseUrl configured. Construct with `new SinasClient({ baseUrl })` for standalone use.",
|
|
182
|
+
0
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return url;
|
|
186
|
+
}
|
|
187
|
+
getBaseUrl() {
|
|
188
|
+
if (this.options.baseUrl) return trim(this.options.baseUrl);
|
|
189
|
+
const apiBase = this.getConfig().apiBase;
|
|
190
|
+
if (!apiBase) return null;
|
|
191
|
+
return trim(apiBase).replace(/\/api\/v1$/, "");
|
|
192
|
+
}
|
|
193
|
+
// ─── Tokens ───
|
|
194
|
+
getAccessToken() {
|
|
195
|
+
if (this.options.getAccessToken) return this.options.getAccessToken();
|
|
196
|
+
if (hasWindow()) return window.__SINAS_AUTH_TOKEN__ ?? null;
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
getRefreshToken() {
|
|
200
|
+
return this.options.getRefreshToken ? this.options.getRefreshToken() : null;
|
|
201
|
+
}
|
|
202
|
+
async tryRefresh() {
|
|
203
|
+
const refreshToken = this.getRefreshToken();
|
|
204
|
+
if (!refreshToken) return null;
|
|
205
|
+
if (this.refreshInFlight) return this.refreshInFlight;
|
|
206
|
+
const baseUrl = this.getBaseUrl();
|
|
207
|
+
if (!baseUrl) return null;
|
|
208
|
+
this.refreshInFlight = (async () => {
|
|
209
|
+
try {
|
|
210
|
+
const resp = await refresh(baseUrl, refreshToken);
|
|
211
|
+
this.options.onTokenRefresh?.(resp.access_token);
|
|
212
|
+
return resp.access_token;
|
|
213
|
+
} catch {
|
|
214
|
+
return null;
|
|
215
|
+
} finally {
|
|
216
|
+
this.refreshInFlight = null;
|
|
217
|
+
}
|
|
218
|
+
})();
|
|
219
|
+
return this.refreshInFlight;
|
|
220
|
+
}
|
|
221
|
+
// ─── Headers / proxy ───
|
|
61
222
|
getAuthHeaders() {
|
|
62
|
-
const token =
|
|
223
|
+
const token = this.getAccessToken();
|
|
63
224
|
const headers = { "Content-Type": "application/json" };
|
|
64
|
-
if (token) {
|
|
65
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
66
|
-
}
|
|
225
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
67
226
|
return headers;
|
|
68
227
|
}
|
|
69
228
|
getProxyBase() {
|
|
@@ -71,7 +230,8 @@ var SinasClient = class {
|
|
|
71
230
|
const comp = config.component;
|
|
72
231
|
return `${config.apiBase}/components/${comp.namespace}/${comp.name}/proxy`;
|
|
73
232
|
}
|
|
74
|
-
|
|
233
|
+
// ─── Fetch with refresh-on-401 ───
|
|
234
|
+
async fetch(url, options = {}, _retried = false) {
|
|
75
235
|
const res = await fetch(url, {
|
|
76
236
|
...options,
|
|
77
237
|
headers: {
|
|
@@ -79,15 +239,18 @@ var SinasClient = class {
|
|
|
79
239
|
...options.headers || {}
|
|
80
240
|
}
|
|
81
241
|
});
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
if (res.status === 404) throw new SinasNotFoundError(message);
|
|
88
|
-
throw new SinasError(message, res.status);
|
|
242
|
+
if (res.ok || res.status === 204) return res;
|
|
243
|
+
if (res.status === 401 && !_retried) {
|
|
244
|
+
const newToken = await this.tryRefresh();
|
|
245
|
+
if (newToken) return this.fetch(url, options, true);
|
|
246
|
+
this.options.onUnauthenticated?.();
|
|
89
247
|
}
|
|
90
|
-
|
|
248
|
+
const body = await res.json().catch(() => ({ detail: res.statusText }));
|
|
249
|
+
const message = body.detail || body.message || res.statusText;
|
|
250
|
+
if (res.status === 401) throw new SinasAuthError(message);
|
|
251
|
+
if (res.status === 403) throw new SinasPermissionError(message);
|
|
252
|
+
if (res.status === 404) throw new SinasNotFoundError(message);
|
|
253
|
+
throw new SinasError(message, res.status);
|
|
91
254
|
}
|
|
92
255
|
};
|
|
93
256
|
|
|
@@ -411,6 +574,14 @@ export {
|
|
|
411
574
|
SinasPermissionError,
|
|
412
575
|
SinasNotFoundError,
|
|
413
576
|
SinasTimeoutError,
|
|
577
|
+
getInfo,
|
|
578
|
+
login,
|
|
579
|
+
verifyOTP,
|
|
580
|
+
refresh,
|
|
581
|
+
logout,
|
|
582
|
+
getMe,
|
|
583
|
+
checkPermissions,
|
|
584
|
+
SinasClientAuth,
|
|
414
585
|
SinasClient,
|
|
415
586
|
executeQuery,
|
|
416
587
|
executeFunction,
|
|
@@ -429,4 +600,4 @@ export {
|
|
|
429
600
|
uploadFile,
|
|
430
601
|
generateFileUrl
|
|
431
602
|
};
|
|
432
|
-
//# sourceMappingURL=chunk-
|
|
603
|
+
//# sourceMappingURL=chunk-IABVF56L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/errors.ts","../src/client/auth.ts","../src/client/SinasClient.ts","../src/client/queries.ts","../src/client/functions.ts","../src/client/states.ts","../src/client/chat.ts","../src/client/collections.ts"],"sourcesContent":["export class SinasError extends Error {\n public readonly status: number;\n public readonly detail: string;\n\n constructor(message: string, status: number = 0, detail?: string) {\n super(message);\n this.name = 'SinasError';\n this.status = status;\n this.detail = detail || message;\n }\n}\n\nexport class SinasAuthError extends SinasError {\n constructor(message: string = 'Authentication required') {\n super(message, 401);\n this.name = 'SinasAuthError';\n }\n}\n\nexport class SinasPermissionError extends SinasError {\n constructor(message: string = 'Permission denied') {\n super(message, 403);\n this.name = 'SinasPermissionError';\n }\n}\n\nexport class SinasNotFoundError extends SinasError {\n constructor(resource: string) {\n super(`${resource} not found`, 404);\n this.name = 'SinasNotFoundError';\n }\n}\n\nexport class SinasTimeoutError extends SinasError {\n constructor(message: string = 'Request timed out') {\n super(message, 408);\n this.name = 'SinasTimeoutError';\n }\n}\n","import {\n SinasError,\n SinasAuthError,\n SinasPermissionError,\n SinasNotFoundError,\n} from './errors';\nimport type {\n AuthUser,\n InfoResponse,\n LoginRequest,\n LoginResponse,\n OTPVerifyRequest,\n OTPVerifyResponse,\n PermissionCheckRequest,\n PermissionCheckResponse,\n RefreshResponse,\n} from './types';\n\nfunction trimBase(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, '');\n}\n\nasync function authFetch(\n baseUrl: string,\n path: string,\n init: RequestInit = {},\n accessToken?: string | null,\n): Promise<Response> {\n const headers = new Headers(init.headers);\n if (!headers.has('Content-Type') && init.body !== undefined) {\n headers.set('Content-Type', 'application/json');\n }\n if (accessToken) headers.set('Authorization', `Bearer ${accessToken}`);\n\n const res = await fetch(`${trimBase(baseUrl)}${path}`, { ...init, headers });\n if (res.ok || res.status === 204) return res;\n\n let detail: string = res.statusText;\n try {\n const body = await res.clone().json();\n detail = body.detail || body.message || detail;\n } catch {\n // body wasn't JSON\n }\n if (res.status === 401) throw new SinasAuthError(detail);\n if (res.status === 403) throw new SinasPermissionError(detail);\n if (res.status === 404) throw new SinasNotFoundError(detail);\n throw new SinasError(detail, res.status, detail);\n}\n\n/** Fetch unauthenticated instance info. Use before showing a login screen. */\nexport async function getInfo(baseUrl: string): Promise<InfoResponse> {\n const res = await authFetch(baseUrl, '/info');\n return (await res.json()) as InfoResponse;\n}\n\n/**\n * Start a login. Response shape depends on the workspace's auth_mode:\n * - \"password\": access_token + refresh_token are set → done.\n * - \"otp\" or \"password+otp\": session_id is set → call verifyOTP next.\n */\nexport async function login(\n baseUrl: string,\n request: LoginRequest,\n): Promise<LoginResponse> {\n const res = await authFetch(baseUrl, '/auth/login', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n return (await res.json()) as LoginResponse;\n}\n\n/** Second step for \"otp\" / \"password+otp\" modes. Returns final tokens. */\nexport async function verifyOTP(\n baseUrl: string,\n request: OTPVerifyRequest,\n): Promise<OTPVerifyResponse> {\n const res = await authFetch(baseUrl, '/auth/verify-otp', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n return (await res.json()) as OTPVerifyResponse;\n}\n\n/** Exchange a refresh token for a new access token. */\nexport async function refresh(\n baseUrl: string,\n refreshToken: string,\n): Promise<RefreshResponse> {\n const res = await authFetch(baseUrl, '/auth/refresh', {\n method: 'POST',\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n return (await res.json()) as RefreshResponse;\n}\n\n/** Revoke a refresh token. Best-effort; ignore 404. */\nexport async function logout(\n baseUrl: string,\n refreshToken: string,\n): Promise<void> {\n try {\n await authFetch(baseUrl, '/auth/logout', {\n method: 'POST',\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n } catch (e) {\n if (e instanceof SinasNotFoundError) return;\n throw e;\n }\n}\n\n/** Return the authenticated user (id, email, roles). */\nexport async function getMe(\n baseUrl: string,\n accessToken: string,\n): Promise<AuthUser> {\n const res = await authFetch(baseUrl, '/auth/me', { method: 'GET' }, accessToken);\n return (await res.json()) as AuthUser;\n}\n\n/** Check whether the authenticated user has the given permissions. */\nexport async function checkPermissions(\n baseUrl: string,\n accessToken: string,\n request: PermissionCheckRequest,\n): Promise<PermissionCheckResponse> {\n const res = await authFetch(\n baseUrl,\n '/auth/check-permissions',\n {\n method: 'POST',\n body: JSON.stringify({ logic: 'AND', ...request }),\n },\n accessToken,\n );\n return (await res.json()) as PermissionCheckResponse;\n}\n","import {\n SinasError,\n SinasAuthError,\n SinasPermissionError,\n SinasNotFoundError,\n} from './errors';\nimport * as authApi from './auth';\nimport type {\n SinasConfig,\n InfoResponse,\n LoginRequest,\n LoginResponse,\n OTPVerifyRequest,\n OTPVerifyResponse,\n PermissionCheckRequest,\n PermissionCheckResponse,\n RefreshResponse,\n AuthUser,\n} from './types';\n\ndeclare global {\n interface Window {\n __SINAS_CONFIG__?: SinasConfig;\n __SINAS_AUTH_TOKEN__?: string | null;\n }\n}\n\nexport interface SinasClientOptions {\n /** Embedded-component config. Falls back to window.__SINAS_CONFIG__. */\n config?: SinasConfig;\n /** Workspace base URL for standalone use. Overrides config.apiBase for non-proxy calls. */\n baseUrl?: string;\n /** Returns the current access token, or null. Falls back to window.__SINAS_AUTH_TOKEN__. */\n getAccessToken?: () => string | null;\n /** Returns the current refresh token. Required for auto-refresh on 401. */\n getRefreshToken?: () => string | null;\n /** Called with the new access token after a successful /auth/refresh. */\n onTokenRefresh?: (accessToken: string) => void;\n /** Called when a request remains unauthenticated after a refresh attempt. */\n onUnauthenticated?: () => void;\n}\n\nfunction hasWindow(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction trim(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n\n/**\n * Auth namespace on SinasClient. Standalone counterparts live in client/auth.ts.\n */\nexport class SinasClientAuth {\n constructor(private readonly client: SinasClient) {}\n\n getInfo(): Promise<InfoResponse> {\n return authApi.getInfo(this.client.requireBaseUrl());\n }\n\n login(request: LoginRequest): Promise<LoginResponse> {\n return authApi.login(this.client.requireBaseUrl(), request);\n }\n\n verifyOTP(request: OTPVerifyRequest): Promise<OTPVerifyResponse> {\n return authApi.verifyOTP(this.client.requireBaseUrl(), request);\n }\n\n refresh(refreshToken: string): Promise<RefreshResponse> {\n return authApi.refresh(this.client.requireBaseUrl(), refreshToken);\n }\n\n logout(refreshToken: string): Promise<void> {\n return authApi.logout(this.client.requireBaseUrl(), refreshToken);\n }\n\n getMe(): Promise<AuthUser> {\n const token = this.client.getAccessToken();\n if (!token) throw new SinasAuthError('No access token available');\n return authApi.getMe(this.client.requireBaseUrl(), token);\n }\n\n checkPermissions(request: PermissionCheckRequest): Promise<PermissionCheckResponse> {\n const token = this.client.getAccessToken();\n if (!token) throw new SinasAuthError('No access token available');\n return authApi.checkPermissions(this.client.requireBaseUrl(), token, request);\n }\n}\n\nexport class SinasClient {\n readonly auth: SinasClientAuth;\n\n private readonly options: SinasClientOptions;\n private refreshInFlight: Promise<string | null> | null = null;\n\n constructor(options: SinasClientOptions = {}) {\n this.options = options;\n this.auth = new SinasClientAuth(this);\n }\n\n // ─── Config / base URL ───\n\n getConfig(): SinasConfig {\n const config =\n this.options.config || (hasWindow() ? window.__SINAS_CONFIG__ : undefined);\n if (!config) {\n return {\n apiBase: this.options.baseUrl ? `${trim(this.options.baseUrl)}/api/v1` : '',\n component: { namespace: '', name: '', version: '' },\n resources: {\n enabledAgents: [],\n enabledFunctions: [],\n enabledQueries: [],\n enabledComponents: [],\n enabledStores: [],\n },\n input: {},\n };\n }\n return config;\n }\n\n getInput(): Record<string, unknown> {\n return this.getConfig().input || {};\n }\n\n /** Workspace base URL (root of the Sinas instance). Throws if unset. */\n requireBaseUrl(): string {\n const url = this.getBaseUrl();\n if (!url) {\n throw new SinasError(\n 'No baseUrl configured. Construct with `new SinasClient({ baseUrl })` for standalone use.',\n 0,\n );\n }\n return url;\n }\n\n getBaseUrl(): string | null {\n if (this.options.baseUrl) return trim(this.options.baseUrl);\n // Embedded mode: derive from config.apiBase by stripping /api/v1\n const apiBase = this.getConfig().apiBase;\n if (!apiBase) return null;\n return trim(apiBase).replace(/\\/api\\/v1$/, '');\n }\n\n // ─── Tokens ───\n\n getAccessToken(): string | null {\n if (this.options.getAccessToken) return this.options.getAccessToken();\n if (hasWindow()) return window.__SINAS_AUTH_TOKEN__ ?? null;\n return null;\n }\n\n private getRefreshToken(): string | null {\n return this.options.getRefreshToken ? this.options.getRefreshToken() : null;\n }\n\n private async tryRefresh(): Promise<string | null> {\n const refreshToken = this.getRefreshToken();\n if (!refreshToken) return null;\n if (this.refreshInFlight) return this.refreshInFlight;\n const baseUrl = this.getBaseUrl();\n if (!baseUrl) return null;\n\n this.refreshInFlight = (async () => {\n try {\n const resp = await authApi.refresh(baseUrl, refreshToken);\n this.options.onTokenRefresh?.(resp.access_token);\n return resp.access_token;\n } catch {\n return null;\n } finally {\n this.refreshInFlight = null;\n }\n })();\n return this.refreshInFlight;\n }\n\n // ─── Headers / proxy ───\n\n getAuthHeaders(): Record<string, string> {\n const token = this.getAccessToken();\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (token) headers['Authorization'] = `Bearer ${token}`;\n return headers;\n }\n\n getProxyBase(): string {\n const config = this.getConfig();\n const comp = config.component;\n return `${config.apiBase}/components/${comp.namespace}/${comp.name}/proxy`;\n }\n\n // ─── Fetch with refresh-on-401 ───\n\n async fetch(url: string, options: RequestInit = {}, _retried = false): Promise<Response> {\n const res = await fetch(url, {\n ...options,\n headers: {\n ...this.getAuthHeaders(),\n ...((options.headers as Record<string, string>) || {}),\n },\n });\n\n if (res.ok || res.status === 204) return res;\n\n if (res.status === 401 && !_retried) {\n const newToken = await this.tryRefresh();\n if (newToken) return this.fetch(url, options, true);\n this.options.onUnauthenticated?.();\n }\n\n const body = await res.json().catch(() => ({ detail: res.statusText }));\n const message = body.detail || body.message || res.statusText;\n\n if (res.status === 401) throw new SinasAuthError(message);\n if (res.status === 403) throw new SinasPermissionError(message);\n if (res.status === 404) throw new SinasNotFoundError(message);\n throw new SinasError(message, res.status);\n }\n}\n","import type { SinasClient } from './SinasClient';\nimport type { QueryResult } from './types';\n\nfunction parseRef(ref: string): [string, string] {\n const parts = ref.split('/');\n if (parts.length !== 2) {\n throw new Error(`Invalid query ref \"${ref}\": expected \"namespace/name\"`);\n }\n return [parts[0], parts[1]];\n}\n\nexport async function executeQuery(\n client: SinasClient,\n ref: string,\n input: Record<string, unknown> = {}\n): Promise<QueryResult> {\n const [ns, name] = parseRef(ref);\n const base = client.getProxyBase();\n const res = await client.fetch(`${base}/queries/${ns}/${name}/execute`, {\n method: 'POST',\n body: JSON.stringify({ input }),\n });\n const data = await res.json();\n return {\n success: data.success,\n operation: data.operation,\n data: data.data,\n rowCount: data.row_count,\n affectedRows: data.affected_rows,\n durationMs: data.duration_ms,\n };\n}\n","import type { SinasClient } from './SinasClient';\nimport type { FunctionResult } from './types';\n\nfunction parseRef(ref: string): [string, string] {\n const parts = ref.split('/');\n if (parts.length !== 2) {\n throw new Error(`Invalid function ref \"${ref}\": expected \"namespace/name\"`);\n }\n return [parts[0], parts[1]];\n}\n\nexport async function executeFunction(\n client: SinasClient,\n ref: string,\n input: Record<string, unknown> = {},\n timeout?: number\n): Promise<FunctionResult> {\n const [ns, name] = parseRef(ref);\n const base = client.getProxyBase();\n const body: Record<string, unknown> = { input };\n if (timeout !== undefined) {\n body.timeout = timeout;\n }\n const res = await client.fetch(`${base}/functions/${ns}/${name}/execute`, {\n method: 'POST',\n body: JSON.stringify(body),\n });\n const data = await res.json();\n return {\n status: data.status,\n executionId: data.execution_id,\n result: data.result,\n error: data.error,\n };\n}\n","import type { SinasClient } from './SinasClient';\nimport type { StateGetResult, StateListResult } from './types';\n\nexport async function stateGet(\n client: SinasClient,\n ns: string,\n key: string\n): Promise<StateGetResult> {\n const base = client.getProxyBase();\n const res = await client.fetch(`${base}/states/${ns}`, {\n method: 'POST',\n body: JSON.stringify({ action: 'get', key }),\n });\n return res.json();\n}\n\nexport async function stateSet(\n client: SinasClient,\n ns: string,\n key: string,\n value: unknown,\n visibility: 'private' | 'shared' = 'private'\n): Promise<void> {\n const base = client.getProxyBase();\n await client.fetch(`${base}/states/${ns}`, {\n method: 'POST',\n body: JSON.stringify({ action: 'set', key, value, visibility }),\n });\n}\n\nexport async function stateDelete(\n client: SinasClient,\n ns: string,\n key: string\n): Promise<void> {\n const base = client.getProxyBase();\n await client.fetch(`${base}/states/${ns}`, {\n method: 'POST',\n body: JSON.stringify({ action: 'delete', key }),\n });\n}\n\nexport async function stateList(\n client: SinasClient,\n ns: string\n): Promise<StateListResult> {\n const base = client.getProxyBase();\n const res = await client.fetch(`${base}/states/${ns}`, {\n method: 'POST',\n body: JSON.stringify({ action: 'list' }),\n });\n return res.json();\n}\n","import type { SinasClient } from './SinasClient';\nimport type { ChatCreateResult, ChatMessage, ChatDetail, ChatMessageFull, ApprovalRequest, ApprovalResult, SSEChunk, MessageContent } from './types';\n\nexport async function createChat(\n client: SinasClient,\n agentRef: string,\n input?: Record<string, unknown>\n): Promise<ChatCreateResult> {\n const [ns, name] = agentRef.split('/');\n if (!ns || !name) {\n throw new Error(`Invalid agent ref \"${agentRef}\": expected \"namespace/name\"`);\n }\n const config = client.getConfig();\n const res = await client.fetch(`${config.apiBase}/agents/${ns}/${name}/chats`, {\n method: 'POST',\n body: JSON.stringify({ input: input || {} }),\n });\n const data = await res.json();\n return {\n id: data.id,\n agentNamespace: data.agent_namespace,\n agentName: data.agent_name,\n title: data.title,\n };\n}\n\nexport async function sendMessage(\n client: SinasClient,\n chatId: string,\n content: MessageContent\n): Promise<ChatMessage> {\n const config = client.getConfig();\n const res = await client.fetch(`${config.apiBase}/chats/${chatId}/messages`, {\n method: 'POST',\n body: JSON.stringify({ content }),\n });\n const data = await res.json();\n return {\n id: data.id,\n chatId: data.chat_id,\n role: data.role,\n content: data.content,\n createdAt: data.created_at,\n };\n}\n\nfunction mapMessage(data: Record<string, unknown>): ChatMessageFull {\n const toolCalls = data.tool_calls as ChatMessageFull['toolCalls'] | undefined;\n return {\n id: data.id as string,\n chatId: data.chat_id as string,\n role: data.role as ChatMessageFull['role'],\n content: (data.content as string) ?? null,\n toolCalls: toolCalls ?? null,\n toolCallId: (data.tool_call_id as string) ?? null,\n name: (data.name as string) ?? null,\n createdAt: data.created_at as string,\n };\n}\n\nexport async function getChat(\n client: SinasClient,\n chatId: string,\n): Promise<ChatDetail> {\n const config = client.getConfig();\n const res = await client.fetch(`${config.apiBase}/chats/${chatId}`);\n const data = await res.json();\n return {\n id: data.id,\n agentNamespace: data.agent_namespace,\n agentName: data.agent_name,\n title: data.title,\n messages: (data.messages || []).map(mapMessage),\n pendingApprovals: (data.pending_approvals || []).map((pa: Record<string, unknown>): ApprovalRequest => ({\n type: 'approval_required',\n toolCallId: pa.tool_call_id as string,\n functionNamespace: pa.function_namespace as string,\n functionName: pa.function_name as string,\n arguments: (pa.arguments as Record<string, unknown>) || {},\n })),\n };\n}\n\nexport async function approveToolCall(\n client: SinasClient,\n chatId: string,\n toolCallId: string,\n approved: boolean,\n): Promise<ApprovalResult> {\n const config = client.getConfig();\n const res = await client.fetch(\n `${config.apiBase}/chats/${chatId}/approve-tool/${toolCallId}`,\n { method: 'POST', body: JSON.stringify({ approved }) },\n );\n const data = await res.json();\n return {\n status: data.status,\n toolCallId: data.tool_call_id,\n channelId: data.channel_id,\n };\n}\n\nexport function streamFromChannel(\n client: SinasClient,\n chatId: string,\n channelId: string,\n onChunk: (chunk: SSEChunk) => void,\n onDone?: () => void,\n onError?: (error: Error) => void,\n): AbortController {\n const controller = new AbortController();\n const config = client.getConfig();\n\n (async () => {\n try {\n const res = await fetch(\n `${config.apiBase}/chats/${chatId}/stream/${channelId}?last_id=0`,\n { headers: client.getAuthHeaders(), signal: controller.signal },\n );\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ detail: res.statusText }));\n throw new Error(body.detail || 'Stream reconnect failed');\n }\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const { chunks, remaining } = parseSSE(buffer);\n buffer = remaining;\n\n for (const chunk of chunks) {\n onChunk(chunk);\n if (chunk.event === 'done') {\n onDone?.();\n return;\n }\n }\n }\n\n if (buffer.trim()) {\n const { chunks } = parseSSE(buffer + '\\n\\n');\n for (const chunk of chunks) {\n onChunk(chunk);\n }\n }\n\n onDone?.();\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n onError?.(err as Error);\n }\n })();\n\n return controller;\n}\n\nfunction parseSSE(buffer: string): { chunks: SSEChunk[]; remaining: string } {\n const chunks: SSEChunk[] = [];\n // Normalize \\r\\n to \\n (sse_starlette uses \\r\\n line endings)\n const normalized = buffer.replace(/\\r\\n/g, '\\n');\n const lines = normalized.split('\\n');\n let event = '';\n let data = '';\n let remaining = '';\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // If last line and doesn't end with newline, it's incomplete\n if (i === lines.length - 1 && !normalized.endsWith('\\n')) {\n remaining = line;\n break;\n }\n\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n data = line.slice(5).trim();\n } else if (line === '') {\n if (event || data) {\n chunks.push({ event: event || 'message', data });\n event = '';\n data = '';\n }\n }\n }\n\n return { chunks, remaining };\n}\n\nexport function streamMessage(\n client: SinasClient,\n chatId: string,\n content: MessageContent,\n onChunk: (chunk: SSEChunk) => void,\n onDone?: () => void,\n onError?: (error: Error) => void\n): AbortController {\n const controller = new AbortController();\n const config = client.getConfig();\n\n (async () => {\n try {\n const res = await fetch(`${config.apiBase}/chats/${chatId}/messages/stream`, {\n method: 'POST',\n headers: client.getAuthHeaders(),\n body: JSON.stringify({ content }),\n signal: controller.signal,\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ detail: res.statusText }));\n throw new Error(body.detail || 'Stream request failed');\n }\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const { chunks, remaining } = parseSSE(buffer);\n buffer = remaining;\n\n for (const chunk of chunks) {\n onChunk(chunk);\n if (chunk.event === 'done') {\n onDone?.();\n return;\n }\n }\n }\n\n // Process any remaining buffer\n if (buffer.trim()) {\n const { chunks } = parseSSE(buffer + '\\n\\n');\n for (const chunk of chunks) {\n onChunk(chunk);\n }\n }\n\n onDone?.();\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n onError?.(err as Error);\n }\n })();\n\n return controller;\n}\n","import type { SinasClient } from './SinasClient';\nimport type { Collection, FileInfo, FileUploadRequest, FileUrlResult } from './types';\n\nexport async function listCollections(client: SinasClient): Promise<Collection[]> {\n const base = client.getProxyBase();\n const res = await client.fetch(`${base}/collections`);\n return res.json();\n}\n\nexport async function listFiles(\n client: SinasClient,\n namespace: string,\n collection: string\n): Promise<FileInfo[]> {\n const base = client.getProxyBase();\n const res = await client.fetch(`${base}/files/${namespace}/${collection}`);\n return res.json();\n}\n\nexport async function uploadFile(\n client: SinasClient,\n namespace: string,\n collection: string,\n data: FileUploadRequest,\n): Promise<FileInfo> {\n const apiBase = client.getConfig().apiBase;\n const res = await client.fetch(`${apiBase}/files/${namespace}/${collection}`, {\n method: 'POST',\n body: JSON.stringify(data),\n });\n return res.json();\n}\n\nexport async function generateFileUrl(\n client: SinasClient,\n namespace: string,\n collection: string,\n filename: string,\n expiresIn?: number,\n): Promise<FileUrlResult> {\n const apiBase = client.getConfig().apiBase;\n const params = new URLSearchParams();\n if (expiresIn) params.set('expires_in', String(expiresIn));\n const qs = params.toString() ? `?${params.toString()}` : '';\n const res = await client.fetch(\n `${apiBase}/files/${namespace}/${collection}/${encodeURIComponent(filename)}/url${qs}`,\n { method: 'POST' },\n );\n return res.json();\n}\n"],"mappings":";AAAO,IAAM,aAAN,cAAyB,MAAM;AAAA,EAIpC,YAAY,SAAiB,SAAiB,GAAG,QAAiB;AAChE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,SAAS,UAAU;AAAA,EAC1B;AACF;AAEO,IAAM,iBAAN,cAA6B,WAAW;AAAA,EAC7C,YAAY,UAAkB,2BAA2B;AACvD,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,WAAW;AAAA,EACnD,YAAY,UAAkB,qBAAqB;AACjD,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EACjD,YAAY,UAAkB;AAC5B,UAAM,GAAG,QAAQ,cAAc,GAAG;AAClC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,oBAAN,cAAgC,WAAW;AAAA,EAChD,YAAY,UAAkB,qBAAqB;AACjD,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;;;ACpBA,SAAS,SAAS,SAAyB;AACzC,SAAO,QAAQ,QAAQ,QAAQ,EAAE;AACnC;AAEA,eAAe,UACb,SACA,MACA,OAAoB,CAAC,GACrB,aACmB;AACnB,QAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AACxC,MAAI,CAAC,QAAQ,IAAI,cAAc,KAAK,KAAK,SAAS,QAAW;AAC3D,YAAQ,IAAI,gBAAgB,kBAAkB;AAAA,EAChD;AACA,MAAI,YAAa,SAAQ,IAAI,iBAAiB,UAAU,WAAW,EAAE;AAErE,QAAM,MAAM,MAAM,MAAM,GAAG,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC;AAC3E,MAAI,IAAI,MAAM,IAAI,WAAW,IAAK,QAAO;AAEzC,MAAI,SAAiB,IAAI;AACzB,MAAI;AACF,UAAM,OAAO,MAAM,IAAI,MAAM,EAAE,KAAK;AACpC,aAAS,KAAK,UAAU,KAAK,WAAW;AAAA,EAC1C,QAAQ;AAAA,EAER;AACA,MAAI,IAAI,WAAW,IAAK,OAAM,IAAI,eAAe,MAAM;AACvD,MAAI,IAAI,WAAW,IAAK,OAAM,IAAI,qBAAqB,MAAM;AAC7D,MAAI,IAAI,WAAW,IAAK,OAAM,IAAI,mBAAmB,MAAM;AAC3D,QAAM,IAAI,WAAW,QAAQ,IAAI,QAAQ,MAAM;AACjD;AAGA,eAAsB,QAAQ,SAAwC;AACpE,QAAM,MAAM,MAAM,UAAU,SAAS,OAAO;AAC5C,SAAQ,MAAM,IAAI,KAAK;AACzB;AAOA,eAAsB,MACpB,SACA,SACwB;AACxB,QAAM,MAAM,MAAM,UAAU,SAAS,eAAe;AAAA,IAClD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AACD,SAAQ,MAAM,IAAI,KAAK;AACzB;AAGA,eAAsB,UACpB,SACA,SAC4B;AAC5B,QAAM,MAAM,MAAM,UAAU,SAAS,oBAAoB;AAAA,IACvD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AACD,SAAQ,MAAM,IAAI,KAAK;AACzB;AAGA,eAAsB,QACpB,SACA,cAC0B;AAC1B,QAAM,MAAM,MAAM,UAAU,SAAS,iBAAiB;AAAA,IACpD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,eAAe,aAAa,CAAC;AAAA,EACtD,CAAC;AACD,SAAQ,MAAM,IAAI,KAAK;AACzB;AAGA,eAAsB,OACpB,SACA,cACe;AACf,MAAI;AACF,UAAM,UAAU,SAAS,gBAAgB;AAAA,MACvC,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,eAAe,aAAa,CAAC;AAAA,IACtD,CAAC;AAAA,EACH,SAAS,GAAG;AACV,QAAI,aAAa,mBAAoB;AACrC,UAAM;AAAA,EACR;AACF;AAGA,eAAsB,MACpB,SACA,aACmB;AACnB,QAAM,MAAM,MAAM,UAAU,SAAS,YAAY,EAAE,QAAQ,MAAM,GAAG,WAAW;AAC/E,SAAQ,MAAM,IAAI,KAAK;AACzB;AAGA,eAAsB,iBACpB,SACA,aACA,SACkC;AAClC,QAAM,MAAM,MAAM;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,OAAO,OAAO,GAAG,QAAQ,CAAC;AAAA,IACnD;AAAA,IACA;AAAA,EACF;AACA,SAAQ,MAAM,IAAI,KAAK;AACzB;;;AC/FA,SAAS,YAAqB;AAC5B,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,KAAK,KAAqB;AACjC,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAKO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA6B,QAAqB;AAArB;AAAA,EAAsB;AAAA,EAEnD,UAAiC;AAC/B,WAAe,QAAQ,KAAK,OAAO,eAAe,CAAC;AAAA,EACrD;AAAA,EAEA,MAAM,SAA+C;AACnD,WAAe,MAAM,KAAK,OAAO,eAAe,GAAG,OAAO;AAAA,EAC5D;AAAA,EAEA,UAAU,SAAuD;AAC/D,WAAe,UAAU,KAAK,OAAO,eAAe,GAAG,OAAO;AAAA,EAChE;AAAA,EAEA,QAAQ,cAAgD;AACtD,WAAe,QAAQ,KAAK,OAAO,eAAe,GAAG,YAAY;AAAA,EACnE;AAAA,EAEA,OAAO,cAAqC;AAC1C,WAAe,OAAO,KAAK,OAAO,eAAe,GAAG,YAAY;AAAA,EAClE;AAAA,EAEA,QAA2B;AACzB,UAAM,QAAQ,KAAK,OAAO,eAAe;AACzC,QAAI,CAAC,MAAO,OAAM,IAAI,eAAe,2BAA2B;AAChE,WAAe,MAAM,KAAK,OAAO,eAAe,GAAG,KAAK;AAAA,EAC1D;AAAA,EAEA,iBAAiB,SAAmE;AAClF,UAAM,QAAQ,KAAK,OAAO,eAAe;AACzC,QAAI,CAAC,MAAO,OAAM,IAAI,eAAe,2BAA2B;AAChE,WAAe,iBAAiB,KAAK,OAAO,eAAe,GAAG,OAAO,OAAO;AAAA,EAC9E;AACF;AAEO,IAAM,cAAN,MAAkB;AAAA,EAMvB,YAAY,UAA8B,CAAC,GAAG;AAF9C,SAAQ,kBAAiD;AAGvD,SAAK,UAAU;AACf,SAAK,OAAO,IAAI,gBAAgB,IAAI;AAAA,EACtC;AAAA;AAAA,EAIA,YAAyB;AACvB,UAAM,SACJ,KAAK,QAAQ,WAAW,UAAU,IAAI,OAAO,mBAAmB;AAClE,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS,KAAK,QAAQ,UAAU,GAAG,KAAK,KAAK,QAAQ,OAAO,CAAC,YAAY;AAAA,QACzE,WAAW,EAAE,WAAW,IAAI,MAAM,IAAI,SAAS,GAAG;AAAA,QAClD,WAAW;AAAA,UACT,eAAe,CAAC;AAAA,UAChB,kBAAkB,CAAC;AAAA,UACnB,gBAAgB,CAAC;AAAA,UACjB,mBAAmB,CAAC;AAAA,UACpB,eAAe,CAAC;AAAA,QAClB;AAAA,QACA,OAAO,CAAC;AAAA,MACV;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,WAAoC;AAClC,WAAO,KAAK,UAAU,EAAE,SAAS,CAAC;AAAA,EACpC;AAAA;AAAA,EAGA,iBAAyB;AACvB,UAAM,MAAM,KAAK,WAAW;AAC5B,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,aAA4B;AAC1B,QAAI,KAAK,QAAQ,QAAS,QAAO,KAAK,KAAK,QAAQ,OAAO;AAE1D,UAAM,UAAU,KAAK,UAAU,EAAE;AACjC,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,KAAK,OAAO,EAAE,QAAQ,cAAc,EAAE;AAAA,EAC/C;AAAA;AAAA,EAIA,iBAAgC;AAC9B,QAAI,KAAK,QAAQ,eAAgB,QAAO,KAAK,QAAQ,eAAe;AACpE,QAAI,UAAU,EAAG,QAAO,OAAO,wBAAwB;AACvD,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAiC;AACvC,WAAO,KAAK,QAAQ,kBAAkB,KAAK,QAAQ,gBAAgB,IAAI;AAAA,EACzE;AAAA,EAEA,MAAc,aAAqC;AACjD,UAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAI,CAAC,aAAc,QAAO;AAC1B,QAAI,KAAK,gBAAiB,QAAO,KAAK;AACtC,UAAM,UAAU,KAAK,WAAW;AAChC,QAAI,CAAC,QAAS,QAAO;AAErB,SAAK,mBAAmB,YAAY;AAClC,UAAI;AACF,cAAM,OAAO,MAAc,QAAQ,SAAS,YAAY;AACxD,aAAK,QAAQ,iBAAiB,KAAK,YAAY;AAC/C,eAAO,KAAK;AAAA,MACd,QAAQ;AACN,eAAO;AAAA,MACT,UAAE;AACA,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF,GAAG;AACH,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAIA,iBAAyC;AACvC,UAAM,QAAQ,KAAK,eAAe;AAClC,UAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,QAAI,MAAO,SAAQ,eAAe,IAAI,UAAU,KAAK;AACrD,WAAO;AAAA,EACT;AAAA,EAEA,eAAuB;AACrB,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,OAAO,OAAO;AACpB,WAAO,GAAG,OAAO,OAAO,eAAe,KAAK,SAAS,IAAI,KAAK,IAAI;AAAA,EACpE;AAAA;AAAA,EAIA,MAAM,MAAM,KAAa,UAAuB,CAAC,GAAG,WAAW,OAA0B;AACvF,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAG,KAAK,eAAe;AAAA,QACvB,GAAK,QAAQ,WAAsC,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAED,QAAI,IAAI,MAAM,IAAI,WAAW,IAAK,QAAO;AAEzC,QAAI,IAAI,WAAW,OAAO,CAAC,UAAU;AACnC,YAAM,WAAW,MAAM,KAAK,WAAW;AACvC,UAAI,SAAU,QAAO,KAAK,MAAM,KAAK,SAAS,IAAI;AAClD,WAAK,QAAQ,oBAAoB;AAAA,IACnC;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE;AACtE,UAAM,UAAU,KAAK,UAAU,KAAK,WAAW,IAAI;AAEnD,QAAI,IAAI,WAAW,IAAK,OAAM,IAAI,eAAe,OAAO;AACxD,QAAI,IAAI,WAAW,IAAK,OAAM,IAAI,qBAAqB,OAAO;AAC9D,QAAI,IAAI,WAAW,IAAK,OAAM,IAAI,mBAAmB,OAAO;AAC5D,UAAM,IAAI,WAAW,SAAS,IAAI,MAAM;AAAA,EAC1C;AACF;;;AC1NA,SAAS,SAAS,KAA+B;AAC/C,QAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,sBAAsB,GAAG,8BAA8B;AAAA,EACzE;AACA,SAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAC5B;AAEA,eAAsB,aACpB,QACA,KACA,QAAiC,CAAC,GACZ;AACtB,QAAM,CAAC,IAAI,IAAI,IAAI,SAAS,GAAG;AAC/B,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI,YAAY,EAAE,IAAI,IAAI,YAAY;AAAA,IACtE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,EAChC,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO;AAAA,IACL,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,IAChB,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,IACf,cAAc,KAAK;AAAA,IACnB,YAAY,KAAK;AAAA,EACnB;AACF;;;AC5BA,SAASA,UAAS,KAA+B;AAC/C,QAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,yBAAyB,GAAG,8BAA8B;AAAA,EAC5E;AACA,SAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAC5B;AAEA,eAAsB,gBACpB,QACA,KACA,QAAiC,CAAC,GAClC,SACyB;AACzB,QAAM,CAAC,IAAI,IAAI,IAAIA,UAAS,GAAG;AAC/B,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,OAAgC,EAAE,MAAM;AAC9C,MAAI,YAAY,QAAW;AACzB,SAAK,UAAU;AAAA,EACjB;AACA,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI,cAAc,EAAE,IAAI,IAAI,YAAY;AAAA,IACxE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,aAAa,KAAK;AAAA,IAClB,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,EACd;AACF;;;AC/BA,eAAsB,SACpB,QACA,IACA,KACyB;AACzB,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI,WAAW,EAAE,IAAI;AAAA,IACrD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,QAAQ,OAAO,IAAI,CAAC;AAAA,EAC7C,CAAC;AACD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,SACpB,QACA,IACA,KACA,OACA,aAAmC,WACpB;AACf,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,OAAO,MAAM,GAAG,IAAI,WAAW,EAAE,IAAI;AAAA,IACzC,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,QAAQ,OAAO,KAAK,OAAO,WAAW,CAAC;AAAA,EAChE,CAAC;AACH;AAEA,eAAsB,YACpB,QACA,IACA,KACe;AACf,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,OAAO,MAAM,GAAG,IAAI,WAAW,EAAE,IAAI;AAAA,IACzC,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,QAAQ,UAAU,IAAI,CAAC;AAAA,EAChD,CAAC;AACH;AAEA,eAAsB,UACpB,QACA,IAC0B;AAC1B,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI,WAAW,EAAE,IAAI;AAAA,IACrD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,QAAQ,OAAO,CAAC;AAAA,EACzC,CAAC;AACD,SAAO,IAAI,KAAK;AAClB;;;ACjDA,eAAsB,WACpB,QACA,UACA,OAC2B;AAC3B,QAAM,CAAC,IAAI,IAAI,IAAI,SAAS,MAAM,GAAG;AACrC,MAAI,CAAC,MAAM,CAAC,MAAM;AAChB,UAAM,IAAI,MAAM,sBAAsB,QAAQ,8BAA8B;AAAA,EAC9E;AACA,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,OAAO,OAAO,WAAW,EAAE,IAAI,IAAI,UAAU;AAAA,IAC7E,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC,EAAE,CAAC;AAAA,EAC7C,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,gBAAgB,KAAK;AAAA,IACrB,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,EACd;AACF;AAEA,eAAsB,YACpB,QACA,QACA,SACsB;AACtB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,OAAO,OAAO,UAAU,MAAM,aAAa;AAAA,IAC3E,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,EAClC,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,EAClB;AACF;AAEA,SAAS,WAAW,MAAgD;AAClE,QAAM,YAAY,KAAK;AACvB,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAU,KAAK,WAAsB;AAAA,IACrC,WAAW,aAAa;AAAA,IACxB,YAAa,KAAK,gBAA2B;AAAA,IAC7C,MAAO,KAAK,QAAmB;AAAA,IAC/B,WAAW,KAAK;AAAA,EAClB;AACF;AAEA,eAAsB,QACpB,QACA,QACqB;AACrB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,OAAO,OAAO,UAAU,MAAM,EAAE;AAClE,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,gBAAgB,KAAK;AAAA,IACrB,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,IACZ,WAAW,KAAK,YAAY,CAAC,GAAG,IAAI,UAAU;AAAA,IAC9C,mBAAmB,KAAK,qBAAqB,CAAC,GAAG,IAAI,CAAC,QAAkD;AAAA,MACtG,MAAM;AAAA,MACN,YAAY,GAAG;AAAA,MACf,mBAAmB,GAAG;AAAA,MACtB,cAAc,GAAG;AAAA,MACjB,WAAY,GAAG,aAAyC,CAAC;AAAA,IAC3D,EAAE;AAAA,EACJ;AACF;AAEA,eAAsB,gBACpB,QACA,QACA,YACA,UACyB;AACzB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,MAAM,MAAM,OAAO;AAAA,IACvB,GAAG,OAAO,OAAO,UAAU,MAAM,iBAAiB,UAAU;AAAA,IAC5D,EAAE,QAAQ,QAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,EAAE;AAAA,EACvD;AACA,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,YAAY,KAAK;AAAA,IACjB,WAAW,KAAK;AAAA,EAClB;AACF;AAEO,SAAS,kBACd,QACA,QACA,WACA,SACA,QACA,SACiB;AACjB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,SAAS,OAAO,UAAU;AAEhC,GAAC,YAAY;AACX,QAAI;AACF,YAAM,MAAM,MAAM;AAAA,QAChB,GAAG,OAAO,OAAO,UAAU,MAAM,WAAW,SAAS;AAAA,QACrD,EAAE,SAAS,OAAO,eAAe,GAAG,QAAQ,WAAW,OAAO;AAAA,MAChE;AAEA,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE;AACtE,cAAM,IAAI,MAAM,KAAK,UAAU,yBAAyB;AAAA,MAC1D;AAEA,YAAM,SAAS,IAAI,KAAM,UAAU;AACnC,YAAM,UAAU,IAAI,YAAY;AAChC,UAAI,SAAS;AAEb,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,cAAM,EAAE,QAAQ,UAAU,IAAI,SAAS,MAAM;AAC7C,iBAAS;AAET,mBAAW,SAAS,QAAQ;AAC1B,kBAAQ,KAAK;AACb,cAAI,MAAM,UAAU,QAAQ;AAC1B,qBAAS;AACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO,KAAK,GAAG;AACjB,cAAM,EAAE,OAAO,IAAI,SAAS,SAAS,MAAM;AAC3C,mBAAW,SAAS,QAAQ;AAC1B,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAEA,eAAS;AAAA,IACX,SAAS,KAAK;AACZ,UAAK,IAAc,SAAS,aAAc;AAC1C,gBAAU,GAAY;AAAA,IACxB;AAAA,EACF,GAAG;AAEH,SAAO;AACT;AAEA,SAAS,SAAS,QAA2D;AAC3E,QAAM,SAAqB,CAAC;AAE5B,QAAM,aAAa,OAAO,QAAQ,SAAS,IAAI;AAC/C,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,MAAI,QAAQ;AACZ,MAAI,OAAO;AACX,MAAI,YAAY;AAEhB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AAGpB,QAAI,MAAM,MAAM,SAAS,KAAK,CAAC,WAAW,SAAS,IAAI,GAAG;AACxD,kBAAY;AACZ;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,cAAQ,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,IAC7B,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,aAAO,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,IAC5B,WAAW,SAAS,IAAI;AACtB,UAAI,SAAS,MAAM;AACjB,eAAO,KAAK,EAAE,OAAO,SAAS,WAAW,KAAK,CAAC;AAC/C,gBAAQ;AACR,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,UAAU;AAC7B;AAEO,SAAS,cACd,QACA,QACA,SACA,SACA,QACA,SACiB;AACjB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,SAAS,OAAO,UAAU;AAEhC,GAAC,YAAY;AACX,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,OAAO,UAAU,MAAM,oBAAoB;AAAA,QAC3E,QAAQ;AAAA,QACR,SAAS,OAAO,eAAe;AAAA,QAC/B,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,QAChC,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE;AACtE,cAAM,IAAI,MAAM,KAAK,UAAU,uBAAuB;AAAA,MACxD;AAEA,YAAM,SAAS,IAAI,KAAM,UAAU;AACnC,YAAM,UAAU,IAAI,YAAY;AAChC,UAAI,SAAS;AAEb,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,cAAM,EAAE,QAAQ,UAAU,IAAI,SAAS,MAAM;AAC7C,iBAAS;AAET,mBAAW,SAAS,QAAQ;AAC1B,kBAAQ,KAAK;AACb,cAAI,MAAM,UAAU,QAAQ;AAC1B,qBAAS;AACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI,OAAO,KAAK,GAAG;AACjB,cAAM,EAAE,OAAO,IAAI,SAAS,SAAS,MAAM;AAC3C,mBAAW,SAAS,QAAQ;AAC1B,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAEA,eAAS;AAAA,IACX,SAAS,KAAK;AACZ,UAAK,IAAc,SAAS,aAAc;AAC1C,gBAAU,GAAY;AAAA,IACxB;AAAA,EACF,GAAG;AAEH,SAAO;AACT;;;AChQA,eAAsB,gBAAgB,QAA4C;AAChF,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI,cAAc;AACpD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,UACpB,QACA,WACA,YACqB;AACrB,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI,UAAU,SAAS,IAAI,UAAU,EAAE;AACzE,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,WACpB,QACA,WACA,YACA,MACmB;AACnB,QAAM,UAAU,OAAO,UAAU,EAAE;AACnC,QAAM,MAAM,MAAM,OAAO,MAAM,GAAG,OAAO,UAAU,SAAS,IAAI,UAAU,IAAI;AAAA,IAC5E,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,gBACpB,QACA,WACA,YACA,UACA,WACwB;AACxB,QAAM,UAAU,OAAO,UAAU,EAAE;AACnC,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,UAAW,QAAO,IAAI,cAAc,OAAO,SAAS,CAAC;AACzD,QAAM,KAAK,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,CAAC,KAAK;AACzD,QAAM,MAAM,MAAM,OAAO;AAAA,IACvB,GAAG,OAAO,UAAU,SAAS,IAAI,UAAU,IAAI,mBAAmB,QAAQ,CAAC,OAAO,EAAE;AAAA,IACpF,EAAE,QAAQ,OAAO;AAAA,EACnB;AACA,SAAO,IAAI,KAAK;AAClB;","names":["parseRef"]}
|
package/dist/client.cjs
CHANGED
|
@@ -22,18 +22,25 @@ var client_exports = {};
|
|
|
22
22
|
__export(client_exports, {
|
|
23
23
|
SinasAuthError: () => SinasAuthError,
|
|
24
24
|
SinasClient: () => SinasClient,
|
|
25
|
+
SinasClientAuth: () => SinasClientAuth,
|
|
25
26
|
SinasError: () => SinasError,
|
|
26
27
|
SinasNotFoundError: () => SinasNotFoundError,
|
|
27
28
|
SinasPermissionError: () => SinasPermissionError,
|
|
28
29
|
SinasTimeoutError: () => SinasTimeoutError,
|
|
29
30
|
approveToolCall: () => approveToolCall,
|
|
31
|
+
checkPermissions: () => checkPermissions,
|
|
30
32
|
createChat: () => createChat,
|
|
31
33
|
executeFunction: () => executeFunction,
|
|
32
34
|
executeQuery: () => executeQuery,
|
|
33
35
|
generateFileUrl: () => generateFileUrl,
|
|
34
36
|
getChat: () => getChat,
|
|
37
|
+
getInfo: () => getInfo,
|
|
38
|
+
getMe: () => getMe,
|
|
35
39
|
listCollections: () => listCollections,
|
|
36
40
|
listFiles: () => listFiles,
|
|
41
|
+
login: () => login,
|
|
42
|
+
logout: () => logout,
|
|
43
|
+
refresh: () => refresh,
|
|
37
44
|
sendMessage: () => sendMessage,
|
|
38
45
|
stateDelete: () => stateDelete,
|
|
39
46
|
stateGet: () => stateGet,
|
|
@@ -41,7 +48,8 @@ __export(client_exports, {
|
|
|
41
48
|
stateSet: () => stateSet,
|
|
42
49
|
streamFromChannel: () => streamFromChannel,
|
|
43
50
|
streamMessage: () => streamMessage,
|
|
44
|
-
uploadFile: () => uploadFile
|
|
51
|
+
uploadFile: () => uploadFile,
|
|
52
|
+
verifyOTP: () => verifyOTP
|
|
45
53
|
});
|
|
46
54
|
module.exports = __toCommonJS(client_exports);
|
|
47
55
|
|
|
@@ -79,16 +87,131 @@ var SinasTimeoutError = class extends SinasError {
|
|
|
79
87
|
}
|
|
80
88
|
};
|
|
81
89
|
|
|
90
|
+
// src/client/auth.ts
|
|
91
|
+
function trimBase(baseUrl) {
|
|
92
|
+
return baseUrl.replace(/\/+$/, "");
|
|
93
|
+
}
|
|
94
|
+
async function authFetch(baseUrl, path, init = {}, accessToken) {
|
|
95
|
+
const headers = new Headers(init.headers);
|
|
96
|
+
if (!headers.has("Content-Type") && init.body !== void 0) {
|
|
97
|
+
headers.set("Content-Type", "application/json");
|
|
98
|
+
}
|
|
99
|
+
if (accessToken) headers.set("Authorization", `Bearer ${accessToken}`);
|
|
100
|
+
const res = await fetch(`${trimBase(baseUrl)}${path}`, { ...init, headers });
|
|
101
|
+
if (res.ok || res.status === 204) return res;
|
|
102
|
+
let detail = res.statusText;
|
|
103
|
+
try {
|
|
104
|
+
const body = await res.clone().json();
|
|
105
|
+
detail = body.detail || body.message || detail;
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
if (res.status === 401) throw new SinasAuthError(detail);
|
|
109
|
+
if (res.status === 403) throw new SinasPermissionError(detail);
|
|
110
|
+
if (res.status === 404) throw new SinasNotFoundError(detail);
|
|
111
|
+
throw new SinasError(detail, res.status, detail);
|
|
112
|
+
}
|
|
113
|
+
async function getInfo(baseUrl) {
|
|
114
|
+
const res = await authFetch(baseUrl, "/info");
|
|
115
|
+
return await res.json();
|
|
116
|
+
}
|
|
117
|
+
async function login(baseUrl, request) {
|
|
118
|
+
const res = await authFetch(baseUrl, "/auth/login", {
|
|
119
|
+
method: "POST",
|
|
120
|
+
body: JSON.stringify(request)
|
|
121
|
+
});
|
|
122
|
+
return await res.json();
|
|
123
|
+
}
|
|
124
|
+
async function verifyOTP(baseUrl, request) {
|
|
125
|
+
const res = await authFetch(baseUrl, "/auth/verify-otp", {
|
|
126
|
+
method: "POST",
|
|
127
|
+
body: JSON.stringify(request)
|
|
128
|
+
});
|
|
129
|
+
return await res.json();
|
|
130
|
+
}
|
|
131
|
+
async function refresh(baseUrl, refreshToken) {
|
|
132
|
+
const res = await authFetch(baseUrl, "/auth/refresh", {
|
|
133
|
+
method: "POST",
|
|
134
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
135
|
+
});
|
|
136
|
+
return await res.json();
|
|
137
|
+
}
|
|
138
|
+
async function logout(baseUrl, refreshToken) {
|
|
139
|
+
try {
|
|
140
|
+
await authFetch(baseUrl, "/auth/logout", {
|
|
141
|
+
method: "POST",
|
|
142
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
if (e instanceof SinasNotFoundError) return;
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function getMe(baseUrl, accessToken) {
|
|
150
|
+
const res = await authFetch(baseUrl, "/auth/me", { method: "GET" }, accessToken);
|
|
151
|
+
return await res.json();
|
|
152
|
+
}
|
|
153
|
+
async function checkPermissions(baseUrl, accessToken, request) {
|
|
154
|
+
const res = await authFetch(
|
|
155
|
+
baseUrl,
|
|
156
|
+
"/auth/check-permissions",
|
|
157
|
+
{
|
|
158
|
+
method: "POST",
|
|
159
|
+
body: JSON.stringify({ logic: "AND", ...request })
|
|
160
|
+
},
|
|
161
|
+
accessToken
|
|
162
|
+
);
|
|
163
|
+
return await res.json();
|
|
164
|
+
}
|
|
165
|
+
|
|
82
166
|
// src/client/SinasClient.ts
|
|
167
|
+
function hasWindow() {
|
|
168
|
+
return typeof window !== "undefined";
|
|
169
|
+
}
|
|
170
|
+
function trim(url) {
|
|
171
|
+
return url.replace(/\/+$/, "");
|
|
172
|
+
}
|
|
173
|
+
var SinasClientAuth = class {
|
|
174
|
+
constructor(client) {
|
|
175
|
+
this.client = client;
|
|
176
|
+
}
|
|
177
|
+
getInfo() {
|
|
178
|
+
return getInfo(this.client.requireBaseUrl());
|
|
179
|
+
}
|
|
180
|
+
login(request) {
|
|
181
|
+
return login(this.client.requireBaseUrl(), request);
|
|
182
|
+
}
|
|
183
|
+
verifyOTP(request) {
|
|
184
|
+
return verifyOTP(this.client.requireBaseUrl(), request);
|
|
185
|
+
}
|
|
186
|
+
refresh(refreshToken) {
|
|
187
|
+
return refresh(this.client.requireBaseUrl(), refreshToken);
|
|
188
|
+
}
|
|
189
|
+
logout(refreshToken) {
|
|
190
|
+
return logout(this.client.requireBaseUrl(), refreshToken);
|
|
191
|
+
}
|
|
192
|
+
getMe() {
|
|
193
|
+
const token = this.client.getAccessToken();
|
|
194
|
+
if (!token) throw new SinasAuthError("No access token available");
|
|
195
|
+
return getMe(this.client.requireBaseUrl(), token);
|
|
196
|
+
}
|
|
197
|
+
checkPermissions(request) {
|
|
198
|
+
const token = this.client.getAccessToken();
|
|
199
|
+
if (!token) throw new SinasAuthError("No access token available");
|
|
200
|
+
return checkPermissions(this.client.requireBaseUrl(), token, request);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
83
203
|
var SinasClient = class {
|
|
84
|
-
constructor(
|
|
85
|
-
this.
|
|
204
|
+
constructor(options = {}) {
|
|
205
|
+
this.refreshInFlight = null;
|
|
206
|
+
this.options = options;
|
|
207
|
+
this.auth = new SinasClientAuth(this);
|
|
86
208
|
}
|
|
209
|
+
// ─── Config / base URL ───
|
|
87
210
|
getConfig() {
|
|
88
|
-
const config = this.
|
|
211
|
+
const config = this.options.config || (hasWindow() ? window.__SINAS_CONFIG__ : void 0);
|
|
89
212
|
if (!config) {
|
|
90
213
|
return {
|
|
91
|
-
apiBase: "",
|
|
214
|
+
apiBase: this.options.baseUrl ? `${trim(this.options.baseUrl)}/api/v1` : "",
|
|
92
215
|
component: { namespace: "", name: "", version: "" },
|
|
93
216
|
resources: {
|
|
94
217
|
enabledAgents: [],
|
|
@@ -105,12 +228,56 @@ var SinasClient = class {
|
|
|
105
228
|
getInput() {
|
|
106
229
|
return this.getConfig().input || {};
|
|
107
230
|
}
|
|
231
|
+
/** Workspace base URL (root of the Sinas instance). Throws if unset. */
|
|
232
|
+
requireBaseUrl() {
|
|
233
|
+
const url = this.getBaseUrl();
|
|
234
|
+
if (!url) {
|
|
235
|
+
throw new SinasError(
|
|
236
|
+
"No baseUrl configured. Construct with `new SinasClient({ baseUrl })` for standalone use.",
|
|
237
|
+
0
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return url;
|
|
241
|
+
}
|
|
242
|
+
getBaseUrl() {
|
|
243
|
+
if (this.options.baseUrl) return trim(this.options.baseUrl);
|
|
244
|
+
const apiBase = this.getConfig().apiBase;
|
|
245
|
+
if (!apiBase) return null;
|
|
246
|
+
return trim(apiBase).replace(/\/api\/v1$/, "");
|
|
247
|
+
}
|
|
248
|
+
// ─── Tokens ───
|
|
249
|
+
getAccessToken() {
|
|
250
|
+
if (this.options.getAccessToken) return this.options.getAccessToken();
|
|
251
|
+
if (hasWindow()) return window.__SINAS_AUTH_TOKEN__ ?? null;
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
getRefreshToken() {
|
|
255
|
+
return this.options.getRefreshToken ? this.options.getRefreshToken() : null;
|
|
256
|
+
}
|
|
257
|
+
async tryRefresh() {
|
|
258
|
+
const refreshToken = this.getRefreshToken();
|
|
259
|
+
if (!refreshToken) return null;
|
|
260
|
+
if (this.refreshInFlight) return this.refreshInFlight;
|
|
261
|
+
const baseUrl = this.getBaseUrl();
|
|
262
|
+
if (!baseUrl) return null;
|
|
263
|
+
this.refreshInFlight = (async () => {
|
|
264
|
+
try {
|
|
265
|
+
const resp = await refresh(baseUrl, refreshToken);
|
|
266
|
+
this.options.onTokenRefresh?.(resp.access_token);
|
|
267
|
+
return resp.access_token;
|
|
268
|
+
} catch {
|
|
269
|
+
return null;
|
|
270
|
+
} finally {
|
|
271
|
+
this.refreshInFlight = null;
|
|
272
|
+
}
|
|
273
|
+
})();
|
|
274
|
+
return this.refreshInFlight;
|
|
275
|
+
}
|
|
276
|
+
// ─── Headers / proxy ───
|
|
108
277
|
getAuthHeaders() {
|
|
109
|
-
const token =
|
|
278
|
+
const token = this.getAccessToken();
|
|
110
279
|
const headers = { "Content-Type": "application/json" };
|
|
111
|
-
if (token) {
|
|
112
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
113
|
-
}
|
|
280
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
114
281
|
return headers;
|
|
115
282
|
}
|
|
116
283
|
getProxyBase() {
|
|
@@ -118,7 +285,8 @@ var SinasClient = class {
|
|
|
118
285
|
const comp = config.component;
|
|
119
286
|
return `${config.apiBase}/components/${comp.namespace}/${comp.name}/proxy`;
|
|
120
287
|
}
|
|
121
|
-
|
|
288
|
+
// ─── Fetch with refresh-on-401 ───
|
|
289
|
+
async fetch(url, options = {}, _retried = false) {
|
|
122
290
|
const res = await fetch(url, {
|
|
123
291
|
...options,
|
|
124
292
|
headers: {
|
|
@@ -126,15 +294,18 @@ var SinasClient = class {
|
|
|
126
294
|
...options.headers || {}
|
|
127
295
|
}
|
|
128
296
|
});
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
if (res.status === 404) throw new SinasNotFoundError(message);
|
|
135
|
-
throw new SinasError(message, res.status);
|
|
297
|
+
if (res.ok || res.status === 204) return res;
|
|
298
|
+
if (res.status === 401 && !_retried) {
|
|
299
|
+
const newToken = await this.tryRefresh();
|
|
300
|
+
if (newToken) return this.fetch(url, options, true);
|
|
301
|
+
this.options.onUnauthenticated?.();
|
|
136
302
|
}
|
|
137
|
-
|
|
303
|
+
const body = await res.json().catch(() => ({ detail: res.statusText }));
|
|
304
|
+
const message = body.detail || body.message || res.statusText;
|
|
305
|
+
if (res.status === 401) throw new SinasAuthError(message);
|
|
306
|
+
if (res.status === 403) throw new SinasPermissionError(message);
|
|
307
|
+
if (res.status === 404) throw new SinasNotFoundError(message);
|
|
308
|
+
throw new SinasError(message, res.status);
|
|
138
309
|
}
|
|
139
310
|
};
|
|
140
311
|
|
|
@@ -455,18 +626,25 @@ async function generateFileUrl(client, namespace, collection, filename, expiresI
|
|
|
455
626
|
0 && (module.exports = {
|
|
456
627
|
SinasAuthError,
|
|
457
628
|
SinasClient,
|
|
629
|
+
SinasClientAuth,
|
|
458
630
|
SinasError,
|
|
459
631
|
SinasNotFoundError,
|
|
460
632
|
SinasPermissionError,
|
|
461
633
|
SinasTimeoutError,
|
|
462
634
|
approveToolCall,
|
|
635
|
+
checkPermissions,
|
|
463
636
|
createChat,
|
|
464
637
|
executeFunction,
|
|
465
638
|
executeQuery,
|
|
466
639
|
generateFileUrl,
|
|
467
640
|
getChat,
|
|
641
|
+
getInfo,
|
|
642
|
+
getMe,
|
|
468
643
|
listCollections,
|
|
469
644
|
listFiles,
|
|
645
|
+
login,
|
|
646
|
+
logout,
|
|
647
|
+
refresh,
|
|
470
648
|
sendMessage,
|
|
471
649
|
stateDelete,
|
|
472
650
|
stateGet,
|
|
@@ -474,6 +652,7 @@ async function generateFileUrl(client, namespace, collection, filename, expiresI
|
|
|
474
652
|
stateSet,
|
|
475
653
|
streamFromChannel,
|
|
476
654
|
streamMessage,
|
|
477
|
-
uploadFile
|
|
655
|
+
uploadFile,
|
|
656
|
+
verifyOTP
|
|
478
657
|
});
|
|
479
658
|
//# sourceMappingURL=client.cjs.map
|